为 DSH 会话挂一个独立评审模型:观察主会话 transcript,按 nit/concern/blocker 三级严重度把建议注入回主循环,不接管也不递归评审自己。
- 语言
- TypeScript
- License
- MIT
- 分支
- main
安装
$ dsh plugin --profile web add github:btspoony/dsh-advisor在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
对话式安装
帮我安装 DeepSeek Harness 插件 btspoony/dsh-advisor:先查看仓库 https://github.com/btspoony/dsh-advisor 确认安全性,然后执行安装命令并验证插件加载成功。
把这段指令粘贴给 DSH Web GUI 里的助手,由它代你完成安装与验证。
一句话定位
为 DSH(DeepSeek Harness)会话挂一个独立的评审模型:观察主会话 transcript,按 nit / concern / blocker 三级严重度把建议注入回主循环,既不接管主代理的动作,也不递归评审自己发出的建议。
核心能力
- 按会话运行一个独立的评审模型,每个 stepped 主 turn 评审一次;评审模型和主代理完全隔离,只发建议、不执行工具
- 按严重度把建议投递到主循环:nit(轻微样式 / 清晰度建议)走非唤醒通道、concern / blocker(值得停下权衡 / 明显继续就是在浪费工作)走唤醒通道并带可配的冷却步数
- 评审模型和 provider / model 由用户在
advisor命名空间显式声明,启用时未同时填齐就拒发起模型调用(硬门禁,不是警告),未知配置键会直接拒绝加载 - 失败策略不卡主循环:限流 / 配额耗尽时只丢弃自己有界 backlog,永久错误进入 halted,任何状态下主代理都不会被阻塞或污染
- 支持三条等价的配置面:profile 补丁层、web Settings 的 Advisor 卡片、dsh-tui
/settings的 Advisor 分节(dsh-tui ≥ v0.8.0),保存后新会话立即生效、无需重启 - 在会话里用
/advisor(toggle)或/advisor on/off/status/config临时控制本会话评审;这些命令只翻转会话级 override,永远不会写入持久化配置
技术实现
- 语言: TypeScript(host 端 + client 端 React 组件),输出 ESM
- 关键依赖:
@deepseek-ai/cordis^4.0.1(host 服务注入)、@deepseek-ai/dsh-session/@deepseek-ai/dsh-agent/@deepseek-ai/dsh-llm(订阅会话事件、调用评审模型)、@deepseek-ai/schemastery^3.18.1(设置 schema)、@deepseek-ai/dsh-typert-protocol+@deepseek-ai/dsh-typert-registry(自建/api/advisor/get|set网关通道) - 架构模式: mount-only cordis 插件——
cordis.patch.yml只插入一行id: advisor;host 端通过订阅session/event/agent/created/agent/disposed驱动观察器 → 评审运行时 → 投递路由 → 发射守卫;client 端通过settings.plugin.item插槽注册设置卡片;自带 typert 网关是唯一读写advisor命名空间的用户层路径,不修改 dsh 源码 - 入口文件:
src/index.ts(host 端apply()+name+inject: ['sessions','agents','llm'])、src/client/index.ts(client 端 React 组件注册),分别被 bundle patch 与dsh.client.inject列表装载
适用场景
想给 DSH 会话配一个「旁观者清」的二审模型、但又不希望它接管主代理的工具调用时使用:评审模型在每个 stepped 主 turn 后独立调用一次,按 nit/concern/blocker 把建议插回主会话,主代理拿到的是带 [advisor:{severity}] 前缀的 user-role 消息。适合需要持续捕捉方向偏离、明显的代码异味、或者与用户原意相悖行为的开发者;不适合需要工具自验或并行多个评审者的场景(这两类显式不在 MVP 范围内)。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH | ^0.1.1-rc.2 | 所有 @deepseek-ai/dsh-* peer 依赖均为 ^0.1.1-rc.2(package.json:53-69);dsh-tui /settings 面板需要 ≥ v0.8.0(README.md:50、docs/configuration.md:7) |
| Node.js | `^22.19 | |
| 平台 | 跨平台 | package.json 未声明 os / cpu,无原生模块依赖 |
| 原生模块 | 无 | 不引入 node-pty、node:sqlite 等原生绑定 |
安装方式
dsh plugin --profile web add github:btspoony/dsh-advisor
配置项
所有配置都落在 dsh 设置文档的 advisor 命名空间下,可通过 web Settings 的 Advisor 卡片、$DSH_HOME/settings.yaml 文件、或 dsh-tui 的 /settings 区域编辑。说明列写人话,完整字段约束见 docs/configuration.md。
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
enabled | boolean | 总开关;关闭时插件完全 no-op | false |
provider | 字符串(启用时必填) | 评审模型走哪个 provider 路由;空字符串也会被门禁拦下 | 未设置 |
model | 字符串(启用时必填) | 评审模型 id;空字符串也会被门禁拦下 | 未设置 |
systemPrompt | 字符串 | 自定义评审 prompt;留空则用内置的严重度定义 + JSON 输出契约 | "" |
immuneTurns | 整数 ≥ 0 | 刚送过一次打断性 note 后,必须先完成多少个 stepped 主 turn 才能再送下一次;窗口内新的打断性 note 自动降级为 inject | 3 |
maxDeltaMessages | 整数 ≥ 0 | 每次评审送给评审模型的 transcript 增量上限;超过则截断并标注;0 表示无上限 | 60 |
未知键会被严格拒绝并阻止插件加载;
enabled: true但provider/model缺失或仅含空白,会被解析为「禁用并给出原因」,状态查询可见,运行时不发模型调用。
常见问题
Q: 装上之后默认就会开始评审吗?
A: 不会。enabled 默认是 false,插件默认零侵入。需要先在 Advisor 卡片(或 settings.yaml)里打开 enabled,并同时填好 provider 和 model,否则评审模型根本不会发起调用,状态会显示「禁用并给出原因」。
Q: 我打开了开关,但 provider / model 还没填,怎么办?
A: 这是「硬门禁」而不是警告:插件永远不会调用评审模型,/advisor status 会给出具体原因(缺 provider、缺 model、或两者都缺)。web 卡片在这种情况下会直接阻止保存;dsh-tui /settings 没有跨字段校验,可能保存后还是被门禁拦下,行为一致。
Q: 评审意见会以什么形式进入主会话?
A: 作为一条带 [advisor:{severity}] 前缀的 user-role 消息。nit 不打断主代理、在下一个 pre-step 边界消费;concern / blocker 唤醒主代理立即权衡;为了避免评审风暴,刚送过一次打断性 note 后必须先完成 immuneTurns 个 stepped 主 turn,下一条打断性 note 才能再次唤醒,期间会自动降级为 inject。
Q: 怎么在单个会话里临时开 / 关评审?
A: 输入 /advisor 切换、或 /advisor on / /advisor off 显式控制,/advisor status 看当前会话的开关 / provider / model / 运行时状态(running / paused / quota_exhausted / halted / disabled)/ 待处理数 / 最近一次注入时间。这些命令只翻转本会话的临时 override,不会写入持久化配置。
Q: 评审模型被限流或挂了,会影响主代理吗?
A: 不会。失败策略只丢评审自己有界 backlog;quota 耗尽进入 quota_exhausted(需 /advisor on 手动恢复,无自动恢复计时器);永久错误(如凭据失效)进入 halted(/advisor on 会原地重建一个全新的评审实例)。任何状态下主循环都不会被阻塞或被污染。
Q: 我能在 dsh-tui 终端里编辑这些配置吗?
A: 在 dsh-tui ≥ v0.8.0 的 /settings 屏幕里可以编辑 enabled / provider / model / immuneTurns / maxDeltaMessages 这五个键;systemPrompt 故意没做进 TUI 字段(单行输入控件会截断多行 prompt),请用 web 卡片或 settings.yaml 编辑。低于 v0.8.0 的 dsh-tui 会干净地 no-op,仍可以走文件或 /advisor config 回读配置。
Q: 我在配置里写错了键名(比如多了个空格或多打了一个字段),会被悄悄忽略吗?
A: 不会。advisor 命名空间走严格 schema,未知键会直接抛错并拒绝插件加载;如果错的是 settings user layer(web 卡片 / TUI 写入),热路径会落到带原因的「禁用」状态,永远不会发起模型调用。
Q: 卸载需要做什么额外操作吗?
A: 跑 dsh plugin --profile web remove dsh-advisor(或对应的 dsh-tui profile)然后重启会话即可。插件没有任何 postinstall 钩子,也没有改过 dsh 源码,卸载是干净的。
上手难度
进阶 — 启用门槛很低(卡片打开开关 + 填两个字段),但要理解 advisor 的语义(inject vs steer 的区别、immuneTurns 冷却、emission guard 去重、单评审者守卫)需要先读几分钟配置文档;不需要改任何 dsh 源码。
已知问题与限制
- 每个会话只有一个评审者实例,不支持并行评审者 roster 或基于
WATCHDOG配置文件自动发现(README.md:97)。 - 评审者只能发建议,没有任何 advisor 工具——它不能自己读文件 / 跑命令验证自己的怀疑(
README.md:98)。 - 没有会话内的 advisor 面板:建议只以注入消息的形式出现在主会话里;web Advisor 卡片是配置面板,不是会话视图(
README.md:99)。 - 没有 transcript 持久化、没有成本统计:插件不写自己的 advisor 历史,也无法做成本可观测(
README.md:100)。 - transcript 里的 secrets 不会被混淆,会原样到达评审模型;如需保密请配可信的私有评审模型(
README.md:101)。 - 没有「不安全输出的隔离区」:评审模型理论上可以在 note 里塞指令性文本,目前的缓解仅有 JSON 帧 + 校验 + advisory-only 包装(
README.md:102)。 - 没有
syncBacklog追赶等待:评审模型严重落后时不会等主循环,有界 backlog 直接丢弃,note 可能晚于下一个主 turn 送达(README.md:103)。 - 评审上下文有界(
maxDeltaMessages):长会话超过窗口后早期内容会被截断,compaction 后评审模型可能丢失早期上下文(README.md:104)。 - 单评审者守卫(
globalThis.__dshAdvisorReviewer__):当 host 同时 compose 多份 dsh-advisor fiber 时,只有第一份真正接管观察 / 运行时 / 指令;后续 fiber 只尝试注册 settings 命名空间并在已注册时干净 no-op(src/index.ts:80-99、src/index.ts:319-323)。
A standalone dsh (DeepSeek Harness) plugin bundle porting the omp "advisor" subsystem: a per-session independent reviewer model that observes the primary transcript, reviews each stepped turn with an explicitly configured model (provider + model are required), and injects severity-ranked advice (nit / concern / blocker) back into the session — without polluting or recursively reviewing itself.
Advisory only. The advisor never approves or rejects the primary agent's actions, and never issues commands as if it were the primary agent. Every delivered message is self-described advisory content, and a misbehaving reviewer is bounded end to end (emission guard, immuneTurns cooldown, failure policy) so it can never stall or pollute the primary loop.
Works in both dsh front ends: the web profile (Settings → 插件配置 → Advisor card) and the dsh-tui terminal profile (/advisor + /advisor config).
Quick start
Install
dsh plugin --profile web add dsh-advisor # web profile (Settings → Advisor card)
dsh plugin --profile dsh-tui add dsh-advisor # dsh-tui terminal profile
Same plugin, either front end — the only difference is the --profile flag. Pin a version with @<version> (e.g. [email protected]). A registry install fetches the published tarball, which ships the built artifacts (lib/ + cordis.patch.yml) — nothing builds on the target machine, and runtime dependencies (@deepseek-ai/cordis, @deepseek-ai/schemastery, @deepseek-ai/dsh-* peers) resolve through the dsh installation's flat profile module fallback — no extra install step. Registry / git / tarball / local-directory variants (local-dir from a built checkout: dsh plugin --profile web add . or dsh plugin --profile dsh-tui add .), web Settings exposure, uninstall, and --dump-config verification → docs/install.md.
Configuration
Add an advisor: section to the global dsh settings document (default $DSH_HOME/settings.yaml — shared across profiles; the web Settings card writes to this same file):
advisor:
enabled: true # master switch (default false) — set explicitly to enable
provider: deepseek-official # REQUIRED when enabled
model: deepseek-v4-flash # REQUIRED when enabled
systemPrompt: "" # optional; "" = built-in reviewer prompt
immuneTurns: 3 # int ≥ 0, default 3 — cooldown after a delivered steer
maxDeltaMessages: 60 # int ≥ 0, default 60 — delta window; 0 = unbounded
The advisor is off by default. When enabled, provider and model are mandatory: enabled: true without both is a hard gate — the advisor never starts a model call and reports a disabled-with-reason status; unknown config keys are rejected.
The same keys compose across three surfaces (later layers override earlier ones; every surface shares the same key set and the same hard gate, with the host-side gate as the final line of defense on every path):
- Plugin-row config — the profile patch layer (
$DSH_HOME/profiles/<profile>/cordis.patch.yml). This is the composition base. - dsh web Settings page — the "插件配置" (Plugin Configuration) page — the Advisor card (namespace key
advisor) with the enabled toggle, provider / model selects restricted to system-configured providers and their models, and the optional fields. Saving writes into theadvisorsettings namespace and applies to new sessions immediately — no restart. The card requires a current dsh web build whose shell declares thesettings.plugin.itemcard slot and loads packages that declaredsh.client; it reads and writes the namespace through the officialGatewayServiceRPC channel (/api/advisor/get+/api/advisor/set), which is not gated by the settings exposure allowlist. It additionally blocks saving while enabled with a required field empty. /advisorcommand — per-session and ephemeral: it flips a session override, never the persisted config (see Verify).
In a dsh-tui profile the same five keys are editable in the TUI /settings screen: run dsh --profile dsh-tui, open /settings, and edit the Advisor section (enabled / provider / model / immuneTurns / maxDeltaMessages, each with zh/en label + hint). Edits are staged and written on save through the revision-fenced settings.mutate into the same advisor namespace user layer the web card writes, and re-apply live without a restart. systemPrompt is NOT a TUI field (the TUI text control is single-line; a multi-line prompt would be truncated) — edit it via the web card or $DSH_HOME/settings.yaml. The section requires dsh-tui ≥ v0.8.0 (shipped in the dsh-tui-settings-sections row of the v0.8.0+ bundle); older dsh-tui versions no-op it cleanly and the two file paths — profile patch layer + global $DSH_HOME/settings.yaml — remain the edit paths. /advisor config stays a read-only readback whose edit hint names the /settings screen when the seam is mounted. Save behavior differs from the web card: the TUI seam has no cross-field validation, so a save may set enabled: true with empty provider/model — the explicit model gate resolves that to disabled-with-reason at runtime (visible via /advisor status and /advisor config); the web card blocks such a save outright. Full reference → docs/configuration.md.

Verify
dsh --profile web --dump-config # shows a "# == dsh-advisor" layer with the advisor row
With the advisor installed and enabled, control it in-session with the /advisor command (available when a command registry is composed):
/advisor toggle the advisor for this session
/advisor on enable the advisor for this session
/advisor off disable the advisor for this session
/advisor status show state, model, runtime status, pending count, last activity
/advisor on|off|toggle are session-scoped and ephemeral: they flip a per-session override, never the persisted config. Enabling a session whose config lacks provider/model starts no model call — /advisor status (and the /advisor on reply) shows the gate reason: the advisor runs only when enabled with both configured. /advisor on is also the manual recovery path: a session advisor paused by a quota/rate-limit (quota_exhausted — no auto-resume timer) resumes in place, and a halted advisor (permanent model error, e.g. invalid credentials) is rebuilt fresh for the session.
In a dsh-tui profile, /advisor config additionally reads back the composed configuration — read-only, with edit hints naming the real write paths: the TUI /settings screen (Advisor section, dsh-tui ≥ v0.8.0), the profile patch layer, and the shared $DSH_HOME/settings.yaml advisor: section. The /advisor / on|off|status|config commands are listed in the TUI / menu with subcommand completion (command discovery requires the dsh-tui-command-trees row — the shipped dsh-tui bundle has it).
Features
-
Independent reviewer per session: a separate model call observes the primary transcript and reviews each stepped primary turn; advisor messages are excluded from later deltas, so the advisor never reads its own advice back.
-
Severity-ranked advice with inject/steer semantics: at most one note per review — nit (a minor style, clarity, or quality suggestion; delivered via non-waking
agent.inject, consumed at the next pre-step boundary), concern (a material risk or clearly better direction to weigh before continuing; delivered via wakingagent.steer, subject to theimmuneTurnscooldown), blocker (continuing clearly wastes work — contradicts an explicit user instruction, going in circles, fundamentally unsound; delivered viaagent.steer). Delivered messages carry the[advisor:{severity}]prefix and are self-described advisory content:[advisor:concern] extract the helper into a module and unit-test it -
Explicit model gate:
enableddefaults to off;enabled: truewithoutprovider+modelnever starts a model call — status reports disabled-with-reason. Unknown config keys are rejected. -
Zero-tool minimal start: the reviewer is an independent model call only — no advisor tools, nothing it can do to the session besides advisory messages.
-
No-stall failure policy: a failing or quota-limited advisor only drops its own bounded backlog — it can never park or pollute the primary loop.
-
Session-scoped controls:
/advisor on|off|status|configwork per session; the toggles are ephemeral overrides, never persisted config.

Mount-only (no dsh modification)
The plugin installs as a pure mount: bundle insert + client card (web Settings 插件配置) + its own gateway channel (/api/advisor/get|set, claimed by the host's typertGateway — the same mechanism the dsh goals service uses, not gated by the settings exposure allowlist) + the /advisor commands — no dsh patches, no postinstall step, and dsh upgrades never require re-patching.
Limitations & roadmap
The MVP deliberately drops full omp parity. Accepted gaps (tracked in the harness iteration roadmap):
- Single advisor per session — no parallel advisor roster or WATCHDOG-style file discovery (next iteration).
- No advisor tools — the reviewer is an independent model call only; it cannot verify claims itself (next-next iteration).
- No in-session advisor panel — advice surfaces only as tagged injected messages; the web Advisor card is a config surface, not a session view (next-next iteration).
- No transcript persistence or cost stats — no resumable advisor history or cost observability (next-next iteration).
- No secret obfuscation of delta content — secrets present in the transcript can reach the advisor model; mitigate by configuring a trusted reviewer model.
- No quarantine of unsafe advisor output — a misbehaving note can carry directive text; the JSON frame + validation + advisory-only framing are the only mitigation, and the note is delivered as-is (roadmap).
- No
syncBacklogcatch-up wait — a far-behind advisor does not wait for the primary loop; its backlog is bounded and dropped, so notes may arrive after the next primary turn started (roadmap: context-maintenance batch). - Bounded advisor context — long-session full replays are truncated (
maxDeltaMessages), so the advisor may lose early context after compaction (roadmap: next-next iteration).
Documentation
| Doc | Content |
|---|---|
| docs/install.md | profile install (web + dsh-tui) / registry / git / tarball / local-directory variants / web Settings exposure / uninstall / --dump-config verification |
| docs/configuration.md | full advisor namespace reference: keys & defaults, explicit model gate (S4), settings surfaces (web card / patch layer / global settings.yaml), example YAML, live re-apply behavior |
| docs/consumer-api.md | developer consumption contract: package-root library API, dsh-advisor/client entry, /advisor command surface, export inventory, lifecycle |
| docs/verification.md | verification records: test matrix (16 files / 319 cases), typecheck/build, CI contract, real-environment steps |
| docs/release.md | release process: PR-driven Release prep + Release workflows, OIDC trusted publishing, version strategy, rollback |
License
Released under the MIT License — see LICENSE. The LICENSE file is authoritative for copyright and license terms.
查看使用指南 →
该插件的安装步骤、关键要点、FAQ 与兼容性说明(基于已收录字段派生)。
收录徽章
[](https://deepseek-plugin.org/plugins/btspoony/dsh-advisor)把这段 markdown 粘贴到你的 GitHub README,链接回本插件详情页。徽章只声明已被本站收录,不代表安全认证。