- Home
- Plugins
- Usage & Billing
- dsh-token-usage-panel
dsh-token-usage-panel
jaytdd/dsh-token-usage-panel
Token 用量面板 / Token usage panel: 侧边栏入口,概览(活动热力图、每日趋势、模型环图)与会话明细(筛选、排序、导出)。零依赖、无金额、无定价。
Install
dsh plugin --profile web add github:jaytdd/dsh-token-usage-panelREADME
dsh-token-usage-panel
DeepSeek Harness 插件:在侧边栏加一个「Token 用量」入口,用两个视图回答同一个问题——token 花在哪儿了。
- 概览 — KPI 条、近一年活动热力图、每日趋势(多模型折线)、模型用量环图
- 会话 — 总消耗与构成、按模型拆分、可筛选可排序可导出的会话明细
零依赖。没有金额。没有厂商标签。 这个插件的职责是"用量",不是"账单"。
Token 用量统计 (概览 │ 会话) ↻ 刷新
────────────────────────────────────────────────────────────────────────
287K 273K 3 小时 0 分钟 2 天 2 天
累计 Token 峰值 Token 当前连续天数 最长连续天数
────────────────────────────────────────────────────────────────────────
[🔍 搜索…] [📁 目录 ▾] [☰ 总量 ↓ ▾] [⤓ 导出 ▾] [重置筛选]
(全部│今天│7天│30天) ☑ 仅顶层会话 ☑ 仅显示有用量的会话
────────────────────────────────────────────────────────────────────────
Token 活动
▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ 一格一天,按当天用量着色
────────────────────────────────────────────────────────────────────────
每日 Token 趋势 (7 天 │ 30 天)
273K ┤ ╭─╮
│ ╭────╯ ╰──╮
0 └──┴──────────┴──────────────────────
────────────────────────────────────────────────────────────────────────
模型用量
╭───╮ ● opencode go chat · deepseek-v4.1-flash 273,400 token 95.4%
│287K│ ● anthropic · Claude Y 13,300 token 4.6%
╰───╯ 点一行 → 只看使用该模型的会话
安装
图形界面:侧栏「插件」页 →「添加插件」→ 填 dsh-token-usage-panel → 安装 → 重启 DSH 并刷新浏览器。
命令行:
dsh plugin --profile <profile-name> add dsh-token-usage-panel
npm 包:dsh-token-usage-panel
装完必须重启一次 DSH。 Host 半场(三个投影单元)是已加载模块,平台 HMR 默认不监听插件目录;不重启就只有浏览器半场,图表会提示"还没有按天数据"。
老会话会在你第一次打开面板时补读。 早于本插件写入的会话缓存里没有按模型/按天数据,面板会并发补读(折叠历史日志、不激活 Agent、底部显示进度)。所以刚装完概览先是空的、随后自己填满,这是正常行为而不是出错。
配置(可选)
Host 半场按本机 UTC 偏移把用量分到"天"。桌面端 Host 与用户同机,默认就是你的时区,通常不用配。需要固定成别的时区时(例如长期在异地查看):
config:
utcOffsetMinutes: 480 # 东八区;默认 -new Date().getTimezoneOffset()
使用
概览视图
- KPI 条:累计 Token、峰值(最忙那一天的用量)、当前连续天数、最长连续天数。
- Token 活动:近一年,一格一天,按当天用量分五级着色。点某一格 → 只看那一天的会话(筛选栏出现可清除的日期 chip)。不可多选,也没有按周/按月聚合。
- 每日 Token 趋势:多模型折线,可切 7 天 / 30 天;指针移上去显示当天各模型数值。
- 模型用量环图:显示占比。点某一行 → 跳到会话视图并只看该模型,这就是"看到占比 → 看到背后是谁"的闭环。
概览的日历、趋势与 KPI 刻意忽略日期筛选——否则你点热力图某一格,整张年历会塌成一天。
会话视图
- 总消耗卡:总量 + 构成条(未缓存输入 / 缓存读取 / 缓存写入 / 输出)。
- 模型用量条:可按网关或按模型分组,点一行同样下钻。
- 会话表:每页 20 行;表头点击排序,也可用排序菜单(7 个度量 × 升/降);列宽可拖动并持久化;窄面板自动隐藏次要列。
- 导出:复制 TSV 到剪贴板,或下载 CSV(带 BOM,Excel 打开不乱码;数字是原始值,未缩写)。
- 跳到当前会话:清掉筛选并把当前会话滚进视野,跨页时先翻到它所在那一页。
- 失败重试:某个会话的投影读取失败时,行内出现「重试」。
筛选
搜索(标题 / 会话 ID / 目录)、时间范围(全部 / 今天 / 7 天 / 30 天)、目录、排序、仅顶层会话、仅显示有用量的会话、模型、某一天。筛选条件连同视图、趋势窗口、列宽一起存在 localStorage["dsh-token-usage-panel.filters.v3"]——损坏、类型错误、越界或旧版本的值都会被字段级校验后回退默认。
快捷键
| 键 | 作用 |
|---|---|
/ | 聚焦搜索框 |
r | 刷新用量 |
Esc | 在输入框内清空搜索 |
数据什么时候更新
用量由会话事件折叠而来,Host 在写检查点时更新(默认 200 事件 / 5 秒节流,另加每个 turn 结束必写)。所以冷会话的数字可能滞后一个 turn,而"时间范围"筛的是最近活动(创建时间与最后一次用户输入中较晚者),不是"最后一次记账时间"。想立刻拿到最新数字,按 r。
主题与无障碍
浅色是默认主题,深色跟随平台属性自动切换。面板自身有一个 live region,正在读取/读取完成/失败都会朗读;热力图的可点日期是可聚焦的按钮角色(role="button" + tabIndex,Enter/Space 激活)并带日期名字,表头排序按钮移出了 Tab 序列(键盘入口是排序菜单);所有动画都遵守 prefers-reduced-motion。
数据来源与口径
面板上的每个数字都来自会话投影。官方的 tokenUsage(四个计数桶)与 sessionStats(轮次)之外,本插件的 Host 半场注册了三个单元:
| 投影键 | 内容 | 保留窗口 |
|---|---|---|
tokenUsageByRoute | 按 provider/model 的用量(含网关名与模型显示名) | 全量 |
tokenUsageByDay | 按天用量 + 会话跨度 + 折叠用的 UTC 偏移 | 366 天 |
tokenUsageByRouteByDay | 按天 × 模型(趋势图数据) | 31 天 |
三个单元与官方 tokenUsage 共用同一个事件推进步骤,所以在任何样本上都成立:
sum(按模型) === sum(按天) === sum(按天 × 模型) === tokenUsage
Host 自检用"逐行复刻官方算法"的 oracle 做差分对比来钉住这条等式;面板运行时还会自己再查一次——sum(按模型) ≠ 总量 就在页脚亮一条警告并列出问题会话,不必再靠肉眼发现。
天界:按 Host 本机 UTC 偏移分桶(utcOffsetMinutes 可配),偏移随数据一起下发,浏览器用同一帧标注日期;跨午夜的会话按该日界切分。
路由标签只有两项,都取自 Host 的 LLM 注册表:网关名 · 模型名,例如 opencode go chat · deepseek-v4.1-flash。注册表读不到时回落到原始 id。
有意如此的取舍
- 没有金额。 一张写死的价目表几周内就会过期,然后自信地画出错误的金额。代码、配置、文案、导出里都不含价格。
- 没有厂商字段。 事件里只有
provider/model,而provider是路由键(网关),不是模型公司——同一个模型会以opencodegochat/*、opencodego/*、codexpert/*等前缀出现。从模型 id 前缀猜一个公司名看起来像事实,实际是猜测,而且猜不出来时只能显示网关名、反而更像错的。 - 零依赖。 平台只提供冻结的种子模块表(React、React DOM、Cordis、client-store、ui-slots、ui-primitives、dockkit),既没有图表库也没有构建工具——所以折线、环图、热力图都是手写 SVG,
scripts/build.mjs是零依赖的字符串拼接,schema 校验是自带的小鸭子类型。 - 子代理会话是独立行,并计入总量:它们在自己的会话里花 token,不重复计入父会话。
- 同一模型经不同网关访问会分成两行——这是数据事实,不是合并失误。
- 归档会话也计入:会话列表是完整逻辑语料,没有条数上限。
已知限制
- 统计是日志口径的累计用量,不是账单。
- 按天数据保留 366 天、按天 × 模型保留 31 天,更早的在折叠时被裁剪,因此热力图是滚动的一年窗口。
- 天界取决于 Host 本机时区(可配)。
- 热力图不可多选,也没有按周/按月聚合。
- 虚拟化以固定行高为前提(行高恒为 54px),但分页之后窗口化永不触发,那段代码只是保留。
- 折线图的 y 轴上限取整到便于阅读的刻度,所以曲线顶端不一定贴网格线。
排障
| 现象 | 原因 / 处理 |
|---|---|
| 概览显示「还没有按天数据」 | Host 半场没生效——没重启 DSH,或该组合里没有投影服务。重启即可。 |
| 面板数字和图表对不上 | 正常不该发生。页脚出现警告就是在说某条读取路径没覆盖到,悬浮可看是哪几个会话。 |
| 老会话缺按模型/按天数据 | 第一次打开面板时会自动补读,读完前显示骨架屏与进度。 |
| 冷会话数字偏旧 | 检查点写入有节流,可能滞后一个 turn;按 r 刷新。 |
| 装了但侧边栏没有入口 | 确认装完重启过 DSH,并刷新了浏览器页面。 |
开发
node scripts/build.mjs # 从 src/ 重新生成 lib/client.js
node scripts/build.mjs --check # 产物过期闸门
node scripts/verify-host.mjs # Host 半场自检(含与官方算法的差分 oracle)
node scripts/verify-bundle.mjs # 浏览器半场自检
node scripts/dry-run-audit.mjs # 只读:在真实 $DSH_HOME 上验证审计不误报
零依赖是硬约束,不是审美:平台只提供冻结的种子模块表,安装版 app.asar 里没有 tsdown / esbuild / rollup,所以产物生成、图表、schema 校验都必须自己实现。
lib/index.js Host 入口:注册三个单元 + 名称缓存刷新
lib/route-usage.js Host 折叠:共用推进步骤、三个单元、窗口裁剪
lib/route-names.js Host 名称缓存:网关名 + 模型显示名(无厂商)
lib/client.js 浏览器产物(生成物,勿手改)
src/00-boot.js … 99-apply.js 浏览器半场源码,共 14 个模块
scripts/build.mjs 零依赖生成器(--check 是过期闸门)
改完请跑完上面四条命令。lib/client.js 由 src/ 生成,手改会在第一项自检就失败。
许可
MIT © JAYTDD
Related plugins
DeepSeek-Balance-Whale-Widget
meteornox/deepseek-balance-whale-widget
dsh-context
bowenliang123/dsh-context
dsh-cost-meter
han-1413141/dsh-cost-meter
dsh-damage-pulse
wssfk12138/dsh-damage-pulse