From 33ed54396cf8b650cb1d5f6a6c1ebe429db04b43 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 8 Apr 2026 19:45:18 -0400 Subject: [PATCH] Fix output() tool for forked agents: extract from AST after tool turns The old dispatch_tools intercepted output() calls and stored them in auto.outputs. The new Agent::turn() dispatches normally, so output() was hitting the filesystem path (which fails without POC_AGENT_OUTPUT_DIR). Now run_with_backend scans the conversation AST after each tool turn and extracts output() call arguments into auto.outputs. collect_results in dmn.rs reads these to surface memories and inject reflections. Co-Authored-By: Proof of Concept --- src/agent/oneshot.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/agent/oneshot.rs b/src/agent/oneshot.rs index 9c31307..b865363 100644 --- a/src/agent/oneshot.rs +++ b/src/agent/oneshot.rs @@ -165,6 +165,28 @@ impl AutoAgent { .map_err(|e| format!("{}: {}", self.name, e))?; if result.had_tool_calls { + // Extract output() calls from the conversation + let ctx = backend.0.context.lock().await; + for node in ctx.conversation() { + if let super::context::AstNode::Branch { children, .. } = node { + for child in children { + if let Some(leaf) = child.leaf() { + if let super::context::NodeBody::ToolCall { name, arguments } = leaf.body() { + if name == "output" { + if let Ok(args) = serde_json::from_str::(arguments) { + let key = args["key"].as_str().unwrap_or(""); + let value = args["value"].as_str().unwrap_or(""); + if !key.is_empty() { + self.outputs.insert(key.to_string(), value.to_string()); + } + } + } + } + } + } + } + } + drop(ctx); continue; }