Add graph_topology, graph_health, interference_pairs tools

Convert {{topology}}, {{health}}, {{pairs}} placeholders to
{{tool:}} calls. Made format_topology_header, format_health_section,
format_pairs_section pub so tools can call them.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
ProofOfConcept 2026-04-10 15:25:57 -04:00
parent 1a03264233
commit fd722662da
9 changed files with 49 additions and 13 deletions

View file

@ -33,7 +33,7 @@ async fn get_provenance(agent: &Option<std::sync::Arc<crate::agent::Agent>>) ->
// ── Definitions ────────────────────────────────────────────────
pub fn memory_tools() -> [super::Tool; 11] {
pub fn memory_tools() -> [super::Tool; 14] {
use super::Tool;
[
Tool { name: "memory_render", description: "Read a memory node's content and links.",
@ -69,6 +69,15 @@ pub fn memory_tools() -> [super::Tool; 11] {
Tool { name: "memory_query", description: "Run a structured query against the memory graph.",
parameters_json: r#"{"type":"object","properties":{"query":{"type":"string","description":"Query expression"}},"required":["query"]}"#,
handler: Arc::new(|_a, v| Box::pin(async move { query(&v).await })) },
Tool { name: "graph_topology", description: "Show graph topology stats (nodes, edges, clustering, hubs).",
parameters_json: r#"{"type":"object","properties":{}}"#,
handler: Arc::new(|_a, _v| Box::pin(async { graph_topology().await })) },
Tool { name: "graph_health", description: "Show graph health report with maintenance recommendations.",
parameters_json: r#"{"type":"object","properties":{}}"#,
handler: Arc::new(|_a, _v| Box::pin(async { graph_health().await })) },
Tool { name: "interference_pairs", description: "Find similar nodes that may interfere (duplicates or near-duplicates).",
parameters_json: r#"{"type":"object","properties":{"threshold":{"type":"number","description":"Similarity threshold (default 0.5)"},"limit":{"type":"integer","description":"Max pairs to return (default 10)"}}}"#,
handler: Arc::new(|_a, v| Box::pin(async move { interference_pairs(&v).await })) },
]
}
@ -317,3 +326,30 @@ async fn journal_update(agent: &Option<std::sync::Arc<crate::agent::Agent>>, arg
let word_count = body.split_whitespace().count();
Ok(format!("Updated last entry (+{} words)", word_count))
}
// ── Graph tools ───────────────────────────────────────────────
async fn graph_topology() -> Result<String> {
let arc = cached_store().await?;
let store = arc.lock().await;
let graph = store.build_graph();
Ok(crate::subconscious::prompts::format_topology_header(&graph))
}
async fn graph_health() -> Result<String> {
let arc = cached_store().await?;
let store = arc.lock().await;
let graph = store.build_graph();
Ok(crate::subconscious::prompts::format_health_section(&store, &graph))
}
async fn interference_pairs(args: &serde_json::Value) -> Result<String> {
let threshold = args.get("threshold").and_then(|v| v.as_f64()).unwrap_or(0.5) as f32;
let limit = args.get("limit").and_then(|v| v.as_u64()).unwrap_or(10) as usize;
let arc = cached_store().await?;
let store = arc.lock().await;
let graph = store.build_graph();
let mut pairs = crate::neuro::detect_interference(&store, &graph, threshold);
pairs.truncate(limit);
Ok(crate::subconscious::prompts::format_pairs_section(&pairs, &store, &graph))
}