前言¶
DeepSeek Harness(DSH)在构建多轮对话与智能体系统时,经常需要看到整个会话的完整上下文。默认情况下,DSH 只在当前会话内维护事件日志,缺乏对历史会话的统一投影与可调用的只读查询能力。dsh-session-recall 为 DSH 提供了一份有界、零模型的会话史书,并支持按当前 harness 精确版本打开上游那 5 个只读会话历史工具。
是什么¶
- 名称:dsh-session-recall
- 维护者:xingzoudefengye
- 分类:记忆
- 许可证:MIT
- 核心价值:
- 会话史书:对会话事件日志的纯函数投影,不落盘、不建索引、不跑后台任务,硬性渲染预算 6,000 字符。
- 上游工具开关:以脚本方式安装并挂载
@deepseek-ai/dsh-tool-session-query与@deepseek-ai/dsh-session-query-sqlite,版本与@deepseek-ai/dsh-base完全相等。
兼容性¶
- 平台:Windows 10/11(PowerShell)、macOS(zsh)、Linux(bash/zsh)
- Node:
>=22 - DSH:需要宿主提供
defineTool、ctx.tools.register、cordis 的Service,以及session.snapshotEvents()能力
安装与启用¶
1. 安装史书(必选)¶
dsh plugin --profile web add github:xingzoudefengye/dsh-session-recall
安装后重启宿主:
dsh web
2. 启用上游 5 个只读历史工具(可选)¶
在任意目录执行(PowerShell 与 zsh 通用):
node "$HOME/.dsh/profiles/web/node_modules/dsh-session-recall/scripts/enable-read-tools.mjs" web
(若设置了 DSH_HOME,把 $HOME/.dsh 换成 $env:DSH_HOME。)
该脚本完成四件事:
1. 从 profile 的 @deepseek-ai/dsh-base 读取 harness 版本;若 manifest 不存在,回退到 dsh --version。
2. 在 profile 目录里 pnpm add 两个包:@deepseek-ai/dsh-tool-session-query 与 @deepseek-ai/dsh-session-query-sqlite,版本与 harness 精确相等。
3. 把 cordis.patch.yml 备份成 cordis.patch.yml.bak-<YYYYMMDD-HHMMSS>,再追加一个 optional-session-search 隔离组。
4. 打印挂载成功提示,并要求重启。
之后同样重启:
dsh web
macOS/Linux 也可以使用 bash 版:
~/.dsh/profiles/web/node_modules/dsh-session-recall/scripts/enable-read-tools.sh web
验证与自检¶
运行自检脚本(在已安装的 profile 里):
node "$HOME/.dsh/profiles/web/node_modules/dsh-session-recall/scripts/check.mjs" web
它检查三件事:两个史书 row 是否在合成树里;上游读工具是否已挂载;若已挂载,两个包的版本是否与 harness 精确相等。退出码 0 表示没有 FAIL,1 表示有 FAIL(或 profile / dsh 不存在)。
示例输出(已挂载):
ok: session-chronicle is in the composed tree
ok: tool-session-chronicle is in the composed tree
ok: upstream read tools are mounted (harness 0.2.1-rc.2)
ok: @deepseek-ai/dsh-tool-session-query@0.2.1-rc.2 matches the harness
ok: @deepseek-ai/dsh-session-query-sqlite@0.2.1-rc.2 matches the harness
示例输出(未挂载):
ok: session-chronicle is in the composed tree
ok: tool-session-chronicle is in the composed tree
note: upstream read tools are not mounted (run scripts/enable-read-tools.mjs web to add them)
示例输出(版本漂移):
FAIL: @deepseek-ai/dsh-tool-session-query@0.2.0-rc.2 does not match the harness (0.2.1-rc.2) — re-run scripts/enable-read-tools.mjs web
开发自检(纯离线):
npm test
配置¶
史书参数(每次调用)¶
| 参数 | 类型 | 默认 | 作用 |
|---|---|---|---|
lastTurns |
integer | 不传 = 全部 | 只返回最新的 N 条回合记录;非正整数按不传处理。 |
maxChars |
integer | 6000 |
返回文本的字符预算,上限也是 6000;低于 64 时按 64 渲染。 |
maxChars 限制的是渲染出来的史书文本;API 返回的对象另有 12000 字符的传输上限,不会为了它删除读者还有额度容纳的回合。
挂载点¶
bundle 默认在 cordis.patch.yml 中插入两行:
- insert:
- id: session-chronicle
name: 'dsh-session-recall/service'
- id: tool-session-chronicle
name: 'dsh-session-recall/tool'
session-chronicle提供ctx.sessionChronicle服务,供其他插件消费,本身不占模型请求。tool-session-chronicle注册模型可调用的session_chronicle工具,每个请求多一个 tool schema。
只想关掉模型工具、保留服务,可在 profile 的 cordis.patch.yml 里按 id 覆盖:
- id: tool-session-chronicle
disabled: true
读工具开关¶
enable-read-tools.mjs 追加的组长如下:
- insert:
- id: optional-session-search
name: cordis:group
group: true
isolate:
sessionQuery: true
config:
- id: optional-session-query-sqlite
name: '@deepseek-ai/dsh-session-query-sqlite'
config:
path: ':memory:'
openAt: first-search
- id: optional-tool-session-query
name: '@deepseek-ai/dsh-tool-session-query'
isolate.sessionQuery 让这个组拥有独立的 sessionQuery,profile 里原有的 sessionQuery 保持自身配置;组内使用 :memory: 索引,且在第一次搜索时才打开(openAt: first-search)。
代价:这 5 个工具是上游的 opt-in 功能,每个模型请求固定多出 5 个 tool schema 加一段引导文字,即使这一轮根本不搜历史。不需要跨会话检索就不要开。
卸载¶
1. 移除插件¶
dsh plugin --profile web remove dsh-session-recall
2. 撤销读工具(如果开过)¶
脚本每次追加前都写了备份,恢复最近一份即可。
PowerShell:
$patch = "$HOME/.dsh/profiles/web/cordis.patch.yml"
$bak = Get-ChildItem "$patch.bak-*" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
Copy-Item $bak.FullName $patch
zsh:
cd ~/.dsh/profiles/web
cp "$(ls -t cordis.patch.yml.bak-* | head -1)" cordis.patch.yml
也可以手工编辑 cordis.patch.yml,删掉以 # --- dsh-session-recall: ... 开头的那一段——它下面的 - insert: 里就是 optional-session-search 组,直到 name: '@deepseek-ai/dsh-tool-session-query' 为止。
如果不再需要这两个上游包,顺手移除:
dsh plugin --profile web remove @deepseek-ai/dsh-tool-session-query @deepseek-ai/dsh-session-query-sqlite
3. 重启¶
dsh web
磁盘上剩下什么¶
cordis.patch.yml.bak-*备份文件(脚本写的,不会自动清理,可手删)。- 若跳过了上面的可选移除:profile 的
node_modules、package.json、pnpm-lock.yaml里仍有那两个上游包。 - 会话日志本身:史书不写任何数据,插件卸载不会删除或改变
~/.dsh下的会话记录。 - 插件自己的
node_modules/dsh-session-recall会随dsh plugin remove一起消失。
排错¶
| 现象 | 原因 | 处理 |
|---|---|---|
插件装好了,模型看不到 session_chronicle |
插件在宿主启动时 import;dsh plugin add 只改 profile,不会热加载新包 |
完全退出并重启 dsh web。刷新浏览器页面不算重启宿主。 |
改了 lib/*.js,行为没变 |
Node 的 ESM 模块缓存按进程生效,宿主还拿着旧模块 | 重启宿主。不需要清缓存或重装。 |
dsh plugin add 超时、403 或卡住 |
dsh plugin 把参数转发给 pnpm,需要同时访问 GitHub 与 npm registry;代理或纯内网会失败 |
换到能访问的网络重试,或先给 pnpm 配好代理与 registry。 |
| 读工具已挂载,但模型调不到 | 宿主没重启;或两个包没装进 profile;或版本漂移 | 先重启,再跑 node scripts/check.mjs web。not installed 就重跑 enable-read-tools.mjs;版本不等就重装。 |
check 报版本不匹配 |
两个上游包必须与 @deepseek-ai/dsh-base 精确相等。它们与 harness 同批发布,rc 与 rc 之间也可能不兼容,所以检查用字符串严格相等,而不是 semver 范围 |
重跑 node scripts/enable-read-tools.mjs web,它会按当前 harness 版本重装。 |
| 新会话里史书是空的 | 史书只记录真人开过的回合(source.kind === "user");注入的上下文、工具结果、子 agent 消息都不算。新会话还没有真人消息时就是 0 条 |
先发一条真人消息;回合进行中会显示「回合进行中」,结束之后才有结论。空史书会明确写「本会话还没有记录到带真实用户输入的回合」。 |
本地路径安装后报找不到 @deepseek-ai/cordis |
dsh plugin add /abs/path 装的是 link: 依赖,ESM 跟随软链到仓库真实路径后,解析不到 profile 的 node_modules |
开发时先跑 node scripts/dev-link.mjs;正常安装请用 github: 地址。 |
scripts/*.sh 在 Windows 报 set: pipefail: invalid option name |
脚本在 Windows 上不应直接执行,应使用同名 .mjs 文件 |
适用场景与注意¶
- 适合需要按会话时间轴回溯上下文、在当前会话内投影历史事件、或需要调用上游只读历史工具的场景。
- 插件以当前 dsh 进程权限运行,安装前应检查源码与许可证。
- 上游工具属于 opt-in 功能,开启后每个模型请求固定多出 5 个 tool schema 与一段引导文字,仅在需要跨会话检索时开启。
- 史书不写入任何数据,卸载不会影响
~/.dsh下的会话记录。