dsh-all-usage 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +193 -19
- package/fixtures/usage-events.json +172 -0
- package/lib/aggregation.js +1002 -0
- package/lib/balance.js +112 -0
- package/lib/client.js +1 -2906
- package/lib/http.js +305 -0
- package/lib/index.js +2 -2119
- package/lib/ledger.js +464 -0
- package/lib/plugin.js +276 -0
- package/lib/pricing-runtime.js +282 -0
- package/lib/pricing.js +299 -36
- package/lib/session-sync.js +589 -0
- package/lib/usage-core.js +127 -0
- package/package.json +28 -3
- package/scripts/replay-fixture.mjs +155 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,70 @@ All notable changes to `dsh-all-usage` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.1.3] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Make Cost Statistics tier-aware: show expandable official rate schedules and support validated context bands in explicit price overrides.
|
|
12
|
+
- Added deterministic usage invariants and a redacted fixture replay command covering failed requests, orphan usage chunks, cache buckets, replacement semantics, and exact expected totals.
|
|
13
|
+
- Added a Node 22/24 CI matrix with package-content checks and required real DSH runtime smoke coverage for DSH 0.1.1-rc.1 and 0.1.1-rc.2.
|
|
14
|
+
- Added community issue templates for data inconsistencies, plugin startup failures, and cost calculation issues.
|
|
15
|
+
|
|
16
|
+
### Performance
|
|
17
|
+
|
|
18
|
+
- Avoid rebuilding and writing a clean session's derived ledger at `session/flush`; queue and coalesce dirty records, then drain pending writes during disposal.
|
|
19
|
+
- Store derived ledger records in 32 stable-hash JSON units so a session update rewrites only its shard; retain the legacy single-unit migration path.
|
|
20
|
+
- Build scoped query and fixed 53-week heatmap results from ingest-time date/workspace/model cubes; use exact BigInt decimal accumulators and a minimal heatmap projection instead of rescanning usage rows or parsing cost strings on cold reads.
|
|
21
|
+
- Isolate heatmap pointer tracking from the dashboard render path: memoize the 53-week calendar, cells, lookup maps, charts, records, and pricing dialog, while tooltip coordinates are coalesced through refs and requestAnimationFrame, with a throttled fallback for background tabs.
|
|
22
|
+
- Generate the shipped browser entry from readable `src/client.js` with pinned Terser during prepack, reducing the current raw client artifact from about 276 KB to about 177 KB; transport gzip/Brotli remains a DSH host concern.
|
|
23
|
+
|
|
24
|
+
### Correctness
|
|
25
|
+
|
|
26
|
+
- Keep the usage ledger debounce timer referenced while write waiters are pending: an unreferenced timer let the event loop settle before `persistLedgerRecord` could run, cancelling Node 22 test runs and short-lived processes.
|
|
27
|
+
- Derive the latest session sequence from the tail event instead of scanning the full session log on live flush and again while building the ledger record.
|
|
28
|
+
- Use the previous ledger cursor for safe append-only tail folding and fall back to a full rebuild when sequence continuity or turn replacement is uncertain.
|
|
29
|
+
- Wait for the persisted pricing configuration (and the ledger it backfills) before serving pricing reads and writes, so an early API call can neither report an empty config nor be silently overwritten by the load.
|
|
30
|
+
- Force a full historical rebuild when the workspace behind a session path was recreated with a different id; the previous record can no longer be reused under the wrong workspace, and ledger rows whose top-level workspace differs from their historical items are marked unusable and rebuilt once.
|
|
31
|
+
- Keep the pricing refresh classification order intact: a pricing revision change always wins over a concurrent data change so summary costs and the open settings panel cannot consume a partially-consumed baseline.
|
|
32
|
+
- Refresh the open cost-settings panel when the pricing revision changes, merging fresh catalog data while preserving unsaved local mappings and overrides.
|
|
33
|
+
- Invalidate every in-flight official-model search when a mapping row is deleted (row generation bump), so a stale response can never populate a shifted row even when per-index sequence numbers collide.
|
|
34
|
+
- Skip the pricing revision bump when a catalog sync succeeds with an unchanged catalog hash and no newly priced usage.
|
|
35
|
+
- Round hourly bucket indices against the requested range so fractional-hour zone offsets (Lord Howe) never drop or merge events, and emit real bucket boundaries as trend labels so spring-forward hours carry the true 03:00 label instead of drifting 30 minutes off.
|
|
36
|
+
- Mark mixed-workspace ledger records as unfoldable so both the scan tail path and session flush rebuild them instead of persisting historical items under the wrong workspace.
|
|
37
|
+
- Exclude the per-fetch fetchedAt stamp from the catalog content hash, so syncing identical models.dev contents keeps pricingRevision (and query caches) stable.
|
|
38
|
+
- Wait for the persisted pricing and ledger state before serving the full snapshot, so the first payload cannot embed a default empty pricing summary.
|
|
39
|
+
- Bump the official-model search row generation when the settings panel closes, so in-flight responses cannot populate a reopened panel.
|
|
40
|
+
- Require safe-integer event sequences everywhere sequences gate folding or fast-forward comparisons, so contract-external values such as Infinity cannot freeze later flushes or poison the live-event cursor.
|
|
41
|
+
- Keep the mixed-workspace upgrade flag through pricing backfills too: repairing costs must never re-enable tail folding of a record whose historical items still belong to another workspace.
|
|
42
|
+
- Invalidate in-flight official-model searches whenever the catalog is replaced (manual sync, open-panel refresh, close/reopen), not only when a mapping row is deleted.
|
|
43
|
+
- Normalize live-fallback sequences to non-negative safe integers and give positional keys to invalid events, so contract-external sequences cannot overwrite ledger turns or poison the live cursor; ledger rows with non-safe sequences are marked for rebuild.
|
|
44
|
+
- Sort the catalog by its stable key before truncating, so models.dev catalogs above the entry cap keep the same models and content hash regardless of upstream object order.
|
|
45
|
+
- Enforce the ledger sequence contract (-1 sentinel or non-negative safe integer) when loading persisted records, flag old Infinity/NaN/negative keys and sequences for rebuild, and never clear the rebuild flag during cost repacking or ledger recovery.
|
|
46
|
+
- Resolve normalized duplicate catalog entries deterministically (stable sort with conflict groups comparing full content, provider id case-normalized) so enumeration order can no longer change which price survives.
|
|
47
|
+
- Extend the ledger sequence contract to every write and read path: oversized numeric keys (past Number.MAX_SAFE_INTEGER) and unsafe numbers in usage/turn data are normalized at the entry points and flagged for rebuild; the rebuild reason is persisted so a source-read failure followed by a restart can never silently reuse a polluted record.
|
|
48
|
+
- Persist the rebuild reason for legacy-version and invalid-updated-at records too, not only sequence/workspace damage, so a source-read failure followed by restart cannot fast-path a record that was upgraded in memory.
|
|
49
|
+
- Recognise any non-canonical numeric text (floats, exponents, negatives) in old event keys as pollution, and forbid both memory and ledger tail-folding when an incremental log contains invalid sequences anywhere before the fold start.
|
|
50
|
+
- Refuse to tail-fold a flush whose log tail does not advance and whose history contains invalid sequences: the whole usage index is rebuilt from source so the in-memory aggregate and the persisted ledger cannot disagree.
|
|
51
|
+
- Detect invalid sequences on every dirty flush (not only when the tail did not advance), so a history rewrite followed by a normal appended tail also rebuilds instead of folding stale in-memory rows.
|
|
52
|
+
- Persist an invalid-flush-sequence rebuild flag on the stale ledger record before triggering the full rebuild, so a lagging persistence revision cannot fast-path the baseline back to the old data.
|
|
53
|
+
- Match Infinity/NaN pollution only as bare whole values, keeping composite keys such as Infinity-session:step:1:1 on the revision fast path.
|
|
54
|
+
- Keep the server-persisted pricing auto-sync flag as the single truth: the client stops seeding the draft from its own local UI state, so saving unrelated settings cannot revert the server value.
|
|
55
|
+
- Move in-flight official-model search state (timers, sequence guards, results) when mappings are deleted, so a stale response can no longer populate a shifted row.
|
|
56
|
+
- Restrict pricing revision bumps to cost-affecting changes: sync attempts and failed attempts no longer invalidate scoped query caches or records cursors, while the client treats pricing changes as a full snapshot refresh so summary costs stay fresh.
|
|
57
|
+
- Bucket hourly rows by the local hour boundary at the event's own offset, keeping both repeated hours of a DST fall-back day distinct.
|
|
58
|
+
- Add a CI guard that rejects a missing or untracked generated client bundle (`git ls-files --error-unmatch`) before the determinism diff.
|
|
59
|
+
- Initialized the durable ledger revision clock and reject persisted ledger records whose `updatedAt` is not finite.
|
|
60
|
+
- Require HTTP socket peers to be loopback before accepting a request, including IPv4-mapped loopback addresses.
|
|
61
|
+
- Preserve route-specific pricing mappings through the `identityKey` field, while accepting legacy `usageIdentityKey` data.
|
|
62
|
+
- Add validated context-tiered model pricing using the request input context; malformed schedules remain unsupported instead of producing a guessed estimate.
|
|
63
|
+
- Require `webServer` before Host activation so the dashboard routes cannot silently disappear when the service mounts late.
|
|
64
|
+
- Migrate legacy tiered flat cost snapshots to `unsupported`, reject timestamps outside JavaScript's TimeClip range, and exercise the real SessionStore append/flush firehose in runtime smoke tests.
|
|
65
|
+
- Require manual npm recovery dispatches to provide and verify the target release tag and full commit SHA.
|
|
66
|
+
|
|
67
|
+
### Documentation
|
|
68
|
+
|
|
69
|
+
- Documented the DSH compatibility matrix, the difference between local replayable statistics and provider billing, cache/token examples, and the fixture workflow.
|
|
70
|
+
|
|
7
71
|
## [1.1.2] - 2026-08-30
|
|
8
72
|
|
|
9
73
|
### Added
|
|
@@ -127,6 +191,8 @@ All notable changes to `dsh-all-usage` are documented here.
|
|
|
127
191
|
- Allowed same-origin browser balance GET requests that omit `Origin` while retaining token protection.
|
|
128
192
|
- Standardized English date buckets, range filters, streaks, heatmap dates, and export timestamps on UTC.
|
|
129
193
|
|
|
194
|
+
[1.1.3]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.3
|
|
195
|
+
[1.1.2]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.2
|
|
130
196
|
[1.1.0]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.1.0
|
|
131
197
|
[1.0.9]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.0.9
|
|
132
198
|
[1.0.8]: https://github.com/ParticleLight/dsh-all-usage/releases/tag/v1.0.8
|
package/README.md
CHANGED
|
@@ -21,14 +21,96 @@ DeepSeek Harness 全量用量看板:按模型、供应商、工作区和时间
|
|
|
21
21
|
- **完整历史与增量重建**:基线扫描全部可读历史会话;独立用量账本同时作为每会话游标——未变化的会话直接复用账本,新增事件只增量回填,长历史重启不再全量重建
|
|
22
22
|
- **重启免读**:用持久化日志的 revision 作为每会话的变更信号(只读头部行 + stat,不读全量)——日志未变的会话重启时连事件都不读,直接从账本复用;仅日志变化(新增/修改)的会话才做增量读取
|
|
23
23
|
- **数据健康与按需刷新**:扫描完成后浏览器只检查轻量状态版本,只有用量、别名或同步状态变化时才拉完整历史;显示本次数据更新时间、历史扫描健康、revision 免读、实际读取、账本恢复和失败,网络异常保留上次成功数据并可重试
|
|
24
|
-
- **性能优化**:Host
|
|
24
|
+
- **性能优化**:Host 在 ingest 时维护 local/UTC 的日期、工作区、模型身份日级 cube 与单日小时桶;scope 查询按 bucket 合并,成本使用精确 BigInt 小数累加,53 周热力图只生成实际需要的字段,并继续使用 revision-scoped snapshot/records 缓存和可回收的实时事件队列;Client 将热力图、tooltip、趋势、环形图、请求日志和定价对话框隔离为 memoized 边界,指针坐标通过 ref + requestAnimationFrame 更新,不再触发整页重渲染;浏览器入口在打包前确定性压缩
|
|
25
25
|
- **趋势折线图**:按当前范围、时区、工作区、供应商和模型显示输入、缓存读写、输出、推理及总处理量;单日范围按小时聚合并显示小时轴,跨日范围按日聚合;使用平滑单调曲线与入场动画,悬停查看精确值,图例可切换曲线,点击点位进入当日明细
|
|
26
26
|
- **统一筛选与审计**:工作区、供应商、模型和日期筛选贯穿摘要、热力图、趋势、表格与 CSV;工作区、供应商、模型三个筛选维度可独立自由组合,工作区、供应商和模型选项只展示当前日期范围内实际使用过的值;切换范围后失效筛选会自动清除;请求日志以紧凑分页表常驻显示,选择单条后查看分组 Token 详情
|
|
27
27
|
- **Token 口径**:输入按「未含缓存命中」计,缓存命中 / 写入与推理独立成桶;全 0 用量的重放事件不会覆盖已记录的真实用量,仅缓存命中的请求也会计入
|
|
28
28
|
- **成本口径**:模型价格来自 models.dev 的 USD / 1M Token 目录;成本快照按 DSH 已归一化的 fresh input 和四类价格桶计算,倍率只作用于最终总价,已有正成本历史不会因价格更新重算;只按模型选择官方厂商条目,未找到官方价格时显示为未计价
|
|
29
29
|
|
|
30
|
+
### 兼容性与已知限制
|
|
31
|
+
|
|
32
|
+
- **运行环境**:需要 Node.js `>=22 <25`;CI 会在 Node 22 和 Node 24 上运行测试、语法检查和 npm 包内容检查。
|
|
33
|
+
- **DSH 兼容**:`package.json` 声明 DSH runtime `>=0.1.1-rc.1 <0.1.2`,已使用 `0.1.1-rc.2` 和 `0.1.1-rc.1` 的真实 Cordis 服务链验证。
|
|
34
|
+
- **Web 服务依赖**:Host 将 `webServer` 声明为必需依赖,确保服务晚挂载时由 DSH 等待后再执行插件;该包面向 DSH Web profile,不提供无 WebServer 的 headless 路由。HTTP 守卫还会检查真实 socket peer,反向代理只有在连接本身来自 loopback 时才会被接受。
|
|
35
|
+
|
|
36
|
+
| DSH runtime | Node.js 支持 | 真实 Cordis smoke | 结论 |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| `0.1.1-rc.2` | `>=22 <25`,CI 覆盖 22/24 | 通过(当前 Node 24) | 已声明、已验证 |
|
|
39
|
+
| `0.1.1-rc.1` | `>=22 <25`,CI 覆盖 22/24 | 通过(当前 Node 24) | 已声明、已验证 |
|
|
40
|
+
| 其他版本 | `>=22 <25` | 未测试 | 不在已验证矩阵内 |
|
|
41
|
+
|
|
42
|
+
未列出的 DSH 版本不代表一定不兼容;提交问题时请附 DSH、Node.js 和插件版本。
|
|
43
|
+
|
|
44
|
+
- **中断请求**:上游请求被中断时可能只有 `assistant/chunk` 的 usage,没有最终 `assistant/message`;本插件会保留该 chunk 用量。同一 `turn / step` 后续出现最终 message 时,message 会替换 chunk。若上游完全没有 usage 事件,则无法从响应内容精确恢复 Token。
|
|
45
|
+
- **估算成本**:成本是基于 models.dev 价格和 DSH usage 桶的估算,不是供应商账单;目录不可用或模型没有官方匹配时不会猜测价格,而是显示未计价。缓存读取、缓存写入和 reasoning 的口径取决于 DSH 上游事件。
|
|
46
|
+
- **分层价格**:models.dev 的 tiered/context-dependent 价格按本次请求的输入上下文(fresh input + cache read + cache write)选择对应档位;阈值边界遵循目录定义,无法验证的异常 tier 仍显示为 unsupported。
|
|
47
|
+
- **历史边界**:只有能按 cwd 映射到已注册工作区的会话会进入统计;会话尚未成功 flush 前删除或损坏的日志无法由独立账本恢复。
|
|
48
|
+
|
|
49
|
+
### 本地统计与官方账单
|
|
50
|
+
|
|
51
|
+
本插件展示的是 DSH 本地事件日志上的可重放统计,不是供应商账单的镜像:
|
|
52
|
+
|
|
53
|
+
- 本地统计读取 DSH 的 `assistant/chunk`、最终 `assistant/message` 和其他会话事件,按同一 `turn / step` 去重和替换;官方账单可能按供应商自己的请求、分词器、舍入、折扣、免费额度和结算周期计算。
|
|
54
|
+
- 失败请求只要留下 usage chunk,就会进入本地统计;供应商是否对该失败请求收费,应以官方账单为准。
|
|
55
|
+
- 价格来自 models.dev 的公开模型目录和本地显式覆盖;目录价格、供应商实际价格、区域费率和账单折扣可能不同。成本字段应理解为估算值。
|
|
56
|
+
- 本地统计只包含能映射到已注册工作区的会话,并可能因日志损坏、清理或上游没有发出 usage 而少于官方账单。
|
|
57
|
+
|
|
58
|
+
### 可复现事件示例
|
|
59
|
+
|
|
60
|
+
下面的事件是脱敏的最小示例;完整可运行数据见 [`fixtures/usage-events.json`](fixtures/usage-events.json)。
|
|
61
|
+
|
|
62
|
+
#### 失败请求仍保留 usage chunk
|
|
63
|
+
|
|
64
|
+
~~~json
|
|
65
|
+
[
|
|
66
|
+
{"type": "assistant/chunk", "data": {"turn": 1, "step": 1, "chunk": {"type": "usage", "usage": {"inputTokens": 100, "outputTokens": 20}}}},
|
|
67
|
+
{"type": "request/error", "data": {"code": "upstream-failed"}}
|
|
68
|
+
]
|
|
69
|
+
~~~
|
|
70
|
+
|
|
71
|
+
没有最终 `assistant/message` 时,chunk 仍计为一个本地调用;这不等于官方一定收费。
|
|
72
|
+
|
|
73
|
+
#### 孤立 usage chunk
|
|
74
|
+
|
|
75
|
+
~~~json
|
|
76
|
+
{"type": "assistant/chunk", "data": {"turn": 1, "step": 1, "chunk": {"type": "usage", "usage": {"inputTokens": 7, "cacheReadTokens": 8}}}}
|
|
77
|
+
~~~
|
|
78
|
+
|
|
79
|
+
缺少 request/context 或 request/header 时,Token 仍可统计,但模型身份显示为 Unknown;插件不会从 Provider 名称或展示字符串猜测模型。
|
|
80
|
+
|
|
81
|
+
#### 缓存 Token 的四桶含义
|
|
82
|
+
|
|
83
|
+
~~~json
|
|
84
|
+
{"inputTokens": 100, "outputTokens": 20, "cacheReadTokens": 40, "cacheWriteTokens": 5, "reasoningTokens": 3}
|
|
85
|
+
~~~
|
|
86
|
+
|
|
87
|
+
本地 processed total 为 `100 + 20 + 40 + 5 + 3 = 168`;成本只对 input、output、cacheRead、cacheWrite 四个桶定价,reasoning 不会再次加到 output。
|
|
88
|
+
|
|
89
|
+
使用仓库中的 fixture 复现:
|
|
90
|
+
|
|
91
|
+
~~~bash
|
|
92
|
+
node scripts/replay-fixture.mjs fixtures/usage-events.json
|
|
93
|
+
~~~
|
|
94
|
+
|
|
95
|
+
该命令会加载真实插件 Host、调用兼容 API、校验预期 Token/records,并输出不含敏感信息的摘要。
|
|
96
|
+
|
|
97
|
+
### 报告问题
|
|
98
|
+
|
|
99
|
+
- [数据不一致 / Data inconsistency](.github/ISSUE_TEMPLATE/data-inconsistency.md)
|
|
100
|
+
- [插件启动失败 / Plugin startup failure](.github/ISSUE_TEMPLATE/startup-failure.md)
|
|
101
|
+
- [成本计算问题 / Cost calculation issue](.github/ISSUE_TEMPLATE/cost-calculation.md)
|
|
102
|
+
|
|
30
103
|
### 最近更新
|
|
31
104
|
|
|
105
|
+
**v1.1.3**
|
|
106
|
+
|
|
107
|
+
- 成本统计支持经验证的 context-tiered 官方费率、可展开费率表和显式价格覆盖
|
|
108
|
+
- durable usage ledger 支持稳定分片、dirty flush 合并、revision 快路径和安全的增量/全量重建恢复
|
|
109
|
+
- 查询、趋势和固定 53 周热力图改用写入时聚合索引,减少冷读取时的历史 usage 扫描
|
|
110
|
+
- 定价目录、价格同步、模型检索和映射编辑强化确定性与并发刷新边界
|
|
111
|
+
- 加强非法序列、旧账本、工作区重建、滞后 persistence revision 与复合账本键的恢复保护
|
|
112
|
+
- 增加 Node 22/24、DSH rc.1/rc.2 runtime smoke、脱敏 fixture replay 和包内容发布门禁
|
|
113
|
+
|
|
32
114
|
**v1.1.2**
|
|
33
115
|
|
|
34
116
|
- 模型与工作区环图及右侧列表新增 Token 数、成本和占比展示,其他分组同步合并成本
|
|
@@ -86,7 +168,7 @@ dsh plugin --profile web add github:ParticleLight/dsh-all-usage
|
|
|
86
168
|
|
|
87
169
|
### 架构
|
|
88
170
|
|
|
89
|
-
- **Host
|
|
171
|
+
- **Host 端**(入口 `lib/index.js`,组装 `lib/plugin.js`):按职责拆分为 `aggregation.js`(聚合与查询)、`ledger.js`(持久账本)、`session-sync.js`(历史/实时同步)、`pricing-runtime.js`(运行时定价)、`balance.js`(余额)、`http.js`(安全路由);扫描 `turn/end`、`assistant/chunk` usage 和最终 `assistant/message.usage`,监听 `session/event` 实时折叠,并通过 `webServer` 服务注册数据路由:
|
|
90
172
|
- `GET /api/all-usage` — 兼容统计快照
|
|
91
173
|
- `GET /api/all-usage/status` — 轻量 revision 与同步健康状态
|
|
92
174
|
- `GET /api/all-usage/query` — 按 scope 返回聚合、daily/hourly 趋势和 heatmap 数据;单日 scope 填充 `hourly`,跨日 scope 的 `hourly` 为空
|
|
@@ -95,13 +177,13 @@ dsh plugin --profile web add github:ParticleLight/dsh-all-usage
|
|
|
95
177
|
- `POST /api/all-usage/alias` — 设置工作区别名
|
|
96
178
|
- `GET /api/all-usage/pricing` — 查看 models.dev 同步状态、已用模型匹配和显式覆盖
|
|
97
179
|
- `GET /api/all-usage/pricing/models?q=...` — 检索官方模型 ID 与名称匹配结果
|
|
98
|
-
- `POST /api/all-usage/pricing` — 保存同步、mapping
|
|
180
|
+
- `POST /api/all-usage/pricing` — 保存同步、mapping 和显式价格覆盖(含 context tier 档位)
|
|
99
181
|
- `POST /api/all-usage/pricing/sync` — 手动同步 models.dev 并回填未计价调用
|
|
100
|
-
- **Client
|
|
182
|
+
- **Client 端**:可读源码位于 `src/client.js`,`npm run build:client` 使用固定版本 Terser 生成 `window.__ModuleLoader__` 工厂格式的 `lib/client.js` 浏览器 bundle,并注册侧边栏「用量统计」入口(`sidebar.footer.action` 槽位)。所有 API 仅接受本机 loopback 请求并拒绝显式跨域请求;余额读取与别名写入还要求插件启动时生成、仅在当前进程有效的令牌(余额 GET 兼容浏览器省略 Origin)。英文模式的日期分桶、范围筛选、连续使用、热力图和导出时间统一按 UTC;中文模式按本地时区。
|
|
101
183
|
|
|
102
184
|
### 数据说明
|
|
103
185
|
|
|
104
|
-
- 使用次数与 Token 来自 DSH
|
|
186
|
+
- 使用次数与 Token 来自 DSH 会话日志;`session/flush` 只在存在新的相关事件时重建并将派生账本写入异步队列,同一 session 的 pending record 会合并,插件退出时 drain;插件激活时会回填日志与账本历史,插件卸载/重启后已成功持久化的数据不丢
|
|
105
187
|
- 按日范围统计会保留全部可读取历史会话的有使用记录日期;热力图仅作为最近 53 周的固定视图窗口
|
|
106
188
|
- 会话删除后,已成功 flush 的用量仍从独立账本恢复;会话销毁提示和周期对账只负责触发重建,不会删除账本记录
|
|
107
189
|
- 同一会话的同一 `turn / step` 只保留一份最终 usage;重试或替换消息会替换旧贡献,不重复累计
|
|
@@ -110,15 +192,19 @@ dsh plugin --profile web add github:ParticleLight/dsh-all-usage
|
|
|
110
192
|
- scope query 将回合(turns)、模型调用(calls)和去重会话(sessions)分开统计;Provider/模型筛选缺少路由信息时明确归为 Unknown,不从展示字符串猜测
|
|
111
193
|
- records 接口只返回短 hash、时间、工作区 ID、结构化模型身份、turn/step、Token buckets 和当前物化来源,不返回原始 session ID、路径、提示词、回复或凭据
|
|
112
194
|
- 看板中的总处理量 = 输入 + 输出 + 缓存读写 + 推理;缓存命中表示复用的上下文 Token,不等于新生成 Token 或实际费用
|
|
113
|
-
- 成本计算沿用 cc-switch 的四桶公式:输入、输出、缓存读取和缓存写入分别乘每百万价格,四项相加后再乘倍率;DSH 的 reasoning 字段不再次加到 output,避免底层 completion/thoughts 已含推理时重复计费
|
|
114
|
-
-
|
|
195
|
+
- 成本计算沿用 cc-switch 的四桶公式:输入、输出、缓存读取和缓存写入分别乘每百万价格,四项相加后再乘倍率;context tier 在输入上下文严格大于阈值时为整次请求切换四项费率,不做渐进分段;DSH 的 reasoning 字段不再次加到 output,避免底层 completion/thoughts 已含推理时重复计费
|
|
196
|
+
- 历史账本中带 `tiered` 标志的旧 flat 成本会在加载升级时迁移为 `unsupported`(`tiered-pricing-not-modeled`),不再继续显示为当前精确 priced;Token 统计不受影响。
|
|
197
|
+
- 价格同步默认关闭;models.dev 不可用时保留最近一次成功目录,未匹配模型不会套用默认价格;成本设置可展开查看官方档位,并为显式 override 增删 context tier;看板范围与明细视图保存在浏览器本地,6 小时自动同步开关会立即写入受保护的 pricing API
|
|
198
|
+
- Mapping 语义:带 `identityKey` 的 mapping 只对精确路由身份生效;不带身份键的 mapping 才按模型做全局回退;旧配置中的 `usageIdentityKey` 会在加载时归一化。
|
|
115
199
|
- 余额查询走 DeepSeek 官方 `/user/balance` 接口;未配置 API Key 时卡片显示引导文案
|
|
200
|
+
- 账本按 session ID 稳定 hash 到 32 个 JSON shard,单次 flush 只重写对应 shard;旧的 `all_usage_ledger.json` 会在首次加载时迁移,异步写失败或退出前未落盘不会丢失内存统计,只会让下次启动重新扫描
|
|
116
201
|
- 仅统计能归属到已注册工作区(按会话 cwd 匹配)的会话
|
|
117
202
|
|
|
118
203
|
### 开发
|
|
119
204
|
|
|
120
|
-
- 修改 `
|
|
121
|
-
-
|
|
205
|
+
- 修改 `src/client.js` 后先运行 `npm run build:client`,再让 DSH 重载客户端模块并刷新页面;`lib/client.js` 是生成产物,不直接编辑。修改 `lib/plugin.js` 或其他 Host 模块后,需由 DSH 重载该包或重启进程
|
|
206
|
+
- 插件无第三方运行时依赖:Host 端只使用 Cordis 服务,Client 端只使用 runtime 提供的 React 模块;Terser 仅作为固定版本开发依赖生成浏览器产物
|
|
207
|
+
- 手动恢复 npm 发布时,GitHub Actions 要求输入目标 `v<package.version>` tag 和完整 commit SHA,并在 checkout 后校验 tag、SHA 与包版本一致;Release 事件同样执行 commit 校验。
|
|
122
208
|
|
|
123
209
|
## English
|
|
124
210
|
|
|
@@ -137,16 +223,100 @@ A full usage dashboard for DeepSeek Harness. Analyze tokens, cache behavior, est
|
|
|
137
223
|
- **Full history & incremental rebuild**: the baseline scans every readable historical session; the durable usage ledger doubles as a per-session cursor, so unchanged sessions are reused straight from the ledger and only newly appended events are folded — long histories restart without a full rebuild
|
|
138
224
|
- **Restart with no re-read**: the persisted log revision (a header-line + stat via `sessionPersistence.listSnapshots()`) acts as a per-session change signal — sessions whose log is unchanged are applied from the ledger on restart without reading their events at all; only changed/new sessions are read incrementally
|
|
139
225
|
- **Data health and on-demand refresh**: after a scan completes, the browser polls only a lightweight status revision and fetches full history only after usage, alias, or sync state changes; it shows the latest full-data update, historical scan health, revision skips, rereads, ledger recovery, and failures while preserving last-good data on network errors
|
|
140
|
-
- **Performance**: Host
|
|
226
|
+
- **Performance**: Host maintains ingest-time local/UTC day, workspace, model-identity cubes and single-day hour buckets; scope queries merge buckets, exact costs use BigInt decimal accumulators, and the 53-week heatmap emits only the fields it consumes, while revision-scoped snapshot/records caches and recyclable live-event queues remain in place. Client isolates the heatmap, tooltip, trend, donuts, request records, and pricing dialog behind memoized boundaries; pointer coordinates update through refs plus requestAnimationFrame instead of rerendering the page, and the browser entry is deterministically minified before packing
|
|
141
227
|
- **Trend line chart**: show input, cache read/write, output, reasoning, and total processed tokens for the active range, timezone, workspace, provider, and model scope; use hourly buckets for a single-day scope and daily buckets for cross-day scopes, with smooth monotone curves, staged entrance animation, hover for exact values, and click a point to inspect that day
|
|
142
228
|
- **Unified filters and audit**: workspace, provider, model, and date filters apply to the summary, heatmap, trend, tables, and CSV; workspace, provider, and model filters remain independent and can be combined freely, while workspace, provider, and model options are limited to values used in the selected date range and stale selections clear automatically; request logs stay visible as a compact paginated table with grouped Token details for the selected row
|
|
143
229
|
- **Token accounting semantics**: input tokens are fresh (exclude cache hits/writes, which sit in separate buckets along with reasoning); all-zero usage replays never overwrite recorded usage, while cache-only requests still count
|
|
144
230
|
- **Cost semantics**: prices come from the models.dev USD per 1M token catalog; DSH-normalized fresh input and the four cost buckets are snapshotted at calculation time, the multiplier applies only to final total, and existing positive historical costs are not recalculated; matching uses the model's official vendor entry and ignores the DSH provider, while missing official prices stay unpriced
|
|
145
231
|
|
|
232
|
+
### Compatibility and Known Limitations
|
|
233
|
+
|
|
234
|
+
- **Runtime**: Node.js `>=22 <25` is required. CI runs the test suite, syntax checks, and package-content checks on Node 22 and Node 24.
|
|
235
|
+
- **DSH compatibility**: `package.json` declares DSH runtime `>=0.1.1-rc.1 <0.1.2`; the real Cordis service chain is verified on `0.1.1-rc.2` and `0.1.1-rc.1`.
|
|
236
|
+
- **Web service dependency**: the Host declares `webServer` as a required dependency, so DSH waits for a late-mounted service before applying the plugin; this package targets the DSH Web profile and does not expose routes without WebServer. The HTTP guard also checks the actual socket peer, so a reverse proxy is accepted only when the connection itself is loopback.
|
|
237
|
+
|
|
238
|
+
| DSH runtime | Node.js support | Real Cordis smoke | Conclusion |
|
|
239
|
+
| --- | --- | --- | --- |
|
|
240
|
+
| `0.1.1-rc.2` | `>=22 <25`, CI covers 22/24 | Passed (current Node 24) | Declared and verified |
|
|
241
|
+
| `0.1.1-rc.1` | `>=22 <25`, CI covers 22/24 | Passed (current Node 24) | Declared and verified |
|
|
242
|
+
| Other versions | `>=22 <25` | Not tested | Outside the verified matrix |
|
|
243
|
+
|
|
244
|
+
An unlisted DSH version is not necessarily incompatible. Include the DSH, Node.js, and plugin versions when reporting an issue.
|
|
245
|
+
|
|
246
|
+
- **Interrupted requests**: an interrupted upstream request may emit only `assistant/chunk` usage and never produce a final `assistant/message`; that chunk is retained. A later final message for the same turn/step replaces it. If the upstream emits no usage event at all, exact token usage cannot be reconstructed from response text.
|
|
247
|
+
- **Estimated cost**: cost is an estimate based on models.dev rates and DSH usage buckets, not a provider invoice. Unavailable catalogs and unmatched models remain unpriced instead of receiving guessed rates. Cache reads, cache writes, and reasoning follow the buckets reported by the upstream DSH event.
|
|
248
|
+
- **Tiered prices**: models.dev context-tiered entries select the applicable rate from the request input context (fresh input plus cache read/write tokens); malformed schedules remain unsupported.
|
|
249
|
+
- **History boundary**: only sessions whose cwd maps to a registered workspace are included; data deleted or corrupted before a successful session flush cannot be recovered from the separate ledger.
|
|
250
|
+
|
|
251
|
+
### Local Statistics vs Official Billing
|
|
252
|
+
|
|
253
|
+
This plugin reports replayable statistics from local DSH event logs; it is not a mirror of a provider invoice:
|
|
254
|
+
|
|
255
|
+
- Local statistics read DSH `assistant/chunk`, final `assistant/message`, and related session events, then deduplicate and replace samples by logical `turn / step`. Official billing may use a provider tokenizer, rounding rules, discounts, free quotas, and billing periods.
|
|
256
|
+
- A failed request is included locally whenever it leaves a usage chunk; whether the provider charged for that failed request must be checked against the official bill.
|
|
257
|
+
- Prices come from the public models.dev catalog and local explicit overrides. Catalog prices can differ from provider prices, regional rates, and invoice discounts, so the cost field is an estimate.
|
|
258
|
+
- Local statistics include only sessions mapped to registered workspaces and can be lower than the official bill when logs are damaged, cleaned up, or the upstream emits no usage event.
|
|
259
|
+
|
|
260
|
+
### Reproducible Event Examples
|
|
261
|
+
|
|
262
|
+
The following are redacted minimal examples; the complete runnable data is in [`fixtures/usage-events.json`](fixtures/usage-events.json).
|
|
263
|
+
|
|
264
|
+
#### Retaining a failed request chunk
|
|
265
|
+
|
|
266
|
+
~~~json
|
|
267
|
+
[
|
|
268
|
+
{"type": "assistant/chunk", "data": {"turn": 1, "step": 1, "chunk": {"type": "usage", "usage": {"inputTokens": 100, "outputTokens": 20}}}},
|
|
269
|
+
{"type": "request/error", "data": {"code": "upstream-failed"}}
|
|
270
|
+
]
|
|
271
|
+
~~~
|
|
272
|
+
|
|
273
|
+
Without a final `assistant/message`, the chunk remains one local call; this does not mean the provider necessarily charged for it.
|
|
274
|
+
|
|
275
|
+
#### Orphan usage chunk
|
|
276
|
+
|
|
277
|
+
~~~json
|
|
278
|
+
{"type": "assistant/chunk", "data": {"turn": 1, "step": 1, "chunk": {"type": "usage", "usage": {"inputTokens": 7, "cacheReadTokens": 8}}}}
|
|
279
|
+
~~~
|
|
280
|
+
|
|
281
|
+
Without request/context or request/header, tokens are still counted, but the model identity is shown as Unknown; the plugin does not guess a model from a provider name or display string.
|
|
282
|
+
|
|
283
|
+
#### Cache token buckets
|
|
284
|
+
|
|
285
|
+
~~~json
|
|
286
|
+
{"inputTokens": 100, "outputTokens": 20, "cacheReadTokens": 40, "cacheWriteTokens": 5, "reasoningTokens": 3}
|
|
287
|
+
~~~
|
|
288
|
+
|
|
289
|
+
The local processed total is `100 + 20 + 40 + 5 + 3 = 168`; cost uses the input, output, cacheRead, and cacheWrite buckets, and reasoning is not added to output again.
|
|
290
|
+
|
|
291
|
+
Replay the repository fixture:
|
|
292
|
+
|
|
293
|
+
~~~bash
|
|
294
|
+
node scripts/replay-fixture.mjs fixtures/usage-events.json
|
|
295
|
+
~~~
|
|
296
|
+
|
|
297
|
+
The command loads the real plugin Host, calls its compatible APIs, checks the documented token/record totals, and prints a non-sensitive summary.
|
|
298
|
+
|
|
299
|
+
### Report An Issue
|
|
300
|
+
|
|
301
|
+
- [Data inconsistency / 数据不一致](.github/ISSUE_TEMPLATE/data-inconsistency.md)
|
|
302
|
+
- [Plugin startup failure / 插件启动失败](.github/ISSUE_TEMPLATE/startup-failure.md)
|
|
303
|
+
- [Cost calculation issue / 成本计算问题](.github/ISSUE_TEMPLATE/cost-calculation.md)
|
|
304
|
+
|
|
146
305
|
### Latest Update
|
|
147
306
|
|
|
148
|
-
**v1.1.
|
|
307
|
+
**v1.1.3**
|
|
308
|
+
|
|
309
|
+
- Added validated context-tiered official pricing, expandable rate schedules, and explicit price overrides
|
|
310
|
+
- Reworked the durable usage ledger with stable shards, dirty-flush coalescing, revision reuse, and safe incremental/full recovery
|
|
311
|
+
- Built scoped queries, trends, and the fixed 53-week heatmap from ingest-time aggregates to reduce cold historical scans
|
|
312
|
+
- Hardened deterministic pricing catalogs, pricing sync, official-model search, and mapping refresh races
|
|
313
|
+
- Strengthened recovery for invalid sequences, legacy ledgers, recreated workspaces, lagging persistence revisions, and composite ledger keys
|
|
314
|
+
- Added Node 22/24, DSH rc.1/rc.2 runtime smoke, redacted fixture replay, and package-content release gates
|
|
315
|
+
|
|
316
|
+
**v1.1.2**
|
|
149
317
|
|
|
318
|
+
- Official models.dev pricing, cache/reasoning token buckets, and persisted pricing configuration
|
|
319
|
+
- Assistant chunk usage is retained and replaced by the final message for the same turn/step
|
|
150
320
|
- Structured model identity with backward-compatible ledger v2 migration
|
|
151
321
|
- Unified scope queries for time, timezone, workspace, provider, and model filters
|
|
152
322
|
- Token trend line chart with hourly single-day data, selectable series, exact hover values, and point-to-audit drill-down
|
|
@@ -187,7 +357,7 @@ The profile patch layer hot-reloads; save the file and refresh the page.
|
|
|
187
357
|
|
|
188
358
|
### Architecture
|
|
189
359
|
|
|
190
|
-
- **Host** (`lib/index.js`):
|
|
360
|
+
- **Host** (entry `lib/index.js`, assembled by `lib/plugin.js`): split by responsibility across `aggregation.js` (aggregation/query), `ledger.js` (durable ledger), `session-sync.js` (history/live sync), `pricing-runtime.js` (runtime pricing), `balance.js` (balance), and `http.js` (protected routes); aggregates `turn/end`, `assistant/chunk` usage, and final `assistant/message.usage`, folds live `session/event` updates, and exposes data routes through `webServer`:
|
|
191
361
|
- `GET /api/all-usage` — compatible usage snapshot
|
|
192
362
|
- `GET /api/all-usage/status` — lightweight revision and sync health
|
|
193
363
|
- `GET /api/all-usage/query` — scoped aggregate, daily/hourly trend, and heatmap data; single-day scopes populate `hourly`, while cross-day scopes return an empty `hourly` array
|
|
@@ -196,13 +366,13 @@ The profile patch layer hot-reloads; save the file and refresh the page.
|
|
|
196
366
|
- `POST /api/all-usage/alias` — update workspace aliases
|
|
197
367
|
- `GET /api/all-usage/pricing` — inspect models.dev sync status, used-model matches, and explicit overrides
|
|
198
368
|
- `GET /api/all-usage/pricing/models?q=...` — search official model IDs and display-name matches
|
|
199
|
-
- `POST /api/all-usage/pricing` — save sync, mappings, and explicit price overrides
|
|
369
|
+
- `POST /api/all-usage/pricing` — save sync, mappings, and explicit price overrides, including context-tier bands
|
|
200
370
|
- `POST /api/all-usage/pricing/sync` — sync models.dev and backfill unpriced calls
|
|
201
|
-
- **Client
|
|
371
|
+
- **Client**: readable source lives in `src/client.js`; `npm run build:client` uses the pinned Terser version to generate the `window.__ModuleLoader__` bundle at `lib/client.js`, which registers the “Usage statistics” sidebar entry through the `sidebar.footer.action` slot. All API routes accept loopback requests and reject an explicit cross-origin Origin; balance reads and alias writes also require a process-scoped token generated when the plugin starts (the balance GET tolerates browsers omitting Origin).
|
|
202
372
|
|
|
203
373
|
### Data semantics
|
|
204
374
|
|
|
205
|
-
- Calls and tokens come from DSH session logs and
|
|
375
|
+
- Calls and tokens come from DSH session logs; `session/flush` rebuilds and queues the derived ledger only when related events are dirty, coalescing the latest pending record per session and draining on plugin disposal. Readable logs and ledger history are backfilled when the plugin activates, so successfully persisted data survives reloads or session deletion
|
|
206
376
|
- Day-level range data retains every readable historical session date with tracked usage; the heatmap is only a fixed latest-53-week view
|
|
207
377
|
- After a session is deleted, successfully flushed usage is restored from the separate ledger; disposal hints and periodic reconciliation trigger rebuilds without deleting ledger rows
|
|
208
378
|
- For each session and logical `turn / step`, only the final usage contribution is kept; retries or replaced messages do not double-count
|
|
@@ -211,16 +381,20 @@ The profile patch layer hot-reloads; save the file and refresh the page.
|
|
|
211
381
|
- Scoped results keep turns, model calls, and distinct sessions as separate metrics; missing route identity is explicitly Unknown rather than inferred from a display label
|
|
212
382
|
- The records endpoint returns only a short hash, time, workspace ID, structured model identity, turn/step, token buckets, and current materialization source. It omits raw session IDs, paths, prompts, replies, and credentials
|
|
213
383
|
- Processed tokens = input + output + cache read/write + reasoning; a cache hit means reused context, not newly generated tokens or actual cost
|
|
214
|
-
- Cost follows the cc-switch four-bucket formula: input, output, cache-read, and cache-write tokens are priced independently, summed, then multiplied by the final multiplier; DSH reasoning is not added to output a second time
|
|
215
|
-
-
|
|
384
|
+
- Cost follows the cc-switch four-bucket formula: input, output, cache-read, and cache-write tokens are priced independently, summed, then multiplied by the final multiplier; when input context is strictly greater than a context-tier threshold, all four rates switch for the whole request instead of progressive band splitting, and DSH reasoning is not added to output a second time
|
|
385
|
+
- Legacy ledger costs carrying `tiered` are migrated to `unsupported` (`tiered-pricing-not-modeled`) on load instead of remaining falsely marked as current flat priced estimates; token statistics are unchanged.
|
|
386
|
+
- Pricing sync is off by default; when models.dev is unavailable the last good catalog remains in use, and unmatched models never receive a guessed default price; Cost Statistics can expand official tier schedules and add or remove context tiers on explicit overrides; dashboard range and detail-view preferences are stored in browser storage, while the 6-hour sync toggle is immediately saved through the protected pricing API
|
|
387
|
+
- Mapping semantics: a mapping with `identityKey` applies only to that exact route identity; a mapping without an identity key is the model-wide fallback. Legacy `usageIdentityKey` values are normalized when loaded.
|
|
216
388
|
- Balance data comes from DeepSeek’s official `/user/balance` endpoint; the card shows guidance when no API key is configured
|
|
217
389
|
- English mode uses UTC for date buckets, range filters, streaks, heatmap dates, and export timestamps; Chinese mode uses local time
|
|
390
|
+
- The ledger assigns each session ID to one of 32 stable-hash JSON shards, so a flush rewrites only its shard; the old `all_usage_ledger.json` is migrated on first load. An async write failure or an unflushed shutdown does not lose in-memory statistics; the next startup simply scans that session again
|
|
218
391
|
- Only sessions that can be mapped to a registered workspace by their working directory are included
|
|
219
392
|
|
|
220
393
|
### Development
|
|
221
394
|
|
|
222
|
-
- After editing `
|
|
223
|
-
- The plugin has no third-party
|
|
395
|
+
- After editing `src/client.js`, run `npm run build:client`, reload the DSH client module, and refresh the page; `lib/client.js` is generated and should not be edited directly. After editing `lib/plugin.js` or another Host module, reload the package through DSH or restart the process
|
|
396
|
+
- The plugin has no third-party runtime dependencies: the Host uses Cordis services and the Client uses the runtime-provided React module; pinned Terser is only a development dependency for generating the browser artifact
|
|
397
|
+
- Manual npm recovery publishes require a target `v<package.version>` tag and full commit SHA; GitHub Actions checks both against the checked-out tag and package version. Release events perform the same commit check.
|
|
224
398
|
|
|
225
399
|
## License / 许可证
|
|
226
400
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "redacted-usage-fixture",
|
|
4
|
+
"description": "Synthetic DSH session events covering a failed request, an orphan usage chunk, and a chunk replaced by a final message.",
|
|
5
|
+
"timezone": "UTC",
|
|
6
|
+
"query": { "start": "2024-01-01", "end": "2024-01-01", "utc": "1" },
|
|
7
|
+
"workspaces": [
|
|
8
|
+
{
|
|
9
|
+
"id": "workspace-example",
|
|
10
|
+
"path": "/redacted/example-workspace",
|
|
11
|
+
"title": "Example Workspace"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"sessions": [
|
|
15
|
+
{ "header": { "id": "session-failed", "cwd": "/redacted/example-workspace" } },
|
|
16
|
+
{ "header": { "id": "session-complete", "cwd": "/redacted/example-workspace" } },
|
|
17
|
+
{ "header": { "id": "session-orphan", "cwd": "/redacted/example-workspace" } }
|
|
18
|
+
],
|
|
19
|
+
"events": {
|
|
20
|
+
"session-failed": [
|
|
21
|
+
{
|
|
22
|
+
"seq": 1,
|
|
23
|
+
"time": 1704110400000,
|
|
24
|
+
"type": "request/context",
|
|
25
|
+
"data": { "provider": "deepseek", "model": "deepseek-chat" }
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"seq": 2,
|
|
29
|
+
"time": 1704110400000,
|
|
30
|
+
"type": "assistant/chunk",
|
|
31
|
+
"data": {
|
|
32
|
+
"turn": 1,
|
|
33
|
+
"step": 1,
|
|
34
|
+
"chunk": {
|
|
35
|
+
"type": "usage",
|
|
36
|
+
"usage": {
|
|
37
|
+
"inputTokens": 100,
|
|
38
|
+
"outputTokens": 20,
|
|
39
|
+
"cacheReadTokens": 50,
|
|
40
|
+
"cacheWriteTokens": 5,
|
|
41
|
+
"reasoningTokens": 7
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"seq": 3,
|
|
48
|
+
"time": 1704110400000,
|
|
49
|
+
"type": "request/error",
|
|
50
|
+
"data": { "code": "upstream-failed" }
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"session-complete": [
|
|
54
|
+
{
|
|
55
|
+
"seq": 1,
|
|
56
|
+
"time": 1704110400000,
|
|
57
|
+
"type": "request/context",
|
|
58
|
+
"data": { "provider": "deepseek", "model": "deepseek-chat" }
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"seq": 2,
|
|
62
|
+
"time": 1704110400000,
|
|
63
|
+
"type": "assistant/chunk",
|
|
64
|
+
"data": {
|
|
65
|
+
"turn": 1,
|
|
66
|
+
"step": 1,
|
|
67
|
+
"chunk": {
|
|
68
|
+
"type": "usage",
|
|
69
|
+
"usage": {
|
|
70
|
+
"inputTokens": 10,
|
|
71
|
+
"outputTokens": 15,
|
|
72
|
+
"cacheReadTokens": 3,
|
|
73
|
+
"cacheWriteTokens": 2,
|
|
74
|
+
"reasoningTokens": 1
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"seq": 3,
|
|
81
|
+
"time": 1704110400000,
|
|
82
|
+
"type": "assistant/message",
|
|
83
|
+
"data": {
|
|
84
|
+
"turn": 1,
|
|
85
|
+
"step": 1,
|
|
86
|
+
"message": { "source": { "provider": "deepseek", "model": "deepseek-chat" } },
|
|
87
|
+
"usage": {
|
|
88
|
+
"inputTokens": 12,
|
|
89
|
+
"outputTokens": 18,
|
|
90
|
+
"cacheReadTokens": 4,
|
|
91
|
+
"cacheWriteTokens": 2,
|
|
92
|
+
"reasoningTokens": 2
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"seq": 4,
|
|
98
|
+
"time": 1704110400000,
|
|
99
|
+
"type": "turn/end",
|
|
100
|
+
"data": { "turn": 1, "reason": { "kind": "completed" } }
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"session-orphan": [
|
|
104
|
+
{
|
|
105
|
+
"seq": 1,
|
|
106
|
+
"time": 1704110400000,
|
|
107
|
+
"type": "assistant/chunk",
|
|
108
|
+
"data": {
|
|
109
|
+
"turn": 1,
|
|
110
|
+
"step": 1,
|
|
111
|
+
"chunk": {
|
|
112
|
+
"type": "usage",
|
|
113
|
+
"usage": {
|
|
114
|
+
"inputTokens": 7,
|
|
115
|
+
"outputTokens": 4,
|
|
116
|
+
"cacheReadTokens": 8,
|
|
117
|
+
"cacheWriteTokens": 1,
|
|
118
|
+
"reasoningTokens": 0
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"expected": {
|
|
126
|
+
"totals": {
|
|
127
|
+
"turns": 1,
|
|
128
|
+
"sessions": 3,
|
|
129
|
+
"input": 119,
|
|
130
|
+
"output": 42,
|
|
131
|
+
"cacheRead": 62,
|
|
132
|
+
"cacheWrite": 8,
|
|
133
|
+
"reasoning": 9
|
|
134
|
+
},
|
|
135
|
+
"records": 3,
|
|
136
|
+
"models": [
|
|
137
|
+
{
|
|
138
|
+
"provider": "deepseek",
|
|
139
|
+
"requestedModel": "deepseek-chat",
|
|
140
|
+
"actualModel": null,
|
|
141
|
+
"calls": 1,
|
|
142
|
+
"input": 100,
|
|
143
|
+
"output": 20,
|
|
144
|
+
"cacheRead": 50,
|
|
145
|
+
"cacheWrite": 5,
|
|
146
|
+
"reasoning": 7
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"provider": "deepseek",
|
|
150
|
+
"requestedModel": "deepseek-chat",
|
|
151
|
+
"actualModel": "deepseek-chat",
|
|
152
|
+
"calls": 1,
|
|
153
|
+
"input": 12,
|
|
154
|
+
"output": 18,
|
|
155
|
+
"cacheRead": 4,
|
|
156
|
+
"cacheWrite": 2,
|
|
157
|
+
"reasoning": 2
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"provider": null,
|
|
161
|
+
"requestedModel": null,
|
|
162
|
+
"actualModel": null,
|
|
163
|
+
"calls": 1,
|
|
164
|
+
"input": 7,
|
|
165
|
+
"output": 4,
|
|
166
|
+
"cacheRead": 8,
|
|
167
|
+
"cacheWrite": 1,
|
|
168
|
+
"reasoning": 0
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
}
|