Skip to content
dsh.fish
Bundle

dsh-persona-anchor

Pin a persona prompt section that never competes for the AGENTS.md instruction budget

Source
harmless0819-dev
License
MIT
Updated
Updated 5 days ago

Readme

# 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()` 里有这一句:

```js
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),即「部署人设」该在的位置。

## 安装

```sh
dsh plugin --profile web add github:harmless0819-dev/dsh-persona-anchor
```

## 配置

```yaml
- 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

Install

dsh plugin --profile web add github:harmless0819-dev/dsh-persona-anchor#2ca773fb709eee2a451ef8a268eddb4c17f99bf1

Profile: web

Source