dsh-plugin-usage 0.2.2 → 0.4.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/README.md +43 -135
- package/icon.svg +11 -0
- package/lib/client/index.js +747 -31
- package/lib/host/query.js +24 -4
- package/lib/host/settings.js +39 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,167 +1,75 @@
|
|
|
1
1
|
# dsh-plugin-usage
|
|
2
2
|
|
|
3
|
-
DeepSeek Harness 的 **Token
|
|
3
|
+
DeepSeek Harness 的 **Token 用量统计**插件:按天 / 自定义范围查看 Token、调用次数与成本,支持模型筛选、定价配置和年度热力图。
|
|
4
4
|
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
> GitHub: [bennett-dsh/dsh-plugin-usage](https://github.com/bennett-dsh/dsh-plugin-usage) · npm: `dsh-plugin-usage`
|
|
5
|
+
> Token usage statistics for DeepSeek Harness.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
- 可配置的每百万 Token 价格表(内置 DeepSeek 常见模型默认价,未配置的模型标记为「未定价」)
|
|
12
|
-
- 深/浅色主题自适应(使用 DSH 主题变量),无第三方图表库(手写堆叠柱状图)
|
|
7
|
+

|
|
8
|
+

|
|
13
9
|
|
|
14
|
-
|
|
10
|
+
## 功能
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
- 今日 / 近 7 天 / 近 30 天 / 全部 / 自定义范围(不限跨度),按小时·天聚合
|
|
13
|
+
- 模型筛选、按模型明细(请求数、输入/输出、缓存、成本、占比)
|
|
14
|
+
- KPI 网格里的「模型占比」卡:按总 Token 显示前 4 个模型与「其它」
|
|
15
|
+
- 参考成本可在 ¥ / $ 之间切换(固定汇率 1 USD = 7 CNY,宿主侧折算)
|
|
16
|
+
- 可配置的每百万 Token 价格表(内置 DeepSeek 常见模型默认价)
|
|
17
|
+
- 年度热力图;深/浅色自适应,只用 DSH 主题变量,无第三方图表库
|
|
18
|
+
- **输入区成本 pill**:composer 旁显示「今日 ¥x.xx」(今日无调用时不占位),title 带调用次数与 Token;币种跟随设置页的 ¥/$ 选择
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
- 📅 **时间范围** — 今日 / 近 7 天 / 近 30 天 / 自定义范围
|
|
20
|
-
- 🔍 **模型筛选** — 多选模型,按模型查看明细与占比
|
|
21
|
-
- 📈 **每日趋势** — 按天堆叠柱状图(输入=蓝、输出=绿),hover 查看明细
|
|
22
|
-
- 💰 **定价配置** — 为模型设置每百万 Token 价格(输入 / 输出 / 缓存命中 / 缓存创建),保存后立即生效
|
|
23
|
-
- 🌗 **主题自适应** — 跟随 DSH 深/浅色主题,无第三方图表库
|
|
20
|
+
## 安装
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
插件已发布到 npm:`dsh-plugin-usage`。
|
|
26
23
|
|
|
27
|
-
|
|
24
|
+
- **DSH Desktop**:设置 → 插件 → 添加插件,输入 `dsh-plugin-usage`
|
|
25
|
+
- **Web / CLI profile**:`dsh plugin --profile <name> add dsh-plugin-usage`,重启生效
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
升级同理(桌面端在插件页点更新,CLI 用 `update`)。
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
> `desktop` profile 由 Electron 应用独占,不能用 `dsh plugin --profile desktop` 操作。
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
npm install # 首次(devDependencies:typescript)
|
|
35
|
-
npm run build # tsc 输出到 lib/,并生成 client 模块入口
|
|
36
|
-
```
|
|
31
|
+
## 配置
|
|
37
32
|
|
|
38
|
-
|
|
33
|
+
设置 → 插件 → `dsh-plugin-usage` 可改 `currency` 和 `prices`(每百万 Token 价格),写入 profile patch,重启保留。
|
|
34
|
+
`currency` 是默认显示币种;仪表盘上参考成本卡里的 ¥ / $ 切换只影响当前界面(同浏览器记住选择)。
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```sh
|
|
43
|
-
dsh plugin --profile web add dsh-plugin-usage
|
|
44
|
-
dsh web # 重启后生效
|
|
45
|
-
```
|
|
36
|
+
价格优先匹配 `provider/model`,其次裸 `model`;未配置的模型标为「未定价」,成本记 0。
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
profile 的 `dsh.profile.bundles` 层栈,无需手动编辑任何配置文件。卸载 / 更新:
|
|
38
|
+
## 数据来源与口径
|
|
49
39
|
|
|
50
|
-
|
|
51
|
-
dsh plugin --profile web remove dsh-plugin-usage # 卸载
|
|
52
|
-
dsh plugin --profile web update dsh-plugin-usage # 更新
|
|
53
|
-
```
|
|
40
|
+
> 输入区 pill 与设置页共用同一条 `usage/query` 通道,口径一致(今日 00:00 → 现在,按记录里的 `provider/model` 逐条计价)。它不看官方 `tokenUsage` 投影:那个投影只有会话内合计、不带模型归因,用来算钱会把不同单价混成一个数。口径是「今日」而不是「本会话」——宿主渲染 `conversation.composer.dock` 时不传 props,dock 条目拿不到会话标识。
|
|
54
41
|
|
|
55
|
-
|
|
56
|
-
> `dsh-plugin-usage@<version>` 加入 profile 的 `pnpm-workspace.yaml` 的
|
|
57
|
-
> `minimumReleaseAgeExclude` 列表后重试(官方对新发布包同样采用此做法)。
|
|
42
|
+
折叠 DSH 会话日志中已持久化的用量事件,不自己记日志:
|
|
58
43
|
|
|
59
|
-
|
|
44
|
+
- 读取走官方接口:活跃会话 `snapshotEvents()`,历史会话 `sessionPersistence.open/read`,按 `revision` 跳过未变日志
|
|
45
|
+
- 计费对齐官方 `tokenUsage` 投影:同一 `(turn, step)` 替换;`llm/retry-started` 后的重试累加;`assistant/attempt` 的 stream 用量也计入
|
|
46
|
+
- fork 会话按 `inheritedEventCount` 跳过父会话前缀,不重复计费
|
|
47
|
+
- 费用 = Σ(各 Token 分桶 × 对应单价) / 1e6
|
|
48
|
+
- 价目表以**美元 / 百万 Token** 为基准(与 DeepSeek 官方价一致);显示 `¥` 时按固定 7:1 折算,价目表本身不改写
|
|
60
49
|
|
|
61
|
-
|
|
50
|
+
## 兼容性
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
- id: usage-host
|
|
66
|
-
name: '/path/to/dsh-plugin-usage/lib/host/index.js'
|
|
67
|
-
- id: usage-client
|
|
68
|
-
name: '/path/to/dsh-plugin-usage/lib/client/index.js'
|
|
69
|
-
```
|
|
52
|
+
- DSH `>=0.2.0-rc.2 <0.3.0`(`engines.dsh`),Node ≥ 22
|
|
53
|
+
- 更早的宿主保留 `Session.events` / `readFrom` 回退路径
|
|
70
54
|
|
|
71
|
-
|
|
55
|
+
## 开发
|
|
72
56
|
|
|
73
57
|
```sh
|
|
74
|
-
|
|
58
|
+
npm install
|
|
59
|
+
npm run build # tsc → lib/,再生成 lib/client/index.js
|
|
60
|
+
npm test # node --test
|
|
75
61
|
```
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## 使用说明 / Usage
|
|
80
|
-
|
|
81
|
-
1. 打开设置(左下角)→ 左侧导航「用量统计」。
|
|
82
|
-
2. 顶部筛选:日期预设(今日 / 近 7 天 / 近 30 天 / 自定义)、模型多选。
|
|
83
|
-
3. 汇总卡:总 Token、输入 Token、输出 Token、调用次数、成本(未定价调用会在卡片下提示)。
|
|
84
|
-
4. 每日用量趋势:按天堆叠柱状图(输入=蓝、输出=绿),hover 查看明细。
|
|
85
|
-
5. 按模型明细表:请求数 / 输入 / 输出 / 总 Token / 成本 / 占比。
|
|
86
|
-
6. 「定价配置」区块:为模型设置每百万 Token 价格,保存后立即生效。
|
|
87
|
-
|
|
88
|
-
## 数据来源与口径 / Data Source
|
|
89
|
-
|
|
90
|
-
插件**不自己记录原始日志**,而是折叠 DSH 已持久化的会话日志:
|
|
91
|
-
|
|
92
|
-
- DSH 的 agent loop 把每次模型调用的用量写进会话日志:`assistant/message` 携带
|
|
93
|
-
`usage`(输入/输出/缓存命中/缓存创建 Token)与 `message.source.{provider,model}`;
|
|
94
|
-
重试或失败但已计费的调用记为 `assistant/attempt`(无 `usage` 字段,usage 在其
|
|
95
|
-
`stream` 的最后一个 `usage` chunk 里)。日志是 v4 zstd(`~/.dsh/sessions/**/session.v4.jsonl.zstd`)。
|
|
96
|
-
- 读取走官方 0.2.x 访问器:活跃会话 `ctx.sessions.list()` + `session.snapshotEvents(seq)`;
|
|
97
|
-
持久化会话 `ctx.sessionPersistence.list()`(`{header, revision, eventCount?}`)+
|
|
98
|
-
`open(id, 'read')` → `handle.read(offset)`,并按 `revision` 跳过未变更的日志。
|
|
99
|
-
- 启动时**回填(backfill)全部历史会话**,之后每 2s 扫描活跃会话、每 30s 扫描持久化会话
|
|
100
|
-
(按 seq 水位 + revision)。
|
|
101
|
-
- 覆盖范围:所有 agent loop 调用(含子代理)。compaction / session-title 等辅助调用不写入
|
|
102
|
-
会话日志,不在统计范围内。
|
|
103
|
-
- 计费口径对齐官方 `tokenUsage` 投影:同一 `(turn, step)` 的后续样本**替换**先前样本;
|
|
104
|
-
但 `llm/retry-started` 之后的重试是新的计费调用,**累加**。fork 会话按
|
|
105
|
-
`inheritedEventCount` 跳过父会话前缀,不重复计费。
|
|
106
|
-
- 无 `message.source` 的结算按最近的 `request/context` / `request/header` 路由归因。
|
|
107
|
-
- 费用 = `(输入×输入价 + 输出×输出价 + 缓存命中×缓存命中价 + 缓存创建×缓存创建价) / 1e6`,价格表可改。
|
|
108
|
-
- 价格表就是插件配置:`src/host/index.js` 导出 schemastery `Config`,DSH 在
|
|
109
|
-
Plugins 配置页生成表单并存入 profile patch(重启保留);客户端定价编辑走官方
|
|
110
|
-
`ctx.configForms.get('usage')`,不可用时回退 `usage/prices` RPC。
|
|
111
|
-
|
|
112
|
-
> 动态插件形态下数据保存在进程内存中,重启后自动从会话日志重新回填,无需落盘文件。
|
|
113
|
-
|
|
114
|
-
## 源码结构 / Project Structure
|
|
63
|
+
CI 跑 install → build → test → bundle id 契约 → tarball 内容检查;推 `v*` tag 会校验版本、构建测试并创建 GitHub Release。
|
|
115
64
|
|
|
116
65
|
```
|
|
117
|
-
src/
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
│ ├── settings.js 价格表 + 费用计算(内置 DeepSeek 常见模型默认价,配置由 index.js 的 Config 承载)
|
|
121
|
-
│ ├── state.js 运行时状态:records / watermarks / revisions / lastSample / route / backfill / index
|
|
122
|
-
│ ├── aggregate.js 增量聚合索引:add / remove / recordsInRange,供查询高效取数
|
|
123
|
-
│ ├── fold.js 会话事件 → usage 记录(对齐官方 tokenUsage:替换槽、retry 累加、attempt/stream usage、路由归因)
|
|
124
|
-
│ ├── scan.js 启动回填 + 活跃/持久化会话增量扫描(0.2.x snapshotEvents / open+read,revision 跳过,水位修复)
|
|
125
|
-
│ ├── query.js 聚合与查询:按天/按模型汇总、未定价检测、heatmap
|
|
126
|
-
│ ├── rpc.js 传输注册:动态 harness / Typert 网关 / 静态安装的 Connection 共享 `/api` Fetch 路由(含旧版 `/usage` 前缀通道回退)
|
|
127
|
-
│ ├── client-source.js 读取 src/client/index.js 实时提供给浏览器(动态插件形态)
|
|
128
|
-
│ └── time.js 时间分桶:day/hour/minute 粒度与 step 网格(纯函数)
|
|
129
|
-
├── client/index.js Client half:设置页「用量统计」仪表盘(筛选/汇总卡/柱状图/模型表/定价配置),样式内联
|
|
130
|
-
└── client/styles.js UI 样式源(构建脚本已合并进 index.js,可删除)
|
|
131
|
-
scripts/
|
|
132
|
-
└── build-client.js 构建时生成 lib/client/index.js 模块入口(同一份 UI 代码的正式加载形态)
|
|
133
|
-
cordis.patch.yml bundle patch:`dsh plugin add` 安装后由 `dsh.bundle` 声明自动激活
|
|
66
|
+
src/host/ 宿主:scan / fold / query / settings / aggregate / rpc
|
|
67
|
+
src/client/ 设置页「用量统计」仪表盘(纯 JS,样式内联)
|
|
68
|
+
scripts/ 构建客户端 bundle 入口
|
|
134
69
|
```
|
|
135
70
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
```sh
|
|
139
|
-
npm install # 首次安装依赖(devDependencies:typescript)
|
|
140
|
-
npm run build # tsc 输出到 lib/,再由 scripts/build-client.js 生成 client 模块入口
|
|
141
|
-
npm test # node --test tests/
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
`src/host/` 下的宿主逻辑(fold / scan / query / aggregate / time / settings 等)均为可直接
|
|
145
|
-
import 的 ESM 模块,单元测试直接运行,无需启动 DSH harness。CI(Node 22/24)跑
|
|
146
|
-
install → build → test → bundle id 契约 → tarball 内容检查。
|
|
147
|
-
|
|
148
|
-
兼容性:`engines.dsh` 声明 `>=0.2.0-rc.2 <0.3.0`(0.2.x 官方 API),更早版本依赖
|
|
149
|
-
`readFrom` / `Session.events` 回退路径。
|
|
150
|
-
|
|
151
|
-
## 说明 / Notes
|
|
152
|
-
|
|
153
|
-
- 插件名 `usage`;动态插件运行在会话级,卸载后统计重新回填即可恢复。
|
|
154
|
-
- 价格表持久化策略见「数据来源与口径」(插件 `Config` → 官方 Plugins 配置页 → profile patch;
|
|
155
|
-
0.2.x 没有可用的 `settingsScope` / `settings.register`,旧路径已删除)。
|
|
156
|
-
- 静态安装的传输:DSH 0.2+ 注册在 Connection 共享 `/api` 通道的 exact Fetch 路由上
|
|
157
|
-
(`POST /api/usage/query`、`/api/usage/prices`、`/api/usage/client-source`,请求体为
|
|
158
|
-
args JSON,响应为 `{ ok, value }` / `{ ok, error }`);旧版宿主自动回退到 `/usage`
|
|
159
|
-
前缀 RPC 通道。这条路由不依赖插件自身 fiber 注入 `webServer`——0.2.x 下后者会抛错并
|
|
160
|
-
让通道静默消失(症状是查询一律 HTTP 405),见
|
|
161
|
-
[#1](https://github.com/bennett-dsh/dsh-plugin-usage/issues/1)。
|
|
162
|
-
- 客户端 bundle 的 loader id 在构建时取自 `package.json#name`,因此 scoped 名、
|
|
163
|
-
npm alias、`file:` tarball 等安装形态都能正常注册(不要手改 `lib/client/index.js`)。
|
|
71
|
+
> 开发期也可用 `--patch` 从源码加载:`dsh web --patch cordis.yml`(路径见 `cordis.yml`)。
|
|
164
72
|
|
|
165
|
-
##
|
|
73
|
+
## License
|
|
166
74
|
|
|
167
75
|
[MIT](./LICENSE)
|
package/icon.svg
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Usage statistics">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="usage-bars" x1="8" y1="7.5" x2="28" y2="28" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop stop-color="#67C7FE"/>
|
|
5
|
+
<stop offset="1" stop-color="#3F77D8"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect x="8" y="20.5" width="5.5" height="7.5" rx="2.4" fill="url(#usage-bars)"/>
|
|
9
|
+
<rect x="15.25" y="14" width="5.5" height="14" rx="2.4" fill="url(#usage-bars)"/>
|
|
10
|
+
<rect x="22.5" y="7.5" width="5.5" height="20.5" rx="2.4" fill="url(#usage-bars)"/>
|
|
11
|
+
</svg>
|