Bundle
dsh-fingerprint-show
DeepSeek Harness plugin: capture the provider model fingerprint (system_fingerprint) of every LLM call and show it as a hover-revealed plain-text suffix on each assistant message's metrics row in the Web UI.
- Source
- Bortor
- License
- MIT
- Updated
- Updated 2 days ago
Readme
# dsh-fingerprint-show
一个 [DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/)(DSH)插件:捕获每次模型调用的**提供方模型指纹**(OpenAI 兼容的 `system_fingerprint` 字段),并在 Web UI 中每条 AI 回复的指标行末尾以纯文本显示。
## 功能
- **完整指纹文本** — 每条有指标行的 AI 回复末尾以纯文本追加该次调用实际的
模型指纹(如 `… 127 tok/s · 0123456789abcdef0123456789abcdef`),完整不截断、
无按钮、无图标、无复制交互;
- **样式与原生一致** — 字体 14px、行高 24px、三级灰色
(`--dsw-alias-label-tertiary`)、10px 圆点间距,与指标文本像素级统一;
- **悬停同步** — 指纹与 `时间 · 用时 · 首 token · tok/s` 指标文本**同生同隐**:
悬停或聚焦消息时一起淡入,移开一起消失(与框架原生行为相同的 80ms 过渡);
- **历史保留** — 中途切换模型后,每条回复各自标注当时实际生效的部署;
- **悬停提示** — tooltip 显示模型 id、提供方与调用时间;
- **零侵入** — 不修改会话日志、不进入模型上下文、不影响 KV 缓存。
## 工作原理
DSH 自带的 DeepSeek 适配器把提供方 SSE 翻译成框架内部的 `StreamChunk` 协议,
响应级元数据(包括 `system_fingerprint`)在这一步被丢弃,因此 `llm/stream`
瀑布事件里看不到指纹。本插件在两个互补的接缝上工作:
1. **fetch 包装**(主机侧)— 所有适配器最终都走全局 `fetch`。插件 tee 每个
匹配 `chat/completions` 的响应体,从 SSE 分支中提取
`system_fingerprint`,另一分支原样交还适配器。
2. **`llm/stream` 瀑布监听**(主机侧)— 提供 `(sessionId, model, purpose)`。
每次流式调用恰好对应一个提供方请求,观测按「同模型优先、时间最近」关联到
进行中的瀑布调用。
3. **HTTP 路由**(主机侧)— 通过 `ctx.webServer.register()` 在 Web 服务上暴露
`GET <pathPrefix>/api/observations?sessionId=…&limit=…`。之所以不用自定义
会话事件:持久化读取层会拒绝未知事件类型且 `Session.append` 不支持
`ignorable` 标记;Remote 命名空间则需要构建期代码生成。
4. **消息内文本**(浏览器侧)— 客户端半区注册
`conversation.chat.assistant-actions` 槽位条目(定稿 AI 消息的操作条,
与复制/分支按钮同区),按时间单调对齐观测与消息——每条消息取「开始于该
消息落盘之前、且未被更早消息消费」的最新观测——以纯文本渲染在指标行末尾;
可见性与指标文本同步(悬停显示)。样式完全镜像原生时间文本
(`font-size:14px`、`line-height:24px`、三级灰色、圆点仅右侧 10px
边距、左侧间距由行的 flex `gap:10px` 提供)。
## 安装
前置条件:已安装 `dsh` CLI 与 pnpm。
```sh
git clone <this-repo> dsh-fingerprint-show
cd dsh-fingerprint-show
pnpm install # prepare 钩子自动构建 lib/
dsh plugin --profile web add <path-to-checkout> # 插件包目录本身的绝对路径,或 .
```
> 注意 `add` 的参数是**插件包目录本身**。在仓库目录里执行 `add ./dsh-fingerprint-show`
> 会把链接指到不存在的子目录(pnpm 会照常记录依赖但 bundle 层不会生效)。
> 装好后用 `dsh --profile web --dump-config` 确认输出里有
> `# == dsh-fingerprint-show` 一层。
重启 `dsh web` 后,发起一次对话;把鼠标移到 AI 回复上,指标行末尾会出现
`· 完整指纹` 文本。
> 插件只在 **web profile** 下激活(依赖其 `webServer` 服务);headless profile
> 中保持休眠。也可以用开发模式快速试用:
> `dsh web --patch ./cordis.patch.yml`(需先把 patch 中 `name:` 改为指向
> `src/index.ts` 的绝对路径)。
## 配置
在 profile 的 `cordis.patch.yml` 或 `--patch` 覆盖层中按 id 覆盖该行配置:
```yaml
- id: fingerprint-show
config:
pathPrefix: /dsh-fingerprint-show # HTTP 路由前缀
matchPatterns: # 对请求 URL 做子串匹配
- chat/completions
maxObservations: 500 # 进程内环形缓冲容量
```
注意:patch 会整行替换 config,覆盖时请重述全部需要的键。
## 诊断
浏览器直接访问 `/dsh-fingerprint-show/api/observations`(同源)可查看捕获结果:
```json
{
"observations": [ { "fingerprint": "…", "model": "…", "sessionId": "…", "time": 123 } ],
"stats": {
"matchedResponses": 2, // 被拦截的匹配响应数
"capturedFingerprints": 2, // 成功提取指纹数
"parsedChunks": 2, // 解析的 SSE 载荷数
"inflightCalls": 0, // 进行中的瀑布调用数
"totalStored": 2 // 缓冲中观测总数
}
}
```
若 `matchedResponses > 0` 而 `capturedFingerprints = 0`,说明提供方响应里没有
`system_fingerprint`(自建/代理端点常见);`lastPayloadSample` 会给出最近一次
无指纹响应的首个 SSE 载荷样本。
## 已知限制
- 并发同模型调用(如同时运行的 subagent)之间按「时间最近」归因,极端并发下
可能归属到相邻调用——但指纹本身标识的是模型部署版本,值始终正确;
- 辅助调用(会话标题、压缩)带 `purpose` 标记,匹配时排除,不参与消息标注;
- 指纹由提供方返回,非 OpenAI 兼容的自建端点可能不携带该字段(此时不显示);
- 只在有指标行(`timing`)的消息上显示,无指标文本的消息不显示指纹。
## 开发
```sh
pnpm install
pnpm run build # esbuild → lib/index.js (Node ESM) + lib/client.js (浏览器 lazy-CJS)
pnpm test # 主机流水线 + 客户端 bundle 冒烟测试
```
客户端半区必须构建为 DSH 模块加载器的 lazy-CJS 工厂形式
(`window.__ModuleLoader__.load({id, factory})`),见 `scripts/build.mjs`。
## License
MIT
Install
dsh plugin --profile web add github:Bortor/dsh-fingerprint-show#1f5ab663d6d0b57489b697f77927c477afe07399
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-fingerprint-show from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.