ZheFox
f8b4382a54
test(gateway): align Claude response message ids
2026-09-03 17:04:22 +08:00
ZheFox
d78b5a81fb
fix(gemini): preserve thought-only max-token responses
2026-09-03 17:04:12 +08:00
ZheFox
4c6bafe255
Merge remote-tracking branch 'upstream/main' into codex/fix-antigravity-quota
2026-09-03 15:50:22 +08:00
elky
9309ad844f
test(gateway): align routing fixtures with strategy policies
2026-09-03 14:11:15 +08:00
ZheFox
d672ba2068
test(gateway): seed routing strategy for antigravity flows
2026-09-03 13:45:57 +08:00
ZheFox
587486ab0c
Merge remote-tracking branch 'upstream/main' into codex/fix-antigravity-quota
2026-09-03 13:24:39 +08:00
ZheFox
40a5e1470d
fix(gateway): persist quota refresh from strong catalog reads
2026-09-03 13:16:40 +08:00
elky
77f93c638d
Merge codex/routing-strategy-consolidation into main
2026-09-03 12:00:51 +08:00
fawney
2cb4d554aa
feat(routing): consolidate scheduling strategy configuration
2026-09-03 11:05:59 +08:00
ZheFox
76fb8905c9
test(gateway): align antigravity response message id
2026-09-03 11:04:18 +08:00
ZheFox
f822df6cce
Merge remote-tracking branch 'origin/main' into codex/fix-antigravity-quota
2026-09-03 10:46:49 +08:00
ZheFox
45c840b8d3
fix(providers): refresh Antigravity grouped quotas
2026-09-03 10:46:44 +08:00
elky
214f3d6406
fix(providers): hide billing fields in provider form
2026-09-02 23:17:01 +08:00
elky
7323d41fbe
feat(routing): move sticky-key retries into routing policy with lazy attempts
...
Replace the provider/endpoint max_retries fields as the source of same-key
retries with a routing policy setting, sticky_key_attempts (default 2). Only
the first-ranked candidate is retried on the same key; every failover
candidate gets a single attempt so failover keeps advancing instead of
retrying each fallback key.
Materialize exactly one attempt per candidate and derive same-key retries in
the attempt loop after a candidate-scoped failure, so the retry budget no
longer inflates up-front materialization and needs no upper bound. The budget
travels in the report context; retries reuse the plan with a fresh candidate
id and incremented retry index. Pool groups only retry their first key within
the retry-index stride.
Expose the setting in the routing profile editor and the set_scheduling rule
action, and drop the max_retries input from the provider form.
2026-09-02 20:48:40 +08:00
elky
415b2da81b
feat(routing): make routing profiles the sole scheduler policy source
...
Bootstrap an enabled system-default routing group from the legacy
scheduler config keys on startup, resolve the default ordering config
from that group before falling back to the legacy keys, and stop merging
keep_priority_on_conversion with the legacy flag when a policy is
resolved. Thread the policy-derived ordering config into candidate
preselection so it no longer reads system config independently.
Add per-API-format key priority overrides so a key serving several
formats keeps independent ordering, matching the legacy
global_priority_by_format semantics. Expose keep_priority_on_conversion
in the routing profile editor and read the effective policy in the
model routing preview, monitoring metrics and provider page badge.
2026-09-02 17:04:04 +08:00
zhefox
a0369cf49a
Merge remote-tracking branch 'zhefox/main' into zhefox-main
...
# Conflicts:
# crates/aether-admin/src/provider/quota.rs
# crates/aether-ai/formats/src/formats/openai/chat/stream.rs
# crates/aether-ai/formats/src/formats/openai/responses/mod.rs
# crates/aether-provider/pool/src/provider.rs
# crates/aether-provider/pool/src/quota.rs
2026-09-02 15:25:27 +08:00
zhefox
dbbe7b22ab
fix(pool): isolate dynamic model quota buckets and 429 scheduling
2026-09-02 15:23:23 +08:00
ZheFox
144a28f544
feat(admin-users): add plan entitlement revocation flow
2026-09-02 11:23:24 +08:00
zhefox
7ae984df4b
fix(gateway): detect DeepSeek custom relay models
2026-09-01 22:49:35 +08:00
fawney
30a75832f8
feat(vscodex): add remote Codex collaboration module
2026-09-01 20:25:35 +08:00
ZheFox
5a69cfe40d
Merge pull request #772 from zhefox/main
...
fix(gateway): handle pool saturation and malformed Gemini calls
2026-09-01 19:31:44 +08:00
ZheFox
3d87bbf230
style(rust): apply workspace formatting
2026-09-01 19:31:13 +08:00
ZheFox
633363e190
fix(gateway): handle pool saturation and malformed Gemini calls
2026-09-01 19:25:00 +08:00
elky
d07dc86376
refactor(codex): generalize fingerprint convergence
2026-09-01 17:05:54 +08:00
elky
3e540ce589
fix(gateway): route Codex context through transport facade
2026-09-01 15:53:47 +08:00
elky
a39048ecce
feat(codex): stabilize identity across retries
2026-09-01 15:33:40 +08:00
ZheFox
57abb20778
fix(pool): show Antigravity quota reset times
2026-09-01 11:29:48 +08:00
ZheFox
2fe2600021
fix(pool): isolate model quotas and compact account display
2026-09-01 10:15:57 +08:00
ZheFox
9b819169d5
Merge pull request #767 from zhefox/fix/provider-key-concurrency-cache-affinity
...
fix(gateway): improve provider pool concurrency, quotas, and affinity
2026-09-01 08:11:46 +08:00
ZheFox
9631b229b3
fix(gateway): add provider key concurrency and cache affinity modes
2026-09-01 08:06:58 +08:00
zhefox
56395945c0
fix(gateway): route Responses compaction only to Responses providers
2026-08-29 12:28:55 +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
4da8c57fe3
fix(ai): align Gemini and Responses compatibility
2026-08-27 22:13:20 +08:00
ZheFox
9d9892be6a
fix(gateway): finalize cross-format sync JSON responses
2026-08-26 00:43:58 +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
ZheFox
6a9eea34a0
test(gateway): fix Codex Realtime route fixture
2026-08-23 04:00:16 +08:00
ZheFox
2cd20da1ec
fix(gateway): support current Codex Realtime live routes
2026-08-23 02:51:49 +08:00
ZheFox
acde38b8e7
fix(usage): unify OpenAI Live and WebSocket records
2026-08-21 11:53:53 +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
4185ad1b1e
feat(gateway): add Codex Live transport
2026-08-20 21:59:05 +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
c50a1c6c46
fix(ws): preserve Codex continuation bindings
2026-08-18 17:17:45 +08:00
elky
535ee098c3
fix(auth): reject unsigned admin identity headers
2026-08-18 11:12:17 +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
AAEE86
dbf2809bd6
fix(ws): settle the previous attempt before transparent retry replanning
...
评审第 2 条。配额透明重试原来的顺序是「detach 旧 attempt → 规划并绑定新
attempt → 把旧 attempt 的结算排进队列」。规划因此读到的是旧 attempt 还没投射的
health / adaptive / pool 状态,而且旧 attempt 仍占着自己的 pool key lease——替代
key 的挑选看到的是一把仍被占用的 key,最坏情况下判成「无可用供应商」而放弃一次
本可以成功的重试。
普通的新 turn 早就挡住了这件事:client.rs 在处理 response.create 前调用
await_pending_turn_finalization,注释写的正是「不要让新 turn 基于陈旧的 health /
adaptive / pool 状态规划」。透明重试是同一个问题的另一条入口,漏了这一步。
现在顺序是:detach → 释放准入 → 结算旧 attempt 并等它落地 → 规划/绑定新 attempt。
新增 lifecycle::settle_turn_finalization:与 queue_turn_finalization 的区别只在于
「等」。后者把 handle 挂在连接上让 relay loop 继续跑,用在结算之后不再读取共享
状态的出口;前者用在必须先看到结算结果才能继续的路径上。
顺序用类型固定,而不是靠注释:settle_turn_finalization 返回
PreviousAttemptSettled,retry_active_turn_after_quota_exhaustion 要求这个参数。
凭证只能由 lifecycle 颁发(结算完成,或明确「没有 attempt 要结算」),所以把顺序
写反连编译都过不了。
重试失败路径随之变化:旧 attempt 已经结算,不再 resume 回去。logical turn 仍停在
Replanning,后续分支的 end() / finalize_active_turn 只清 logical turn、不交出
attempt,因此不存在重复结算。结算 outcome 取值不变(两条路径用的都是
terminal_outcome.unwrap_or_else(upstream_closed),而这条分支里 terminal_outcome
必为 Some——usage_limit_error 成立意味着有一个已解析的 error 终态帧)。
代价(都落在「重试失败」这一侧,且只影响已终态 attempt 的报告注解,不影响计费):
- 那条最终转发给客户端的 429 事件不再进旧 attempt 的 client capture;
provider 侧 capture 早在 observe_upstream_frame 里就记下了。
- 如果转发 429 给客户端也失败,record_client_delivery_aborted 落在一个已经结算的
attempt 上,成为 no-op。
测试:
- lifecycle:await_turn_finalization_handle 必须「等到落地」而不是「排进队列」
(C6 依赖的性质);结算完成后规划才读状态的顺序型断言(计数器替身);结算任务
panic 也必须放行调用方,不能卡死 relay loop。
- turn_state:Replanning 状态下 end() 不再交出第二个 attempt(无重复结算)。
- e2e 新增 provider_quota_exhaustion_transparently_retries_onto_another_key:
mock 上游首轮只回 Codex 的 429 usage_limit_reached,网关换到第二把 key 重放同一个
response.create;断言客户端看不到 429、上游被连两次、两次用的不是同一把 key、两个
attempt 各留一条终态行(429 的那条 + 计费的那条)。已验证它在改动前后都通过——
它覆盖的是整条路径可用,顺序由上面的单测确定性覆盖。
夹具随之参数化出 ProviderFixture::CodexKeyPair:透明重试只有 Codex adapter 会
开启,而 codex 候选要求 auth_type = oauth,所以这个夹具用未过期的 oauth 凭证。
2026-08-17 14:53:40 +08:00