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,
34};
35pub use validator::{ConfigValidator, ValueType};
36
37use thiserror::Error;
38
39#[derive(Error, Debug)]
41pub enum ConfigError {
42 #[error("Key not found: {key}")]
44 NotFound {
45 key: String,
47 },
48
49 #[error("Invalid value for {key}: {message}")]
51 InvalidValue {
52 key: String,
54 message: String,
56 },
57
58 #[error("Serialization error: {0}")]
60 Serialization(#[from] serde_json::Error),
61
62 #[error("IO error: {0}")]
64 Io(#[from] std::io::Error),
65
66 #[error("Environment error: {0}")]
68 Env(#[from] std::env::VarError),
69
70 #[error("Provider error: {message}")]
72 Provider {
73 message: String,
75 },
76
77 #[error("{0}")]
79 ValidationErrors(ValidationErrors),
80}
81
82#[derive(Debug)]
83pub struct ValidationErrors(pub Vec<ConfigError>);
84
85impl std::fmt::Display for ValidationErrors {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "Validation failed: ")?;
88 let msgs: Vec<String> = self.0.iter().map(|e| e.to_string()).collect();
89 write!(f, "{}", msgs.join("; "))
90 }
91}
92
93pub type ConfigResult<T> = std::result::Result<T, ConfigError>;
95
96pub struct ConfigBuilder {
98 providers: Vec<Box<dyn ConfigProvider>>,
99}
100
101impl ConfigBuilder {
102 pub fn new() -> Self {
104 Self {
105 providers: Vec::new(),
106 }
107 }
108
109 pub fn env(mut self) -> Self {
111 self.providers.push(Box::new(EnvConfigProvider::new()));
112 self
113 }
114
115 pub fn env_with_prefix(mut self, prefix: &str) -> Self {
117 self.providers
118 .push(Box::new(EnvConfigProvider::with_prefix(prefix)));
119 self
120 }
121
122 pub fn file(mut self, path: impl AsRef<std::path::Path>) -> Self {
124 self.providers.push(Box::new(FileConfigProvider::new(
125 path.as_ref().to_path_buf(),
126 )));
127 self
128 }
129
130 pub fn memory(mut self, provider: MemoryConfigProvider) -> Self {
132 self.providers.push(Box::new(provider));
133 self
134 }
135
136 pub fn provider(mut self, provider: Box<dyn ConfigProvider>) -> Self {
138 self.providers.push(provider);
139 self
140 }
141
142 pub async fn build(self) -> ConfigResult<CompositeConfigProvider> {
144 let mut composite = CompositeConfigProvider::new();
145 for provider in self.providers {
146 composite.add_provider(provider);
147 }
148 Ok(composite)
149 }
150}
151
152impl Default for ConfigBuilder {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn test_config_error_display() {
164 let err = ConfigError::NotFound {
165 key: "api_key".to_string(),
166 };
167 assert!(err.to_string().contains("api_key"));
168 }
169
170 #[test]
171 fn test_config_builder() {
172 let builder = ConfigBuilder::new().env().env_with_prefix("CLAUDE_");
173 assert!(!builder.providers.is_empty());
174 }
175}