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

@ -457,17 +457,30 @@ impl Mind {
};
for (idx, handle) in finished {
let name = self.subconscious.lock().await[idx].auto.name.clone();
let output_dir = crate::store::memory_dir()
.join("agent-output").join(&name);
match handle.await {
Ok(Ok(_output)) => {
// Surfaced memories
let surface_path = output_dir.join("surface");
if let Ok(content) = std::fs::read_to_string(&surface_path) {
Ok(Ok(_)) => {
// The outer task already put the AutoAgent back —
// read outputs from it
let mut subs = self.subconscious.lock().await;
let name = subs[idx].auto.name.clone();
let outputs = std::mem::take(&mut subs[idx].auto.outputs);
// Walked keys — update all subconscious agents
if let Some(walked_str) = outputs.get("walked") {
let walked: Vec<String> = walked_str.lines()
.map(|l| l.trim().to_string())
.filter(|l| !l.is_empty())
.collect();
for sub in subs.iter_mut() {
sub.auto.walked = walked.clone();
}
}
drop(subs);
// Surfaced memories → inject into conscious agent
if let Some(surface_str) = outputs.get("surface") {
let mut ag = self.agent.lock().await;
for key in content.lines().map(|l| l.trim()).filter(|l| !l.is_empty()) {
for key in surface_str.lines().map(|l| l.trim()).filter(|l| !l.is_empty()) {
if let Some(rendered) = crate::cli::node::render_node(
&crate::store::Store::load().unwrap_or_default(), key,
) {
@ -481,41 +494,23 @@ impl Mind {
});
}
}
std::fs::remove_file(&surface_path).ok();
}
// Walked keys — store for next run
let walked_path = output_dir.join("walked");
if let Ok(content) = std::fs::read_to_string(&walked_path) {
let walked: Vec<String> = content.lines()
.map(|l| l.trim().to_string())
.filter(|l| !l.is_empty())
.collect();
// Store on all subconscious agents (shared state)
let mut subs = self.subconscious.lock().await;
for sub in subs.iter_mut() {
sub.auto.walked = walked.clone();
}
std::fs::remove_file(&walked_path).ok();
}
// Reflection
let reflect_path = output_dir.join("reflection");
if let Ok(content) = std::fs::read_to_string(&reflect_path) {
if !content.trim().is_empty() {
// Reflection → inject into conscious agent
if let Some(reflection) = outputs.get("reflection") {
if !reflection.trim().is_empty() {
let mut ag = self.agent.lock().await;
ag.push_message(crate::agent::api::types::Message::user(format!(
"<system-reminder>\n--- subconscious reflection ---\n{}\n</system-reminder>",
content.trim(),
reflection.trim(),
)));
}
std::fs::remove_file(&reflect_path).ok();
}
dbglog!("[mind] {} completed", name);
}
Ok(Err(e)) => dbglog!("[mind] {} failed: {}", name, e),
Err(e) => dbglog!("[mind] {} panicked: {}", name, e),
Ok(Err(e)) => dbglog!("[mind] subconscious agent failed: {}", e),
Err(e) => dbglog!("[mind] subconscious agent panicked: {}", e),
}
}
}
@ -561,17 +556,12 @@ impl Mind {
let conscious = self.agent.lock().await;
let mut spawns = Vec::new();
for (idx, mut auto) in to_run {
let output_dir = crate::store::memory_dir()
.join("agent-output").join(&auto.name);
std::fs::create_dir_all(&output_dir).ok();
dbglog!("[mind] triggering {}", auto.name);
let forked = conscious.fork(auto.tools.clone());
let keys = memory_keys.clone();
let handle: tokio::task::JoinHandle<(AutoAgent, Result<String, String>)> =
tokio::spawn(async move {
unsafe { std::env::set_var("POC_AGENT_OUTPUT_DIR", &output_dir); }
let result = auto.run_forked(&forked, &keys).await;
(auto, result)
});