1use crate::error::{ConfigError, ConfigResult};
4use serde::{Deserialize, Serialize};
5use std::path::Path;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct AgentDBConfig {
10 pub max_agents: usize,
12 pub prune_threshold: usize,
14 pub enable_persistence: bool,
16 pub persistence_dir: Option<String>,
18}
19
20impl Default for AgentDBConfig {
21 fn default() -> Self {
22 Self {
23 max_agents: 10000,
24 prune_threshold: 8000,
25 enable_persistence: true,
26 persistence_dir: Some("data/agentdb".to_string()),
27 }
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct MemoryConfig {
34 pub working_capacity: usize,
36 pub short_term_capacity: usize,
38 pub long_term_capacity: usize,
40 pub consolidation_interval: u64,
42 pub enable_compression: bool,
44 pub persistence_dir: Option<String>,
46}
47
48impl Default for MemoryConfig {
49 fn default() -> Self {
50 Self {
51 working_capacity: 1000,
52 short_term_capacity: 10000,
53 long_term_capacity: 1000000,
54 consolidation_interval: 300, enable_compression: true,
56 persistence_dir: Some("data/memory".to_string()),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct LoopsConfig {
64 pub enable_conscious: bool,
66 pub conscious_interval: u64,
68 pub enable_subconscious: bool,
70 pub subconscious_interval: u64,
72 pub enable_meta: bool,
74 pub meta_interval: u64,
76 pub enable_unconscious: bool,
78 pub unconscious_interval: u64,
80}
81
82impl Default for LoopsConfig {
83 fn default() -> Self {
84 Self {
85 enable_conscious: true,
86 conscious_interval: 100,
87 enable_subconscious: true,
88 subconscious_interval: 500,
89 enable_meta: true,
90 meta_interval: 1000,
91 enable_unconscious: true,
92 unconscious_interval: 5000,
93 }
94 }
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct MetaSONAConfig {
100 pub population_size: usize,
102 pub generations: usize,
104 pub mutation_rate: f64,
106 pub crossover_rate: f64,
108 pub enable_nas: bool,
110 pub enable_self_modification: bool,
112 pub cache_size: usize,
114}
115
116impl Default for MetaSONAConfig {
117 fn default() -> Self {
118 Self {
119 population_size: 100,
120 generations: 50,
121 mutation_rate: 0.1,
122 crossover_rate: 0.7,
123 enable_nas: true,
124 enable_self_modification: true,
125 cache_size: 1000,
126 }
127 }
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct OmegaConfig {
133 pub agentdb: AgentDBConfig,
135 pub memory: MemoryConfig,
137 pub loops: LoopsConfig,
139 pub meta_sona: MetaSONAConfig,
141 pub enable_event_logging: bool,
143 pub enable_metrics: bool,
145 pub data_dir: String,
147}
148
149impl Default for OmegaConfig {
150 fn default() -> Self {
151 Self {
152 agentdb: AgentDBConfig::default(),
153 memory: MemoryConfig::default(),
154 loops: LoopsConfig::default(),
155 meta_sona: MetaSONAConfig::default(),
156 enable_event_logging: true,
157 enable_metrics: true,
158 data_dir: "data/omega".to_string(),
159 }
160 }
161}
162
163impl OmegaConfig {
164 pub fn from_file(path: &Path) -> ConfigResult<Self> {
166 let content = std::fs::read_to_string(path)
167 .map_err(|e| ConfigError::FileNotFound(format!("{}: {}", path.display(), e)))?;
168
169 let config: OmegaConfig = serde_json::from_str(&content)
170 .map_err(|e| ConfigError::Parse(format!("Failed to parse config: {}", e)))?;
171
172 config.validate()?;
173 Ok(config)
174 }
175
176 pub fn to_file(&self, path: &Path) -> ConfigResult<()> {
178 let content = serde_json::to_string_pretty(self)?;
179 std::fs::write(path, content)?;
180 Ok(())
181 }
182
183 pub fn validate(&self) -> ConfigResult<()> {
185 if self.agentdb.max_agents == 0 {
187 return Err(ConfigError::Validation(
188 "max_agents must be greater than 0".to_string(),
189 ));
190 }
191 if self.agentdb.prune_threshold >= self.agentdb.max_agents {
192 return Err(ConfigError::Validation(
193 "prune_threshold must be less than max_agents".to_string(),
194 ));
195 }
196
197 if self.memory.working_capacity == 0 {
199 return Err(ConfigError::Validation(
200 "working_capacity must be greater than 0".to_string(),
201 ));
202 }
203 if self.memory.consolidation_interval == 0 {
204 return Err(ConfigError::Validation(
205 "consolidation_interval must be greater than 0".to_string(),
206 ));
207 }
208
209 if self.loops.conscious_interval == 0 {
211 return Err(ConfigError::Validation(
212 "conscious_interval must be greater than 0".to_string(),
213 ));
214 }
215
216 if self.meta_sona.population_size == 0 {
218 return Err(ConfigError::Validation(
219 "population_size must be greater than 0".to_string(),
220 ));
221 }
222 if !(0.0..=1.0).contains(&self.meta_sona.mutation_rate) {
223 return Err(ConfigError::Validation(
224 "mutation_rate must be between 0.0 and 1.0".to_string(),
225 ));
226 }
227 if !(0.0..=1.0).contains(&self.meta_sona.crossover_rate) {
228 return Err(ConfigError::Validation(
229 "crossover_rate must be between 0.0 and 1.0".to_string(),
230 ));
231 }
232
233 Ok(())
234 }
235
236 pub fn minimal() -> Self {
238 Self {
239 agentdb: AgentDBConfig {
240 max_agents: 100,
241 prune_threshold: 80,
242 enable_persistence: false,
243 persistence_dir: None,
244 },
245 memory: MemoryConfig {
246 working_capacity: 100,
247 short_term_capacity: 1000,
248 long_term_capacity: 10000,
249 consolidation_interval: 60,
250 enable_compression: false,
251 persistence_dir: None,
252 },
253 loops: LoopsConfig {
254 enable_conscious: true,
255 conscious_interval: 1000,
256 enable_subconscious: false,
257 subconscious_interval: 5000,
258 enable_meta: false,
259 meta_interval: 10000,
260 enable_unconscious: false,
261 unconscious_interval: 30000,
262 },
263 meta_sona: MetaSONAConfig {
264 population_size: 10,
265 generations: 5,
266 mutation_rate: 0.1,
267 crossover_rate: 0.7,
268 enable_nas: false,
269 enable_self_modification: false,
270 cache_size: 100,
271 },
272 enable_event_logging: false,
273 enable_metrics: false,
274 data_dir: "test_data".to_string(),
275 }
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_default_config_is_valid() {
285 let config = OmegaConfig::default();
286 assert!(config.validate().is_ok());
287 }
288
289 #[test]
290 fn test_minimal_config_is_valid() {
291 let config = OmegaConfig::minimal();
292 assert!(config.validate().is_ok());
293 }
294
295 #[test]
296 fn test_invalid_max_agents() {
297 let mut config = OmegaConfig::default();
298 config.agentdb.max_agents = 0;
299 assert!(config.validate().is_err());
300 }
301
302 #[test]
303 fn test_invalid_prune_threshold() {
304 let mut config = OmegaConfig::default();
305 config.agentdb.prune_threshold = config.agentdb.max_agents + 1;
306 assert!(config.validate().is_err());
307 }
308
309 #[test]
310 fn test_invalid_mutation_rate() {
311 let mut config = OmegaConfig::default();
312 config.meta_sona.mutation_rate = 1.5;
313 assert!(config.validate().is_err());
314 }
315
316 #[test]
317 fn test_serialization() {
318 let config = OmegaConfig::default();
319 let json = serde_json::to_string(&config).unwrap();
320 let deserialized: OmegaConfig = serde_json::from_str(&json).unwrap();
321 assert!(deserialized.validate().is_ok());
322 }
323}