claude_agent/config/
mod.rs1pub mod cloud;
17pub mod composite;
18pub mod env;
19pub mod file;
20pub mod memory;
21pub mod provider;
22pub mod settings;
23pub mod validator;
24
25pub use cloud::{BedrockConfig, CloudConfig, FoundryConfig, TokenLimits, VertexConfig};
26pub use composite::CompositeConfigProvider;
27pub use env::EnvConfigProvider;
28pub use file::FileConfigProvider;
29pub use memory::MemoryConfigProvider;
30pub use provider::{ConfigProvider, ConfigProviderExt};
31pub use settings::{
32 HookConfig, HooksSettings, NetworkSandboxSettings, PermissionSettings, SandboxSettings,
33 Settings, SettingsLoader, SettingsSource, ToolSearchSettings,
34};
35pub use validator::{ConfigValidator, ValueType};
36
37use thiserror::Error;
38
39#[derive(Error, Debug)]
40pub enum ConfigError {
41 #[error("Key not found: {key}")]
42 NotFound { key: String },
43
44 #[error("Invalid value for {key}: {message}")]
45 InvalidValue { key: String, message: String },
46
47 #[error("Serialization error: {0}")]
48 Serialization(#[from] serde_json::Error),
49
50 #[error("IO error: {0}")]
51 Io(#[from] std::io::Error),
52
53 #[error("Environment error: {0}")]
54 Env(#[from] std::env::VarError),
55
56 #[error("Provider error: {message}")]
57 Provider { message: String },
58
59 #[error("{0}")]
60 ValidationErrors(ValidationErrors),
61}
62
63#[derive(Debug)]
64pub struct ValidationErrors(pub Vec<ConfigError>);
65
66impl std::fmt::Display for ValidationErrors {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 write!(f, "Validation failed: ")?;
69 let msgs: Vec<String> = self.0.iter().map(|e| e.to_string()).collect();
70 write!(f, "{}", msgs.join("; "))
71 }
72}
73
74pub type ConfigResult<T> = std::result::Result<T, ConfigError>;
75
76pub struct ConfigBuilder {
77 providers: Vec<Box<dyn ConfigProvider>>,
78}
79
80impl ConfigBuilder {
81 pub fn new() -> Self {
82 Self {
83 providers: Vec::new(),
84 }
85 }
86
87 pub fn env(mut self) -> Self {
88 self.providers.push(Box::new(EnvConfigProvider::new()));
89 self
90 }
91
92 pub fn env_with_prefix(mut self, prefix: &str) -> Self {
93 self.providers
94 .push(Box::new(EnvConfigProvider::prefixed(prefix)));
95 self
96 }
97
98 pub fn file(mut self, path: impl AsRef<std::path::Path>) -> Self {
99 self.providers.push(Box::new(FileConfigProvider::new(
100 path.as_ref().to_path_buf(),
101 )));
102 self
103 }
104
105 pub fn memory(mut self, provider: MemoryConfigProvider) -> Self {
106 self.providers.push(Box::new(provider));
107 self
108 }
109
110 pub fn provider(mut self, provider: Box<dyn ConfigProvider>) -> Self {
111 self.providers.push(provider);
112 self
113 }
114
115 pub async fn build(self) -> ConfigResult<CompositeConfigProvider> {
116 let mut composite = CompositeConfigProvider::new();
117 for provider in self.providers {
118 composite.add_provider(provider);
119 }
120 Ok(composite)
121 }
122}
123
124impl Default for ConfigBuilder {
125 fn default() -> Self {
126 Self::new()
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_config_error_display() {
136 let err = ConfigError::NotFound {
137 key: "api_key".to_string(),
138 };
139 assert!(err.to_string().contains("api_key"));
140 }
141
142 #[test]
143 fn test_config_builder() {
144 let builder = ConfigBuilder::new().env().env_with_prefix("CLAUDE_");
145 assert!(!builder.providers.is_empty());
146 }
147}