dsh-bottom-cost
Verifieddsh-bottom-cost · v0.5.2 · MIT · Web UI
Per-turn session cost chip in the composer stats row: each turn's spend, with the conversation total split into cache-hit and cache-miss (CNY), priced from an official price table that refreshes on demand. · 输入框下方统计栏里的会话费用胶囊:逐轮列出每轮花费,并把总额拆成缓存命中与未命中两笔(CNY)
Install
dsh plugin add dsh-bottom-cost Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-bottom-cost
给 DeepSeek Harness 加一颗会话费用胶囊:它坐在输入框正下方那条统计栏里,和内置的统计胶囊同一行,一眼回答「这段对话花了多少钱」与「最近一轮花了多少钱」,并把费用拆成命中缓存与未命中两笔。

安装
方式一:在 DSH 界面里装(最简单)
- 侧栏打开插件 → 添加插件;
- 二选一填进去:
- 包名
dsh-bottom-cost—— 到处都能装,包括官方桌面客户端(它只支持 npm 源); - 仓库地址
https://github.com/LanFeng97/dsh-bottom-cost—— 在dsh web上可用;它要经 codeload 下载 tarball,网络抖动会失败;
- 包名
- 点安装,再按它的提示重启 DeepSeek Harness(关闭当前
dsh进程后重新运行,例如dsh web)。
宿主半区是 Node 模块,只重载配置不会被导入,所以这一步重启不能省。重启后打开界面就能看到胶囊,不需要再刷新页面。
以后的更新是显式的。 安装会钉住精确版本(profile 里会写成 "dsh-bottom-cost": "0.5.1"),所以新版本要你在插件管理里点更新才会生效——它不会在你不知情的时候自己变。
方式二:让你的 AI 帮你装
把下面这一整段复制给任意一个能读写你电脑的 AI(DSH 里的 agent、Claude Code、Codex 都行),它会自己完成克隆与安装:
帮我安装 https://github.com/LanFeng97/dsh-bottom-cost 这个插件到我的 DeepSeek Harness:
克隆仓库,运行 node tools/install.mjs,装好后告诉我需要重启 DSH 才能生效。
方式三:从插件市场搜(上架后)
DSH 插件以包的形式分发;在 dshmarket 里搜索 dsh-bottom-cost。上架之前请用方式一或方式二。
方式四:从源码安装(开发者)
要改代码、或要装到非默认 profile 时用这条:
git clone https://github.com/LanFeng97/dsh-bottom-cost
cd dsh-bottom-cost
node tools/install.mjs # 复制进 profile 的 node_modules,并追加一行 loader 行
node tools/install.mjs --dry-run # 只打印要做什么,不写任何文件
node tools/install.mjs web # 指定别的 profile(默认 desktop)
脚本是幂等的,git pull 之后再跑一次即可同步更新;它按 $DSH_HOME、~/.dsh 的顺序解析 DSH 家目录,与 harness 本身一致。装完同样需要重启。之后改 lib/client.js 只需刷新页面,改 lib/index.js 仍需重启。
本插件零运行时依赖(形状校验用自带的 lib/shape.js,约 90 行),所以这条路径不需要联网装任何包。这里用复制而不是目录联结也是因此:联结会被 Node realpath 回克隆目录,万一将来引入裸三方导入,装载阶段就会在那里找不到它。
装不上 / 卸不掉?(先看这里)
桌面客户端只能装 npm 源。 如果你用的是官方桌面端,往「添加插件」里贴 GitHub 地址可能装不上——这不是网络问题,而是客户端的安装边界(它自己的提示原话就是「这个桌面客户端只能安装已发布到 npm 的插件」)。改用 npm 包名安装。
网络不好时 GitHub 源容易超时。 「添加插件」背后是 pnpm:它先把 owner/repo 解析成具体 commit,再从 codeload.github.com 下载 tarball,而解析那一步有 6 秒超时。网络抖动就会失败,重试通常能过。
两条安装路线不要混用(重要)。 用「插件管理 / 插件市场」装过之后,不要再跑 tools/install.mjs(也别让 AI 跑它),反过来也一样。原因:脚本会往 profile 的 cordis.patch.yml 追加一行 loader 行,而插件管理自己也声明这个组件——同一个组件被两层声明后,插件管理会拒绝停用与卸载,报的就是:
卸载失败:其他配置仍在使用这个组合包的组件,请先停用它们
这种情况下那个「停用」开关也压不住另一层,所以你会看到停用后功能照旧、重启后依旧如此。
遇到上面的报错怎么办(按顺序):
打开
<DSH 安装目录>/dsh/profiles/<profile>/cordis.patch.yml,找到这样一段(注释行 +insert三行)并整段删掉:# dsh-bottom-cost: ... - insert: - id: ui-session-cost name: 'dsh-bottom-cost'完全退出 DSH 再启动(不是刷新页面);
回到「插件管理」,这时停用与卸载都能正常点;
若改报「当前 profile 的 patch 无法唯一定位这一项」,说明还有第二处声明——把该 profile 的
cordis.patch.yml内容发我,我按行给处置。
一行自查(在 <DSH 安装目录>/dsh/profiles/<profile>/ 下):
grep -n "dsh-bottom-cost" cordis.patch.yml package.json
package.json 里有它 = 插件管理装的(正常);cordis.patch.yml 里也有它 = 两层声明,就是上面那个问题。
怎么读这个界面
看截图:最下面那一行就是输入框下方的统计栏——◎ ¥5.294 · ¥0.9230 是本插件,它与内置的 15 轮 388 步 · 228 tok/s(会话统计)、147M tok · 缓存命中 99%(Token 用量)以及最右边的上下文占用环排在同一行;上面那块是展开后的面板。
点面板里的第 N 轮会跳到对话中的那一轮:它只读地驱动官方右侧那颗「轮次导航」轨道——已加载的轮次直接落位,还没加载的轮次由官方先取回更早的分页再落位。定位不到时,面板底部会给出说明,不会静默失败。
每一轮的轮次号右侧会显示该轮用的是哪个模型(v4-pro、v4-flash……,只削掉 deepseek- 前缀;一轮里混用了多个就并列显示,悬停可看完整 id)。
标题行最右边的小太阳(或月亮)是明暗开关:它只切换本插件自己的内容——面板与底部那颗费用胶囊都会立刻换成另一套配色,应用的全局主题不受影响。图标表示当前模式(太阳=浅色、月亮=深色),配色取自官方主题的两套定义,所以两种模式下都与 DSH 其他界面同一套颜色,只是与本插件之外的界面相反。胶囊切到与外部相反时,会自动带上一层主题底色——否则近白的字落在浅色的统计栏上会看不清。
统计栏里的胶囊:
◎ ¥2.922 · ¥0.4877
↑ 左 ↑ 右
当前会话的总花费 本轮(最近一轮)的花费
- 左边是这段对话累计花了多少;右边是最近一轮花了多少。两个数字都随对话推进实时更新。
- 花费为零、或这段对话还没有产生过计费轮次时,胶囊不显示——与内置统计胶囊「无内容即不渲染」的行为一致。
点一下胶囊,面板贴着你向上展开:
- 顶部固定区:整段对话的总花费按「命中缓存」与「未命中」拆成两笔(截图里的
¥1.609与¥1.313)。这两个数加起来永远等于胶囊左边那个总额——总 = 命中 + 未命中是构造上成立的,不是四舍五入碰巧对上的。 - 下面的滚动列表:每一轮的花费,每轮三行——总费用 / 命中 / 未命中(截图里的第 7、8 轮)。默认停在最新一轮,向上滚即可依次回看更早的轮次。
- 滚动区高度恰好是两块轮次——你要看的就是「最近这一轮」和「上一轮」,不需要为此把面板拉得很长。
右上角那颗「刷新」
它管的是计价用的价目表,不是重新统计你的对话:点击后宿主去抓官方中文价目页,解析出 12 个单价并逐项校验,然后把差异先列给你看(哪一项从多少变成多少)——你点「采用」才真正生效。这么设计是因为 DeepSeek 没有机读价目 API,只有人读文档页,解析天生可能出错;一次静默的错误解析会污染你看到的每一个金额。
面板第二行那条「价目:官方页 · 10/13 02:17」就是在告诉你当前用的是哪一份价目、什么时候抓的;显示「价目:内置表」则表示还没抓过,用的是随插件发布的内置表。
要不要经常点它? 不必。官方调价时点一次即可;点完采用后,这段对话的全部历史花费会立刻按新价重算(因为金额是浏览器按当前价目表现算的,历史里只存 token 事实),不会出现新旧两代价格混在一本账里的情况。
数字是怎么来的
只有 DeepSeek 官方路由有公开价目表,所以只有它们会产生金额:
| 命中费用 | 缓存读 tokens × 命中价 |
| 未命中费用 | (未命中输入 + 缓存写)× 未命中输入价 + 输出 tokens × 输出价 |
| 峰谷 | 北京时间周一至周五 09:00-12:00、14:00-18:00 为高峰(双倍价);周末与中国法定节假日全天空闲 |
| 按什么时刻计价 | 每次调用发生那一刻——取会话事件自带的时间戳,所以回放几个月前的历史也按当时的档位算,不会拿今天的价套旧账 |
| 其他 provider | 绝不猜成 ¥0:显示为未计价,面板底部给出未计价的调用次数 |
统计范围是当前会话自身的轮次。子 agent 是另一个会话,刻意不并入,所以胶囊上的数字与你看到的轮次严格一一对应。
是估算,不是账单
金额由 token 数与公开价目推算。插件不读你的余额、不碰凭据,也无法得知 DeepSeek 实际扣了多少。
deepseek-v4-pro 按它自己的官方价目计价
2026-09-14 曾计划下线 Pro,把它的请求按 V4.1-Flash 承接并计费;@linxin666/dsh-usage 据此设了一条时间栅栏,本插件早期也照抄了它(当时 README 里那段「档位存在争议」就是这么来的)。
官方随后决定继续提供 Pro、计费方式不变(Pro 严格按它自己的官方价目计费,与 Flash 分开)。因此 0.5.1 起删掉了那条栅栏:deepseek-v4-pro 的请求恒计在它自己那一行(未命中 4.5/9.0、输出 13.5/27.0),按Flash档估 的标记与汇总提醒也一并移除——它们的前提已不成立。
如果你从别处又看到"Pro 已被 Flash 承接"的说法,请注意那是 2026-09-14 之前的旧计划;不要再把栅栏加回来。
刷新价目表的完整流程
- 宿主抓取官方中文价目页(
api-docs.deepseek.com/zh-cn/quick_start/pricing,给人民币;英文页给美元,不用); - 解析那张表并校验全部 12 个单价——任何一个缺失或不合理,整份解析直接作废;
- 把差异列给你看,点 采用 才生效,也可以 放弃。
价目表只存在 <DSH_HOME>/dsh-bottom-cost/pricebook.json(原子写),重启后仍然生效;抓取失败(断网、超时、官网改版)会明确报出来并保留当前价目;首次启动的兜底始终是内置表。
能力边界
- 只有一次出网请求:抓上面那个公开文档页,且只在你点「刷新」时发生。除此之外它不把任何东西发出去。
- 只写一个文件:
<DSH_HOME>/dsh-bottom-cost/pricebook.json。 - 三条价目路由都是仅回环 + 同源校验(与本工作区既有 DSH 插件同一套围栏)。
- 宿主半区不读凭据、不写会话数据、不装定时器。
- 面板里的第 N 轮是只读地驱动官方的轮次导航:读取刻度按钮的
aria-label(含轮号)与aria-current,并调用刻度自己的点击;轨道整个不可用时回落到 transcript 行上的data-chat-turn锚点。本插件不注入节点、不改官方布局,也不写死任何构建哈希类名——但官方若改掉这些语义属性,跳转会失效,届时面板会如实提示定位失败。
为什么形状校验是手写的
DSH 的投影注册表向每个单元索取 stateSchema 与 wire.viewSchema,并且只对它们调用 .parse(@deepseek-ai/dsh-session-projection 里共 6 处;没有 safeParse、没有 optional、没有 refine)。这个契约是鸭子类型的,所以 lib/shape.js 只用约 90 行、零依赖地实现了本插件真正需要的七个谓词:object / string / 有限数字 / boolean / array / 枚举 / nullable。
另一条路是 zod(DSH 自己的 dsh-token-meter 就用它)。那条路不算错,但对本插件不划算:发布的包有 840 个文件 / 5.86 MB(哪怕只留 v4 ESM 运行时也有 111 个文件 / 886 KB),而本 README 首推的安装路径是复制式安装、不带依赖——要带上 zod 就只能往仓库里塞一大块第三方代码,或者让安装脚本联网跑 pnpm 去改写你 profile 的 package.json。手写让这条路径真正自足。
一处刻意比 zod 更严:NaN 与 Infinity 一律拒绝——它们一旦混进 token 或金额会静默污染累计值。另外,因为校验器是本仓库自己的代码,自测可以直接测它(zod 作为三方导入做不到这一点)。
实现要点
用官方扩展点,不做 DOM 注入
- 胶囊注册进内置 slot
conversation.composer.dock(order: 1;随包发布的stats两颗胶囊是order: 0)。该 slot 就是 输入框下方那条统计栏,容器是display:flex; gap:12px的横向行,因此胶囊是内置胶囊的同级兄弟——不用 DOM 插桩,也不怕官方重渲染。 - 面板复用
@deepseek-ai/dsh-client-ui-primitives的useAnchoredPosition与useDismissOnOutsidePointer,与内置统计弹层同一套,所以定位、夹取、点击外部关闭、Esc 的行为完全一致。 - 样式只走主题 CSS 变量(
--dsw-*),跟随你的主题而不是写死颜色。
token 事实通过会话投影传输
宿主注册一个会话投影单元(sessionCost),浏览器用 useProjection('sessionCost') 读。这白拿三件事:
- 历史回填:投影注册表会在首次触碰时把后注册的单元在内存日志上回放一遍,所以装上插件或重启 DSH 之后,当前对话里已经发生的轮次也被折进来——胶囊不会从 ¥0 开始。
- 持久化:状态搭 harness 的投影检查点缓存,插件自己不写数据文件。
- 推送而非轮询:值走会话控制流下发,没有定时器,也没有拉取循环。
分层,便于脱离 DSH 自测
| 文件 | 职责 |
|---|---|
lib/fold.js |
纯折叠:会话事件 → 按轮 token 事实。零依赖。 |
lib/pricing.js |
纯计价:峰谷时钟、模型→价目行判定、tokens→金额。零依赖。 |
lib/pricebook.js |
纯价目书:内置表、严格校验、官方页解析器。零依赖。 |
lib/projection.js |
薄适配:形状 schema + 客户端视图。 |
lib/pricebook-store.js |
抓取、暂存候选、采用、落盘。 |
lib/routes.js、lib/guard.js |
仅回环的 HTTP 翻译层。 |
lib/client.js |
胶囊与面板;按「事实 × 当前价目书」算钱。 |
自测
npm test # node tools/selftest.mjs —— 66 项,不联网
npm run test:live # node tools/live-check.mjs —— 抓真页面、解析、落盘、读回
npm run test:schema # node tools/schema-check.mjs —— schema ↔ 状态 ↔ 视图 一致性(从已安装副本导入)
selftest 覆盖峰谷与节假日例外、解析器(对着随仓库附带的官方页快照)、价目书校验、换一本价目书重算、按桶聚合、重放幂等、状态 JSON 安全、明细裁剪、以及客户端文案键集合。
selftest 覆盖峰谷与节假日例外、解析器(对着随仓库附带的官方页快照)、价目书校验、换一本价目书重算、按桶聚合、重放幂等、状态 JSON 安全、明细裁剪、客户端文案键集合,以及——因为校验器现在是本仓库自己的代码——投影 schema 本身(未声明字段被丢弃、类型不符按路径报错、NaN 被拒)。
test:schema 是另一种检查:它导入profile 里实际装着的那份副本,把 状态 → 视图 → schema 整条走一遍,因此同时验证「装上的文件能加载」与「viewOf() 与视图 schema 仍逐字段一致」。后者在开发中真的挂过一次,现在有专门的守卫。
兼容性
- DSH ≥ 0.2.0-rc.2(开发与验证均在 0.2.0-rc.2 上完成)。
- Node ≥ 20。
- 零运行时依赖:投影 schema 由插件自带的
lib/shape.js校验。
许可
MIT © 2026 LanFeng97。
有两处不是本插件原创,保留其上游署名:
lib/holidays.js—— 中国法定节假日日期,来自 bastengao/chinese-holidays-node(MIT)。lib/pricing.js的峰谷规则与价目行判定、lib/pricebook.js的内置表 —— 与 @linxin666/dsh-usage(Apache-2.0)同一套口径。
零运行时耦合
上面两处只是署名:规则与数据是抄进本插件源码的,本插件不 import dsh-usage,也不 import 任何 @linxin666/* 包。把 dsh-usage 卸载掉、或它升级/改名,本插件照常工作——反过来说,官方调价时这两份副本要各自更新(这就是「同口径」想表达的意思)。
零运行时依赖。 没有要顺带安装的东西,也没有要跟进同步的东西:投影 schema 来自插件自带的 lib/shape.js(理由见上文「为什么形状校验是手写的」)。
相关
- dsh-workspace-create-dialog —— 同一作者的姊妹插件,做「创建工作区」对话框。