feat(topology): cm-topology crate + architecture doc (Phases 0–1)
Foundation for the dynamic agentic-topologies platform (see docs/topology-platform.md), porting agentorg's topology modeling into pure Rust: - TopologyKind: curated 12-kind taxonomy (hierarchical, flat, pipeline, swarm, mesh, hub_spoke, ring, star_moe, market, blackboard, debate, holacratic). - TopologyGraph: role-slot nodes + typed edges, with validation. - adapter: normalize a loose JSON spec → validated graph (fills edge kinds). - classifier: structural metrics (density, hub dominance, clustering, diameter, hierarchy score) → inferred kind + confidence (tree→hierarchical, line→pipeline, cycle→ring, star→hub_spoke, complete→mesh, empty→flat). - heuristics: per-kind role distributions (ported from topology_manager.py). Pure, offline, dependency-light (serde/thiserror). 17 unit tests, clippy clean. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
34da54ccaa
commit
817d8c712c
@@ -0,0 +1,113 @@
|
||||
//! The curated taxonomy of execution-meaningful topologies (v1).
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An organizational topology pattern. The v1 set covers shapes that differ
|
||||
/// *in how a task executes*; governance/novel forms are deferred.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TopologyKind {
|
||||
/// Tree: an orchestrator delegates down; results bubble up.
|
||||
Hierarchical,
|
||||
/// Autonomous peers with minimal coordination.
|
||||
Flat,
|
||||
/// Linear stages: output of stage n feeds stage n+1.
|
||||
Pipeline,
|
||||
/// Parallel attempts with consensus/aggregation.
|
||||
Swarm,
|
||||
/// Dense peer-to-peer exchange until convergence.
|
||||
Mesh,
|
||||
/// A central hub routes to spokes and aggregates.
|
||||
HubSpoke,
|
||||
/// A cycle: sequential round-trips, refining each lap.
|
||||
Ring,
|
||||
/// Router + experts (mixture-of-experts).
|
||||
StarMoe,
|
||||
/// Tasks auctioned to agents by fit/cost.
|
||||
Market,
|
||||
/// Agents read/write a shared workspace.
|
||||
Blackboard,
|
||||
/// Adversarial proposer vs critic rounds, then a judge.
|
||||
Debate,
|
||||
/// Self-organizing circles assign within roles.
|
||||
Holacratic,
|
||||
}
|
||||
|
||||
impl TopologyKind {
|
||||
/// Every supported kind, for iteration in tests/UIs/benchmarks.
|
||||
pub const ALL: [TopologyKind; 12] = [
|
||||
TopologyKind::Hierarchical,
|
||||
TopologyKind::Flat,
|
||||
TopologyKind::Pipeline,
|
||||
TopologyKind::Swarm,
|
||||
TopologyKind::Mesh,
|
||||
TopologyKind::HubSpoke,
|
||||
TopologyKind::Ring,
|
||||
TopologyKind::StarMoe,
|
||||
TopologyKind::Market,
|
||||
TopologyKind::Blackboard,
|
||||
TopologyKind::Debate,
|
||||
TopologyKind::Holacratic,
|
||||
];
|
||||
|
||||
/// The snake_case wire name (matches the serde representation).
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
TopologyKind::Hierarchical => "hierarchical",
|
||||
TopologyKind::Flat => "flat",
|
||||
TopologyKind::Pipeline => "pipeline",
|
||||
TopologyKind::Swarm => "swarm",
|
||||
TopologyKind::Mesh => "mesh",
|
||||
TopologyKind::HubSpoke => "hub_spoke",
|
||||
TopologyKind::Ring => "ring",
|
||||
TopologyKind::StarMoe => "star_moe",
|
||||
TopologyKind::Market => "market",
|
||||
TopologyKind::Blackboard => "blackboard",
|
||||
TopologyKind::Debate => "debate",
|
||||
TopologyKind::Holacratic => "holacratic",
|
||||
}
|
||||
}
|
||||
|
||||
/// One-line human description.
|
||||
pub fn description(&self) -> &'static str {
|
||||
match self {
|
||||
TopologyKind::Hierarchical => "orchestrator delegates down; results bubble up",
|
||||
TopologyKind::Flat => "autonomous peers with minimal coordination",
|
||||
TopologyKind::Pipeline => "linear stages; each feeds the next",
|
||||
TopologyKind::Swarm => "parallel attempts with consensus/aggregation",
|
||||
TopologyKind::Mesh => "dense peer-to-peer exchange until convergence",
|
||||
TopologyKind::HubSpoke => "a central hub routes to spokes and aggregates",
|
||||
TopologyKind::Ring => "a cycle refining the result each lap",
|
||||
TopologyKind::StarMoe => "a router dispatches subtasks to experts",
|
||||
TopologyKind::Market => "tasks auctioned to agents by fit/cost",
|
||||
TopologyKind::Blackboard => "agents collaborate via a shared workspace",
|
||||
TopologyKind::Debate => "proposer vs critic rounds, then a judge",
|
||||
TopologyKind::Holacratic => "self-organizing circles assign within roles",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn as_str_matches_serde() {
|
||||
for k in TopologyKind::ALL {
|
||||
let json = serde_json::to_string(&k).unwrap();
|
||||
assert_eq!(json, format!("\"{}\"", k.as_str()));
|
||||
let back: TopologyKind = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(back, k);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_is_complete_and_unique() {
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for k in TopologyKind::ALL {
|
||||
assert!(seen.insert(k.as_str()), "duplicate in ALL: {}", k.as_str());
|
||||
assert!(!k.description().is_empty());
|
||||
}
|
||||
assert_eq!(seen.len(), 12);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user