use crate::error::{ConfigError, ConfigResult};
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentDBConfig {
pub max_agents: usize,
pub prune_threshold: usize,
pub enable_persistence: bool,
pub persistence_dir: Option<String>,
}
impl Default for AgentDBConfig {
fn default() -> Self {
Self {
max_agents: 10000,
prune_threshold: 8000,
enable_persistence: true,
persistence_dir: Some("data/agentdb".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryConfig {
pub working_capacity: usize,
pub short_term_capacity: usize,
pub long_term_capacity: usize,
pub consolidation_interval: u64,
pub enable_compression: bool,
pub persistence_dir: Option<String>,
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
working_capacity: 1000,
short_term_capacity: 10000,
long_term_capacity: 1000000,
consolidation_interval: 300, enable_compression: true,
persistence_dir: Some("data/memory".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoopsConfig {
pub enable_conscious: bool,
pub conscious_interval: u64,
pub enable_subconscious: bool,
pub subconscious_interval: u64,
pub enable_meta: bool,
pub meta_interval: u64,
pub enable_unconscious: bool,
pub unconscious_interval: u64,
}
impl Default for LoopsConfig {
fn default() -> Self {
Self {
enable_conscious: true,
conscious_interval: 100,
enable_subconscious: true,
subconscious_interval: 500,
enable_meta: true,
meta_interval: 1000,
enable_unconscious: true,
unconscious_interval: 5000,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MetaSONAConfig {
pub population_size: usize,
pub generations: usize,
pub mutation_rate: f64,
pub crossover_rate: f64,
pub enable_nas: bool,
pub enable_self_modification: bool,
pub cache_size: usize,
}
impl Default for MetaSONAConfig {
fn default() -> Self {
Self {
population_size: 100,
generations: 50,
mutation_rate: 0.1,
crossover_rate: 0.7,
enable_nas: true,
enable_self_modification: true,
cache_size: 1000,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OmegaConfig {
pub agentdb: AgentDBConfig,
pub memory: MemoryConfig,
pub loops: LoopsConfig,
pub meta_sona: MetaSONAConfig,
pub enable_event_logging: bool,
pub enable_metrics: bool,
pub data_dir: String,
}
impl Default for OmegaConfig {
fn default() -> Self {
Self {
agentdb: AgentDBConfig::default(),
memory: MemoryConfig::default(),
loops: LoopsConfig::default(),
meta_sona: MetaSONAConfig::default(),
enable_event_logging: true,
enable_metrics: true,
data_dir: "data/omega".to_string(),
}
}
}
impl OmegaConfig {
pub fn from_file(path: &Path) -> ConfigResult<Self> {
let content = std::fs::read_to_string(path)
.map_err(|e| ConfigError::FileNotFound(format!("{}: {}", path.display(), e)))?;
let config: OmegaConfig = serde_json::from_str(&content)
.map_err(|e| ConfigError::Parse(format!("Failed to parse config: {}", e)))?;
config.validate()?;
Ok(config)
}
pub fn to_file(&self, path: &Path) -> ConfigResult<()> {
let content = serde_json::to_string_pretty(self)?;
std::fs::write(path, content)?;
Ok(())
}
pub fn validate(&self) -> ConfigResult<()> {
if self.agentdb.max_agents == 0 {
return Err(ConfigError::Validation(
"max_agents must be greater than 0".to_string(),
));
}
if self.agentdb.prune_threshold >= self.agentdb.max_agents {
return Err(ConfigError::Validation(
"prune_threshold must be less than max_agents".to_string(),
));
}
if self.memory.working_capacity == 0 {
return Err(ConfigError::Validation(
"working_capacity must be greater than 0".to_string(),
));
}
if self.memory.consolidation_interval == 0 {
return Err(ConfigError::Validation(
"consolidation_interval must be greater than 0".to_string(),
));
}
if self.loops.conscious_interval == 0 {
return Err(ConfigError::Validation(
"conscious_interval must be greater than 0".to_string(),
));
}
if self.meta_sona.population_size == 0 {
return Err(ConfigError::Validation(
"population_size must be greater than 0".to_string(),
));
}
if !(0.0..=1.0).contains(&self.meta_sona.mutation_rate) {
return Err(ConfigError::Validation(
"mutation_rate must be between 0.0 and 1.0".to_string(),
));
}
if !(0.0..=1.0).contains(&self.meta_sona.crossover_rate) {
return Err(ConfigError::Validation(
"crossover_rate must be between 0.0 and 1.0".to_string(),
));
}
Ok(())
}
pub fn minimal() -> Self {
Self {
agentdb: AgentDBConfig {
max_agents: 100,
prune_threshold: 80,
enable_persistence: false,
persistence_dir: None,
},
memory: MemoryConfig {
working_capacity: 100,
short_term_capacity: 1000,
long_term_capacity: 10000,
consolidation_interval: 60,
enable_compression: false,
persistence_dir: None,
},
loops: LoopsConfig {
enable_conscious: true,
conscious_interval: 1000,
enable_subconscious: false,
subconscious_interval: 5000,
enable_meta: false,
meta_interval: 10000,
enable_unconscious: false,
unconscious_interval: 30000,
},
meta_sona: MetaSONAConfig {
population_size: 10,
generations: 5,
mutation_rate: 0.1,
crossover_rate: 0.7,
enable_nas: false,
enable_self_modification: false,
cache_size: 100,
},
enable_event_logging: false,
enable_metrics: false,
data_dir: "test_data".to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config_is_valid() {
let config = OmegaConfig::default();
assert!(config.validate().is_ok());
}
#[test]
fn test_minimal_config_is_valid() {
let config = OmegaConfig::minimal();
assert!(config.validate().is_ok());
}
#[test]
fn test_invalid_max_agents() {
let mut config = OmegaConfig::default();
config.agentdb.max_agents = 0;
assert!(config.validate().is_err());
}
#[test]
fn test_invalid_prune_threshold() {
let mut config = OmegaConfig::default();
config.agentdb.prune_threshold = config.agentdb.max_agents + 1;
assert!(config.validate().is_err());
}
#[test]
fn test_invalid_mutation_rate() {
let mut config = OmegaConfig::default();
config.meta_sona.mutation_rate = 1.5;
assert!(config.validate().is_err());
}
#[test]
fn test_serialization() {
let config = OmegaConfig::default();
let json = serde_json::to_string(&config).unwrap();
let deserialized: OmegaConfig = serde_json::from_str(&json).unwrap();
assert!(deserialized.validate().is_ok());
}
}