Skip to content

Commit 48ed8df

Browse files
authored
feat(dashboard): 供应商状态卡片新增「状态复位」按钮,并修复 reset 误清配额用量; (#279)
* feat(dashboard): 供应商状态卡片新增「状态复位」按钮,并修复 reset 误清配额用量; Overview 页「供应商状态」卡片标题栏右侧新增 ⟲ 状态复位 按钮,把处于熔断 / 限流等异常态的供应商一键复位为可正常访问,无需切到终端执行 CLI。 根因修复:QuotaGuard.reset() 此前把「状态机复位」与「用量计数清零」两件正交 的事耦合在一个方法里(_entries.clear() + _total = 0)。而窗口基线 load_baseline() 的唯一调用点在进程启动的 lifespan 钩子中、运行期不再回填,导致 Dashboard 的 「1d配额 45%」徽章一经 reset 便永久停在 0%。现只保留 _transition_to(WITHIN_QUOTA) (该方法本身已清 _cap_error_active 并还原探测间隔),CLI / API / Dashboard 三条 路径经单一事实源同时修复,无需 --keep-quota 之类开关。 语义取舍为「如实」:用量确已超过 token_budget × threshold_percent 时,复位后下 一次判定立即回落 QUOTA_EXCEEDED,不伪造用量数字;真正被解开的是熔断、Rate Limit 与上游 cap 错误卡死标志。 实现要点: - 按钮调用无 body 的 POST /api/reset,服务端据此跳过重排序,故不改动供应商优先级; - 新增 .btn-card-action 卡片标题栏控件通用类,复用 .card-title 既有的 justify-content: space-between 实现右对齐,零布局 CSS 改动,并纳入 :focus-visible 焦点环列表; - 交互沿用 persistTierOrder 的 in-flight 防并发范式与 copyFromParent 的瞬时反馈 范式(复位中… → ✓ 已复位 / ✗ 失败,1.5s 还原),成功后定向重渲染供应商列表, 不必等 10 分钟轮询。 顺带修复:「限速中」徽章读 rlInfo.limited,而后端 VendorTier.get_rate_limit_info() 产出的键是 is_rate_limited,键名不匹配使该徽章从未渲染过、Rate Limit 异常态在 UI 上完全不可观测。 测试与文档:新增 7 条用例(配额用量保留、cap 卡死解开、真实超限不放行、/api/reset 无 body 与 -v 两种形态均保留用量、按钮与键名前端守卫);旧用例 test_reset_clears_all_state 曾断言 window_usage_tokens == 0,等于把缺陷固化为契约, 已改写为 test_reset_preserves_window_usage。cli-reference / api-reference 补明「仅 复位状态、不清用量」,dashboard.md 新增「供应商状态复位」小节,issue.md 归档复盘。 隔离实例(端口 3399,复刻 anthropic 熔断 + zhipu 45.6% 配额 + 限速中)实机验证: 复位后熔断转正常、限速徽章消失、配额 456,193,510 tokens 原样保留、链路顺序不变; CLI `reset -p 3399 -v anthropic,zhipu` 同样保留用量。全量 1656 条测试通过。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com> * fix(quota-guard): 用量超阈值时复位不再推后探测时钟,并消除复位后的误报失败; 处理 PR #279 的两条评审意见。 回归修复(评审 #1):初版修复让 reset() 无条件 _transition_to(WITHIN_QUOTA), 用量仍超阈值时下一次判定再回落 QUOTA_EXCEEDED —— 而该回环会经 _transition_to(EXCEEDED) 把 _last_probe 刷成当前时刻,令探测恢复凭空推迟一个 probe_interval(默认 300s);反复点击「状态复位」可无限饿死探测(旧实现清零 用量,不存在此回环)。现 reset() 在用量仍超阈值且已处 EXCEEDED 时不再触发任何 状态转移,仅清 _cap_error_active 并把被 Retry-After 拉长的 _effective_probe_interval 还原为默认值——即「宁可不放行,也不推迟恢复」。 补 2 条回归用例(mock 时钟锁定探测点不被推后 / cap 拉长的探测间隔被还原), 并改写 test_reset_does_not_unblock_genuinely_exhausted_quota:超阈值时复位后 状态保持 quota_exceeded(旧断言 within_quota 恰是回环存在的证据)。 误报修复(评审 #2):/api/reset 已返回 200 后,紧随的 /api/status 定向刷新若 失败(网络抖动、进程重载)会被同一个 catch 误标为「✗ 失败」,诱导用户重复 点击——复位其实已生效。现刷新失败单独吞掉,仅影响展示。 文档(cli-reference / api-reference / dashboard.md)与 CHANGELOG、issue.md 复盘同步对齐终态语义:超阈值 → 保持 EXCEEDED、清 cap 卡死标志、还原探测间隔。 全量 1658 条测试通过。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com> * docs(agents): 移除仓库内的 Agent 协作治理文档; 删除 AGENTS.md / CLAUDE.md(Agent 工程行为准则与协作协议)及其卫星规范 docs/.agents/browser-validation.md(浏览器验证协议)与 docs/.agents/reference-specifications.md(IEEE 引用规范模板)——四者均为 面向本机 AI Agent 环境的私有治理内容,不属于开源仓库交付物。 🤖 Generated with [Claude Code](https://claude.com/claude-code), [CodeX](https://openai.com), [Gemini Code Assist](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com> * build(deps): 同步 uv.lock 中 coding-proxy 版本至 0.5.2a8; pyproject.toml 已 bump 至 0.5.2a8,但 uv.lock 仍停留在 0.5.2a7, 补上发布时遗漏的锁文件版本同步。 🤖 Generated with [Claude Code](https://claude.com/claude-code), [CodeX](https://openai.com), [Gemini Code Assist](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com> * docs(knowledge-map): 清理指向已删除 Agent 治理文档的死链; 随 8fc09d9 移除 AGENTS.md / browser-validation.md / reference-specifications.md 后同步收尾:knowledge-map 移除死链行与 AGENTS.md 锚定表述,合并「Agent 协作」 与「问题档案」两节(issue.md 实际位于 docs/.agents/,原 ../issue.md 链接为 死链,一并修正),路径基准勘误为 docs/.agents/;中英 README 的文档地图同步 移除 AGENTS.md 条目。全部相对链接经脚本自检可解析。 🤖 Generated with [Claude Code](https://claude.com/claude-code), [CodeX](https://openai.com), [Gemini Code Assist](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
1 parent f18eb09 commit 48ed8df

17 files changed

Lines changed: 298 additions & 280 deletions

‎AGENTS.md‎

Lines changed: 0 additions & 58 deletions
This file was deleted.

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
## [Unreleased]
66

7+
- fix(quota-guard): `coding-proxy reset` / `POST /api/reset` 不再清空配额守卫的滑动窗口用量——根因是 `QuotaGuard.reset()` 把「状态机复位」与「用量计数清零」耦合在一个方法里(`_entries.clear()` + `_total = 0`),而窗口基线 `load_baseline()` 的唯一调用点在进程启动的 lifespan 钩子中、运行期不再回填,导致 Dashboard 的 `1d配额 45%` 徽章复位后永久停在 0%;现 `reset()` 只保留 `_transition_to(WITHIN_QUOTA)`(该方法本身已清 `_cap_error_active` 并还原探测间隔),CLI / API / Dashboard 三条路径经单一事实源同时修复。语义取舍为**如实**:用量确已超过 `token_budget × threshold_percent` 时守卫保持 `QUOTA_EXCEEDED`(不伪造用量数字),但仍清除上游 cap 错误卡死标志并把被 `Retry-After` 拉长的探测间隔还原为默认值——刻意不走 WITHIN_QUOTA → QUOTA_EXCEEDED 回环,因为 `_transition_to(EXCEEDED)` 会把 `_last_probe` 刷成当前时刻,令探测恢复凭空推迟一个 probe_interval,反复复位即可饿死探测(PR 评审发现的回归,补 2 条用例锁定);文档口径(`cli-reference.md` / `api-reference.md`)同步补明「仅复位状态、不清用量」;
8+
- feat(dashboard): Overview 页「供应商状态」卡片标题栏右侧新增 **⟲ 状态复位** 按钮,一键把处于熔断 / 限流等异常态的供应商复位为可正常访问——调用无 body 的 `POST /api/reset`,因此**不触发重排序、不改动供应商优先级**,配合上述配额修复亦**不清空额度用量**;新增 `.btn-card-action` 卡片标题栏控件通用类(复用 `.card-title` 既有的 `justify-content: space-between`,零布局 CSS 改动)并纳入 `:focus-visible` 焦点环列表;交互沿用 `persistTierOrder` 的 in-flight 防并发范式与 `copyFromParent` 的瞬时反馈范式(复位中… → ✓ 已复位 / ✗ 失败,1.5s 还原),成功后定向重渲染供应商列表而不必等 10 分钟轮询;定向刷新 `/api/status` 失败时单独吞掉、不误报「✗ 失败」诱导重复点击(复位已生效,刷新失败仅影响展示)(实机验证);
9+
- fix(dashboard): 修复「限速中」徽章从未渲染的问题——前端读 `rlInfo.limited`,而后端 `VendorTier.get_rate_limit_info()` 产出的键是 `is_rate_limited`,键名不匹配使 Rate Limit 异常态在 UI 上完全不可观测;补前端守卫测试锁定键名;
10+
711
## [v0.5.2a8](https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.5.2a8) - 2026-07-06
812

913
- fix(vendor-logging): 修复流式 4xx/5xx 错误日志中文乱码——根因是 `logger.warning("...body=%s...", error_body[:500])` 对 `bytes` 走 `repr()`,非 ASCII 的 UTF-8 字节被转义为 `\xe6\x82\xa8` 之类不可读序列(上游限流/鉴权等中文错误信息无法辨认);新增 `decode_error_body(raw, limit=500)` 工具(`errors="replace"` 容错解码、先整体解码再按字符截断以避免在多字节 UTF-8 边界切断产生二次乱码,`limit` 语义为字符数),`base.py` / `copilot.py` / `antigravity.py` 三处流式错误日志统一收敛,并经 `model/__init__` 与 `vendors/base` 导出复用 (#278);

‎CLAUDE.md‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎README.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ To ensure this project outlives us all (long-term maintainability), we offer exh
175175

176176
- 📖 **[User Guide](./docs/user-guide.md)** — From installation and bare-minimum configs to the semantic breakdown of every `config.yaml` field and common troubleshooting manuals. (Currently in Chinese)
177177
- 🏗️ **[Architecture Framework](./docs/framework.md)** — A meticulous decoding of underlying design patterns (Template Method, Circuit Breaker, State Machine, etc.), targeted at devs who want to peek into the matrix or contribute new vendors. (Currently in Chinese)
178-
- 🤝 **[Engineering Guidelines (AGENTS.md)](./AGENTS.md)** — The systemic context mindset and AI Agent collaboration protocol. It preaches **refactoring, reuse, and orthogonal abstractions** and serves as the ultimate guiding light for all development in this repository.
179178

180179
---
181180

0 commit comments

Comments
 (0)