← 返回列表
⚠ 装前注意
description: "在 DSH Web 客户端底部状态条的 token 用量右边显示本会话花费,单价由用户按…
基本兼容但装前注意:npm 同名包「dsh-cost-meter」归属 han-1413141/dsh-cost-meter,装到的可能不是本插件 · 最近上游提交 2026/9/11 · 已提供中文文档
DSH Web 客户端的会话支出:一个统计行胶囊,使用用户配置的按桶单价为持久化的 tokenUsage 投影定价。
综合分
28.9
GitHub 分
28.9
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add Nanako660/dsh-cost-meternpm 同名包「dsh-cost-meter」归属 han-1413141/dsh-cost-meter,装到的可能不是本插件,改用 GitHub 源安装
信任档位:已验证本站已于 0 天前真实安装成功
- 是什么
- dsh 原生插件 · tool
- 装得上吗
- 本站已真实安装成功(非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 15 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/25
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/21(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查⚠ 装前注意
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-cost-meter @ 1.7.35
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
npm 同名包「dsh-cost-meter」归属 han-1413141/dsh-cost-meter,装到的可能不是本插件
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/24 00:05:21
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-settings用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成description: "在 DSH Web 客户端底部状态条的 token 用量右边显示本会话花费,单价由用户按 token 桶配置。"
kind: "package-reference"
dsh-cost-meter
在底部状态条的 token 用量右边显示本会话花费,点开有分桶账单,单价由你自己配置。
它是 @deepseek-ai/dsh-token-meter 的纯消费者——不计量、不碰模型请求、不写会话日志,只是把已有的
tokenUsage 投影乘上你填的单价。
装上之后那一行是:
⬤ 4 轮 68 步 · 191 tok/s ⬤ 25.7M tok · 缓存命中 99% ⬤ ¥13.974
三个 pill 都可点开详情面板(前两个与 ui-chat 原版一致,第三个是分桶账单)。
目录
- 为什么不需要改 Host 的计量本体
- 安装
- 配置单价
- 卸载
- 实现要点
- 兼容性与版本策略
- 变更记录
- 已知限制
- 开发
- 验证状态
- 许可
为什么不需要改 Host 的计量本体
DSH 底部的状态条(4 轮 68 步 · 191 tok/s · 5.9M tok · 缓存命中 98%)由 @deepseek-ai/dsh-client-ui-chat
的 StatsPills 渲染,它注册在 conversation.composer.dock 这个 list 槽里,只做一件事:读两个 Host 投影。
| 屏幕片段 | 来源 |
|---|---|
| 4 轮 68 步、191 tok/s | sessionStats 投影(全日志折叠,dsh-session-stats) |
| 5.9M tok、缓存命中 98% | tokenUsage 投影(dsh-token-meter) |
tokenUsage 的 wire 值正好是四个互不重叠的计费桶:
{ uncachedInputTokens, cacheReadTokens, cacheWriteTokens, outputTokens }
其中 uncachedInputTokens = usage.inputTokens(缓存未命中的 prompt 输入),缓存读取与缓存写入各自独立。
所以花费就是一次乘加:
cost = (uncached·P_in + cacheRead·P_read + cacheWrite·P_write + output·P_out) / 单价分母
dsh-llm 的模型元数据(LlmModelInfo)里没有任何价格字段,llm-pi-ai 与 router 目录也不提供价格,
所以单价只能由用户配置——这正是本插件唯一新增的东西。
安装
两条路径选一条,不要混用:dsh plugin add 走 pnpm,之后任何一次 pnpm install 都会把手工复制进去的
目录当作多余包清掉。
A. 官方路径(pnpm / GitHub)
dsh plugin --profile web add github:Nanako660/dsh-cost-meter
它把参数转发给 profile 目录里的 pnpm,所以 $DSH_HOME\profiles\web\package.json 会多一条依赖,
包本体(以及它的 @deepseek-ai/schemastery 依赖)落到该 profile 的 node_modules 下,loader 从那里解析。
装完包还要加一行组合(pnpm 只装包,不改组合)。把下面这段追加到
$DSH_HOME\profiles\web\cordis.patch.yml:
dsh-cost-meter
- insert:
- id: cost-meter
name: dsh-cost-meter
config:
currency: ¥
unit: per-million
input: 0
cacheRead: 0
cacheWrite: 0
output: 0
decimals: 3
showSavings: true
。
两条路径共同点
web profile 的 patchReload: live 会让 Host 热加载那一行,不用重启;浏览器刷新一次页面
即可拿到新的客户端 bundle。
自检
powershell
1. 行是否进入组合树(无警告且出现 - id: cost-meter 即正确)
dsh --profile web --dump-config | Select-String cost-meter
2. profile 能否解析两个半侧、Host 半能否 import、行 config 能否过 schema
node test\verify-install.mjs
注意 http://127.0.0.1:3080/plugins/... 不能用来自检:未带启动 URL 里那个认证凭据的请求一律 404
(连内置插件的 bundle 也一样)。
配置单价
设置 → 插件 → 插件配置,卡片「花费金额(估算)」:
| 字段 | 含义 |
|---|---|
| 未命中输入 | uncachedInputTokens 单价 |
| 缓存读取 | cacheReadTokens 单价(命中价) |
| 缓存写入 | cacheWriteTokens 单价;DeepSeek 侧恒为 0,留 0 即可 |
| 输出 | outputTokens 单价 |
| 货币符号 | 显示前缀,默认 ¥ |
| 计价单位 | 每百万 / 每千 token |
| 金额小数位 | 0–6,默认 3 |
| 同时显示缓存省下的金额 | 花费面板里附一行反事实节省(cacheRead × (P_in − P_read)) |
单价保存在 ~/.dsh/settings.yaml 的 cost-meter: 段,随时可「重置为默认」清空用户层。
四个单价全为 0 时,花费 pill 显示「花费未配置」(悬停给出配置路径)而不是 ¥0.000——不编造金额是有意为之。
卸载
powershell
A. 官方路径
dsh plugin --profile web remove dsh-cost-meter
B. 脚本路径(同时移除 patch 里的整段标记块与安装目录)
pwsh -File install.ps1 -Uninstall
两条路径都要手动删掉 patch 里那段标记块,然后刷新页面。删掉标记块会立刻恢复 ui-chat 原本的状态条。
实现要点
| 位置 | 作用 |
|---|---|
| lib/index.js | 唯一的 Host 侧职责:用 settings.installSection 注册 cost-meter 命名空间(可选挂载,没有 settings provider 时回退到组合配置) |
| lib/client.js | 手写的 lazy-CJS 客户端 bundle:接管状态条那一格(三个 pill)+ 价格卡片 |
| test/smoke.mjs | 走真实的 window.__ModuleLoader__ 信封做冒烟测试(React 用垫片,因为部署只装了预构建前端) |
| test/verify-install.mjs | 安装后复刻 loader 的解析路径,验证两个半侧可解析、Host 半可 import、行 config 过 schema |
客户端 bundle 为什么是手写的:@deepseek-ai/dsh-client-modules 把每个声明 dsh.client 的包按
lib/client.js 原样服务并在页面里求值,而产出该信封的构建设置(packages/client/tsdown.client.ts)
不是已发布包,仓库外的插件只能自己写下这个信封。factory 里可以 require 外壳的平台 seed 表:
react、react/jsx-runtime、react-dom、react-dom/client、@deepseek-ai/cordis、
@deepseek-ai/dsh-client-store、@deepseek-ai/dsh-client-ui-slots、
@deepseek-ai/dsh-client-ui-primitives、@deepseek-ai/dsh-client-ui-dockkit。
这些都是基座内的请求,所以 dsh.client.external 不需要声明任何东西。
两个注册点(都由实测核对过槽位协议):
conversation.composer.dock list, session → 需要 id;本插件用 id:"stats" + priority:-1 影子接管该格
settings.plugin.item keyed, root → 需要 key(= settings 命名空间 "cost-meter")
价格读取走客户端设置作用域 ctx.settingsScope.bind({ namespace: 'cost-meter' }),
经 uSES 订阅;tokenUsage / sessionStats 经会话作用域 slot 的标准 props useProjection 读取。
两者变化都会立即重渲染,保存单价后无需刷新。
为什么是"接管整格"而不是"再加一个 pill"
底部状态条那一行不是 conversation.composer.dock 的容器,而是 StatsPills 自己的根节点
(dsh-client-ui-chat)。dock 的父容器是 InputBar.root,样式为
flex-direction:column; align-items:center —— 所以往 dock 里再加一个条目只会竖排掉到状态条下面,
不可能出现在 token 用量右边。
要做到"token 用量右边",唯一受支持的机制是 list 槽的影子注册:register({ id: "stats", priority: -1 }),
priority 更低者渲染(槽核心的校验信息原文就是 "register at a different priority to shadow it (lowest renders)"),
于是这一格由本插件渲染。代价是必须把原来的两个 pill 和它们的面板一起复刻:
- TimePill(轮/步 + tok/s)与其"会话统计"面板;
- UsagePill(总 tok + 缓存命中率)与其"Token 用量"面板;
- 全部格式化函数:formatTokens / formatExactTokens / formatTokensPerSecond /
formatCacheHitPercent(含"部分命中不许四舍五入成 100%"那段二分舍入)。
面板的定位与关闭复用平台 seed 里的 useAnchoredPosition / useDismissOnOutsidePointer
(导出缺失时退回本地实现),几何常量与 CSS 逐字照搬 ui-chat 的 stat-dialog。
两个 pill 的文案通过 ctx.locale.bind("chat") 取部署自己的字典,因此跟随当前语言;
locale 服务缺失时退回内置中文副本。
因为这一格现在由本插件独占,行外面包了一层 RowErrorBoundary:万一样式行抛错,会退回一行纯文本统计
(自己重新读投影算数),保证状态条不会整行消失。
复刻部分的来源与许可见 THIRD-PARTY-NOTICES.md。
兼容性与版本策略
本插件的版本号独立于 DSH 的版本号,但它依赖 DSH 的槽位协议、投影键与服务名,这些都不是稳定 API。
| dsh-cost-meter | 已核对过的 DSH | 说明 |
|---|---|---|
| 0.1.0 | 0.1.5-rc.1 | 首次发布。槽位协议、tokenUsage/sessionStats 投影键、settingsScope 契约都按该版本逐一核实 |
peerDependencies 里写了这个区间(@deepseek-ai/dsh-settings@^0.1.5-rc.1、@deepseek-ai/cordis@^4.0.2),
装包时就能看到不匹配。
版本号怎么升:
- PATCH:只改文档、注释、内部整理,行为不变。
- MINOR:新增配置项或新的展示内容,旧配置继续有效。
- MAJOR:任何要求不同 DSH 版本的改动——槽位协议变了、投影键改名了、服务改名了。
这类改动不会让插件报错,只会让 pill 静默消失,所以必须靠 MAJOR 提示升级者。
0.1.0 不算稳定版:它接管了 ui-chat 的一个单元格,上游改动随时可能让这份复刻失效。
升级 DSH 后请重跑自检两条命令。逐版变更见 CHANGELOG.md。
已知限制
- 会话级聚合没有路由维度:一个会话里换过 provider/模型时,整会话总价会按同一套单价计算而失真。
单路由会话不受影响;要精确需按 turn 折叠 deriveTurnTokenUsage(带 routes)。
- 只统计 provider 上报的用量:中断或未上报用量的步不计入,所以这是「账本估算」而非账单对账。
- cacheWriteTokens 的语义随供应商而变:DeepSeek 恒为 0;Anthropic 风格缓存写入是独立加价档,需要单独填价。
- 非 loopback 访问时没有可持久化设置通道,卡片会提示这一点,此时单价只随组合配置生效。
- 升级 DSH 不会动这个包:它住在 profile 里而不是 DSH 安装目录;但 0.1.x 的槽位/服务 API
若变动,需要跟着更新 lib/client.js。
- 状态条那一格由本插件渲染(影子接管)。好处是花费 pill 就在 token 用量右边、三个 pill 共用一套
面板样式与互斥开合;代价是 ui-chat 的 StatsPills 被遮住,上游以后改那两个 pill(新桶、新文案、
新面板行)不会自动出现在这里,需要同步更新 lib/client.js 里的复刻。想彻底放弃接管就把注册改成
{ name: "conversation.composer.dock", id: "cost", order: 10 }(去掉 priority),花费 pill 会回到
状态条下面一行,其余功能不变。
- Host 半的包清单会被上报:DSH 会把存活 Loader 包的 {name, version} 随每次官方 API 请求发给
DeepSeek 用于诊断,所以 package.json 里的 name/version 必须是真实且非空的(格式错误的 manifest
会让请求准备直接失败)。
开发
powershell
npm run check # node --check 两个半侧
npm test # 客户端 bundle:信封、接管注册、三个 pill、两个复刻面板、花费面板、各种降级态
npm run test:install # 安装后:profile 能否解析并 import 两个半侧、行 config 是否过 schema
smoke.mjs 覆盖:包信封与导出面、接管注册的 id/priority/order、三个 pill 的渲染与先后顺序、
两个复刻面板与花费面板的内容、四桶计价算术、空会话不渲染、缺投影席位不渲染、未配置单价的状态、
错误边界的兜底、以及 react-dom/primitives 缺失时的降级渲染。
verify-install.mjs 复刻 loader 的解析方式(createRequire 锚在 profile manifest 上,与
cordis-plugin-loader 用 profile 目录作 parentURL 一致),确认 dsh-cost-meter、dsh-cost-meter/client
与 @deepseek-ai/schemastery 都能从 profile 解析出来。
三个容易踩的坑(都已在代码里规避)
- cordis.patch.yml 里的新增行必须包在 - insert: 里。裸 - id: x 是「按 id 覆盖既有行」,
目标不存在时只打一行 patch: entry "x" not found 然后跳过——静默不生效。
语义来自 dsh-app-boot 的 applyEntryPatches。
- 清空补丁文件会留下 null。文件只剩注释时 YAML 解析出 null 而不是空列表,
所以 -Uninstall 在移除后若发现文档已无条目,会补回 [] 哨兵。
- list 槽同 id 同 priority 会直接抛错,不是静默覆盖:already has an entry with id "stats" at
priority 0 — register at a different priority to shadow it。接管必须显式给出不同的 priority。
验证状态
已跑通:
- 行已进入组合树:dsh --profile web --dump-config 无警告,cost-meter 出现在 user patch 层;
- profile 能解析两个半侧并 import Host 半(apply / Config / 命名空间常量齐全),行 config 过 schema;
- 冒烟测试全绿(接管注册、三个 pill 顺序、两个复刻面板 + 花费面板的内容、全部降级态);
- 安装目录里的 lib/client.js、lib/index.js 与仓库里通过冒烟测试的字节完全一致(SHA256 比对)。
未验证(需要浏览器):运行中的页面是否真的把花费 pill 画在 token 用量右边、三个面板能否点开、
设置卡片能否保存。若刷新后这一行不对,先按卸载删掉那段标记块回滚(会恢复 ui-chat 原本的状态条)。
许可
MIT,Copyright (c) 2026 Nanako660。见 LICENSE。
本包复刻了 @deepseek-ai/dsh-client-ui-chat 的展示层代码(同样 MIT),来源与声明见
THIRD-PARTY-NOTICES.md。