In-memory output() tool — no more POC_AGENT_OUTPUT_DIR

AutoAgent intercepts output() tool calls and stores results in an
in-memory HashMap instead of writing to the filesystem. Mind reads
auto.outputs after task completion. Eliminates the env-var-based
output dir which couldn't work with concurrent agents in one process.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-07 02:04:29 -04:00
parent 85aafd206c
commit c2a3844d69
2 changed files with 47 additions and 41 deletions

View file

@ -56,6 +56,9 @@ pub struct AutoAgent {
priority: i32,
/// Memory keys the surface agent was exploring — persists between runs.
pub walked: Vec<String>,
/// Named outputs from the agent's output() tool calls.
/// Collected per-run, read by Mind after completion.
pub outputs: std::collections::HashMap<String, String>,
// Observable status
pub current_phase: String,
pub turn: usize,
@ -159,6 +162,7 @@ impl AutoAgent {
},
priority,
walked: Vec::new(),
outputs: std::collections::HashMap::new(),
current_phase: String::new(),
turn: 0,
}
@ -206,6 +210,7 @@ impl AutoAgent {
bail_fn: Option<&(dyn Fn(usize) -> Result<(), String> + Sync)>,
) -> Result<String, String> {
self.turn = 0;
self.outputs.clear();
self.current_phase = self.steps.first()
.map(|s| s.phase.clone()).unwrap_or_default();
let mut next_step = 0;
@ -238,7 +243,7 @@ impl AutoAgent {
let has_tools = msg.tool_calls.as_ref().is_some_and(|tc| !tc.is_empty());
if has_tools {
Self::dispatch_tools(backend, &msg).await;
self.dispatch_tools(backend, &msg).await;
continue;
}
@ -324,7 +329,7 @@ impl AutoAgent {
unreachable!()
}
async fn dispatch_tools(backend: &mut Backend, msg: &Message) {
async fn dispatch_tools(&mut self, backend: &mut Backend, msg: &Message) {
let mut sanitized = msg.clone();
if let Some(ref mut calls) = sanitized.tool_calls {
for call in calls {
@ -354,7 +359,18 @@ impl AutoAgent {
}
};
let output = agent_tools::dispatch(&call.function.name, &args).await;
// Intercept output() — store in-memory instead of filesystem
let output = if call.function.name == "output" {
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());
}
format!("{}: {}", key, value)
} else {
agent_tools::dispatch(&call.function.name, &args).await
};
backend.log(format!("result: {} chars", output.len()));
backend.push_raw(Message::tool_result(&call.id, &output));
}