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 下的會話記錄。
羽毛球分组比赛记分
小程序二维码

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

小夜