dsh-token-total 0.0.0-stage → 1.0.0
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/LICENSE +22 -0
- package/README.md +109 -2
- package/cordis.patch.yml +24 -0
- package/icon.svg +38 -0
- package/lib/client.js +32103 -0
- package/lib/index.js +1857 -0
- package/lib/types/client/ChartTip.d.ts +27 -0
- package/lib/types/client/Donut.d.ts +92 -0
- package/lib/types/client/StatsLineEnhanced.d.ts +60 -0
- package/lib/types/client/TokenTotalPanel.d.ts +40 -0
- package/lib/types/client/api.d.ts +31 -0
- package/lib/types/client/format.d.ts +47 -0
- package/lib/types/client/glass.d.ts +91 -0
- package/lib/types/client/index.d.ts +55 -0
- package/lib/types/client/locales.d.ts +13 -0
- package/lib/types/client/stat-dialog.d.ts +39 -0
- package/lib/types/client/stats-icon.d.ts +12 -0
- package/lib/types/client/stats-line-core.d.ts +226 -0
- package/lib/types/client/use-session-usage.d.ts +24 -0
- package/lib/types/collector.d.ts +208 -0
- package/lib/types/context-types.d.ts +311 -0
- package/lib/types/index.d.ts +31 -0
- package/lib/types/model-names.d.ts +7 -0
- package/lib/types/query.d.ts +54 -0
- package/lib/types/routes.d.ts +58 -0
- package/lib/types/session-usage.d.ts +43 -0
- package/lib/types/shared.d.ts +25 -0
- package/lib/types/store.d.ts +216 -0
- package/lib/types/trust-fence.d.ts +59 -0
- package/lib/types/wire.d.ts +120 -0
- package/locale/en.json +6 -0
- package/locale/zh-TW.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +153 -3
- package/src/client/ChartTip.tsx +105 -0
- package/src/client/Donut.tsx +182 -0
- package/src/client/StatsLineEnhanced.module.css +203 -0
- package/src/client/StatsLineEnhanced.tsx +599 -0
- package/src/client/TokenTotalPanel.module.css +772 -0
- package/src/client/TokenTotalPanel.tsx +825 -0
- package/src/client/api.ts +75 -0
- package/src/client/format.ts +124 -0
- package/src/client/glass.ts +125 -0
- package/src/client/index.tsx +306 -0
- package/src/client/locales.ts +285 -0
- package/src/client/stat-dialog.ts +81 -0
- package/src/client/stats-icon.tsx +37 -0
- package/src/client/stats-line-core.ts +571 -0
- package/src/client/use-session-usage.ts +115 -0
- package/src/collector.ts +787 -0
- package/src/context-types.ts +318 -0
- package/src/css-modules.d.ts +4 -0
- package/src/index.ts +238 -0
- package/src/model-names.ts +81 -0
- package/src/query.ts +265 -0
- package/src/routes.ts +245 -0
- package/src/session-usage.ts +221 -0
- package/src/shared.ts +64 -0
- package/src/store.ts +606 -0
- package/src/trust-fence.ts +195 -0
- package/src/wire.ts +175 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HaoyueQin (dsh-usage-statistics-panel, the upstream project this plugin derives from)
|
|
4
|
+
Copyright (c) 2026 GaoHu1997 (dsh-token-total modifications and additions)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,110 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-token-total
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
DSH(DeepSeek Harness)Web 插件:**Token 用量统计看板** + **单会话用量(含子智能体)**。
|
|
4
|
+
|
|
5
|
+
两件事,一个插件:
|
|
6
|
+
|
|
7
|
+
1. **统计看板** — 侧边栏插件区下方的入口,点开是完整的用量看板(快捷筛选 / 六卡片 / 活跃热力图 / 缓存命中率趋势 + 分模型柱状图 / 按模型与按供应商 Top5)。
|
|
8
|
+
2. **单会话统计** — 增强会话输入框下方的原生信息栏,把「Token 用量」从「只有主智能体」改成「主智能体 + 全部子智能体」,让一次会话的真实消耗有地方可看。
|
|
9
|
+
|
|
10
|
+
所有图表都是手写 SVG,不依赖任何图表库;配色走 DSH 主题变量,自动适配明暗主题。
|
|
11
|
+
|
|
12
|
+
## 功能
|
|
13
|
+
|
|
14
|
+
### 统计看板
|
|
15
|
+
|
|
16
|
+
入口在左侧边栏的插件区(与原生「插件」页并列的独立页面),点开即为看板,分上中下三部分。
|
|
17
|
+
|
|
18
|
+
#### 上部
|
|
19
|
+
|
|
20
|
+
- **快捷筛选**:今日 / 近 3 天 / 近 7 天 / 近 1 月 / 近 3 月 / 自定义(起止日期)。
|
|
21
|
+
- **一行六个卡片**:总 Tokens、输入 Tokens、输出 Tokens、缓存 Tokens、缓存命中率、请求数量。
|
|
22
|
+
Token 数量用 **K / M / B** 紧凑单位显示主值,下方一行给出精确数字。
|
|
23
|
+
- **活跃热力图**:GitHub 风格,格子颜色深浅表示当天 token 消耗的多少;图例「较少 → 较多」五档。
|
|
24
|
+
- 右上角保留 **刷新**(只重取聚合结果),不再提供重建统计按钮。
|
|
25
|
+
|
|
26
|
+
#### 中部
|
|
27
|
+
|
|
28
|
+
- **缓存命中率趋势**:一条平滑折线(Catmull-Rom 转贝塞尔)。
|
|
29
|
+
- **分模型柱状图**:堆叠柱表示实际 token 消耗,不同模型不同颜色;右轴为 0–100% 缓存命中率。
|
|
30
|
+
- **不显示图例**:鼠标悬浮时 tooltip 逐项列出该时间桶内各模型的 token 与命中率。
|
|
31
|
+
- **横轴粒度**:今日 / 近 3 天按**小时**分桶,更长的区间按**天**分桶。
|
|
32
|
+
|
|
33
|
+
#### 下部
|
|
34
|
+
|
|
35
|
+
- **按模型**:按模型选择器的**显示名称**(不是路由 id)跨供应商聚合,取前 5,展示模型名、总 Tokens、缓存命中率(跨多个供应商时附供应商列表)。排行与趋势使用同一归一化规则:忽略大小写,将空格、下划线和连字符统一为 `-`,例如 `gpt-6.1-sol`、`GPT 6.1 sol`、`gpt 6.1 sol` 合并为 `gpt-6.1-sol`;版本号和后缀仍区分,避免误合并不同模型。无法读取历史路由的模型元数据时,回退到历史引用中的模型名称;不改写原始记录,不需要重建统计。
|
|
36
|
+
- **按供应商**:一个供应商下所有模型聚合,取前 5,展示供应商名、总 Tokens、缓存命中率。
|
|
37
|
+
|
|
38
|
+
### 单会话统计
|
|
39
|
+
|
|
40
|
+
会话输入框下方原生的「用时与速度 / Token 用量」两枚胶囊被接管并增强:
|
|
41
|
+
|
|
42
|
+
- **Token 胶囊**显示的是**整棵会话树**(主智能体 + 全部子智能体)的合计,点开弹窗分为「主智能体 / 子智能体 / 会话合计」三行,并给出子智能体会话数。
|
|
43
|
+
- 子智能体是独立持久化的会话,通过日志头的 `parentSession` 串成树;插件按需重放这些日志汇总(同一套 `(turn, step)` 去重规则,且跳过 fork 继承来的事件前缀,避免与父会话重复计数)。
|
|
44
|
+
- **会话 Token 明细始终开启**:未命中缓存、缓存读 / 写、输出分别列出;底部胶囊的缓存命中率始终显示两位小数。
|
|
45
|
+
- **流式吞吐速度始终开启**:输出过程中显示估算的解码速度;暂无有效样本或输出结束后,回到会话累计的精确值。
|
|
46
|
+
- 不再提供底部增强功能的开关;旧版本保存的关闭设置不再影响显示。
|
|
47
|
+
|
|
48
|
+
## 安装
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
dsh plugin --profile <profile> add dsh-token-total@latest
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
本地开发时直接指向目录:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
dsh plugin --profile <profile> add "file:D:\work\dsh-token-total"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`package.json` 里的 `dsh.bundle.patch` 会让 CLI 在安装后把本插件追加进该 profile 的 `dsh.profile.bundles`,重启后自动挂载,无需手改 profile 配置。若该 profile 的 `cordis.patch.yml` 里还留着旧的手工挂载行,请先删掉,否则会重复挂载(两个宿主实例、两条重复路由)。
|
|
61
|
+
|
|
62
|
+
> Electron 桌面端的 `desktop` profile 由应用独占管理,CLI 会拒绝写入(`profile "desktop" is managed exclusively by the Electron application`)。请用应用内的插件管理器安装,或另建一个 profile 验证。
|
|
63
|
+
|
|
64
|
+
## 数据来源与统计口径
|
|
65
|
+
|
|
66
|
+
- **事件来源**:`sessionPersistence` 的会话日志(`assistant/message` 的 `usage`)。插件订阅 `session/event` 实时增量累加,同时一次性回扫已有历史会话;`llm/retry-started` 会清空当前 `(turn, step)` 槽位,所以重试不会漏计也不会重复计。
|
|
67
|
+
- **本地持久化**:聚合结果写入 storage-domain 的 `token_total_history` 域(`$DSH_HOME/storages/` 下),纯本地、无外部依赖。回扫游标按会话记录已消费的事件序号,重启后从断点继续。
|
|
68
|
+
- **单会话统计**:不走聚合存储(那里没有会话维度),而是按需读该会话及其所有子孙会话的日志重放求和,结果短暂缓存,并在该会话树任一成员产生新事件时精确失效。
|
|
69
|
+
- **缓存命中率** = 缓存命中 token ÷ 输入 token 总量(命中 + 未命中)。
|
|
70
|
+
|
|
71
|
+
## HTTP 接口
|
|
72
|
+
|
|
73
|
+
宿主侧注册一个前缀路由 `/token-total/api`,全部为 `POST` + JSON:
|
|
74
|
+
|
|
75
|
+
| 路径 | 作用 |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `/token-total/api/range` | 取某个时间范围的聚合(`{range, from?, to?}`) |
|
|
78
|
+
| `/token-total/api/session` | 取某会话树的用量(`{sessionId}`,返回 `self` / `subagents` / `total` / `subagentSessions`) |
|
|
79
|
+
| `/token-total/api/status` | 回扫进度 |
|
|
80
|
+
| `/token-total/api/reset` | 清空统计并重新回扫 |
|
|
81
|
+
|
|
82
|
+
请求经过与官方 `/api` 网关同源的信任栅栏(Host / Origin / `sec-fetch-site` 三重校验,防 DNS rebinding)。
|
|
83
|
+
|
|
84
|
+
## 配置
|
|
85
|
+
|
|
86
|
+
| 键 | 默认 | 说明 |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| `source` | `session-log` | 统计来源 |
|
|
89
|
+
| `backfillConcurrency` | `4` | 历史回扫的并发会话数 |
|
|
90
|
+
|
|
91
|
+
## 兼容性
|
|
92
|
+
|
|
93
|
+
- DSH `>= 0.1.7-rc.1`(`peerDependencies`);实测运行于 `0.2.1-rc.2`,会话日志格式 v3 与 v4 均可读取(v3 走 alpha 的 `open/read` 接口,v4 走句柄分页读取)。
|
|
94
|
+
- 浏览器半区只依赖 `@deepseek-ai/dsh-client-{locale,ui-slots,ui-primitives}` 与 React 18,不打入任何 Node 内置模块。
|
|
95
|
+
|
|
96
|
+
## 开发
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
pnpm install
|
|
100
|
+
pnpm run build # tsc 声明 + 宿主/浏览器两个 bundle
|
|
101
|
+
pnpm run typecheck # 宿主半区
|
|
102
|
+
pnpm run typecheck:client
|
|
103
|
+
pnpm test # 模型显示名称聚合、趋势、底部偏好回归测试
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
产物:`lib/index.js`(宿主,ESM)、`lib/client.js`(浏览器,CJS 包装进 `__ModuleLoader__.load`)、`lib/types/**/*.d.ts`。CSS Modules 在构建时被内联成 `<style data-plugin-css>` 注入,因此 Web 外壳不需要 CSS 管线。
|
|
107
|
+
|
|
108
|
+
## 许可
|
|
109
|
+
|
|
110
|
+
MIT。本项目的宿主与浏览器实现改编自 [dsh-usage-statistics-panel](https://github.com/HaoyueQin/dsh-usage-statistics-panel)(MIT, Copyright (c) 2026 HaoyueQin),在其基础上按本项目的需求重做了卡片、筛选、图表与列表,并新增了整棵会话树(含子智能体)的用量统计。原始版权声明保留在 [LICENSE](./LICENSE) 中。
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# dsh-token-total bundle patch
|
|
2
|
+
#
|
|
3
|
+
# This file is the `dsh.bundle.patch` layer of the published npm package: when
|
|
4
|
+
# the plugin is installed through the official CLI --
|
|
5
|
+
# dsh plugin --profile <name> add dsh-token-total@<version>
|
|
6
|
+
# -- the command reconciles `dsh.profile.bundles` against installed packages
|
|
7
|
+
# and, seeing this declaration, appends `dsh-token-total` to the bundle stack.
|
|
8
|
+
# The profile boot then merges THIS patch (a single `insert` of the plugin row)
|
|
9
|
+
# exactly like a manual cordis.patch.yml mount line. No profile file edits are
|
|
10
|
+
# needed -- one command installs and mounts.
|
|
11
|
+
#
|
|
12
|
+
# If the profile still carries an old manual mount line in its own
|
|
13
|
+
# cordis.patch.yml, remove it before switching to the bundle channel to avoid
|
|
14
|
+
# double-mounting (two host halves, two duplicate route registrations).
|
|
15
|
+
#
|
|
16
|
+
# Aggregate double-mount guard: aggregate bundles may already mount this
|
|
17
|
+
# package under their own entry id. Two mounts register /token-total/api twice
|
|
18
|
+
# and fail the whole plugin tree at boot ("duplicate prefix route"). The `!!js`
|
|
19
|
+
# disabled expression backs THIS row off when another *enabled* entry already
|
|
20
|
+
# mounts `dsh-token-total`; the aggregate instance then owns the panel.
|
|
21
|
+
- insert:
|
|
22
|
+
- id: token-total
|
|
23
|
+
name: 'dsh-token-total'
|
|
24
|
+
disabled: !!js "[...ctx.loader.entries()].some((e) => e.options.name === 'dsh-token-total' && e.options.id !== 'token-total' && !e.disabled)"
|
package/icon.svg
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36">
|
|
2
|
+
<!-- Card icon read by app-boot's readPluginMeta() from package.json "icon".
|
|
3
|
+
Composition follows the bar-chart brand marks collected in
|
|
4
|
+
glincker/thesvg (chunky rounded bars near the frame's full height, one
|
|
5
|
+
colour each, no axis line — cf. chartdotjs, mixpanel); no brand's
|
|
6
|
+
artwork is copied, only that composition. What this panel adds is its
|
|
7
|
+
own two signatures: the stacked token bars and the cache hit-rate trend
|
|
8
|
+
line drawn over them as a two-bend polyline, closed by an end dot. The
|
|
9
|
+
line is a polyline, not a smooth curve, on purpose: on this 36px canvas
|
|
10
|
+
the old three-segment bezier's wiggles were only a pixel or two tall, so
|
|
11
|
+
they read as meaningless bends; two bends keep the rising trend without
|
|
12
|
+
inventing detail (issue #12). The three hues are the hexes the project's
|
|
13
|
+
banner uses for its first three chart colours, so the icon matches the
|
|
14
|
+
donuts and lists it opens. Bars carry a per-hue vertical
|
|
15
|
+
gradient for depth; the ink is centred on its bounding box.
|
|
16
|
+
Transparent background on purpose: the Plugins page draws its own 48px
|
|
17
|
+
(card) / 40px (row) hairline frame, so a filled tile would double it.
|
|
18
|
+
Read in an <img> context: no foreignObject, scripts or external refs. -->
|
|
19
|
+
<defs>
|
|
20
|
+
<linearGradient id="usageStatsBlue" x1="18" y1="9" x2="18" y2="29" gradientUnits="userSpaceOnUse">
|
|
21
|
+
<stop offset="0" stop-color="#7CBBFF" />
|
|
22
|
+
<stop offset="1" stop-color="#2F7FE0" />
|
|
23
|
+
</linearGradient>
|
|
24
|
+
<linearGradient id="usageStatsGreen" x1="18" y1="9" x2="18" y2="29" gradientUnits="userSpaceOnUse">
|
|
25
|
+
<stop offset="0" stop-color="#9BC49F" />
|
|
26
|
+
<stop offset="1" stop-color="#46734C" />
|
|
27
|
+
</linearGradient>
|
|
28
|
+
<linearGradient id="usageStatsOrange" x1="18" y1="9" x2="18" y2="29" gradientUnits="userSpaceOnUse">
|
|
29
|
+
<stop offset="0" stop-color="#F0B57F" />
|
|
30
|
+
<stop offset="1" stop-color="#AC6835" />
|
|
31
|
+
</linearGradient>
|
|
32
|
+
</defs>
|
|
33
|
+
<path d="M4.3 17.6L12.5 14L21.3 10.8L29.5 9" fill="none" stroke="#4D6BFE" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" />
|
|
34
|
+
<circle cx="29.5" cy="9" r="2.1" fill="#4D6BFE" />
|
|
35
|
+
<rect x="5.7" y="18.8" width="5.6" height="10.2" rx="2.8" fill="url(#usageStatsBlue)" />
|
|
36
|
+
<rect x="14.3" y="13" width="5.6" height="16" rx="2.8" fill="url(#usageStatsGreen)" />
|
|
37
|
+
<rect x="22.9" y="16" width="5.6" height="13" rx="2.8" fill="url(#usageStatsOrange)" />
|
|
38
|
+
</svg>
|