Usage hides model attempts without token data and marks interrupted tools as successful
- Dominant language
- TypeScript
- Stars
- 5.4k
- Forks
- 502
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 715
Description
> **Current main status (2026-08-28):** Desktop Usage now reads from the selected Runtime Host, so the legacy-scanner premise below is historical. The remaining scope here is missing/partial/unpriced model-attempt coverage, aborted tool status, provenance, and log truncation presentation. Revision-consistent whole-page loading is tracked in #4058; retiring the unused legacy Storage scanner is tracked in #4059.
## What I saw
While testing Settings → Usage against an isolated Desktop run, I ran into two results that disagreed with the actual runtime history.
### Model calls disappear when the provider omits token usage
The provider completed streamed responses normally, and the canonical model-call ledger recorded nine real attempts (eight completed and one aborted). Because this OpenAI-compatible endpoint did not return token usage, those attempts correctly had `usageBasis: "missing"`.
After refreshing Usage, the model/provider/request counts were still zero and no model request rows appeared. Tool rows from the same session were visible. A real request should not disappear just because its token count or price is unknown.
### An interrupted tool is shown as successful
I started a long Bash command and pressed Stop while it was running. The conversation correctly showed `Interrupted`, and the process stopped, but the matching Usage row was rendered as `Success`.
## Why these are the same problem
The current renderer path still reads the legacy `settings:usageStats` projection. That scanner creates model rows only from persisted `token_usage` messages, so an attempt with missing usage metadata has no row at all.
For tools, it joins a `tool_call` to an optional `tool_result` and currently treats every result that is not explicitly an error—including a missing result—as success. Its renderer contract cannot represent `aborted`, while the Host-owned Usage contract already can.
So I don't think the right fix is to add more guesses to the legacy scanner.
## Suggested scope and sequencing
This looks like a concrete Usage adapter slice under #2010:
- wait for the shared Desktop Host-client lifecycle/epoch boundary;
- have Electron main query the canonical Host Usage authority and expose a narrow semantic adapter to the existing page;
- keep missing usage/cost explicit rather than converting it to zero or absence;
- preserve `aborted` for interrupted tool runs;
- do not restore `window.maka.usage`, open Host stores directly, or fall back to `settings:usageStats`.
This follows the decision in #1982/#2065: the speculative preload namespace is gone, while the final renderer adapter belongs to M4. #2024 only changes the page hierarchy and can remain independent.
## Acceptance
- Every canonical model attempt in the selected range has a request row, including `usageBasis: "missing"` attempts.
- Unknown tokens and cost remain visibly unknown.
- An interrupted/aborted tool is never shown as successful.
- Summary, buckets, and request rows come from the same Host authority and time range.
- Reconnect/Host replacement discards stale results through the shared #2010 lifecycle.
- There is no legacy scanner fallback or second durable Usage authority.
If this is a useful M4 slice, I'd be happy to work on it after the shared client lifecycle lands.
简体中文
## 我观察到的现象
我在隔离的 Desktop 环境中测试“设置 → 使用统计”时,发现两处展示结果与实际 Runtime 历史不一致。
### Provider 不返回 token usage 时,真实模型调用会消失
Provider 正常完成了流式响应,canonical model-call ledger 也记录了 9 次真实请求(8 次完成、1 次中断)。由于这个 OpenAI-compatible endpoint 没有返回 token usage,这些记录正确标记为 `usageBasis: "missing"`。
但刷新 Usage 后,model/provider/request 计数仍为 0,也没有模型请求行;同一个 Session 的工具行却能显示。真实请求不应仅因为 token 数量或价格未知就完全消失。
### 被中断的工具显示为成功
我启动了一个长时间运行的 Bash 命令,并在执行期间按下 Stop。会话中正确显示 `Interrupted`,进程也已经停止,但 Usage 中对应的行显示为 `Success`。
## 为什么这是同一个问题
当前 renderer 仍读取旧的 `settings:usageStats` 投影。这个 scanner 只从持久化的 `token_usage` message 创建模型行,所以缺少 usage metadata 的真实 attempt 不会产生任何行。
工具路径会把 `tool_call` 与可选的 `tool_result` 关联,并把“不是显式 error”的情况都视为 success,其中也包括完全没有 result 的中断调用。旧 renderer contract 不能表达 `aborted`,而 Host-owned Usage contract 已经可以。
因此,我认为正确方向不是继续给旧 scanner 增加推测逻辑。
## 建议范围与顺序
这更适合作为 #2010 下一个具体的 Usage adapter 交付切片:
- 等待共享 Desktop Host-client lifecycle/epoch 边界完成;
- 由 Electron main 查询 canonical Host Usage authority,再向现有页面暴露窄的语义 adapter;
- 缺少 usage/cost 时明确显示 unknown,不要转换成 0 或直接消失;
- 保留工具调用的 `aborted` 状态;
- 不恢复 `window.maka.usage`,不直接打开 Host store,也不 fallback 到 `settings:usageStats`。
这与 #1982/#2065 的决定一致:删除 speculative preload namespace,最终 renderer adapter 归入 M4。#2024 只调整页面层级,可以继续独立进行。
## 验收
- 选定时间范围内每个 canonical model attempt 都有请求行,包括 `usageBasis: "missing"`。
- 未知 token 与费用保持为明确的 unknown 状态。
- interrupted/aborted 工具绝不能显示为成功。
- summary、buckets 与请求行使用同一个 Host authority 和时间范围。
- Host 重连或 replacement 后通过 #2010 的共享 lifecycle 丢弃 stale 结果。
- 不存在 legacy scanner fallback 或第二份持久化 Usage authority。
如果维护者认为这是合适的 M4 切片,我愿意在共享 client lifecycle 合并后继续实现。
Contributor guide
Assessment
This issue has not been assessed yet.