前言¶
在 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 在仍有引用时会拒绝执行。
核心功能¶
- 注册 prompt 变量:默认变量名为
inject,可在cordis.patch.yml中改为符合[a-z][a-z0-9_]*的名字;预设 persona 的prefix末尾通过工具脚本追加{{variable}}(幂等)。 - 内容来源:支持
textFile(UTF-8 绝对路径,按 mtime 自动重载)或内联text;textFile优先;两者都空则不注入任何内容。 - 作用范围:可选
presets、sessions、cwds白名单;enabled总开关;可选stateFile/stateKey跟随外部 JSON 开关(键严格等于true才注入)。 - 配套脚本:
install.mjs/uninstall.mjs管理 profile 的dsh.profile.bundles;enable.mjs/disable.mjs管理预设引用;check.mjs列出 profile 内全部变量引用并在危险时以退出码 1 结束。 - 容错: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 列表相对稳定)。
启用流程概要:
- 在 profile 的
cordis.patch.yml中配置插件(见下一节)。 - 为目标预设挂上变量引用:
node tools/install.mjs
node tools/enable.mjs --preset preset-<你的预设 id>
node tools/check.mjs
- 重启 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 与白名单、开关决定何时返回空串。
典型用法¶
- 准备一段只给某个 complete persona 用的规则或上下文,保存为 UTF-8 文件,在配置里填
textFile。 - 对目标 agent 预设执行
node tools/enable.mjs --preset preset-<id>,在 personaprefix末尾追加{{inject}}(或你配置的variable)。 - 用
node tools/check.mjs确认引用与 bundles 配对正常后再重启 DSH。 - 需要临时关闭注入时,可设
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 为准。