From d2dbdedc8f4178458373e0414e8055e4ffc1f7ca Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 11 Apr 2026 21:34:41 -0400 Subject: [PATCH] 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 --- src/agent/oneshot.rs | 65 ++++++++++++++++++++++++++++++++++++++-- src/mind/subconscious.rs | 2 +- src/mind/unconscious.rs | 56 ++-------------------------------- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/agent/oneshot.rs b/src/agent/oneshot.rs index 8f4fd3d..d638f24 100644 --- a/src/agent/oneshot.rs +++ b/src/agent/oneshot.rs @@ -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, +} + +/// 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) -> 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 = 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 diff --git a/src/mind/subconscious.rs b/src/mind/subconscious.rs index d10f9e1..58f971e 100644 --- a/src/mind/subconscious.rs +++ b/src/mind/subconscious.rs @@ -617,7 +617,7 @@ impl Subconscious { self.agents[idx].handle = Some(tokio::spawn(async move { let result = auto.run_forked_shared(&forked, &keys, &st, &recent).await; - super::unconscious::save_agent_log(&auto.name, &forked).await; + crate::agent::oneshot::save_agent_log(&auto.name, &forked).await; (auto, result) })); } diff --git a/src/mind/unconscious.rs b/src/mind/unconscious.rs index 5678b19..5bd6183 100644 --- a/src/mind/unconscious.rs +++ b/src/mind/unconscious.rs @@ -9,7 +9,7 @@ use std::time::Instant; use std::collections::HashMap; use futures::FutureExt; -use crate::agent::oneshot::{AutoAgent, AutoStep}; +use crate::agent::oneshot::{AutoAgent, AutoStep, RunStats}; use crate::agent::tools; use crate::subconscious::defs; @@ -293,61 +293,11 @@ impl Unconscious { self.agents[idx].handle = Some(tokio::spawn(async move { let result = auto.run_shared(&agent).await; - let stats = save_agent_log(&auto.name, &agent).await; + let stats = crate::agent::oneshot::save_agent_log(&auto.name, &agent).await; auto.steps = orig_steps; (auto, result, stats) })); } } -pub async fn save_agent_log(name: &str, agent: &std::sync::Arc) -> 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<&crate::agent::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!("[unconscious] {} — {} msgs, {} tool calls", - name, stats.messages, stats.tool_calls); - stats -} - -#[derive(Clone, serde::Serialize)] -pub struct RunStats { - pub messages: usize, - pub tool_calls: usize, - pub tool_calls_by_type: HashMap, -} - -fn compute_run_stats(conversation: &[crate::agent::context::AstNode]) -> RunStats { - use crate::agent::context::{AstNode, NodeBody}; - - let mut messages = 0usize; - let mut tool_calls = 0usize; - let mut by_type: HashMap = 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 } -} +// save_agent_log and RunStats moved to crate::agent::oneshot