dsh-recall:DSH Web UI 的消息撤回插件,不回退代碼改動

前言

在 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.js combo URL 服務。

適用場景是 DSH Web UI 中需要撤回某輪對話及後續節點,同時保留代碼、文件或其他副作用的場景。如果對話中包含子智能體指令、壓縮、重試或工作流節點,並且希望它們一起從後續模型可見歷史中消失,這類插件會直接對應這個需求。

注意事項:

  • 撤回邊界必須爲當前 surface 上的活躍消息節點,否則可能返回 recall-rejected;
  • 智能體運行中撤銷按鈕會禁用,需先停止當前回合再撤回;
  • 撤回不會回退代碼或文件改動,但它會改變後續對話中模型可見的歷史範圍;
  • 資料未提供官方安裝命令,部署前應按項目自身插件安裝流程處理,並檢查源碼與許可證。

鏈接

資料提供的目錄頁線索是:https://www.skillhub.cn/plugins/Mongfayi/dsh-recall

GitHub:https://github.com/Mongfayi/dsh-recall

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

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

小夜