use super::delegation::DelegationManager;
use super::handoff::HandoffManager;
use super::scheduler::ConcurrencyScheduler;
use super::team::TeamManager;
use super::{AgentCapability, AgentInfo, SwarmStorage, Task, TaskPriority, TaskStatus};
use anyhow::Result;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct SwarmCoordinator {
storage: Arc<dyn SwarmStorage>,
message_queue: Arc<RwLock<Vec<String>>>,
pub delegation: DelegationManager,
pub teams: TeamManager,
pub handoffs: HandoffManager,
pub scheduler: Arc<ConcurrencyScheduler>,
}
impl SwarmCoordinator {
pub fn new(storage: Arc<dyn SwarmStorage>) -> Self {
let scheduler = Arc::new(ConcurrencyScheduler::new());
Self {
delegation: DelegationManager::new(storage.clone()),
teams: TeamManager::new(storage.clone()),
handoffs: HandoffManager::new(storage.clone()),
scheduler: scheduler.clone(),
storage,
message_queue: Arc::new(RwLock::new(Vec::new())),
}
}
pub async fn init(&self) -> Result<()> {
self.delegation.sync_counts().await?;
Ok(())
}
pub fn storage(&self) -> &Arc<dyn SwarmStorage> {
&self.storage
}
pub async fn submit_task(
&self,
title: String,
description: String,
priority: TaskPriority,
) -> Result<String> {
let task = Task::new(title, description, priority);
let task_id = task.task_id.clone();
self.storage.store_task(&task).await?;
Ok(task_id)
}
pub async fn assign_task(&self, task_id: &str) -> Result<Option<String>> {
let _task = match self.storage.get_task(task_id).await? {
Some(t) => t,
None => return Ok(None),
};
let agents = self.storage.list_active_agents().await?;
if let Some(agent) = agents.first() {
self.storage
.update_task_status(task_id, TaskStatus::Running)
.await?;
return Ok(Some(agent.agent_id.clone()));
}
Ok(None)
}
pub async fn register_agent(
&self,
name: String,
capabilities: Vec<AgentCapability>,
model: Option<String>,
tools: Option<Vec<String>>,
) -> Result<String> {
let mut agent = AgentInfo::new(name, capabilities);
if let Some(m) = model {
agent = agent.with_model(m);
}
if let Some(t) = tools {
agent = agent.with_tools(t);
}
let agent_id = agent.agent_id.clone();
self.storage.register_agent(&agent).await?;
Ok(agent_id)
}
pub async fn heartbeat(&self, agent_id: &str) -> Result<()> {
self.storage.update_agent_heartbeat(agent_id).await
}
pub async fn queue_message(&self, message: String) {
let mut queue = self.message_queue.write().await;
queue.push(message);
}
pub async fn pop_message(&self) -> Option<String> {
let mut queue = self.message_queue.write().await;
if !queue.is_empty() {
Some(queue.remove(0))
} else {
None
}
}
pub async fn list_pending_tasks(&self) -> Result<Vec<Task>> {
self.storage.list_pending_tasks().await
}
pub async fn list_active_agents(&self) -> Result<Vec<AgentInfo>> {
self.storage.list_active_agents().await
}
pub async fn list_all_agents(&self) -> Result<Vec<AgentInfo>> {
self.storage.list_all_agents().await
}
pub async fn get_agent_by_name(&self, name: &str) -> Result<Option<AgentInfo>> {
self.storage.get_agent_by_name(name).await
}
pub async fn deploy_parallel_agents(
&self,
runner: Arc<crate::agent::AgentRunner>,
tasks: Vec<String>,
base_chat_id: &str,
parallelism: usize,
) -> Vec<(String, String)> {
let parallelism = parallelism.max(1);
let mut all_results = Vec::new();
for (chunk_idx, chunk) in tasks.chunks(parallelism).enumerate() {
let handles: Vec<_> = chunk
.iter()
.enumerate()
.map(|(i, task)| {
let coordinator = Arc::new(self.clone_for_worker());
let runner = runner.clone();
let chat_id = format!("{}_sw{}_{}", base_chat_id, chunk_idx, i);
let task = task.clone();
tokio::spawn(async move {
let slot_id = match coordinator
.scheduler
.acquire_slot("swarm_worker", super::scheduler::Lane::Delegate, &task)
.await
{
Some(id) => id,
None => {
return (task, "⚠️ Swarm lane full, task deferred.".to_string())
}
};
let msg = crate::channels::IncomingMessage {
id: format!("sw_{}_{}", chunk_idx, i),
sender_id: "swarm".to_string(),
sender_name: None,
chat_id,
text: task.clone(),
is_group: false,
reply_to: None,
timestamp: chrono::Utc::now(),
};
let null_ch = crate::agent::mode::NullChannel::new("swarm");
let result = runner
.handle_message(&msg, &null_ch)
.await
.unwrap_or_else(|e| format!("⚠️ Agent error: {}", e));
coordinator.scheduler.release_slot(&slot_id).await;
(task, result)
})
})
.collect();
for handle in handles {
match handle.await {
Ok(result) => all_results.push(result),
Err(e) => tracing::warn!("Swarm worker panicked: {}", e),
}
}
}
all_results
}
fn clone_for_worker(&self) -> Self {
Self {
storage: self.storage.clone(),
message_queue: self.message_queue.clone(),
delegation: DelegationManager::new(self.storage.clone()),
teams: TeamManager::new(self.storage.clone()),
handoffs: HandoffManager::new(self.storage.clone()),
scheduler: self.scheduler.clone(), }
}
}