logging: single output stream through caller's log closure

Pass the caller's log closure all the way through to api.rs instead
of creating a separate eprintln closure in llm.rs. Everything goes
through one stream — prompt, think blocks, tool calls with args,
tool results with content, token counts, final response.

CLI uses println (stdout), daemon uses its task log. No more split
between stdout and stderr.

Also removes the llm-log file creation from knowledge.rs — that's
the daemon's concern, not the agent runner's.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kent Overstreet 2026-03-22 01:57:47 -04:00
parent e74d533748
commit 543e1bdc8a
4 changed files with 25 additions and 45 deletions

View file

@ -17,12 +17,12 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
if crate::agents::daemon::send_rpc_pub("ping").is_some() {
return crate::agents::daemon::rpc_run_agent(agent, count);
}
eprintln!("Daemon not running — falling back to local execution");
println!("Daemon not running — falling back to local execution");
}
// Slow path: need the store for local execution or target resolution
let mut store = store::Store::load()?;
let log = |msg: &str| eprintln!("[{}] {}", agent, msg);
let log = |msg: &str| println!("{}", msg);
// Resolve targets: explicit --target, --query, or agent's default query
let resolved_targets: Vec<String> = if !target.is_empty() {
@ -35,7 +35,7 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
return Err(format!("query returned no results: {}", q));
}
let keys: Vec<String> = results.into_iter().map(|(k, _)| k).collect();
eprintln!("[{}] query matched {} nodes", agent, keys.len());
println!("[{}] query matched {} nodes", agent, keys.len());
keys
} else {
vec![] // use agent's built-in query
@ -45,15 +45,15 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
// --local or daemon unavailable: run directly
if needs_local || crate::agents::daemon::send_rpc_pub("ping").is_none() {
if !needs_local {
eprintln!("Daemon not running — falling back to local execution");
println!("Daemon not running — falling back to local execution");
}
for (i, key) in resolved_targets.iter().enumerate() {
eprintln!("[{}] [{}/{}] {}", agent, i + 1, resolved_targets.len(), key);
println!("[{}] [{}/{}] {}", agent, i + 1, resolved_targets.len(), key);
if i > 0 { store = store::Store::load()?; }
if let Err(e) = crate::agents::knowledge::run_one_agent_with_keys(
&mut store, agent, &[key.clone()], count, "test", &log, debug,
) {
eprintln!("[{}] ERROR on {}: {}", agent, key, e);
println!("[{}] ERROR on {}: {}", agent, key, e);
}
}
return Ok(());
@ -67,7 +67,7 @@ pub fn cmd_run_agent(agent: &str, count: usize, target: &[String], query: Option
queued += 1;
}
}
eprintln!("[{}] queued {} tasks to daemon", agent, queued);
println!("[{}] queued {} tasks to daemon", agent, queued);
} else {
// Local execution (--local, --debug, dry-run, or daemon unavailable)
crate::agents::knowledge::run_one_agent(