Skip to content

fix(executors): preserve tool-name casing on native Claude OAuth (#4307) - #4314

Merged
diegosouzapw merged 1 commit into
release/v3.8.30from
fix/4307-tool-name-case
Jun 19, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.30from
fix/4307-tool-name-case

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Closes #4307

Problem

Native Claude OAuth traffic runs through an anti-fingerprint tool-name cloak (remapToolNamesInRequest/cloakThirdPartyToolNames) that renames a tool literally named read → Read on the wire and records the reverse alias (Read → read) on a non-enumerable body._toolNameMap. The response side un-cloaks the streamed tool_use.name back to the client's original casing using that map.

Since v3.8.27 (#3941/#3968) execute() returns a JSON.parse(JSON.stringify())-round-tripped serializedBody as result.transformedBody. The round-trip drops the non-enumerable _toolNameMap, so chatCore's response-side restore sees an empty map and the cloaked Read streams verbatim to the client — corrupting the tool name (reporter: read → Read, also affects write/bash/etc.). Turning compression off does not help (it is unrelated); works direct-to-OpenRouter (cloak only fires for the native claude provider).

Fix

open-sse/executors/base.ts — after building serializedBody, re-attach the live _toolNameMap from transformedBody (non-enumerable, so it never re-serializes upstream). Mirrors the existing antigravity.ts::attachToolNameMap pattern and the #4091 capture-boundary guard.

Validation (Hard Rule #18 — TDD)

tests/unit/tool-name-case-preserve-4307.test.ts exercises the real base.ts execute() through the claude-OAuth cloak path (mocked fetch), asserting:

  • precondition: the cloak fired (Read sent upstream; map not serialized on the wire);
  • regression guard: result.transformedBody._toolNameMap is a Map restoring Read → read (fails RED on unfixed code, passes GREEN with the fix), and stays non-enumerable.

Related toolname/cloak/executor suites (4091/4181/oauth-cloak/passthrough/field-400) green (47/47). Lint + typecheck:core clean. base.ts file-size baseline bumped 1358 → 1387 in the same commit.

The native-Claude OAuth anti-fingerprint cloak renames a tool named `read`
to `Read` on the wire and records the reverse alias on a non-enumerable
`_toolNameMap`, which the response side un-cloaks to restore the client's
original casing. Since v3.8.27 (#3941/#3968) `execute()` returned a
JSON-round-tripped `serializedBody` as `transformedBody`; the round-trip
drops the non-enumerable map, so the restore saw an empty map and the
cloaked `Read` streamed verbatim to the client.

Re-attach the live `_toolNameMap` onto the serialized body before returning
(non-enumerable, mirrors antigravity.ts::attachToolNameMap) so tool-name
casing round-trips correctly.

Regression test exercises base.ts execute() through the claude-OAuth cloak
path and asserts the returned transformedBody carries the reverse map.

Closes #4307
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@diegosouzapw
diegosouzapw merged commit 6103288 into release/v3.8.30 Jun 19, 2026
4 checks passed
@diegosouzapw
diegosouzapw deleted the fix/4307-tool-name-case branch June 19, 2026 23:45
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…gosouzapw#4307) (diegosouzapw#4314)

The native-Claude OAuth anti-fingerprint cloak renames a tool named `read`
to `Read` on the wire and records the reverse alias on a non-enumerable
`_toolNameMap`, which the response side un-cloaks to restore the client's
original casing. Since v3.8.27 (diegosouzapw#3941/diegosouzapw#3968) `execute()` returned a
JSON-round-tripped `serializedBody` as `transformedBody`; the round-trip
drops the non-enumerable map, so the restore saw an empty map and the
cloaked `Read` streamed verbatim to the client.

Re-attach the live `_toolNameMap` onto the serialized body before returning
(non-enumerable, mirrors antigravity.ts::attachToolNameMap) so tool-name
casing round-trips correctly.

Regression test exercises base.ts execute() through the claude-OAuth cloak
path and asserts the returned transformedBody carries the reverse map.

Closes diegosouzapw#4307
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