dsh-session-recall:DeepSeek Harness 的会话史书与上游历史工具开关

前言

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 下的会话记录。
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜