dsh-memory-system
给 DeepSeek Harness(DSH)用的工作区级永久记忆插件:会话一开始,当前工作区的 记忆系统/00_热层.md 与 01_冷层索引.md 就已经在系统提示里,不用再靠模型「自觉先读文件」。
记忆不该靠自觉,应该靠注入;但注入不该污染别的工作区。
仓库:https://github.com/juechen06/dsh-memory-system
它做什么
- 装配提示词时,把当前 workdir 下的
记忆系统/热层 + 冷层索引注入为一个名为memory-system:boot的上下文块; - 工作区里没有
记忆系统/00_热层.md→ 完全不注入,别的项目零影响; - 文件按
mtime缓存 2 秒,内容不变时提示词前缀稳定,不额外烧缓存; - 任何异常都只让插件闲置,不会阻塞宿主启动或提示词组装。
目录约定
<你的工作区>/
├── 记忆系统/
│ ├── 00_热层.md # 必备:每次会话都注入
│ ├── 01_冷层索引.md # 可选:关键词 → 冷层记录
│ └── 冷层/… # 按需读取,不注入
└── …
热层放「每次都要知道的事」,冷层索引放「关键词 → 记录文件」,正文留在冷层里按需读——这样长线记忆可以无限增长而几乎不烧 token。
安装
DSH 插件是 profile 级的(装在 profile 的 node_modules + dsh.profile.bundles 里),本插件靠 cwd 判定来做到「只对当前工作区生效」。
方式 A:本地 link(开发/自用,改源码即生效,推荐)
dsh plugin --profile <profile 名> add "link:D:\path\to\dsh-memory-system"
方式 B:从 GitHub 装
dsh plugin --profile <profile 名> add "github:juechen06/dsh-memory-system"
github:是 pnpm 的包源语法,DSH 的plugin add走 pnpm。若本机 HTTPS 被中间人代理(例如 SteamTools)拦截导致SSL certificate problem,先让 git 信任该 CA:git config --global http.sslCAInfo <含该 CA 的 bundle>。作者仅在本地link:方式上完整验证过。
方式 C:下载 zip / tgz 手动装
解压后按方式 A 用 link: 指向解压目录即可。
装完重启 DSH(桌面版:完全退出再打开;Web 版:重启 dsh web)。
⚠️ 别用
Copy-Item往node_modules里手工塞:之后再跑任何dsh plugin add,pnpm 会把这个「不在依赖树里」的包移到node_modules\.ignored\。要手工放就同时写进 profilepackage.json的dependencies。
配置
全部通过环境变量,无需改代码:
| 变量 | 作用 |
|---|---|
DSH_MEMORY_SYSTEM_DIR |
直接指定记忆目录,跳过工作区判定(测试 / 特殊部署用) |
DSH_MEMORY_SYSTEM_WORKSPACE |
把插件钉死在某个工作区:cwd 不等于它就跳过(多工作区机器上想「只认一个」时用) |
DSH_MEMORY_SYSTEM_LOG_DIR |
诊断日志根目录;不可写时退回系统临时目录 |
注入预算:MAX_CHARS = 9000,热层与索引各占一半,超长按半额截断并提示用 read 工具读原文。
验证
# 1) 看日志
Get-Content "<日志目录>\.dsh\logs\dsh-memory-system.log" -Tail 10
正常应出现:
apply 被调用(固定工作区=(未固定,按 cwd 判定))
已注册 systemPrompt.context 声明式注入
已注册 system-prompt/assemble 瀑布监听(prepend)
瀑布注入命中(N 字,第 1 次)
# 2) 直接问模型:你的系统提示里有没有「记忆系统」这个块
出现「## 记忆系统(本工作区权威,已自动加载)」即为生效。
自测(不启动宿主)
node .\test.mjs
六个用例:本工作区注入 / 无记忆系统不注入 / 任意带记忆系统的工作区都能用 / 无 workingDirectory 不崩 / DSH_MEMORY_SYSTEM_DIR 覆盖 / DSH_MEMORY_SYSTEM_WORKSPACE 门控。全部通过时 exit 0。
卸载
dsh plugin --profile <profile 名> remove dsh-memory-system
重启。工作区的 记忆系统/ 完全不受影响(只是回到「靠模型自觉读」)。
设计取舍
- 为什么不自动写记忆:写记忆要判断类别、关键词、是否与旧条目冲突,是判断密集型工作,交给会话里的模型做更可靠;插件只负责「读进来」。
- 为什么两条注入路径:
ctx.systemPrompt.context()声明式注册是宿主内部主流写法(dsh-working-directory就这么干),但可能被抑制;再挂一个system-prompt/assemble瀑布监听兜底,就地改assembly.contexts,即使外层监听器丢弃返回值也能生效。 - 为什么用 cwd 而不是配置项做门控:DSH 插件没有「按工作区启用」的原生开关,而会话 cwd 是宿主自己维护的真相源(
workingDirectory.get(agent.session)),用它判定最不容易和宿主脱节。 - 为什么要
mtime缓存:提示词前缀稳定对 prompt cache 很关键,而同一轮里文本可能被两条路径各算一次。
已知限制
- 依赖 DSH 宿主内部服务(
systemPrompt/workingDirectory/sessionProjections),宿主大版本升级后建议回归一次自测; - 只注入两个文件的内容,不做向量检索、不做自动摘要——那是别的插件(如
dsh-plugin-memory)的活;两者可以共存,冲突时以本插件注入的记忆系统为准。
License
MIT
No comments yet. Be the first to write one.