@wingsky-1/dsh-provider-usage
多 provider 用量统计框架(v2 适配器契约):常驻胶囊 + 详情面板;内置 DeepSeek 官方(区间记账法推算每日用量 + 峰谷倒计时徽标,官方无用量接口也能算)与 OpenCode Go;其他数据源只需放入一个 mjs 适配器文件即可接入,设置页热插拔,密钥只留在宿主端。
安装
dsh plugin --profile web add @wingsky-1/dsh-provider-usage
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
@wingsky-1/dsh-provider-usage


DSH(DeepSeek Harness)Web GUI 插件:多 provider 通用用量统计框架(v2 适配器契约)。
聊天界面右上角常驻悬浮胶囊,展示当前模型 provider 的用量信息;点击展开详情面板。
内置两套适配器开箱即用——DeepSeek 官方(余额 + 峰谷倒计时徽标 + 每日用量推算)与
OpenCode Go(官方 /v1/usage 三窗口用量);其他任意数据源只需按 v2 契约写一个
mjs 适配器文件即可接入(设置页检测/添加/切换热插拔,见「适配器开发指南」)。
渲染在宿主端完成——适配器返回 HTML、客户端只做注入,密钥不进浏览器。
一键安装
dsh plugin --profile web add @wingsky-1/dsh-provider-usage
安装 / 卸载 / 更新后都需重启一次 dsh web(bundle 层只在启动时组合)生效。
核心优势
- 通用框架 + 开箱即用:一套 v2 适配器契约承载任意 provider;DeepSeek 官方与
OpenCode Go 两套适配器内置,装完即显示用量
- 接入任意数据源只需一个 mjs 文件:
fetchData/formatCapsule/formatPanel
三个导出即完成接入;设置页检测/添加/切换热插拔,改文件自动热更新
- 官方没有用量接口也能算:DeepSeek 内置适配器以区间记账法推算每日消耗
(纯消费区间 = 余额降幅,可与平台账单对账;充值独立列示不混算;异常区间不计),
余额折线充值时刻自动断轴平移,附峰谷倒计时徽标与 15 日用量柱形面板
- 密钥不出宿主:取数在宿主端执行,密钥只在宿主端持有与使用、不下发浏览器
(推荐凭据链 / env 注入;显式 apiKey 配置会随宿主配置落盘并以 0600 保护);
渲染输出双层净化(esc() 转义义务 + 结构化净化兜底),XSS 双重防线
- 历史可回溯、性能有兜底:按天分片 JSONL 落盘(0600)、超龄超量自动清理;
面板渲染进程内缓存 + stats 缓存 + 后台预热,数据未变时重复请求零重算
安装
前提:已安装 DeepSeek Harness 且 dsh web 可正常启动(未全局安装 dsh 见下方「未全局安装 dsh」)。
安装插件(add)
dsh plugin --profile web add @wingsky-1/dsh-provider-usage
卸载插件(remove)
dsh plugin --profile web remove @wingsky-1/dsh-provider-usage
更新插件(update)
dsh plugin --profile web update @wingsky-1/dsh-provider-usage
安装 / 卸载 / 更新后都需重启一次 dsh web(bundle 层只在启动时组合)生效。
未全局安装 dsh
若本机没有全局 dsh 命令,用 npx 临时拉起:
npx @deepseek-ai/dsh plugin --profile web add @wingsky-1/dsh-provider-usage
工作原理(v2)
宿主端(Node) 客户端(浏览器)
───────────────────────────── ─────────────────────
预热定时器(5min) ─┐
├→ getStats() 60s 轮询 /stats(取数前先复检
客户端轮询 ───────┘ │ Mutex 互斥锁 会话当前 provider,#71 自愈)
│ 60s 缓存 胶囊框架 ← capsuleHtml
│ 5s 取数超时 面板框架 ← panelHtml(/history,90s 兜底缓存)
↓
adapter.fetchData(ctx) ← 用户 mjs(apiEndpoint/staticPath/apiKey 注入)
↓
按天分片 JSONL 历史落盘 ──→ 面板渲染缓存全清(主失效)
↓
adapter.formatCapsule/Panel() → 净化 → HTML 下发
内置适配器 opencode-go-builtin(OpenCode Go 官方 /v1/usage 三窗口用量)与
deepseek-official-builtin(DeepSeek 官方余额 + 峰谷倒计时徽标,见下节)开箱即用。
provider 跟随语义(0.1.2 投影面,#383):切换会话即时刷新;会话内切模型经宿主
modelSelection 投影帧(control frame type:projection)实时推送、客户端切完即重拉;
信号缺失最坏场景由每次取数前的复检兜底自愈(#71)——最长一个轮询周期内收敛。
图解文档:完整的流程图 / 时序图(启动装配、/stats取数全链路、/history面板、自定义适配器注入三条路径与热更新、客户端交互、密钥解析链)见 [docs/architecture.md](docs/architecture.md)。
配置
键 · 默认值 · 含义
enabled · true · 插件开关
adapter · 无 · 用户适配器 mjs 路径(缺省用内置 opencode-go)
provider · opencode-go · 关联的模型 provider 名
staticPath · 无 · API 路径(注入 fetchData 入参,与 apiEndpoint 拼接)
apiEndpoint · 无 · API 基础地址(可选;显式配置优先于凭据链)
apiKey · 无 · 显式密钥(可选;缺省走凭据解析链,不进设置面板回显)
historyDir · <DSH_HOME>/dsh-provider-usage/ · 历史存储根目录
warmupIntervalMs · 300000 · 后台预热间隔(无客户端访问时保持历史连续)
cacheDurationMs · 30000 · 缓存新鲜度(毫秒,下限 5000;#198 由 60000 下调——峰谷徽标跨时段边界端到端翻转延迟 ≤95s = 宿主缓存 30s + 客户端轮询 60s + 渲染余量)
fetchTimeoutMs · 5000 · fetchData 强制超时(固定值,不可配置;#208 起 2s→5s,用户配置不生效)
autoReload · true · 热更新开关(编辑适配器文件后自动加载;默认开启,可显式 false 关闭)
maxAgeDays · 30 · 历史保留天数
maxSizeMB · 20 · 历史大小上限(MB,超限从最旧日文件删)
trendRetentionDays · 180 · 会话用量趋势聚合保留天数(#503;日切压实后按天留存,正整数上界 3650)
报告配置(historyDir/reports/config.json,设置页「报告」tab 承载)
键 · 默认值 · 含义
daily / weekly / monthly · 全关 08:00/09:00/09:00 · 三周期独立开关与触发时刻(weekly 另有 weekStartsOn 周一起点、monthly 另有 dayOfMonth 触发日)
provider / model · ""(跟随默认) · 报告生成所用模型路由(空串 = dsh 注册序首个)
reasoningEffort · 未设置 · 当前 exact model 的 DSH reasoning effort opaque ID;未设置时请求省略该字段并沿用 DSH 默认。设置值必须存在于该模型的能力响应中,否则在发起模型请求前 fail closed;档位顺序、名称与默认值不复制、不按 low/off 或数组末档推断
prompts · 三周期年报模板 · 三周期独立提示词({stats} 占位;#633 起默认模板含目录观察——目录名 basename、占比分母 totals.total、只报数字不解读目录内容;#662 起默认模板再含时段观察——钟点/时段档只可原样引用 byHour/byPeriod/peakHour 字段、禁行为脑补、禁与目录交叉关联;存量旧默认模板读时自动升级)
push.enabled · false · 生成完成后经 dsh-notifier 推送摘要(摘要仅周期/窗口/总量/调用数数值,不含项目路径)
directories · [](全部) · #633 目录范围:非空数组(目录 basename 列表,"all" 显式全选语义,至多 32 项)= 报告统计只呈现所选目录的目录分布;空数组 = 全部目录。影响报告生成统计口径(byDirectory 维度按所选目录过滤)
报告生成、推理等级与有界重试
- reasoning effort:客户端只展示并原样保存当前 exact model 的 DSH 能力响应;未选择时省略
reasoningEffort,显式 ID 在生成前按同一 exact model 校验。能力暂不可用时保留已有值并显示提示,不静默清空,也不回退到low/off。 - 预算与退避:初次报告调用之外最多自动 retry 5 次,
attempts=0..5;第 1 至第 5 次自动重试分别退避 1、2、4、8、16 分钟。只有可分类的 transient 与空输出(reasoning-only / 双空)进入该预算;认证、额度、非法请求、content-filter、abort、未知终态与 unsupported block 均 fail closed,不自动重试。 - attempt 口径:初次调用 + 自动 retry 最多形成 6 个报告级 outer attempt,每个 outer attempt 至多 dispatch 一次报告 stream。插件直接消费
ctx.llm.stream,不经过 DSH agent request retry waterfall;因此这只是报告级预算,不等于也不保证底层 HTTP 请求恰好 6 次。 - 状态与恢复:逻辑身份是
period + report key。读取会在内存中按 period 规范化:所有非终态 entry 保留在records,每个 period 只保留按 key 排序后的最后一条 terminal entry;写盘序列化时再次裁剪,并把被裁剪的 terminal key 写入全量terminalKeys(period → key → 终态 code,按 key 排序且不按数量淘汰)。墓碑只保留终态 code,不携带 attempts、observations 或 usage;所有已知 terminal key 都保留墓碑,避免历史 key 被自动重开。flatten以及list/listDue/get只投影records,不会把墓碑展开成完整 entry。没有 entry 且没有墓碑的 key,自动beginAttempt才会创建 initial entry;已有 entry 时必须带匹配的cycleId,waiting 还必须已到nextRetryAt,in-flight 或 terminal 返回null;若records没有该 key 但terminalKeys有墓碑,也返回null。对这个只剩墓碑的 key,手动「重新生成」(force) 才会清除墓碑并创建新 cycle、重置计数、重新读取当前配置;force 失败仍不推进 lastRun。
例如
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:17,最后更新 2026-11-06