dsh-cost-meter
Đã xác minh@gamegeek-saikel/dsh-cost-meter · v0.5.1 · MIT · Giao diện web
Cost tracking plugin for the DeepSeek Harness Web GUI — snapshot-anchored per-turn pricing, account balance, and live cost estimates.
Cài đặt
dsh plugin add @gamegeek-saikel/dsh-cost-meter Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Thẻ
Readme
DSH Cost Meter(对话花费计量)
English · 简体中文
DSH Cost Meter 是为 DeepSeek Harness(DSH)Web GUI 打造的对话成本追踪插件——价格快照锚定的逐轮成本(感知峰值/闲时)、账户余额、花费标签页、每条回复成本小标签,以及带流式实时估算的头部胶囊。每一步的成本、价格档位与快照版本都只计算一次——锚定到该用量事件自身时刻生效的价格快照,此后永不重算——因此后续价格变动绝不会改写已写入的对话记录。
- Host 半区(
src/):DeepSeekGET /user/balance余额查询、持久化的快照锚定价格簿、sessionCost投影与不读价格簿的sessionCostIndex消息索引、子代理成本聚合,以及带信任围栏的/cost-meter路由。 - Client 半区(
src/client/):输入框下方读数、花费标签页、每条回复成本小标签、头部胶囊,以及插件配置页(设置 → 插件)——内置简体中文与英文。
安装
本插件已发布到 npm:@gamegeek-saikel/dsh-cost-meter,以官方 DSH 插件 bundle 形态交付(单个 cordis.patch.yml 行同时挂载 host 与浏览器两半)。
通过官方 DSH CLI(npx 方式,无需全局安装)装入 web profile:
npx @deepseek-ai/dsh plugin --profile web add @gamegeek-saikel/dsh-cost-meter
上面装的是 npm 的 latest 标签,它跟随当前 DSH 发布线。本插件与 DSH 使用同样的两条 npm 通道,而每个构建只能在它对应的那条 DSH 发布线上运行,因此请按你的运行时选择通道:
| npm dist-tag | 对应 | 安装命令 |
|---|---|---|
latest |
当前 DSH 发布线 | dsh plugin --profile web add @gamegeek-saikel/dsh-cost-meter |
next |
下一条 DSH 发布线 | dsh plugin --profile web add @gamegeek-saikel/dsh-cost-meter@next |
alpha |
alpha 构建 | dsh plugin --profile web add @gamegeek-saikel/dsh-cost-meter@alpha |
用 npm dist-tag ls @deepseek-ai/dsh 可查看各条通道对应哪个 DSH 版本,用 npm view @gamegeek-saikel/dsh-cost-meter dist-tags 查看各条通道对应哪个插件版本。DSH 运行时会拒绝加载对等依赖不匹配的 bundle,因此选错通道会直接安装失败,而不会把插件装成半可用的状态。
然后启动:
npx @deepseek-ai/dsh web
如果已全局安装 DSH CLI,也可以使用 dsh 代替 npx @deepseek-ai/dsh。安装到其他 profile 时,把 web 替换成你的 profile 名称即可。每个已发布版本都声明并已验证兼容上表所列对应通道的 DSH 发布线。开发环境要求 Node ^22.19.0 || >=24.0.0 与 pnpm 11.7.0。
概述
DeepSeek 的价格随时间变化(官方价目表、USD→CNY 汇率、2026-08-17 上线的峰值/闲时分时计价,以及 2026-09-10 的模型改名——Flash 列更名为 deepseek-flash 并下调为 V4.1-Flash 价),而一次对话跨越很多轮,且每轮都含缓存命中、缓存未命中、缓存写入与输出等 token 桶。若按"当前价格"重算成本,每次价目变动都会让历史记录漂移。
Cost Meter 用只追加的价格簿解决这一问题:每次价格/汇率/分时表变化都会开启一个新的不可变 PricebookSnapshot(单调 version、effectiveAt),每个用量事件锚定到其自身时刻生效的快照。结果是一个只增长、永不改写的不可变逐步成本账本。流式实时估算明确标注为"估算"——因为它使用当前价格;一旦该步结算,即被精确的锚定值取代。
关键性质
| 性质 | 值 |
|---|---|
| 成本锚定 | 只追加价格簿快照;步成本在事件自身时刻只计算一次 |
| 价格来源 | 手动覆盖 > 官方价格页 > 内置回退 > OpenRouter(仅回退,USD→CNY)> 无 |
| 官方页适配 | 解析当前 2026-09-10 版中英文页面(deepseek-flash / deepseek-v4-pro 两列、每个 token 桶行内的空闲/高峰单元格,以及英文 UTC 时段),同时兼容此前的合并表与旧版分表;已下线的 deepseek-v4-flash、deepseek-v4-flash-vision-exp 不再有独立列,按页面说明直接以 Flash 价格计费;页面不再提供旧单价表时继续用内置历史单价锚定 single |
| 峰值定价 | 2026-08-17 00:00 北京生效;高峰窗口仅周一至周五,且不含中国法定节假日(中英文页面时区可能不同,缺省 09:00–12:00 / 14:00–18:00 北京),因此周末、法定节假日全天及其余时段均为半价闲时 |
| 成本公式 | 未命中输入 + 缓存命中(命中价)+ 缓存写入(按未命中输入价计)+ 输出,每百万 tokens,CNY |
| 账户余额 | 官方 GET /user/balance,缓存 60 秒,单飞请求,路由带信任围栏 |
| 子代理支持 | 沿 subagents.listDescendants 枚举本会话持久子代理树(子代理再派生的孙代理、已结束或已冷启动的子会话都计入,无层数上限);账本优先取常驻会话的投影,未常驻的经 sessionQuery.readSession + sessionProjections.restore 从其持久日志冷读——因此主机重启后,旧会话的历史子代理花费同样会被补算;未挂载该服务时回退到活跃代理树 BFS |
| 对话总花费 | 主会话 + 全部后代子代理(任意层数);主会话自身账本尚未就绪时仍展示子代理合计 |
| UI 表面 | 输入框读数 · 花费标签页 · 回复小标签 · 头部胶囊(实时估算)· 插件配置页 |
| 本地化 | 简体中文(键源)+ 英文 |
| 复杂度 | 全同步折叠;经内存镜像 O(1) 查价 |
用法
安装后,插件贡献五个浏览器表面(默认显示简体中文文案):
| 表面 | 插槽 | 说明 |
|---|---|---|
| 输入框下方读数 | conversation.composer.dock |
锚定的本会话花费 + 账户余额,每分钟刷新;悬停查看分类明细与快照信息 |
| 花费标签页 | conversation.view |
全对话总花费(主会话 + 任意层级的子代理)、分类小计、带层级的子代理列表与逐回复锚定账本 |
| 每条回复成本小标签 | conversation.chat.assistant-actions |
单条已定稿回复的锚定成本,做成与官方「用量」「用时」完全同形的统计胶囊(28px 药丸、悬停底色、aria-expanded 展开锚定在触发件上方的对话框);位置收在统计串末:在「用量」「用时」之后、末尾时刻文本之前,间距沿用行自身的 gap;按计价档位着色(闲时绿、高峰红);对话框列出三类计费、档位与倍率、模型与快照版本;插槽只给出消息 id,由 sessionCostIndex 投影解析为账本坐标(无价格时显示 —) |
| 头部胶囊 | conversation.session.header.utilities |
锚定总花费;流式中显示 预计 ¥x.xx(估算);点击展开详情面板 |
| 插件配置页 | plugins.row.config |
设置 → 插件 中 cost-meter 行自己的配置页(DSH 0.2.0 以 <包名>#<行 id> 为键托管插件自带配置):按模型覆盖价、OpenRouter 别名、节假日日历的额外休息日与工作日、缓存折扣、汇率模式、开关与立即刷新。可编辑字段即 schema 中标记 volatile() 的字段——部署类字段(端点、凭据引用、刷新周期、可信主机、历史上限)仍在 profile patch 中手工维护,这正是 DSH 配置投影能够写入的边界 |
/cost-meter 宿主路由通过 GET 提供余额快照、价格簿视图与子代理合计;通过 POST({"action":"refresh"})执行手动刷新。与 /api 围栏一致,路由只应答 Host 头为回环地址或已声明可信主机的请求——这是防 DNS 重绑定的安全校验。
价格簿与快照锚定
价格簿(src/pricebook.ts)是持久的定价源,持久化在 pricebook 存储域全局槽上:
- 优先级链——按规范模型键(
provider/model、裸模型名,或 DeepSeek 系模型的flash/pro定价键):手动覆盖 > 官方页面 > 内置回退 > OpenRouter(仅回退,USD→CNY,缓存读按配置折扣)> 无。 - 快照选取——
snapshotForTime取effectiveAt <= 事件时间的最新快照(安装前的会话一次性锚到首个快照)。 - 峰值/闲时——2026-08-17 上线前所有步按单一价目计费;上线后按事件自身时刻与该价格簿页面的时段表选档(中英文页面各自解析自己的高峰窗口,英文新版为 UTC,抓取失败时回退到北京 09:00–12:00 / 14:00–18:00,其余闲时)。官方页面限定高峰仅周一至周五且不含中国法定节假日,因此时区表内的周六、周日全天为闲时,法定节假日同样全天闲时——即便在英文页面的 UTC 窗口下,节假日也按北京日历日判定。日期取自国务院办公厅通知,转录在
src/holidays.ts(2026 年,依据国办发明电〔2025〕7号);尚未覆盖的年份回退到「周一至周五」原规则,可用设置页的休息日/工作日清单在不发版的情况下补齐。调休来的周末工作日仍按闲时计(因为页面写的是周一至周五),若要按高峰计,把它们列进工作日清单即可。新版合并表没有旧单价列时,single继续锚定内置历史单价;页面若有独立旧表,则优先用它。每步的档位在折叠时锚定一次,逐回复卡片与回复小标签永远显示该轮对话当时被计价的档位,而不是查看时刻的档位。 - 不可变账本——
sessionCost投影(src/session-cost-projection.ts)把request/header(模型)与携带用量的事件折叠为逐步记录;同一 (turn, step) 的第二次用量样本替换第一条(同一步终结,而非重新计价),总计以 O(1) 增量维护。配套的sessionCostIndex投影(src/session-cost-index.ts)把每条已定稿助手消息 id 映射到其账本坐标;它不读价格簿、不算成本,因此折叠它绝不会重新计价任何会话。
项目结构
src/
index.ts # Host 入口:apply() 装配、余额、路由、信任围栏
types.ts # wire/公共类型 + 投影映射合并
pricing.ts # 官方价格页解析、峰值定价、北京时段
pricebook.ts # 只追加快照、优先级链、存储域
session-cost-projection.ts # sessionCost 投影(不可变逐步账本)
session-cost-index.ts # sessionCostIndex:消息 id → 账本坐标
holidays.ts # 中国法定节假日日历及其部署覆盖项
subagent-cost.ts # 子代理成本聚合(持久子代理树 + 活跃代理树回退)
invariant.ts # 路由释放对称性 invariant 伴生插件
client/ # 浏览器半区:5 个插槽组件 + 数学/格式化/本地化
shared/
tsdown.client.ts # 共享 tsdown 预设(CSS Modules、模块表、纯度门)
web-platform.ts # 浏览器平台模块清单
tests/ # 封闭式 vitest 套件(网络全部 stub)
cordis.patch.yml # web profile 插件行(同时挂载两半)
开发
pnpm install
pnpm typecheck # tsc -b(仅 src)
pnpm test # vitest run(封闭式,网络 stub)
pnpm build # tsc -b && tsdown(lib/ + lib/client.js)
测试套件完全离线:价格页 HTML、OpenRouter 模型目录与汇率接口全部 stub。覆盖:信任围栏、余额解析、价格簿优先级链与快照选取、不可变账本折叠(含同一步替换与按事件时间选峰值/闲时档)、子代理聚合(持久子代理树的嵌套/冷会话/失败回退,以及真实 SessionStore + 投影注册表上的多层链路),以及客户端表面(jsdom)。
发布通道
推送 v* 标签后由 .github/workflows/publish.yml 发布。标签决定 npm dist-tag,而这不只是记账问题:社区市场安装的是不带版本号的包名,也就是 latest 指向的那个版本,直接装进访客的运行时。DSH 同时并行两条发布线(@deepseek-ai/dsh 把当前线放在 latest、把下一条线放在 next),而插件版本只能在它的 @deepseek-ai/dsh* 对等依赖所接受的那条线上运行,因此 scripts/dist-tag.mjs 会用这些依赖范围去比对 registry 上 DSH 自己的发布线,据此选定通道:
| 版本 | 通道 |
|---|---|
接受 DSH latest 线 |
latest |
只接受 DSH next 线 |
next |
带 - 先行版本后缀 |
alpha |
node scripts/dist-tag.mjs pairs 会打印所有已发布版本的归属表;node scripts/dist-tag.mjs reconcile 会把每个标签重新指向支持它的最新版本,同时修正早期发布流程写错的标签(.github/workflows/dist-tags.yml 可按需单独执行同一套 reconcile)。
文档
src/pricing.ts、src/pricebook.ts、src/session-cost-projection.ts、src/session-cost-index.ts、src/holidays.ts——解析、锚定、节假日日历与账本契约的详细模块注释README.md— English version
许可证
本仓库(源码、测试、README 与 DSH 插件 bundle 形态)以 MIT License 授权——见 LICENSE。
Copyright (c) 2026 Saikel-Orado-Liu aka GameGeek-Saikel