Skip to main content

agent_diva_nano/
config.rs

1use std::collections::HashMap;
2use std::path::PathBuf;
3
4/// Re-export MCP server configuration from the core crate.
5pub use agent_diva_core::config::MCPServerConfig;
6
7/// Re-export tool assembly types.
8pub use crate::tool_assembly::{BuiltInToolsConfig, ShellToolConfig, WebToolConfig};
9
10/// Simplified web search configuration.
11#[derive(Debug, Clone)]
12pub struct WebSearchConfig {
13    /// Search provider name (e.g. "bocha").
14    pub provider: String,
15    /// API key for the search provider.
16    pub api_key: Option<String>,
17    /// Maximum number of results to return.
18    pub max_results: u32,
19}
20
21impl Default for WebSearchConfig {
22    fn default() -> Self {
23        Self {
24            provider: "bocha".to_string(),
25            api_key: None,
26            max_results: 5,
27        }
28    }
29}
30
31/// Soul (identity) configuration.
32#[derive(Debug, Clone)]
33pub struct SoulConfig {
34    /// Whether soul context injection is enabled.
35    pub enabled: bool,
36    /// Maximum characters for soul context.
37    pub max_chars: usize,
38    /// Bootstrap soul only once.
39    pub bootstrap_once: bool,
40    /// Notify on soul changes.
41    pub notify_on_change: bool,
42    /// Window in seconds for frequent-change detection.
43    pub frequent_change_window_secs: u64,
44    /// Threshold for frequent-change hints.
45    pub frequent_change_threshold: usize,
46    /// Show boundary confirmation hint.
47    pub boundary_confirmation_hint: bool,
48}
49
50impl Default for SoulConfig {
51    fn default() -> Self {
52        Self {
53            enabled: true,
54            max_chars: 4000,
55            bootstrap_once: true,
56            notify_on_change: true,
57            frequent_change_window_secs: 300,
58            frequent_change_threshold: 3,
59            boundary_confirmation_hint: true,
60        }
61    }
62}
63
64/// Minimal configuration to create an agent.
65///
66/// # Example
67/// ```rust,no_run
68/// use agent_diva_nano::NanoConfig;
69/// use std::path::PathBuf;
70///
71/// let config = NanoConfig {
72///     model: "deepseek-chat".to_string(),
73///     api_key: std::env::var("NANO_API_KEY").unwrap(),
74///     ..Default::default()
75/// };
76/// ```
77#[derive(Debug, Clone)]
78pub struct NanoConfig {
79    /// LLM model identifier, e.g. "deepseek-chat", "gpt-4o", "openrouter/anthropic/claude-sonnet-4".
80    pub model: String,
81    /// API key for the provider.
82    pub api_key: String,
83    /// Custom API base URL (optional, for private deployments or OpenRouter).
84    pub api_base: Option<String>,
85    /// Workspace directory — root for skills, memory, and SOUL.md.
86    pub workspace: PathBuf,
87    /// Maximum tool-call iterations per turn (default: 20).
88    pub max_iterations: usize,
89    /// Shell command execution timeout in seconds (default: 60).
90    pub exec_timeout: u64,
91    /// Restrict file-system tools to the workspace directory (default: true).
92    pub restrict_to_workspace: bool,
93    /// Web search configuration (optional).
94    pub web_search: Option<WebSearchConfig>,
95    /// MCP server configurations.
96    pub mcp_servers: HashMap<String, MCPServerConfig>,
97    /// Soul / identity context configuration.
98    pub soul: SoulConfig,
99    /// Built-in tools enable/disable configuration.
100    /// If not set, defaults to BuiltInToolsConfig::default().
101    pub builtin_tools: Option<BuiltInToolsConfig>,
102}
103
104impl Default for NanoConfig {
105    fn default() -> Self {
106        Self {
107            model: String::new(),
108            api_key: String::new(),
109            api_base: None,
110            workspace: PathBuf::from("."),
111            max_iterations: 20,
112            exec_timeout: 60,
113            restrict_to_workspace: true,
114            web_search: None,
115            mcp_servers: HashMap::new(),
116            soul: SoulConfig::default(),
117            builtin_tools: None, // Uses BuiltInToolsConfig::default() when not set
118        }
119    }
120}
121
122impl NanoConfig {
123    /// Build from environment variables:
124    /// - `NANO_MODEL`
125    /// - `NANO_API_KEY`
126    /// - `NANO_API_BASE` (optional)
127    pub fn from_env() -> Result<Self, String> {
128        let model = std::env::var("NANO_MODEL")
129            .map_err(|_| "NANO_MODEL environment variable not set")?;
130        let api_key = std::env::var("NANO_API_KEY")
131            .map_err(|_| "NANO_API_KEY environment variable not set")?;
132        let api_base = std::env::var("NANO_API_BASE").ok().filter(|s| !s.is_empty());
133
134        Ok(Self {
135            model,
136            api_key,
137            api_base,
138            ..Default::default()
139        })
140    }
141}