dsh-token-stats

August 16, 2026 · View on GitHub

English | 中文

跨会话 Token 消耗统计插件,为 DeepSeek Harness 提供:

  1. /token-stats 斜杠命令 —— 在 Web 聊天输入框键入 /token-stats,插件回复一份纯文本统计报告(总量 / 按天 / 按周 / 按月 / 按模型 / 会话排行 / 最近请求、缓存命中率)。
  2. tokenStats Typert Remote —— 宿主编排的 TokenStatsGateway 在 /api/tokenStats/aggregate 暴露完整的统计文档,供浏览器或其他调用方复用。
  3. 设置页仪表盘 —— 设置中新增「Token 统计」分区(与通用 / 模型 / 插件 / Agent 预设同层级,自带品牌 Logo):总量卡片、可切换按天 / 按周 / 按月的渐变柱状趋势图(悬停显示明细)、按模型表格、会话排行、缓存命中率与逐请求记录(最新在前,时间/会话/模型/输入/输出/缓存读)。

数据来源

不依赖任何运行中的会话状态:直接解码 dsh-session-persistence-jsonl 落盘的会话日志 ($DSH_HOME/sessions/<workspace>/<session-id>/session.jsonl.zstd),因此所有历史会话都计入,包括已关闭的、以及本进程从未加载过的会话。

  • 日志是多个完整 zstd frame 拼接的容器(每个持久化追加批次一个 frame),插件自带 frame 边界扫描与逐帧解码(lib/log-reader.js),零第三方依赖(node:zlib + node:fs)。
  • 用量语义与 dsh-token-meter 的投影折叠一致:assistant/chunk(usage) 提供早期样本,同一 (turn, step) 的最终 assistant/message 用量替换而非累加(失败的请求保留其分片样本);推理 token 是输出的细分项,不重复计入。
  • 模型归属取最近的 request/context(回退 request/header);按天/按周/按月均使用本地时区(周一为一周起点);标题取 session/title(回退首条用户消息)。

安装

方式一:npm 发布版(推荐)

包已发布到 npm:@kaguyaluna2333/dsh-token-stats。

Web(浏览器 GUI,dsh web)

  1. 安装到 profile(等价于在 profile 目录执行 pnpm add):
    dsh plugin --profile web add @kaguyaluna2333/dsh-token-stats
    
  2. 在 ~/.dsh/profiles/web/cordis.patch.yml 追加:
    - insert:
        - id: token-stats
          name: '@kaguyaluna2333/dsh-token-stats'
    
    可选配置(默认根为 $DSH_HOME/sessions):
          config:
            root: '/path/to/sessions'
    
  3. 重启 dsh web(loader 树在启动时固定,必须重启才能加载新行)。

桌面端(DSH Desktop)

桌面端使用独立的 desktop profile:

dsh plugin --profile desktop add @kaguyaluna2333/dsh-token-stats

把上面的 patch 行加入 ~/.dsh/profiles/desktop/cordis.patch.yml,然后退出并重新打开桌面端应用。

方式二:本地软链(仅开发者)

无需 npm 发布版时(本地开发、离线环境),也可以直接把仓库目录软链进 profile:

# Web
mkdir -p ~/.dsh/profiles/node_modules/@kaguyaluna2333
ln -s <仓库目录> ~/.dsh/profiles/node_modules/@kaguyaluna2333/dsh-token-stats
# 桌面端(模块解析锚定在 profile 自己的 node_modules)
mkdir -p ~/.dsh/profiles/desktop/node_modules/@kaguyaluna2333
ln -s <仓库目录> ~/.dsh/profiles/desktop/node_modules/@kaguyaluna2333/dsh-token-stats

patch 行与方式一相同,然后重启对应前端。

使用

  • 聊天框输入 /token-stats。
  • 或打开 设置 → Token 统计 分区(与通用 / 模型 / 插件 / Agent 预设同层级)。
  • 聚合结果在进程内有 15 秒缓存,重复调用不重复解码。

结构

文件职责
lib/index.jscordis 函数插件入口:挂载 gateway、注册 /token-stats 命令
lib/gateway.jsTokenStatsGateway(TypertRemoteService):tokenStats 服务 + Remote 方法 aggregate();手写装饰器协议安装 @Remote 标记
lib/typert.host.jsTypert host-face manifest:声明 tokenStats/aggregate 调用与 zod 线格式
lib/aggregate.js纯函数聚合核心(折叠、总量/按天/按模型/会话排行、报告渲染),无 cordis 依赖,可独立测试
lib/log-reader.js会话日志枚举、zstd frame 扫描、存储记录解码
lib/client.js手写浏览器 bundle(window.__ModuleLoader__.load):设置页「Token 统计」分区(顶层 settings.section),直接以 RPC 信封调用 /api/tokenStats/aggregate

验证

  • node test/aggregate.test.mjs —— 对真实会话根做聚合并打印报告。
  • 临时实例端到端(克隆 profile 到独立 DSH_HOME,dsh --profile web --port <x>):loader 行 active、 /api/tokenStats/aggregate 返回文档、/plugins/@kaguyaluna2333/dsh-token-stats/client.js 200、index.html 启动图含本包。

已知限制

  • 统计口径是日志口径:被压缩掉的轮次仍计入(与 dsh-session-stats 一致)。
  • cacheWriteTokens 在多数提供方上报中为 0;合计(含缓存)数字对提示缓存敏感。
  • 报告读取的是持久化日志的快照;会话正在运行时的最新请求可能尚未落盘(检查点间隔内)。
  • 页面 Logo:分区页顶部的品牌头(渐变圆角徽标 + 上升柱 + token 圆点,内联 SVG,随主题变色)位于 lib/client.js,随插件 bundle 分发,无需额外操作。

  • 侧边栏图标:设置外壳(dsh-client-ui-settings-general)的 navIcon() 对分区 id → 图标是硬编码的(models / agent-presets / plugins 之外一律回退到齿轮)。为了让「Token 统计」分区有自己的图标,scripts/patch-shell.mjs 会向两处内置外壳 bundle 注入一个分支(自定义 SVG 图标):

    • ~/.npm/_npx/*/node_modules/@deepseek-ai/dsh-client-ui-settings-general/lib/client.js(浏览器 profile 用)
    • /Applications/DSH Desktop.app/Contents/Resources/app.asar.unpacked/...(桌面端用)

    幂等:已打过补丁的文件会跳过;CLI / 桌面端升级覆盖外壳后,重跑一次即可:

    node scripts/patch-shell.mjs