//! Per-topology heuristics: a default role mix + a short rationale. //! //! Ported/adapted from agentorg's `topology_manager.py` role distributions. //! These guide how the orchestrator (Phase 2) staffs a topology and how the //! evolution layer (Phase 5) biases search; they are advisory, not hard rules. use crate::kind::TopologyKind; /// Advisory staffing/optimization hints for a topology. #[derive(Debug, Clone, Copy)] pub struct Heuristics { /// Suggested fraction of agents per role (sums to ~1.0). pub role_distribution: &'static [(&'static str, f32)], /// Why this mix suits the topology. pub notes: &'static str, } /// Heuristics for a given topology kind. Every kind is covered. pub fn heuristics(kind: TopologyKind) -> Heuristics { use TopologyKind::*; match kind { Hierarchical => Heuristics { role_distribution: &[ ("coordinator", 0.15), ("executor", 0.60), ("analyst", 0.15), ("innovator", 0.05), ("validator", 0.05), ], notes: "few coordinators, many executors; optimize span of control and depth", }, Flat => Heuristics { role_distribution: &[ ("coordinator", 0.05), ("executor", 0.30), ("analyst", 0.25), ("innovator", 0.25), ("validator", 0.15), ], notes: "high autonomy; reward peer collaboration, penalize consensus drag", }, Pipeline => Heuristics { role_distribution: &[ ("coordinator", 0.10), ("executor", 0.55), ("analyst", 0.15), ("innovator", 0.05), ("validator", 0.15), ], notes: "stage specialists in sequence; validators between stages", }, Swarm => Heuristics { role_distribution: &[ ("coordinator", 0.10), ("executor", 0.25), ("analyst", 0.25), ("innovator", 0.25), ("validator", 0.15), ], notes: "value diversity, reward emergent behavior, penalize redundancy", }, Mesh => Heuristics { role_distribution: &[ ("coordinator", 0.05), ("executor", 0.30), ("analyst", 0.30), ("innovator", 0.20), ("validator", 0.15), ], notes: "dense peer exchange; analysts dominate to converge information", }, HubSpoke => Heuristics { role_distribution: &[ ("coordinator", 0.30), ("executor", 0.50), ("analyst", 0.10), ("innovator", 0.05), ("validator", 0.05), ], notes: "central hub coordinates; cap hub fan-out, reward routing efficiency", }, Ring => Heuristics { role_distribution: &[ ("coordinator", 0.10), ("executor", 0.40), ("analyst", 0.20), ("innovator", 0.15), ("validator", 0.15), ], notes: "sequential cycles; reward cycle completion and bidirectional flow", }, StarMoe => Heuristics { role_distribution: &[ ("coordinator", 0.15), ("executor", 0.55), ("analyst", 0.20), ("innovator", 0.05), ("validator", 0.05), ], notes: "a router dispatches to specialist experts; reward routing accuracy", }, Market => Heuristics { role_distribution: &[ ("coordinator", 0.10), ("executor", 0.55), ("analyst", 0.20), ("innovator", 0.05), ("validator", 0.10), ], notes: "agents bid on tasks by fit/cost; reward allocative efficiency", }, Blackboard => Heuristics { role_distribution: &[ ("coordinator", 0.10), ("executor", 0.35), ("analyst", 0.30), ("innovator", 0.15), ("validator", 0.10), ], notes: "shared workspace; analysts synthesize contributions opportunistically", }, Debate => Heuristics { role_distribution: &[ ("coordinator", 0.10), ("executor", 0.35), ("analyst", 0.20), ("innovator", 0.20), ("validator", 0.15), ], notes: "proposer vs critic with a judge; reward decisive, well-argued outcomes", }, Holacratic => Heuristics { role_distribution: &[ ("coordinator", 0.20), ("executor", 0.30), ("analyst", 0.20), ("innovator", 0.20), ("validator", 0.10), ], notes: "self-organizing circles; reward clear roles and tension resolution", }, } } #[cfg(test)] mod tests { use super::*; #[test] fn every_kind_has_valid_distribution() { for k in TopologyKind::ALL { let h = heuristics(k); assert!(!h.role_distribution.is_empty(), "{} empty", k.as_str()); assert!(!h.notes.is_empty()); let sum: f32 = h.role_distribution.iter().map(|(_, w)| *w).sum(); assert!( (sum - 1.0).abs() < 0.01, "{} role distribution sums to {sum}, expected ~1.0", k.as_str() ); } } }