From c82047d1c5d38c56cd341bfc275ebf08f9edb878 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Wed, 19 Nov 2025 15:44:05 -0500 Subject: [PATCH] Revert "fix: Add schema-aware numeric coercion for MCP tool arguments (#5478)" This reverts commit 78fd31a47ae1a618463de751459156b71448f6fc. --- crates/goose/src/agents/reply_parts.rs | 90 +------------------------- 1 file changed, 2 insertions(+), 88 deletions(-) diff --git a/crates/goose/src/agents/reply_parts.rs b/crates/goose/src/agents/reply_parts.rs index f9755c716771..4a555f47f4b9 100644 --- a/crates/goose/src/agents/reply_parts.rs +++ b/crates/goose/src/agents/reply_parts.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use async_stream::try_stream; use futures::stream::StreamExt; -use serde_json::{json, Value}; use tracing::debug; use super::super::agents::Agent; @@ -20,79 +19,6 @@ use crate::agents::recipe_tools::dynamic_task_tools::should_enabled_subagents; use crate::session::SessionManager; use rmcp::model::Tool; -fn coerce_value(s: &str, schema: &Value) -> Value { - let type_str = schema.get("type"); - - match type_str { - Some(Value::String(t)) => match t.as_str() { - "number" | "integer" => try_coerce_number(s), - "boolean" => try_coerce_boolean(s), - _ => Value::String(s.to_string()), - }, - Some(Value::Array(types)) => { - // Try each type in order - for t in types { - if let Value::String(type_name) = t { - match type_name.as_str() { - "number" | "integer" if s.parse::().is_ok() => { - return try_coerce_number(s) - } - "boolean" if matches!(s.to_lowercase().as_str(), "true" | "false") => { - return try_coerce_boolean(s) - } - _ => continue, - } - } - } - Value::String(s.to_string()) - } - _ => Value::String(s.to_string()), - } -} - -fn try_coerce_number(s: &str) -> Value { - if let Ok(n) = s.parse::() { - if n.fract() == 0.0 && n >= i64::MIN as f64 && n <= i64::MAX as f64 { - json!(n as i64) - } else { - json!(n) - } - } else { - Value::String(s.to_string()) - } -} - -fn try_coerce_boolean(s: &str) -> Value { - match s.to_lowercase().as_str() { - "true" => json!(true), - "false" => json!(false), - _ => Value::String(s.to_string()), - } -} - -fn coerce_tool_arguments( - arguments: Option>, - tool_schema: &Value, -) -> Option> { - let args = arguments?; - - let properties = tool_schema.get("properties").and_then(|p| p.as_object())?; - - let mut coerced = serde_json::Map::new(); - - for (key, value) in args.iter() { - let coerced_value = - if let (Value::String(s), Some(prop_schema)) = (value, properties.get(key)) { - coerce_value(s, prop_schema) - } else { - value.clone() - }; - coerced.insert(key.clone(), coerced_value); - } - - Some(coerced) -} - async fn toolshim_postprocess( response: Message, toolshim_tools: &[Tool], @@ -268,25 +194,13 @@ impl Agent { &self, response: &Message, ) -> (Vec, Vec, Message) { - let tools = self.list_tools(None).await; - - // First collect all tool requests with coercion applied + // First collect all tool requests let tool_requests: Vec = response .content .iter() .filter_map(|content| { if let MessageContent::ToolRequest(req) = content { - let mut coerced_req = req.clone(); - - if let Ok(ref mut tool_call) = coerced_req.tool_call { - if let Some(tool) = tools.iter().find(|t| t.name == tool_call.name) { - let schema_value = Value::Object(tool.input_schema.as_ref().clone()); - tool_call.arguments = - coerce_tool_arguments(tool_call.arguments.clone(), &schema_value); - } - } - - Some(coerced_req) + Some(req.clone()) } else { None }