Commit Graph

86 Commits

Author SHA1 Message Date
sususu
df7e04ea28 fix(claude): upgrade default Claude Code baseline and fingerprint to 2.1.258
- Bump default Claude Code version baseline from 2.1.220 to 2.1.258 to resolve upstream 400 version gate error
- Update Stainless SDK package version to 0.112.1 and runtime version to v26.3.0
- Refresh default device profile, billing header build hashes, and cloaking signatures
- Decouple unconfirmed client OS/Arch test assertions from host runner platform
- Update config.example.yaml and test suites across executor and helps packages
2026-09-03 10:21:13 +08:00
Luis Pater
5ff4a31eaf feat(claude): support advisor tool beta header
- Add `advisor-tool-2026-03-01` beta header support when advisor server tools are declared or explicitly requested.
- Ensure proper ordering of the advisor tool beta before advanced tool use and effort betas.
- Inject and preserve advisor tool beta across token counting and fingerprint preservation paths.

Closes: #5330
2026-08-29 14:47:51 +08:00
Luis Pater
d36b776c79 fix(test): improve cross-platform compatibility across unit tests
- Support CRLF line endings and skip hidden dot directories in nocopy invariant tests.
- Handle environment variable overrides and skip case-sensitive token priority tests on Windows.
- Use static OS and architecture values in Claude header fingerprint assertions for deterministic test results.

Closes: #5295
2026-08-28 05:01:42 +08:00
Luis Pater
92d96e0b72 fix(cliproxy): support base_URL-only config credentials and skip stale auth headers
- Preserve API key entries with empty `api_key` when `base_url` is configured, and extend config dedupe/ID logic to include base URL, proxy, prefix, and headers so identities are stable.
- Update config/auth handling so `auth_kind=apikey` is treated as config API-key auth even without an `api_key` field, enabling base_url-only credential records.
- Ensure Gemini/Codex/XAI request path clears `Authorization`/provider auth headers when token is empty to avoid leaking unrelated auth state.
2026-08-20 15:19:07 +08:00
sususu98
85d2faddd1 fix(claude): preserve native subagent and environment headers (#4982) (#5084) 2026-08-20 00:30:41 +08:00
sususu
aec70dfec4 fix(claude): gate CCH signing by upstream origin and validate fingerprint-profile
Claude Code 2.1.220 through 2.1.234 emit the cch attribution only for
firstParty on api.anthropic.com and for vertex; every other backend sends
the billing header unsigned. CPA had dropped its endpoint check, so an
opted-in API key signed a per-request hash on any gateway and could bust
that gateway's prompt cache.

- Restore the endpoint gate in claudeCCHSigningEnabled: a real Claude OAuth
  credential still signs on every upstream, because a downstream Claude Code
  pointed at CPA cannot produce that value itself, while a claude-code-cli
  API key signs only on api.anthropic.com or Vertex
- Drop the unused origin parameter from Claude fingerprint policy resolution
  and restore the original resolveClaudeWirePolicy signature; the wire profile
  follows the credential and only CCH follows the origin
- Add config.NormalizeClaudeFingerprintProfile / ValidateClaudeFingerprintProfile
  as the single source of truth for fingerprint-profile values
- Reject unknown fingerprint-profile values in the Management API, and warn
  once per distinct value at request time instead of on every resolution,
  which previously logged about four warnings per request for one typo
- Preserve unrecognized values through config sanitization so rewriting a
  config file never discards operator input
- Update config.example.yaml and tests for the origin-scoped CCH behavior
2026-08-18 18:06:40 +08:00
sususu98
f1b0431c77 feat(claude): add fingerprint-profile=claude-code-cli for API keys and delegated providers (#5047)
* feat(config): add fingerprint-profile to Claude keys and auth JSON

- Add FingerprintProfile to ClaudeKey configuration struct and normalizer
- Track fingerprint-profile in config diff
- Map fingerprint-profile / fingerprint_profile to auth attributes in file and config synthesizers
- Support fingerprint-profile in Management API PatchClaudeKey and normalization
- Add Claude billing attribution string manipulation utilities in internal/util
- Document fingerprint-profile options in config.example.yaml

* feat(claude): add fingerprint policy and request-local CLI identity

- Centralize Claude fingerprint policy resolution in claude_fingerprint_policy.go
- Support stable Claude CLI identity synthesis (UUIDv5 account_uuid and SHA-256 device_id)
  seeded from API keys or stable OAuth IDs, keeping access tokens isolated
- Warn on unrecognized fingerprint-profile values

* feat(claude): apply CLI fingerprint to Messages and keep API keys caller-owned

- Wire centralized fingerprint policy into Claude and Kimi executors
- Keep first-party Anthropic API keys and delegated providers caller-owned by default
- Apply Claude Code CLI wire profile (betas, metadata, diagnostics, MCP aliases)
  when fingerprint-profile=claude-code-cli is configured
- Strictly align CCH signing with native Claude Code 2.1.220: only first-party
  api.anthropic.com and Vertex sign dynamic CCH; third-party gateways and Kimi
  receive billing header without cch= to avoid prompt cache busting
- Respect caller-owned count_tokens bodies by default while aligning CLI shape on opt-in
- Fall back to CLIProxyAPI/<version> User-Agent when caller sends no UA in caller-owned mode
- Scope custom operator header overrides accurately in caller-owned mode
- Add comprehensive test coverage for policy resolution, gateway opt-in, Kimi, and token counting
2026-08-18 17:29:26 +08:00
mardausdennis
297139cc8d fix(claude): keep tool_result blocks first when injecting currentDate
injectClaudeCodeCurrentDate inserted the reminder at index 0 of the first user message. Anthropic requires the message after an assistant tool_use turn to lead with its tool_result blocks, so the request was rejected with 400. Advance the insert index past leading tool_result blocks, matching the existing guard in prependClaudeSystemRemindersToFirstUserMessage. Every other content shape keeps the current index-0 placement.
2026-08-15 11:45:49 +08:00
sususu
8638f28db5 fix(claude): drop auto context_management without eligible thinking
Anthropic rejects the injected clear_thinking_20251015 strategy unless
thinking is enabled or adaptive:

  `clear_thinking_20251015` strategy requires `thinking` to be enabled or
  adaptive

Both sides of the automatic injection only special-cased the literal
{"type":"disabled"}, so an absent thinking field slipped through
gjson's empty string and the request was sent with a strategy the API
refuses. Two reachable paths produced it:

- a cloaked caller that never sent thinking at all;
- a caller whose thinking was enabled at injection time and then removed
  by disableThinkingIfToolChoiceForced, which runs between injection and
  reconciliation.

Both now test the accepted values instead of excluding the disabled one,
via a shared claudeThinkingAcceptsClearThinking helper, so reconciliation
also withdraws an object CPA injected itself once thinking disappears.
Caller-owned and payload-rule-owned objects keep their existing
precedence and are never withdrawn.

Verified against api.anthropic.com: context_management with thinking
absent or disabled returns 400, with thinking enabled returns 200. The
existing expectation that forced tool choice retains the automatic object
pinned the rejected shape and is inverted accordingly.
2026-08-11 19:33:40 +08:00
sususu
a8bbbea2b9 fix(claude): recognize and pass through native Haiku helpers
Claude Code issues measured Haiku helper requests that intentionally omit the
claude-code beta and, for the minimal shape, the system field. Treat those
profiles as confirmed native clients so CPA does not cloak or rewrite them.

Accept the native metadata builder optional parent_session_id, require
platform headers only for presence and software baseline rather than exact
equality, derive timeout and version from the same header defaults the emitter
uses, and keep discriminating signals strict: exact beta allowlist, body
shape, lowercase hex CCH, and session binding. Preserve helper transport
headers, omit synthetic stream false on markerless helpers, and gate the
billing and CCH fallback on system presence so a later pipeline-attached system
prompt cannot go upstream unsigned while the measured no-system wire stays
intact.
2026-08-11 19:33:40 +08:00
sususu
f0034ca663 fix(claude): restore cloaked prompt-cache ownership and native shape
Cloaked Responses/Chat/Gemini→Claude traffic was skipping ensureCacheControl
once the first-user cloak marker existed, freezing multi-turn cache hits.
Always ensure section-independent system and rolling-message breakpoints for
non-native callers, keep confirmed Claude Code placement intact, and leave
tools unstamped when a usable system prompt already covers the prefix.

Align the wire shape with the Claude Code 2.1.220/2.1.221/2.1.227 cache-control
constructor: the default is {"type":"ephemeral"} with no ttl. A 1h body ttl is
applied only after placement, only for OAuth credentials, and only onto blocks
that already carry cache_control, so it stays strictly paired with
extended-cache-ttl-2025-04-11. Explicit caller-owned 5m choices survive.

Match the native rolling selector (skip thinking-like assistant tails; final
system string special case), fall back to a tools breakpoint when system is
absent or blank, and leave empty/whitespace string systems unconverted so they
cannot double-stamp tools plus a useless system host.
2026-08-11 19:33:40 +08:00
Luis Pater
93c378b791 fix(claude): recover malformed OAuth MCP aliases when reverse-remapping Claude tool names
Closes: #4867
2026-08-10 04:32:28 +08:00
DefinitelyNotSpammy
533b69e3e0 fix(claude): skip context management when thinking is disabled 2026-08-05 18:25:40 +08:00
sususu
9b1142399c fix(claude): rebuild the Responses reasoning chain
A Responses caller that asked for reasoning summaries got an empty chain
of thought back: every reasoning item carried a signature and no text, so
replaying it produced a Claude thinking block with an empty thinking
field. The cause was the beta list, not the translator. Cloaked requests
always sent redact-thinking-2026-02-12, which makes Anthropic withhold
the summary text even when thinking.display is summarized.

Native Claude Code 2.1.220 treats the two as mutually exclusive: the beta
is only appended while thinking summaries are off, and the request
builder removes it again whenever a display value is attached. An
isolated 2.1.220 profile with showThinkingSummaries enabled confirms it
on the wire, still on cc_entrypoint=cli, sending display=summarized
without the beta and receiving thinking text. A direct A/B against
claude-opus-4-8 pins the effect down: with the beta the thinking text is
empty for every display value, without it and with display=summarized the
text comes back. The beta is now dropped whenever the request carries
thinking.display, which is exactly the native rule.

Two translation gaps kept the chain lossy on the way back. redacted_thinking
blocks had no Responses representation at all and vanished, even though
Anthropic requires them to be replayed verbatim; they now ride in
encrypted_content behind a marker prefix and are restored as
redacted_thinking blocks. Reasoning text was only read from summary[],
so a caller whose SDK models the text in content[] lost it; content[] is
now used as a fallback, and only as a fallback so a client that mirrors
both arrays does not replay the text twice.

An item whose encrypted_content is missing or belongs to another provider
is still dropped rather than replayed, because Anthropic rejects a
thinking block without a signature and there is nothing to synthesize.
2026-08-03 21:46:27 +08:00
sususu
6f8f11a324 fix(claude): carry caller system inputs into Claude system blocks
OpenAI callers can raise instructions above user content in three ways
and Claude has one system slot for all of them, but the translators
disagreed on where each one landed. Responses instructions became a
leading user turn, a role=system item was only demoted for the first
item, role=developer silently became user text, and the Chat translator
dropped developer messages outright. An operator instruction could
therefore lose its authority or disappear without any signal.

All five sources now become separate top-level Claude system blocks in
source order, so the executor cloak decides the final placement on its
own: a mid-conversation role=system message on models that accept one,
an individual <system-reminder> block on legacy models. Blocks are never
merged, trimmed, reordered or demoted.

Anthropic only accepts text in a system slot. Verified against
api.anthropic.com: the top-level system field rejects anything else with
"system.<i>.type: Input should be 'text'", and a role=system message
accepts text, tool_addition and tool_removal only. A non-text system part
is therefore kept as a typed marker without its payload and rejected by
the cloak with a request-scoped 400 that names the offending type. That
keeps the failure local, spends no upstream call on a request that cannot
succeed, and stops caller content from ever reaching the top-level system
field where it would break the Claude Code fingerprint shape.
2026-08-03 21:45:56 +08:00
sususu
3fac4a09d8 fix(claude): preserve cloak system block boundaries 2026-08-03 17:35:46 +08:00
sususu
3e70208d43 fix(claude): keep custom token counts local
Route count_tokens upstream only for the strict first-party Anthropic origin. Custom base URLs now use local estimation for both OAuth and API-key credentials.
2026-08-03 14:47:26 +08:00
sususu
1214326bd7 fix(claude): align OAuth betas with native accounts
Use advanced-tool-use for OAuth requests with tools and stop synthesizing cache-diagnosis. Two isolated Claude Code 2.1.220 OAuth accounts reproduced the same current profile.
2026-08-03 14:47:26 +08:00
sususu
ce7fcd920f fix(claude): keep client cancellation availability-neutral 2026-08-03 14:47:26 +08:00
sususu
2228847e63 fix(claude): close the count_tokens cloaking gap
A cloaked direct-Anthropic count_tokens request skipped applyCloaking entirely
while still reporting cloaked=true, so two guarantees that hold on the Messages
path were silently dropped on this endpoint:

- configured sensitive words reached Anthropic verbatim, even though the same
  words are obfuscated on the Messages request
- a third-party caller's system prompt was forwarded in the system slot, which
  measured Claude Code 2.1.220 count_tokens traffic never carries

Skipping the full Messages cloaking is still correct here, because native
count_tokens sends only model, messages and tools and must not gain the Claude
Code system blocks. Apply the two parts that do have to hold instead: relocate
the caller's system prompt into messages with the same positional mapping the
Messages path uses, so its tokens stay counted without leaking it as a system
prompt, and obfuscate sensitive words. Strict mode keeps dropping caller
prompts, matching the Messages path.
2026-08-03 14:47:26 +08:00
sususu
b3ed702e3a fix(claude): harden OAuth identity and native routing 2026-08-03 14:47:26 +08:00
sususu
fa6bc77f28 fix(claude): decode stacked response encodings 2026-08-03 14:47:26 +08:00
sususu
f63a925d15 fix(claude): replay measured OAuth wire, Fast and diagnostic profiles
Align the remaining measured OAuth wire profiles, including the ordered
connection writer in internal/httpwire that reproduces the observed header
sequence, and the refresh/profile response shapes in internal/auth/claude.

Replay the measured Fast path and keep diagnostic continuity across cloaked and
native requests.

Preserve the native direct token-counting shape so a caller that reaches
count_tokens itself is not reshaped into the cloaked form.

Scope cloak dates to the credential's timezone rather than the host's, so
currentDate matches what the real client would have sent for that account.
2026-08-03 14:47:26 +08:00
sususu
a2933c7737 fix(claude): scope Anthropic beta and count_tokens policies
Claude Code builds Anthropic-Beta per request instead of sending a fixed list.
Captured from an isolated 2.1.220 profile pointed at api.anthropic.com through
a local proxy, over two rounds covering 11 model IDs and the [1m] variants:

  constant  claude-code, interleaved-thinking, redact-thinking,
            thinking-token-count, context-management, prompt-caching-scope
  tools     advanced-tool-use-2025-11-20 only when tools are declared
  model     mid-conversation-system-2026-04-07 only on models that accept a
            role=system turn
  [1m]      context-1m-2025-08-07, directly after claude-code-20250219 rather
            than at the end
  trailing  effort-2025-11-24, then server-side-fallback-2026-06-01

claude-sonnet-5 emits mid-conversation-system-2026-04-07, so it accepts a
role=system turn and must not sit in the legacy reminder whitelist.

count_tokens does not reuse the inference fingerprint. Running /context in an
interactive session issues 37 identical calls, which made the endpoint
observable for the first time: four betas only, and 21 headers rather than 22
because X-Stainless-Timeout is absent. The profile is selected from the request
path so no call site has to thread another flag.
2026-08-03 14:47:26 +08:00
sususu
afdd251cca fix(claude): preserve semantics in MCP tool aliases
Keep the opaque MCP alias reversible and meaning-preserving so a cloaked
caller's tool declarations, choices and history survive the round trip without
changing tool ownership.
2026-08-03 14:47:26 +08:00
sususu
ef89c6a69d fix(claude): reconstruct cloaked system prompts like the real client
Preserve a cloaked caller's own system prompt instead of discarding it, place
it as a mid-conversation system turn on models that accept one, and route the
remaining legacy models through system reminders.

Scope the legacy reminder whitelist to official model IDs. claude-opus-4-6-thinking
was dropped: Anthropic publishes no -thinking IDs, that one belongs to the
antigravity provider in models.json and is served by a different executor, so it
can never reach ClaudeExecutor cloaking. Keeping it implied that synthetic
suffixes are normalized here, which they are not, since thinking.ParseSuffix only
strips parenthesis suffixes. The map is anchored to the "claude" provider block
plus Anthropic's bare and "-latest" aliases, and now covers claude-opus-4-7.
2026-08-03 14:47:26 +08:00
sususu
f3e25ab2ba feat(claude): align OAuth wire identity and TLS with Claude Code 2.1.220
Detect confirmed CLI, sdk-cli and VSCode callers before mutation so native
software, system, tool, cache and beta shapes pass through, while unconfirmed
OAuth clients receive a coherent minimum CLI identity.

Persist each Claude OAuth credential's upstream account metadata and one stable
device ID, derive one stable session per agent conversation, and keep body and
header identity synchronized across Messages, streaming and count_tokens.

Alias every cloaked third-party custom tool through caller-stable opaque MCP
names and restore declarations, choices, history, references, non-stream
responses and SSE events without changing tool ownership.

Implement the Claude Code 2.1.220 CCH algorithm over the final serialized
request bytes, align currentDate and first-user cache layout, update the
official beta/header baseline, and use upstream count_tokens for OAuth and
first-party Anthropic credentials.

Match the 2.1.220 TLS ClientHello so the transport fingerprint agrees with the
identity the request now claims, and document the CLI defaults and automatic
OAuth signing / tool alias behaviour in config.example.yaml.
2026-08-03 14:47:26 +08:00
Luis Pater
3d4e160495 feat(executor): add conditional support for Claude fast mode beta
- Introduced `claudeFastModeBeta` constant and logic to append it conditionally based on the `speed` attribute in the request body.
- Ensured `fast-mode-2026-02-01` beta inclusion only when explicitly requested or if the `speed` is set to `fast`.
- Updated `applyClaudeHeaders` to dynamically handle fast-mode beta and adjust headers accordingly.
- Enhanced beta extraction and addition with a new helper `appendClaudeFastModeBeta`.
- Improved flexibility in beta handling by preserving requested overrides while ensuring compatibility with default configurations.

Closes: #4703
2026-08-01 10:17:36 +08:00
sususu
b3046d29b9 feat(thinking): preserve cross-protocol summary visibility 2026-07-30 21:53:30 +08:00
Randi
c405398a48 fix: align Claude headers with upstream streaming 2026-07-27 19:07:57 -04:00
Luis Pater
57ef784224 feat(executor): implement local token counting for Claude requests
- Added `CountClaudeInputTokens` for estimating token usage with O200kBase tokenizer.
- Enhanced `ClaudeExecutor` to handle token counting locally, reducing dependency on upstream services.
- Introduced validation for token count requests for improved error handling.
- Updated tests to cover local token counting behavior and invalid request handling.

Closes: #4103
2026-07-27 00:50:11 +08:00
cyclopentadiene6
08e5515703 fix(executor): restore OAuth tool names from SSE responses 2026-07-26 23:28:18 +10:00
Code_G
29406436c3 fix(executor): keep tool_result blocks first when injecting the cloaking reminder
`prependToFirstUserMessage` always inserted the `<system-reminder>` text block at
index 0 of the first user message's content array. When a client sends a history
that begins with an assistant `tool_use` turn, that first user message is the
`tool_result` carrier, and Anthropic requires those blocks to stay at the head of
the message. Prepending pushed them out of first position, so the upstream
rejected the whole request with:

    messages.N: `tool_use` ids were found without `tool_result` blocks
    immediately after: <id>

Append the reminder instead when the content array already leads with a
`tool_result` block; behaviour is unchanged for every other message shape.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 03:02:43 +09:00
Luis Pater
76dc0fdc54 feat(executor): extend applyClaudeHeaders and Kimi executor with additional header support
- Added an `incomingHeaders` argument to `applyClaudeHeaders` to enable external header injection for flexibility.
- Updated Kimi executor to delegate header support to Claude executor, facilitating upstream request logging and beta header forwarding.
- Introduced tests for delegated configuration, header handling, and upstream request/response logging to improve coverage.
2026-07-18 19:36:09 +08:00
Luis Pater
4231ad6e2a fix(executor): ensure top_p is removed in normalizeClaudeSamplingForUpstream
- Updated `normalizeClaudeSamplingForUpstream` to delete `top_p` from payloads.
- Adjusted test to validate the removal of both `temperature` and `top_p`.

Closes: #4383
2026-07-17 16:43:26 +08:00
Luis Pater
bea9567051 feat(translator): add cache control handling for responses and messages
- Introduced `AttachCacheControl` and `AttachMessageCacheControl` utilities for consistent cache control injection in content parts and messages.
- Updated Claude translator modules to preserve and apply cache control metadata for responses, messages, tools, and parts.
- Added unit tests to validate proper cache control behavior across multiple scenarios.

Closes: #4146
2026-07-09 04:02:51 +08:00
Luis Pater
ab6ed392f2 test(executor): add unit test to validate complete SSE event passthrough in Claude executor
- Verified proper chunking and streaming of SSE events in `ExecuteStream`.
- Refactored executor to ensure complete SSE event delivery without partial fragments.

Closes: #4121
2026-07-07 15:23:02 +08:00
Luis Pater
5afc0f1d5e fix(translator): remove temperature parameter handling in Claude request transformations
Closes: #4071
2026-07-04 00:36:58 +08:00
Wolfgang Schoenberger
956ce7cf78 fix(registry): add Claude Sonnet 5 model metadata 2026-06-30 20:06:40 -07:00
sususu98
1f2504ebcc fix(claude): bypass signature sanitizer for non-Claude models (#3946)
* fix(claude): bypass signature sanitizer for non-Claude models

* test(claude): use subtests for sanitizer gate model cases
2026-06-21 23:06:38 +08:00
Luis Pater
790ec307f9 feat(config): add support for rebuild_mid_system_message configuration
- Introduced `RebuildMidSystemMessage` field in config to move system messages into the top-level Claude system field.
- Updated executor to handle mid-system message rebuilding when enabled via config or auth attributes.
- Added unit tests to verify rebuilding behavior and default behavior when disabled.
- Updated configuration example and API handlers to support the new field.

Closes: #3792
2026-06-20 12:15:06 +08:00
Luis Pater
844b855974 feat(executor): sanitize web search tool domains to meet Anthropic requirements
- Added `sanitizeClaudeWebSearchDomains` to remove empty `allowed_domains` and `blocked_domains` fields for built-in web_search tools, addressing ambiguity errors from Anthropic.
- Integrated domain sanitization into the Claude message preparation pipeline.
- Added test cases to validate correct handling of empty and non-empty domain fields across various tool types.

Closes: #2681
2026-06-16 03:29:44 +08:00
Luis Pater
2a050dc95d feat: enhance fault tolerance for kv-based caching and introduce additional tests
- Updated Antigravity Credits fallback to handle KV store unavailability as a service error.
- Enhanced signature caching mechanisms with request-time KV access and sliding expiration.
- Added and improved tests for KV client interactions, including error handling and expiration behaviors.
- Introduced `CacheSignatureBestEffort` for non-critical signature caching and clarified function flows with required context.
- Ensured consistent error reporting for missing or unavailable KV stores in various scenarios.
- Replaced direct `homekv` calls with injectable KV client interfaces for `antigravity` and `codex_reasoning_replay` modules.
- Improved error reporting and handling for KV operations, including `KVGet`, `KVSet`, `KVDel`, and `KVExpire`.
- Introduced dedicated fake KV clients for expanded and granular test coverage.
- Added new unit tests to validate KV client behaviors and error scenarios, ensuring robustness and sliding expiration functionality.
2026-06-14 21:11:35 +08:00
hkfires
8122b9fe4b feat!: remove amp integration support
BREAKING CHANGE: ampcode configuration, management endpoints, provider
routing, and X-Amp-Thread-Id session affinity are no longer supported
2026-06-14 20:31:00 +08:00
sususu98
aee7a5fbc5 feat: intercept incompatible signature replay 2026-05-29 15:22:57 +08:00
Luis Pater
e50cabac4b chore: upgrade CLIProxyAPI dependency to v7 across the project
- Updated all references from v6 to v7 for `github.com/router-for-me/CLIProxyAPI`.
- Ensured consistency in imports within core libraries, tests, and integration tests.
- Added missing tests for new features in Redis Protocol integration.
2026-05-08 11:46:46 +08:00
Luis Pater
bdc424007e Merge pull request #2896 from edlsh/fix/oauth-tool-rename-per-request-map
fix(amp): smart-mode tool name fixes + deep-mode response repair
2026-05-05 00:58:39 +08:00
Luis Pater
2753d9fb71 feat: add validation for Claude streaming responses
- Implemented `validateClaudeStreamingResponse` to ensure upstream streaming data integrity.
- Added new tests to verify response validation, including empty streams, error events, incomplete streams, and valid streams.
- Integrated validation logic into the Claude executor's streaming handler, returning detailed errors for malformed upstream data.

Fixed: #2193
2026-05-04 03:37:31 +08:00
Enzo Lucchesi
fc1ddf365f fix(claude): centralize oauth tool-name transform flow 2026-04-25 17:45:03 -04:00
Enzo Lucchesi
e707cf7d46 fix(claude): only reverse-remap OAuth tool names that were forward-renamed
remapOAuthToolNames renames lowercase client-sent tools (e.g. `glob` →
`Glob`) to Claude Code equivalents on OAuth requests to avoid tool-name
fingerprinting. The reverse pass previously ran against a *global*
reverse map and rewrote every tool_use block whose name matched any
value in oauthToolRenameMap — regardless of what the client actually
sent.

For clients that send mixed casing (notably Amp CLI — `Bash`, `Read`,
`Grep`, `Task` alongside `glob`, `skill`, etc.) this corrupted the
response. Any forward rename in the request set the "renamed" flag,
which then unconditionally lowercased every `Bash` in the response to
`bash`. Amp's tool registry has `Bash`, not `bash`, so it rejected the
tool_use with `tool "bash" is not allowed for smart mode` and tool
execution failed.

Fix: `remapOAuthToolNames` now returns a per-request map keyed on the
upstream (TitleCase) name valued with the original client-sent name.
The reverse functions take this map and only touch entries in it.
Names the client sent in TitleCase pass through untouched in both
directions.

- Change remapOAuthToolNames signature from `([]byte, bool)` to
  `([]byte, map[string]string)`; populate at every rename site
  (tools[], tool_choice.name, message tool_use, tool_reference,
  nested tool_reference inside tool_result).
- Change reverseRemapOAuthToolNames and
  reverseRemapOAuthToolNamesFromStreamLine to accept and consume the
  per-request map; remove the global oauthToolRenameReverseMap.
- Update all three executor call sites (Execute, ExecuteStream direct
  passthrough, ExecuteStream translated) + count_tokens.
- Add regression tests for the mixed-case scenario in both the
  non-streaming and SSE code paths.
2026-04-25 17:45:03 -04:00