agent_code_lib/config/
mod.rs1mod schema;
13
14pub use schema::*;
15
16use crate::error::ConfigError;
17use std::path::{Path, PathBuf};
18
19impl Config {
20 pub fn load() -> Result<Config, ConfigError> {
22 let mut config = Config::default();
23
24 if let Some(path) = user_config_path()
26 && path.exists()
27 {
28 let content = std::fs::read_to_string(&path)
29 .map_err(|e| ConfigError::FileError(format!("{path:?}: {e}")))?;
30 let user_config: Config = toml::from_str(&content)?;
31 config.merge(user_config);
32 }
33
34 if let Some(path) = find_project_config() {
36 let content = std::fs::read_to_string(&path)
37 .map_err(|e| ConfigError::FileError(format!("{path:?}: {e}")))?;
38 let project_config: Config = toml::from_str(&content)?;
39 config.merge(project_config);
40 }
41
42 Ok(config)
45 }
46
47 fn merge(&mut self, other: Config) {
50 if !other.api.base_url.is_empty() {
51 self.api.base_url = other.api.base_url;
52 }
53 if !other.api.model.is_empty() {
54 self.api.model = other.api.model;
55 }
56 if other.api.api_key.is_some() {
57 self.api.api_key = other.api.api_key;
58 }
59 if other.api.max_output_tokens.is_some() {
60 self.api.max_output_tokens = other.api.max_output_tokens;
61 }
62 if other.permissions.default_mode != PermissionMode::Ask {
63 self.permissions.default_mode = other.permissions.default_mode;
64 }
65 if !other.permissions.rules.is_empty() {
66 self.permissions.rules.extend(other.permissions.rules);
67 }
68 for (name, entry) in other.mcp_servers {
70 self.mcp_servers.insert(name, entry);
71 }
72 }
73}
74
75fn user_config_path() -> Option<PathBuf> {
77 dirs::config_dir().map(|d| d.join("agent-code").join("config.toml"))
78}
79
80fn find_project_config() -> Option<PathBuf> {
82 let cwd = std::env::current_dir().ok()?;
83 find_config_in_ancestors(&cwd)
84}
85
86fn find_config_in_ancestors(start: &Path) -> Option<PathBuf> {
87 let mut dir = start.to_path_buf();
88 loop {
89 let candidate = dir.join(".agent").join("settings.toml");
90 if candidate.exists() {
91 return Some(candidate);
92 }
93 if !dir.pop() {
94 return None;
95 }
96 }
97}