ui writer fixes
This commit is contained in:
@@ -53,10 +53,21 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
|
|
||||||
fn print_tool_arg(&self, key: &str, value: &str) {
|
fn print_tool_arg(&self, key: &str, value: &str) {
|
||||||
// Collect arguments instead of printing immediately
|
// Collect arguments instead of printing immediately
|
||||||
self.current_tool_args
|
// Filter out any keys that look like they might be agent message content
|
||||||
|
// (e.g., keys that are suspiciously long or contain message-like content)
|
||||||
|
let is_valid_arg_key = key.len() < 50 &&
|
||||||
|
!key.contains('\n') &&
|
||||||
|
!key.contains("I'll") &&
|
||||||
|
!key.contains("Let me") &&
|
||||||
|
!key.contains("Here's") &&
|
||||||
|
!key.contains("I can");
|
||||||
|
|
||||||
|
if is_valid_arg_key {
|
||||||
|
self.current_tool_args
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push((key.to_string(), value.to_string()));
|
.push((key.to_string(), value.to_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_output_header(&self) {
|
fn print_tool_output_header(&self) {
|
||||||
@@ -200,11 +211,22 @@ impl UiWriter for RetroTuiWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_arg(&self, key: &str, value: &str) {
|
fn print_tool_arg(&self, key: &str, value: &str) {
|
||||||
self.current_tool_output
|
// Filter out any keys that look like they might be agent message content
|
||||||
.lock()
|
// (e.g., keys that are suspiciously long or contain message-like content)
|
||||||
.unwrap()
|
let is_valid_arg_key = key.len() < 50 &&
|
||||||
.push(format!("{}: {}", key, value));
|
!key.contains('\n') &&
|
||||||
|
!key.contains("I'll") &&
|
||||||
|
!key.contains("Let me") &&
|
||||||
|
!key.contains("Here's") &&
|
||||||
|
!key.contains("I can");
|
||||||
|
|
||||||
|
if is_valid_arg_key {
|
||||||
|
self.current_tool_output
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push(format!("{}: {}", key, value));
|
||||||
|
}
|
||||||
|
|
||||||
// Build caption from first argument (usually the most important one)
|
// Build caption from first argument (usually the most important one)
|
||||||
let mut caption = self.current_tool_caption.lock().unwrap();
|
let mut caption = self.current_tool_caption.lock().unwrap();
|
||||||
if caption.is_empty() && (key == "file_path" || key == "command" || key == "path") {
|
if caption.is_empty() && (key == "file_path" || key == "command" || key == "path") {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use tracing::{debug, error, info, warn};
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolCall {
|
pub struct ToolCall {
|
||||||
pub tool: String,
|
pub tool: String,
|
||||||
pub args: serde_json::Value,
|
pub args: serde_json::Value, // Should be a JSON object with tool-specific arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -167,14 +167,47 @@ impl StreamingToolParser {
|
|||||||
let json_str = &json_text[..=i];
|
let json_str = &json_text[..=i];
|
||||||
debug!("Attempting to parse JSON tool call: {}", json_str);
|
debug!("Attempting to parse JSON tool call: {}", json_str);
|
||||||
|
|
||||||
|
// First try to parse as a ToolCall
|
||||||
if let Ok(tool_call) = serde_json::from_str::<ToolCall>(json_str) {
|
if let Ok(tool_call) = serde_json::from_str::<ToolCall>(json_str) {
|
||||||
debug!("Successfully parsed JSON tool call: {:?}", tool_call);
|
// Validate that this is actually a proper tool call
|
||||||
|
// The args should be a JSON object with reasonable keys
|
||||||
|
if let Some(args_obj) = tool_call.args.as_object() {
|
||||||
|
// Check if any key looks like it contains agent message content
|
||||||
|
// This would indicate a malformed tool call where the message
|
||||||
|
// got mixed into the args
|
||||||
|
let has_message_like_key = args_obj.keys().any(|key| {
|
||||||
|
key.len() > 100 ||
|
||||||
|
key.contains('\n') ||
|
||||||
|
key.contains("I'll") ||
|
||||||
|
key.contains("Let me") ||
|
||||||
|
key.contains("Here's") ||
|
||||||
|
key.contains("I can") ||
|
||||||
|
key.contains("I need") ||
|
||||||
|
key.contains("First") ||
|
||||||
|
key.contains("Now") ||
|
||||||
|
key.contains("The ")
|
||||||
|
});
|
||||||
|
|
||||||
// Reset JSON parsing state
|
if has_message_like_key {
|
||||||
self.in_json_tool_call = false;
|
debug!("Detected malformed tool call with message-like keys, skipping");
|
||||||
self.json_tool_start = None;
|
// This looks like a malformed tool call, skip it
|
||||||
|
self.in_json_tool_call = false;
|
||||||
|
self.json_tool_start = None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return Some(tool_call);
|
// Also check if the values look reasonable
|
||||||
|
// Tool arguments should typically be file paths, commands, or content
|
||||||
|
// Not entire agent messages
|
||||||
|
|
||||||
|
debug!("Successfully parsed valid JSON tool call: {:?}", tool_call);
|
||||||
|
// Reset JSON parsing state
|
||||||
|
self.in_json_tool_call = false;
|
||||||
|
self.json_tool_start = None;
|
||||||
|
return Some(tool_call);
|
||||||
|
}
|
||||||
|
// If args is not an object, skip this as invalid
|
||||||
|
debug!("Tool call args is not an object, skipping");
|
||||||
} else {
|
} else {
|
||||||
debug!("Failed to parse JSON tool call: {}", json_str);
|
debug!("Failed to parse JSON tool call: {}", json_str);
|
||||||
// Reset and continue looking
|
// Reset and continue looking
|
||||||
|
|||||||
Reference in New Issue
Block a user