Move save_agent_log to oneshot.rs for shared Mind/CLI use

Both Mind-run agents (unconscious/subconscious) and CLI-run agents
(poc-memory agent run) now use the same logging path. AutoAgent::run()
calls save_agent_log automatically at the end.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-11 21:34:41 -04:00
parent 271e09adcc
commit d2dbdedc8f
3 changed files with 67 additions and 56 deletions

View file

@ -10,6 +10,7 @@
use crate::store::{self, Store};
use crate::subconscious::{defs, prompts};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
@ -17,6 +18,64 @@ use super::context::AstNode;
use super::tools::{self as agent_tools};
use super::Agent;
// ---------------------------------------------------------------------------
// Agent logging — shared by Mind and CLI paths
// ---------------------------------------------------------------------------
#[derive(Clone, serde::Serialize)]
pub struct RunStats {
pub messages: usize,
pub tool_calls: usize,
pub tool_calls_by_type: HashMap<String, usize>,
}
/// Save agent conversation to JSON log file.
/// Used by both mind-run agents and CLI-run agents.
pub async fn save_agent_log(name: &str, agent: &std::sync::Arc<Agent>) -> RunStats {
let dir = dirs::home_dir().unwrap_or_default()
.join(format!(".consciousness/logs/{}", name));
let ctx = agent.context.lock().await;
let stats = compute_run_stats(ctx.conversation());
if std::fs::create_dir_all(&dir).is_ok() {
let ts = chrono::Utc::now().format("%Y%m%d-%H%M%S");
let path = dir.join(format!("{}.json", ts));
let mut context: Vec<&super::context::AstNode> = Vec::new();
for section in ctx.sections() {
context.extend(section);
}
if let Ok(json) = serde_json::to_string_pretty(&context) {
let _ = std::fs::write(&path, json);
}
}
dbglog!("[agent] {} — {} msgs, {} tool calls",
name, stats.messages, stats.tool_calls);
stats
}
fn compute_run_stats(conversation: &[super::context::AstNode]) -> RunStats {
use super::context::{AstNode, NodeBody};
let mut messages = 0usize;
let mut tool_calls = 0usize;
let mut by_type: HashMap<String, usize> = HashMap::new();
for node in conversation {
if let AstNode::Branch { children, .. } = node {
messages += 1;
for child in children {
if let AstNode::Leaf(leaf) = child {
if let NodeBody::ToolCall { name, .. } = leaf.body() {
tool_calls += 1;
*by_type.entry(name.to_string()).or_default() += 1;
}
}
}
}
}
RunStats { messages, tool_calls, tool_calls_by_type: by_type }
}
// ---------------------------------------------------------------------------
// AutoAgent — multi-step autonomous agent
// ---------------------------------------------------------------------------
@ -147,8 +206,10 @@ impl AutoAgent {
st.priority = Some(10);
}
let mut backend = Backend(agent);
self.run_with_backend(&mut backend, bail_fn).await
let mut backend = Backend(agent.clone());
let result = self.run_with_backend(&mut backend, bail_fn).await;
save_agent_log(&self.name, &agent).await;
result
}
/// Run using a pre-created agent Arc. The caller retains the Arc