- 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.
- 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
All streaming executors use bare channel sends (out <- chunk) inside goroutines
that process upstream SSE responses. When the downstream consumer disconnects
(client timeout, network drop, etc.), these sends block indefinitely, causing
the goroutine and all associated resources (HTTP response body, scanner buffers,
translation state) to leak permanently.
Over time, leaked goroutines accumulate monotonically, leading to RSS growth
from ~30MB to 3.7GB+ and eventual OOM kills on resource-constrained VPS hosts.
Fix: Replace all bare 'out <- ...' sends with:
select {
case out <- ...:
case <-ctx.Done():
return
}
This ensures goroutines terminate promptly when the request context is canceled,
allowing GC to reclaim all associated resources.
Affected executors (9 files, 36+ send sites):
- antigravity_executor.go (5 sites)
- gemini_cli_executor.go (6 sites)
- gemini_vertex_executor.go (6 sites)
- aistudio_executor.go (4 sites)
- gemini_executor.go (3 sites)
- openai_compat_executor.go (3 sites)
- claude_executor.go (4 sites)
- codex_executor.go (2 sites)
- kimi_executor.go (3 sites)
- Introduced `DisableImageGenerationMode` with support for `false`, `true`, and `chat` values.
- Updated payload handling to preserve `image_generation` on images endpoints when `chat` mode is enabled.
- Modified OpenAI image handlers (`ImagesGenerations`, `ImagesEdits`) to respect tri-state logic.
- Added unit tests for `DisableImageGenerationMode` behavior and endpoint-specific handling.
- Enhanced configuration diff logging to support `DisableImageGenerationMode`.
Address Gemini code review suggestion: the reverseMap can contain at
most len(oauthToolRenameMap) entries, so pre-allocating avoids
reallocations as entries are added.
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.
Anthropic has moved the 1M-context-window feature to General Availability,
so the context-1m-2025-08-07 beta flag is no longer accepted and now causes
400 Bad Request errors when forwarded upstream.
Remove the X-CPA-CLAUDE-1M detection and the corresponding injection of the
now-invalid beta header. Also drop the unused net/textproto import that was
only needed for the header-key lookup.
- Introduced `WithProxyURL` variants for `CodexAuth`, `ClaudeAuth`, `IFlowAuth`, and `DeviceFlowClient`.
- Updated executors to use proxy-aware constructors for improved configurability.
- Added unit tests to validate proxy override precedence and functionality.
Closes: #2823
- Use buildTextBlock for billing header to avoid raw JSON string interpolation
- Fix empty array edge case in prependToFirstUserMessage
- Allow remapOAuthToolNames to process messages even without tools array
- Move claude_system_prompt.go to helps/ per repo convention
- Export prompt constants (ClaudeCode* prefix) for cross-package access
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
A/B testing confirmed that Anthropic uses tool name fingerprinting to detect
third-party clients on OAuth traffic. OpenCode-style lowercase names like
'bash', 'read', 'todowrite' trigger extra-usage billing, while Claude Code
TitleCase names like 'Bash', 'Read', 'TodoWrite' pass through normally.
Changes:
- Add oauthToolRenameMap: maps lowercase tool names to Claude Code equivalents
- Add oauthToolsToRemove: removes 'question' and 'skill' (no Claude Code counterpart)
- remapOAuthToolNames: renames tools, removes blacklisted ones, updates tool_choice and messages
- reverseRemapOAuthToolNames/reverseRemapOAuthToolNamesFromStreamLine: reverse map for responses
- Apply in Execute(), ExecuteStream(), and CountTokens() for OAuth token requests
Only for Claude OAuth requests, sanitize forwarded system-prompt context before
it is prepended into the first user message. This preserves neutral task/tool
instructions while removing OpenCode branding, docs links, environment banners,
and product-specific workflow sections that still triggered Anthropic extra-usage
classification after top-level system[] cloaking.
sjson treats 'cache_control.type' as nested path, creating
{ephemeral: {scope: org}} instead of {type: ephemeral, scope: org}.
Pass the whole map to sjson.SetBytes as a single value.
The previous commit used fmt.Sprintf with %s to insert multi-line string
constants into JSON strings. Go raw string literals contain actual newline
bytes, which produce invalid JSON (control characters in string values).
Replace with buildTextBlock() helper that uses sjson.SetBytes to properly
escape text content for JSON serialization.
Previous fix only injected billing header + agent identifier (2 blocks).
Anthropic's updated detection now validates system prompt content depth:
- Block count (needs 4-6 blocks, not 2)
- Cache control scopes (org for agent, global for core prompt)
- Presence of known Claude Code instruction sections
Changes:
- Add claude_system_prompt.go with extracted Claude Code v2.1.63 system prompt
sections (intro, system instructions, doing tasks, tone & style, output efficiency)
- Rewrite checkSystemInstructionsWithSigningMode to build 5 system blocks:
[0] billing header (no cache_control)
[1] agent identifier (cache_control: ephemeral, scope=org)
[2] core intro prompt (cache_control: ephemeral, scope=global)
[3] system instructions (no cache_control)
[4] doing tasks (no cache_control)
- Third-party client system instructions still moved to first user message
Follow-up to 69b950db4c
Three changes to avoid Anthropic's content-based system prompt validation:
1. Fix identity prefix: Use 'You are Claude Code, Anthropic's official CLI
for Claude.' instead of the SDK agent prefix, matching real Claude Code.
2. Move user system instructions to user message: Only keep billing header +
identity prefix in system[] array. User system instructions are prepended
to the first user message as <system-reminder> blocks.
3. Enable cch signing for OAuth tokens by default: The xxHash64 cch integrity
check was previously gated behind experimentalCCHSigning config flag.
Now automatically enabled when using OAuth tokens.
Related: router-for-me/CLIProxyAPI#2599
Added comprehensive tests to ensure key order is maintained when modifying payloads in `normalizeCacheControlTTL` and `enforceCacheControlLimit` functions. Removed unused helper functions and refactored implementations for better readability and efficiency.
The review asked for the builtin tool registry helper to live with the rest
of executor support utilities. This moves the registry code into the helps
package, exports the minimal surface executor needs, and keeps behavior tests
with the executor while leaving registry-focused checks with the helper.
Constraint: Requested layout keeps executor helper utilities centralized under internal/runtime/executor/helps
Rejected: Keep the files in executor and reply with rationale | conflicts with requested package organization
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep executor behavior tests near applyClaudeToolPrefix and keep pure registry tests in helps
Tested: go test ./internal/runtime/executor/helps ./internal/runtime/executor -run 'Claude|Builtin|Tool'; go test ./test/...; go test ./...
Not-tested: End-to-end Claude Code direct-connect/session runtime behavior
This change stops short of broader Claude Code runtime alignment and instead
hardens two safe edges: builtin tool prefix handling and source-informed
sentinel coverage for future drift checks.
Constraint: Must preserve existing default behavior for current users
Rejected: Implement control-plane/session alignment now | too much runtime risk for a first slice
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Treat the new fixtures as compatibility sentinels, not a full Claude Code schema contract
Tested: go test ./test/...; go test ./sdk/translator/...; go test ./internal/runtime/executor -run 'Claude|Builtin|Tool'; go test ./...
Not-tested: End-to-end Claude Code direct-connect/session runtime behavior