From 03310dafa44707b303ffc0c44b4517031a1c063f Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Mon, 16 Mar 2026 20:44:09 -0400 Subject: [PATCH] agent logging: single log file, --debug prints to stdout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate agent logging to one file per run in llm-logs/{agent}/. Prompt written before LLM call, response appended after. --debug additionally prints the same content to stdout. Remove duplicate eprintln! calls and AgentResult.prompt field. Kill experience_mine and fact_mine job functions from daemon — observation.agent handles all transcript mining. Co-Authored-By: Claude Opus 4.6 (1M context) --- poc-memory/src/agents/daemon.rs | 40 +++--------------------------- poc-memory/src/agents/knowledge.rs | 34 ++++++++++++++----------- poc-memory/src/cli/agent.rs | 13 +++------- 3 files changed, 27 insertions(+), 60 deletions(-) diff --git a/poc-memory/src/agents/daemon.rs b/poc-memory/src/agents/daemon.rs index f29abd0..dbf88e1 100644 --- a/poc-memory/src/agents/daemon.rs +++ b/poc-memory/src/agents/daemon.rs @@ -39,29 +39,7 @@ fn run_job(ctx: &ExecutionContext, name: &str, f: impl FnOnce() -> Result<(), St jobkit_daemon::Daemon::run_job(&crate::config::get().data_dir, ctx, name, f) } -fn job_experience_mine(ctx: &ExecutionContext, path: &str, segment: Option) -> Result<(), TaskError> { - let path = path.to_string(); - run_job(ctx, &format!("experience-mine {}", path), || { - ctx.log_line("loading store"); - let mut store = crate::store::Store::load()?; - ctx.log_line("mining"); - let count = super::enrich::experience_mine(&mut store, &path, segment)?; - ctx.log_line(format!("{count} entries mined")); - Ok(()) - }) -} - -fn job_fact_mine(ctx: &ExecutionContext, path: &str) -> Result<(), TaskError> { - let path = path.to_string(); - run_job(ctx, &format!("fact-mine {}", path), || { - ctx.log_line("mining facts"); - let p = std::path::Path::new(&path); - let progress = |msg: &str| { ctx.set_progress(msg); }; - let count = super::fact_mine::mine_and_store(p, Some(&progress))?; - ctx.log_line(format!("{count} facts stored")); - Ok(()) - }) -} +// experience_mine and fact_mine removed — observation.agent handles all transcript mining /// Run a single consolidation agent (replay, linker, separator, transfer, health). fn job_consolidation_agent( @@ -100,7 +78,7 @@ fn job_rename_agent( ctx.log_line(&format!("running rename agent (batch={})", batch)); let log = |msg: &str| ctx.log_line(msg); - let result = super::knowledge::run_one_agent(&mut store, "rename", batch, "consolidate", &log)?; + let result = super::knowledge::run_one_agent(&mut store, "rename", batch, "consolidate", &log, false)?; // Parse RENAME actions from response (rename uses its own format, not WRITE_NODE/LINK/REFINE) let mut applied = 0; @@ -898,12 +876,7 @@ pub fn run_daemon() -> Result<(), String> { log_event("extract", "queued", &task_name); let path = path_str.clone(); let seg = *segment; - choir_sw.spawn(task_name) - .resource(&llm_sw) - .retries(2) - .init(move |ctx| { - job_experience_mine(ctx, &path, seg) - }); + // experience_mine killed — observation.agent handles transcript mining extract_queued += 1; } @@ -922,12 +895,7 @@ pub fn run_daemon() -> Result<(), String> { let task_name = format!("fact-mine:{}", filename); log_event("fact-mine", "queued", path_str); let path = path_str.clone(); - choir_sw.spawn(task_name) - .resource(&llm_sw) - .retries(1) - .init(move |ctx| { - job_fact_mine(ctx, &path) - }); + // fact_mine killed — observation.agent handles transcript mining fact_queued += 1; } } else { diff --git a/poc-memory/src/agents/knowledge.rs b/poc-memory/src/agents/knowledge.rs index 9a46ff1..1c3d13f 100644 --- a/poc-memory/src/agents/knowledge.rs +++ b/poc-memory/src/agents/knowledge.rs @@ -548,7 +548,6 @@ pub fn resolve_naming( /// Result of running a single agent through the common pipeline. pub struct AgentResult { - pub prompt: String, pub output: String, pub actions: Vec, pub no_ops: usize, @@ -616,7 +615,7 @@ pub fn run_and_apply_with_log( llm_tag: &str, log: &dyn Fn(&str), ) -> Result<(usize, usize), String> { - let result = run_one_agent(store, agent_name, batch_size, llm_tag, log)?; + let result = run_one_agent(store, agent_name, batch_size, llm_tag, log, false)?; let actions = resolve_action_names(store, result.actions); let ts = store::compact_timestamp(); let mut applied = 0; @@ -653,6 +652,7 @@ pub fn run_one_agent( batch_size: usize, llm_tag: &str, log: &dyn Fn(&str), + debug: bool, ) -> Result { let def = super::defs::get_def(agent_name) .ok_or_else(|| format!("no .agent file for {}", agent_name))?; @@ -669,19 +669,26 @@ pub fn run_one_agent( log(&format!(" node: {}", key)); } + // Single log file: prompt then response + let log_dir = store::memory_dir().join("llm-logs").join(agent_name); + fs::create_dir_all(&log_dir).ok(); + let log_path = log_dir.join(format!("{}.txt", store::compact_timestamp())); + let prompt_section = format!("=== PROMPT ===\n\n{}\n\n=== CALLING LLM ===\n", agent_batch.prompt); + fs::write(&log_path, &prompt_section).ok(); + if debug { print!("{}", prompt_section); } + log(&format!("log: {}", log_path.display())); + log("calling LLM"); let output = llm::call_for_def(&def, &agent_batch.prompt)?; - let output_kb = output.len() / 1024; - log(&format!("response {}KB", output_kb)); - - // Log raw output to file, not the graph - let ts = store::compact_timestamp(); - let log_dir = store::memory_dir().join("llm-logs").join(agent_name); - fs::create_dir_all(&log_dir).ok(); - let log_path = log_dir.join(format!("{}.txt", ts)); - fs::write(&log_path, &output).ok(); - log(&format!("logged to {}", log_path.display())); + // Append response to same log file + use std::io::Write; + let response_section = format!("\n=== RESPONSE ===\n\n{}\n", output); + if let Ok(mut f) = fs::OpenOptions::new().append(true).open(&log_path) { + write!(f, "{}", response_section).ok(); + } + if debug { print!("{}", response_section); } + log(&format!("response {}KB", output.len() / 1024)); let actions = parse_all_actions(&output); let no_ops = count_no_ops(&output); @@ -694,7 +701,6 @@ pub fn run_one_agent( } Ok(AgentResult { - prompt: agent_batch.prompt, output, actions, no_ops, @@ -983,7 +989,7 @@ fn run_cycle( for agent_name in &agent_names { eprintln!("\n --- {} (n={}) ---", agent_name, config.batch_size); - let result = match run_one_agent(&mut store, agent_name, config.batch_size, "knowledge", &|msg| eprintln!(" {}", msg)) { + let result = match run_one_agent(&mut store, agent_name, config.batch_size, "knowledge", &|msg| eprintln!(" {}", msg), false) { Ok(r) => r, Err(e) => { eprintln!(" ERROR: {}", e); diff --git a/poc-memory/src/cli/agent.rs b/poc-memory/src/cli/agent.rs index 8a5e7d6..627b639 100644 --- a/poc-memory/src/cli/agent.rs +++ b/poc-memory/src/cli/agent.rs @@ -13,20 +13,13 @@ pub fn cmd_run_agent(agent: &str, count: usize, dry_run: bool, debug: bool) -> R let log = |msg: &str| eprintln!("[{}] {}", agent, msg); if debug { - // Debug mode: show prompt, call LLM, show response — don't apply - let result = crate::agents::knowledge::run_one_agent( - &mut store, agent, count, "test", &log, + crate::agents::knowledge::run_one_agent( + &mut store, agent, count, "test", &log, true, )?; - eprintln!("\n=== PROMPT ({} bytes) ===\n", result.prompt.len()); - println!("{}", result.prompt); - eprintln!("\n=== RESPONSE ({} bytes) ===\n", result.output.len()); - println!("{}", result.output); - eprintln!("\n=== PARSED: {} actions, {} no-ops ===", result.actions.len(), result.no_ops); } else { - let (total, applied) = crate::agents::knowledge::run_and_apply_with_log( + crate::agents::knowledge::run_and_apply_with_log( &mut store, agent, count, "test", &log, )?; - eprintln!("[{}] {} actions, {} applied", agent, total, applied); } Ok(()) }