use super::{SubagentDefinition, SubagentError, SubagentResult};
use std::fs;
use std::path::Path;
pub struct SubagentParser;
impl SubagentParser {
pub fn parse_file(path: &Path) -> SubagentResult<(SubagentDefinition, String)> {
let content = fs::read_to_string(path)?;
Self::parse_content(&content)
}
pub fn parse_content(content: &str) -> SubagentResult<(SubagentDefinition, String)> {
let parts: Vec<&str> = content.splitn(3, "---").collect();
if parts.len() < 3 {
return Err(SubagentError::Parse(
"Invalid subagent file format: missing frontmatter".to_string(),
));
}
let frontmatter = parts[1].trim();
let body = parts[2].trim();
let mut definition: SubagentDefinition = serde_yaml::from_str(frontmatter)
.map_err(|e| SubagentError::Parse(format!("Failed to parse YAML: {}", e)))?;
Self::validate_definition(&mut definition)?;
Ok((definition, body.to_string()))
}
pub fn parse_directory(dir: &Path) -> SubagentResult<Vec<(SubagentDefinition, String)>> {
if !dir.exists() {
return Ok(Vec::new());
}
let mut agents = Vec::new();
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("md") {
match Self::parse_file(&path) {
Ok(agent) => agents.push(agent),
Err(e) => {
crate::utils::common::logging::log_parse_warning(
&path.display().to_string(),
&e,
);
}
}
}
}
Ok(agents)
}
pub fn validate_definition(definition: &mut SubagentDefinition) -> SubagentResult<()> {
if definition.name.is_empty() {
return Err(SubagentError::Validation(
"Subagent name cannot be empty".to_string(),
));
}
if definition.description.is_empty() {
return Err(SubagentError::Validation(
"Subagent description cannot be empty".to_string(),
));
}
if definition.tools.standard.is_empty()
&& definition.tools.semantic.is_empty()
&& definition.tools.memory.is_empty()
&& definition.tools.custom.is_empty()
{
return Err(SubagentError::Validation(
"Subagent must have at least one tool".to_string(),
));
}
if definition.capabilities.is_empty() {
return Err(SubagentError::Validation(
"Subagent must have at least one capability".to_string(),
));
}
Ok(())
}
}