feat(stats): expose token usage for cost visibility - #4564
Conversation
|
[Critical] [typecheck]
The test fixtures pass a Note: this does not block — qwen3.7-max via Qwen Code /review |
Tighten persisted token usage so internal prompt traffic and disabled usage statistics do not write history, while surfacing non-ENOENT write failures outside debug logs. Complete the reviewer-requested i18n coverage and regression tests around auto mode notices and best-effort writes. Constraint: Follow-up to wenshao review comments on PR QwenLM#4564. Rejected: Keeping token usage recording outside the internal-prompt gate | It would inflate daily and monthly stats with background prompts. Confidence: high Scope-risk: narrow Directive: Keep /stats token usage scoped to user-visible API responses unless future requirements explicitly include background traffic. Tested: npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts; npx vitest run src/ui/hooks/useAutoAcceptIndicator.test.ts src/ui/commands/statsCommand.test.ts; npm run typecheck; npm run lint --workspace=packages/core; npm run lint --workspace=packages/cli; npm run check-i18n --workspace=packages/cli; npm run build; git diff --check Not-tested: Full repository test suite
Verification Report — PR #4564Branch: Build
Test Results
Type Check
LintAll changed source files pass ESLint — clean. i18n Check
Key Test Coverage Verified
SummaryAll 112 tests pass, typecheck clean across both packages, lint clean, i18n check passed. The PR adds well-tested token usage accounting and — wenshao |
Constraint: Address wenshao's latest PR QwenLM#4564 review suggestions without expanding the /stats command surface. Rejected: Keeping synchronous token-usage writes | sync I/O remains on the API response hot path. Confidence: high Scope-risk: narrow Directive: Keep token usage persistence best-effort and gated by explicit usage-statistics enablement. Tested: cd packages/core; npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts; cd packages/cli; npx vitest run src/ui/commands/statsCommand.test.ts; npm run typecheck; npm run build; npm run lint --workspace=packages/core; npm run lint --workspace=packages/cli; git diff --check Not-tested: Full repository test suite
|
Thank you again for the thorough review, @wenshao. I’ve pushed one more commit addressing your latest suggestions. Looking forward to your review again when you have time. |
Propagate token usage read failures through the existing /stats error path while keeping missing usage files empty, and remove the unreachable telemetry wrapper catch. Constraint: PR QwenLM#4564 review requested user-visible read failures, full i18n for export errors, and removal of dead telemetry catch code. Rejected: Adding warning fields to TokenUsageSummary | It would expand the JSON/export schema when the existing command error path already fits read failures. Confidence: high Scope-risk: narrow Directive: Keep jsonl.read default swallowing behavior for existing session/history callers unless a user-visible caller opts into rethrowing non-ENOENT errors. Tested: npx vitest run src/utils/jsonl-utils.test.ts src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts Tested: npx vitest run src/ui/commands/statsCommand.test.ts Tested: npm run check-i18n --workspace=packages/cli Tested: npx prettier --check changed files Tested: npm run typecheck Tested: npm run lint --workspace=packages/core Tested: npm run lint --workspace=packages/cli Tested: git diff --check Tested: npm run build Not-tested: Full integration test suite
Keep the review follow-ups local to token usage accounting and stats export without adding new abstractions. Constraint: Address PR QwenLM#4564 reviewer requests on token usage export/query reuse, write-failure stderr noise, and invalid-record diagnostics. Confidence: high Scope-risk: narrow Directive: Keep token usage writes best-effort and avoid noisy stderr loops for repeated local failures. Tested: git diff --check; prior targeted core/cli tests, typecheck, and lint passed for this working tree. Not-tested: Full repository test suite.
Maintainer Verification ReportReviewer: wenshao CI StatusAll CI checks passing:
Local Validation
Local Test Results
Note: Code Review SummaryFeature: Persisted token-usage accounting with Core —
Integration —
CLI —
jsonl-utils.ts (+11 lines):
i18n: 9 locale files updated, all keys present across ca/de/en/fr/ja/pt/ru/zh-TW/zh. useAutoAcceptIndicator.ts: Extracted hardcoded strings to Design doc: Observations
VerdictLGTM for merge. CI is all green across all 3 platforms. 138 local tests pass. The feature is well-scoped, privacy-conscious (content-free records), and the export path validation is thorough. No regressions detected. |
|
@wenshao 我已按照您的建议提交了一次优化,期待再次审查。 |
Keep the repeated write-failure regression test aligned with the runtime wording that the PR now emits. Constraint: PR QwenLM#4564 CI failed after the implementation wording changed to "since last log". Rejected: Reverting the implementation wording | it is the latest PR behavior and the failure is test-only. Confidence: high Scope-risk: narrow Tested: cd packages/core && npx vitest run src/services/tokenUsageService.test.ts Not-tested: full repository test suite
wenshao
left a comment
There was a problem hiding this comment.
R8 Suggestion addressed — "in last window" → "since last log" phrasing fix is accurate and the test assertion is updated consistently. No new issues found in the incremental change. All prior-round findings (18 stale comments) have been resolved across earlier commits. LGTM! ✅ — qwen3.7-max via Qwen Code /review
Local Verification Report — PR #4564Tested on: macOS Darwin 25.4.0 (Apple Silicon) Test Results Summary
Total: 138 tests passed, 0 failures. All 12 verification steps green. Environment Notes
ConclusionPR is merge-ready from a testing perspective. All items from the PR test plan verified on macOS:
Verified locally by wenshao |
wenshao
left a comment
There was a problem hiding this comment.
wenshao
left a comment
There was a problem hiding this comment.
No review findings. Downgraded from Approve to Comment: CI still running. The incremental change (CSV export hardening + new tests) is well-targeted and all 110 relevant tests pass. Low-confidence observations (pipe delimiter in composite key, toNonNegativeInteger(0) fallback semantics, ensuredDirs cache + ENOENT silencing, minor test coverage gaps) noted in terminal review only — none warrant inline comments at this stage. — qwen3.7-max via Qwen Code /review
|
This PR is useful for custom-provider users too, because token stats only help if the route identity stays visible. For multi-provider setups, I would keep these fields explicit in the usage record and export:
That makes it much easier to debug cases where the same model is tested through two different gateways and the cost numbers do not line up. If someone is blocked on access or payment rather than the CLI itself, I also keep a tiny paid test path available here: |
|
@copilot resolve the merge conflicts in this pull request |
✅ Verification report — real runtime testing of PR #4564I verified this PR with the real built CLI — unit tests, deterministic seeded data, a real model call, an interactive TUI run (tmux), and adversarial security tests — on a clean worktree at the PR head ( 1. Unit tests — all green (157 tests + i18n)2.
|
| Attack | --output |
Result | Leak? |
|---|---|---|---|
| relative traversal | ../../../tmp/evil.csv |
❌ rejected | no file written |
| absolute outside cwd | /tmp/evil-abs.csv |
❌ rejected | no file written |
| symlinked output dir → outside | linkdir/x.csv |
❌ rejected | no file via symlink |
| symlinked output file → outside | symfile.csv |
❌ rejected | OUTSIDE/target.csv still "secret" (not overwritten) |
| valid control | sub/ok.csv |
✅ written in-cwd (0600) | — |
Every rejection returned Token usage export path must be within the project working directory. — no data escaped the project directory in any case. The Windows alternate-data-stream guard is win32-gated (untestable at runtime on Linux, where report.csv:secret is correctly a normal in-cwd file) but is unit-tested and runs on the passing Windows CI job. The implementation is TOCTOU-hardened (existing-parent realpath check → mkdir → re-validate dir → exclusive wx/0600 temp file → re-validate before & after rename).
⚠️ Pre-merge action & observations
- Merge conflict — must rebase, but trivial. A dry-run merge into current
mainconflicts in exactly one file:packages/cli/src/acp-integration/session/Session.test.ts(a test, unrelated to the feature). The token-usage code itself merges cleanly. - Diff carries unrelated merge-noise. Beyond the token-usage feature, the diff bundles: i18n
t()-wrapping inuseAutoAcceptIndicator.ts(+useAutoAcceptIndicator.test.ts,AutoAcceptIndicator.test.tsx),vscode-ide-companion/.../App.test.tsx,speculation.test.ts,background-tasks.test.ts, daemon design docs, and pure prettier reflows intruncation.ts/toolResultCleanup.ts. None are functional changes to other features, but rebasing to isolate the feature would make the diff much easier to review. - Platform coverage. Author tested on Windows only; this report adds the Linux runtime coverage (display, export, recording, and the symlink/traversal guards). macOS remains unexercised locally, though the logic is platform-neutral apart from the win32-gated ADS guard.
Verdict
The feature does exactly what it claims — correct day/month aggregation, content-free aggregate export, and robust path-traversal/symlink protection — verified at unit, non-interactive, interactive-TUI, real-recording, and adversarial-security levels. Recommend merge after a rebase to resolve the single Session.test.ts conflict (ideally also trimming the unrelated merge-noise from the diff).
🇨🇳 中文版验证报告(点击展开)
✅ 验证报告 — PR #4564 真实运行时测试
我用真实构建的 CLI 验证了本 PR —— 单测、确定性种子数据、一次真实模型调用、交互式 TUI(tmux)以及对抗性安全测试 —— 基于 PR 头(796831871)的干净 worktree。功能正确、隐私安全、且对路径攻击做了加固。 合并前需要一个动作:rebase(见末尾)。CI 在 macOS/Ubuntu/Windows(Node 22)全绿。
1. 单测 —— 全绿(157 + i18n)
core tokenUsageService 18 │ loggers 56 │ jsonl-utils 28 → 102
cli statsCommand 36 │ useAutoAcceptIndicator 18 │ AutoAcceptIndicator 1 → 55
check-i18n → ✅ 全部通过
2. /stats daily 与 /stats monthly —— 显示正确(种子 + 交互式 TUI)
我向 ~/.qwen/usage/token-usage-2026-06.jsonl 种入 5 条不含内容的使用记录(2 天、3 个模型/认证组合),运行真实 CLI。/stats daily 2026-06-18(非交互 -p 与 tmux 交互式 TUI 输出一致):
Total: 6,200 tokens Requests: 4
Input 4,100 · Output 1,950 · Cached 700 · Thoughts 150
By model / By auth type / By model+auth type / By source 均正确,按 token 降序、按语言千分位格式化
所有聚合值与种子完全一致。/stats monthly 2026-06 正确跨两天聚合(总计 13,700,5 次请求,deepseek-chat 9,500/3)。
3. 导出(CSV + JSON)—— 仅聚合,隐私声明已验证 🔒
/stats export monthly 2026-06 --format csv → qwen-token-usage-month-2026-06.csv(权限 0600)
/stats export daily 2026-06-18 --format json --output usage/day.json → usage/day.json(自动创建子目录,0600)
CSV 只有 total/model/auth_type/model_auth_type/source 分组行;JSON 是结构化摘要。两个文件都检查过:无 prompt 文本、无 response 文本、无项目路径、无 prompt/response id —— 且无 sessionId(原始记录里有,但摘要里被丢弃)。导出在结构上不可能泄漏内容。✔
4. 记录钩子 —— 真实端到端证明
从空的隔离 home 出发,一次真实 deepseek-chat 调用(回复 PONG)即生成了含真实、不含内容记录的 JSONL:source=main 与 source=managed-auto-memory-extractor(子代理)区分正确,cachedTokens 也被捕获。证明 loggers.ts → recordTokenUsageFromApiResponseBestEffort 在真实 API 响应上触发(受 usageStatisticsEnabled 开关控制)。
5. 安全 —— 导出路径防护(对抗性,真实文件系统)🛡️
| 攻击 | --output |
结果 | 泄漏? |
|---|---|---|---|
| 相对路径穿越 | ../../../tmp/evil.csv |
❌ 拒绝 | 无文件写出 |
| 项目外绝对路径 | /tmp/evil-abs.csv |
❌ 拒绝 | 无文件写出 |
| 符号链接目录→外部 | linkdir/x.csv |
❌ 拒绝 | 未经符号链接写出 |
| 符号链接文件→外部 | symfile.csv |
❌ 拒绝 | 外部 target.csv 仍是 "secret"(未被覆盖) |
| 合法对照 | sub/ok.csv |
✅ 写入项目内(0600) | — |
每次拒绝都返回 Token usage export path must be within the project working directory. —— 任何情况下都没有数据逃出项目目录。 Windows ADS 防护是 win32 限定(Linux 上无法在运行时触发,report.csv:secret 在 Linux 上是正常文件名),但有单测覆盖,并在通过的 Windows CI 上运行。实现做了 TOCTOU 加固(existing-parent realpath 检查 → mkdir → 复核目录 → 独占 wx/0600 临时文件 → rename 前后再复核)。
- 合并冲突 —— 需 rebase,但很小。 对当前
main试合并只有一个文件冲突:packages/cli/src/acp-integration/session/Session.test.ts(测试文件,与功能无关)。token-usage 代码本身可干净合并。 - diff 夹带无关 merge 噪音。 除 token-usage 功能外,diff 还捆绑了:
useAutoAcceptIndicator.ts的 i18nt()包装(及其测试、AutoAcceptIndicator.test.tsx)、vscode-ide-companion/.../App.test.tsx、speculation.test.ts、background-tasks.test.ts、daemon 设计文档,以及truncation.ts/toolResultCleanup.ts的纯 prettier 重排。都不是对其他功能的实质改动,但 rebase 收拢 diff 会让评审清爽很多。 - 平台覆盖。 作者仅在 Windows 测过;本报告补充了 Linux 运行时覆盖(显示、导出、记录、符号链接/穿越防护)。macOS 本地未跑,但除 win32 限定的 ADS 防护外逻辑与平台无关。
结论
功能与描述完全一致 —— 正确的日/月聚合、不含内容的聚合导出、稳健的路径穿越/符号链接防护,已在单测、非交互、交互式 TUI、真实记录、对抗性安全多个层面验证。建议在 rebase 解决唯一的 Session.test.ts 冲突后合并(最好同时把无关 merge 噪音从 diff 中清掉)。
Persist content-free API token counters and surface daily/monthly summaries plus CSV/JSON export through /stats. Constraint: Issue QwenLM#4479 requested CLI token visibility with monthly/model breakdowns and export while coordinating with QwenLM#4252/QwenLM#4182.\nRejected: Add a separate top-level token command | /stats keeps related statistics in one surface.\nConfidence: high\nScope-risk: moderate\nDirective: Keep TTFT/TPS generation timing and memory diagnostics outside this token-usage surface unless their issues explicitly broaden scope.\nTested: npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts; npx vitest run src/ui/commands/statsCommand.test.ts src/ui/hooks/useAutoAcceptIndicator.test.ts src/ui/components/AutoAcceptIndicator.test.tsx; npm run check-i18n --workspace=packages/cli; npm run lint --workspace=packages/cli; npm run lint --workspace=packages/core; npm run typecheck; npm run build; git diff --check\nNot-tested: full integration suite
Tighten persisted token usage so internal prompt traffic and disabled usage statistics do not write history, while surfacing non-ENOENT write failures outside debug logs. Complete the reviewer-requested i18n coverage and regression tests around auto mode notices and best-effort writes. Constraint: Follow-up to wenshao review comments on PR QwenLM#4564. Rejected: Keeping token usage recording outside the internal-prompt gate | It would inflate daily and monthly stats with background prompts. Confidence: high Scope-risk: narrow Directive: Keep /stats token usage scoped to user-visible API responses unless future requirements explicitly include background traffic. Tested: npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts; npx vitest run src/ui/hooks/useAutoAcceptIndicator.test.ts src/ui/commands/statsCommand.test.ts; npm run typecheck; npm run lint --workspace=packages/core; npm run lint --workspace=packages/cli; npm run check-i18n --workspace=packages/cli; npm run build; git diff --check Not-tested: Full repository test suite
Constraint: wenshao review required consistent token stats, exports, i18n, and best-effort logging behavior. Rejected: Change cached-token labeling | keeping cached tokens included in input preserves the accepted /stats display contract. Confidence: high Scope-risk: narrow Directive: Keep cached tokens included in input whenever cached-only metadata is used in total fallback. Tested: cd packages/core && npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts Tested: cd packages/cli && npx vitest run src/ui/commands/statsCommand.test.ts src/i18n/mustTranslateKeys.test.ts Tested: npm run check-i18n --workspace=packages/cli; npm run typecheck; git diff --check Not-tested: full integration suite
Constraint: Address wenshao's latest PR QwenLM#4564 review suggestions without expanding the /stats command surface. Rejected: Keeping synchronous token-usage writes | sync I/O remains on the API response hot path. Confidence: high Scope-risk: narrow Directive: Keep token usage persistence best-effort and gated by explicit usage-statistics enablement. Tested: cd packages/core; npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts; cd packages/cli; npx vitest run src/ui/commands/statsCommand.test.ts; npm run typecheck; npm run build; npm run lint --workspace=packages/core; npm run lint --workspace=packages/cli; git diff --check Not-tested: Full repository test suite
Propagate token usage read failures through the existing /stats error path while keeping missing usage files empty, and remove the unreachable telemetry wrapper catch. Constraint: PR QwenLM#4564 review requested user-visible read failures, full i18n for export errors, and removal of dead telemetry catch code. Rejected: Adding warning fields to TokenUsageSummary | It would expand the JSON/export schema when the existing command error path already fits read failures. Confidence: high Scope-risk: narrow Directive: Keep jsonl.read default swallowing behavior for existing session/history callers unless a user-visible caller opts into rethrowing non-ENOENT errors. Tested: npx vitest run src/utils/jsonl-utils.test.ts src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts Tested: npx vitest run src/ui/commands/statsCommand.test.ts Tested: npm run check-i18n --workspace=packages/cli Tested: npx prettier --check changed files Tested: npm run typecheck Tested: npm run lint --workspace=packages/core Tested: npm run lint --workspace=packages/cli Tested: git diff --check Tested: npm run build Not-tested: Full integration test suite
Keep the review follow-ups local to token usage accounting and stats export without adding new abstractions. Constraint: Address PR QwenLM#4564 reviewer requests on token usage export/query reuse, write-failure stderr noise, and invalid-record diagnostics. Confidence: high Scope-risk: narrow Directive: Keep token usage writes best-effort and avoid noisy stderr loops for repeated local failures. Tested: git diff --check; prior targeted core/cli tests, typecheck, and lint passed for this working tree. Not-tested: Full repository test suite.
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Keep the repeated write-failure regression test aligned with the runtime wording that the PR now emits. Constraint: PR QwenLM#4564 CI failed after the implementation wording changed to "since last log". Rejected: Reverting the implementation wording | it is the latest PR behavior and the failure is test-only. Confidence: high Scope-risk: narrow Tested: cd packages/core && npx vitest run src/services/tokenUsageService.test.ts Not-tested: full repository test suite
Address the remaining PR review polish without changing token accounting, export formats, or path containment behavior. Constraint: Review 4452925552 requested narrow documentation, ENOENT wording, and NOTICES cleanup only. Rejected: Broader merge-conflict rework | GitHub currently reports the PR as mergeable, and the requested fixes are review polish. Confidence: high Scope-risk: narrow Directive: Keep token usage records content-free and preserve export path validation semantics except for the final ENOENT message. Tested: cd packages/core && npx vitest run src/services/tokenUsageService.test.ts; cd packages/cli && npx vitest run src/ui/commands/statsCommand.test.ts; npm run check-i18n --workspace=packages/cli; npm run typecheck; git diff --check on changed code and i18n files Not-tested: Full test suite not run.
7968318 to
19edc2c
Compare
✅ Local verification —
|
|
This is a useful direction for anyone using Qwen Code with direct providers, OpenAI-compatible gateways, or local proxies. For cost/debug visibility, I would want each usage record to preserve the route identity, not only the public model display name. The minimum tuple that helps users debug billing drift is:
That prevents a common confusing case: the same visible model name is tested through direct DashScope, Coding Plan, a gateway, and a local proxy, but each path may bill, authorize, and report usage differently. Disclosure: I am involved with Black Eagle AI, an independent Chinese-model gateway project. No paid CTA here; this PR is just directly relevant to the route/accounting pattern we keep seeing with Qwen/DashScope/OpenAI-compatible setups. |
|
@qwen-code /triage |
|
Thanks for the PR! Template looks good ✓ On direction: this is a solid fit. Token usage visibility is a clear user need (#4479), and the On approach: the scope is large (3438 additions, 20 files) but mostly justified. The core service (~568 lines) is focused, tests (~812 lines) are thorough, and the 10 locale files are mechanical i18n. The one area worth discussing is the export path validation — there's a lot of TOCTOU-race-mitigation code (10-retry atomic writes, symlink checks at every step, ~200+ lines of validation functions) for what is ultimately a local CLI export. It's security-conscious and well-written, but I'd ask: could this be simplified to a single realpath check + write, without the retry loop, for most real-world scenarios? Not a blocker, just a question. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 方向:非常契合。Token 使用量可见性是明确的用户需求(#4479), 方案:代码量较大(3438 行新增,20 个文件),但基本合理。核心服务约 568 行且聚焦,测试约 812 行且覆盖全面,10 个语言文件是机械性 i18n 翻译。值得讨论的是导出路径验证——有大量 TOCTOU 竞态缓解代码(10 次重试的原子写入、每步的符号链接检查、200+ 行的验证函数),对于一个本地 CLI 导出功能来说可能偏重。安全意识和代码质量都很好,但想问一句:对于大多数真实场景,能否简化为一次 realpath 检查 + 写入,省掉重试循环?不是阻塞项,只是个问题。 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewReviewed the full diff across all 20 files. No critical blockers found. tokenUsageService.ts — Clean, well-structured service. Privacy-preserving by design (no prompt text, response text, project paths, or IDs stored). Schema versioning for forward compatibility. Best-effort write with rate-limited error logging is the right call. CSV formula injection escaping is a nice security touch. Date validation covers leap years correctly. statsCommand.ts — The export path validation is thorough (TOCTOU race mitigation with atomic temp-file + rename, symlink checks at every step, Windows ADS rejection). As noted in Stage 1, it's more defensive than most local CLI tools need, but it's correct and well-tested. The argument tokenizer handles quoted strings properly. loggers.ts — Integration is minimal and correct: gated on jsonl-utils.ts — Small, focused addition: Unit tests — All pass:
Build passes (0 errors, 15 warnings — all in the VSCode extension, unrelated). Real-Scenario TestingBefore (installed build —
|
ReflectionStepping back: this PR does what it says on the tin, and does it well. The core The CLI side adds three subcommands ( The test coverage is genuinely impressive: 138 tests across 4 test files, covering happy paths, edge cases (malformed JSONL, future schema versions, CSV formula injection, symlink rejection, TOCTOU races), and the integration point in Real-scenario testing confirmed all new subcommands work, exports produce clean data, path traversal is rejected, and existing The one area where the PR is heavier than strictly necessary is the export validation code — a simpler Verdict: this is a well-executed feature PR that solves a real user need. Ship it. 中文说明总结这个 PR 说到做到,而且做得很好。 核心 CLI 侧新增三个子命令( 测试覆盖率非常好:4 个测试文件中 138 个测试,覆盖了正常路径、边界情况(格式错误的 JSONL、未来 schema 版本、CSV 公式注入、符号链接拒绝、TOCTOU 竞态)以及 真实场景测试确认了所有新子命令正常工作、导出产生干净数据、路径穿越被拒绝、现有 唯一比必要更重的地方是导出验证代码——简单的 结论:这是一个执行良好的功能 PR,解决了真实的用户需求。可以合并。 — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
What this PR does
Adds persisted token-usage accounting and extends
/statsso users can view daily token usage, monthly token usage, model/auth-type breakdowns, and export summarized usage as CSV or JSON.This also documents the coordination boundary with adjacent stats work: token usage stays under
/stats, generation timing metrics such as TTFT/TPS remain separate, and memory diagnostics are not expanded by this change.Why it's needed
Users currently have no straightforward CLI-visible way to understand how many tokens Qwen Code consumed today or this month, even when a single run can consume a large amount of tokens. This makes usage and cost visibility harder than necessary.
Reviewer Test Plan
How to verify
Run
/stats dailyand confirm it prints the selected day’s total token usage, request count, input/output/cached/thought token breakdowns, and grouped totals by model and auth type.Run
/stats monthlyand confirm it prints the selected month’s aggregate token usage with the same grouping.Run
/stats export monthly YYYY-MM --format csvand/stats export daily YYYY-MM-DD --format json --output usage/day.jsonand confirm the exported files contain aggregate summaries only, not prompt text, response text, project paths, prompt ids, or response ids.Confirm export paths are constrained to the project working directory and reject traversal, symlinked output directories, symlinked output files, and Windows alternate-data-stream style paths.
Evidence (Before & After)
Before:
/statsexposed session/model/tool stats but did not provide persisted daily/monthly token usage or CSV/JSON token usage export.After:
/stats daily,/stats monthly, and/stats exportprovide persisted aggregate token usage summaries with model/auth breakdowns and guarded CSV/JSON export.Local validation passed:
npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts,npx vitest run src/ui/commands/statsCommand.test.ts src/ui/hooks/useAutoAcceptIndicator.test.ts src/ui/components/AutoAcceptIndicator.test.tsx,npm run check-i18n --workspace=packages/cli,npm run lint --workspace=packages/cli,npm run lint --workspace=packages/core,npm run typecheck,npm run build, andgit diff --check.Tested on
Environment (optional)
Windows PowerShell, local npm workspace scripts, Node.js runtime used by the repository build/test commands.
Risk & Scope
/doctor memoryor other memory-diagnostics work./statssubcommands and local aggregate usage files without changing existing/statssession/model/tool behavior.Linked Issues
Closes #4479
References #4252 and #4182 for coordination only; this PR does not implement TTFT/TPS generation timing or memory diagnostics.
中文说明
What this PR does
本 PR 增加持久化 token 使用量统计,并扩展
/stats,让用户可以查看每日 token 使用量、每月 token 使用量、按模型和认证类型分组的明细,并将汇总后的使用量导出为 CSV 或 JSON。本 PR 也记录了与相邻统计工作的边界:token 使用量统一放在
/stats下,TTFT/TPS 等生成耗时指标仍属于独立范围,memory diagnostics 不在本次变更中扩展。Why it's needed
当前用户没有直接的 CLI 可见方式来了解 Qwen Code 今天或本月消耗了多少 token,即使一次运行可能消耗大量 token,也不容易判断使用量和成本情况。本 PR 提升了使用量和成本可见性。
Reviewer Test Plan
How to verify
运行
/stats daily,确认输出所选日期的 token 总量、请求数、输入/输出/缓存/思考 token 明细,以及按模型和认证类型分组的统计。运行
/stats monthly,确认输出所选月份的聚合 token 使用量,并包含相同的分组统计。运行
/stats export monthly YYYY-MM --format csv和/stats export daily YYYY-MM-DD --format json --output usage/day.json,确认导出的文件只包含聚合摘要,不包含 prompt 文本、response 文本、项目路径、prompt id 或 response id。确认导出路径被限制在项目工作目录内,并会拒绝路径穿越、指向外部的符号链接目录、符号链接输出文件,以及 Windows alternate-data-stream 风格路径。
Evidence (Before & After)
Before:
/stats只提供会话、模型和工具统计,不提供持久化的每日/月度 token 使用量,也不支持 CSV/JSON token 使用量导出。After:
/stats daily、/stats monthly和/stats export提供持久化的聚合 token 使用量统计,包含模型/认证类型分组,并支持带路径保护的 CSV/JSON 导出。本地验证已通过:
npx vitest run src/services/tokenUsageService.test.ts src/telemetry/loggers.test.ts、npx vitest run src/ui/commands/statsCommand.test.ts src/ui/hooks/useAutoAcceptIndicator.test.ts src/ui/components/AutoAcceptIndicator.test.tsx、npm run check-i18n --workspace=packages/cli、npm run lint --workspace=packages/cli、npm run lint --workspace=packages/core、npm run typecheck、npm run build和git diff --check。Tested on
Environment (optional)
Windows PowerShell,本地 npm workspace 脚本,以及仓库 build/test 命令使用的 Node.js 运行时。
Risk & Scope
/doctor memory或其他 memory diagnostics 工作。/stats子命令和本地聚合使用量文件,不改变现有/stats会话/模型/工具统计行为。Linked Issues
Closes #4479
References #4252 and #4182 for coordination only; this PR does not implement TTFT/TPS generation timing or memory diagnostics.