use std::collections::HashMap;
use crate::domain::agent::{AgentConfig, AgentDefinition, builtin_agents};
pub fn discover_agents(overrides: &HashMap<String, AgentConfig>) -> Vec<AgentDefinition> {
let builtins = builtin_agents();
let mut result = Vec::new();
for mut def in builtins {
if let Some(config) = overrides.get(&def.name) {
def.binary = config.binary.clone();
if !config.args.is_empty() {
def.args = config.args.clone();
}
if let Some(desc) = &config.description {
def.description = desc.clone();
}
if let Some(timeout) = config.timeout {
def.timeout = timeout;
}
}
if which::which(&def.binary).is_ok() {
result.push(def);
}
}
let builtin_names: std::collections::HashSet<String> =
result.iter().map(|a| a.name.clone()).collect();
for (name, config) in overrides {
if builtin_names.contains(name) {
continue; }
if which::which(&config.binary).is_ok() {
result.push(AgentDefinition {
name: name.clone(),
binary: config.binary.clone(),
args: if config.args.is_empty() {
vec!["{prompt}".to_string()]
} else {
config.args.clone()
},
description: config
.description
.clone()
.unwrap_or_else(|| format!("Custom agent: {name}")),
timeout: config.timeout.unwrap_or(120),
});
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn discover_agents_no_overrides_finds_available_builtins() {
let overrides = HashMap::new();
let agents = discover_agents(&overrides);
for agent in &agents {
assert!(!agent.name.is_empty());
assert!(!agent.binary.is_empty());
assert!(!agent.args.is_empty());
assert!(!agent.description.is_empty());
assert!(agent.timeout > 0);
}
}
#[test]
fn discover_agents_custom_agent_not_on_path_is_excluded() {
let mut overrides = HashMap::new();
overrides.insert(
"my-custom-agent".to_string(),
AgentConfig {
binary: "nonexistent_binary_xyz_12345".to_string(),
args: vec![],
description: None,
timeout: None,
},
);
let agents = discover_agents(&overrides);
assert!(!agents.iter().any(|a| a.name == "my-custom-agent"));
}
#[test]
fn discover_agents_override_description_applied() {
let mut overrides = HashMap::new();
overrides.insert(
"gemini".to_string(),
AgentConfig {
binary: "cargo".to_string(),
args: vec![],
description: Some("Overridden description".to_string()),
timeout: Some(42),
},
);
let agents = discover_agents(&overrides);
let gemini = agents.iter().find(|a| a.name == "gemini");
if let Some(agent) = gemini {
assert_eq!(agent.binary, "cargo");
assert_eq!(agent.description, "Overridden description");
assert_eq!(agent.timeout, 42);
}
}
}