diff --git a/src/agent/tools/memory.rs b/src/agent/tools/memory.rs index 690718c..466b204 100644 --- a/src/agent/tools/memory.rs +++ b/src/agent/tools/memory.rs @@ -122,6 +122,7 @@ async fn dispatch( "memory_query" => query(&args).await, "graph_topology" => graph_topology().await, "graph_health" => graph_health().await, + "graph_communities" => graph_communities(&args).await, "journal_tail" => journal_tail(&args).await, "journal_new" => journal_new(agent, &args).await, "journal_update" => journal_update(agent, &args).await, @@ -573,3 +574,43 @@ async fn graph_health() -> Result { let graph = store.build_graph(); Ok(crate::subconscious::prompts::format_health_section(&store, &graph)) } + +async fn graph_communities(args: &serde_json::Value) -> Result { + let top_n = args.get("top_n").and_then(|v| v.as_u64()).unwrap_or(10) as usize; + let min_size = args.get("min_size").and_then(|v| v.as_u64()).unwrap_or(3) as usize; + + let arc = cached_store().await?; + let store = arc.lock().await; + let g = store.build_graph(); + let infos = g.community_info(); + + let total = infos.len(); + let shown: Vec<_> = infos.into_iter() + .filter(|c| c.size >= min_size) + .take(top_n) + .collect(); + + use std::fmt::Write; + let mut out = String::new(); + writeln!(out, "{} communities total ({} with size >= {})\n", + total, shown.len(), min_size).ok(); + writeln!(out, "{:<6} {:>5} {:>7} {:>7} members", "id", "size", "iso", "cross").ok(); + writeln!(out, "{}", "-".repeat(70)).ok(); + + for c in &shown { + let preview: Vec<&str> = c.members.iter() + .take(5) + .map(|s| s.as_str()) + .collect(); + let more = if c.size > 5 { + format!(" +{}", c.size - 5) + } else { + String::new() + }; + writeln!(out, "{:<6} {:>5} {:>6.0}% {:>7} {}{}", + c.id, c.size, c.isolation * 100.0, c.cross_edges, + preview.join(", "), more).ok(); + } + + Ok(out) +} diff --git a/src/cli/graph.rs b/src/cli/graph.rs index 89840cd..10eb9a0 100644 --- a/src/cli/graph.rs +++ b/src/cli/graph.rs @@ -354,36 +354,11 @@ pub fn cmd_organize(term: &str, key_only: bool, create_anchor: bool) -> Result<( /// Useful for finding poorly-integrated knowledge clusters that need /// organize agents aimed at them. pub fn cmd_communities(top_n: usize, min_size: usize) -> Result<(), String> { - let store = store::Store::load()?; - let g = store.build_graph(); - let infos = g.community_info(); - - let total = infos.len(); - let shown: Vec<_> = infos.into_iter() - .filter(|c| c.size >= min_size) - .take(top_n) - .collect(); - - println!("{} communities total ({} with size >= {})\n", - total, shown.len(), min_size); - println!("{:<6} {:>5} {:>7} {:>7} members", "id", "size", "iso", "cross"); - println!("{}", "-".repeat(70)); - - for c in &shown { - let preview: Vec<&str> = c.members.iter() - .take(5) - .map(|s| s.as_str()) - .collect(); - let more = if c.size > 5 { - format!(" +{}", c.size - 5) - } else { - String::new() - }; - println!("{:<6} {:>5} {:>6.0}% {:>7} {}{}", - c.id, c.size, c.isolation * 100.0, c.cross_edges, - preview.join(", "), more); - } - + let result = crate::mcp_server::memory_rpc( + "graph_communities", + serde_json::json!({"top_n": top_n, "min_size": min_size}), + ).map_err(|e| e.to_string())?; + print!("{}", result); Ok(()) }