dsh-persona-anchor
把「人设」文本钉进 system prompt,且不吃 AGENTS.md 的指令预算。
- 插件类型:DSH host plugin(web profile),无客户端半边
- 依赖:仅 node 内置模块
- 状态:自用插件,已在本机跑通
为什么需要它
人设原本写在全局 ~/.dsh/AGENTS.md 里,由 @deepseek-ai/dsh-agent-instructions 注入。
那个插件给「全局 + 项目 AGENTS.md」总共 65536 字节(maxBytes),渲染规则是
按最宽泛 → 最具体排序,先整份丢掉最宽泛的,放不下才截断最具体那份。
人设恰好在最宽泛那份里 ⇒ 项目文件一长大,人设就是第一个被牺牲的,
而且不报错(只在注入块顶部留一行 Workspace instruction budget …)。
源码核对(dsh-agent-instructions/lib/index.js):Config 只有
maxBytes / maxSourceBytes / 候选名之类,没有任何 pin / alwaysInclude / priority
能保住某个文件。
⇒ 结论:在 AGENTS.md 这条通道里没有「永不掉」的配置,必须换通道。
为什么不用 personaPrefix(最直觉,但会静默失效)
dsh-system-prompt 的 assemble() 里有这一句:
const sectionByName = this.layers.merge(scope, (layer) => layer.sections)
而 section() 的文档写着「A scoped section shadows a global section with the same name」。
本机默认 agent preset 是 standard,它自己就注册了 deployment:persona-prefix
⇒ 往跑着的会话上写 personaPrefix,会被那个 scoped section 整个盖掉,且不报错。
这正是本插件存在的理由:换一个没人会注册的 section 名。
做法
注册一个独有名字的 prompt section(默认 deployment:persona-anchor),内容从磁盘文件读。
- 名字独有 ⇒ 不可能被 preset shadow
- 通道是
systemPrompt.section() ⇒ 完全不经过 65536 预算
排序借用 getSectionOrder('DEPLOYMENT_PERSONA_PREFIX')(= 0),即「部署人设」该在的位置。
安装
dsh plugin --profile web add github:harmless0819-dev/dsh-persona-anchor
配置
- id: dsh-persona-anchor
name: dsh-persona-anchor
config:
file: 'C:/Users/<you>/.dsh/persona.md' # 必填,绝对路径
onError: log # log(默认)| throw
| 键 | 默认 | 说明 |
|---|
file | 必填 | 人设文件绝对路径 |
section | deployment:persona-anchor | section 名;改成别的独特名也行 |
maxBytes | 524288 (512 KiB) | 单次读取上限,防手滑指到大文件 |
onError | 'log' | 读文件失败时:log 只告警 / throw 硬失败 |
order | 部署人设位 | section 排序 |
reloadMs | 0 | >0 时定时重读 |
route | true | 是否注册状态路由 |
验证它真的生效
改完 persona.md 后,新开一个会话,问它「你的名字/设定是什么」。
若人设没进来,插件会注册一个状态路由报告 state.error,可从那里看到失败原因
(文件不存在 / 太大 / 空文件)。
注意
inject 只列了 systemPrompt。webServer 是可选依赖,
代码里用 ctx.inject([...]) 延迟注册 —— 写进顶层 inject 会让
headless profile(没有 webServer)整个加载失败。
- 读文件失败默认不抛,只在日志和状态里报告,避免一个人设文件打不开就把整个 profile 搞挂。
License
MIT