dsh-report-fix:強制 task_dispatch 回合在 task_report 前不得結束

前言

在 DSH 裏用 dsh-call-session 做跨會話協作時,常見模式是:會話 A 通過 session_call(call_type="task_dispatch") 把任務派給會話 B,B 做完後再 session_call(call_type="task_report") 把結果回給 A。session_call 本身是「只投遞、不確認」:task_dispatch 最多等約 300 ms 完成握手,無法知道被叫方有沒有回傳 task_report。若 B 直接給出最終答覆並結束回合,A 可能一直等不到結果。下面介紹社區插件 dsh-report-fix(維護者 JohnnnSinaaa,分類:工作流),它在不改動 dsh-call-session、不新增工具的前提下,用 DSH 宿主已有的生命週期鉤子,在回合邊界檢查是否已回傳 task_report,缺失則阻止回合關閉。

這是什麼

dsh-report-fix 是一句行爲約束的落地實現:**由 session_call(task_dispatch) 開啓回合的會話,在未向調用方成功發送 task_report 之前,不能結束該回合。插件不修改 dsh-call-session 內部邏輯,只監聽三個鉤子、在回合邊界覈對「欠賬」,缺報告時用 agent.steer 重新打開回合,促使模型調用 session_call(call_type="task_report")。

缺口可以用下面示意理解:

session A ──session_call(task_dispatch)──▶ session B
                                            │
                                            ├─ ok:      session_call(task_report) ──▶ A gets the result
                                            └─ missing: final answer, turn closes ───▶ A waits forever

倉庫:GitHub - JohnnnSinaaa/dsh-report-fix
社區目錄:skillhub.cn/plugins/JohnnnSinaaa/dsh-report-fix
許可證:MIT;當前 package 版本 0.1.0;要求 Node >= 20,DSH >=0.2.0-rc.2 <0.3.0-0。

核心機制

三個鉤子

Hook 時機 作用
agent/pre-step 每步消息進模型前 識別入站 task_dispatch,登記欠賬,可選追加提醒
tools/post-execute 每次工具調用後 成功的 session_call(task_report) 清除對應欠賬
agent/turn-stopping 回合即將關閉(已有最終答覆) 若仍有欠賬,通過 agent.steer(message) 阻止關閉,再跑一步

agent/turn-stopping 是當前 DSH 裏「阻止回合提交」的正式路徑:有監聽器反對時會 steer,狀態機重讀 inbox 再執行一步,而不是直接關回合。

如何判定「dispatch 驅動的回合」

入站 session_call 會以原生 user 消息出現:source.kind === 'plugin:dsh-call-session',source.form === 'notice'(由 session_call 投遞,而非 session_create),首行 transport 頭可解析,且 CallType 爲 task_dispatch。入站的 notice / task_report 不會產生欠賬。

首行格式示例:

[From: <callerSessionId> (<callerTitle>) | CallType: task_dispatch]
> Context Ref: #post-...        ← optional

<body>

何種 task_report 算清賬

在 tools/post-execute 中需同時滿足:

  • exec.name === 'session_call'
  • result.isError !== true 且 result.value.success === true
  • result.value.callType === 'task_report'
  • result.value.targetSessionId 與 caller 匹配(不區分大小寫;支持前綴尋址,與 session_call 行爲一致)

同一回合內多個 caller 各自一條欠賬,須分別回傳。

攔截時模型會看到什麼

缺報告且觸發硬門禁時,插件注入類似下面的 steer 文案(語言隨入站 dispatch 正文或 locale 配置):

[task_report guard · interception 1/3] This turn cannot end: you have not sent a task_report back to the task_dispatch caller.

Awaiting a report (1):
1. 「Worker A」 caller-session-0001
   dispatch excerpt: deploy the staging build and report back with the url

Call session_call now (finish it before the turn ends; do not emit the final user-facing answer yet):
- session_call({"target_session_id":"caller-session-0001","call_type":"task_report","message":"<result summary>"})

文案說明:此要求優先於 dispatch 正文中與之衝突的指令(例如「不要回傳」);報告成功後回合即可釋放;調用失敗需修正參數重試。

安裝與啓用

這是 DSH profile 插件(bundle 形態):package.json 聲明 dsh.bundle.patch,由 cordis.patch.yml 掛載。官方 README 給出的安裝方式是對本地目錄執行 dsh plugin add,不是 github:owner/repo 短名。

# local checkout (writes into the profile's dependencies and dsh.profile.bundles)
git clone https://github.com/JohnnnSinaaa/dsh-report-fix.git
dsh plugin --profile web add "$PWD/dsh-report-fix"

# or any absolute path
dsh plugin --profile web add /path/to/dsh-report-fix

dsh plugin add 之後:

  • ~/.dsh/profiles/web/package.json 的 dsh.profile.bundles 會加入 dsh-report-fix;
  • dsh-hmr 監視 profile 的 package.json 與 patch 文件並熱重組,一般無需重啓 dsh web 即可生效;
  • 日誌中出現 [dsh-report-fix] active (maxNudges=3 preStepReminder=on locale=auto excerptMaxChars=600) 可確認已加載。

若以 link: 依賴指向本地目錄,改插件源碼後不會被 dsh-hmr 自動重載(它監視 profile 的 package.json 與 patch,不監視 link 背後的工作區),需重啓 dsh web。

卸載:

dsh plugin --profile web remove dsh-report-fix

配置

在 profile 的 cordis.patch.yml 中按 id 覆蓋(dsh-hmr 會重組 profile,改配置通常不必重啓進程):

- id: dsh-report-fix
  config:
    maxNudges: 5
    locale: zh
鍵 默認 含義
enabled true 總開關;false 時不註冊任何鉤子
maxNudges 3 每回合攔截次數;0 關閉硬門禁,僅保留 pre-step 提醒
preStepReminder true 首步追加提醒,多數回合在門禁前即合規
locale auto auto 跟進入站語言;zh / en 強制
excerptMaxChars 600 nudge 中引用的 dispatch 摘要最大字符數

典型用法與邊界

典型流程:工作流裏 A 派任務給 B(task_dispatch),B 在插件約束下必須先對 A 發起成功的 task_report,回合才允許結束;與 dsh-call-session 的消息格式約定一致,插件不 import 該包,只讀 source.kind / source.form 與首行頭。

已知限制(摘自上游文檔):

  1. 最終 assistant 文本可能在 agent/turn-stopping 之前已提交併流式展示;保證的是「回合不會因未報告而結束」,不是「用戶一定看不到未報告前的最終文本」。
  2. maxNudges 用盡後回合會釋放並打 warn,避免模型死循環佔住回合;maxNudges: 0 僅提醒、不硬攔。
  3. 欠賬按回合計,新回合不繼承。
  4. 工具報錯、success: false 或 report 發錯 session 均不清賬。
  5. 上游 dsh-call-session 消息格式變更時,本插件需同步適配。
  6. dispatch 正文若與 guard 衝突,仍由模型抉擇,測試中可能出現燒完 maxNudges 才釋放的情況。

適用場景與注意

適合已經在用 session_call + task_dispatch / task_report 做多會話編排的 DSH 開發者,希望被叫方「漏報告就關回合」這類缺口有宿主側兜底。插件以當前 dsh 進程權限運行,安裝前請自行審閱 源碼與 MIT 許可證。社區目錄 skillhub.cn 與 DeepSeek / 幻方無官方從屬關係,屬於 DSH「一切皆插件」生態裏的第三方條目。

結尾

dsh-report-fix 用三個生命週期鉤子把「dispatch 驅動的回合必須以 task_report 收尾」寫成可執行的回合邊界檢查,配置項少、與 dsh-call-session 解耦。需要細節與測試說明時,以倉庫 README(含 簡體中文)爲準。

  • 目錄頁:https://www.skillhub.cn/plugins/JohnnnSinaaa/dsh-report-fix
  • GitHub:https://github.com/JohnnnSinaaa/dsh-report-fix
羽毛球分组比赛记分
小程序二维码

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

小夜