Commit Graph

3270 Commits

Author SHA1 Message Date
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
05e7232d8f fix(httpwire): retain request state after partial writes 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
842dbe6385 perf(claude): batch OAuth tool name rewrites
Collect the tool-name edits and apply them in one pass instead of rewriting the
serialized body once per tool, without changing the resulting bytes.
2026-08-03 14:47:26 +08:00
sususu
a20626f1ee fix(claude): send Anthropic header names with the real client's casing
CPA negotiates ALPN http/1.1 with Anthropic, so header names are not lowercased
by HPACK and reach the server verbatim. The casing is therefore part of the
fingerprint, and six of the eighteen names CPA emits were wrong because Go
canonicalises everything passed through Header.Set: anthropic-beta,
anthropic-dangerous-direct-browser-access, anthropic-version, x-app,
x-client-request-id and X-Stainless-OS. Writing the map keys directly is the
only way to keep the original casing.

This also fixes ordering at no extra cost. Go sorts header names bytewise when
it serialises a request, and the captured order of the real client is exactly
that same bytewise sort. Host, User-Agent and Content-Length stay misplaced
because Go writes them ahead of the sorted block; a test records that gap and
will fail if it ever closes.

The pass runs at the send boundary rather than inside applyClaudeHeaders: the
rewritten keys are unreachable through Header.Get, and doing it earlier hid
these headers from the rest of the pipeline. The boundary is a single
doClaudeUpstreamRequest helper pinned by a structural test, after a mutation
check showed that dropping the call from the streaming path alone was otherwise
undetectable. Expected order is pinned by serialising the request and reading
the header lines back, not by inspecting the header map.
2026-08-03 14:47:26 +08:00
sususu
6912a74064 fix(claude): keep a fast-mode refusal request-scoped
An account without the fast-mode entitlement answers speed:"fast" with HTTP 429
and "Usage credits are required for fast mode." The generic pipeline treats any
429 as quota exhaustion: it marks the credential Quota.Exceeded, assigns an
exponential cooldown up to 30 minutes and rotates to the next credential, so a
single request could walk and cool down the entire Claude pool over a
capability the account will never have.

Classify it through the existing RequestScopedError contract instead, which
already suppresses cooldown, rotation and retry. The status and body are then
returned verbatim: the classifier exists to stop the generic pipeline from
handling the error, not to handle it.

Detection deliberately requires both "fast mode" and a credits phrase, so a
genuine rate limit, which never mentions fast mode, keeps its cooldown. Tests
cover both observed wordings, byte-exact pass-through, and the negative cases.
2026-08-03 14:47:26 +08:00
sususu
4fdf59c436 fix(claude): synchronize credential metadata and device pools
A single *Auth is shared by every concurrent request that selects the same
credential, so any path reaching into Auth.Metadata directly races the others.
The credential identity helpers initialized and wrote the map outside
claudeDevicePoolMu; only EnsureDeviceIDPool took the lock, so a lazy
`auth.Metadata = make(...)` racing a pool write could abort the whole process
with "concurrent map writes" instead of failing a request.

Locking only the device-pool helpers was not enough: the account-profile and
refresh paths kept mutating the same map unguarded, which a concurrency probe
surfaced as data races. Widen the lock to the whole metadata map and route the
remaining call sites through new accessors in internal/auth/claude, including
the lazy map initialization, which needs a pointer to the field to stay inside
the critical section. claudeAccountProfileLookupDue now takes the already-read
timestamp so it cannot be handed an unsynchronized map.
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
481c726587 Merge pull request #4451 from madhavajay/add-alex
docs: Add Alex to related projects
2026-08-03 14:28:57 +08:00
Luis Pater
134a66738c fix(codex): hydrate missing response.completed output item IDs
When a `response.completed` payload already includes output entries, fill in only missing/empty item `id`s from the streamed `output_item.done` data while keeping existing IDs untouched.

Closes: #4622
2026-08-03 06:19:56 +08:00
Luis Pater
ffdb9c9fbc Merge pull request #4748 from patrick-fu/p/patrick/fix-codex-collaboration-message-encryption
Handle encrypted collaboration message schemas
v7.2.115
2026-08-03 05:47:20 +08:00
Luis Pater
872070259e fix(translator): emit response.completed on stream end when finish_reason is missing
Closes: #4745
2026-08-03 05:37:05 +08:00
Luis Pater
0879929821 fix(translator): preserve non-object Claude tool inputs when building function call args
- Keep `tool_use.input` values as valid JSON for function-call args instead of only handling objects or stringified objects.
- Preserve primitive/string/array inputs and convert `null` to `{}` so present inputs are not dropped.

Closes: #4744
2026-08-03 05:27:23 +08:00
Luis Pater
aea71c0070 fix(translator): preserve content block order when building non-stream Claude OpenAI responses
Closes: #4743
2026-08-03 04:55:05 +08:00
Patrick Fu
1cf9a45ca2 Handle encrypted collaboration message schemas
- Generalize spawn_agent tool path discovery into codexToolPathsByNames
  driven by a name set, and add codexCollaborationMessageTools covering
  spawn_agent, send_message, and followup_task.
- Strip parameters.properties.message.encrypted from all collaboration
  message tools (top-level tools and input[].additional_tools, including
  nested namespace tools) via removeCodexCollaborationMessageEncryption,
  invoked unconditionally before the spawn-agent optimization decision.
- Extend optimize_multi_agent_v2_test.go with coverage for the new tool
  path discovery, encrypted-field removal semantics, preservation of
  unrelated encrypted fields, and end-to-end OptimizeCodexMultiAgentV2Request
  behavior across namespace and additional_tools payloads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-08-03 04:40:13 +08:00
Luis Pater
0cc24b2e00 fix(translator): emit function_call_arguments.done and make function call stream events idempotent
- Ensure `response.function_call_arguments.done` is emitted with final arguments (including `{}` for empty args).
- Track per-call state so duplicate `step.start` / `step.stop` / `arguments_delta` events do not re-emit redundant output.
- Populate `response.output_item.done` and completion payloads from a single normalized function-call argument source.

Closes: #4742
2026-08-03 04:30:43 +08:00
Luis Pater
abbb1c7534 fix(translator): accept snake_case Gemini usage metadata in interactions conversion
Closes: #4741
2026-08-03 04:12:31 +08:00
Luis Pater
13435c93d2 feat(executor): normalize OpenAI tool results for text-only compatibility models
- Add OpenAI-compat executor-time normalization for `tool` message content, converting non-string tool results to plain text and replacing image parts with a clear unsupported marker for models configured with text-only `input-modalities`.
- Apply normalization in both regular and streaming OpenAI-compat execution paths before prompt-cache processing.
- Update config example to document `[text]` `input-modalities` for upstreams that reject multimodal tool-result content.

Closes: #4737
2026-08-03 03:37:24 +08:00
Luis Pater
a303fd869b feat(codex): support max-context-length overrides for configured models
- Add optional `max-context-length` model configuration across supported provider model types and expose it via `GetMaxContextLength`.
- Propagate the override into model metadata so Codex/client model catalog responses honor the configured value (`context_window`, `max_context_window`, and `max_context_length`).
- Update example configuration with documented usage of the new option.

Closes: #4728
2026-08-03 03:01:43 +08:00
Luis Pater
8d675e690d feature(codex): Normalize invalid sub2api message item IDs during Codex input sanitization
- Prefix non-compliant message input IDs with `msg_` while leaving valid/prefixed IDs unchanged.
- Apply normalization before length checks and shortening to keep ID handling deterministic and consistent across Codex request paths.
2026-08-03 02:45:49 +08:00
Luis Pater
41fc5e1346 fix(auth): add bounded timeouts to Codex and Claude token refresh paths
- Introduce explicit per-refresh request timeouts in Codex and Claude OAuth token refresh logic.
- Ensure refresh flows use `context.WithTimeout` with `context.WithoutCancel` to avoid inheriting caller cancellation and avoid hanging refresh calls.
- Add a dedicated Claude TLS handshake timeout for utls transport creation via request context and enforce it by setting connection deadlines during handshake.

Closes: #4712
v7.2.114
2026-08-03 01:29:43 +08:00
Chén Mù
bcebbad687 Merge pull request #4735 from router-for-me/home
fix(main): ensure safe closure of homeClient to prevent idle connections
2026-08-02 21:04:03 +08:00
hkfires
448893290d fix(main): ensure safe closure of homeClient to prevent idle connections 2026-08-01 13:34:30 +08:00
sususu98
bc71c77f5c Merge pull request #4707 from sususu98/fix/codex-websocket-cloaking
fix(codex): align websocket cloaking headers
v7.2.113
2026-08-01 13:04:09 +08:00
sususu
91561df0b1 fix(codex): align websocket cloaking headers 2026-08-01 13:01:33 +08:00
Luis Pater
08eb05ae87 feat(config): add support-prompt-cache-key option for OpenAI compatibility
- Introduced a new `support-prompt-cache-key` configuration option to enable optional prompt cache key derivation for supported models.
- Updated relevant API handlers and internal logic to handle the new configuration.
- Enhanced executor workflows to apply prompt cache keys conditionally during request processing.
- Added tests to validate prompt cache key behavior across various scenarios and providers.
- Updated configuration examples and documentation for the new option.

Closes: #4700
2026-08-01 11:39:50 +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
Luis Pater
4d498ec7f7 feat(translator): enhance OpenAI response handling for structured tool outputs
- Added logic to parse and normalize structured tool outputs, including text and image content.
- Introduced `setFunctionCallOutputContent` and related helper methods for consistent response processing.
- Enhanced handling of image details with normalization (`normalizeChatImageDetail`) and fallback mechanisms.
- Updated tests to cover various tool output scenarios, ensuring robustness and accuracy in conversions.

Closes: #4699
2026-08-01 02:08:52 +08:00
Luis Pater
198a26737c feat(codex): add Alpha Search API key support with configurable endpoint
- Introduced `alpha-search` flag for Codex API keys to enable Alpha Search functionality.
- Added `CredentialPolicyCodexAlphaSearchV1` for filtering and validating API keys compatible with Alpha Search.
- Extended configuration, synthesizer, and watcher functionality to track and manage `alpha-search` flag changes.
- Updated Codex executor to dynamically construct Alpha Search endpoint based on API key attributes.
- Enhanced tests to validate Alpha Search flag handling, endpoint construction, and credential filtering.

Closes: #4692
2026-08-01 00:31:26 +08:00
Luis Pater
8c37dd9862 feat(executor): introduce Kimi Thinking Replay cache and continuity mechanisms
- Added logic for caching and restoring Kimi "Thinking Replay" states to improve continuity across requests.
- Implemented `kimiThinkingReplayScope`, content replay preparation, and conditional cache storage based on replay validity.
- Introduced helper methods for replay content restoration, caching, and cleanup on errors.
- Enhanced executor workflows to utilize the "Thinking Replay" cache for both immediate and streaming response handling.
- Integrated periodic cleanup of expired and oversized replay cache entries.

Closes: #4695
2026-07-31 22:59:13 +08:00
Supra4E8C
d9460a8df6 feat: add sponser LMU 2026-07-31 20:31:28 +08:00
hkfires
a63da8ae76 Revert "Merge pull request #4687 from router-for-me/fix/home-401-refresh-recovery"
This reverts commit 4a31513673, reversing
changes made to 7d00936acc.
v7.2.112
2026-07-31 16:35:33 +08:00
sususu
3a995bd801 chore: ignore root logs directory 2026-07-31 15:29:02 +08:00
sususu98
9d46c8d145 Merge pull request #4684 from sususu98/fix/thinking-summary-visibility
feat(thinking): preserve cross-protocol summary visibility
2026-07-31 14:12:00 +08:00
sususu
24323ee4b7 fix(thinking): drop disabled Interactions summaries 2026-07-31 13:40:41 +08:00
sususu
c4dcd8703a fix(thinking): respect final summary authority 2026-07-31 13:28:14 +08:00
sususu
0c2ec7da23 fix(thinking): honor normalized summary payloads 2026-07-31 12:45:13 +08:00
Supra4E8C
4a31513673 Merge pull request #4687 from router-for-me/fix/home-401-refresh-recovery
Fix/home 401 refresh recovery
v7.2.111
2026-07-31 02:55:42 +08:00
Supra4E8C
4db8e12029 fix: recover Home OAuth credentials after 401 2026-07-31 01:34:11 +08:00
Luis Pater
7d00936acc feat(models): add Kimi K3 256K and extend Kimi K3 configuration
- Added new model `Kimi K3 256K` with 256K context support and image input capability.
- Enhanced `Kimi K3` configuration by introducing `thinking` options and increasing context length.

Closes: #4612
2026-07-31 00:53:23 +08:00
sususu
87ceaf83bb fix(thinking): honor provider visibility semantics 2026-07-31 00:05:59 +08:00
sususu
5d307c195d fix(thinking): close summary translation gaps 2026-07-30 23:26:20 +08:00
sususu
92b6bc4a86 docs(thinking): clarify Claude model defaults 2026-07-30 23:05:14 +08:00
sususu
76008b4720 fix(thinking): decouple Interactions effort summaries 2026-07-30 22:44:01 +08:00