← Back to PRs

#11453: fix: apply normalizeToolName() at all tool lookup points

by sypsyp97 open 2026-02-07 20:41 View on GitHub →
gateway agents stale size: S
## Summary Apply `normalizeToolName()` consistently at tool dispatch entry points to handle model-generated tool names with leading/trailing whitespace or unexpected casing. Fixes #11441. ## Problem When a model outputs a tool call with leading/trailing whitespace in the tool name (e.g., `" exec"` instead of `"exec"`), OpenClaw fails to find the tool and returns "Tool not found". The existing `normalizeToolName()` function already handles `.trim()` + `.toLowerCase()` + alias resolution, but was not applied at all lookup points. ## Changes - **`src/gateway/tools-invoke-http.ts`**: Replace bare `.trim()` with `normalizeToolName()` for the HTTP tools/invoke endpoint — this also adds alias resolution (`bash` → `exec`) and case normalization that `.trim()` alone misses. - **`src/auto-reply/reply/get-reply-inline-actions.ts`**: Normalize `dispatch.toolName` before tool lookup in skill command dispatch. - **`src/agents/tool-policy.normalize-tool-name.test.ts`**: Add test coverage for `normalizeToolName()` edge cases — whitespace trimming, case normalization, alias resolution, and empty input handling. ## Upstream note The core model→tool dispatch in `@mariozechner/pi-agent-core` (`agent-loop.js` `executeToolCalls`) also uses strict `===` equality without trimming: ```js const tool = tools?.find((t) => t.name === toolCall.name); ``` Fixing that lookup upstream would fully resolve the issue for all model-generated tool calls. This PR addresses the OpenClaw-controlled dispatch points. ## Testing - [x] New unit tests for `normalizeToolName()` covering whitespace, casing, aliases, empty input - [x] AI-assisted (OpenClaw agent + Claude Opus 4.6); changes reviewed and understood - [x] CI: `pnpm build && pnpm check && pnpm test` <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR makes tool dispatch more tolerant of model-generated tool names by applying `normalizeToolName()` (trim + lowercase + alias resolution) at additional entry points: - `/tools/invoke` HTTP handler now normalizes `body.tool` before policy checks and lookup. - Inline skill command tool dispatch now normalizes `dispatch.toolName` before searching the available tool list. - Adds Vitest coverage for `normalizeToolName()` behavior around whitespace, casing, aliases, and empty input. Overall this improves resilience to minor formatting differences in tool call names, but care is needed to ensure alias normalization doesn’t break lookups when any tools are registered under an aliased (non-canonical) name. <h3>Confidence Score: 4/5</h3> - This PR is likely safe to merge, with one correctness check needed around alias vs canonical tool names in HTTP tool invocation. - Changes are small and targeted (normalizing tool names at dispatch boundaries plus unit tests). The main remaining risk is behavior change when callers send an alias (e.g. "bash") but the actual registered tool name is the alias rather than the canonical name, which would cause a new 404 until lookup/registration is made consistent. - src/gateway/tools-invoke-http.ts <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs