tools: delete ToolOutput, dispatch returns String
ToolOutput was just { text: String } — replaced with plain String.
dispatch() and dispatch_shared() return String directly.
ActiveToolCall handle is (ToolCall, String).
Error results are prefixed with "Error: " by convention.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
a24a6605b8
commit
37fad63ba9
3 changed files with 23 additions and 35 deletions
|
|
@ -602,7 +602,7 @@ impl Agent {
|
||||||
if call.function.name == "working_stack" {
|
if call.function.name == "working_stack" {
|
||||||
let mut me = agent.lock().await;
|
let mut me = agent.lock().await;
|
||||||
let result = tools::working_stack::handle(&args, &mut me.context.working_stack);
|
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);
|
me.apply_tool_result(call, output, ui_tx, ds);
|
||||||
if !result.starts_with("Error:") {
|
if !result.starts_with("Error:") {
|
||||||
me.refresh_context_state();
|
me.refresh_context_state();
|
||||||
|
|
@ -643,7 +643,7 @@ impl Agent {
|
||||||
fn apply_tool_result(
|
fn apply_tool_result(
|
||||||
&mut self,
|
&mut self,
|
||||||
call: &ToolCall,
|
call: &ToolCall,
|
||||||
output: tools::ToolOutput,
|
output: String,
|
||||||
ui_tx: &UiSender,
|
ui_tx: &UiSender,
|
||||||
ds: &mut DispatchState,
|
ds: &mut DispatchState,
|
||||||
) {
|
) {
|
||||||
|
|
@ -651,20 +651,20 @@ impl Agent {
|
||||||
serde_json::from_str(&call.function.arguments).unwrap_or_default();
|
serde_json::from_str(&call.function.arguments).unwrap_or_default();
|
||||||
|
|
||||||
ds.had_tool_calls = true;
|
ds.had_tool_calls = true;
|
||||||
if output.text.starts_with("Error:") {
|
if output.starts_with("Error:") {
|
||||||
ds.tool_errors += 1;
|
ds.tool_errors += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = ui_tx.send(UiMessage::ToolResult {
|
let _ = ui_tx.send(UiMessage::ToolResult {
|
||||||
name: call.function.name.clone(),
|
name: call.function.name.clone(),
|
||||||
result: output.text.clone(),
|
result: output.clone(),
|
||||||
});
|
});
|
||||||
self.active_tools.lock().unwrap().retain(|t| t.id != call.id);
|
self.active_tools.lock().unwrap().retain(|t| t.id != call.id);
|
||||||
|
|
||||||
// Tag memory_render results for context deduplication
|
// 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()) {
|
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();
|
msg.stamp();
|
||||||
self.push_entry(ConversationEntry::Memory { key: key.to_string(), message: msg });
|
self.push_entry(ConversationEntry::Memory { key: key.to_string(), message: msg });
|
||||||
self.publish_context_state();
|
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.
|
/// Build context state summary for the debug screen.
|
||||||
|
|
|
||||||
|
|
@ -134,20 +134,6 @@ pub struct ToolCallDelta {
|
||||||
pub function: Option<FunctionCallDelta>,
|
pub function: Option<FunctionCallDelta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
/// A tool call in flight — metadata for TUI + JoinHandle for
|
||||||
/// result collection and cancellation.
|
/// result collection and cancellation.
|
||||||
|
|
@ -157,7 +143,7 @@ pub struct ActiveToolCall {
|
||||||
pub detail: String,
|
pub detail: String,
|
||||||
pub started: Instant,
|
pub started: Instant,
|
||||||
pub background: bool,
|
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.
|
/// 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 through the registry.
|
||||||
|
/// Dispatch a tool call by name. Returns the result text,
|
||||||
|
/// or an error string prefixed with "Error: ".
|
||||||
pub async fn dispatch(
|
pub async fn dispatch(
|
||||||
name: &str,
|
name: &str,
|
||||||
args: &serde_json::Value,
|
args: &serde_json::Value,
|
||||||
) -> ToolOutput {
|
) -> String {
|
||||||
dispatch_with_agent(name, args, None).await
|
dispatch_with_agent(name, args, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,16 +170,16 @@ pub async fn dispatch_with_agent(
|
||||||
name: &str,
|
name: &str,
|
||||||
args: &serde_json::Value,
|
args: &serde_json::Value,
|
||||||
agent: Option<std::sync::Arc<tokio::sync::Mutex<super::Agent>>>,
|
agent: Option<std::sync::Arc<tokio::sync::Mutex<super::Agent>>>,
|
||||||
) -> ToolOutput {
|
) -> String {
|
||||||
for tool in tools() {
|
for tool in tools() {
|
||||||
if tool.name == name {
|
if tool.name == name {
|
||||||
return match (tool.handler)(agent, args.clone()).await {
|
return match (tool.handler)(agent, args.clone()).await {
|
||||||
Ok(s) => ToolOutput::text(s),
|
Ok(s) => s,
|
||||||
Err(e) => ToolOutput::error(e),
|
Err(e) => format!("Error: {}", e),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToolOutput::error(format!("Unknown tool: {}", name))
|
format!("Error: Unknown tool: {}", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch shared tools — used by subconscious agents.
|
/// Dispatch shared tools — used by subconscious agents.
|
||||||
|
|
@ -199,12 +187,12 @@ pub async fn dispatch_shared(
|
||||||
name: &str,
|
name: &str,
|
||||||
args: &serde_json::Value,
|
args: &serde_json::Value,
|
||||||
_provenance: Option<&str>,
|
_provenance: Option<&str>,
|
||||||
) -> Option<ToolOutput> {
|
) -> Option<String> {
|
||||||
for tool in tools() {
|
for tool in tools() {
|
||||||
if tool.name == name {
|
if tool.name == name {
|
||||||
return Some(match (tool.handler)(None, args.clone()).await {
|
return Some(match (tool.handler)(None, args.clone()).await {
|
||||||
Ok(s) => ToolOutput::text(s),
|
Ok(s) => s,
|
||||||
Err(e) => ToolOutput::error(e),
|
Err(e) => format!("Error: {}", e),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
use crate::agent::api::ApiClient;
|
use crate::agent::api::ApiClient;
|
||||||
use crate::agent::api::types::*;
|
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;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
|
@ -181,17 +181,17 @@ pub async fn call_api_with_tools(
|
||||||
let prov = provenance.borrow().clone();
|
let prov = provenance.borrow().clone();
|
||||||
let output = match agent_tools::dispatch_shared(&call.function.name, &args, Some(&prov)).await {
|
let output = match agent_tools::dispatch_shared(&call.function.name, &args, Some(&prov)).await {
|
||||||
Some(out) => out,
|
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() {
|
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 {
|
} 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));
|
log(&format!("Result: {}", preview));
|
||||||
}
|
}
|
||||||
|
|
||||||
messages.push(Message::tool_result(&call.id, &output.text));
|
messages.push(Message::tool_result(&call.id, &output));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue