dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 跨会话 token 记账插件:进程内每一次模型调用都记入本地 SQLite 账本,设置面板一眼看全、agent 一问即答。只做 token,不做钱。
跨会话、跨模型/提供方聚合的 DSH 用量记账插件——「我这个月用了多少 token、按模型分布如何、各供应商额度还剩多少」,设置面板一眼可见、agent 一问即答。只做 token 与供应商实报额度,不做计价换算。
dsh-usage 是一个标准的 DSH 插件:单个 npm 包 dsh-usage-ledger(双面包——宿主半边跑在 Node、浏览器半边跑在 App 客户端),不 fork 核心、不改 DSH 源码。它在 llm/stream waterfall 上为进程内每一次模型调用记账,落成本地 SQLite 账本,并从已配置的模型路由按需读取各供应商实报的剩余额度,以两种方式呈现:设置页的「数据与统计」面板 + 面向模型的 usage_stats 工具。
答案是本地、持久、跨会话、跨模型/提供方的真实数字——提供方实报的 token,外加各供应商自报的剩余额度;估算只作可选的兜底,并永远单独标记。实现位于 dsh-usage-ledger/,详见其 README。
DSH 拥有完整的会话事件基础设施,但没有一张「账」——没有跨会话的用量账本、没有「按模型/按提供方/按时间」的用量视图:
| 现有能力 | 位置 | 能做什么 | 缺什么 |
|---|---|---|---|
@deepseek-ai/dsh-token-meter | 内置 | 启发式 token 估算(chars/4 + 结构开销) | 服务于上下文水位、compaction;不是提供方实报用量 |
@deepseek-ai/dsh-session-stats | 内置 | 单会话投影:turns / steps / decodeTokens | 只统计 output tokens、只到会话粒度;无 input、无跨会话聚合 |
@deepseek-ai/dsh-session-telemetry-otel | 内置(默认 DISABLED) | 可选地把会话事件以 OTLP 分享出去 | 是外发遥测,不是本地记账 |
| 会话事件日志 | 内置 | append-only 规范日志;assistant/message 携带提供方实报 usage | 只按会话存取;没有任何消费方聚合成账本 |
这就是 dsh-usage 填的洞。
llm/stream waterfall——agent 轮次、子代理、会话标题、压缩摘要都经过它,比会话事件日志更完整(标题/压缩调用不进事件日志);estimateFallback(默认关)开启后,无实报的调用用与 token-meter 同一套启发式(chars/4)入账并打 estimated 标记——实报与估算永远分开展示;INSERT OR REPLACE),重试不会重复记账;finish.replayState 刻意忽略——它是 pi-ai 的溯源元数据,不是「缓存重放」信号,不能作为排除依据;node:sqlite 数据库(WAL),账本在 $DSH_HOME/storages/usage-ledger.sqlite,不依赖 storage hub,web / tui / headless 通用,跨 profile 共享同一本账;条目先进内存缓冲、批量落盘(定时 5s / 满 32 条 / 关停),单写者链串行化,失败整批保留并重试,不静默丢数据;usage_stats agent 工具返回 monospace 报表(带 includeQuotas: true 时追加供应商额度段);设置页「数据与统计」dashboard——时间范围切换(7 天 / 30 天)+ 手动刷新、六张统计卡(tokens 用量、会话数、调用次数、活跃天数、连续天数、最常用模型)、GitHub 风格活跃热力图(近 53 周)、按天 Token 趋势堆叠柱状图 + 模型用量占比环形图、供应商额度区块(每个已配置的模型路由一张卡:智谱 GLM / Kimi 的 Coding Plan 窗口、OpenAI Codex 的 5 小时/每周/每月与 credits/额度重置、DeepSeek 按量余额);数字按语言本地化(zh 万/亿,en K/M/G),样式走客户端主题 token,深浅色自适应;llm-pi-ai provider profiles 与内置 llm-deepseek 路由发现;API key 走同一条 credentials 引用通道,openai-codex 则读取模型页登录后保存的 OAuth grant(令牌不出宿主)。按 endpoint host(*.bigmodel.cn/*.z.ai、*.kimi.com、chatgpt.com、*.deepseek.com、*.moonshot.cn/*.moonshot.ai、openrouter.ai、*.minimax.io/*.minimaxi.com、*.baseten.co)匹配探针;路由 id 关键词仅在未配置 baseURL 时回退,端点指向未知 host 的路由(本地网关/代理)一律跳过——凭证绝不发往路由端点之外的地址。支持智谱 GLM/Kimi/MiniMax 的 Coding Plan 窗口、Claude Pro/Max(OAuth)与 OpenAI Codex 的窗口与 credits、DeepSeek/Moonshot/OpenRouter 的按量余额、Baseten 的月度用量;其余预制供应商(groq/together/mistral/xai/Qwen 与小米的 Token 包等)无公开额度 API,刻意不猜端点。额度是实时外网读取:TTL 5 分钟缓存(面板刷新按钮可强制跳过)、失败时降级展示上一次好数据并标 cached、逐供应商隔离(一家挂了不拖累其他)、凭证永不出宿主进程(载荷只有数字);/api 通道内的 exact Fetch 路由,请求先过宿主 Connection 的 Host/Origin fence(loopback/trustedHosts + 同源校验)与 browser-session 签名 Cookie 鉴权,非本机/跨站请求一律 403/401;额度探测只向供应商官方/控制台端点发请求,不经过任何第三方;quota.providers 覆写的 url 仅接受 https(回环 http 例外),否则记录日志并忽略——凭证永不明文出网;| 环节 | 说明 |
|---|---|
| 挂载 | cordis.patch.yml 两行:usage-ledger(双面:宿主服务 + 浏览器 bundle)+ usage-ledger-tool(入口 dsh-usage-ledger/tool,挂 usage_stats 工具;整行摘除即可对 agent 隐藏工具,账本与面板照常工作);配置走 profile 配置树(0.2.0-rc.x 起无需 connection 行覆写) |
| 捕获 | 监听 llm/stream waterfall,透传 chunk 零侵入;实报优先 / 估算兜底;每次调用一条幂等记录 |
| 存储 | 内存缓冲 → 批量落盘 usage-ledger.sqlite(WAL);启动时全量加载为内存镜像,查询在镜像上聚合,本地时区切日/月 |
| 查询 | 唯一入口 ctx.usageLedger.query({ from, to, by }):任意时间范围(今天 / 本月 / 7d / Nd / YYYY-MM / 全部)× 任意维度(模型 / 提供方 / 天 / 会话);工具与面板路由共用;返回总 token(input / cache read / cache write / output 分开)、调用次数、实报 vs 估算拆分、分布视图 |
| 额度 | 独立入口 ctx.usageLedger.quotas({ force }):从 settings 树发现已配置路由 → 经 credentials 解析 key → 逐路由探测供应商额度接口(逐家隔离、TTL 缓存、失败降级);额度不入账本,与 token 统计完全分离 |
| 展示 | 宿主:usage_stats 工具(monospace 报表,includeQuotas 按需追加额度段);浏览器:/plugins/dsh-usage-ledger/client.js 经 settings.section list slot 注册「数据与统计」section(零壳改动;自带折线图 nav 图标),经共享 /api 通道的 exact Fetch 路由(/api/usage-ledger/dashboard、/api/usage-ledger/quotas)拉取聚合与额度——宿主 Connection 的 Host/Origin fence + browser-session Cookie 鉴权兜底;额度独立端点,慢/挂不拖累用量面板 |
架构:
bundle 补丁:usage-ledger(双面)· usage-ledger-tool(usage_stats 工具)
宿主(Node) llm/stream waterfall(进程内所有 LLM 调用)
│ 监听(透传 chunk,零侵入)
▼
┌─────────────────────┐ 批量落盘(5s / 32 条 / 关停;单写者,失败重缓冲重试)
│ Usage Collector │ ───────────────────────────────▶ ┌───────────────────────────┐
│ (pending 缓冲) │ ◀── 启动时同步全量加载(内存镜像) ── │ usage-ledger.sqlite (WAL) │
└─────────────────────┘ │ $DSH_HOME/storages/ │
│ └───────────────────────────┘
│ ctx.usageLedger.query() connection.fetch.register('/api/usage-ledger/*', 共享通道 fence 内)
额度探测(宿主侧,与账本完全分离):
settings 树(llm-pi-ai profiles + llm-deepseek)
│ 路由 → 探针匹配(baseURL host → 缺端点时 id 关键词)
▼
┌───────────────────────┐ key ← credentials 服务(apiKeyEnv 引用)
│ QuotaCache (TTL 5min) │ ──────────────▶ 智谱 / Kimi / Codex / DeepSeek 额度接口
└───────────────────────┘ ◀── 解析后的数字(逐家隔离,失败降级 last-good)
数据模型:条目 { id, time, provider, model, sessionId?, purpose?, inputTokens, cacheReadTokens?, cacheWriteTokens?, outputTokens, reasoningTokens?, estimated? },存储为 entries(id TEXT PRIMARY KEY, time INTEGER, json TEXT) + time 索引;原始条目列表不出宿主,面板只拿聚合。额度不是条目:它是按需实时读取的供应商实报数字,不进 SQLite、不参与任何聚合。
# 构建(浏览器半边源码 src/client/,产物 lib/client.js 必须预构建后进包):
cd dsh-usage-ledger
npm run build # tsdown → lib/client.js(+ map)
npm pack # → dsh-usage-ledger-0.8.2.tgz
# 安装(装完重启 App 客户端——宿主插件与客户端模块都只在启动时加载):
dsh plugin --profile web add /path/to/dsh-usage-ledger-0.8.2.tgz
# 验证:
dsh --profile web --dump-config # 应看到 # == dsh-usage-ledger 层(两行)
# 使用:
设置 → 数据与统计 # 面板:最近 7 天 / 30 天切换 + 刷新(刷新同时强制重读额度)
usage_stats 工具 # 对话中让 agent 查询(如「这个月用了多少 token」「额度还剩多少」)
cordis.patch.yml 的 usage-ledger 行,全部选项与默认值:
| 字段 | 默认 | 说明 |
|---|---|---|
estimateFallback | false | 开启后,无实报 usage 的调用按启发式估算入账(标记 estimated) |
retentionDays | 0 | 0 = 永久保留;N = 丢弃 N 天前的条目(每次落盘后清理) |
flushIntervalMs | 5000 | 缓冲条目最短落盘间隔(下限 1000ms) |
flushEveryEntries | 32 | 缓冲满 N 条立即落盘 |
maxMemoryEntries | 200000 | 存储不可用时内存账本上限(超出丢最旧并计数,绝不静默) |
quota.enabled | true | 是否探测供应商额度;false = 不渲染额度区块、不发任何额度请求 |
quota.ttlMs | 300000 | 一次额度读取的缓存时长(面板刷新按钮可强制跳过) |
quota.timeoutMs | 15000 | 单个路由探测的网络超时 |
quota.providers | {} | 按路由 id 的逃生门:{ probe, url, credentialRef }——强制探针家族、指向迁移后的端点、或改用别的凭证引用;url 仅接受 https(回环 http 例外),否则记录日志并忽略 |
额度探测哪些路由不需要配置:从 settings 树(模型页写的 llm-pi-ai profiles + 内置 llm-deepseek 路由)自动发现。API key 经 credentials 服务按路由的 apiKeyEnv 解析;原生 openai-codex 从 llm-pi-ai/openai-codex OAuth record 读取当前 access token/account id。匹配规则:先看 endpoint host(*.bigmodel.cn/*.z.ai → 智谱,*.kimi.com → Kimi,chatgpt.com → Codex,*.deepseek.com → DeepSeek,*.moonshot.cn/*.moonshot.ai → Moonshot);路由 id 关键词(zai/zhipu/glm/bigmodel、kimi、deepseek、moonshot)只在路由未配置 baseURL 时作为回退——端点指向未知 host 的路由(本地网关、企业代理、api.openai.com 等)一律跳过:凭证只发给它所属端点的厂商,绝不发往路由端点之外(想探测就走 quota.providers 显式覆写)。Codex 刻意收窄——仅 chatgpt.com 端点或精确路由 id openai-codex 自动命中。都不匹配的路由静默跳过(本地网关不会出现一张坏卡)。额度缓存按「路由 + 凭证身份」键控:同路由换账号/换 key 立即重新探测,绝不复用、也绝不在跨凭证间降级旧读数。DeepSeek 同时配置账号登录与官方 API key 时只显示「DeepSeek 账号」钱包一张卡(账号未登录或读取失败时回退官方 API key 卡);自定义 pi-ai 的 DeepSeek 路由不受影响。
npm run build 用 tsdown 产出宿主与浏览器半边产物(客户端构建配置复制自宿主 packages/client/tsdown.client.ts,产出闭包工厂格式,外部依赖只限平台模块表);node:sqlite)、宿主 base 层暴露 llm/stream waterfall 与 tokenMeter 服务(0.1.0-rc.5 世代);设置面板需要 web profile(App 客户端),headless/TUI 下浏览器半边不加载、面板路由不注册,其余能力不受影响;额度探测额外需要 settings 与 credentials 服务(base 层标配),缺了只是不显示额度区块,账本与用量面板照常;$DSH_HOME;estimated 标记;quota.providers 按路由修;插件只读取 Codex 当前 OAuth grant、不替 llm-pi-ai 刷新,若过期先发起一次 Codex 模型调用再刷新面板;dsh.client 包,机制已在宿主源码逐行核实。usage_stats 工具(两行架构,工具行可独立摘除)includeQuotas(额度不入账本、不做计价换算)MIT