//! # Agent Selection Example //! //! Demonstrates how agents are ranked and selected based on expertise and load. //! //! ## What This Example Shows //! - Comparing multiple agents for a task //! - Understanding the scoring formula: 0.3*load + 0.5*expertise + //! 0.2*confidence //! - How load balancing prevents over-allocation //! - Real-world selection decisions //! //! ## Run //! ```bash //! cargo run --example 03-agent-selection -p vapora-agents //! ``` fn main() { println!("=== Agent Selection Example ===\n"); // Step 1: Define agent profiles with different characteristics #[derive(Debug, Clone)] struct AgentProfile { name: String, expertise: f64, // 0.0 to 1.0 confidence: f64, // 0.0 to 1.0 (based on sample size) current_load: f64, // 0.0 to 1.0 } let agents = vec![ AgentProfile { name: "alice".to_string(), expertise: 0.92, confidence: 0.95, current_load: 0.30, // Moderately busy }, AgentProfile { name: "bob".to_string(), expertise: 0.78, confidence: 0.85, current_load: 0.05, // Very available }, AgentProfile { name: "carol".to_string(), expertise: 0.88, confidence: 0.70, current_load: 0.50, // Quite busy }, ]; println!("Available agents for 'coding' task:\n"); for agent in &agents { println!( " {}: expertise={:.0}%, confidence={:.0}%, load={:.0}%", agent.name, agent.expertise * 100.0, agent.confidence * 100.0, agent.current_load * 100.0 ); } // Step 2: Apply scoring formula println!("\n=== Scoring Formula ==="); println!("score = (1 - 0.3*load) + 0.5*expertise + 0.2*confidence"); println!(" ↓ ↓ ↓"); println!(" availability expertise confidence/trust\n"); // Normalize load contribution (lower load = higher score) let scores: Vec<_> = agents .iter() .map(|agent| { let availability = 1.0 - (0.3 * agent.current_load); let expertise_score = 0.5 * agent.expertise; let confidence_score = 0.2 * agent.confidence; let total = availability + expertise_score + confidence_score; ( agent, availability, expertise_score, confidence_score, total, ) }) .collect(); println!("Agent Scores:"); for (agent, avail, exp, conf, total) in &scores { println!( "\n {}: {:.3} (avail={:.3}, exp={:.3}, conf={:.3})", agent.name, total, avail, exp, conf ); } // Step 3: Rank agents let mut sorted_scores = scores.clone(); sorted_scores.sort_by(|a, b| b.4.partial_cmp(&a.4).unwrap_or(std::cmp::Ordering::Equal)); println!("\n=== Ranking (Best → Worst) ==="); for (rank, (agent, _, _, _, total)) in sorted_scores.iter().enumerate() { let medal = match rank { 0 => "🥇", 1 => "🥈", 2 => "🥉", _ => " ", }; println!( "{} {}. {} (score: {:.3})", medal, rank + 1, agent.name, total ); } // Step 4: Selection decision let best_agent = sorted_scores[0].0; println!("\n=== Selection Decision ==="); println!("Assigned to: {}", best_agent.name); println!( "Reason: Best balance of expertise ({:.0}%), availability ({:.0}%), and confidence \ ({:.0}%)", best_agent.expertise * 100.0, (1.0 - (0.3 * best_agent.current_load)) * 100.0, best_agent.confidence * 100.0 ); // Step 5: Demonstrate impact of load balancing println!("\n=== Load Balancing Impact ==="); println!("If alice wasn't available (hypothetical):"); let mut remaining = sorted_scores.clone(); remaining.remove(0); let second_best = &remaining[0].0; println!( " → Would select: {} (score: {:.3})", second_best.name, remaining[0].4 ); println!("\nWithout load balancing, carol would be selected despite:"); println!(" - Lower expertise (88% vs 92%)"); println!(" - Same recent success rate"); println!(" BUT: It's already running at 50% capacity!"); }