use super::{
SubagentConfig, SubagentDefinition, SubagentError, SubagentResult,
parser::SubagentParser,
spawner::{DynamicSpawner, SpawnerConfig},
workload_balancer::WorkloadBalancer,
};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct SubagentManager {
config: SubagentConfig,
agents: Arc<RwLock<HashMap<String, SubagentInstance>>>,
definitions: Arc<RwLock<HashMap<String, (SubagentDefinition, String)>>>,
}
#[derive(Debug, Clone)]
pub struct SubagentInstance {
pub definition: SubagentDefinition,
pub instructions: String,
pub status: SubagentStatus,
pub session_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum SubagentStatus {
Available,
Busy,
Initializing,
Error(String),
}
impl SubagentManager {
pub fn new(config: SubagentConfig) -> Self {
Self {
config,
agents: Arc::new(RwLock::new(HashMap::new())),
definitions: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn create_spawner_from(manager: Arc<RwLock<Self>>) -> DynamicSpawner {
let spawner_config = SpawnerConfig::default();
DynamicSpawner::new(manager, spawner_config)
}
pub fn create_balancer(&self) -> WorkloadBalancer {
WorkloadBalancer::with_defaults()
}
pub async fn select_agent_for_task(
&self,
required_capabilities: &[String],
) -> SubagentResult<String> {
let agents = self.agents.read().await;
let available: Vec<_> = agents
.iter()
.filter(|(_, a)| a.status == SubagentStatus::Available)
.map(|(id, _)| id.clone())
.collect();
if available.is_empty() {
return Err(SubagentError::Delegation(
"No available agents for task".to_string(),
));
}
let balancer = self.create_balancer();
balancer
.select_agent(&available, required_capabilities, None, 0)
.await
}
pub async fn initialize(&self) -> SubagentResult<()> {
let definitions = SubagentParser::parse_directory(&self.config.agents_dir)?;
let mut defs = self.definitions.write().await;
for (definition, instructions) in definitions {
log::info!("Loaded subagent definition: {}", definition.name);
defs.insert(definition.name.clone(), (definition, instructions));
}
log::info!(
"Initialized SubagentManager with {} definitions",
defs.len()
);
Ok(())
}
pub async fn create_subagent(&self, name: &str) -> SubagentResult<String> {
let definitions = self.definitions.read().await;
let (definition, instructions) = definitions
.get(name)
.ok_or_else(|| SubagentError::NotFound(name.to_string()))?
.clone();
let agents = self.agents.read().await;
let active_count = agents
.values()
.filter(|a| matches!(a.status, SubagentStatus::Busy | SubagentStatus::Available))
.count();
if active_count >= self.config.max_concurrent_agents {
return Err(SubagentError::Validation(format!(
"Maximum concurrent agents ({}) reached",
self.config.max_concurrent_agents
)));
}
drop(agents);
let instance = SubagentInstance {
definition,
instructions,
status: SubagentStatus::Initializing,
session_id: None,
};
let instance_id = format!("{}-{}", name, uuid::Uuid::new_v4());
let mut agents = self.agents.write().await;
agents.insert(instance_id.clone(), instance);
log::info!("Created subagent instance: {}", instance_id);
let self_clone = self.clone();
let id_clone = instance_id.clone();
tokio::spawn(async move {
if let Err(e) = self_clone.initialize_subagent(&id_clone).await {
crate::utils::common::logging::log_init_failure("subagent", &id_clone, &e);
}
});
Ok(instance_id)
}
async fn initialize_subagent(&self, instance_id: &str) -> SubagentResult<()> {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
let mut agents = self.agents.write().await;
if let Some(agent) = agents.get_mut(instance_id) {
agent.session_id = Some(format!("session-{}", instance_id));
agent.status = SubagentStatus::Available;
log::info!("Subagent {} initialized successfully", instance_id);
}
Ok(())
}
pub async fn get_status(&self, instance_id: &str) -> Option<SubagentStatus> {
let agents = self.agents.read().await;
agents.get(instance_id).map(|a| a.status.clone())
}
pub async fn list_definitions(&self) -> Vec<String> {
let definitions = self.definitions.read().await;
definitions.keys().cloned().collect()
}
pub async fn list_instances(&self) -> HashMap<String, SubagentStatus> {
let agents = self.agents.read().await;
agents
.iter()
.map(|(id, agent)| (id.clone(), agent.status.clone()))
.collect()
}
pub async fn delegate_task(&self, instance_id: &str, task: &str) -> SubagentResult<String> {
let mut agents = self.agents.write().await;
let agent = agents
.get_mut(instance_id)
.ok_or_else(|| SubagentError::NotFound(instance_id.to_string()))?;
if agent.status != SubagentStatus::Available {
return Err(SubagentError::Delegation(format!(
"Subagent {} is not available",
instance_id
)));
}
agent.status = SubagentStatus::Busy;
let task_id = format!("task-{}", uuid::Uuid::new_v4());
log::info!("Delegated task to subagent {}: {}", instance_id, task);
Ok(task_id)
}
pub async fn complete_task(&self, instance_id: &str) -> SubagentResult<()> {
let mut agents = self.agents.write().await;
if let Some(agent) = agents.get_mut(instance_id) {
agent.status = SubagentStatus::Available;
log::info!("Subagent {} completed task", instance_id);
}
Ok(())
}
pub async fn remove_subagent(&self, instance_id: &str) -> SubagentResult<()> {
let mut agents = self.agents.write().await;
if agents.remove(instance_id).is_some() {
log::info!("Removed subagent instance: {}", instance_id);
Ok(())
} else {
Err(SubagentError::NotFound(instance_id.to_string()))
}
}
pub async fn create_dynamic_definition(
&self,
name: String,
description: String,
tools: super::SubagentTools,
capabilities: Vec<String>,
instructions: String,
) -> SubagentResult<()> {
if !self.config.enable_dynamic_generation {
return Err(SubagentError::Validation(
"Dynamic subagent generation is disabled".to_string(),
));
}
let definition = SubagentDefinition {
name: name.clone(),
description,
tools,
capabilities,
metadata: HashMap::new(),
execution_config: Default::default(),
resource_limits: Default::default(),
spawn_context: None,
handoff_config: None,
};
SubagentParser::validate_definition(&mut definition.clone())?;
let mut definitions = self.definitions.write().await;
definitions.insert(name.clone(), (definition, instructions));
log::info!("Created dynamic subagent definition: {}", name);
Ok(())
}
}
impl Clone for SubagentManager {
fn clone(&self) -> Self {
Self {
config: self.config.clone(),
agents: Arc::clone(&self.agents),
definitions: Arc::clone(&self.definitions),
}
}
}