前言¶
用 DSH 做長任務時,常會遇到「換個工作區繼續」。手工搬通常丟三件事:歷史、結論、下一步。複製文件帶不走對話;新開一個空會話等於讓模型從零開始;把整段記錄粘進輸入框既超長又失真。
dsh-handoff 是給 DeepSeek Harness(DSH)的會話交接插件,由 GarinZ 維護,屬於社區目錄裏的工作流分類。它讓 Agent 在對話裏直接調用 handoff_session 工具,把當前會話交接到另一個工作區的新會話,並附上一份按固定骨架寫好的交接簡報。源會話默認保持不變。
核心能力¶
插件做了三件事,用的都是 DSH 自身能力:
- fork —
sessionController.fork()把當前會話的事件前綴複製成獨立新會話(不寫parentSession); - relocate — 把新會話的存儲遷到目標工作區:重寫日誌頭行的
cwd、重綁活動寫句柄、切換工作區賬本,全程不重啓; - brief — 把交接簡報追加成新會話的第一條消息,簡報按固定六節骨架寫。
交接有兩種歷史策略:
| 模式 | history |
新會話裏有什麼 | 什麼時候用 |
|---|---|---|---|
| 全文複製(默認) | full |
完整事件歷史 + 交接簡報 | 需要精確上下文,且源會話還健康 |
| 僅摘要 | summary |
只有交接簡報 | 源會話已經很大、上下文快撐爆,或用了不支持主動壓縮的插件 |
需要「僅摘要」的原因是:fork 是事實複製,不是壓縮。源會話若已被上下文壓力拖到邊緣,複製出來的會話會繼承同樣的壓力。摘要模式直接在目標工作區新建空白會話、只寫簡報,新會話的上下文壓力從零開始,代價是丟掉原始對話裏的細節。
安裝¶
從 npm 或 GitHub 安裝:
# 從 npm
dsh plugin --profile <profile> add @garinz/dsh-handoff
# 或直接從 GitHub
dsh plugin --profile <profile> add github:GarinZ/dsh-handoff
從本地檢出的源碼安裝:
dsh plugin --profile <profile> add /path/to/dsh-handoff
# 或在該目錄裏
dsh plugin --profile desktop add .
宿主半熱加載,裝完即用,不需要刷新頁面。但客戶端半是 client.js(浮層與追問按鈕),裝或升級後需要刷新一次頁面纔會加載:dsh 自帶 Web 殼打開開發者工具(⌘⌥I)執行 location.reload(),生產版沒有 ⌘R。
典型用法¶
插件註冊了三個命令,輸入 / 可見:/handoff <自然語言>(全文複製)、/handoff-summary <自然語言>(僅摘要)、/btw <問題>(旁問)。命令本身秒回「旁問中…」「正在生成簡報並交接…」,把輸入框讓出來,答案回來後再替換命令結果,避免看起來卡死。
例如:
/handoff-summary 交接給 ~/Project/llm/agent-skills。ESP32 那攤活先放下,下一階段只做 skill 倉庫整理:重點寫清楚哪些 skill 已經沉澱、哪些還只是草稿,以及"別自動入庫"這條約束。
斜槓命令優先走側路請求:插件取當前會話的消息快照(含 system prompt),追加「請按六節骨架寫交接簡報」的指令,用同一個 provider/model 單獨請求一次,拿到簡報後直接調用 handoff_session。這條請求不開啓回合、不往對話裏寫事件。只有當目標工作區無法唯一確定、或本次會話還沒有一問一答時,才退回「模型自己寫簡報再調工具」的路徑。
直接說人話也可以,Agent 會調用工具,參數形如:
{
"target": "/Users/me/Project/new-repo",
"summary": "## 目標\n…\n## 下一步\n…",
"history": "full",
"title": "可選:給新會話一個能認出來的標題",
"start_turn": false
}
各字段的含義:
target:目標工作區的絕對路徑(或~開頭)、工作區 id 或標題。目錄不存在時會先mkdir -p再註冊,所以「交接給~/proj/新項目」可以直接開一個新工作區。summary:交接簡報,六節骨架。history: "full"時是補充;history: "summary"時是新會話唯一的上下文。history:full複製完整歷史;summary不復制任何事件,只開帶簡報的空白會話。title:可選,避免目標工作區出現兩個同名會話。start_turn:爲true時立刻在新會話裏跑一輪;默認只記錄,不消耗模型調用。mode:copy(默認)複製出新會話,原會話不動;move(beta)把當前會話本身在回合結束後遷到目標工作區(id 不變、歷史全保留),只能搭配history: "full"。
摘要模式的新會話會被包進一個只含簡報、不含模型回覆的回合(turn/start → 簡報 → turn/end)。這是爲了 GUI 的 sessionListMetadata.blank 判斷:該投影只在遇到 turn/start 時才翻成 false,不補這個回合,僅摘要交接出來的會話在側欄裏不可見。回合裏沒有 step、沒有 assistant 消息,不會調模型、不跑工具。
簡報骨架¶
兩種模式共用固定的六節:
## 目標 這一段要達成什麼
## 決策 決定了什麼 + 爲什麼(理由比結論重要)
## 已完成 帶產物:文件路徑、跑過的命令、測試結果
## 剩餘 還沒做的
## 關鍵上下文 路徑、符號、報錯原文、配置值
## 下一步 新會話第一條該做什麼
寫作規則對齊了 oh-my-pi 與 pi-handoff:只用對話裏出現過的事實、不臆造路徑與行號;關鍵細節不知道就寫「未知」並給出最小驗證步驟;用祈使句對下一任說話,不用第一人稱;不把「寫這份簡報」本身寫進進度或下一步。
旁問 /btw¶
/btw 剛纔那個 403 是哪個開關沒開?
它複用簡報用的同一個側路請求原語:快照 + 一句問題 → 一次獨立模型調用,不開啓回合、不寫事件、不佔會話記憶。側路請求發的是扁平文本(把會話壓成 ## 用戶 / ## 助手 / ## 工具結果 的對話記錄塞進一條 user 消息),因爲請求裏不聲明 tools 時,provider 會拒絕帶 tool-call 塊和圖片的原始歷史。預算按字符算:旁問 20 萬字符、簡報 40 萬字符,超了從最舊整條丟起,圖片一律變 [圖片]。留空 maxTokens 時由 ctx.llm 填該模型聲明的 defaultMaxTokens,避免「聊天能寫完、旁問被截斷」。
進度面板¶
/btw 和 /handoff* 的快路徑會在右下角彈出固定進度卡:標題、狀態、已跑秒數、流式正文和「停止」。它走獨立宿主路由 GET /handoff/activity?session=<id>(?cancel=1 中止),不依賴聊天流。底部輸入框是追問口,ping POST /handoff/ask 把問題交給宿主,答案流回同一張卡,不在對話裏留命令節點。追問時模型能看到本次會話最近 12 組旁問問答(原文不截斷,僅存內存,重啓即失)。
落盤結果¶
history: "full":
<目標工作區>/…/session-<new>/session.v4.jsonl.zstd
header.cwd = 目標工作區
事件 = 源會話的完整前綴 + 簡報
history: "summary":
<目標工作區>/…/session-<new>/session.v4.jsonl.zstd
header.cwd = 目標工作區
事件 = 標題 + 簡報(沒有別的)
適用場景與注意¶
適合需要在 DSH 裏跨工作區延續長任務、且希望把上下文和結論一起搬走的開發者。安裝前應檢查源碼與許可證(MIT),插件以當前 dsh 進程權限運行。
行爲上有幾點需要知道:
- subagent 會話不能交接;沒有記錄
cwd的會話不能交接。會話裏連一問一答都沒有時,工具會直接拒絕(這次會話還沒有可交接的對話)。 - 新會話的
header.cwd是目標工作區路徑,沙箱根、AGENTS.md、skills 發現都跟着走。 - 存儲遷移先寫臨時目錄、讀回校驗,再改內存態與賬本;任一步失敗都會回滾並保留原會話。
- 全文模式是 fork 語義:新會話
isSeeded爲true,歷史標記爲繼承(session/end-seed)。依賴「自身事件」的功能(例如按會話統計 token 用量)會把繼承部分算作前人歷史;摘要模式沒有這個問題,但它只知道簡報裏寫了的東西。 - 工作區賬本與日誌是即時寫好的,側欄刷新時機由 DSH 客戶端決定,個別界面狀態可能需要切一下工作區或刷新頁面才顯示。
- 插件依賴若干 DSH 內部接口(
sessionPersistence.tracker.writers、workspaceRegistry.indexHeader/attachSession、commands.register)。DSH 升級後請先在一個臨時會話上驗證。 - 兼容性:開發與驗證環境爲 DSH
0.2.2-rc.1(macOS 桌面版)、Node 24。需要 hosting 暴露sessionController、workspaceRegistry、sessionPersistence三個服務(官方dsh-base都有)。
結尾¶
dsh-handoff 的價值在於把「跨工作區繼續」這件事從手工搬運變成對話裏的一次工具調用:歷史、結論、下一步按固定骨架一起過去,源會話默認不動。倉庫:https://github.com/GarinZ/dsh-handoff,目錄頁:https://www.skillhub.cn/plugins/GarinZ/dsh-handoff。