dsh-prompt-inject:为 complete 预设注入可配置的 prompt 变量

前言

在 DeepSeek Harness(DSH)里,系统提示由多个 section 拼装。若某个 agent 预设使用了带 complete: true 的 persona(例如 @deepseek-ai/dsh-persona 独占整段人格),assemble() 会只保留这一个 section,其余通过 ctx.systemPrompt.section() 注册的段落都会被丢弃。常见做法是再堆 section,但在 complete 场景下这条路走不通。complete 段仍会经过 renderPrompt() 的 interpolate(),因此可以在 persona 文本里写 {{变量名}},由 prompt 变量 provider 返回值展开。下面介绍 MacilyDots 维护的 dsh-prompt-inject:把工作流里「一段附加提示」注册成变量,供预设前缀引用;插件本身不含固定文案,内容由你在配置或外部文件里提供。

这是什么

dsh-prompt-inject(npm 包名 @macily.dots/dsh-prompt-inject,当前资料中版本 0.1.2)是 DSH 工作流类插件。它向 DSH 注册一个可配置的 prompt 变量,让使用 complete: true persona 的 agent 预设仍能在系统提示里插入一块自定义文本。维护者为 MacilyDots;源码与说明见 GitHub 仓库,社区目录页为 SkillHub 插件页。许可为 MIT。

为什么需要 prompt 变量而不是再加 section

DSH 系统提示的注册入口是 @deepseek-ai/dsh-system-prompt 的 ctx.systemPrompt.section()。拼装时有硬规则:只要存在 complete: true 的 section,最终列表里只剩该段。此时还能生效的入口是 prompt 变量插值——complete 段不是拼接对象,但照样参与 interpolate(),前缀或 persona 里写 {{inject}}(名称可配置)即可展开。

需要注意:interpolate() 对未注册的变量会抛错(例如 unknown prompt variable "{{x}}" in section "..."),错误发生在渲染系统提示阶段,该预设下的会话链路会整体失败。因此前缀里写了 {{x}},就必须保证注册 x 的插件处于加载状态;卸载前先用 tools/disable.mjs 去掉引用;tools/check.mjs 可检查配对,tools/uninstall.mjs 在仍有引用时会拒绝执行。

核心功能

  1. 注册 prompt 变量:默认变量名为 inject,可在 cordis.patch.yml 中改为符合 [a-z][a-z0-9_]* 的名字;预设 persona 的 prefix 末尾通过工具脚本追加 {{variable}}(幂等)。
  2. 内容来源:支持 textFile(UTF-8 绝对路径,按 mtime 自动重载)或内联 text;textFile 优先;两者都空则不注入任何内容。
  3. 作用范围:可选 presets、sessions、cwds 白名单;enabled 总开关;可选 stateFile / stateKey 跟随外部 JSON 开关(键严格等于 true 才注入)。
  4. 配套脚本:install.mjs / uninstall.mjs 管理 profile 的 dsh.profile.bundles;enable.mjs / disable.mjs 管理预设引用;check.mjs 列出 profile 内全部变量引用并在危险时以退出码 1 结束。
  5. 容错:provider 在 assemble() 里同步调用,抛错会废掉会话;插件内部读文件、读状态均 try/catch,最坏返回空串(等同不注入)。

插件不注册 system-prompt section,因此不参与「多个 complete section」的冲突;同名变量重复注册仍会报错,需改 variable 配置避免与其他插件撞名。

安装与启用

下文用 %DSH_HOME% 表示 DSH 主目录(Windows 默认 %USERPROFILE%\.dsh,其它平台 ~/.dsh),profile 名默认 desktop。插件要求 Node >= 22.5。

从 npm 安装(官方命令):

dsh plugin --profile desktop add @macily.dots/dsh-prompt-inject

说明:npm 上必须使用 scope 包名 @macily.dots/dsh-prompt-inject;无 scope 的 dsh-prompt-inject 已被其它包占用。

手动安装等价于:将仓库复制到 profile 的 node_modules/@macily.dots/dsh-prompt-inject,再执行 node tools/install.mjs 写入 bundles。DSH 是否加载插件由 package.json 的 dsh.profile.bundles 决定,而不是仅改 cordis.patch.yml(GUI 可能重写 patch,bundles 列表相对稳定)。

启用流程概要:

  1. 在 profile 的 cordis.patch.yml 中配置插件(见下一节)。
  2. 为目标预设挂上变量引用:
   node tools/install.mjs
   node tools/enable.mjs --preset preset-<你的预设 id>
   node tools/check.mjs
  1. 重启 DSH。

所有写操作脚本会在同目录留 .bak-prompt-inject-<时间戳> 备份;加 --dry 可预览不落盘。

配置示例

在 profile 的 cordis.patch.yml 里覆盖插件项:

- id: prompt-inject
  config:
    variable: inject
    textFile: '<文本文件的绝对路径>'
字段 默认 说明
variable inject 注册的变量名;预设里写 {{<这个名字>}}
textFile '' 文本文件路径(UTF-8),改动后按 mtime 重载
text '' 内联文本;textFile 优先
presets [] agent 预设 id 白名单;空表示不限制
sessions [] 会话 id 白名单
cwds [] 工作目录白名单(header.cwd)
enabled true 总开关
stateFile '' 外部 JSON 开关文件
stateKey enabled 从 JSON 读取的键,须严格为 true 才注入
debug false 写入 %DSH_HOME%/prompt-inject.log

variable 与 presets 是两道独立闸门:引用决定哪些预设会展开该变量;provider 与白名单、开关决定何时返回空串。

典型用法

  1. 准备一段只给某个 complete persona 用的规则或上下文,保存为 UTF-8 文件,在配置里填 textFile。
  2. 对目标 agent 预设执行 node tools/enable.mjs --preset preset-<id>,在 persona prefix 末尾追加 {{inject}}(或你配置的 variable)。
  3. 用 node tools/check.mjs 确认引用与 bundles 配对正常后再重启 DSH。
  4. 需要临时关闭注入时,可设 enabled: false、收窄白名单,或通过 stateFile 与其它插件联动;改文件内容无需重启(textFile 按 mtime 重载)。

适用场景与注意

适合:已采用 complete: true persona、又需要在系统提示里稳定插入团队规范、项目说明或可变指令块的 DSH 用户;希望把注入内容与 persona 仓库解耦、用外部文件或开关控制的情况。

务必注意:

  • 插件以当前 DSH 进程权限运行,安装前应阅读源码与 MIT 许可证,确认 textFile 路径与内容可信。
  • 未注册变量即引用会导致整条预设会话失败;变更 bundles 或卸载前必须 disable 并 check。
  • 卸载顺序:node tools/disable.mjs --preset <preset-id> → node tools/uninstall.mjs → 重启 DSH → 自行删除 node_modules 中插件目录。

结尾

dsh-prompt-inject 不试图绕过 complete section 的拼装规则,而是利用 prompt 变量插值,在 complete persona 预设上追加可配置文本块;配合 bundles 安装、enable/check 脚本和 cordis.patch.yml 配置,把「引用」与「何时注入」分开管理。更多细节以仓库 README 为准。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye