前言¶
在 DSH 的 Web UI 裏做智能體對話時,經常會遇到這樣的需求:某輪用戶消息發送出去後,智能體已經繼續回覆,甚至觸發了子智能體指令、壓縮、重試、工作流等後續節點;此時希望把這一整段從對話中移除,讓後續模型看不到這些內容,但不想因此回滾已經發生的代碼或文件改動。
dsh-recall 爲 DSH Web UI 提供這個能力:撤回一條消息及其之後的全部內容,並通過 append-only 日誌中的持久墓碑事件保證重啓後仍然生效。DSH 的插件生態強調「一切皆插件」;下面按資料介紹這個客戶端插件的功能、使用方式和實現邊界。社區目錄是獨立站點,不應理解爲官方應用商店。
這是什麼¶
dsh-recall 是 DSH 的客戶端插件,許可證爲 MIT。倉庫路徑爲 Mongfayi/dsh-recall,資料中的維護者信息記爲 Mongfayi。
它解決的問題是:把一條用戶消息及其之後的所有內容從對話中移除——界面不再顯示、模型不再可見——但絕不回退任何代碼/文件改動。撤回不是簡單刪除界面元素,而是通過追加日誌(append-only)中的一條持久墓碑事件實現,重啓後依然生效。
核心功能¶
- 整輪撤回:點擊用戶消息旁的撤銷按鈕,撤回該輪對話及其後的全部內容。撤回範圍包括用戶提問、智能體回覆,以及長對話中的子智能體指令、壓縮、重試、工作流等。
- 恢復編輯:撤回後,被撤回用戶消息的文本與圖片整體恢復到輸入框,可修改後重新發送。
- 不破壞界面:撤回按鈕與框架的複製按鈕同一行、互不遮擋;消息氣泡、複製鍵、引用標籤、圖片畫廊保持框架原樣;含圖片的消息始終正常顯示圖片。
- 持久且可追溯:撤回記錄是一條持久墓碑事件,隨會話日誌
flush持久化,重啓後依然生效;日誌記錄一個不刪。 - 即時更新:墓碑到達即時會話後觸發會話裝配重建,被撤回行立即消失,無需刷新頁面。
- 宿主端路由:提供
POST /recall路由,支持{sessionId, messageId}或{sessionId, boundary},基於既有會話協議完成撤回。
典型用法¶
1、會話空閒時,點擊用戶消息旁的撤銷按鈕(複製鍵左側)。
2、確認彈窗後,該輪對話及其後的全部內容被撤回。
3、撤回位置顯示「已撤回的消息」提示。
4、被撤回消息的文本與圖片恢復到輸入框,可修改後重新發送。
注意:智能體運行中撤銷按鈕會禁用,需先停止當前回合再撤回。
安裝與啓用¶
資料未提供官方安裝命令,因此這裏不補充拼接出的安裝命令。
插件依賴 @deepseek-ai/dsh-session:經本插件 node_modules/@deepseek-ai/dsh-session 符號鏈接指向 dsh 源碼部署的 packages/core/session,與宿主共享同一模塊實例、同一版本。README 給出的重建符號鏈接命令如下,用於讓插件指向同一份 session 模塊:
ln -sfn ../../../../deepseek-harness/packages/core/session node_modules/@deepseek-ai/dsh-session
因爲插件會註冊宿主路由並覆蓋客戶端渲染器,安裝前建議先閱讀源碼,確認 MIT 許可證和行爲符合預期。插件以當前 dsh 進程權限運行,部署環境應按生產組件對待。
工作原理¶
宿主端¶
宿主端提供 POST /recall 路由,請求體可以是:
{ "sessionId": "...", "messageId": "..." }
或:
{ "sessionId": "...", "boundary": "..." }
撤回處理分爲三步:
1、校驗邊界:邊界必須爲當前 surface 上的活躍消息節點;如果該邊界已撤回或被遮蔽,會返回 recall-rejected。
2、追加墓碑:追加一條持久墓碑,形式爲空內容的 assistant/message,其中 surfaceOp 爲 {op:'replace', start: boundary, end},且 sourceEventSeqs 覆蓋全部被遮蔽節點。空內容 assistant 消息不派生任何消息,模型可見歷史收縮到 boundary 之前。
3、標記與持久化:在 data.recall = {boundary, end} 中記錄墓碑標記,用於客戶端提示節點;隨後隨常規 flush 持久化。
相關錯誤碼包括:
session-not-found
subagent-owned
agent-busy
message-not-found
recall-rejected
瀏覽器端¶
瀏覽器端通過客戶端腳本完成按鈕、隱藏、提示與輸入框恢復。
撤回按鈕以 priority: -1 覆蓋 conversation.chat.node 的 user keyed 渲染器,並委託給框架自己的用戶渲染器。這樣消息氣泡、複製按鍵、引用標籤與圖片畫廊都保持框架原樣;撤銷按鈕定位在框架操作行同一行、複製按鍵左側,避免遮擋。
圖片渲染始終經過框架的圖片槽 renderMessageImages,會話授權、標籤與燈箱保持框架原樣,不依賴插件自帶的畫廊加載器。
整輪隱藏發生在裝配期。實現上統一包裝每個框架對話定義的 buildViewNode:調用原構建器後,如果該行的錨點 seq 落在已撤回區間內就返回 null。涉及的錨點字段包括 anchorSeq、data.seq、data.finalNode.seq 和 data.closing.finalNode.seq。資料列出的覆蓋節點種類包括 steering、context、assistant-step、command、manual-compaction、compaction、model-retry、turn-error、turn-max-tokens、turn-tail、unknown、command-input、tool-call、workflow-run。
「已撤回的消息」提示通過 recall 定義匹配墓碑事件(assistant/message + data.recall)註冊。
即時更新方面,墓碑到達即時會話後,會重新註冊本插件的 recall 定義,觸發一次會話裝配重建,被撤回行立即消失,無需刷新頁面。
輸入框恢復時,文本經 conversation.input.for(scope).setDraft() 寫回;圖片經會話遠程 sessions.binding(sessionId).session.readAttachment() 取回字節,再經 conversation.createDraftImages() 註冊爲草稿圖片,並用 addImages() 掛到圖片軌道。被撤回附件仍保留在 append-only 日誌中,因此恢復有真實數據源;單張圖片恢復失敗不會影響其餘恢復,也不會回滾已完成的撤回。
兼容性與適用場景¶
dsh-recall 不需要 session/recall 事件類型、Session.recall 或客戶端窗口過濾;它基於框架既有的 surface 替換協議與 keyed Chat Node 席位。
已適配並驗證於 DSH 0.1.1-rc.1、0.1.1-rc.2 與 0.1.2-alpha.1。資料列出的 0.1.2 適配點包括:
- 定義註冊服務由
conversationEvents改爲uiConversation.events; - 子代理歸屬檢查(原
@deepseek-ai/dsh-api-remotes的hasApiRemoteSubagentOwner)已內聯進插件; - 圖片恢復改走會話遠程
readAttachment(原conversation.resolveImage已移除); - 客戶端 bundle 改經
/plugins/??<id>/client.jscombo URL 服務。
適用場景是 DSH Web UI 中需要撤回某輪對話及後續節點,同時保留代碼、文件或其他副作用的場景。如果對話中包含子智能體指令、壓縮、重試或工作流節點,並且希望它們一起從後續模型可見歷史中消失,這類插件會直接對應這個需求。
注意事項:
- 撤回邊界必須爲當前
surface上的活躍消息節點,否則可能返回recall-rejected; - 智能體運行中撤銷按鈕會禁用,需先停止當前回合再撤回;
- 撤回不會回退代碼或文件改動,但它會改變後續對話中模型可見的歷史範圍;
- 資料未提供官方安裝命令,部署前應按項目自身插件安裝流程處理,並檢查源碼與許可證。
鏈接¶
資料提供的目錄頁線索是:https://www.skillhub.cn/plugins/Mongfayi/dsh-recall
GitHub:https://github.com/Mongfayi/dsh-recall