use anyhow::Result;
use futures::future::join_all;
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
use crate::agent::Agent;
use crate::event::AgentEvent;
use crate::message::{Message, Role};
use crate::runtime::AgentRuntime;
pub async fn discuss(
runtime: &dyn AgentRuntime,
agents: &[Agent],
topic: &str,
rounds: usize,
cancel: CancellationToken,
events: mpsc::Sender<AgentEvent>,
) -> Result<String> {
let mut history: Vec<Message> = vec![Message {
role: Role::User,
content: topic.to_string(),
}];
let mut primary_last_response = String::new();
for round in 1..=rounds {
if cancel.is_cancelled() {
let _ = events.send(AgentEvent::Cancelled).await;
return Ok(String::new());
}
let _ = events
.send(AgentEvent::Progress {
current_round: round,
max_rounds: rounds,
})
.await;
let futs: Vec<_> = agents
.iter()
.map(|agent| {
let snap = history.clone();
async move {
runtime
.respond(agent, &snap)
.await
.map(|content| (agent.name.clone(), content))
}
})
.collect();
let results = join_all(futs).await;
for (agent_name, content) in results.into_iter().flatten() {
if agent_name == agents[0].name {
primary_last_response = content.clone();
}
let _ = events
.send(AgentEvent::Round {
round,
agent_name: agent_name.clone(),
content: content.clone(),
})
.await;
history.push(Message {
role: Role::User,
content: format!("[{agent_name}]: {content}"),
});
}
}
let _ = events
.send(AgentEvent::Summary {
content: primary_last_response.clone(),
})
.await;
let _ = events.send(AgentEvent::Completed).await;
Ok(primary_last_response)
}