From 52dd6697c6ca11f9ccfeb6a04804a6204d3082ee Mon Sep 17 00:00:00 2001 From: john Date: Wed, 23 Sep 2026 14:25:12 +0800 Subject: [PATCH] fix(agents): recover bare tool names to their unique prefixed tool Models prompted with bare names such as write_file hit 'Tool not advertised' even though sandbox-fs__write_file was available. Ambiguous matches still fail. Co-authored-by: Cursor --- crates/goose/src/agents/extension_manager.rs | 37 +++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/agents/extension_manager.rs b/crates/goose/src/agents/extension_manager.rs index bc48d0e30..27522adc1 100644 --- a/crates/goose/src/agents/extension_manager.rs +++ b/crates/goose/src/agents/extension_manager.rs @@ -309,10 +309,15 @@ pub(crate) fn recover_mangled_tool_name<'a>( let owner_mangled = owner.map(|o| format!("{o}.{name}")); let owner_prefixed = owner.map(|o| format!("{o}__{name}")); + // Models prompted with bare tool names ("write_file") drop the extension + // prefix entirely; recover only when exactly one extension owns that tool. + let bare_tool = name.split_once("__").map(|(_, tool)| tool); + let matches = stripped == name || separator_mangled.as_deref() == Some(stripped) || owner_mangled.as_deref() == Some(stripped) - || owner_prefixed.as_deref() == Some(stripped); + || owner_prefixed.as_deref() == Some(stripped) + || bare_tool == Some(stripped); if name == emitted || !matches { continue; } @@ -3805,6 +3810,36 @@ mod tests { ); } + #[test] + fn test_recover_mangled_tool_name_bare_tool_without_extension_prefix() { + let tools = [ + ("sandbox-fs__write_file", None), + ("sandbox-fs__read_file", None), + ("developer__shell", None), + ]; + assert_eq!( + recover_mangled_tool_name("write_file", tools.iter().copied()).as_deref(), + Some("sandbox-fs__write_file") + ); + assert_eq!( + recover_mangled_tool_name("functions.read_file", tools.iter().copied()).as_deref(), + Some("sandbox-fs__read_file") + ); + assert_eq!( + recover_mangled_tool_name("edit_file", tools.iter().copied()), + None + ); + + let ambiguous = [ + ("sandbox-fs__write_file", None), + ("other__write_file", None), + ]; + assert_eq!( + recover_mangled_tool_name("write_file", ambiguous.iter().copied()), + None + ); + } + #[test] fn test_recover_mangled_tool_name_non_extension_manager_tools() { // recipe__final_output and platform__manage_schedule are appended by