Skip to content

Runner: normalize malformed tool call names before dispatch#39328

Merged
vincentkoc merged 3 commits intomainfrom
vincentkoc-code/clean-tool-name-normalization
Mar 8, 2026
Merged

Runner: normalize malformed tool call names before dispatch#39328
vincentkoc merged 3 commits intomainfrom
vincentkoc-code/clean-tool-name-normalization

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • Problem: some models emit tool names with provider prefixes or alternate tool-call block types, which can miss canonical tool dispatch and surface as Tool not found failures.
  • Why it matters: the same underlying tool may be available, but malformed/prefixed names like functions.read or tools/exec still fail before dispatch.
  • What changed: the embedded runner now strips common provider prefixes before matching against the allowed tool set, and applies the same normalization path to toolCall, toolUse, and functionCall blocks.
  • What did NOT change (scope boundary): this does not change tool-call argument validation, parallel_tool_calls compatibility, or the already-fixed onboarding tools.profile regression path.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

Malformed but recoverable tool names such as functions.read and tools/exec now normalize to the underlying canonical tool when that tool is allowed. Alternate tool-call block types (toolUse, functionCall) now get the same pre-dispatch normalization path as toolCall.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node.js 22 + pnpm
  • Model/provider: unit-test path
  • Integration/channel (if any): n/a
  • Relevant config (redacted): n/a

Steps

  1. Pass streamed or final assistant messages containing prefixed tool names such as functions.read or tools/exec through wrapStreamFnTrimToolCallNames(...) with canonical tools allowed.
  2. Pass toolUse / functionCall blocks with padded tool names through the same path.
  3. Observe normalized names before dispatch.

Expected

  • recoverable prefixed tool names normalize to canonical allowed tools
  • all supported tool-call block types share the same normalization path

Actual

  • provider-prefixed names were left unmatched and could fail dispatch
  • toolUse / functionCall names were not normalized in the same way as toolCall

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: pnpm vitest run src/agents/pi-embedded-runner/run/attempt.test.ts; pnpm check src/agents/pi-embedded-runner/run/attempt.ts src/agents/pi-embedded-runner/run/attempt.test.ts
  • Edge cases checked: alias normalization still works; whitespace-only placeholder names still preserve existing behavior
  • What you did not verify: live provider/channel end-to-end runs

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert commit 52274526ac
  • Files/config to restore: src/agents/pi-embedded-runner/run/attempt.ts, src/agents/pi-embedded-runner/run/attempt.test.ts
  • Known bad symptoms reviewers should watch for: provider-prefixed names no longer dispatching to their canonical tool, or alternate tool-call block types behaving differently from toolCall

Risks and Mitigations

  • Risk: normalization could accidentally over-match a malformed provider name to the wrong tool.
    • Mitigation: normalization only accepts suffixes that already match the allowed tool set or its existing alias normalization path, and ambiguity falls back to the candidate instead of forcing an arbitrary canonical name.

@vincentkoc vincentkoc self-assigned this Mar 8, 2026
@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S maintainer Maintainer-authored PR labels Mar 8, 2026
@vincentkoc vincentkoc marked this pull request as ready for review March 8, 2026 01:23
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR fixes a class of Tool not found dispatch failures by normalizing provider-prefixed tool names (e.g. functions.read, tools/exec) to their canonical equivalents before dispatch, and extends the same normalization path to toolUse and functionCall block types alongside the existing toolCall handling.

Key changes:

  • normalizeToolCallNameForDispatch now builds a candidate set from the full trimmed name, its alias-normalized form, and the suffix after the last .// delimiter (plus its alias-normalized form), checking exact then case-insensitive matches across all candidates.
  • trimWhitespaceFromToolCallNamesInMessage is widened to process toolUse and functionCall blocks via the shared isToolCallBlockType predicate, giving all three block types a consistent pre-dispatch normalization path.

Note: While the test at line 307 is titled "normalizes toolUse and functionCall names before dispatch," it currently only exercises whitespace trimming for those block types, not prefix-stripping normalization. Consider expanding that test with an allowedToolNames set and prefixed tool names to match the coverage in the preceding toolCall test.

Confidence Score: 4/5

  • This PR is safe to merge; it is backward-compatible, tightly scoped, and the core normalization logic is correct.
  • The implementation is logically sound: exact matches are checked before case-insensitive fallback, suffix extraction only triggers when the full name isn't recognized, and all path changes are covered by at least one unit test. The normalization logic correctly handles the target use case (provider-prefixed names and block type aliases). The test coverage gap noted for toolUse/functionCall prefix-stripping is a minor documentation concern that doesn't affect correctness for realistic tool-catalogue shapes (all-lowercase canonical names).
  • src/agents/pi-embedded-runner/run/attempt.test.ts (test coverage enhancement for toolUse/functionCall prefix-stripping, optional)

Last reviewed commit: 00dd796

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00dd7963a4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@vincentkoc vincentkoc merged commit 69a6c0a into main Mar 8, 2026
28 of 29 checks passed
@vincentkoc vincentkoc deleted the vincentkoc-code/clean-tool-name-normalization branch March 8, 2026 01:34
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26f5184646

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +262 to +264
for (let index = 1; index < segments.length; index += 1) {
const suffix = segments.slice(index).join(".");
candidateNames.add(suffix);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restrict suffix fallback to known provider prefixes

Building candidates from every dotted/slashed suffix can remap arbitrary namespaced tool calls to unrelated allowed tools. For example, if only search is allowed, a model output like calendar.search will now normalize to search and execute it instead of failing with tool-not-found as before. That is a behavior regression introduced here and can cause unintended side effects when models emit non-provider namespaces; this fallback should be limited to known provider prefixes (e.g. functions. / tools/) rather than dropping any leading segment(s).

Useful? React with 👍 / 👎.

vincentkoc added a commit that referenced this pull request Mar 8, 2026
vincentkoc added a commit that referenced this pull request Mar 8, 2026
vincentkoc added a commit to BryanTegomoh/openclaw-fork that referenced this pull request Mar 8, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
vincentkoc added a commit to BryanTegomoh/openclaw-fork that referenced this pull request Mar 8, 2026
vincentkoc added a commit to BryanTegomoh/openclaw-fork that referenced this pull request Mar 8, 2026
openperf pushed a commit to openperf/moltbot that referenced this pull request Mar 8, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
openperf pushed a commit to openperf/moltbot that referenced this pull request Mar 8, 2026
openperf pushed a commit to openperf/moltbot that referenced this pull request Mar 8, 2026
mcaxtr pushed a commit to mcaxtr/openclaw that referenced this pull request Mar 8, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
mcaxtr pushed a commit to mcaxtr/openclaw that referenced this pull request Mar 8, 2026
mcaxtr pushed a commit to mcaxtr/openclaw that referenced this pull request Mar 8, 2026
Saitop pushed a commit to NomiciAI/openclaw that referenced this pull request Mar 8, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
Saitop pushed a commit to NomiciAI/openclaw that referenced this pull request Mar 8, 2026
Saitop pushed a commit to NomiciAI/openclaw that referenced this pull request Mar 8, 2026
GordonSH-oss pushed a commit to GordonSH-oss/openclaw that referenced this pull request Mar 9, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
GordonSH-oss pushed a commit to GordonSH-oss/openclaw that referenced this pull request Mar 9, 2026
GordonSH-oss pushed a commit to GordonSH-oss/openclaw that referenced this pull request Mar 9, 2026
jenawant pushed a commit to jenawant/openclaw that referenced this pull request Mar 10, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
jenawant pushed a commit to jenawant/openclaw that referenced this pull request Mar 10, 2026
jenawant pushed a commit to jenawant/openclaw that referenced this pull request Mar 10, 2026
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
…#39328)

* Runner: normalize malformed tool call names before dispatch

* Runner: tighten prefixed tool name normalization
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 22, 2026
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 22, 2026
alexey-pelykh added a commit to remoteclaw/remoteclaw that referenced this pull request Mar 22, 2026
…r live test fixes (#1795)

* Changelog: credit openclaw#39328 to @vincentkoc

(cherry picked from commit 2ec478c)

* Changelog: move openclaw#39328 credit to section end

(cherry picked from commit 5b30c9d)

* Pi Runner: gate parallel_tool_calls to compatible APIs (openclaw#39356)

* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging

(cherry picked from commit daecd2d)

# Conflicts:
#	CHANGELOG.md
#	src/agents/pi-embedded-runner-extraparams.test.ts
#	src/agents/pi-embedded-runner/extra-params.ts

* docs: add changelog for Telegram DM draft restore (openclaw#39398)

(cherry picked from commit 722c5e5)

* fix: document discord agentComponents schema parity (openclaw#39378) (thanks @gambletan) (openclaw#39378)

Co-authored-by: Shadow <[email protected]>
(cherry picked from commit 9c8e34d)

* fix: land openclaw#39337 by @goodspeed-apps for acpx MCP bootstrap

Co-authored-by: Goodspeed App Studio <[email protected]>
(cherry picked from commit 5659d7f)

# Conflicts:
#	extensions/acpx/openclaw.plugin.json
#	extensions/acpx/src/config.test.ts
#	extensions/acpx/src/config.ts
#	extensions/acpx/src/runtime-internals/test-fixtures.ts
#	extensions/acpx/src/runtime.test.ts
#	extensions/acpx/src/runtime.ts
#	extensions/acpx/src/service.ts

* docs: clean up latest changelog sections

(cherry picked from commit c743fd9)

* fix: land contributor PR openclaw#39516 from @Imhermes1

macOS app/chat/browser/cron/permissions fixes.

Co-authored-by: ImHermes1 <[email protected]>
(cherry picked from commit d15b6af)

# Conflicts:
#	CHANGELOG.md
#	apps/macos/Sources/RemoteClaw/NodeMode/MacNodeBrowserProxy.swift
#	apps/macos/Sources/RemoteClaw/NodeMode/MacNodeModeCoordinator.swift
#	apps/macos/Sources/RemoteClaw/NodeMode/MacNodeRuntime.swift
#	apps/macos/Sources/RemoteClaw/PermissionsSettings.swift
#	apps/macos/Tests/RemoteClawIPCTests/MacNodeBrowserProxyTests.swift
#	apps/shared/RemoteClawKit/Sources/RemoteClawChatUI/ChatView.swift
#	apps/shared/RemoteClawKit/Sources/RemoteClawKit/BrowserCommands.swift
#	apps/shared/RemoteClawKit/Tests/RemoteClawKitTests/ChatComposerPasteSupportTests.swift

* fix: stage docker live tests from mounted source

(cherry picked from commit 21df014)

* fix: add minimal process shim for acpx mcp-agent-command

The upstream process.ts depends on gutted runtime-api, so provide a
minimal spawnAndCollect implementation that satisfies the import.

---------

Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: gambletan <[email protected]>
Co-authored-by: Shadow <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: toolCallId parsing inconsistency causes Tool not found"

1 participant