dsh-plugin-usage 0.1.4 → 0.2.2

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 CHANGED
@@ -22,6 +22,12 @@ DeepSeek Harness 的 **Token 用量统计**插件(UI 参考 CC Switch 的「
22
22
  - 💰 **定价配置** — 为模型设置每百万 Token 价格(输入 / 输出 / 缓存命中 / 缓存创建),保存后立即生效
23
23
  - 🌗 **主题自适应** — 跟随 DSH 深/浅色主题,无第三方图表库
24
24
 
25
+ ## 效果图
26
+
27
+ ![alt text](image.png)
28
+
29
+ ![alt text](image-1.png)
30
+
25
31
  ## 安装与构建 / Install & Build
26
32
 
27
33
  ```sh
@@ -83,10 +89,25 @@ dsh web --patch /path/to/dsh-plugin-usage/cordis.yml
83
89
 
84
90
  插件**不自己记录原始日志**,而是折叠 DSH 已持久化的会话日志:
85
91
 
86
- - DSH 的 agent loop 会把每次模型调用的用量以 `assistant/message` 会话事件(携带 `usage`:输入/输出/缓存命中/缓存创建 Token 与 `message.source.{provider,model}`)写入会话日志(`~/.dsh/sessions/`)。
87
- - 插件启动时**回填(backfill)全部历史会话**,之后每 2s 增量扫描活跃会话(内存),每 30s 增量扫描持久化会话(按 seq 水位)。
88
- - 覆盖范围:所有 agent loop 调用(含子代理)。compaction / session-title 等辅助调用不写入会话日志,不在统计范围内。
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` 路由归因。
89
107
  - 费用 = `(输入×输入价 + 输出×输出价 + 缓存命中×缓存命中价 + 缓存创建×缓存创建价) / 1e6`,价格表可改。
108
+ - 价格表就是插件配置:`src/host/index.js` 导出 schemastery `Config`,DSH 在
109
+ Plugins 配置页生成表单并存入 profile patch(重启保留);客户端定价编辑走官方
110
+ `ctx.configForms.get('usage')`,不可用时回退 `usage/prices` RPC。
90
111
 
91
112
  > 动态插件形态下数据保存在进程内存中,重启后自动从会话日志重新回填,无需落盘文件。
92
113
 
@@ -94,7 +115,17 @@ dsh web --patch /path/to/dsh-plugin-usage/cordis.yml
94
115
 
95
116
  ```
96
117
  src/
97
- ├── host/index.js Host half:采集(扫描/回填)+ 聚合 + 价格表 + RPC(usage/query、usage/prices、usage/client-source)
118
+ ├── host/
119
+ │ ├── index.js Host 入口:接线 fold / scan / query / settings / aggregate / rpc / client-source,驱动定时扫描
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 网格(纯函数)
98
129
  ├── client/index.js Client half:设置页「用量统计」仪表盘(筛选/汇总卡/柱状图/模型表/定价配置),样式内联
99
130
  └── client/styles.js UI 样式源(构建脚本已合并进 index.js,可删除)
100
131
  scripts/
@@ -102,10 +133,34 @@ scripts/
102
133
  cordis.patch.yml bundle patch:`dsh plugin add` 安装后由 `dsh.bundle` 声明自动激活
103
134
  ```
104
135
 
136
+ ## 开发与测试 / Development & Testing
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
+
105
151
  ## 说明 / Notes
106
152
 
107
153
  - 插件名 `usage`;动态插件运行在会话级,卸载后统计重新回填即可恢复。
108
- - 价格表修改在进程内有效(动态插件形态);正式 patch 加载后可扩展为落盘持久化。
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`)。
109
164
 
110
165
  ## 开源协议 / License
111
166
 
package/image-1.png ADDED
Binary file
package/image.png ADDED
Binary file