Skip to content

fix(mimic): rewrite tool_use names in messages to match renamed tools#2340

Open
iFwu wants to merge 1 commit intoWei-Shaw:mainfrom
iFwu:fix/mimic-rewrite-tool-use-in-messages
Open

fix(mimic): rewrite tool_use names in messages to match renamed tools#2340
iFwu wants to merge 1 commit intoWei-Shaw:mainfrom
iFwu:fix/mimic-rewrite-tool-use-in-messages

Conversation

@iFwu
Copy link
Copy Markdown

@iFwu iFwu commented May 10, 2026

Summary

When claude_code_mimic rewrites tool names in tools[] and tool_choice, it currently leaves messages[].content[].name blocks (type == "tool_use") with their original names. Anthropic validates that every tool referenced by a tool_use block is declared in tools[], so the mismatch produces an error like:

messages.N.content.M: Input tag 'original_name' not found in tools

surfaced as HTTP 400 directly, or wrapped as 424 by upstream proxies (e.g. Bedrock gateways).

Reproduction

  1. An account with extra.claude_code_mimic = true
  2. A client that sends tools beyond the Claude Code built-in set (e.g. web_search, or any user-defined tool whose name gets rewritten)
  3. A multi-turn request where the assistant has previously invoked one of those tools, so the history contains tool_use blocks referencing the original name

The rewrite renames tools[*].name, but the older tool_use blocks in messages still point at the old name → Anthropic rejects the request.

Why Parrot didn't need this

The existing code comment referenced Parrot's behavior:

历史 $.messages[*].content[*].name(tool_use)不在请求侧改写——这与 Parrot 一致;响应侧 bytes.Replace 会连带还原它们。

Parrot only mimics Claude Code's built-in tool set, so by construction messages[].name and tools[].name use the same set of names, and there is no cross-turn mismatch. sub2api is more permissive — clients may send any tools[] — so the assumption no longer holds for historical tool_use blocks, which were named back when the rewrite hadn't been applied yet.

Fix

Apply the same ToolNameRewrite.Forward map to messages[].content[] entries where type == "tool_use", keeping tools[], tool_choice and messages self-consistent before the request hits Anthropic.

  • tool_result blocks reference tools via tool_use_id, not name, so they don't need changes.
  • Server tools (e.g. web_search_20250305 with non-empty type) are still skipped by shouldMimicToolName, so they aren't touched.
  • Response-side bytes.Replace still restores the original names in the final output, so the client sees no difference.

Testing

Added TestApplyToolNameRewriteToBody_RenamesToolUseInMessages to gateway_tool_rewrite_test.go, covering:

  • tools[*].name rewritten
  • tool_choice.name rewritten
  • messages[*].content[*].name (type == "tool_use") rewritten
  • Server tools (type != "") untouched
  • Text blocks untouched
  • tool_result blocks untouched (no name field)
$ go test ./internal/service/ -run TestApplyToolNameRewriteToBody -v
=== RUN   TestApplyToolNameRewriteToBody_RenamesToolsAndToolChoice
--- PASS: TestApplyToolNameRewriteToBody_RenamesToolsAndToolChoice (0.00s)
=== RUN   TestApplyToolNameRewriteToBody_RenamesToolUseInMessages
--- PASS: TestApplyToolNameRewriteToBody_RenamesToolUseInMessages (0.00s)
PASS

Validated in production: previously the affected account hit 424 on every multi-turn request containing web_search tool_use history; after this fix those requests succeed.

The Claude Code mimic path rewrites tool names in tools[] (and
tool_choice) but left tool_use blocks in messages[] with their
original names. Anthropic validates that every tool referenced by
a tool_use block is declared in tools[], so the mismatch produces:

    messages.N.content.M: Input tag 'original_name' not found in tools

(surfaced as HTTP 400 directly, or wrapped as 424 by upstream proxies
such as Bedrock gateways.)

The previous code comment asserted 'this matches Parrot; response-side
bytes.Replace will restore the names'. Parrot's behavior is fine for
Claude Code's own tool set, but breaks once the upstream client sends
additional tools (e.g. web_search) that are not part of Claude Code
and therefore get renamed here.

Fix: apply the same ToolNameRewrite to messages[].content[] blocks
where type == 'tool_use', keeping tools[], tool_choice and messages
self-consistent before the request reaches Anthropic. tool_result
blocks reference tools via tool_use_id, not name, so no change is
needed there.

A new unit test covers the full rewrite flow and guards against
server tools (type != '') being affected.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

All contributors have signed the CLA. ✅
Posted by the CLA Assistant Lite bot.

@iFwu
Copy link
Copy Markdown
Author

iFwu commented May 10, 2026

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request May 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant