dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Token 用量看板插件,用于 DSH(DeepSeek Harness)。
按本机时区记录每次模型调用的 token 消耗,并把「攒了多少」做成看得见的方块墙。
本插件以 Cordis bundle 形式发布,宿主是 DSH 的 Web profile。
# <profile> 通常是 ~/.dsh/profiles/<名字>
# Windows: %USERPROFILE%\.dsh\profiles\<名字>
cd ~/.dsh/profiles/<profile>/node_modules
git clone https://github.com/ChinRinhan/dsh-token-usage.git
然后在 profile 的 cordis.patch.yml 里插入本 bundle(或直接用方式二让 DSH 自己写)。
在 DSH 会话里执行:
plugin_manager install_bundle target=<本地路径或包名>
plugin_manager set_bundle target=dsh-token-usage enabled=true
启用后宿主会注册四条路由。把 <port> 换成你的 Web GUI 端口:
curl http://127.0.0.1:<port>/dsh-token-usage/today
返回 {"ok":true,"totals":{...},"allTime":{...},...} 就说明装好了。
界面上应该能看到三样东西:侧栏多出一个方块图标、右下角出现桌宠、设置页多出「Token 用量」一节。
backfillOnStart(默认开启)会扫描 $DSH_HOME/sessions 下的会话日志,把装上之前的用量补进来。
参考量级:本机 116 个会话、22 天、8,410 条记录,回填耗时数秒。
点侧栏的方块图标进入。
总消耗 684,561,075 tokens 已获得 68 块 · 第 1 页
████ ████ ████ ████ ████ ████ ████ ████ ████ ████
████ ████ ████ ████ ████ ████ ████ ████ ████ ████
...
████ ████ ████ ████ ████ ██▓░ ░░░░ ░░░░ ░░░░ ░░░░
░░░░ ░░░░ ░░░░ ░░░░ ░░░░ ░░░░ ░░░░ ░░░░ ░░░░ ░░░░
为什么是 10M:按真实数据量过,单轮对话中位 1.41M、p90 10.4M,典型活跃日 2–3 块、重度日 7–9 块。快慢都合适。
常驻在窗口任意位置,也可以拖走。
┌─ Token 方块墙 ● dafeiyu ─┐
│ 累计 2.98B │
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓░░ 94% │ ← 充能块:当前这块填了多少
│ ■ 297 块 │ ← 池:已攒下的整块数
│ 今日 31.44M 1.1% · │
│ 速度 4.0K/s 昨日 127.79M │
└─────────────────────────────┘
localStorage,窗口缩放时自动钳制在可视范围内动效很克制:充能到 90% 以上时充能块轻微呼吸,攒到新的一块时池弹一下。系统开了「减少动态效果」时会全部关掉。
同一块区域,三个视角切换:
| 维度 | 回答的问题 |
|---|---|
| 工作区 | 我在哪个项目花得多 |
| 模型 | 我在用哪个模型花 |
| 厂商 | 我在给哪家公司送钱 |
「模型」视角会自动归并同一模型的不同写法。比如这四行其实是同一个模型:
deepseek-v4.1-flash 1.54B ← 主名
workbuddy/deepseek-v4.1-flash 25.6M ← 带渠道前缀
deepseek-ai/deepseek-v4.1-flash 52K ← 另一种前缀
deepseek-v4.1-flash-free 23.1M ← 带 free 后缀
归并后合成一行:1.62B · 4 个变体。
⚠️ 但不同代际不合并。deepseek-flash、deepseek-v4-flash、deepseek-v4.1-flash 是三个版本,合并会掩盖「还在用旧模型」这件事。
⚠️ 认不出厂商的模型归入「其他」,不猜。可以用配置里的 modelAliases 显式声明,见下。
当前在用的工作区 / 模型会高亮。
「Token 用量」一节包含:
在 profile 的 cordis.patch.yml 里覆盖,插件升级不会丢:
- id: dsh-token-usage
name: 'dsh-token-usage'
config:
keepDays: 400 # 保留天数(落盘时淘汰更早的日键)
includeSubagents: true # 计入子代理 / 团队 / workflow 子会话
includeAuxiliary: true # 计入压缩等辅助调用
statusBarEnabled: true # 是否允许显示输入框上方的横幅
statusBarRefreshMs: 1000 # 轮询间隔,最小 1000
backfillOnStart: true # 启动时回填历史
# 可选:手动声明模型别名(认不出的模型可以在这里归类)
modelAliases:
dfmodel:
vendor: deepseek
model: deepseek-v4.1-flash
| 位置 | 生效方式 | 用途 | |
|---|---|---|---|
config.statusBarEnabled | cordis.patch.yml | 重启 DSH | 部署期的硬开关 |
| 设置页三个开关 | $DSH_HOME/token-usage/prefs.json | 立即生效 | 日常调整 |
设置页那三个开关存在独立文件里,是因为改 Cordis config 要重启,而「我想把桌宠关掉」显然不该重启。
启用后宿主注册四条路由,默认绑定 Web GUI 的端口。
| 路径 | 说明 |
|---|---|
GET /dsh-token-usage/today | 今日 + 昨日 + 累计 + 本次运行平均速度 + 当前工作区/模型 + 运行时开关 + 诊断 |
GET /dsh-token-usage/summary | 区间汇总。groupBy 可取 day week month provider model providerModel kind workspace modelNorm vendor |
GET /dsh-token-usage/workspaces | 工作区分布,只回 top N(limit / from / to) |
GET / PUT /dsh-token-usage/prefs | 运行时开关(statusBar / pet / wallPanel)。唯一可写的端点 |
/summary 还支持 from / to / includeSub / includeAux / workspace 参数。
这一节讲清楚「数字是怎么算出来的」,因为它决定了你看到的数字意味着什么。
会话日志里 assistant/message 事件的 usage 字段。它是持久化的,所以「历史回填」和「实时捕获」读的是同一份数据,不存在两套口径。
| 事件 | 类型 | 说明 |
|---|---|---|
assistant/message | 对话调用 | 主力来源 |
compaction/summary | 辅助调用 | 压缩摘要也是真实模型调用,计入 |
⚠️ 标题生成走的 session/title-llm-request 不带 usage,因此那部分开销无法从日志恢复。这是已知限制,不是遗漏。
totalTokens = inputTokens + cacheReadTokens + cacheWriteTokens + outputTokens
即「这次调用实际过了一遍的 token 总量」。它与 provider 上报的 totalTokens(通常只是 input+output)不是一回事,所以本插件不读那个字段,自己按上式算。
outputTokens 已含思考 token,reasoningTokens 只作拆分展示,不重复计入。
没带 usage 的调用(中断、上游提前断开、失败)不写 0,而是根本不入桶。覆盖率在设置页诊断区如实展示。
按本机时区切日,不是 UTC。午夜归零。
$DSH_HOME/token-usage/daily.json(日聚合)与 $DSH_HOME/token-usage/prefs.json(开关)。
只落日聚合、不落明细;增量合并写,多实例并存不互相覆盖;默认 2 秒防抖落盘。
更多实现细节见 docs/DESIGN.md。
npm test # 全部不依赖本机数据的测试
npm run test:data # 需要本机会话日志:交叉校验 + 存储端到端
npm run visual # 生成视觉验证 HTML,再用浏览器截图
npm run check # 语法检查 + 落单反引号检查
node --test test/fold.test.mjs # 日界、周月归属、合计口径、水位线去重、fork 前缀
node --test test/blocks.test.mjs # 方块换算:整除、跨页、当前块、进度、异常输入
node --test test/models.test.mjs # 模型归并:归一化、代际不合并、别名
node --test test/prefs.test.mjs # 运行时开关存储:缺省、原子写、脏输入、损坏回退
node test/client.smoke.mjs # 四个 slot 注册、样式真进 DOM、主题 token
node test/odometer.text.mjs # 桌宠可见文案逐条断言
node test/sparkline.test.mjs # 上升曲线几何:左低右高、不除零
node test/blocks-cross.test.mjs # 主面板/桌宠 与 lib/blocks.js 的跨端一致性
node test/distribution.test.mjs # 消耗分布:形状守卫、列宽预算、当前项高亮
node test/host.routes.test.mjs # 四条路由的 JSON 契约
需要本机数据的两个(不在 npm test 里):
node test/cross-validate.mjs "$DSH_HOME/sessions" # 与独立实现交叉校验真实日志
node test/store.e2e.mjs "$DSH_HOME/sessions" # 回填 → 落盘 → 重开 → 幂等 → 并发
node tools/usage-cli.mjs --sessions "$DSH_HOME/sessions" --group-by provider
node tools/rehearse.mjs # 用真实 home 跑一遍完整回填
node tools/preview-blocks.mjs # 字符画方块墙
node tools/analyze-blocks.mjs # 分析「10M 一格」的填充速度
node tools/migrate-workspace.mjs --home "$DSH_HOME" # 桶键 4 段 → 5 段(dry-run)
node tools/visual-check.mjs # 生成视觉验证 HTML
tools/visual-check.mjs 把真实组件装进真实 React 18,在浏览器里渲染(effect / fetch 全真),主题 token 从宿主的真实 CSS 里读。截图用 Windows 自带的 Edge 就行:
"/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" \
--headless=new --disable-gpu --hide-scrollbars --virtual-time-budget=6000 \
--window-size=1000,1400 --screenshot=tools/out/light.png \
"file:///$(pwd)/tools/out/visual-check.html"
| 改动 | 生效方式 |
|---|---|
client.js | 约 500ms 内热更新(HMR 轮询文件),不用重启、不用构建 |
cordis.patch.yml / package.json | 热重载 |
index.js / lib/** | 禁用→重新启用该 bundle 即可,不用重启 DSH |
usage,无法恢复tools/visual-check.mjs 用的是真实组件 + 真实 CSS + 真实数据,但宿主外壳是模拟的(侧栏、设置面板外框、composer 布局)。驱动真实页面需要 launch token,没有也不该去取