Skip to content

Upgrade to v8.0.64 and preserve Claude Code versions across updates - #2

Closed
brycedbjork wants to merge 289 commits into
northbrookfrom
fix/claude-upgrade-compatibility
Closed

brycedbjork wants to merge 289 commits into
northbrookfrom
fix/claude-upgrade-compatibility

Conversation

@brycedbjork

Copy link
Copy Markdown

Claude Code updates could be relabeled as the proxy's older fallback version, causing model requests to fail with errors such as “version 2.1.290 or newer is required” even when the installed client was newer.

Merge upstream v8.0.64 into the Northbrook fork while preserving quota-aware routing, account reserves, and session affinity. Recognize compatible native Claude Code/Agent SDK requests independently of the fallback release line, and prevent device-profile stabilization from downgrading newer native User-Agent versions. Retain native request-signal validation and the existing safeguards for non-native clients.

Regression tests cover patch/minor/major updates, SDK clients, request extensions, and ordinary Messages, streaming, and count_tokens with default/stabilized profiles and an obsolete fallback configuration. Document removal of old local User-Agent overrides and the remaining limitation: future protocol changes can still require proxy updates.

Validation: full CGO_ENABLED=0 go test ./... passed; focused race tests for routing, quota usage, client detection, and executor version preservation passed; server build passed with Go 1.26.10. One earlier upstream WebSocket test had a temporary-directory cleanup race; the complete rerun passed.

luispater and others added 30 commits October 27, 2026 17:27
…onversion

Convert structured Vertex functionCall.partialArgs fragments into OpenAI
Chat Completions, OpenAI Responses, and Claude Messages streaming tool
argument deltas while preserving call identity, nested JSONPath assembly,
string continuations, thought signatures, placeholder argument cleaning,
and incomplete-stream guards.

Fixes router-for-me#7043
…losing downstream

When an upstream Codex WebSocket returns an early 429 usage_limit_reached (via an error or response.failed frame) before any downstream payload chunk is emitted, notifying UpstreamDisconnectChan caused the Responses WebSocket handler to close the client connection and cancel the request context before the conductor could fail over to another eligible credential.

Suppress downstream disconnect notification on pre-output upstream WebSocket errors and treat bootstrap usage-limit terminal failures as failover-eligible while bootstrap buffering is active, allowing the conductor to retry another credential on the same downstream WebSocket connection.

Fixes router-for-me#7051
…usting descriptors

Defer eager request body reads and temporary file creation until after authentication or over the 1 MiB in-memory threshold, expire read deadlines and close connections when responses finish with unconsumed request bodies, bound HTTP header and unauthenticated RESP setup reads, and retry transient EMFILE/ENFILE accept errors with exponential backoff.

Fixes GHSA-j4xx-x47j-7h54
…t logging

- Cap captured request body zstd decompression to max-request-body-bytes or 32 MiB when no smaller limit is configured, and remove the unbounded decode helpers.
- Restrict the request-log zstd decoder to concurrency 1 and an 8 MiB maximum window so frames declaring oversized windows fall back to logging raw bytes.
- Add regression tests covering unconfigured limits, single-segment window bombs, and oversized zstd windows.

Closes: GHSA-4w5v-m7vx-jpmh
…ailability

docs(readme): update Kimi and OpenAI model availability
…decode-sync-zstd

perf(executor): decode upstream zstd synchronously and sniff unlabeled bodies lazily
…ndow

Every compressed response created a new encoder: zstd with its default
8 MiB window allocated about 18 MB, gzip about 1 MB, and an open SSE
stream held that for its whole life. Pool zstd and gzip encoders, and
give zstd a 1 MiB window with lower encoder memory; API responses are
far smaller than the window, so the wire size is unchanged. finish now
returns the encoder to the pool and fails later writes instead of
sending them uncompressed under Content-Encoding.
BenchmarkResponseCompressionOpenStreams took its baseline after one GC,
which only moves pooled encoders to the sync.Pool victim cache. Streams
then reused memory the baseline already counted, so heap per open stream
collapsed toward zero once b.N > 1. Run two GC cycles before the baseline
so every sample starts with empty pools.

TestResponseCompressionReusesPooledEncoders now counts encoder creations
and fails when finished encoders are not returned to the pool. It also
interleaves responses whose client writes fail, so an encoder pooled
after an error must still produce correct output.
…E framing recovery

- Filter out internal metadata events such as moderation data for standard clients in OpenAI responses API and websocket streams.
- Enhance `responsesSSEFramer` and frame accumulator to robustly handle fragmented JSON payloads, empty data fields, and recovery of split SSE fields.
- Add comprehensive unit tests covering SSE metadata filtering, fragmented frame recovery, and websocket message handling.
- Track the running response identity in the Codex websocket session and reject interrupts that do not target it, so an interrupt after response.completed is never forwarded upstream while turn teardown is pending.
- Gate the handler's local interrupt path by explicit turn ownership and close it before terminal payloads are written downstream, preventing fabricated response.incomplete events and silently dropped claimed frames.
- Add deterministic regression tests covering late and unknown interrupts across completion, failure, queued rejection, upstream loss, and HTTP fallback turns.

Closes: router-for-me#7065
… body delivery

- Let schema v7+ frontend auth providers opt out of receiving request bodies via frontend_auth_provider_omit_body / frontend_auth_omit_body so metadata-only auth plugins skip reading, decoding, cloning, and marshaling the request body during authentication.
- Avoid cloning the buffered request body slice before JSON serialization when invoking RPC-backed frontend auth providers that still inspect the body.

Closes: router-for-me#7071
Existing request interceptors wrap the full request body in a JSON RPC envelope with Base64 encoding and skip subsequent duplex WebSocket business frames, causing ~3.33x memory and CPU amplification when rewriting small fields such as Codex `<timezone>` and `<current_date>` in large contexts.

- Add schema v8 raw request body patch methods (`request.patch_body_before` and `request.patch_body_after`) and capabilities (`request_interceptor_patch_body_before/after`, `request_body_patcher_before/after`) that pass raw `Body []byte` directly across the C ABI without JSON/Base64 request wrapping
- Add `RequestBodyEdit`, `RequestBodyPatchResponse`, and `RequestBodyPatcher` in `sdk/pluginapi` with single-pass host splicing, bounds/overlap validation, `json.Valid` verification, no-op original body reuse, and sequential multi-plugin chaining
- Eliminate redundant full-body slice clones in handler/conductor request interceptor application paths
- Run before-auth and after-auth request interceptors on subsequent duplex WebSocket `response.create`, `response.append`, and `response.steer` messages

Closes: router-for-me#7072
…ia-live-demo

docs(readme): add Nia Live Demo to "Who is with us?"
- Update the Gemini OpenAI Responses tool search call item ID prefix from ts_ to tsc_ so replayed search items pass Codex upstream validation after switching models.
- Normalize legacy ts_ and unprefixed tool_search_call item IDs in SanitizeCodexInputItemIDs on outbound Codex requests while preserving call_id and avoiding ID collisions.

Closes: router-for-me#7084
…connect

Fix WebSocket disconnect test and Devin diagnostics
sususu98 and others added 28 commits November 9, 2026 18:57
…ignature-replay

feat(gemini): support asymmetric thoughtSignature replay KV across Gemini executors and eliminate KV double base64 encoding
Add attempt-scoped HomeSelection metadata carrying the reused and
additional flags, scheduling route model, and credential policy
through usage records to the Redis queue. Mark retained executions
and Codex duplex successors as reused so Home can compensate later
turns after completion without redispatching or reacquiring a
concurrency slot.

Mark split additional-model records as additional so they never add
scheduling charges, while preserving independent per-response
execution IDs for deduplication. Document the deferred accounting
and add coverage across conductor, duplex, reporter, and queue.
- Move top-level automatic prompt caching markers onto the last cacheable block and remove the top-level field during ensureCacheControl so cloaked requests avoid TTL mismatches and duplicate breakpoints.
- Extend the Claude cache_control stream scanner and helper routines to account for top-level cache_control when counting, enforcing the 4-block limit, and normalizing or upgrading TTLs.

Closes: router-for-me#7366
Co-authored-by: Dylan <1990016@gmail.com>
…contention

- Hijack mock CONNECT proxy connections before writing 200 OK and forward buffered client bytes so TLS ClientHello records are not truncated under CPU contention, while isolating Codex refresh test journals.
- Wait for client request payloads and test completion before closing mock websocket connections in Codex keepalive upload tests.
- Cancel the in-flight HTTP upstream context before writing response.incomplete downstream during local websocket interrupts.

Closes: router-for-me#7379
Co-authored-by: Dylan <1990016@gmail.com>
feat(auth): account for pinned and reused traffic in weighted routing
- Exclude unrouted 404 responses without upstream activity or API error evidence from per-request and forced error log dumps so high-frequency probes cannot evict diagnostic dumps from the error-logs-max-files ring.
- Avoid initializing or retaining streaming log writers and temporary part files when Gin matches no route for a 404 response while preserving routed 404 and panic error dumps.

Closes: router-for-me#7363
Co-authored-by: Dylan <1990016@gmail.com>
…ime auth-dir changes

- Synchronize Watcher.authDir and rebind the fsnotify directory watch when SetConfig or reloadConfig updates the authentication directory.
- Read the active auth directory across snapshots, full rescans, and incremental file events while discarding stale pre-switch directory events.
- Add regression tests covering runtime auth-dir reloads, shared credential filenames, concurrent SetConfig updates, and stale event isolation.

Closes: router-for-me#7160
Co-authored-by: Dylan <1990016@gmail.com>
…che-write

fix(devin): count cache-write tokens in total input
…-proxy

feat(cmd): add -login-proxy flag for CLI OAuth logins
… registry

- Register Claude Fable 5.2 in the Anthropic collection with thinking levels, image input support, and updated pricing description.
- Register Gemini Omni 1.2 Flash across Google, Vertex, and Gemini CLI collections with thinking token ranges and multimodal input/output support.
…nses without reasoning

- gate automatic image_generation tool injection for use_responses_lite catalog models on actual Responses-Lite routing (including credential and model header overrides) or presence of reasoning effort
- retract untouched auto-injected image_generation tools during single-pass payload finalization when user payload rules configure reasoning effort or switch to an incompatible route
- update Codex executor and payload barrier regression tests across HTTP and WebSocket streaming and non-streaming paths

Closes: router-for-me#7384
Co-authored-by: Dylan <1990016@gmail.com>
Anthropic now rejects claude-fable-5-2 from Claude Code versions older than
2.1.290, so every cloaked (non-Claude-Code) request for the model failed with
400 "Claude Code 2.1.280 does not support this model".

Update the emulated CLI baseline to the measured 2.1.321 release:
- User-Agent claude-cli/2.1.321, Stainless package 0.128.0, runtime v26.12.1,
  billing cc_version and default fallback version.
- Rebuild Anthropic-Beta assembly from native 2.1.321 captures:
  thinking-token-count moves after advisor-tool, effort precedes
  dangerous-tool-use, message-threads is added when the body carries a thread
  object, mid-conversation-system is only sent when requested, and the quota
  probe omits the claude-code beta.
- Recognize Fable 5.2 and Haiku 5.5 for progress display, per-turn control and
  effort handling, matching the observed client.
- Add a regression test that reproduces each captured 2.1.321 beta header and
  the billing fingerprint.

Fixes router-for-me#7386
…li-baseline-2.1.321

fix(claude): bump Claude Code CLI fingerprint baseline to 2.1.321
…laude Fable 5.2

- Include claude-fable-5-2 in preserved-thinking block binding so replayed signed thinking blocks default to drop_block on prefix mismatch.
- Consolidate 2.1.321 per-turn effort and timing model capability checks to cover Fable 5.2, Sonnet 5.5, and Mythos 5.2 while keeping Haiku 5.5 excluded from timing.
- Update the baseline software profile test failure message to match 0.128.0/v26.12.1 and add regression tests for 2.1.321 timing and preserved thinking.

Closes: router-for-me#7386
Co-authored-by: Dylan <1990016@gmail.com>
…ion under session affinity

- Document in config.example.yaml and RoutingConfig.SessionAffinity that Merkle LCP compaction matching requires at least 2 shared trailing turns.
- Note that clients whose compaction replaces all earlier turns with a summary should send X-Session-ID or another explicit session ID to preserve credential affinity.

Closes: router-for-me#7390
Co-authored-by: Dylan <1990016@gmail.com>
…ipeline

- Treat thinking.display="updates" as an enabled reasoning summary mode when extracting Claude summary configuration so translated requests emit target visibility controls such as Antigravity includeThoughts.
- Preserve an existing "updates" display mode when applying enabled summary configuration back onto Claude request documents instead of overwriting it with "summarized".
- Add unit and cross-protocol translation regression tests for Claude thinking.display="updates".

Closes: router-for-me#7393
Co-authored-by: Dylan <1990016@gmail.com>
Preserve an absolute heartbeat deadline across config,
cluster, and telemetry messages so ordinary subscription
traffic cannot mask a stalled heartbeat. Only an
empty-payload PONG renews liveness and resets reconnect
failures, and messages arriving after the deadline are
treated as timeouts
…d-errors-usage-fail-code

fix(usage,auth): propagate request-scoped error rule classification to usage fail.code
…ool calls

- Add a single-space reasoning_content placeholder on assistant tool-call turns without replayable thinking text when is-compat and request reasoning are active.
- Reconcile tool-call placeholder reasoning after canonical thinking resolution so model suffixes and capability normalization govern final inclusion before payload rules.
- Add unit and executor regression tests covering absent/whitespace thinking, disabled thinking, suffix overrides, and final payload overrides/filters.

Closes: router-for-me#7398
Co-authored-by: Dylan <1990016@gmail.com>
fix(home): only renew liveness on heartbeat pong
- Start a connection-scoped downstream Ping keepalive loop immediately after upgrading the Responses WebSocket connection instead of waiting for stream forwarding to begin.
- Guard background Ping writes with non-blocking mutex acquisition so active data writes are not contended while blocked Ping writes are still interrupted on terminal close.
- Preserve the socket cancellation cause in response forwarding and add regression coverage for post-upgrade, upstream-bootstrap, and blocked-Ping close paths.

Closes: router-for-me#7407
Co-authored-by: Dylan <1990016@gmail.com>
Co-authored-by: lzt404 <2596933790@qq.com>
…iptions

- Detect input_schema property keys outside Claude's ^[a-zA-Z0-9_.-]{1,64}$ pattern by walking JSON Schema subschema positions in tools[] and inline tool_addition definitions.
- Replace affected schemas with an open object and embed the original schema in the tool description before payload rules, so parameters keep their exact names without request or response rewriting.
- Apply the fallback on execute, stream and count_tokens paths with regression tests for Responses and native Claude sources, MCP aliasing and payload-rule ordering.

Closes: router-for-me#7389
Co-authored-by: Dylan <1990016@gmail.com>
Co-authored-by: lzt404 <2596933790@qq.com>
Handle compaction triggers and capsule replay locally for is-compat models while preserving native Codex behavior. Harden duplex cancellation, event ordering, response ownership, settings inheritance, model aliases, and credential failure classification.

Add HTTP, streaming, duplex, handler, usage, and deterministic concurrency regression coverage.

Fixes router-for-me#7406
…te from summary requests

Clear top-level text format constraints and filter configuration_update control items when preparing local compaction summary payloads so structured JSON schemas do not overwrite the summary output.
- Accept both cli and cli-bg in the native X-App header check so Claude Code background sessions preserve their native request identity instead of receiving the pinned device profile rewrite.
- Add unit and executor regression tests verifying native detection and passthrough for X-App: cli-bg across messages, streaming, count_tokens, and measured helper requests.

Closes: router-for-me#7412
Co-authored-by: Dylan <1990016@gmail.com>
Co-authored-by: lzt404 <2596933790@qq.com>
…-compaction-7406

fix(codex): support local compaction for compatible Responses endpoints
@github-actions

Copy link
Copy Markdown

This repository does not allow modifying AGENTS.md in pull requests.

Detected changes:

  • AGENTS.md

Please revert these changes and open a new PR without touching AGENTS.md.

@github-actions github-actions Bot closed this Nov 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.