939 Commits

Author SHA1 Message Date
Luis Pater
c76dfd4e0e chore(codex): update codex user-agent to 0.153.3
- Update default Codex executor user-agent and model override headers to `codex-tui/0.153.3`.

Closes: #5521
2026-09-06 15:27:15 +08:00
sususu
580df36423 feat(usage): propagate session and parent session hierarchy to usage reporting queue
- Reuse coresession.ExtractSessionInfo across HTTP headers and request payloads to unify canonical session prefix namespaces with the scheduler.
- Extract hierarchical session identities in two phases: initial extraction from request headers on entry, and authoritative deep extraction once request payloads and metadata are available.
- Support Claude Code multi-level subagents (X-Claude-Code-Agent-Id, metadata.agent_id) and Codex thread fork lineages.
- Propagate SessionID and ParentSessionID across ClientRequestMetadata, UsageReporter, and coreusage.Record without root_session_id.
- Include session_id and parent_session_id in queuedUsageDetail for Home LPushUsage forwarding and Redis consumption with self-loop guards.
- Add comprehensive test coverage for canonical headers, body extraction, ghost parent elimination, and self-referential loop guards.
2026-09-06 10:45:32 +08:00
Luis Pater
5ab0bca040 fix(codex): scope usage limit errors to credentials and parse flexible quota resets
- Mark Codex usage limit errors as credential-scoped across HTTP and WebSocket executors.
- Support both top-level and nested error structures with case-insensitive matching when parsing retry-after resets.
- Propagate prevalidated candidate context to session affinity and built-in selectors during auth selection.

Closes: #5529
2026-09-06 06:20:20 +08:00
Luis Pater
7c2f6ce0d1 fix(claude): avoid mid-conversation system splicing for advisor calls or results
- Detect advisor tool calls and advisor results in conversation history.
- Preserve forwarded system prompt blocks in top-level system instead of splicing them into message turns or prepending reminders.
- Prevent message index shifts that break layout bindings for encrypted advisor results and trigger upstream 400 errors.

Closes: #5470
2026-09-06 05:55:42 +08:00
Luis Pater
9dfddd613d fix(aistudio): normalize thinking level to uppercase
- Normalize `generationConfig.thinkingConfig.thinkingLevel` to canonical uppercase enum values (`MINIMAL`, `LOW`, `MEDIUM`, `HIGH`).
- Prevent upstream HTTP 400 invalid argument errors caused by case-sensitive validation.

Closes: #5481
2026-09-06 04:14:41 +08:00
rome-xi
acf919ce50 perf(antigravity): batch reasoning replay mutations 2026-09-04 18:53:21 +08:00
sususu
4a5ab534f8 feat(claude): harden probe and helper request classification, diagnostics isolation, and late cloaking
- Require exactly one non-reminder text block matching quota/test/probe/./Hi for probe request matching.
- Identify title helper requests via expanded session title patterns.
- Implement post-payload bidirectional probe reclassification: strip CPA diagnostics and billing tags on probes, while restoring continuity if declassified.
- Preserve caller-owned and payload-supplied diagnostics on probe requests.
- Gate late sensitive-word obfuscation strictly on cloaked requests in Execute and ExecuteStream.
- Add comprehensive end-to-end tests for probe classification, diagnostics isolation, and late cloaking.
2026-09-04 15:23:31 +08:00
sususu
de4aa60028 feat(claude): add Fable 5.1 reporting outcomes block and post-payload reconciliation
- Inject '# Reporting outcomes' system block for Fable 5.1 / Mythos 5.1 models matching Claude Code 2.1.258 tengu_dapper_lagoon behavior.
- Support both string-format and block-array system prompts for Fable reporting injection.
- Add reconcileClaudeCodeFableModelAfterPayload to reconcile model additions when payload rules override model or thinking.
- Reliably re-add reporting block if omitted after payload rules modify system blocks.
- Drop injected thinking.display on Fable models when payload changes thinking type from adaptive to disabled.
- Enhance payload rule path tracking with ancestor target matching in ApplyPayloadConfigWithTrackedPaths.
2026-09-04 15:23:31 +08:00
sususu
d7052c96af feat(claude): add 2.1.258 dynamic beta headers, model fallbacks, and paired cache TTL
- Introduce 2.1.258 dynamic betas: thinking-display-updates-2026-08-18, server-side-fallback-2026-06-01, and fallback-credit-2026-03-24.
- Prune effort-2025-11-24 on Haiku models, probes, and when thinking is disabled.
- Prune thinking-display-updates on disabled thinking and probe/helper turns.
- Identify Fable 5.1 / Mythos 5.1 models with boundary checks and inject default fallbacks and adaptive thinking display.
- Strictly pair 1h cache control with extended-cache-ttl-2025-04-11, stripping TTL on probes and subagents.
2026-09-04 15:23:31 +08:00
sususu
086ad91bd9 feat(claude): implement 2.1.258 billing header fingerprint chain and upstream request continuity
- Assemble x-anthropic-billing-header strictly following official 2.1.258 binary sequence: cc_version -> cc_entrypoint -> cch -> cc_workload -> cc_is_subagent -> cc_prev_req -> cc_prompt_id.
- Track upstream request-id in thread-safe bounded session continuity state and inject into subsequent turns as cc_prev_req.
- Generate and enforce RFC 4122 UUIDv4 cc_prompt_id per user prompt turn, preserving it across tool continuations while suppressing it on probes and title helpers.
- Detect subagents via agent headers and session metadata to emit cc_is_subagent=true.
- Harmonize diagnostics and continuity lifecycles to prevent uncommitted or truncated streams from corrupting state.
- Exclude x-anthropic-billing-header system blocks from sensitive-word zero-width space injection.
2026-09-04 15:23:31 +08:00
sususu
1c45093d10 fix(antigravity): tighten replacement offset guard in tool provenance degradation
Enforce strict monotonic offset ordering (replacement.start <= last) when
splicing degraded tool provenance IDs to reject unknown zero offsets and
prevent overwriting the payload prefix.
2026-09-04 09:45:49 +08:00
Luis Pater
9ec2bc21c1 Merge pull request #5435 from huangruiteng/codex/openai-compat-bounded-rate-limit-waits
fix(openai-compat): honor bounded rate-limit waits
2026-09-04 01:41:53 +08:00
Luis Pater
ba2cdea3b9 fix(translator/claude): handle incomplete status and terminal state on max_tokens
- Map Claude `max_tokens` stop reason to `response.incomplete` with `max_output_tokens` incomplete details.
- Propagate `incomplete` status to trailing output items across streaming and non-streaming responses.
- Defer and track output item finalization to ensure correct status and arguments when turns are truncated.

Closes: #5439
2026-09-04 00:39:18 +08:00
rome-xi
e44432ab85 perf(antigravity): batch replay degradation rewrites (#5461) 2026-09-03 23:51:04 +08:00
Luis Pater
291cfb87ef feat(codex): support orphan delegation compatibility via orphan-delegation-compatibility
- Add `codex.orphan-delegation-compatibility` configuration option and mirror it to SDK configuration.
- Convert orphan Codex delegation outputs into standard user messages for requests with `X-Openai-Subagent: collab_spawn`.
- Integrate orphan delegation rewriting into OpenAI responses request handling pipeline.

Closes: #5401
2026-09-03 20:21:24 +08:00
Luis Pater
63fdd77f80 Merge pull request #5436 from router-for-me/models
fix(models): apply Home-provided model capabilities during execution
2026-09-03 16:32:54 +08:00
hkfires
c6dd82144b refactor(kimi): use request thinking helper 2026-09-03 13:10:30 +08:00
hkfires
6ff680e90a feat(auth): use home model capabilities for thinking 2026-09-03 13:10:30 +08:00
huangruiteng
6f16121554 fix(openai-compat): honor bounded rate-limit waits 2026-09-03 11:12:09 +08:00
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
272c1cff4e fix(antigravity): bypass quota cooldowns and credit hints when cooling is disabled
- Bypass short cooldown checks and recording in execution flows when cooling is disabled globally or per auth.
- Skip marking credits permanently disabled and refreshing credit hints when cooling is disabled.
- Export quota cooldown status helper functions for auth and configuration evaluations.

Closes: #4793
2026-09-02 22:01:55 +08:00
Luis Pater
d0fb44ca95 fix(antigravity): strip tool config, labels, and session id in token counting
- Strip `request.toolConfig`, `request.labels`, and `request.sessionId` from the payload before dispatching count tokens requests.

Closes: #4749
2026-09-02 21:08:21 +08:00
sususu
acc1500f60 test(executor): update antigravity interactions test to use valid model 2026-09-01 18:00:04 +08:00
Luis Pater
7070785140 fix(auth): preserve upstream status codes in antigravity auth errors
- Introduce `HTTPStatusError` to retain upstream HTTP status codes across Antigravity OAuth and project lookup calls.
- Propagate status codes and retry-after metadata from cause errors in `missingAntigravityProjectIDError`.

Closes: #5368
2026-09-01 08:37:02 +08:00
Luis Pater
9721d9939e feat(usage): track streaming execution state in usage records
- Add `Stream` field to usage records, context helpers, and Redis queue payloads.
- Propagate streaming mode across execution handlers, conductors, and usage reporters.

Closes: #5361
2026-08-31 20:29:19 +08:00
Luis Pater
9fdc460585 fix(claude): preserve tool pairing across intervening system messages
- Preserve pending tool use IDs across message-level system reminders to maintain tool call and result alignment.
- Merge adjacent Gemini request contents for consecutive user and system reminder turns.
- Relax tool response reordering condition and preserve non-response parts in Antigravity executor.
- Align tool results and buffer pending system reminders in OpenAI translator.

Closes: #5354
2026-08-31 19:27:20 +08:00
hkfires
b908ed5d86 fix(store): close git repos during recovery
Close go-git repository handles across store operations and tests to avoid
leaked handles blocking recovery cleanup. Abort recovery before mutating the
worktree when close failures occur and retain backups when rollback fails.
2026-08-31 08:41:08 +08:00
Luis Pater
d31b15916d feat(executor): support token usage parsing for plugin executors
- Add `ParsePluginExecutorResponseUsage` to extract token usage from non-streaming plugin responses across Claude, Gemini, Interactions, Antigravity, and OpenAI/Codex protocols.
- Add `ObservePluginExecutorStreamUsage` to observe and aggregate token usage across streaming chunks.

Closes: #5340
2026-08-30 14:51:08 +08:00
Luis Pater
e4119f83b4 fix(xai): use chat base url resolution for image and video requests
- Route image and video generation requests through `xaiChatBaseURL` so OAuth credentials default to the CLI chat proxy endpoint.
- Update `using_api` and base URL definitions to apply to both HTTP chat and media requests.

Closes: #5335
2026-08-30 14:01:18 +08:00
Luis Pater
c1f3b48999 Merge pull request #5331 from router-for-me/fix-home-refresh-logging
Fix home refresh logging and error handling
2026-08-30 00:46:39 +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
hkfires
6a489fa84d fix(auth): prefer errors from upstream attempts
Track when executor calls cross an upstream transport boundary and use that
signal to keep model/provider errors from being replaced by later local
preparation, selection, or internal failures.

Mark HTTP, websocket, relay, and usage-tracked transports as upstream
attempts, while avoiding marks for local validation, logging, missing
sessions, and successful websocket handshakes before request send.

Parse relative auth expiry metadata and adjust Antigravity refresh timing.
2026-08-29 12:50:46 +08:00
hkfires
bc918ab276 fix(runtime): log safe home refresh error types 2026-08-29 12:50:45 +08:00
hkfires
e4a8f98913 fix(logging): enhance error diagnostics and logging for home refresh operations 2026-08-29 12:50:45 +08:00
hkfires
9a2201c36a fix(auth): forward Home unauthorized upstream errors
Stop refreshing Home-owned OAuth credentials after upstream 401s.
Preserve marked upstream response bodies for direct responses, usage
records, request logs, and websocket handshake failures.
2026-08-29 12:50:44 +08:00
Luis Pater
dd5f9e74e4 fix(kimi): normalize tool and function parameter schemas
- Inline local `$ref` pointers and strip `$defs` and `definitions` from tool parameter schemas for Moonshot compatibility.
- Ensure tool parameter root objects declare an explicit `type: "object"`.

Closes: #5316
2026-08-29 01:22:22 +08:00
sususu98
4b2beb3da1 feat(executor): measure effective TTFT with protocol-aware token classification (#5313)
* feat(executor): measure effective TTFT with protocol-aware token classification

- Introduce protocol-aware streaming token classification under internal/runtime/executor/helps
- Implement responses_ttft_helpers.go for OpenAI Responses / Codex WebSocket & SSE streaming
- Filter out container metadata, rate limits, handshake headers, and tool execution outputs
- Implement dual-track firstPacketDuration fallback for abnormal / zero-token stream terminations
- Add TrackHTTPClientRoundTripOnly to bypass false TTFT triggers on first response body reads
- Optimize UsageReporter.ObserveTokenEvent hot path with fast-path RLock short-circuiting (0 B/op)
- Align terminal event completions across SSE, WebSocket streaming, and non-streaming executions
- Add EnsurePublished metric recording fallback for successful terminal turns lacking usage blocks
- Add stub helpers with comprehensive specifications for Chat, Claude, and Gemini protocols

* fix(executor): normalize SSE response.done and terminate incomplete WS streams

* fix(usage): capture first-packet fallback on initial body reads with TrackHTTPClientRoundTripOnly
2026-08-29 01:22:21 +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
95f83a8d96 fix(claude): treat allowed_warning as allowed in unified rate limit checks
- Treat `allowed_warning` status as allowed for shared 5h and 7d rate limit windows.
- Ensure Fable-only rejections with warning-level shared windows remain model-scoped instead of credential-scoped.

Closes: #5275
2026-08-27 17:32:07 +08:00
Luis Pater
fcea738f74 fix(codex): use codex status error for websocket handshake rejections
- Use `newCodexStatusErr` when handling HTTP handshake rejections in WebSocket execution and streaming.
- Ensure rate limit retry-after metadata and error payload details are properly parsed from handshake responses.

Closes: #5270
2026-08-27 17:09:28 +08:00
Luis Pater
4b5f1eab25 feat(plugin): support observing upstream websocket response events
- Introduce `WebSocketResponseObserver` capability and bump plugin ABI schema version to 4.
- Forward upstream WebSocket response frames from Codex and xAI executors to configured observers.
- Wire `WebSocketResponseObserver` across API handlers and plugin host dispatchers.

Closes: #5248
2026-08-27 05:30:19 +08:00
Luis Pater
9b88808fc7 fix(xai): fold namespace tools and restore dispatcher tool calls
- Introduce `xaiNamespaceRestorer` to track and restore folded dispatcher tool calls across SSE and WebSocket response events.
- Support unwrapping dispatcher tool calls and arguments in `output_item.added` and `function_call_arguments.done` events.
- Normalize historical input namespace tool calls to dispatcher format when namespace folding is active.

Closes: #5214
2026-08-27 01:08:35 +08:00
Luis Pater
2555cde2f1 fix(xai): inline local refs and broaden codex app tool normalization
- Export `InlineLocalRefs` utility to resolve local JSON Pointer references.
- Inline local definitions and remove `$defs`/`definitions` in tool function parameters.
- Support `mcp__` prefixes and `codex_apps` namespace variations when identifying Codex app automation update tools.
- Handle `$ref` entries when inspecting and normalizing root union schema branches.
2026-08-26 23:41:44 +08:00
sususu98
998dcfeba2 fix(antigravity): safely synthesize terminal finish reasons (#5230)
The Antigravity backend sometimes ends a 200 stream without ever emitting
finishReason. Evidence from local request logs: 25 of 18,346 captured
cloudcode-pa streams have no finishReason at all (gemini-3.7-flash x23,
gemini-3.6-flash x2). Gemini and OpenAI chat clients then never see a
terminal event and wait forever.

Only synthesize on a clean end of stream
- The [DONE] tail is now translated only when scanner.Err() is nil. A
  truncated upstream stream previously still produced a terminal event:
  replaying a cut stream to a Claude client emitted the full
  content_block_stop / message_delta / message_stop sequence, so the
  truncation was reported as a completed message.
- Only Antigravity translators synthesize on [DONE], so the other
  executors that emit the tail before checking scanner.Err() cannot leak a
  fake terminal event and are left unchanged.

Never finalize a stream that produced nothing
- Synthesis requires at least one chunk carrying candidates or token
  accounting. Both translators share the same check, and presence alone is
  not enough: `{}`, `{"response":{}}` and `{"response":{"candidates":[]}}`
  leave the stream unstarted.
- Without that guard the synthetic chunk defeats the existing empty_stream
  detection in sdk/cliproxy/auth/conductor_stream.go, which only fires when
  the executor produced no chunk at all. An empty 200 would be reported as
  a successful empty completion instead of a failure.

Synthetic chunks mirror the observed upstream shape
- All 18,321 real terminal chunks carry candidates/usageMetadata/
  modelVersion/responseId with a model-role candidate whose parts are
  [{"text":""}]. The Gemini synthetic chunk now reproduces that shape and
  key order instead of a bare finishReason candidate.
- The last known usage snapshot is carried into the synthetic chunk.
  Without it the final chunk a client sees reports no tokens, because
  FilterSSEUsageMetadata renames non-terminal usage to cpaUsageMetadata
  and the Gemini path restores it per chunk.
- The OpenAI chat path keeps the latest cpaUsageMetadata as pending usage
  and emits it on [DONE] for the same reason.

Do not mistake an intermediate chunk for the terminal one
- A chunk carrying usage but no finishReason stays non-terminal.
  FilterSSEUsageMetadata forwards real usageMetadata on such a chunk only
  after an earlier chunk already carried finishReason, which the existing
  condition covers; finalizing on usage alone would cut the stream short.
- finish_reason and native_finish_reason are resolved by one shared
  helper, so the upstream terminal chunk and the synthesized [DONE] chunk
  cannot drift apart.
- The non-stream Gemini conversion defaults a missing finishReason for
  every candidate rather than only the first one.

Also fixes the unreachable alt != "" branch, which parsed an always-nil
buffer, and replaces an unchecked param type assertion.

Verified by replaying byte-exact upstream bodies extracted from request
logs through a mock backend, comparing this change against the unmodified
branch point: clean streams keep exactly one terminal event, streams
without finishReason gain one carrying the last usage snapshot, a stream
cut mid-chunk surfaces the read error with no terminal event, and an empty
200 now fails with empty_stream instead of reporting a successful empty
completion.
2026-08-25 15:13:04 +08:00
Luis Pater
f2b1996b3f fix(gemini,antigravity): align parallel tool results with preceding tool calls
- Add `AlignClaudeToolResults` to order `tool_result` blocks to match the preceding `tool_use` IDs while preserving other content parts.
- Apply tool result alignment in Claude-to-Gemini and Claude-to-Antigravity request translators.
- Preserve mixed non-response parts when normalizing and reordering parallel function responses in Antigravity executor.

Closes: #5199
2026-08-25 14:57:46 +08:00
Chén Mù
adf052984f fix(antigravity): remove cross-endpoint fallback (#5209) (#5228)
Fixes #5209
2026-08-25 11:51:17 +08:00
sususu98
ca601db05d feat: observe upstream provider quota signals (#5211)
Codex and Claude already emit credential-level quota watermarks on ordinary
responses. CPA used to drop them. Keep the latest watermark in memory and
return it from the management auth-file API.

Hard rule: this is observation only. It must not change scheduling, cooldown
selection, or auth-file persistence.

Snapshot, not accumulation
- QuotaState now has ObservedAt and a bounded Signals map. MarkResult fills
  them from the response headers already recorded on the request.
- Signals is the current response, not a union of earlier ones. Retry-After
  and "limit reached" only appear on the response that produced them; merging
  across responses would keep an expired value forever.
- A response with no quota header (transport failure, 5xx, unrelated endpoint)
  leaves the previous snapshot in place.
- ObservedAt is the time of the current snapshot. It advances even when the
  values did not change, so a consumer can tell a fresh reading from a stale
  one.
- When two model states merge, keep the newer snapshot. Do not union keys
  captured at different times.

What is observed, and what is not
- One predicate, ProviderSupportsQuotaObservation, decides the provider set.
- Keep Codex and Claude. Drop Kimi, xAI/Grok, Antigravity, and the Gemini
  family (gemini/vertex/aistudio): their ordinary headers are not a reliable
  credential-level remaining quota.
- Count-tokens reuses the credential but is not generation traffic.
  ExecuteCount sets SkipQuotaObservation so those headers cannot replace the
  last generation snapshot. Cooldown and success/failure accounting still run.

Cooldown must not overwrite the last snapshot
- Observation writes only ObservedAt and Signals.
- Cooldown writes only Exceeded, Reason, NextRecoverAt, and BackoffLevel,
  through applyCooldownFields. Never assign a fresh QuotaState{...} over a
  live value: that would zero the snapshot on 429, Cloudflare, credential-
  scope sibling updates, and cooldown clears.
- If a credential-quota cooldown is still active, MarkResult still observes
  an already-present model state. It does not create scheduler state just to
  record a watermark.
- .cds files persist cooldownFieldsOf(Quota) only. Restore keeps the newer
  ObservedAt, so reloading cooldown cannot clobber a newer in-memory snapshot.
- cooldownQuotaEqual still ignores observation fields, so a watermark change
  cannot by itself persist cooldown or move the scheduler.
- The management payload omits every cooldown field, so it cannot be mistaken
  for scheduler state or wired back into scheduling.
- Manual ResetQuota still clears the full QuotaState.

Codex websocket events
- Codex WS reports quota as codex.rate_limits frames, not HTTP headers.
  ParseCodexQuotaEventHeaders turns one event into the same bounded header
  shape, and MergeResponseHeaders folds it into the request-scoped holder.
  additional_rate_limits is accepted as an object (websocket) or an array
  (/wham/usage).
- Parse only through AppendCodexAPIWebsocketResponse. The shared
  AppendAPIWebsocketResponse is also used by xAI, and xAI error frames really
  do carry x-ratelimit-* headers. Parsing every frame as Codex quota would
  forge Codex headers into another provider's request log.
- Also capture code_review_rate_limits.
- A malformed active-limit name drops only that one header, not the window
  watermarks parsed from the same event.
- The type discriminator scans a bounded frame prefix, not every byte of
  every frame.
- HTTP namespaces an extra limit by short name (x-codex-bengalfox-*); WS
  namespaces it by limit name (GPT-5.3-Codex-Spark). The two paths cannot
  emit the same header names. The X-Codex-Additional- prefix marks the WS
  origin, and snapshot replacement keeps the two spellings from piling up.

Hardening
- Reject observed values with control characters. These strings reach the
  plain-text request log, and Limit-Name is upstream-controlled, so CR/LF
  could forge a header line.
- When the header cap is hit, keep plan/credits/primary ahead of
  additional-limit namespaces, then sort names so truncation is deterministic.
- QuotaState.Clone deep-copies Signals and is used by Auth.Clone and
  ModelState.Clone.
- Token stores still serialize credential metadata only, so observation adds
  no auth-file writes.
2026-08-24 17:15:37 +08:00
程辉
6f4b6dc5f5 fix(xai): keep forced image_generation from other tools
Rewriting {type: image_generation} to string required would let later
x_search injection or leftover web_search satisfy the choice. Reduce
the tools list to image_generation for that forced case, and skip
x_search injection while the remaining tools are image-only.

Closes: #5183
2026-08-23 12:22:14 +08:00
程辉
fba1ff24ac fix(xai): preserve auto when rewriting image-only allowed_tools
An allowed_tools list that only names image_generation cannot be sent
to chat-proxy. Map that empty remainder to the original mode so
mode=auto stays optional instead of becoming required.

Closes: #5183
2026-08-23 12:03:46 +08:00
程辉
d2742c5f37 fix(xai): map image_generation tool_choice to required
chat-proxy rejects allowed_tools lists that name image_generation.
Rewrite a forced image_generation choice, and an allowed_tools list
that only names that hosted tool, to the string "required". Mixed
allowed_tools lists drop the image_generation entry. Prune orphans
before this rewrite so older models still lose the leftover choice.

Closes: #5183
2026-08-23 10:12:52 +08:00