前言¶
在 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 === trueresult.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 与首行头。
已知限制(摘自上游文档):
- 最终 assistant 文本可能在
agent/turn-stopping之前已提交并流式展示;保证的是「回合不会因未报告而结束」,不是「用户一定看不到未报告前的最终文本」。 maxNudges用尽后回合会释放并打warn,避免模型死循环占住回合;maxNudges: 0仅提醒、不硬拦。- 欠账按回合计,新回合不继承。
- 工具报错、
success: false或 report 发错 session 均不清账。 - 上游
dsh-call-session消息格式变更时,本插件需同步适配。 - 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