← Back to home@DrScorpio

dsh-opencode-auto-review

Unofficial DeepSeek Harness plugin fixing OpenCode's MissingSessionID in Auto review by attaching the reviewed agent's session identity. | 非官方 DSH 插件:为 reviewer 请求补上被审查会话身份,修复 OpenCode MissingSessionID 拒绝

Stars
0
Language
TypeScript
Created
Oct 22, 2026
Updated
Oct 26, 2026

Introduction

dsh-opencode-auto-review

简体中文 | English

License: MIT npm DSH 0.2.1-rc.1 | 0.2.1-rc.2 | 0.2.1-rc.3 Node.js >=22.19.0

让 DSH Auto review 在 DSH 0.2.1-rc.1、0.2.1-rc.2 与 0.2.1-rc.3 上通过 OpenCode 网关正常工作。

dsh-opencode-auto-review@0.1.2 是官方 @deepseek-ai/dsh-experimental-auto-review 组合包(0.2.1-rc.1、0.2.1-rc.2 与 0.2.1-rc.3 为同一份代码)的最小独立派生。它只改变一个行为:冻结的 reviewer 请求现在携带 sessionId: agent.session.id,使 pi-ai 的 OpenCode 提供方能够发出必需的 x-opencode-session 请求头。其余全部——审查策略、五段输入、风险规则、JSON 协议、审批优先级、PTC 处理、取消与卸载——都保持官方实现不变。

版本支持。 本版支持 DSH 0.2.1-rc.1、0.2.1-rc.2 与 0.2.1-rc.3,配套同版本的 @deepseek-ai/dsh-llm-pi-ai 适配器与 pi-ai @earendil-works/pi-ai@1.1.0。这三个宿主版本是同一份代码:@deepseek-ai/* 各包除 version 字段外逐字节相同,因此插件无需修改即可在三者上运行(rc.1↔rc.2 与 rc.2↔rc.3 的对照记录见 VERIFICATION.md)。engines.dsh: "0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3" 是 0.2.1 线上真正生效的闸门——DSH 在加载 profile 前用运行时版本与该范围比对,不匹配时以不兼容诊断拒绝安装/加载(已在真实的 0.2.1-rc.1 CLI 上验证闸门行为)。peerDependencies 携带同一范围,因为仍按 peer 校验的旧宿主版本线与包管理器都以它为准。0.2.0-rc.x 线不受支持:它缺少本包注入的 workingDirectory 服务,也缺少 pi-ai 的 sessionId 传输链路,因此即使强行安装插件也会保持未激活。要继续扩大声明,必须重跑 UPSTREAM.md 与 VERIFICATION.md 记录的一致性对照与传输验证。

目录

快速开始

dsh-opencode-auto-review 的当前版本是 0.1.2,在保留 0.2.1-rc.1 与 0.2.1-rc.2 的同时新增 0.2.1-rc.3 支持;发布到 npm 后 latest dist-tag 指向它(dsh-opencode-auto-review@0.1.2)。0.1.1 是上一版,支持 0.2.1-rc.1 与 0.2.1-rc.2;0.1.0 仅支持 0.2.1-rc.2。安装与生效组合是经过验证的路径;加载/重选步骤与完整 profile 启动不在该证据范围内(见验证状态)。

前置条件:与所运行 DSH 版本(0.2.1-rc.1、0.2.1-rc.2 或 0.2.1-rc.3)匹配的官方 @deepseek-ai/dsh-experimental-auto-review 组合层必须已在该 profile 中启用, 并且在有序 bundle 列表中位于本包之前(安装步骤 1)。缺少该层时,本包 patch 的停用条目只会告警, 下面的组合检查也无法通过。

# 1. 安装本包到目标 profile
dsh plugin --profile <profile> add dsh-opencode-auto-review@0.1.2

#    离线备选:从同一个预构建产物(tarball)安装
#    dsh plugin --profile <profile> add ./dsh-opencode-auto-review-0.1.2.tgz

# 2. 检查生效组合
dsh --profile <profile> --dump-config

# 3. 按安装步骤 4 加载组合,然后重新显式选择 Auto review

--dump-config 必须显示官方 auto-review 行已被停用,且恰好只有一行有效的 auto-review-opencode;参见正确的最终组合。安装组合层从不改变存活会话已选的权限预设, 因此第 3 步重新选择 Auto review 是用户的显式操作;停止轮次、加载与确认顺序见安装。

故障原因

Auto review 通过与对话相同的 LLM 服务发送审查请求,使用当前路由的 provider 和模型。官方 0.2.1-rc.2 实现的 classifyRisk() 构造一个经过 deepFreeze() 的 GenerateOptions 对象,其中包含路由、固定审查策略、一条审查消息、temperature: 0 和取消信号,但不包含 sessionId。

pi-ai 1.1.0 的 OpenCode 提供方只在 sessionId 非空且不存在同名请求头时才添加 x-opencode-session。没有 sessionId 就没有该请求头,OpenCode 网关以 MissingSessionID 拒绝审查请求。Auto review 把一切审查器技术失败视为关闭闸门,因此待审工具正文不会执行:

待审工具调用进入 Auto review
  -> reviewer 请求未携带 sessionId
  -> pi-ai 不生成 x-opencode-session
  -> OpenCode 网关以 MissingSessionID 拒绝请求
  -> reviewer 技术失败
  -> 审查闸门关闭,工具正文不执行

实际后果是:在 Auto 权限预设下使用 OpenCode 路由模型的会话里,工具调用会被审查、以技术失败被拒绝,并且永不执行。其他 provider 路由不受影响。缺陷位于 reviewer 请求的构造处,而非 provider 配置。

选择在该构造处修复,是因为:

  • 官方请求已被 deepFreeze(),llm/stream 监听器无法修改原对象,next() 也不接受替换后的请求;
  • llm/stream 事件没有暴露待审工具所属的 Agent,按进程级「最近会话」推断会在并发会话中串号;
  • 唯一正确的身份是被审 Agent 自己的 agent.session.id;随机 ID、父 ID、从提示词提取的 ID 或进程级缓存 ID 都不正确。

因此本包没有采用运行时源码替换、服务方法 monkey patch 或全局 HTTP 拦截——它们要么在猜测身份,要么在改写共享机制,而不是在已知身份的位置直接写入该字段。本包改为派生官方实现,直接补上缺失字段。

本包的改动

方面官方 0.2.1-rc.2本包
包名@deepseek-ai/dsh-experimental-auto-reviewdsh-opencode-auto-review
组合行插入 auto-review停用 auto-review,插入 auto-review-opencode
reviewer 请求无 sessionId冻结选项中含 sessionId: agent.session.id
源码元数据官方来源与 @module派生来源与 @module dsh-opencode-auto-review
其余部分—与固定上游提交逐字节一致

src/index.ts 与 dsh-v0.2.1-rc.2(提交 687f282e8625c6b8d11ff58211a90524be2e4317)的 packages/experimental/auto-review/src/index.ts 恰好有三处差异:新增来源说明头注释、修改 @module 行、新增唯一一行 sessionId。一致性 diff 记录在 VERIFICATION.md。

为保持最小派生,Cordis 诊断插件名沿用上游的 experimental-auto-review;配置中通过组合行 ID(auto-review-opencode)和包名(dsh-opencode-auto-review)区分本层。

发布包通过两个不同行 ID 的组合 patch 接替官方行:

- id: auto-review
  name: '@deepseek-ai/dsh-experimental-auto-review'
  disabled: true

- insert:
    - id: auto-review-opencode
      name: dsh-opencode-auto-review

必须使用两个不同的行 ID。对既有 auto-review 行设置新 name 不能替换官方插件(patch 的 name 字段只校验行内既有插件名),再次插入同 ID 行也不会覆盖既有行。

本包保留的行为

审查行为就是官方 0.2.1-rc.2 实现,未作改动:

  • 固定的 REVIEW_POLICY 文本,以及五段审查输入:策略、仅 cwd 的环境、带来源的项目约束、过滤后带来源的历史、完整待审动作;
  • low / medium / high 风险规则、仅限本 Session 创建对象的精确清理例外、授权规则,以及效果不明确或授权冲突未解决时失败即拒绝的处理;
  • 严格 JSON 风险/决策协议:单个 JSON 文本对象、重复成员检测、合法的 risk/decision 组合、可选 deny 理由,以及拒绝格式错误、截断或超长响应;
  • 置前的 tools/pre-execute 监听器及其审批优先级:never 审批策略下 reviewer 拒绝为最终结果;ask 下只有在后续所有监听器均放行时才升级为用户审批,因此后续的拒绝、取消或 ask 优先;
  • native 与 PTC inner 审查,每个已开始的 inner 调用审查一次,外层 run_code transport 排除在外;
  • 技术失败关闭闸门,返回具体错误(Auto review of tool "<name>" failed; its body was not executed: <error>),且从不执行工具正文;
  • 取消与卸载:执行信号与生命周期信号组合;卸载时先停止接收新审查,将存活的 Auto 会话迁移到 danger-full-access,再中止并等待在途审查结清,最后撤回监听器与 preset contribution;
  • 相同的必需注入(approval、llm、permissionPresets、sessions、tools、workingDirectory)、同一个 ctx.effect 注册,以及第二个 Auto 提供方注册时同样失败;
  • 不新增配置项、不新增会话事件、无 UI,也不改变模型可见的提示词。

完整行为描述见官方 Auto review README(随 @deepseek-ai/dsh-experimental-auto-review@0.2.1-rc.2 发布,位于 DSH 仓库 packages/experimental/auto-review/README.md),该描述对本包同样适用。

版本支持

项目必需版本
DSH 运行时0.2.1-rc.1、0.2.1-rc.2 或 0.2.1-rc.3——三个版本提供同一套宿主 API
兼容性声明engines.dsh: "0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3"——0.2.1 线上真正生效的闸门,此时由它单独决定,不参考 peers
适配器@deepseek-ai/dsh-llm-pi-ai,版本与宿主相同(0.2.1-rc.1、0.2.1-rc.2 或 0.2.1-rc.3)
pi-ai@earendil-works/pi-ai@1.1.0(含 DSH 仓库补丁)
Cordis@deepseek-ai/cordis@4.0.5
Node.js>=22.19.0(engines.node)

兼容性声明在两处,且两处携带同一窗口:

  • engines.dsh 是 0.2.1 线上生效的闸门。manifest 声明该字段时,DSH 会在加载 profile 前用运行时版本与该范围比对,并仅据此裁决;不匹配时以指出 engines.dsh 的不兼容诊断拒绝。这不是推测:0.1.0 声明精确 0.2.1-rc.2,被真实的 0.2.1-rc.1 CLI 以 requirements {"engines.dsh":"0.2.1-rc.2"} 拒绝,本次修改因此放宽了该范围。
  • peerDependencies 是忽略 engines.dsh 的宿主版本线(0.2.0 线只校验 peer)上的闸门,也是包管理器解析共享 Cordis 与服务实例的依据。它们携带同一 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 范围;Cordis 仍固定 4.0.5。

窗口为何恰好是这三个版本:0.2.1-rc.1、0.2.1-rc.2 与 0.2.1-rc.3 只在 @deepseek-ai/* 各包的版本文本上不同,插件代码、GenerateOptions 契约与注入服务完全一致(差异对照见 VERIFICATION.md)。更早的 0.2.0-rc.x 线是另一套宿主 API:它没有本包注入的 workingDirectory 服务,Cordis 会让插件行保持 pending 而非激活;其 pi-ai 线也完全不发 x-opencode-session,本包要修的缺陷在该线上无法在不改适配器的情况下修复。两者都在本版支持声明之外。

唯一常规运行时依赖是 @deepseek-ai/dsh-util-values,用同一范围声明,使 profile 解析到宿主对应版本。其余 @deepseek-ai/* 包只出现在 devDependencies 中,供针对 0.2.1-rc.3 的类型检查、测试与构建使用(三个版本在此可互换)。构建把 @deepseek-ai/* 标记为 external,共享宿主的 Cordis 与服务实例,不会打入私有副本。

上游若发布携带 reviewer 会话身份的正式修复,届时先升级并重新验证,再移除本包(见 UPSTREAM.md)。

动态传输验收覆盖的四个 OpenCode opencode 聊天 API 已在 VERIFICATION.md 中记录为 PASS(D2/D4);opencode-go 路由因没有真实网关验收而排除在首版支持声明之外。

安装

前置条件:

  • 使用与要修改的 Desktop 或 Web UI 相同的 DSH 0.2.1-rc.1、0.2.1-rc.2 或 0.2.1-rc.3 安装所提供的 CLI,并指向同一个 DSH_HOME;安装到其他 DSH_HOME 或 profile 不会改变当前窗口;
  • 确认 CLI 版本是目标版本(dsh --version 应报告 0.2.1-rc.1、0.2.1-rc.2 或 0.2.1-rc.3);其他运行版本会在 profile 加载阶段被停用并给出不兼容诊断——0.2.1 线上由 engines.dsh 拦截,0.2.0 线上由锁定的 peer 拦截;
  • 与所运行版本匹配的官方 Auto review 组合层必须已启用,并且在 profile 的有序 bundle 列表中位于本包组合层之前。DSH 安装随附该层但默认关闭,将其加入 profile 即启用。

步骤 1 —— 确认官方层存在。请使用与宿主相同的版本;如果 profile 的最终组合中已包含官方 auto-review 行(例如已在 Web 侧栏插件页开启),跳过此步:

# 在 DSH 0.2.1-rc.1 宿主上:
dsh plugin --profile <profile> add @deepseek-ai/dsh-experimental-auto-review@0.2.1-rc.1

# 在 DSH 0.2.1-rc.2 宿主上:
dsh plugin --profile <profile> add @deepseek-ai/dsh-experimental-auto-review@0.2.1-rc.2

# 在 DSH 0.2.1-rc.3 宿主上:
dsh plugin --profile <profile> add @deepseek-ai/dsh-experimental-auto-review@0.2.1-rc.3

步骤 2 —— 安装本包。标准路径是 npm registry 包;预构建 tarball 是同一产物,供离线或内网 profile 使用(两者都无需构建,也不依赖开发者源码路径):

# 从 npm registry 安装(0.1.2 是本版;支持 0.2.1-rc.1、0.2.1-rc.2 与 0.2.1-rc.3)
dsh plugin --profile <profile> add dsh-opencode-auto-review@0.1.2

# 或从发布 tarball 安装(registry 不可达时使用)
dsh plugin --profile <profile> add ./dsh-opencode-auto-review-0.1.2.tgz

registry 包与发布 tarball 是同一个预构建产物:0.1.2 为 29,886 B、SHA-256 24FA21BA84ED06C6022E8F85F679DF5F2C8AC4984417A213CF4C39D274C4A49C(npm latest,与 GitHub Release 附件逐字节一致);发布工作流把它作为 GitHub Release 附件,并与 npm registry 上的 tarball 做字节级校验。0.1.1 为 29,159 B、SHA-256 82457F551ABC63330F3739A9DDFC2780D2BAEDD5824014508C94115F4E808005;0.1.0 为 27,545 B、SHA-256 63A76209BFED6B5614B5F5453DEE58713BF4BD0EC73683D275E784659D93A29C。如果只是需要在其他项目中把它作为依赖使用,npm install dsh-opencode-auto-review@0.1.2 安装的也是同一个预构建包。不要改用 git 检出:lib/ 已被 gitignore,且包内没有 prepare/install 构建钩子,源码安装不会得到已构建的入口。

步骤 3 —— 检查生效组合,而不只是 bundle 列表:

dsh --profile <profile> --dump-config

步骤 4 —— 让配置作用于运行中的 UI:安装或移除组合层不会改变存活会话已选的权限预设;停止当前轮次,在加载与确认组合期间保持会话处于合适的非 Auto 模式,确认组合后显式重新选择 Auto review。验收测试请使用独立测试 profile。

如果官方层缺失,本包 patch 中的停用条目只会告警并跳过;profile 可能仍能加载,但不属于上述标准验收安装。

正确的最终组合

dsh --profile <profile> --dump-config 在语义上必须显示(具体格式随 CLI 版本而定):

行插件必需状态
auto-review@deepseek-ai/dsh-experimental-auto-review存在,且 disabled: true
auto-review-opencodedsh-opencode-auto-review存在且有效(无 disabled)
其他任何行上述任一插件不得有效

也就是说:

  • 官方行保留安装但被停用;
  • 恰好有一个有效的 auto-review-opencode 行指向 dsh-opencode-auto-review;
  • 不得有其他有效行挂载官方实现或本包,从而只有一个 Auto preset 提供方和一套审查监听器。

配置层按顺序生效:profile 的有序 bundle 列表、profile 自身 patch、home patch、命令行 overlay。后面的层可能重新启用官方行或停用本包,因此必须检查最终组合;只看 bundle 列表不够。若两套实现同时加载,重复 Auto 注册会明确失败(registerAuto() 抛错),不会被静默吞掉。

会话身份语义

reviewer 请求携带待审工具所属 Agent 的会话 ID,在构造请求时写入,因此所有 reviewer 路由都得到同一正确身份,无需按 provider 名分支。

调用来源reviewer 会话身份
主代理 native 工具调用主代理的 agent.session.id
并发的另一主会话该会话自己的 ID(不会串会话)
进程内子代理工具调用子代理自己的 agent.session.id,绝不使用父代理 ID
父代理发起进程外委派委派调用使用父代理 ID;外部子进程保留自身权限系统,不使用父代理的 Auto reviewer

不生成随机 ID,不用父会话 ID 替代子会话 ID,不从提示词提取 ID,也不缓存进程级会话身份。该身份是对模型不可见的传输元数据,reviewer 提示词内容不变。

静态 x-opencode-session 请求头注意事项

pi-ai 1.1.0 只在不存在同名请求头(名称比较不区分大小写)时才添加 x-opencode-session。因此任何显式配置的 x-opencode-session 头——包括 X-OpenCode-Session 或其他大小写写法——都会优先于动态生成的每会话值,并被原样发送。

如果曾用静态请求头作为本缺陷的应急规避,它会把所有审查固定到同一个会话 ID,使按会话修复失效。动态验收前请:

  1. 检查 provider 配置中是否存在任意大小写的同名请求头;
  2. 移除它(本包不会代你修改 provider 配置);
  3. 用两个并发会话重跑验收,确认每个审查请求都以自己的会话 ID 到达网关。

上游「显式请求头优先」的规则未被改变,并已由 VERIFICATION.md 中的 D5 项在传输层验证;剩余确认为真实 OpenCode 网关验收(E2),尚未完成。

卸载与回退

移除本包层:

dsh plugin --profile <profile> remove dsh-opencode-auto-review
dsh --profile <profile> --dump-config

会发生与不会发生的事:

  • 移除组合层后,配置重算会恢复官方 auto-review 行此前的设置(本包只是停用了它);
  • 卸载会执行本包保留的官方清理行为:先关闭选择与 review admission,将所有仍处于 Auto 预设的会话迁移到 danger-full-access,并通过 Session writer 写入 never 审批策略;随后中止并等待在途审查结清,再撤回监听器与 preset contribution。沙箱值与持久终端在迁移中保持不变。模型在下一次 runtime-context 快照中看到新策略;不会排入策略变更通知;
  • 存活会话不会自动切回 Auto;重装本层只恢复该选项,也不会把存活会话切回。重装后重新选择 Auto 是用户的显式操作;
  • 移除本包会恢复官方实现,因此 OpenCode 的原始缺陷随之恢复:OpenCode 路由的 reviewer 请求不带 sessionId,网关以 MissingSessionID 拒绝,审查闸门关闭。回退只是回到基线,不代表 OpenCode 审查继续可用。

如果官方层只是为本包而添加、且不再需要 Auto review,可一并移除:

dsh plugin --profile <profile> remove @deepseek-ai/dsh-experimental-auto-review

权限模式迁移从来不是静默或无缝的:在安装、热替换、卸载或回退之后,都要确认当前会话的权限模式与审批策略。

验证状态

证据记录见 VERIFICATION.md,它与本 README 一起位于仓库检出中(发布清单列出的文件才是 tarball 内容;仓库还会包含设计文档、测试与验证记录)。该记录逐项列出验收检查、对应命令或产物证据,并把没有捕获证据的检查标记为 NOT COMPLETED。本 README 不声称任何该记录未证明通过的检查;记录中未标为 PASS 的项目都应视为未验证。

已知限制与延期工作

本版有意不增加:

  • 模型适配器或独立 reviewer 模型——reviewer 使用当前 agent 的 provider 与模型以及随附适配器默认值;
  • 重试、退避或回退层——每个受支持调用一次额外 reviewer 请求,超长或失败的请求使调用失败即拒绝;
  • 可配置策略、确定性工具豁免或持久授权;
  • UI 面板、新权限模式或新会话事件;
  • 提示词可见的会话身份——sessionId 只是传输元数据,reviewer 无法据此判断自己在审查哪个会话;
  • 文件沙箱:外层 run_code transport 与 PTC 程序内直接 Node 效果不经过 inner-tool review;
  • 对 provider 配置的任何修改,包括上文所述移除静态请求头的操作;
  • 对已验证窗口(0.2.1-rc.1 / 0.2.1-rc.2 / 0.2.1-rc.3)之外任何 DSH 版本的支持;尤其是 0.2.0-rc.x 线,它缺少本包注入的 workingDirectory 服务与 pi-ai 的 x-opencode-session 传输链路。

官方固有限制同样适用:模型分类可能出错(Auto 可能放行不安全动作、拒绝有用工作并消耗额外 token);进程外子代理在父委派调用获准后保留自身权限系统;reviewer 通过已废弃的同步 snapshotEvents() 读取会话动作历史。本包只处理 reviewer 缺少 sessionId 导致的 MissingSessionID;其他网关或 provider 拒绝不在范围内。

来源与许可证

本包以 MIT 许可证发布,Copyright (c) 2026 Dr.Scorpio。

派生自 @deepseek-ai/dsh-experimental-auto-review@0.2.1-rc.2,deepseek-ai/deepseek-harness 提交 687f282e8625c6b8d11ff58211a90524be2e4317,MIT,Copyright (c) 2026 DeepSeek。派生内容的第三方声明 位于 LICENSE 中 MIT 文本之后。确切的上游路径、文件哈希、派生变更和重新派生命令见 UPSTREAM.md。