use super::{SubagentDefinition, SubagentError, SubagentResult, SubagentTools};
use crate::config::AgentConfig;
use crate::identity::AgentRole;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
pub struct AgentConverter;
impl AgentConverter {
pub fn convert_agent_config(
config: &AgentConfig,
) -> SubagentResult<(SubagentDefinition, String)> {
let role = Self::role_from_specialization(&config.specialization);
let (tools, capabilities) = Self::extract_tools_and_capabilities(&role);
let definition = SubagentDefinition {
name: config.specialization.clone(),
description: Self::generate_description(&role),
tools,
capabilities,
metadata: Self::extract_metadata(config),
execution_config: Default::default(),
resource_limits: Default::default(),
spawn_context: None,
handoff_config: None,
};
let instructions = Self::generate_instructions(&role, &config.specialization);
Ok((definition, instructions))
}
fn extract_tools_and_capabilities(role: &AgentRole) -> (SubagentTools, Vec<String>) {
match role {
AgentRole::Frontend { .. } => (
SubagentTools {
standard: vec![
"read_file".to_string(),
"write_file".to_string(),
"execute_command".to_string(),
],
semantic: vec!["find_symbol".to_string(), "search_for_pattern".to_string()],
memory: vec!["read_memory".to_string(), "write_memory".to_string()],
custom: vec![
"component_generator".to_string(),
"style_analyzer".to_string(),
],
},
vec![
"React/Vue development".to_string(),
"UI/UX implementation".to_string(),
"Component architecture".to_string(),
"Responsive design".to_string(),
"State management".to_string(),
],
),
AgentRole::Backend { .. } => (
SubagentTools {
standard: vec![
"read_file".to_string(),
"write_file".to_string(),
"execute_command".to_string(),
"database_query".to_string(),
],
semantic: vec![
"find_symbol".to_string(),
"replace_symbol_body".to_string(),
"find_referencing_symbols".to_string(),
"search_for_pattern".to_string(),
],
memory: vec![
"read_memory".to_string(),
"write_memory".to_string(),
"list_memories".to_string(),
],
custom: vec!["api_generator".to_string(), "schema_validator".to_string()],
},
vec![
"API design and implementation".to_string(),
"Database optimization".to_string(),
"Business logic implementation".to_string(),
"Security best practices".to_string(),
"Performance optimization".to_string(),
],
),
AgentRole::DevOps { .. } => (
SubagentTools {
standard: vec![
"read_file".to_string(),
"write_file".to_string(),
"execute_command".to_string(),
],
semantic: vec!["search_for_pattern".to_string()],
memory: vec!["read_memory".to_string(), "write_memory".to_string()],
custom: vec![
"docker_builder".to_string(),
"ci_cd_generator".to_string(),
"infrastructure_analyzer".to_string(),
],
},
vec![
"Docker containerization".to_string(),
"CI/CD pipeline setup".to_string(),
"Infrastructure as Code".to_string(),
"Deployment automation".to_string(),
"Monitoring and logging".to_string(),
],
),
AgentRole::QA { .. } => (
SubagentTools {
standard: vec![
"read_file".to_string(),
"write_file".to_string(),
"execute_command".to_string(),
],
semantic: vec![
"find_symbol".to_string(),
"search_for_pattern".to_string(),
"find_referencing_symbols".to_string(),
],
memory: vec!["read_memory".to_string(), "write_memory".to_string()],
custom: vec![
"test_generator".to_string(),
"coverage_analyzer".to_string(),
"bug_detector".to_string(),
],
},
vec![
"Test strategy development".to_string(),
"Unit and integration testing".to_string(),
"Test coverage analysis".to_string(),
"Bug detection and reporting".to_string(),
"Quality metrics tracking".to_string(),
],
),
_ => (
SubagentTools {
standard: vec![
"read_file".to_string(),
"write_file".to_string(),
"execute_command".to_string(),
],
semantic: vec![],
memory: vec![],
custom: vec![],
},
vec!["General task execution".to_string()],
),
}
}
fn generate_description(role: &AgentRole) -> String {
match role {
AgentRole::Frontend { .. } => {
"Frontend development specialist with expertise in modern web frameworks and UI/UX implementation.".to_string()
}
AgentRole::Backend { .. } => {
"Backend development specialist focused on API design, database optimization, and business logic.".to_string()
}
AgentRole::DevOps { .. } => {
"DevOps specialist handling containerization, CI/CD, and infrastructure automation.".to_string()
}
AgentRole::QA { .. } => {
"Quality assurance specialist ensuring code quality through comprehensive testing and analysis.".to_string()
}
_ => "General purpose agent for various development tasks.".to_string(),
}
}
fn generate_instructions(role: &AgentRole, name: &str) -> String {
let role_specific = match role {
AgentRole::Frontend { .. } => include_str!("../../templates/frontend_instructions.md"),
AgentRole::Backend { .. } => include_str!("../../templates/backend_instructions.md"),
AgentRole::DevOps { .. } => include_str!("../../templates/devops_instructions.md"),
AgentRole::QA { .. } => include_str!("../../templates/qa_instructions.md"),
_ => include_str!("../../templates/general_instructions.md"),
};
format!("# {} Agent Instructions\n\n{}", name, role_specific)
}
fn extract_metadata(config: &AgentConfig) -> HashMap<String, serde_json::Value> {
let mut metadata = HashMap::new();
metadata.insert(
"specialization".to_string(),
serde_json::json!(config.specialization),
);
metadata.insert("worktree".to_string(), serde_json::json!(config.worktree));
metadata.insert("branch".to_string(), serde_json::json!(config.branch));
metadata
}
fn role_from_specialization(specialization: &str) -> AgentRole {
match specialization.to_lowercase().as_str() {
s if s.contains("frontend") => AgentRole::Frontend {
technologies: vec![],
responsibilities: vec![],
boundaries: vec![],
},
s if s.contains("backend") => AgentRole::Backend {
technologies: vec![],
responsibilities: vec![],
boundaries: vec![],
},
s if s.contains("devops") => AgentRole::DevOps {
technologies: vec![],
responsibilities: vec![],
boundaries: vec![],
},
s if s.contains("qa") || s.contains("test") => AgentRole::QA {
technologies: vec![],
responsibilities: vec![],
boundaries: vec![],
},
s if s.contains("search") => AgentRole::Search {
technologies: vec![],
responsibilities: vec![],
boundaries: vec![],
},
_ => AgentRole::Frontend {
technologies: vec![],
responsibilities: vec![],
boundaries: vec![],
},
}
}
pub fn save_subagent_definition(
definition: &SubagentDefinition,
instructions: &str,
output_dir: &Path,
) -> SubagentResult<()> {
fs::create_dir_all(output_dir)?;
let filename = format!("{}.md", definition.name);
let filepath = output_dir.join(filename);
let frontmatter = serde_yaml::to_string(definition).map_err(|e| {
SubagentError::Serialization(serde_json::Error::io(std::io::Error::other(
e.to_string(),
)))
})?;
let content = format!("---\n{}---\n\n{}", frontmatter, instructions);
fs::write(&filepath, content)?;
log::info!("Saved subagent definition to {:?}", filepath);
Ok(())
}
pub fn batch_convert_project(
project_config_path: &Path,
output_dir: &Path,
) -> SubagentResult<Vec<String>> {
let config_content = fs::read_to_string(project_config_path)?;
let project_config: serde_json::Value = serde_json::from_str(&config_content)?;
let mut converted = Vec::new();
if let Some(agents) = project_config.get("agents").and_then(|a| a.as_array()) {
for agent_value in agents {
if let Ok(agent_config) = serde_json::from_value::<AgentConfig>(agent_value.clone())
{
let (definition, instructions) = Self::convert_agent_config(&agent_config)?;
Self::save_subagent_definition(&definition, &instructions, output_dir)?;
converted.push(definition.name);
}
}
}
log::info!("Converted {} agents to subagent format", converted.len());
Ok(converted)
}
}