Combine retained daily aggregates with recent usage without replaying historical records or changing the activation boundary. Complete activation-day metrics and expose the UTC calendar used by legacy history.
Render all 365 calendar dates, size heatmap cells responsively, and soften cell corners. Add regression coverage for history cutoffs, retention, sparse dates, and timezone boundaries.
Merge user accounts and usage reporting into one page with a combined ranking and account table, shared precise time ranges, and simpler range labels.
Parse overview metadata once through a schema-only view migration and disable JIT locally for bucket rebuilds. Preserve automatic backfills.
Add redacted OAuth refresh diagnostics, bucket failure context, and regression coverage. Resolve strict Clippy warnings.
Integrate upstream updates while preserving the local analytics dashboards and schema-only migration changes.
Combine user account analysis with upstream user/group usage statistics in separate tabs, retain all migration versions, and keep the deleted audit document removed.
Validation: gateway all-target cargo check, frontend type check and 57 focused tests, 48 migration tests, schema composition checks, and diff whitespace checks.
cli-chat-proxy.grok.com started rejecting every request on 2026-10-01
with HTTP 426 "Your Grok CLI version (0.2.120) is outdated. Please
update to version 1.0.13 or later", because x-grok-client-version and
the xai-grok-workspace user agent were pinned to 0.2.120.
Replace the pin with a runtime-published version (built-in fallback
1.0.46) and add a gateway worker, modelled on the Codex profile worker,
that prewarms at startup and refreshes every 3h:
- read the official stable channel https://x.ai/cli/stable, falling
back to npm @xai-official/grok/latest (deployments that cannot reach
x.ai directly), requiring all six platform binaries at one version;
- never roll back, persist the verified version in runtime KV and
restore it on restart;
- AETHER_XAI_CLIENT_VERSION pins a version, and
AETHER_XAI_CLIENT_PROFILE_REFRESH=off disables the network check.
Endpoint header rules still win over the injected identity headers.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Add dashboard and overview analytics, health monitoring, provider expense tracking, and announcement updates across the gateway and frontend.
Keep schema migrations free of historical backfills while preserving automatic backfill execution. Bound migration deadlines, run schema preparation before Compose replacement, and anonymize deleted dashboard users.
Include the current documentation cleanup and regression coverage.
Responses output turned every tool call named `web_search` or
`web_search_preview` into a hosted `web_search_call`, regardless of what the
client declared. OMP declares its own `{"type":"function","name":"web_search"}`
tool, so when gemini-3.8-flash called it the client got a hosted item it
cannot execute. OMP then echoed that `web_search_call` back as the last input
item with no output, the Gemini request body could not be built, and every
retry failed with 503 "上游请求体转换失败" (provider_request_body_build_failed).
Observed on stabey-124 on 2026-09-29 (request c6270ef6 and five retries after
b794e7ca returned functionCall web_search / call_109312).
Decide the hosted mapping in one place, NamespaceToolAliases::
emits_hosted_web_search_call, used by both the sync builder and the stream
emitter: emit `web_search_call` only when the name is not a namespaced child
and the client did not declare a function or custom tool of that name. When
both a hosted tool and a function share the name, the function wins.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Verified against a live Antigravity + xAI deployment:
- Gemini and Claude clients calling a forced-stream Responses upstream
(xAI, Codex) without streaming always failed: the aggregated body echoes
request metadata (parallel_tool_calls, tools, encrypted reasoning) that
the strict cross-format check refuses, and the gateway then wrapped the
raw SSE capture in a client error body sent with HTTP 200. Project the
validated aggregate to every client format, as the Chat path already
does, and return 502 instead of raw provider bytes when a successful
cross-format response still cannot be converted.
- Gemini stream decoding keyed tool calls by part position, so parallel
calls arriving in separate chunks (all at parts[0]) merged into one call
with concatenated arguments. Key them by arrival order; ids cannot be
used because they are optional and the Antigravity envelope synthesizes
per-chunk ids that repeat across chunks. Generated call_auto_N ids now
follow arrival order.
- Non-stream Responses output reported truncated or filtered cross-format
answers as completed; derive incomplete + incomplete_details from the
canonical stop reason.
- Gemini request parsing ignored parametersJsonSchema and
responseJsonSchema and passed OpenAPI upper-case type names (OBJECT,
STRING) through to JSON Schema targets, which xAI rejects.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A provider model can be addressed by its upstream name or by any of its
`provider_model_mappings` entries, and neither name is published in the
model catalog, which lists global model names only. Resolution ran per API
format, so an alias could win a format the real global model had no
provider in: a `claude:messages` client asking for `gemini-3.8-flash`
landed on the provider that merely renames its own `gemini-3.8-flash-cursor`
model to `gemini-3.8-flash` on the way upstream, and the separate global
model stopped distinguishing the two routes.
Treat global model names as a reserved namespace instead: when the request
names an active global model, only rows bound to it may serve it, whatever
API format they sit in. Rows in hand answer that question for free whenever
one of them is bound to a global model of that name, so the lookup stays off
the path ordinary requests take. Authorization resolves the same way, so an
API key's allowed models cannot be satisfied through a resolution candidate
planning will no longer make.
A request naming a model that is not a global model keeps every matching
rule, so addressing a provider variant by its upstream name still works.
Co-Authored-By: Claude Opus 5 <[email protected]>