tools: route all dispatch through Tool registry

dispatch() and dispatch_shared() now look up tools by name in the
registry and call the handler directly. No more match-on-name-strings.

MCP server also uses the registry for both definitions and dispatch,
eliminating the last duplicated tool logic.

dispatch_with_agent() passes the optional Arc<Mutex<Agent>> through
for tools that need agent context (control tools, working stack).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
ProofOfConcept 2026-04-04 15:10:13 -04:00 committed by Kent Overstreet
parent 3e6c77e31e
commit 03cf13e9eb
2 changed files with 46 additions and 83 deletions

View file

@ -68,34 +68,32 @@ fn notify(method: &str, params: Value) {
// ── Tool definitions ────────────────────────────────────────────
fn tool_definitions() -> Vec<Value> {
use poc_memory::agent::tools;
let all_defs = tools::memory::definitions().into_iter()
.chain(tools::channels::definitions());
all_defs.map(|td| json!({
"name": td.function.name,
"description": td.function.description,
"inputSchema": td.function.parameters,
})).collect()
poc_memory::agent::tools::tools().into_iter()
.map(|t| json!({
"name": t.def.function.name,
"description": t.def.function.description,
"inputSchema": t.def.function.parameters,
}))
.collect()
}
// ── Tool dispatch ───────────────────────────────────────────────
fn dispatch_tool(name: &str, args: &Value) -> Result<String, String> {
use poc_memory::agent::tools;
let tools = poc_memory::agent::tools::tools();
let tool = tools.iter().find(|t| t.def.function.name == name);
let Some(tool) = tool else {
return Err(format!("unknown tool: {name}"));
};
if name.starts_with("memory_") || name.starts_with("journal_") || name == "output" {
return tools::memory::dispatch(name, args, None)
.map_err(|e| e.to_string());
}
if name.starts_with("channel_") {
return tools::channels::dispatch_blocking(name, args)
.map_err(|e| e.to_string());
}
Err(format!("unknown tool: {name}"))
// Run async handler on a blocking runtime
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| e.to_string())?;
let local = tokio::task::LocalSet::new();
local.block_on(&rt, (tool.handler)(None, args.clone()))
.map_err(|e| e.to_string())
}
// ── Main loop ───────────────────────────────────────────────────