fix(code_execution): handle model quirks with tool calls (#6352)

Signed-off-by: rabi <ramishra@redhat.com>
This commit is contained in:
Rabi Mishra
2026-01-13 23:21:22 +05:30
committed by GitHub
parent 1a2bc4807a
commit d9a30a8f99
2 changed files with 31 additions and 10 deletions
@@ -466,6 +466,8 @@ impl CodeExecutionClient {
- WRONG: Multiple execute_code calls, each with one tool - WRONG: Multiple execute_code calls, each with one tool
- RIGHT: One execute_code call with a script that calls all needed tools - RIGHT: One execute_code call with a script that calls all needed tools
IMPORTANT: All tool calls are SYNCHRONOUS. Do NOT use async/await.
Workflow: Workflow:
1. Use the read_module tool to discover tools and signatures 1. Use the read_module tool to discover tools and signatures
2. Write ONE script that imports and calls ALL tools needed for the task 2. Write ONE script that imports and calls ALL tools needed for the task
@@ -572,12 +574,16 @@ impl CodeExecutionClient {
.and_then(|a| a.get("terms")) .and_then(|a| a.get("terms"))
.ok_or("Missing required parameter: terms")?; .ok_or("Missing required parameter: terms")?;
let terms_vec = if let Some(s) = terms.as_str() { let terms_vec = if let Some(arr) = terms.as_array() {
vec![s.to_string()]
} else if let Some(arr) = terms.as_array() {
arr.iter() arr.iter()
.filter_map(|v| v.as_str().map(String::from)) .filter_map(|v| v.as_str().map(String::from))
.collect() .collect()
} else if let Some(s) = terms.as_str() {
if s.starts_with('[') && s.ends_with(']') {
serde_json::from_str::<Vec<String>>(s).unwrap_or_else(|_| vec![s.to_string()])
} else {
vec![s.to_string()]
}
} else { } else {
return Err("Parameter 'terms' must be a string or array of strings".to_string()); return Err("Parameter 'terms' must be a string or array of strings".to_string());
}; };
@@ -830,9 +836,11 @@ impl McpClientTrait for CodeExecutionClient {
Search for tools by name or description across all available modules. Search for tools by name or description across all available modules.
USAGE: USAGE:
- Single term: search_modules with terms="file" - Single term: terms="github" (just a plain string)
- Multiple terms: search_modules with terms=["git", "shell"] - Multiple terms: terms=["git", "shell"] (a JSON array, NOT a string)
- Regex patterns: search_modules with terms="sh.*", regex=true - Regex patterns: terms="sh.*", regex=true
IMPORTANT: Do NOT stringify arrays. Use terms=["a","b"] not terms="[\"a\",\"b\"]"
Returns matching servers and tools with descriptions. Returns matching servers and tools with descriptions.
Use this when you don't know which module contains the tool you need. Use this when you don't know which module contains the tool you need.
+17 -4
View File
@@ -1135,17 +1135,30 @@ impl ExtensionManager {
tool_call: CallToolRequestParam, tool_call: CallToolRequestParam,
cancellation_token: CancellationToken, cancellation_token: CancellationToken,
) -> Result<ToolCallResult> { ) -> Result<ToolCallResult> {
// Some models strip the tool prefix, so auto-add it for known code_execution tools
let tool_name_str = tool_call.name.to_string();
let prefixed_name = if !tool_name_str.contains("__") {
let code_exec_tools = ["execute_code", "read_module", "search_modules"];
if code_exec_tools.contains(&tool_name_str.as_str())
&& self.extensions.lock().await.contains_key("code_execution")
{
format!("code_execution__{}", tool_name_str)
} else {
tool_name_str
}
} else {
tool_name_str
};
// Dispatch tool call based on the prefix naming convention // Dispatch tool call based on the prefix naming convention
let (client_name, client) = let (client_name, client) =
self.get_client_for_tool(&tool_call.name) self.get_client_for_tool(&prefixed_name)
.await .await
.ok_or_else(|| { .ok_or_else(|| {
ErrorData::new(ErrorCode::RESOURCE_NOT_FOUND, tool_call.name.clone(), None) ErrorData::new(ErrorCode::RESOURCE_NOT_FOUND, tool_call.name.clone(), None)
})?; })?;
// rsplit returns the iterator in reverse, tool_name is then at 0 let tool_name = prefixed_name
let tool_name = tool_call
.name
.strip_prefix(client_name.as_str()) .strip_prefix(client_name.as_str())
.and_then(|s| s.strip_prefix("__")) .and_then(|s| s.strip_prefix("__"))
.ok_or_else(|| { .ok_or_else(|| {