Skip to content

dsh-token-usage-panel

Verified

dsh-token-usage-panel · v1.0.2 · MIT · Web UI

Token 用量面板 / Token usage panel: 侧边栏入口,概览(活动热力图、每日趋势、模型环图)与会话明细(筛选、排序、导出)。零依赖、无金额、无定价。

Install

dsh plugin add dsh-token-usage-panel

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Tags

Creators

Readme

dsh-token-usage-panel

npm license

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