概览
@fufuf-c/dsh-token
README / ZH
插件文档
目录摘要
dsh.pub 核对固定版本的组合包契约、运行时事实与分发语义;完整 README 请查看源仓库。
在 GitHub 阅读完整 READMELIMITATIONS
已知限制
- 规模上限参考(20 万请求 / 400 会话 / 120 模型的合成库,Node 24,2026-09 实测): 落盘 = `store.json` 元数据约 **142 KB** + `shards/` 约 **10 MB**(逐会话一个分片), 请求记录全量驻留内存,**堆占用约 59 MB**; 冷启动 `JSON.parse` + 分片载入约 0.12 s,`rebuildAll` 约 0.42 s; **0.9.5 起,有会话变更的扫描周期只重折被改动的会话**(unfold 旧列表 + fold 新列表), 不再整库重折,同时**只重写变化的分片** (改 2 个会话时约 0.19 s 的写量,而 0.8.x 是整库 19.98 MB / 0.17 s)。 端到端实测(真实 `scanStore` 路径,6 万请求 / 200 会话): **改 2 个会话 2.7 ms,而整库重折 71.6 ms(约 27×)**;无变化仍是 0.2 ms。 两条路都会在 `summary.aggMode` 里如实报出(`full` / `incremental` / `none`)。 冷启动与"聚合不可用"仍走整库重折 —— 没有旧账可减时增量只会多做一轮簿记。 稳态增量扫描实测 **34-52 ms**(无变化时只 list 一遍比对 revision,不解码任何会话), 冷启全量约 2.1 s;扫描周期可用 `refresh.scanSec` 调整或关掉(`0`)。 默认 `retention.days=0` 永久保留,长期大库建议开启保留期 (如 `{"retention":{"days":365}}`)控制体积 —— 开启后稳态扫描是零写放大的。 **`store.json` 的体积随会话数线性增长**(它每个脏周期整体重写):本机 64 会话约 32 KB, 即每会话约 0.5 KB;数千会话时该文件会到 MB 级,这是选分片布局换来的代价,已记录在案。 **分片布局的取舍**:单会话损坏只影响一个分片(其余照旧,该会话下轮从日志重折), 代价是文件数为**会话数**(数千会话即数千个小文件)。逐请求导出(JSON)另有 10 万行上限, 超过会拒绝(见路由表); - **`store.json` 不再含逐请求记录(0.9.0 起)**:它是**元数据 + 索引**,记录在 `shards/*.json`。备份时请连 `$DSH_HOME/dsh-token/` **整个目录**一起备份 (只备份 `store.json` 会丢掉全部用量记录,只留下配置与标题); - **逐请求 JSON 导出的行数上限是 10 万条**:20 万条会生成 68 MB 单个响应体,足以卡死 标签页。需要全量请缩小时间范围,或开启保留期; - `cost/saved/priced` 是**普通数据属性**,不是访问器(0.8.9 起):改完单价/时段后,下一次 **查询**就会用新价(所有查询入口与落盘前都先 flush),但直接读 `store.requests[id][i].cost` 的代码需要自己先 `flushAggregates(store)`; - 通过**域名**反代访问仪表盘时,设置类 POST 会被拒绝(防 DNS rebinding 的代价):Host 白名单只放行回环名、私网/链路本地/CGNAT/唯一本地 IP 与回环 IPv6,**域名与公网 IP 字面量一律拒绝**。私网 IP 直连(如 `http://192.168.1.5:3080`)与 `curl`(无 `Origin`)可用; - 仪表盘价格估算内置 **DeepSeek 官方价目**(¥/M),按官方页口径分档并区分时段 —— 见下方「价格口径」。**只有 DSH 内置官方模型(`deepseek-official`)套用该价目;中继/自建/第三方 路由一律无内置价**,成本计 0,需手动为它们录入自定义单价。未定价部分**不会被藏起来** —— `kpi.totals.unpricedTokens` / `unpricedModelCount` 显式给出,单价表显示"未定价 · 按 ¥0 计", 会话面板与 KPI 卡片都会标注"含未定价模型,费用偏低"。**因此"估算成本"要读成 "已定价部分的成本 + 未定价 token 数",不是完整账单;** > 0.8.5 起收紧了这条口径:此前第三方模型会按名字套用官方价估算,但中转实际计费与官方价 > 无关,那个数字**像账单却不是账单**。现在改为一律不计价,由"未定价"显式报出。 - 默认永久保留全部原始请求记录(会话下钻/导出依赖);设置 `retention.days` 可按天修剪, 修剪在扫描期执行,超龄会话整段清理; - **被宿主拒绝的老会话无法统计**:部分 v0 老日志(插件注入过非标准事件成员,或子代理 描述符为 v2)连 DSH 自身都拒绝迁移,插件只能跳过。这类会话进入隔离清单并计入 `meta.quarantinedCount`(设置页/`/dsh-token/api/meta` 可见),可用 `POST /dsh-token/api/scan` 或重启触发 `force` 重试。它们**上一次成功扫描的记录会保留**在 store 里(不会静默清零), 只是不再更新 —— 本机实测为 18 个会话 / 549 条记录; - **store 损坏时以"留证 + 重建"处理,不尝试原地修复**:形态体检只做结构判定 (字段/类型/NaN),不合格就改名成 `store.json.corrupt-<时间戳>` 再从会话日志重建。 这样不会丢数据、也不会丢证据,但**配置**(自定义单价、预算、保留期) 会随之回默认 —— 因为它们只存在 store 里,日志里没有。想保住配置,请把 `$DSH_HOME/dsh-token/` **整个目录**一起备份(0.9.0 起用量记录在 `shards/`,`store.json` 只是元数据与索引;单独备份 `store.json` 会丢掉全部用量记录); - **小时桶/高峰判定固定北京时间**(UTC+8),不跟随宿主时区,也不可配置;日/月桶按宿主 本地时区。两者口径不同是有意的:前者对齐官方计费,后者对齐用户对"今天"的直觉; - 单价表按 DSH settings 里的模型目录过滤。命名空间形态已知两种(`llm-pi-ai` 的 `providers.<路由>.models[]`,以及适配器自带命名空间的顶层 `models[]`,provider 名靠一张 小映射表补全)。**任何解析不出来时一律关闭过滤显示全部**,并在启动日志里打印所见的命名 空间名(不含任何值)—— 所以"读不到配置"只会退回旧行为,不会把界面清空; - 配置在 `$DSH_HOME/dsh-token/store.json`,用量记录在同目录 `shards/`(均未走 `settings.register`,动态插件沙箱无法构造 schemastery schema);单价表只**读** DSH settings,从不写它,且只取 `provider:model` 标识,settings 原文(含凭据相关字段) 绝不进入 API 载荷; - 会话标题取 DSH 的自动生成标题(`session/title` 事件),缺省回退首条用户消息。
