dsh-session-search-pro:在當前 DSH 會話裏搜回曆史與進行中的會話

前言

用 DeepSeek Harness 久了,一段對話結束後,想找回「上週那個關於 session search 的結論是怎麼得出來的」,往往只能靠記憶硬翻。原生做法是手工翻 ~/.dsh 下的會話文件,再用命令行工具全文撈。本次介紹的插件換條路:直接複用 harness 運行時自帶的 sessionQuery 服務,給 agent 掛上搜索、列表、讀取三個工具,讓模型在自己的會話裏就能順着記憶找內容。

dsh-session-search-pro 是一個 DSH 插件,歸屬「記憶」分類,由 YaoleWu 維護,許可證是 MIT。下面介紹它的能力邊界、安裝方式和實際用法。

是什麼

它給 agent 提供三個工具:agent_session_search、agent_session_list、agent_session_read,底層全部走 harness 的 sessionQuery 服務,插件自身不做文本解析,不建數據庫,也沒有運行時依賴(沒有 ripgrep,沒有 zstd 解析)。它讀的是運行時本來就索引好的數據,對會話文件只讀不寫。

和同生態的 dsh-session-search 相比,兩者取捨不同:前者直接讀會話文件、自己解壓掃描 zstd 幀,因此能覆蓋 Codex、Claude Code、PI、OpenCode 等其他運行時的會話;本插件只走 harness API,代價是隻能搜 DSH 自己的會話,換來的是能搜到正在進行中的當前會話、不依賴文件格式假設、也不依賴外部二進制。

三個工具

分節之前先說一句:工具是插件註冊給 agent 的,實際調用通常由模型發起,你直接用自然語言問就行。

跨全部 DSH 會話做全文搜索,每條結果帶匹配度最高的片段。參數:

  • query(必填,string):要搜索的文本。不區分大小寫、空白寬鬆,按字面匹配,正則元字符沒有特殊含義。
  • limit(number):最多返回的會話數,1–50,默認取插件配置 maxResults(未覆蓋時爲 10)。
  • maxScan(number):退回掃描路徑時最多打開多少個會話,1–500,默認取插件配置 maxScan(200)。走索引時忽略。

返回值帶 engine: "index" | "scan",據此可知這次是哪條路徑給出的結果;掃描路徑還會帶 scanned 和 truncated。

agent_session_list

列出會話,進行中的和已結束的都算,可選按工作目錄過濾並排序。

  • limit(number):最多返回的會話數,1–100,默認 20。
  • cwd(string):按會話工作目錄做子串過濾。
  • sort("newest" | "oldest"):排序方式,默認 newest。

agent_session_read

按 id 讀取單個會話:標題、元數據,以及按順序排列的事件。

  • sessionId(必填,string):要讀取的會話 id,例如 "a4d75296-fc89-44b1"。
  • maxEvents(number):最多返回多少個事件(取最近的若干條),1–200,默認 50。

安裝與啓用

這個包目前還沒有發佈到 npm,所以直接從 GitHub 安裝,寫進 profile 的 package.json:

// ~/.dsh/profiles/<profile>/package.json
{
  "dependencies": {
    "dsh-session-search-pro": "github:LeslieWylie/dsh-session-search-pro"
  },
  "dsh": {
    "profile": {
      "bundles": ["dsh-session-search-pro"]
    }
  }
}

然後重新安裝依賴並重啓 profile:

cd ~/.dsh/profiles/<profile> && pnpm install
dsh --profile <profile>

想固定版本而不是跟隨默認分支,可以用 github:LeslieWylie/dsh-session-search-pro#v0.1.0。

這裏有一個必須說明的來源改動:上面的安裝命令,以及下文涉及的包內路徑,都是插件 README 原文裏的寫法(README 中的署名是 LeslieWylie)。現在這個倉庫的實際歸屬是 YaoleWu——GitHub 上把 LeslieWylie/dsh-session-search-pro 重定向到 YaoleWu/dsh-session-search-pro,package.json 的 repository 字段也仍寫着 LeslieWylie。package.json 的版本爲 0.2.0,倉庫當前有 5 stars、1 fork。按 README 安裝即可,但如果在意不跟隨默認分支,建議自行確認包的來源與版本。

不想改 profile 的話,可以先臨時掛載一次。這個包自帶 cordis.patch.yml,只要它已經裝進 profile 的 node_modules,就能用啓動器的 --patch 參數掛載:

cd ~/.dsh/profiles/<profile> && pnpm add github:LeslieWylie/dsh-session-search-pro
dsh --profile <profile> --patch ./node_modules/dsh-session-search-pro/cordis.patch.yml

包對運行環境的約束寫在 engines 裏:Node ^22.19.0 || >=24.0.0;對等依賴是 @deepseek-ai/cordis ^4.0.1 和 @deepseek-ai/dsh-tools ^0.1.0-rc.6。

典型用法

插件被打包進 profile 之後,agent 會自動拿到這三個工具,直接口語化提問即可,例如:

“幫我搜一下之前關於 session search 的會話”
“列出我在 ~/Desktop 下的最近會話”
“讀一下 a4d75296-fc89-44b1 這個會話”

模型會自己去調 agent_session_search、agent_session_list 或 agent_session_read。

默認 profile 上的搜索路徑

這一步值得單獨講,因爲它是這套插件最容易踩空的地方。agent_session_search 有兩套引擎,調用時自動選擇:

  • 索引:dsh-base bundle 裏的 @deepseek-ai/dsh-session-query-sqlite 提供基於 SQLite FTS5 的 searchSessions(),可用時插件走它,返回 engine: "index"。
  • 有界掃描:索引不可用時,退回用 listSessions() + filterEvents() 按最新優先逐個會話掃描,返回 engine: "scan"。

問題在於索引默認是關的。dsh-base 這樣接線:

- id: session-query-sqlite
  name: '@deepseek-ai/dsh-session-query-sqlite'
  config:
    path: ':memory:'
    openAt: never

引擎自身的守衛在 openAt 爲 never 時會拋 SESSION_QUERY_SEARCH_DISABLED,內容搜索是選擇性開啓的:部署方需要在後續 patch 層把 openAt 覆蓋成 first-search 或 startup,通常還要配一個持久化的 path。所以在默認 profile 上,索引調用一定失敗。

本插件只捕獲「索引不可用」這一類錯誤並退回掃描;如果失敗是後端真的壞了,它就如實報錯——用更慢的掃描去回答一個已壞掉的存儲沒有意義。

README 給出了一份本機 24 會話語料的實測對比:能命中的詞,索引和掃描都是 3 條結果;命中不到的詞,索引 17 毫秒,掃描 3,042 毫秒。索引值得開,但它不該是唯一路徑。插件在 0.1.0 及更早版本里正是把它當成唯一路徑,結果在每個默認安裝上都對任何查詢返回 {"error": "session search is disabled…"},且沒有拋異常,看上去像一個正常但永遠搜不到東西的工具。

要打開索引,在 profile 的 cordis.patch.yml 裏覆蓋那一行 bundle:

- update:
    id: session-query-sqlite
    config:
      path: '~/.dsh/session-index.db'
      openAt: first-search

插件自身的配置項只有兩個,寫在 cordis.patch.yml 的 bundle 行裏:

鍵 默認值 說明
maxResults 10 調用方不傳 limit 時,agent_session_search 使用的默認值。
maxScan 200 退回掃描時最多打開多少個會話。

適用場景與注意

適合這樣的場景:只跑 DSH 一個運行時,希望 agent 在當前會話裏就能檢索自己過去和正在寫入的會話內容,並且不想額外維護索引文件格式或外部命令行工具。

需要注意的幾點:

  • 插件以當前 dsh 進程的權限運行,能讀到 profile 裏能訪問的會話數據。安裝前應檢查 lib/ 下的源碼與 MIT 許可證,不要看到 bundle 名就直接裝。
  • 僅支持 DSH,不搜索 Codex、Claude Code、PI 或 OpenCode 的會話。跨多運行時的檢索需求應選 dsh-session-search。
  • 依賴 sessionQuery:三個工具都依賴它,沒有降級模式。如果該服務未被注入,插件會記一條警告日誌然後不註冊任何工具,而不是註冊一批一調用就報錯的工具。
  • 掃描退路是一個會話一個會話打開的,filterEvents() 要讀完整個會話日誌,一次未命中的搜索會走遍語料;maxScan 用來兜底,truncated: true 表示觸到了上限。語料大就把索引打開。
  • agent_session_read 的事件讀取不支持取消:底層 filterEvents() 不接受 abort signal,調用被中止時讀取本身仍會跑完,只是結果被丟棄。

純 JavaScript 實現,沒有構建步驟,源碼和發佈用同一個文件 lib/index.js。測試有兩套:tests/tools.test.mjs 針對一個打樁的 sessionQuery 驅動 apply();tests/boot.test.mjs 啓動真實 cordis Context、加載 harness 的會話服務、按 profile 方式裝載本包,並經過真實工具註冊表執行這些工具。第二套存在的理由正是 0.1.0 當初壞掉的方式——單元測試的樁自己定義了一個 searchSessions,測試全綠,但真實後端拋出的 SESSION_QUERY_SEARCH_DISABLED 卻被當成了每次查詢的答案。在 profile 的 node_modules 裏跑:

cd ~/.dsh/profiles/<profile>/node_modules/dsh-session-search-pro && node tests/boot.test.mjs

結尾

dsh-session-search-pro 做的事情很窄:把 sessionQuery 的檢索能力包成 agent 可用的三個工具,讓模型在自己的會話裏就能找歷史和進行中的內容。它的價值在於零運行時依賴、會話文件只讀不碰、索引路徑與掃描退路並存,從而在默認 profile 上也能給出結果。社區目錄頁在 https://www.skillhub.cn/plugins/YaoleWu/dsh-session-search-pro ,倉庫在 https://github.com/YaoleWu/dsh-session-search-pro ;目錄是獨立站點,與 DeepSeek 無官方從屬關係,使用時自行覈對來源。

羽毛球分组比赛记分
小程序二维码

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

小夜