Commit Graph
2980 Commits
Author SHA1 Message Date
ZheFox 1bc2287baa fix(gemini): normalize mixed tools for same-format providers 2026-08-29 01:08:01 +08:00
ZheFox a519bcf705 Merge pull request #761 from zhefox/main
Fix response reasoning summaries for Chat
2026-08-29 00:03:16 +08:00
ZheFox 9461b1004f Merge branch 'main' of https://github.com/zhefox/Aether 2026-08-29 00:00:13 +08:00
ZheFox 3c15f523be Merge pull request #760 from zhefox/fix/gemini-tool-wire-model-gating
fix(formats): gate mixed Gemini tools by model
2026-08-28 23:36:08 +08:00
ZheFox 5bcdcca784 fix(formats): normalize Responses additional tools for Chat 2026-08-28 23:03:56 +08:00
ZheFox 83098f98b6 fix(formats): gate mixed Gemini tools by model 2026-08-28 20:42:49 +08:00
ZheFox 5ab35ae6ba Merge pull request #759 from zhefox/fix/gemini-tool-schema-compat
fix(formats): enable mixed Gemini tool calls
2026-08-28 17:58:03 +08:00
ZheFox f0b0064f3d fix(formats): enable mixed Gemini tool calls 2026-08-28 16:55:38 +08:00
ZheFox 4879295f23 Merge pull request #758 from zhefox/fix/gemini-tool-schema-compat
fix(formats): sanitize Gemini tool schemas
2026-08-28 16:15:24 +08:00
ZheFox 64e5725331 fix(formats): sanitize Gemini tool schemas 2026-08-28 16:11:16 +08:00
ZheFox 1995198b18 Merge pull request #757 from zhefox/fix/responses-chat-reasoning-summary
fix(formats): degrade Responses reasoning summaries for Chat
2026-08-28 14:09:57 +08:00
ZheFox 5b6fce1a77 fix(formats): degrade Responses reasoning summaries for Chat 2026-08-28 14:05:48 +08:00
ZheFox fa8e443f7b fix(formats): degrade Responses reasoning summaries for Chat 2026-08-28 14:03:43 +08:00
ZheFox 08e7530adb Merge pull request #756 from zhefox/main
fix: preserve Gemini signatures and enforce provider limits
2026-08-28 14:01:43 +08:00
ZheFox 5687dad177 fix(formats): scope signature helper to tests 2026-08-28 13:21:35 +08:00
ZheFox dd2958a458 fix(admin): persist provider settings and enforce quotas 2026-08-28 12:47:54 +08:00
ZheFox c4b4dfa996 fix(formats): preserve Gemini tool thought signatures 2026-08-28 12:47:34 +08:00
ZheFox d88c454a2c Merge pull request #754 from zhefox/main
fix(ai): align Gemini and Responses compatibility
2026-08-28 08:15:35 +08:00
ZheFox 8cdfa338e5 fix(gemini): pair idless tool history 2026-08-28 02:15:00 +08:00
ZheFox 4da8c57fe3 fix(ai): align Gemini and Responses compatibility 2026-08-27 22:13:20 +08:00
ZheFox 7892aa9485 Merge pull request #753 from zhefox/fix/codex-namespace-tool-conversion
fix(formats): preserve Responses namespace tools through Chat
2026-08-26 01:13:53 +08:00
ZheFox 9d9892be6a fix(gateway): finalize cross-format sync JSON responses 2026-08-26 00:43:58 +08:00
ZheFox e2b003af24 fix(formats): preserve Responses namespace tools through Chat 2026-08-26 00:43:50 +08:00
ZheFox ffca7e0402 Merge pull request #752 from zhefox/main
fix(codex): isolate Spark quotas and repair contaminated account state
2026-08-25 22:13:15 +08:00
ZheFox ec6ddb43a7 fix(data): retain applied legacy backfill for upgrades 2026-08-25 21:22:57 +08:00
ZheFox 2f2d444f97 fix(codex): self-heal Spark-contaminated account quotas
Keep model-scoped Spark windows out of account state, preserve authoritative WHAM exhaustion flags, and repair historical cross-family quota generations without weakening stale-response guards.
2026-08-25 19:13:41 +08:00
stabeyandClaude Opus 5 42deab67b3 fix(admin): keep a model-scoped 429 reset out of the account quota slot
`parse_codex_websocket_usage_limit_error` backfills `primary_reset_at` and
`primary_reset_after_seconds` from the error body whenever the embedded headers
did not supply them. Now that a named per-model limit no longer claims the
unprefixed window headers, that absence is exactly what a Spark 429 produces —
and `resets_at` on such an error is the Spark window's reset, so the backfill
put model-scoped timing back on the account's own quota.

Gate the backfill on the same ownership rule the window parsing uses.

Reported by Cursor Bugbot on the fork PR.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 15:22:29 +08:00
stabeyandClaude Opus 5 1b1be918a9 fix(admin): keep Codex model-scoped rate-limit headers out of the account quota
`parse_codex_usage_headers` reads the unprefixed `x-codex-primary/secondary-*`
headers as the account's own quota. They are not: they carry whichever limit
governed the request, and `x-codex-active-limit` names it — `premium` for the
plan's own limit, or a metered feature such as `codex_bengalfox` for a named
per-model limit. On a request billed against a named limit the unprefixed
headers repeat that limit's windows verbatim.

So a single request to a model with its own limit writes that model's windows
into the account slots. The paid-window swap then makes it worse: a named
limit's secondary window is active, unlike the plan's disabled one, so the swap
promotes the model's weekly window into the account's weekly slot — the slot
the UI labels and the scheduler reads through `quota_usage_ratio`.

It also sticks. Both weekly windows share `window_minutes`, so
`codex_quota_same_window_identity` treats them as one window, and
`codex_quota_merge_same_window` drops an observation whose deadline is earlier
than the stored one. The two weeks start at different instants, so every later
account observation looks like a stale sample of a window that already rolled
over and is discarded until the model window's own deadline passes.

Observed on a `pro` key running both model families: one `gpt-5.3-codex-spark`
request replaced the account weekly window with the Spark weekly one, and the
~3000 plan-limit responses over the next 100 minutes were all discarded. The
account's real weekly usage never landed, and its reset time was reported nine
hours late.

The header set describes itself — every named limit announces
`x-codex-<feature>-limit-name` and carries its windows under the same prefix —
so parse the named families directly and only claim the unprefixed windows for
the account when no announced limit owns them. Responses without
`x-codex-active-limit` keep the previous behaviour.

This also stops the Spark windows from going stale: they were only ever written
by the `wham/usage` admin probe even though every response carries them.

Refs #746

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 15:22:29 +08:00
ZheFox 3f2b67f191 Merge pull request #749 from zhefox/main
test(gateway): fix Codex Realtime route fixture
2026-08-23 12:48:10 +08:00
ZheFox 6a9eea34a0 test(gateway): fix Codex Realtime route fixture 2026-08-23 04:00:16 +08:00
ZheFox 453a0b3ee7 Merge pull request #747 from zhefox/main
fix(gateway): support current Codex Realtime live routes
2026-08-23 03:18:46 +08:00
ZheFox 2cd20da1ec fix(gateway): support current Codex Realtime live routes 2026-08-23 02:51:49 +08:00
ZheFox ea4453321d Merge pull request #743 from zhefox/main
fix(usage): unify OpenAI Live and WebSocket records
2026-08-21 12:47:37 +08:00
ZheFox acde38b8e7 fix(usage): unify OpenAI Live and WebSocket records 2026-08-21 11:53:53 +08:00
ZheFox 9996e75a34 fix(ci): align database snapshot migration cutoff 2026-08-21 11:11:45 +08:00
ZheFox 16f96d73ec Merge pull request #742 from zhefox/main
feat(gateway): add Codex Live and OpenAI Realtime
2026-08-21 08:36:19 +08:00
ZheFox 2c89202001 feat(gateway): add Codex Live and OpenAI Realtime
Implement preflighted Live/Realtime WebSocket transports, protocol-aware authentication, usage auditing, UI filtering, and legacy Codex permission migration.
2026-08-21 04:27:34 +08:00
ZheFox fe38dcd294 Merge pull request #741 from zhefox/main
feat(gateway): add Codex Live transport
2026-08-20 22:22:37 +08:00
ZheFox 4185ad1b1e feat(gateway): add Codex Live transport 2026-08-20 21:59:05 +08:00
ZheFox 6916e9da76 Merge pull request #739 from zhefox/main
fix(ws): secure Responses continuation and opaque reasoning replay
2026-08-20 10:01:46 +08:00
ZheFox 654f798d25 fix(ws): harden Responses continuation state 2026-08-20 08:51:16 +08:00
ZheFox bef282cfee fix(responses): replay DeepSeek opaque reasoning state 2026-08-20 00:40:48 +08:00
ZheFox d21d8ce9f5 fix(codex): avoid replaying static config on websocket continuations 2026-08-20 00:40:40 +08:00
ZheFox 342f8b6a5f Merge pull request #737 from zhefox/main
fix(ws): preserve Codex continuations across turn metadata
2026-08-18 18:20:49 +08:00
ZheFox c50a1c6c46 fix(ws): preserve Codex continuation bindings 2026-08-18 17:17:45 +08:00
elky 535ee098c3 fix(auth): reject unsigned admin identity headers v0.7.13 2026-08-18 11:12:17 +08:00
ZheFox b45df89ce4 Merge pull request #730 from zhefox/fix/responses-websocket-current
feat(gateway): add OpenAI Responses WebSocket mode
2026-08-17 21:14:50 +08:00
ZheFox c8118edf36 fix(ws): harden Responses connection lifecycle
Revalidate control policy per turn, isolate downstream credentials, and make planner/turn ownership cancellation-safe.

Preserve opaque protocol events, align configurable timeout semantics, and extend end-to-end security and settlement coverage.
2026-08-17 18:50:29 +08:00
AAEE86 4a0775c4ea style: apply cargo fmt across gateway and aether-ai crates 2026-08-17 14:53:53 +08:00
AAEE86 6fc02dad3e fix(ws): restore redacted PII in provider frames before client delivery
Responses WebSocket 只实现了脱敏的一半:请求侧 mask 之后,provider 事件帧在推给
客户端之前没有还原,于是 session 映射内的占位符以 <AETHER:EMAIL:...> 的形式直接
透给客户端。这里补齐响应侧,语义与 HTTP 路径对齐。

- 还原点是 relay loop 的最后一跳(send_client_message 之前、capture_client_frame
  之前),对应 HTTP 的 restore_sync_response_body / StreamingResponseRestorer 所在
  位置。审计与终态观测继续消费脱敏态事件,只有发往客户端的那一份拷贝被还原。
- 复用 privacy::restore_json_strings(改为 pub(crate))与
  RedactionSession::restore_text,不复制任何还原逻辑:只还原本 session mask 过的
  映射,未映射的占位符原样保留;type / model / id 等协议字段不可能命中 sentinel,
  因此不受影响。批量 {"chunks":[...]} 帧一并递归还原。
- session 生命周期:mask 仍然是 per-turn(slot 依旧每轮新建),但 session 改由连接
  持有,按有界 FIFO 留最近 8 轮。理由是 WS 的会话历史留在上游,continuation 只发
  增量输入,per-turn 释放会漏还原后续响应里回显的更早轮次占位符;HTTP 不会漏,是
  因为它每次重发整段历史、重新 mask 会派生出同一个 sentinel。被挤出窗口的轮次退回
  「占位符原样透传」,不会错误还原成别的值。
- 未命中还原时不改写字节;连接上没有任何 mask session 时(未启用脱敏)连事件 clone
  都不做。

测试:redaction.rs 新增 8 条单测(还原命中/批量帧/未映射占位符原样/未命中不改写/
无 session 不介入/空 session 不留存/审计侧入参不被改写/跨轮还原/窗口有界);
responses_websocket_e2e 新增一条用例,mock 上游回显收到的 input,断言上游只看到
占位符而客户端拿到真实邮箱。
2026-08-17 14:53:46 +08:00