- [Eliminate 503 Misattribution and Quota False-Deadlock: Rebuild Bucket Scheduling, Custom Mapping Priority and Timeout Contract] (Fixes #3838, #3841, Ref #3821, #3827, #3840):
- Root-cause fix for 503 misattribution (92.6% of all 5xx): Unified the internal rate-limit predicate into
policy::is_internal_gateway_exhaustionas the single source of truth, and filled in the previously missedAll accounts rate-limited(the old list only matchedall accounts limited, causing local pool exhaustion to be misreported as upstream 503); also converged two other independently drifting implementations inrate_limit.rsandtoken_manager.rs. (Fixes #3838) - Dedicated 403 ban attribution: Added
account_forbiddenerror code plus 12-language copy forTOS_VIOLATION/PERMISSION_DENIED, so a banned account is no longer conflated with capacity exhaustion after 403→503 remapping. (Fixes #3838) - Quota diagnosis upgraded to trust upstream authoritative signals: Added L1 locking that prefers the upstream
quotaResetTimeStamp. All four quota bucket classes (Argon dedicated / Ultra shared / standard Gemini / 3P) carry it when exhausted, so trusting the official recovery instant is more reliable than local inference and immune to upstream copy changes;is_quota_depleted_signalis now case-insensitive, keepscheck quotaas the 1.5% bucket trigger, and explicitly excludes transient TPM throttling (preventing pool-wide cascading lockouts, Fixes #3506). (Fixes #3841) - Lock source ordered by hard-quota priority: Bucket predicate relaxed from “weekly only” to “any bucket in the matched group ≤ 1.5%”. A drained weekly locks until its own reset; only when weekly is healthy and solely 5h is drained do we lock the short 5h cycle — avoiding both re-probing every time 5h recovers while weekly is still zero, and locking a recoverable-in-minutes account for a whole day.
- Fixed quota false-full blind spots: Handles upstream omitting
remainingFractionfor exhausted models (previouslyunwrap_or(100)read it as full), and unified multi-key tolerant quota matching across preferred accounts, sticky sessions and the 60s reuse window. - Quota scheduling closed loop: Blocked the whole-pool 0-quota bare-run escape; fixed the 3P path of
accounts_with_positive_quotamissing anavailable_modelsfallback, which let a single drained 3P model trip the 502no quota accountsgate for the entire pool; quota-exhausted 429 responses are now passed through verbatim without gateway rewriting. - Eliminated priority-inversion starvation: Moved quota filtering ahead of priority convergence in
select_with_p2c, establishing the invariant that “priority only competes among healthy accounts holding positive quota for the target model”. Fixes the severe defect where the pedal mode (or a manually boosted account) atpriority=1with 0% quota and zero in-flight would evict all other full-quota accounts and return “no available accounts”. (Ref #3840) - Model routing: user custom mapping takes absolute precedence: Custom mappings moved to the very front, ahead of official hot-update deprecation redirects; fixed the post-hoc
resolve_bare_tiered_model_routerewrite that silently downgraded matched targets totiered/medium; default tier selector flipped to prefer High (upstream medium/tiered are measured to be capacity-starved); added in-place promotion to High when upstream returns 503MODEL_CAPACITY_EXHAUSTED. - Timeout contract: hard truncation removed, frontend/backend aligned: Abolished the 135s/160s hard-coded cap (below the measured medium p90 of 130.9s, which turned legitimately slow requests into 504 and triggered retry storms); first-byte baseline restored to 180s with multimodal ceiling widened to 270s; wired the frontend large-body replay threshold so the backend 4MB hardcode no longer drifts from the frontend 8MB setting.
- Root-cause fix for 503 misattribution (92.6% of all 5xx): Unified the internal rate-limit predicate into
- [Pedal Quota Mode Rebuilt as Highest Scheduling Priority] (PR #3840, Thanks to @zepeng-jin):
- Brute-force suspension replaced by priority competition: Activating pedal mode no longer suspends other accounts via
proxy_disabled = true; instead it boosts imminent accounts to scheduling priority1(default 50). Eliminates three pathologies at once: Prompt Caching invalidation from forced failover of ongoing sessions, 429s from crushing all concurrency onto a single account, and cross-model collateral damage from entity-level disabling. (PR #3840, Thanks to @zepeng-jin) - Concurrency resilience: Existing sessions stay bound to their accounts to preserve cache; new sessions fully prioritize burning the imminent account, with overflow spilling to other idle accounts.
- Smooth automatic recovery: Once target accounts fully drain (0%) or reach their reset time, original priorities are restored precisely from
originalPriorities; legacy suspended-state cleanup is retained for backward compatibility. (PR #3840, Thanks to @zepeng-jin)
- Brute-force suspension replaced by priority competition: Activating pedal mode no longer suspends other accounts via
- [根治 503 归因污染与配额假死:重构配额大桶调度、自定义映射优先级与超时契约] (Fixes #3838, #3841, Ref #3821, #3827, #3840):
- 根除 503 归因污染(占全量 5xx 的 92.6%): 统一收敛网关内部限流判据至
policy::is_internal_gateway_exhaustion单一权威源,补全此前漏判的All accounts rate-limited(旧列表只写all accounts limited,导致本地账号池限流被误报为上游 503);同步收敛rate_limit.rs与token_manager.rs中另两处独立漂移的判据实现。(Fixes #3838) - 新增 403 封禁专用归因: 为
TOS_VIOLATION/PERMISSION_DENIED新增account_forbidden错误码与 12 语言文案,账号封禁不再被 403→503 映射后与容量枯竭混淆。(Fixes #3838) - 配额诊断升级为采信上游权威信号: 新增 L1 上游
quotaResetTimeStamp优先锁定,四类配额桶(Argon 独立桶 / Ultra 共享大桶 / 普通 Gemini 大桶 / 3P 桶)耗尽时直接采信官方恢复时刻,比本地推算更可靠且不受上游改文案影响;is_quota_depleted_signal统一判据大小写不敏感,保留check quota作为 1.5% 木桶触发入口并显式排除 TPM 瞬态限流(避免全池级联锁定,Fixes #3506)。(Fixes #3841) - 锁定源按硬配额优先排序: 桶判据由「仅 weekly」放宽为「命中分组内任意桶 ≤ 1.5%」,weekly 耗尽则锁 weekly reset,仅当 weekly 健康、只有 5h 耗尽时才锁 5h 短周期——既避免 5h 一恢复就去试而 weekly 仍为 0 造成反复调度,也避免把几十分钟可恢复的账号锁上一整天。
- 修复配额假满额盲区: 处理上游对已耗尽模型直接省略
remainingFraction的场景(原先unwrap_or(100)会读成满额),并在优先账号、会话粘性与 60s 复用窗口统一采用多键容错配额匹配。 - 配额调度闭环: 封堵全池 0 配额裸奔放行漏洞;修复
accounts_with_positive_quota的 3P 路径缺available_models兜底导致单个 3P 模型 0% 就让整池命中 502no quota accounts门禁的问题;100% 原样透传上游配额到期 429 响应,禁止网关改写。 - 消除 0 配额高优账号饥饿全池(优先级倒置死锁): 将
select_with_p2c的配额过滤前置于优先级收敛,确立不变式「优先级只在具备该模型有效正配额的健康账号之间竞争」。修复蹬额度模式把临期账号设为priority=1后,该账号配额归零且空闲时会把其他满额账号剔除、进而return None报「无可用账号」的严重缺陷。(Ref #3840) - 模型路由:确立用户自定义映射最高优先级: 自定义映射提升至物理最前位,高于官方热更新淘汰重定向;修复映射命中后被后置
resolve_bare_tiered_model_route二次篡改为tiered/medium的缺陷;默认档位选择器翻转为 High 优先(实测 medium/tiered 在上游处于容量枯竭状态);新增上游 503MODEL_CAPACITY_EXHAUSTED原地升档 High 自愈能力。 - 超时契约:解除硬截断,前后端闭环: 废除 135s/160s 超时硬编码截断(该值低于 medium 实测 p90 130.9s,会把本可成功的慢长请求反向判为 504 并引发重试风暴);首字基准恢复 180s、多模态上限放宽至 270s;打通前端大请求体重放门限配置,消除后端硬编码 4MB 与前端 8MB 的双轨漂移。
- 根除 503 归因污染(占全量 5xx 的 92.6%): 统一收敛网关内部限流判据至
- [蹬额度模式重构为最高调度优先级] (PR #3840, Thanks to @zepeng-jin):
- 解除暴力禁用,改为优先级竞争: 激活蹬额度模式时不再通过
proxy_disabled = true挂起其他账号,改为把临期账号调度优先级提升至1(默认 50)。彻底消除三重症结:既有会话因强制 Failover 导致 Prompt Caching 击穿、多并发压在唯一账号上触发 429、以及账号实体级禁用造成跨模型误伤。(PR #3840, Thanks to @zepeng-jin) - 并发弹性保底: 老会话继续留在已绑定账号以保住缓存,新会话 100% 优先消耗临期账号,并发流量自动外溢至其他空闲账号。
- 平滑自动恢复: 待蹬账号周配额全部消耗(0%)或到达重置时间后,按
originalPriorities精准恢复初始优先级;并保留旧版本残留挂起状态的容错清理逻辑。(PR #3840, Thanks to @zepeng-jin)
- 解除暴力禁用,改为优先级竞争: 激活蹬额度模式时不再通过
What's Changed
- fix(proxy): 放宽长上下文大请求体跨账号重放护栏门槛至4MB并提升上限至3次 (Fixes #3821, Ref #3835) by @cubelikeplayDaniel in #3839
- fix(pedal): 重构蹬额度模式为最高调度优先级,消除会话粘性破坏与多会话并发挤兑 by @zepeng-jin in #3840
Full Changelog: v5.0.3-beta.2...v5.0.3-beta.3