diff --git a/src/agent/mod.rs b/src/agent/mod.rs index 328ff26..69a65e5 100644 --- a/src/agent/mod.rs +++ b/src/agent/mod.rs @@ -602,7 +602,7 @@ impl Agent { if call.function.name == "working_stack" { let mut me = agent.lock().await; let result = tools::working_stack::handle(&args, &mut me.context.working_stack); - let output = tools::ToolOutput::text(result.clone()); + let output = result.clone(); me.apply_tool_result(call, output, ui_tx, ds); if !result.starts_with("Error:") { me.refresh_context_state(); @@ -643,7 +643,7 @@ impl Agent { fn apply_tool_result( &mut self, call: &ToolCall, - output: tools::ToolOutput, + output: String, ui_tx: &UiSender, ds: &mut DispatchState, ) { @@ -651,20 +651,20 @@ impl Agent { serde_json::from_str(&call.function.arguments).unwrap_or_default(); ds.had_tool_calls = true; - if output.text.starts_with("Error:") { + if output.starts_with("Error:") { ds.tool_errors += 1; } let _ = ui_tx.send(UiMessage::ToolResult { name: call.function.name.clone(), - result: output.text.clone(), + result: output.clone(), }); self.active_tools.lock().unwrap().retain(|t| t.id != call.id); // Tag memory_render results for context deduplication - if call.function.name == "memory_render" && !output.text.starts_with("Error:") { + if call.function.name == "memory_render" && !output.starts_with("Error:") { if let Some(key) = args.get("key").and_then(|v| v.as_str()) { - let mut msg = Message::tool_result(&call.id, &output.text); + let mut msg = Message::tool_result(&call.id, &output); msg.stamp(); self.push_entry(ConversationEntry::Memory { key: key.to_string(), message: msg }); self.publish_context_state(); @@ -672,7 +672,7 @@ impl Agent { } } - self.push_message(Message::tool_result(&call.id, &output.text)); + self.push_message(Message::tool_result(&call.id, &output)); } /// Build context state summary for the debug screen. diff --git a/src/agent/tools/mod.rs b/src/agent/tools/mod.rs index 9ff8088..d324916 100644 --- a/src/agent/tools/mod.rs +++ b/src/agent/tools/mod.rs @@ -134,20 +134,6 @@ pub struct ToolCallDelta { pub function: Option, } -/// Result of dispatching a tool call. -pub struct ToolOutput { - pub text: String, -} - -impl ToolOutput { - pub fn error(e: impl std::fmt::Display) -> Self { - Self { text: format!("Error: {}", e) } - } - - pub fn text(s: String) -> Self { - Self { text: s } - } -} /// A tool call in flight — metadata for TUI + JoinHandle for /// result collection and cancellation. @@ -157,7 +143,7 @@ pub struct ActiveToolCall { pub detail: String, pub started: Instant, pub background: bool, - pub handle: tokio::task::JoinHandle<(ToolCall, ToolOutput)>, + pub handle: tokio::task::JoinHandle<(ToolCall, String)>, } /// Truncate output if it exceeds max length, appending a truncation notice. @@ -170,10 +156,12 @@ pub fn truncate_output(mut s: String, max: usize) -> String { } /// Dispatch a tool call by name through the registry. +/// Dispatch a tool call by name. Returns the result text, +/// or an error string prefixed with "Error: ". pub async fn dispatch( name: &str, args: &serde_json::Value, -) -> ToolOutput { +) -> String { dispatch_with_agent(name, args, None).await } @@ -182,16 +170,16 @@ pub async fn dispatch_with_agent( name: &str, args: &serde_json::Value, agent: Option>>, -) -> ToolOutput { +) -> String { for tool in tools() { if tool.name == name { return match (tool.handler)(agent, args.clone()).await { - Ok(s) => ToolOutput::text(s), - Err(e) => ToolOutput::error(e), + Ok(s) => s, + Err(e) => format!("Error: {}", e), }; } } - ToolOutput::error(format!("Unknown tool: {}", name)) + format!("Error: Unknown tool: {}", name) } /// Dispatch shared tools — used by subconscious agents. @@ -199,12 +187,12 @@ pub async fn dispatch_shared( name: &str, args: &serde_json::Value, _provenance: Option<&str>, -) -> Option { +) -> Option { for tool in tools() { if tool.name == name { return Some(match (tool.handler)(None, args.clone()).await { - Ok(s) => ToolOutput::text(s), - Err(e) => ToolOutput::error(e), + Ok(s) => s, + Err(e) => format!("Error: {}", e), }); } } diff --git a/src/subconscious/api.rs b/src/subconscious/api.rs index b9d5be9..38ceece 100644 --- a/src/subconscious/api.rs +++ b/src/subconscious/api.rs @@ -9,7 +9,7 @@ use crate::agent::api::ApiClient; use crate::agent::api::types::*; -use crate::agent::tools::{self as agent_tools, ToolOutput}; +use crate::agent::tools::{self as agent_tools}; use std::sync::OnceLock; @@ -181,17 +181,17 @@ pub async fn call_api_with_tools( let prov = provenance.borrow().clone(); let output = match agent_tools::dispatch_shared(&call.function.name, &args, Some(&prov)).await { Some(out) => out, - None => ToolOutput::error(format!("Unknown tool: {}", call.function.name)), + None => format!("Error: Unknown tool: {}", call.function.name), }; if std::env::var("POC_AGENT_VERBOSE").is_ok() { - log(&format!("TOOL RESULT ({} chars):\n{}", output.text.len(), output.text)); + log(&format!("TOOL RESULT ({} chars):\n{}", output.len(), output)); } else { - let preview: String = output.text.lines().next().unwrap_or("").chars().take(100).collect(); + let preview: String = output.lines().next().unwrap_or("").chars().take(100).collect(); log(&format!("Result: {}", preview)); } - messages.push(Message::tool_result(&call.id, &output.text)); + messages.push(Message::tool_result(&call.id, &output)); } continue; }