dsh-advisor
dsh plugin bundle porting the rpiv advisor subsystem: an on-demand zero-parameter advisor() tool that forwards the full session to a separately-configured reviewer model.
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 23, 2026
- Updated
- Aug 23, 2026
Introduction
dsh-advisor
English | 中文
A standalone dsh plugin bundle porting the
rpiv-advisor
mechanism: a zero-parameter advisor() tool registered per agent scope.
When the primary model needs stronger judgment it calls advisor() on demand;
the plugin forwards the full derived session history plus the executor tool
inventory to a separately-configured reviewer model using the original
rpiv system prompt, and the free-text plan / correction / stop signal comes
back as the tool result in the same turn.
Install with a single command:
dsh plugin --profile web add dsh-advisor # <name> = your profile name
On demand, never automatic. There is no per-turn observer, no injected
[advisor:*] message, and no severity-routing runtime. The primary model keeps
control: it calls advisor() when it decides a stronger reviewer would help,
and it consumes the result before continuing.
Install
One-line registry install
dsh plugin --profile web add dsh-advisor # <name> = your profile name
A registry install fetches the published tarball, which ships the built
artifacts (lib/ + cordis.patch.yml), so no prepare build or build
permission is needed. Runtime dependencies (@deepseek-ai/cordis, @deepseek-ai/schemastery,
and the @deepseek-ai/dsh-* peers) are declared as peerDependencies and resolve
through the dsh installation's flat profile module fallback — no extra install
step. Pin an exact version (dsh-advisor@0.1.3) for reproducible installs.
Local directory install (recommended for development / verification)
pnpm install # build the bundle (the prepare self-build)
dsh plugin --profile web add . # <name> = your profile name
Verify
dsh --profile web --dump-config # shows a "# == dsh-advisor" layer with the advisor row
dsh --profile web
Tarball install and uninstall are covered in docs/install.md.
Config

The advisor is off by default. When enabled, provider and model are
mandatory: enabled: true without both is a hard gate — the advisor tool
is not installed for any agent and reports a disabled-with-reason status.
Unknown config keys are rejected.
Configuration composes across three surfaces (later layers override earlier ones; every surface uses the same key set):
- Plugin-row config —
$DSH_HOME/profiles/web/cordis.patch.yml(below). This is the composition base. - dsh web Settings page — the "插件配置" (Plugin Configuration) page —
the Advisor card (id
advisor, rendered after the upstream bash / agent-loop / web-search cards) with the enabled toggle, provider / model selects restricted to system-configured providers and their models, a reasoning-effort select driven by the selected model's catalog metadata, and the system-prompt override. Saving writes into theadvisorsettings namespace and overrides the plugin-row config without editing it. Saving applies immediately — no restart (the runtime reads the composed value live; existing sessions are reconciled). Requires a current dsh web build whose shell declares thesettings.plugin.itemcard slot and loads packages that declaredsh.client. The card reads and writes the namespace through the officialGatewayServiceRPC channel (/api/advisor/get+/api/advisor/set, claimed by the host's typertGateway — the same mechanism the dshgoalsservice uses), which is not gated by the settings exposure allowlist: the in-process write (ctx.settings.update) carries no exposed-namespace check. No host patching is applied or required. /advisorcommand — per-session and ephemeral: it flips a session override, never the persisted config (see Usage).
Both persisted surfaces share the same hard gate: enabled: true with empty
provider/model never starts a model call (disabled-with-reason). The
Settings page additionally blocks saving while enabled with a required field
empty; the host-side gate stays the final line of defense on every path.
guidance and disabledForModels are full config keys and ride every
configuration surface; the web card currently preserves them while editing the
card-exposed fields.
Plugin-row config:
# profiles/web/cordis.patch.yml — the profile's user patch layer
- id: advisor
config:
enabled: true # master switch (default false)
provider: deepseek-official # REQUIRED when enabled
model: deepseek-v4-flash # REQUIRED when enabled
reasoningEffort: high # optional; "" = auto (high when supported)
systemPrompt: "" # optional; "" = original rpiv advisor prompt
guidance: # optional executor prompt override
promptSnippet: "Call advisor before substantive work."
promptGuidelines: ["Call advisor again before declaring done."]
disabledForModels: [] # optional executor blocklist; [] = none
| Key | Type / default | Meaning |
|---|---|---|
enabled | bool, false | Master switch. |
provider | string, optional | Provider route. Required (non-empty) when enabled: true. |
model | string, optional | Model id. Required (non-empty) when enabled: true. |
reasoningEffort | string, "" | "" = auto (high when the advisor model supports it); or minimal / low / medium / high / xhigh / max / off. Unsupported values are omitted. |
systemPrompt | string, "" | Overrides the built-in original rpiv advisor prompt. "" = built-in. |
guidance | object, optional | Executor-facing prompt override: promptSnippet and/or promptGuidelines; only non-empty values are used, otherwise rpiv defaults apply. |
disabledForModels | array, [] | Executor blocklist. Entries are "provider/model" or `{ model: "provider/model", minEffort?: "minimal |
The old automatic-reviewer keys immuneTurns and maxDeltaMessages are
accepted for profile-upgrade compatibility but are ignored: the new mechanism
has no cooldown or transcript-delta window.
Usage
Once installed and enabled, every eligible agent scope gets the advisor tool
plus the rpiv prompt guidance. Control it per session with the /advisor
command (available when a command registry is composed):
/advisor toggle the advisor tool for this session
/advisor on enable the advisor tool for this session
/advisor off disable the advisor tool for this session
/advisor status show model, effort, tool visibility, and gate/blocklist reasons
/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 installs no tool — /advisor status (and the
/advisor on reply) shows the gate reason. A session whose executor model is
listed in disabledForModels behaves the same way.
When the primary model decides it needs the reviewer, it calls:
advisor()
The result is the advisor's free-text plan, correction, or stop signal as a normal tool result. The primary model stays in its current turn, reads the guidance, and continues — per the rpiv guidance, it surfaces the key advice in its next visible reply. The advisor model is never given tools and never writes into the session transcript directly.
How it works
The plugin keeps a live resolved config bridge and wires each agent at the
agent scope (agent.ctx):
- On
agent/created, if the hard gate passes, the session override is on, and the executor model is not indisabledForModels, the plugin registers the zero-parameteradvisortool plus atool:advisorsystem-prompt section (promptSnippet+promptGuidelines, defaulting to the rpiv text) into that agent. Off or blocked scopes get no tool and no prompt text. - When
advisor()executes, the plugin builds the request as tool inventory first, then the session's full derived history (session.deriveMessages()), stripping the in-flightadvisor()call from the tail and guaranteeing a user-role tail. - The side call uses
ctx.llm.streamwith the separately configured provider/model, the original rpiv advisor system prompt (or the configured override), no tools, and the capability-gated reasoning effort (""auto →highwhen declared by the model). - Collected text becomes the tool result. Expected failures — no session, session off, hard-gate disabled, blocklisted, aborted call, model error, empty response (retried once) — all return explanatory text instead of throwing, so the primary model can always react in the current turn.
- Settings changes reconcile every live agent (install/uninstall the scoped
tool as needed); guidance text reads live config through its prompt-section
provider.
/advisoronly changes the per-session override.
Limitations & roadmap
- No Pi TUI model picker — dsh command handlers return text only, so model/effort selection lives in the Settings card and plugin config.
- No advisor tools — the reviewer is an independent model call only; it cannot verify claims itself (rpiv parity behavior).
- No in-session advisor panel — the Advisor card on the "插件配置" settings page is a config surface, not a session view.
- No transcript persistence or cost stats — no resumable advisor history or cost observability.
- No secret obfuscation — secrets present in the transcript can reach the advisor model; configure a trusted reviewer model.
- No quarantine of unsafe advisor output — the original prompt asks for directive guidance only; the primary model's own rpiv guidelines tell it to treat advice as advice, but text is returned as tool output.
- Full history is sent on every call —
deriveMessages()is the complete current surface; the original mechanism intentionally has no bounded delta window.
Development
The bundle builds itself on install: package.json declares
"prepare": "pnpm build", so any clone is immediately buildable. Private
@deepseek-ai/* runtime packages are peerDependencies only and resolve
from the npm registry at dev time (autoInstallPeers: true in
pnpm-workspace.yaml plus the user-level registry auth); no local dsh source
tree or link farm is required.
pnpm install # registry deps + prepare self-build
pnpm test # vitest (unit + client + gateway/settings suites)
pnpm typecheck # tsc --noEmit (node) + tsc -p tsconfig.client.json --noEmit + tsc -p tsconfig.spec.json --noEmit
pnpm build # tsc -p tsconfig.build.json emit to lib/ + node scripts/build-client.mjs (client bundle)
pnpm pack # build + produce dsh-advisor-0.1.3.tgz
prepack runs pnpm build; prepare is build-only, so pnpm pack builds
twice (once per lifecycle) — the accepted tradeoff that keeps git-install
builds working. pnpm build clears lib/ first (scripts/clean-lib.mjs) so
deleted modules never linger in the tarball. There is no postinstall step:
already-built tarball installs skip the build entirely.
The test suite covers the rpiv-port config/gate/policy, context massaging,
inventory cache, the side-call execute contract, per-agent registration, the
/advisor command, settings bridge + gateway, and the web card store/component
bundle contract.
Documentation
| Doc | Content |
|---|---|
| docs/install.md | full install guide: git / tarball / local-directory install, web Settings exposure, uninstall, --dump-config verification |
| docs/configuration.md | config fields, hard gate, agent-scoped wiring, side-call behavior, web card behavior |
| docs/consumer-api.md | package exports, gateway service, client entry, /advisor command |
| docs/verification.md | test matrix, typecheck/build expectations, real-environment verification |
License
MIT