From d8f01693f43278eac8363d0317b6371761d89493 Mon Sep 17 00:00:00 2001 From: "ilblackdragon@gmail.com" Date: Sun, 22 Mar 2026 23:03:52 -0700 Subject: [PATCH] fix(bridge): convert tool name hyphens to underscores for Python compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause from trace analysis: the LLM writes `web_search()` (valid Python identifier) but the tool registry has `web-search` (with hyphen). The EffectBridgeAdapter couldn't find the tool → "Tool not found" error → model fabricated fake data instead. Fixes: - available_actions(): converts tool names from hyphens to underscores (web-search → web_search) so the system prompt lists valid Python names - execute_action(): tries the original name first, then falls back to hyphenated form (web_search → web-search) for tool registry lookup - Same conversion in router's capability registry builder Co-Authored-By: Claude Opus 4.6 (1M context) --- src/bridge/effect_adapter.rs | 15 +++++++++++++-- src/bridge/router.rs | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/bridge/effect_adapter.rs b/src/bridge/effect_adapter.rs index 972ecba9..f83bc45e 100644 --- a/src/bridge/effect_adapter.rs +++ b/src/bridge/effect_adapter.rs @@ -39,11 +39,21 @@ impl EffectExecutor for EffectBridgeAdapter { format!("Thread {}", context.thread_id), ); + // Convert Python identifier (underscores) back to tool name (hyphens). + // Python can't have hyphens in function names, so the system prompt + // lists tools with underscores. We need to try both forms. + let hyphenated = action_name.replace('_', "-"); + let lookup_name = if self.tools.get(action_name).await.is_some() { + action_name + } else { + &hyphenated + }; + // Execute through the existing tool pipeline let result = crate::tools::execute::execute_tool_with_safety( &self.tools, &self.safety, - action_name, + lookup_name, ¶meters, &job_ctx, ) @@ -75,7 +85,8 @@ impl EffectExecutor for EffectBridgeAdapter { Ok(tool_defs .into_iter() .map(|td| ActionDef { - name: td.name, + // Convert hyphens to underscores for valid Python identifiers + name: td.name.replace('-', "_"), description: td.description, parameters_schema: td.parameters, effects: vec![], // Effect classification happens at the engine level diff --git a/src/bridge/router.rs b/src/bridge/router.rs index 5c7a4129..5034ed88 100644 --- a/src/bridge/router.rs +++ b/src/bridge/router.rs @@ -75,7 +75,7 @@ async fn get_or_init_engine(agent: &Agent) -> Result<(), Error> { actions: tool_defs .into_iter() .map(|td| ironclaw_engine::ActionDef { - name: td.name, + name: td.name.replace('-', "_"), description: td.description, parameters_schema: td.parameters, effects: vec![],