Repository navigation
Conversation
Claude Code reads the unified rate-limit headers of its own API responses and claude-agent-acp forwards them on a usage_update as `_meta["_claude/rateLimit"]`; Codex writes the same picture into its rollout on every token_count (`rate_limits`). Neither was kept. Both are parsed into `PlanLimitWindow`s (`acp::plan_limits`). Claude's live reports become an `AcpEvent::PlanLimits`, held in `SessionState` and the snapshot; the Codex rollout parser keeps the last windows it recorded in `SessionStats.plan_limits`. A report replaces the held window of its kind only when it is newer: a later reset time, or the same reset time with at least as much used. The windows belong to the account, so a new connection starts from what the agent's live connections on the same settings (`config_fingerprint`) already hold, and `plan_limits_subscriber_task` hands a report on one of them to the others. Nothing is requested from any provider.
The context-usage indicator resolved its tab's connection and session stats inline. Both reads move to `use-composer-session`, so the next indicator in that row reads them the same way. No behavior change.
The row below the composer gets an hourglass with the time left until the window closest to its limit resets: amber from 80% (or Claude's `allowed_warning`), red at the limit. Its popover lists every window with the share used and the local reset time. A window past its reset no longer shows its old figure, and nothing renders for a sign-in without a plan. The connection store keeps `planLimits` from `plan_limits` events and snapshots by the backend's rule, so a stale snapshot never rolls the figures back. Codex sessions read theirs from the session stats.
nnnmdzz
added a commit
to nnnmdzz/codeg
that referenced
this pull request
Oct 13, 2026
…odex's own bucket - A plan-limits event no longer counts as activity on the connection that applies it: most arrive forwarded from another connection of the account, so stamping last_activity_at kept idle connections (closed browser tabs) out of the idle sweep for as long as any connection kept reporting. - The subscriber offers the reporter's current figures rather than the report's payload, so two reports that differ only in status (each superseding the other) settle instead of bouncing between the connections forever. - Codex: only the account's own rate-limit bucket counts (limit_id "codex", or none in older rollouts). Codex writes the last bucket a response reported into token_count, which can be a model's separately metered one. - Codex windows carry observed_at, the rollout line's time, and a first turn refused at the limit (no usage, no reply) still yields session stats to carry them. - Docs: the config fingerprint does not see a sign-in the agent keeps itself.
…ures - seven_day_overage_included is a per-model weekly window (Claude Code's "Fable limit"), not usage including extra credit: label it "Weekly · Fable" and drop the sevenDayOverage strings. - The popover notes when recorded figures are over 15 minutes old (Codex's own staleness threshold), since a Codex conversation opened long after its last turn shows that turn's figures, and that sending a message refreshes them.
… the day - The status-tie test now sends a later report once the connections settle and checks it still reaches the peer, so a subscriber that stopped after one forward fails it. - Pin the 15-minute staleness threshold, and check that a note about figures recorded on another day names the day as well as the time.
Collaborator
|
codeg work task |
nnnmdzz
added a commit
to nnnmdzz/codeg
that referenced
this pull request
Oct 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
用订阅登录(Claude Pro/Max、ChatGPT 套餐下的 Codex)时,用量按 5 小时窗口和每周窗口计算。codeg 里看不到用了多少、什么时候重置,额度用完只能去官网或 CLI 里查。
这些数字 agent 自己就有,不需要额外请求:
rate_limit_event抛出,claude-agent-acp 把它放在usage_update的_meta["_claude/rateLimit"]里转发(status、resetsAt、rateLimitType、utilization,CLI 提供时还有各窗口的unifiedWindows)。token_count都把rate_limits(primary/secondary:used_percent、window_minutes、resets_at)写进 rollout。codeg 目前丢弃前者,也没有读后者。
修改
后端
PlanLimitWindow { kind, used_percent, resets_at, window_minutes, status }与AcpEvent::PlanLimits,两种来源都在acp::plan_limits解析:Claude 的utilization是 0–1 的比例,转成百分比;毫秒时间戳按秒处理;旧版 Codex rollout 只有resets_in_seconds,按该行的时间戳换算。Codex 的窗口按长度命名(300 分钟为five_hour,10080 分钟为seven_day),所以只有周窗口的套餐也显示为每周。SessionState.plan_limits(按kind合并)和LiveSessionSnapshot;Codex 的 rollout 解析器把最后一次token_count记录的窗口写入SessionStats.plan_limits。resets_at更晚即是新窗口,直接替换;resets_at相同时用量只增不减,取不低于现值的那份(用量相同但状态变化也接受);其余视为过时报告,忽略。较慢的连接或较早的 snapshot 不会把数字倒回去。前端合并用同一规则。config_fingerprint相同,即同一登录或同一 provider)的活跃连接共用一份:新连接从它们已知的数字开始;任一连接报告新数字时,plan_limits_subscriber_task(订阅内部事件总线)把比各连接现有更新的部分转给其它连接,经各自的事件流发出,已连接的客户端都能收到。配置不同的连接互不共享,所以切到 API key 或第三方 provider 的会话不会显示订阅的数字。桌面和 server 两种模式启动时都会 spawn 该任务。前端
planLimits,处理plan_limits事件;hydrate 的 fresh/stale 两条分支都按上述规则合并。ComposerPlanLimits:沙漏图标加上最接近上限的窗口还有多久重置(已达上限优先,其次用量最高,并列取更早重置的)。80% 起或 Claude 报allowed_warning时为琥珀色,达到上限为红色。点开列出每个窗口的用量、进度条、剩余时间和本地重置时刻。桌面端和移动端都在这一列;移动端分支名照常截断让出空间。ComposerContextUsage读取当前 tab 的连接和 session stats 的逻辑提取到use-composer-session,两个指示器共用,行为不变(单独一个 refactor commit)。刻意不做的:
/api/oauth/usage),也不读取凭据,只显示 agent 已经报告过的数字。所以同账号还没有任何报告之前不显示。claude-agent-acp 只在本回合已有用量数据之后才转发rate_limit_event,数字在回复过程中出现和更新。account/rateLimits/updated,所以 Codex 的数字在回复写入 rollout 后更新,也不跨会话共享。验证
cargo test --no-default-features --features server-bin --lib:新增 13 条,覆盖 Claude 的两种载荷形状、比例与毫秒换算、Codex 窗口命名与旧版resets_in_seconds、过时报告不回滚、同配置连接之间的转发(不同配置、不同 agent 不受影响)、新连接的初始值、snapshot 和 rollout 解析,全部通过。本机环境下(以 root 运行等)有 10 条既有用例失败,在 main 上同样是这 10 条,与本改动无关。cargo clippy --no-default-features --features server-bin --bin codeg-server --lib -- -D warningspnpm lint .、pnpm test(606 个文件 / 8947 条)、./node_modules/.bin/tsc --noEmit、prettier。前端新增 22 条:合并规则、颜色与选取、snapshot、store 的事件与 hydrate、组件渲染。codeg-server加静态导出,用一个模拟 claude-agent-acp 的 agent 在回复后发出带_meta["_claude/rateLimit"]的usage_update,桌面(1440×900)和移动端(390×844)各跑一遍:回复前不显示;回复后显示 5 小时窗口的倒计时,弹层列出两个窗口;第二个新会话发送前就带着同样的数字;第二个会话报告更高用量后,所有活跃连接(9 条,其中 8 条自己没报告过这个数字)的 snapshot 都更新为该数字。另在繁体中文界面下检查了移动端布局。