use super::runtime::RuntimeConfig;
use anyhow::Result;
pub struct ConfigValidator;
impl ConfigValidator {
pub fn validate(config: &RuntimeConfig) -> Result<Vec<String>> {
let mut issues = Vec::new();
if config.meta.name.is_empty() {
issues.push("meta.name cannot be empty".to_string());
}
if config.gateway.port == 0 {
issues.push("gateway.port must be greater than 0".to_string());
}
let default_count = config.agents.list.iter().filter(|a| a.default).count();
if default_count == 0 {
issues.push("No default agent defined. Set one agent as default.".to_string());
} else if default_count > 1 {
issues.push(format!(
"Multiple default agents found ({}). Only one agent can be default.",
default_count
));
}
for agent in &config.agents.list {
if agent.name.is_empty() {
issues.push("Agent name cannot be empty".to_string());
}
if let Some(memory_limit) = agent.memory_limit_mb {
if memory_limit > 2048 {
issues.push(format!(
"Agent '{}' memory_limit_mb ({}) exceeds system limit (2048MB)",
agent.name, memory_limit
));
}
}
}
for provider in &config.models.providers {
if provider.name.is_empty() {
issues.push("Provider name cannot be empty".to_string());
}
if provider.provider_type.is_empty() {
issues.push(format!(
"Provider '{}' has empty provider_type",
provider.name
));
}
let valid_types = [
"openai",
"openai-completions",
"openai-chat",
"anthropic",
"gemini",
"ollama",
];
if !valid_types.contains(&provider.provider_type.as_ref()) {
issues.push(format!(
"Provider '{}' has invalid provider_type '{}'. Valid types: {}",
provider.name,
provider.provider_type,
valid_types.join(", ")
));
}
for model in &provider.models {
if model.name.is_empty() {
issues.push(format!(
"Model in provider '{}' has empty name",
provider.name
));
}
}
}
if config.memory.max_agent_memory_mb > 2048 {
issues.push(format!(
"memory.max_agent_memory_mb ({}) exceeds system limit (2048MB)",
config.memory.max_agent_memory_mb
));
}
if config.memory.token_threshold == 0 {
issues.push("memory.token_threshold must be greater than 0".to_string());
}
if config.memory.max_concurrent_agents < 1 || config.memory.max_concurrent_agents > 5 {
issues.push(format!(
"memory.max_concurrent_agents ({}) must be between 1 and 5",
config.memory.max_concurrent_agents
));
}
if config.session.timeout_minutes == 0 {
issues.push("session.timeout_minutes must be greater than 0".to_string());
}
let agent_names: Vec<&str> = config.agents.list.iter().map(|a| a.name.as_ref()).collect();
for binding in &config.bindings {
if !agent_names.contains(&binding.agent.as_ref()) {
issues.push(format!(
"Binding references non-existent agent '{}'",
binding.agent
));
}
}
Ok(issues)
}
pub fn fix(config: &mut RuntimeConfig, issues: &[String]) -> Result<()> {
for issue in issues {
tracing::info!("Fixing: {}", issue);
if issue.contains("max_concurrent_agents") {
if config.memory.max_concurrent_agents < 1 {
config.memory.max_concurrent_agents = 1;
} else if config.memory.max_concurrent_agents > 5 {
config.memory.max_concurrent_agents = 5;
}
}
if issue.contains("memory_limit_mb") {
for agent in &mut config.agents.list {
if let Some(limit) = agent.memory_limit_mb {
if limit > 2048 {
agent.memory_limit_mb = Some(2048);
}
}
}
}
}
Ok(())
}
}