Commit Graph

3508 Commits

Author SHA1 Message Date
Luis Pater
ab8f00dbd9 fix(claude): derive stable request-scoped metadata.user_id for converters
Closes: #5153
2026-08-22 16:01:25 +08:00
Luis Pater
b3f72cef65 fix(gemini): normalize Claude thinking signatures in Gemini request and response conversion
Closes: #5151
2026-08-22 15:35:54 +08:00
Luis Pater
65071f7c47 test(claude): expand OpenAI conversion tests for reasoning_content and stream/non-stream parity
Closes: #5148
2026-08-22 13:20:00 +08:00
Luis Pater
d9869ed908 test(openai): expand reasoning fallback coverage in OpenAI responses non-stream conversion tests
Closes: #5147
2026-08-22 13:08:11 +08:00
hkfires
0a14eb70ce feat(auth): add retry round credential filtering v7.2.139 2026-08-22 01:20:02 +08:00
hkfires
601ca43090 feat(auth): add credential retry round contract
Redefine request-retry as additional credential retry rounds and
enforce max-retry-credentials per round. Home dispatch now carries
excluded and pinned auth constraints, supports remote retry limits, and
propagates cooldown retry-after metadata across exhausted rounds.

Move Antigravity upstream retries under conductor ownership to avoid
double-consuming retry attempts. Update configuration comments and add
coverage for Home retry rounds, cooldown handling, pinned credentials,
and legacy dispatcher compatibility.
2026-08-22 01:19:58 +08:00
Luis Pater
85e7add6ad feat(models): add Gemini 3.7 Flash model registrations to model registry
Closes: #5137 #5046
2026-08-21 22:51:45 +08:00
Luis Pater
1d5b7612c6 fix(cliproxy): add protocol-aware plugin executor usage parsing for response and streaming payloads
Closes: #5122
v7.2.138
2026-08-21 13:05:54 +08:00
W ARELIK
4053c026e7 fix(executor): sanitize thought signatures in Gemini and Gemini Vertex executors (#5110)
Ensure all Gemini and Gemini Vertex execution and token count pathways invoke SanitizeGeminiRequestThoughtSignatures before dispatching upstream requests. This prevents raw non-Gemini (e.g. Claude CAIS) thought signatures from leaking to upstream Gemini endpoints while preserving valid native protobuf signatures and setting appropriate validator bypass sentinels for function calls.

Co-authored-by: W ARELIK <warelik@WARELIK-MB.local>
2026-08-21 10:57:03 +08:00
Luis Pater
b1c000590b fix(gemini): include empty annotations/logprobs in response.output_item.done message content
Closes: #5116
2026-08-21 04:16:08 +08:00
Luis Pater
a8693c70eb Merge pull request #5124 from YogaSakti/fix/xai-response-incomplete
fix(xai): treat response.incomplete as terminal success (#5113)
2026-08-21 04:05:56 +08:00
Luis Pater
68e96c2716 fix(openai): map max_completion_tokens to Antigravity maxOutputTokens
- Add `max_completion_tokens` fallback handling in OpenAI→Antigravity request conversion.
- Keep `max_tokens` as the preferred source when both fields are present.

Closes: #5108
2026-08-21 03:52:26 +08:00
Luis Pater
5b232e3e98 fix(gemini): generate deterministic sequential IDs for Gemini tool call pairing in Codex/Claude conversions
Closes: #5107
2026-08-21 03:21:55 +08:00
Luis Pater
3db591eecd fix(gemini): preserve Gemini thought signatures in non-stream Claude conversion
Closes: #5106
2026-08-21 03:04:12 +08:00
Luis Pater
8eb3ac2e03 fix(openai): fallback to reasoning when reasoning_content is missing in response conversion
Closes: #5105
2026-08-21 02:41:37 +08:00
Luis Pater
aa5dccc236 fix(claude): use message.reasoning_content for converted thinking output
Closes: #5104
2026-08-21 02:16:01 +08:00
Luis Pater
42d8e746e5 fix(claude): avoid long global cooldowns for Fable-only 7d_oi rate limits
Closes: #5101
2026-08-21 02:02:46 +08:00
Yoga Sakti
9d6b5cdd16 fix(xai): treat response.incomplete as terminal success (#5113)
The xAI executor only switched on response.completed, so any turn that
ended with the spec-correct response.incomplete terminal event fell out
of the loop. Non-streaming requests were reported to the client as a 408
("stream disconnected before response.completed") even though the
upstream request succeeded, and because 408 is retryable it burned
credential rotations against a healthy pool. Streaming requests forwarded
the terminal event without patching the collected output items or
publishing usage.

Accept response.incomplete alongside response.completed in both paths,
mirroring the Codex executor, and keep the reasoning replay cache gated
on response.completed since a truncated turn has no replayable state.
2026-08-20 23:52:09 +07:00
sususu98
4b9d404fb0 feat(codex): add opt-in stream bootstrap buffering and overload failover (#5115)
* feat(codex): add opt-in stream bootstrap buffering

The upstream smuggles capacity rejections into an HTTP 200 stream. The
handshake events arrive normally and only a later event carries
{"error":{"type":"service_unavailable_error","code":
"server_is_overloaded"}}. By then the executor has already handed the
first chunk downstream, the response is committed, and the conductor can
no longer retry on another credential, so the request fails even though
other credentials were available.

When codex.stream-bootstrap-buffering is enabled the executor holds back
the handshake events until it can tell whether the stream carries real
output or a rejection. An overload rejection then fails the attempt
before any chunk is delivered, letting the conductor retry on another
credential; every other terminal failure is flushed in order and
delivered in-stream exactly as before.

Detection uses an event-type allow-list rather than a fixed count. On the
websocket transport codex.rate_limits and codex.response.metadata arrive
before response.created, making the first generated event the fifth
frame, so a small counter would release the stream before the rejection
is visible. Buffering is bounded and hitting the bound degrades to the
original unbuffered behaviour.

Two details are load-bearing. The error must be returned synchronously:
delivering it as the first stream chunk makes ExecuteStream downgrade it
into a committed 200 and the status is lost. And the websocket path must
not signal an upstream disconnect for a rejection it intends to retry,
because the downstream handler closes the client connection on that
signal and the retry would have nowhere to deliver.

The 503 status is produced only on this path rather than in the shared
codexTerminalFailureStatus mapping, so disabling the feature restores the
previous behaviour exactly, including cooldown classification and
retry-after parsing.

Defaults to false: response headers are withheld until generation
starts, which can trip client or reverse-proxy read timeouts.

* test(codex): pin bootstrap overload failover through the conductor

Executor-level tests cannot show what the client finally receives. These
exercise ExecuteStream end to end to pin three properties that are easy
to regress:

- consecutive overloaded credentials are skipped until one serves the
  request, and retries are capped by max-retry-credentials rather than
  multiplying with request-retry
- exhausting the pool surfaces the upstream status instead of a
  committed 200 stream
- with buffering disabled the rejection stays an in-stream error on a
  committed stream, which is the behaviour the feature must preserve

The third case also documents why the executor returns its error
synchronously: an error arriving as the first stream chunk is wrapped and
downgraded into a committed 200, silently losing the status.
2026-08-20 21:31:53 +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
Luis Pater
556328c122 feat(gemini): add namespace-aware OpenAI Responses tool resolution and custom tool call conversion
- Add shared tool descriptor collection and winner selection for Responses tools (top-level vs `additional_tools`, direct vs namespace child, and ordering rules).
- Introduce sanitized Gemini function name mapping with collision disambiguation and 64-char-safe truncation.
- Build forward/reverse tool identity maps for restoring original tool identity (`name`, `namespace`, `custom`) during translation.
- Update Gemini→Responses streaming conversion to emit proper custom tool call events and identity-aware function call events.
- Add helpers for translating `tool_choice` to Gemini config and unwrapping custom tool input payloads.

Closes: #5088
2026-08-20 13:47:15 +08:00
Luis Pater
4874971764 fix(cliproxy): add warn-level diagnostics for auth cooldown and upstream execution failures
Closes: #5085
2026-08-20 03:40:46 +08:00
Luis Pater
9dc51b1f87 feat(cliproxy): add OAuth request-scoped error rules support
- Add `oauth-request-scoped-errors` configuration with normalization, sanitization, and YAML management persistence/hot-reload hooks.
- Route request-scoped error classification to use per-provider rules only for OAuth auth entries.
- Add config diff reporting and management CRUD endpoints for `oauth-request-scoped-errors` (get/put/patch/delete) with input sanitization.

Closes: #5085
2026-08-20 02:55:49 +08:00
sususu98
85d2faddd1 fix(claude): preserve native subagent and environment headers (#4982) (#5084) v7.2.137 2026-08-20 00:30:41 +08:00
sususu98
8aa6868d0d fix(claude): support setup-tokens and gracefully handle 403 OAuth profile errors (#4983) (#5083) 2026-08-20 00:15:31 +08:00
sususu98
788e9b7928 fix(claude): restore tool_search_tool_result references and recognize advisor/agent server tools (#5044) (#5082)
- Add bidirectional remapping for nested tool_references inside tool_search_tool_result across non-stream, SSE stream, and multi-turn message history.
- Add advisor_ and agent_toolset_ to IsClaudeServerToolType to prevent schema stripping and MCP aliasing on native Anthropic server tools.
- Wrap MCP alias restoration errors in claudeMCPAliasRestoreError with IsRequestScoped() bool to avoid cooling down healthy OAuth credentials.
- Add unit tests for tool_search_tool_result remapping, error variants, server tool recognition, and error scoping.
2026-08-19 22:29:51 +08:00
Luis Pater
ec105dac94 fix(cliproxy): handle responses/compact auth cooldowns and fallback semantics
- Add compact-specific error classification to mark transient/non-credential failures as availability-neutral instead of triggering cooldown penalties.
- Stop auth fallback immediately on compact request-fault errors (e.g., bad/not-found/unsupported request errors) and return the upstream compact error.
- Preserve existing cooldown behavior for auth/credential faults (`401`, `403`, `429`) while allowing non-auth compact failures to fail fast without tainting normal traffic routing.

Closes: #5031
2026-08-19 22:05:28 +08:00
Luis Pater
2005788fc3 fix(codex): filter out prompt_cache_retention in OpenAI→Codex responses request conversion
Closes: #5068
2026-08-19 21:29:03 +08:00
sususu
ac0d1888c0 fix(gemini): strip 'encrypted' metadata from tool parameters schemas (#5065) 2026-08-19 19:13:56 +08:00
sususu
5fef17e2ec fix(claude): pass incoming headers when applying custom headers in caller-owned mode 2026-08-19 18:58:47 +08:00
sususu
0f69f09a70 fix(logging): exclude HTTP 499 and client cancellations from forced error logs 2026-08-19 18:58:47 +08:00
sususu98
79ef3618d6 fix(antigravity): attach sibling tool images to the nearest functionResponse (#5075)
Responses→Gemini emits functionResponse plus sibling inline_data, but
fixCLIToolResponse previously dropped those images when regrouping tool
turns. Cloud Code Assist only sees tool images nested in
functionResponse.parts with an explicit mimeType, and parallel tool
results must stay bound to the nearest preceding functionResponse
instead of last-wins.

Closes #5070
2026-08-19 18:58:04 +08:00
sususu98
62f5a2798c fix(executor): prepend empty user turn for model-first Gemini/Antigravity requests (#4959) (#5048)
* fix(executor): prepend empty user turn for model-first requests targeting Gemini/Antigravity (#4959)

When forwarding sliced conversation histories or tool calls across OpenAI Responses,
OpenAI Chat Completions, Claude Messages, and native Gemini, native Gemini and Antigravity
Gemini endpoints require that conversation contents begin with a user turn.

Normalize leading turns at the executor boundary rather than the translator layer:
- Prepend an empty user turn ({"role":"user","parts":[{"text":""}]}) for Gemini, Gemini Vertex,
  AI Studio, and Antigravity Gemini generation and CountTokens requests if the first turn is 'model'.
- Keep Antigravity Claude requests untouched to avoid adapter 400 errors.
- Ensure normalization runs after payload rules so payload index overrides target the original turns.
- Use no-copy GJSON inspection to keep overhead zero on valid user-first requests.

* fix(executor): inject Antigravity leading user after reasoning replay (#4959)

Replay can insert a model functionCall at contents[0] for sliced
tool-result history. Run the empty-user prepend on the final
requestPayload, after sanitize and prepareAntigravityGeminiReasoningReplayPayload.
2026-08-19 18:56:43 +08:00
Supra4E8C
55397bf68d fix: remove temporarily hidden sponsorship details from README files 2026-08-19 13:57:32 +08:00
Luis Pater
497673bf6b feat(antigravity): add video_url content part support to OpenAI request conversion
Closes: #5056
v7.2.136
2026-08-19 02:18:39 +08:00
Luis Pater
4ac37ed3cd fix(claude): always send stop as an array when converting stop_sequences in OpenAI requests
Closes: #5054
2026-08-18 21:14:21 +08:00
Luis Pater
e424bfad00 feat(executor): support $-based custom headers from downstream request headers
- Propagate request headers into custom-header resolution for OpenAI/Gemini/XAI/Codex execution and websocket flows.
- Resolve auth `header:` values like `$ABC` from incoming request headers at request time and omit headers when no value is available.
- Add documentation for the dynamic custom-header behavior in `config.example.yaml`.

Closes: #5053
2026-08-18 19:33:50 +08:00
sususu
f3e836ce6c refactor(claude): deduplicate CLI identity application and tidy helpers
- Extract the credential-identity block shared by the streaming and
  non-streaming Claude paths into applyClaudeCLIIdentity, so the identity
  seed choice (API key versus stable Kimi auth identity) cannot drift
  between the two paths
- Move stripDefaultKimiClaudeCodeAttribution next to the other attribution
  and CCH helpers in claude_signing.go; it is only called from the Claude
  executor paths and never from the Kimi executor itself
- Reattach the addConfigHeadersToAttrs doc comment to its function in the
  watcher synthesizer helpers
2026-08-18 18:21:33 +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
Luis Pater
f985a5cfe2 Merge pull request #5033 from DEAN-Cherry/fix/claude-fable-model-scoped-cooldown
fix(claude): keep Fable-only rate limits model scoped
2026-08-18 14:52:57 +08:00
Supra4E8C
ee2c494788 fix: update LMU registration links in README files 2026-08-18 14:30:15 +08:00
Supra4E8C
9826bd7da9 Merge pull request #5050 from router-for-me/sponsor/add-bestproxy
Sponsor/add bestproxy
2026-08-18 14:03:23 +08:00
Luis Pater
d388a4bef9 Merge pull request #5043 from DragonFSKY/fix/consumed-compaction-trigger
fix(websocket): drop consumed compaction triggers
2026-08-18 13:56:54 +08:00
Luis Pater
3230e37023 fix(claude): accept both max_tokens and max_completion_tokens in OpenAI→Claude request conversion
- Prefer `max_tokens` when both `max_tokens` and `max_completion_tokens` are present, otherwise use whichever exists.
- Default to existing template `max_tokens` limit when neither field is provided.
- Add regression coverage for all token-limit source/preference paths.

Closes: #5040
2026-08-18 13:46:27 +08:00
Luis Pater
20f84e78c1 fix(gemini): support mixed and structured function_call_output handling in OpenAI→Gemini responses translation
Closes: #5039
2026-08-18 13:37:37 +08:00
Supra4E8C
628f535aac docs(readme): link Bestproxy free trial 2026-08-18 12:50:37 +08:00
DragonFSKY
45c90e8d0e fix(websocket): drop consumed compaction triggers
After remote compaction succeeds, the normalized previous request still contains the consumed compaction_trigger. The next WebSocket-to-HTTP merge replays that trigger before the compaction output and current input, causing the upstream 400 error.

Remove compaction_trigger only from previous request items when the previous response contains compaction or compaction_summary. Add a two-step regression test covering trigger normalization followed by compact replay.

Fixes #5041
2026-08-18 04:33:00 +08:00
Supra4E8C
d3a5988fc0 docs: temporarily hide Qiniu Cloud and FennoAI sponsors 2026-08-18 04:05:59 +08:00
Supra4E8C
781544961d add bestproxy sponser 2026-08-18 03:26:35 +08:00