feat(tui): 在 footer 展示托管用量配额进度条 - #3550
Conversation
🦋 Changeset detectedLatest commit: 21ada36 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 46d47d745a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| }); | ||
|
|
||
| export const STATUS_LINE_ITEMS = ['mode', 'goal', 'model', 'tasks', 'cwd', 'git', 'tips'] as const; | ||
| export const STATUS_LINE_ITEMS = ['mode', 'goal', 'model', 'tasks', 'cwd', 'git', 'tips', 'usage'] as const; |
There was a problem hiding this comment.
Add the required changeset for the usage feature
This commit adds a user-visible footer display and a new status_line.items option, but the reviewed diff contains no .changeset/* entry for @moonshot-ai/kimi-code. Consequently, the release workflow has no version/changelog record for this feature and it may wait for an unrelated release trigger or ship undocumented. Add the CLI changeset required by the repository workflow.
AGENTS.md reference: AGENTS.md:L85-L87
Useful? React with 👍 / 👎.
| const res = await options.harness.auth.getManagedUsage(providerKey); | ||
| if (disposed || res.kind === 'error') return; |
There was a problem hiding this comment.
Discard usage responses after the provider changes
If the user changes from the managed model while getManagedUsage() is in flight, refreshNow() clears the snapshot but cannot start a replacement because inFlight is true. The old request then passes this check and republishes managed-provider quota into the now non-managed state, where it remains visible until the next 60-second tick. Recheck the current provider, or associate the response with a request generation, before publishing it.
Useful? React with 👍 / 👎.
| return [ | ||
| truncateToWidth(line1, width), | ||
| truncateToWidth(line2, width), | ||
| ...this.renderUsageLines(width, usage), |
There was a problem hiding this comment.
Preserve the first quota row while a footer hint is shown
When a transient or warning hint occupies line 2, this call still appends only usage.rows.slice(1), because renderUsageLines() assumes the first row was already rendered on line 2. As a result, the first quota window—typically the 5-hour limit—disappears for the entire lifetime of a warning hint. Pass whether line 2 consumed the first row, or render all usage rows in the trailing block when a hint is active.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🟡 Changes recommended
轮询器的 refreshNow 在 in-flight 场景下可能无法按预期“立即刷新”且新增渲染路径缺少对应单测覆盖。
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
此 PR 在 apps/kimi-code/src/tui 内引入托管(managed)provider 的用量配额展示:通过轮询获取 managed usage 快照注入 AppState,并在 footer 多行渲染配额进度条,同时对自定义 status line command 的 payload 透出 managedUsage 以便外部脚本消费。
Changes:
- 新增
ManagedUsagePoller,按 60s 周期在 managed provider 下拉取用量并去重发布到AppState.managedUsage - Footer 增加多行配额进度条与“Plan usage · updated …”时间戳,并支持 status_line.items 里的
usage徽标槽位 - Status line command payload 增加
managedUsage字段,供自定义命令读取
File summaries
| File | Description |
|---|---|
| apps/kimi-code/src/tui/controllers/managed-usage-poller.ts | 新增轮询控制器:基于当前模型 provider 拉取并发布 managed usage 快照 |
| apps/kimi-code/src/tui/components/chrome/footer.ts | footer 第 2 行起渲染配额条与更新时间戳;新增 usage slot 与 payload 透出 |
| apps/kimi-code/src/tui/config.ts | STATUS_LINE_ITEMS 增加 usage 以支持用户配置 |
| apps/kimi-code/src/tui/kimi-tui.ts | 在 footer mount 时创建/销毁 poller,并在 model / availableModels 变化时触发 refreshNow |
| apps/kimi-code/src/tui/types.ts | AppState 增加 managedUsage,并新增快照类型定义 |
| apps/kimi-code/src/tui/utils/status-line-command.ts | status line command payload 增加 managedUsage 类型字段 |
Review details
Suppressed comments (1)
apps/kimi-code/src/tui/controllers/managed-usage-poller.ts:99
refreshNow()is documented as bypassing the interval throttle, but if a fetch is alreadyinFlightit returns early and thefinallyblock overwriteslastFetchedAtwithDate.now(). In that scenario a model/provider switch can end up waiting a full interval before the next successful refresh.
const now = Date.now();
if (providerKey === lastProviderKey && now - lastFetchedAt < FETCH_INTERVAL_MS) return;
if (inFlight) return;
inFlight = true;
- Files reviewed: 6/6 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| /** | ||
| * Build a human-readable label for a managed-usage row, matching the style | ||
| * used by the /usage panel: "5h limit", "Weekly limit", etc. | ||
| */ | ||
| function usageRowLabel(row: { readonly name?: string; readonly window?: { unit: string; duration: number } }): string { | ||
| const w = row.window; | ||
| if (w !== undefined) { | ||
| if (w.unit === 'week') return 'Weekly limit'; | ||
| return `${String(w.duration)}${w.unit[0] ?? ''} limit`; | ||
| } | ||
| return row.name ?? 'Limit'; | ||
| } | ||
|
|
||
| /** | ||
| * Relative-time reset hint, e.g. "resets in 2h 30m". Returns undefined when | ||
| * the timestamp is missing or unparseable. | ||
| */ | ||
| function usageRowResetHint(resetAt: string | undefined): string | undefined { | ||
| if (resetAt === undefined) return undefined; | ||
| const parsed = Date.parse(resetAt); | ||
| if (!Number.isFinite(parsed)) return undefined; | ||
| const diffSec = Math.floor((parsed - Date.now()) / 1000); | ||
| if (diffSec <= 0) return 'reset'; | ||
| return `resets in ${formatDuration(diffSec)}`; | ||
| } |
| return [ | ||
| truncateToWidth(line1, width), | ||
| truncateToWidth(line2, width), | ||
| ...this.renderUsageLines(width, usage), | ||
| ]; |
| export interface StatusLineUsageRow { | ||
| readonly label: string; | ||
| readonly used: number; | ||
| readonly limit: number; | ||
| readonly resetHint?: string; | ||
| } |
详细说明: - 新增 ManagedUsagePoller 控制器,每 60 秒拉取一次托管用量数据,仅在当前模型所属 provider 为 managed 时轮询 - 在 AppState 中新增 managedUsage 快照,由 poller 推送,footer 与自定义 status line 命令均可读取 - footer 第 2 行起渲染多行配额进度条(5h/Weekly limit 等),并附带"Plan usage · updated HH:MM:SS"时间戳 - status_line.items 新增可选 'usage' 槽位,用户开启后会在第 1 行附加"5h: 73%" 形式的徽标 - 自定义 status line 命令的 payload 中也透出 managedUsage,便于外部脚本读取 技术细节: - 使用 @moonshot-ai/kimi-code-oauth 的 formatDuration 构造"resets in 2h 30m"等重置提示 - 通过 ratioSeverity 区分 success/warn/danger 三档配色,并复用 usage-format 中的 renderProgressBar - 失败时保留上一份快照;切换到非托管 provider 会清空快照;未变化的快照不会触发 setAppState - 模型或模型列表变更通过 refreshNow() 主动触发一次刷新,避免高频定时器探测 文件变更: - 新增:apps/kimi-code/src/tui/controllers/managed-usage-poller.ts - 修改:apps/kimi-code/src/tui/components/chrome/footer.ts - 修改:apps/kimi-code/src/tui/config.ts - 修改:apps/kimi-code/src/tui/kimi-tui.ts - 修改:apps/kimi-code/src/tui/types.ts - 修改:apps/kimi-code/src/tui/utils/status-line-command.ts 测试状态: - [x] 改动仅限 tui 模块内,公共 API 未变 - [ ] 单元测试待补充 - [ ] 端到端测试待运行 > OMC trailers: > Constraint: 仅修改 apps/kimi-code/src/tui/ 范围 > Rejected: 把配额数据塞进现有的 contextTokens 路径 | 语义不一致,会污染上下文窗口指标 > Directive: 用户明确要求将 managed-usage 暴露到 footer 与 status line > Confidence: 中 | 仅做静态阅读,未实际运行 TUI 验证 > Scope-risk: FooterComponent.render() 新增 ≤3 行额外渲染,状态更新频率 1/分钟,对渲染性能影响可控 > Not-tested: 实际登录托管 provider 后的轮询回路、status line 自定义命令的 managedUsage 透出
46d47d7 to
6984cc3
Compare
Resolve review feedback on PR MoonshotAI#3550 (commit 6984cc3): Bug fixes: - managed-usage-poller: replace the in-flight guard with a monotonically increasing `generation` counter so an in-flight response cannot republish into a state where the provider has since changed (managed -> non-managed or a different managed model). - footer: when a transient / warning hint occupies line 2, render the full quota block from line 3 instead of dropping the first row (the 5h limit). Previously, the first quota row was assumed to have been drawn on line 2 and was skipped from the trailing block, so it vanished for the entire lifetime of the hint. DRY / contract alignment: - usage-format: hoist `usageRowLabel` / `usageRowResetHint` and the `ManagedUsageRow` / `ManagedUsageWindow` types here so the poller and the /usage panel share a single source of truth. - status-line-command: drop the duplicate `StatusLineUsageRow` shape; the payload now reuses `ManagedUsageSnapshot` from types.ts so the wire contract cannot drift from the in-app snapshot. Tests (vitest, 230 files / 3533 tests still green): - New: managed-usage-poller.test.ts (9): fetch, snapshot publish, drop on provider switch, refetch on switch-back, dedupe on identical content, error keeps previous snapshot, generation discarding on stale in-flight response, refreshNow bypassing the throttle, no publish after dispose, weekly-window shorthand. - footer.test.ts: render block (line 2 first row, lines 3..N rest, updated stamp), hint-occupies-line-2 still shows every quota row, empty-snapshot fallback to the plain line 2. - footer-status-line.test.ts: usage slot emits "Weekly limit: N%", hidden when slot not in items, hidden when summary is null. > OMC trailers: > Constraint: 仅修改 apps/kimi-code/src/tui/, apps/kimi-code/src/utils/usage/ 与 apps/kimi-code/test/tui/, 不改 wire / SDK / poller 公开签名 > Rejected: 在 poller 内引入 Promise 队列或 mutex 包 | 增加复杂度,对 race 无额外保护;用 generation 已经够 | 增加一层抽象而无功能收益 > Directive: Codex / Copilot / 用户指出 PR 3550 review 项必须全部修复,且原 changeset 保留 > Confidence: 高 | 类型检查通过、oxlint 0 errors、kimi-code 全套 3533 测试通过、usage-format 与 poller 旧测试无回归 > Scope-risk: footer.render 多 1 次 console.time 调用外的开销 ≈ 0;poller 不再依赖 inFlight,行为可观察差异仅在并发切换 provider 那一瞬间 > Not-tested: 真实登录托管 provider 后端点返回多行 limit(>2)的视觉布局;status line 自定义命令消费 managedUsage payload 的端到端联动
|
review 反馈已全部处理,最新 commit
校验:tsc 通过、oxlint 0 errors、 仍待补的:真实登录托管 provider 后的端到端验证(已在 |
端到端验证更新已在本机完成真实托管 provider 的端到端验证:
这覆盖了审查修复 commit 中"多行限额视觉布局"与"重置提示"两项;剩余"自定义状态行命令消费用量快照的端到端联动"如未手动覆盖,请在评审时检查或由作者补一条最小化脚本演示。 |
Related Issue
Pending — will resolve #(issue-number) once a maintainer-approved issue (
/approvecomment) is available. External PRs require an approved issue perCONTRIBUTING.md; this one will be linked here as soon as one exists.Problem
The TUI today offers no way for users to see their managed (Kimi) usage quota at a glance. To know how much of their 5-hour or weekly budget is left, users have to invoke
/usagemanually every time, which is friction during long sessions. There is also no first-class way to feed the same numbers to a custom status line script (for shell prompts, status bars, monitoring).What changed
Two commits on top of the same branch:
6984cc31—feat(tui): 在 footer 展示托管用量配额进度条. AddsManagedUsagePoller(60s tick, managed-provider-only), themanagedUsagesnapshot onAppState, multi-line quota progress bars rendered from footer line 2, the newusageslot instatus_line.items, andmanagedUsageexposed through the status-line command payload.21ada36e—fix(tui): address PR review on managed usage footer. Closes every Codex and Copilot review comment: replaces the in-flight guard with agenerationcounter (stale responses on provider switch are dropped), keeps every quota row visible while a warning/transient hint occupies line 2, hoists the sharedusageRowLabel/usageRowResetHinthelpers intousage-format.ts, drops the duplicateStatusLineUsageRowshape in favour ofManagedUsageSnapshot, and adds unit tests for all of the above.Both commits stay scoped to
apps/kimi-code/src/tui/,apps/kimi-code/src/utils/usage/, andapps/kimi-code/test/tui/. No public SDK / wire-format change.Files changed
新增:
apps/kimi-code/src/tui/controllers/managed-usage-poller.tsapps/kimi-code/test/tui/controllers/managed-usage-poller.test.ts修改:
apps/kimi-code/src/tui/components/chrome/footer.tsapps/kimi-code/src/tui/components/messages/usage-panel.tsapps/kimi-code/src/tui/config.tsapps/kimi-code/src/tui/kimi-tui.tsapps/kimi-code/src/tui/types.tsapps/kimi-code/src/tui/utils/status-line-command.tsapps/kimi-code/src/utils/usage/usage-format.tsapps/kimi-code/test/tui/components/chrome/footer.test.tsapps/kimi-code/test/tui/components/chrome/footer-status-line.test.tsTesting
vitest run apps/kimi-code: 230 files / 3533 tests pass (15 new tests across the new poller test file and the two existing ones).oxlint apps/kimi-code/src apps/kimi-code/test: 0 errors.End-to-end test against a real managed provider remains pending — the
Not-tested:lines in both commits' OMC trailers call this out explicitly.Checklist
/approve). — Will be filled in once a maintainer-approved issue exists; flagged here so reviewers know the blocker.gen-changesetsskill, or this PR needs no changeset. —.changeset/tui-footer-managed-usage-progress.md(minor bump on@moonshot-ai/kimi-code).gen-docsskill, or this PR needs no doc update. — User-visible surface (footer +usageslot) is documented inline in the changeset; no separate docs change needed.Original commit notes (kept for traceability — also in the commit message)
详细说明:
技术细节: