前言¶
在 DeepSeek Harness(DSH)里走自定义模型厂商或 pi-ai 路由时,出站 HTTP 往往不会带上 x-deepseek-harness-session-id——这是 0.2.1-rc.2 上不同 LLM 适配器的差异,不是网关偶发丢头。下游若按 OpenCode Go 等生态约定读 x-opencode-session 做会话亲和或审计,就会拿不到与 DSH Session 一致的标识。维护者 Deliay 的联网工具插件 dsh-header-masq 在模型调用路径上把持久化 session id 写入可配置的目标请求头,并在缺省情况下与 DeepSeek 官方适配器发出的 harness 头对齐。
这是什么¶
dsh-header-masq 面向 DSH 0.2.1-rc.2(兼容范围 >=0.2.1-rc.2 <0.3.0),通过 Cordis 补丁拦截 globalThis.fetch 并监听 llm/stream,把当前会话 id 暴露成其他 harness 认识的请求头。npm 包版本 0.2.1,许可证 MIT。社区目录页:skillhub.cn/plugins/Deliay/dsh-header-masq;源码:github.com/Deliay/dsh-header-masq(目录为独立站点,与 DeepSeek / 幻方无官方从属关系)。
默认映射效果如下:
x-deepseek-harness-session-id: session-05681fd4-...
x-opencode-session: session-05681fd4-...
为什么需要关心「源头」差异¶
DSH 0.2.1-rc.2 里,是否发送 x-deepseek-harness-session-id 取决于适配器:
| 适配器 | 用途 | 是否发送 x-deepseek-harness-session-id |
|---|---|---|
@deepseek-ai/dsh-llm-deepseek |
deepseek-official、自定义 baseURL 的 Messages 兼容网关 |
发送,值为 GenerateOptions.sessionId |
@deepseek-ai/dsh-llm-pi-ai |
自定义模型厂商、OpenAI / Anthropic 兼容路由、pi-ai 目录里的 provider | 完全不发送 |
dsh-llm-pi-ai 只把 sessionId 交给 pi-ai 的 streamSimple,wire extension 头由 dsh-llm-deepseek 实现。因此自定义厂商侧看到的是没有这个头,而不是空值;没有 Session 的一次性调用同样不会带该头。
插件以 llm/stream 的 GenerateOptions.sessionId 作为规范值:
- 同一 session 的主对话、标题生成、压缩、重试共用同一 id;
- pi-ai / 自定义厂商没有
x-deepseek-harness-session-id时,直接使用该值; - 新建 session 时 DSH 给出新 id,映射随之变化;
- 仅在拿不到活动 session id(例如模型流之外的调用)时,才回退读取
source配置的请求头(默认x-deepseek-harness-session-id)。
同一 session 内 x-opencode-session(或你配置的 targets)在多轮对话、标题生成、压缩、重试、以及「自定义厂商 vs DeepSeek 适配器」之间保持一致;进程重启后继续同一 session 仍相同(持久化 Session id,非每次请求随机)。插件不会给所有 session 共用一个固定值。
核心行为¶
经过上面的语义约定,插件在运行时做这些事:
- 在模型调用流中,把该次调用的持久化
sessionId写入targets中的每个请求头。 - 拿不到活动
sessionId时,从source读取并写入同一值。 - 目标头已存在时覆盖,避免残留旧 session。
- 支持
fetch的Headers、普通对象、Request三种入参形式。 - 卸载时恢复原始
fetch与llm/stream监听,不破坏之后安装的其他补丁。
实现只依赖 globalThis.fetch、llm/stream 事件和 Cordis 的 ctx.effect,不导入 DSH 内部模块。Node.js 要求 >=20。
安装与启用¶
先做本地或 GitHub 安装,再重启 DSH 引擎;包内 cordis.patch.yml 会被自动激活。
本地目录:
dsh plugin --profile web add file:/absolute/path/to/dsh-header-masq
从 GitHub:
dsh plugin --profile web add github:Deliay/dsh-header-masq
插件以当前 dsh 进程权限运行,安装前建议阅读仓库源码与 MIT 许可证,确认出站请求头改写符合你的合规与网关策略。
配置¶
配置位于 Cordis 插入项 header-masq(见 cordis.patch.yml),字段均可选:
| 键 | 默认值 | 说明 |
|---|---|---|
source |
x-deepseek-harness-session-id |
没有活动 sessionId 时读取的请求头 |
targets |
[x-opencode-session] |
要写入的请求头列表 |
fallbackToSessionId |
true |
使用 llm/stream 的 sessionId 作为固定规范值 |
hosts |
[] |
目标主机白名单;空表示所有主机 |
debug |
false |
每次应用映射时写一条 info 日志 |
典型用法:只对 OpenCode Go 主机生效,并同时写多个头:
- insert:
- id: header-masq
name: dsh-header-masq
config:
source: x-deepseek-harness-session-id
targets:
- x-opencode-session
- x-session-affinity
fallbackToSessionId: true
hosts:
- opencode.ai
debug: true
适用场景与注意¶
适合在 DSH web profile 下需要让自定义 LLM 出站请求携带 OpenCode 会话亲和(x-opencode-session)或自建 targets 头的场景;也可通过 hosts 限制只对特定 API 域名改写,避免误改无关 fetch。
务必记住:fallbackToSessionId: true 时以 DSH 持久化 Session 为准,与适配器是否发送 x-deepseek-harness-session-id 无关;关闭回退且既无活动 sessionId 又无源头的场景下,插件无法凭空造 id。
DSH 理念是「一切皆插件」;本插件归类为联网工具,当前 GitHub 星标为 0,不代表功能完整性,以 README 与版本约束为准。
结尾¶
dsh-header-masq 解决的是 harness 请求头命名与适配器实现不一致的问题:在 fetch 层统一写入可配置的 session 标识,使 pi-ai 与自定义路由也能满足下游对 x-opencode-session 等头的期望。
- 目录页:https://www.skillhub.cn/plugins/Deliay/dsh-header-masq
- GitHub:https://github.com/Deliay/dsh-header-masq