session-chains — 交接鏈面板 for DSH
把「互相交接的對話」自動聚成一條鏈:左側欄一張卡片列出每條鏈、每場對話編號,
點一下切過去;快到上下文上限時提醒你交接,設定打開的話連「開新對話+貼提示詞+切過去」都自己做完。
這是 DeepSeek Harness(DSH) 的外掛(host 端 index.mjs + 瀏覽器端 client.js),
以 file:// 掛進 $DSH_HOME/cordis.patch.yml,不改內建側邊欄、不動 profile。
為什麼要做
拆對話是省 token 最有效的手段(同一條工作線實測可省約 71%),但代價是側邊欄散成一堆看不出關係的對話框。
而「哪幾場是同一條線」其實已經寫在日誌裡 —— 只差沒有人把它讀出來:
- 接手的那一場,交接提示詞是使用者貼進去的第一句話;
- 交出的那一場,同一份文字是助理產出的。
兩側都落在 $DSH_HOME/sessions/<工作區>/<session>/session.v*.jsonl.zstd。
所以只要提示詞裡有一行 鏈=<代號>,兩邊就都認得出來,面板自動分組 —— 不必手動歸類。
長什麼樣
| 位置 | 內容 |
|---|
| 左側欄卡片 | 每條鏈一列,展開是各場對話(001、002…),右側三顆:收合/暫停/開面板 |
| 面板(浮層) | 全部鏈、搜尋、拖拉/多選歸鏈、四鍵排序(名稱/建立/場次數/最後活動) |
| 置頂/封存(2026-10-19) | 側欄每列右側就有 📌(置頂)與 🗄(封存),不必進面板。置頂只在右側顯示圖釘(左側不再加一個);封存是兩段式(側欄與面板一致):按 🗄 會變成「確定封存?」,再按一次才送,旁邊有「取消」。封存的鏈從卡片收起,面板「封存庫 N」才看得到、也才還原得回去 |
| 輸入框上方 HUD | 本場 320k/210 = 這一場的上下文/請求數,達門檻才變色 |
| ⚙ 設定 | 字級、四組顏色、卡片圖示、HUD 五段開關、交接門檻、自動交接 |
置頂與封存存在哪:跟改名同一份 aliases.json(pinned/archived 兩個清單),不是瀏覽器 localStorage,
所以換瀏覽器、重開 DSH 都還在;改名之後置頂也跟著走(讀寫時都會過對照表)。
封存不動任何 session 日誌,只是不在卡片顯示。封存的鏈若又交接出新場次,留在封存庫(不會自己跳回卡片)。
安裝
需要 DSH(桌面版或 web 版都可以)。兩種裝法,選一種:
A. 從插件市場/dsh plugin add(repo 根目錄就是套件根)
# 發佈到 npm 之後:
dsh plugin --profile web add session-chains
# 或直接從 GitHub:
dsh plugin --profile web add github:HildebrandYu/dsh-session-chains
B. 直接掛本機資料夾(開發用,改檔即重載)
git clone <this-repo> dsh-session-chains
cd dsh-session-chains
node scripts/install.mjs # dry-run:只寫 .preview/,讓你先看補丁長什麼樣
node scripts/install.mjs --apply # 真的掛上(會先備份 $DSH_HOME/cordis.patch.yml)
node scripts/install.mjs --remove --apply # 整包移除
掛好後重新整理 GUI 一次就會出現卡片。移除時它會把自己那兩段(插件列+HMR 監看)一起清掉。
套件結構:package.json 在 repo 根(市集與 dsh plugin add 只讀這個),裡面宣告
dsh.bundle.patch = ./cordis.patch.yml(沒有這個就無法安裝,只宣告 dsh.client 不算)
與 dsh.client.platform = web;程式本體在 plugin/,exports 指過去。
本機用 file:// 直掛時,載入器會從 plugin/index.mjs 往上找到根目錄的 package.json。
install.mjs 會寫兩段:session-chains(插件本體)與 session-chains-hmr(把 plugin/ 加進 HMR 的監看根目錄,
沒有這段改 index.mjs 不會生效)。兩段都用哨兵包住,可重複執行。
使用
- 平常:照常工作。交接過的對話會自己出現在同一條鏈裡。
- 要交接時:面板上按「生成交接詞」→ AI 寫交接單與提示詞 → 按「開新對話」自動開+貼+送出+切換。
- 到門檻:畫面會跳提醒(warn 可延後 30 分鐘、hard 只能延後 5 分鐘)。
打開 ⚙ 的「到達門檻自動交接」,hard 會在這一輪結束後自己做完上面第 2 步。
門檻(預設值與怎麼選)
| 訊號 | 提醒(warn) | 強制(hard) |
|---|
| 請求數 | ≥ 200 | ≥ 320 |
| 上下文 tokens | ≥ 320k | ≥ 480k |
| 佔模型視窗比例 | ≥ 50% | ≥ 65% |
- warn 是提示(只顯示,不動作);hard 才是緊急煞車(設了自動交接才會出手)。
- 預設值是回放 42 場真實對話訂出來的:舊的 80/120、160k/240k 會在 25/42 場觸發
(觸發時中位還剩 103 步=一定半路被切);現在只在 6/42 場觸發,都是 300 步以上或 470k 以上的長場。
- 比例那一列是給換模型用的:1M 視窗下幾乎不會先觸發,換成 200k 視窗的模型時它會自動先擋。
- 全部可在 ⚙ 改,或直接改 localStorage 的
dsh.session-chains.settings。
運作原理(三個判定)
| 訊號 | 規則 | 例子 |
|---|
| 接手 1 | 第一句話有明確標記 | 鏈=my-project |
| 接手 2 | 舊式提示詞 | 接續 my-project:讀 … |
| 接手 3 | 第一句話裡的專案路徑 | 30-CodingSkills/my-project |
| 交出 | 助理訊息裡「整行就是標記」 | 產出的提示詞那一行 |
| — | 都沒有 → 未標記 | 一般對話 |
「交出」那一條刻意嚴格(行首就是標記):實測一場正在討論本功能的對話,助理推理裡
鏈=… 這種字串出現 23 次(全在行內),寬鬆比對會把一般對話誤認成鏈的起點。
測試
node --test scripts/ # 單元測試(純函式:鏈判定、編號、改名、建議歸鏈)
node scripts/smoke.mjs # 端到端:在沙箱裡跑 client bundle,檢查面板/卡片/交接流程
node scripts/verify.mjs # 靜態:manifest、bundle 形式、補丁現況
DSH_WEB_URL=http://127.0.0.1:51714 node scripts/probe.mjs # 實機:宿主是否已把 bundle 組進 boot graph
scripts/smoke.mjs 不需要真的 DSH:它自己造假的宿主 API(sessions、workspace、fetch、localStorage),
所以 CI 也能跑。
已知限制
- 只支援 DSH:它讀的是 DSH 自己的 session 日誌格式(
session.v4.jsonl.zstd),換宿主就得改 chains.mjs。
- 紅點還沒有資料來源:宿主目前沒有「這一場失敗了」的狀態可讀,所以失敗圓點先留空。
- 手動「交接→新對話」在沒有交接詞時會顯示兩步錯誤(設計如此:先按「生成交接詞」)。
- 鏈的判定靠提示詞裡的標記;沒用過交接指令的舊對話會落在「未標記」,可在面板上逐一歸鏈。
授權
MIT,見 LICENSE。