use anyhow::Result;
use selfware::config::Config;
use selfware::multiagent::{MultiAgentChat, MultiAgentConfig, MultiAgentEvent};
use selfware::swarm::AgentRole;
use tokio::sync::mpsc;
#[tokio::main]
async fn main() -> Result<()> {
println!("=== Selfware Multi-Agent Example ===\n");
let config = Config::load(None)?;
println!("Endpoint: {}", config.endpoint);
println!("Model: {}", config.model);
println!();
let agent_config = MultiAgentConfig {
max_concurrency: 4,
roles: vec![
AgentRole::Architect, AgentRole::Coder, AgentRole::Tester, AgentRole::Reviewer, ],
streaming: true,
timeout_secs: 120,
temperature: 0.7,
max_tokens: 4096,
failure_policy: selfware::multiagent::MultiAgentFailurePolicy::BestEffort,
};
println!("Multi-Agent Configuration:");
println!(" Max concurrency: {}", agent_config.max_concurrency);
println!(
" Roles: {:?}",
agent_config
.roles
.iter()
.map(|r| r.name())
.collect::<Vec<_>>()
);
println!(" Timeout: {}s per agent", agent_config.timeout_secs);
println!();
let (event_tx, mut event_rx) = mpsc::channel::<MultiAgentEvent>(1000);
let multi_agent = MultiAgentChat::new(&config, agent_config)?.with_events(event_tx);
let task = r#"
Design and review a Rust function that finds all prime numbers up to N
using the Sieve of Eratosthenes algorithm.
Consider:
- API design and function signature
- Implementation efficiency
- Edge cases and error handling
- Test cases for validation
"#;
println!("Task:\n{}\n", task.trim());
println!("--- Running Multi-Agent Task ---\n");
let event_handler = tokio::spawn(async move {
while let Some(event) = event_rx.recv().await {
match event {
MultiAgentEvent::AgentStarted { name, task, .. } => {
println!(
"[START] {} - Working on: {}...",
name,
&task[..40.min(task.len())]
);
}
MultiAgentEvent::AgentToolCall { agent_id, tool } => {
println!("[TOOL] Agent-{} calling: {}", agent_id, tool);
}
MultiAgentEvent::AgentCompleted { result, .. } => {
let status = if result.success { "OK" } else { "FAILED" };
println!(
"[DONE] {} ({}) - {} in {:.2}s",
result.agent_name,
result.role.name(),
status,
result.duration.as_secs_f64()
);
}
MultiAgentEvent::AgentFailed { agent_id, error } => {
println!("[ERROR] Agent-{} failed: {}", agent_id, error);
}
MultiAgentEvent::AllCompleted {
results,
total_duration,
} => {
let success_count = results.iter().filter(|r| r.success).count();
println!(
"\n[SUMMARY] {}/{} agents completed in {:.2}s",
success_count,
results.len(),
total_duration.as_secs_f64()
);
break;
}
_ => {}
}
}
});
let results = multi_agent.run_task(task).await?;
let _ = event_handler.await;
println!("\n--- Agent Responses ---\n");
for result in &results {
if result.success {
println!("=== {} ({}) ===", result.agent_name, result.role.name());
println!();
let preview = if result.content.len() > 500 {
let mut end = 500;
while end > 0 && !result.content.is_char_boundary(end) {
end -= 1;
}
format!(
"{}...\n[{} more characters]",
&result.content[..end],
result.content.len() - end
)
} else {
result.content.clone()
};
println!("{}", preview);
println!();
} else {
println!("=== {} (FAILED) ===", result.agent_name);
if let Some(ref error) = result.error {
println!("Error: {}", error);
}
println!();
}
}
let summary = MultiAgentChat::aggregate_results(&results);
println!("--- Aggregated Summary ---\n");
println!(
"Total response length: {} characters across {} agents",
summary.len(),
results.len()
);
Ok(())
}