前言¶
在 DSH 里,模型通过 ask_user_question 向人提问后,会话往往会一直挂着等回答。你在开会或暂时离开,前端仍开着,链上的 next() 不会结束——事后才发现已经空等一两个小时,并不少见。单靠盯着 DSH 界面很难及时察觉。
下面介绍的是社区插件 dsh-ask-timeout-notify(维护者 SJTUMalPan):在「人还没回、问答仍在等」的前提下,超过可配置阈值(默认 60 分钟)仍无人作答时,向 notify-hub 投递一条带 need_ack 的消息,落成待办并按飞书、webhook、email 等渠道推送。它不替用户作答,也不改变 DSH「一直等」的语义。
这是什么¶
dsh-ask-timeout-notify 是 DSH 宿主侧的工作流类插件(独立 GitHub 仓库,版本 0.1.0,MIT 许可证)。它在 user-questions/request 这条 waterfall 链首启动定时器;到点则调用 notify-hub 的 POST /api/v1/messages,由 notify-hub 按既有规则生成待办并推送。插件本身不改 notify-hub 代码,也不需要为其单独加规则——调用方声明 need_ack: true 即可,待办由 notify-hub 侧分类器处理。
核心功能¶
会做与不会做¶
| 做 | 不做 |
|---|---|
在提问链首起定时器,到点往 notify-hub 投待办(带 dedup_key 去重) |
不替用户作答,不改变 DSH 一直等待的语义 |
| 用户已答、请求取消或出错时销毁定时器 | 不改 notify-hub 源码 |
| 投递失败只记日志,不影响问答主流程 | 不因通知失败中断等待中的问答 |
何时触发¶
维护者在真实 DSH 进程里实测过下列行为(README 原文说明,非推测):
| 场景 | 本插件 |
|---|---|
| 前端开着、一直未点回答 | 到阈值投递待办 |
前端关掉 / 无回答者,链上立刻 NO_PROVIDER 拒绝 |
finally 销毁定时器,不发待办 |
| 阈值内已回答 | 销毁定时器,不发 |
| 会话取消或处理中断 | 销毁定时器,不发 |
结论:管的是「人还没回」,不是「人不在」。浏览器关掉导致无人接手时,问答会立刻失败,本插件不会在这种路径上发待办;价值主要在前端仍开着、会话真的挂着等你的那段时间。
与 notify-hub 的配合¶
notify-hub 接受 need_ack: true 与 dedup_key:同一问题重复超时不会刷出多条未完成待办(服务端按 (source, dedup_key) 复用)。本插件作为普通消息生产者,与 CI 脚本、监控告警走同一入口。
前置条件¶
- DSH 已安装,且能跑
dsh web(profile 名为web)。 - notify-hub 在运行,并知晓地址与访问令牌:
- 默认地址示例:http://127.0.0.1:8000;
- 令牌:notify-hubconfig.yaml里server.auth_token;未配置令牌则服务不鉴权,此时插件仍需配置一个非空令牌值(任意非空即可,见下文配置说明)。
安装与启用¶
插件为独立仓库,仓库根即插件包,可通过 DSH 插件市场命令安装。安装后需重启 dsh web,profile 的插件组合变更只对新进程生效。
从 GitHub 安装(跟最新 main):
dsh plugin --profile web add github:SJTUMalPan/dsh-ask-timeout-notify
锁 commit(可复现):
dsh plugin --profile web add "git+https://github.com/SJTUMalPan/dsh-ask-timeout-notify#<sha>"
本机开发(在仓库根目录执行,符号链接,改完即生效):
dsh plugin --profile web add "link:$PWD"
dsh plugin add 会把包装进 ~/.dsh/profiles/web/ 并把包名写入该 profile package.json 的 dsh.profile.bundles,一般不必手改 profile 文件。
卸载:
dsh plugin --profile web remove dsh-ask-timeout-notify
配置¶
环境变量优先于 cordis.patch.yml 中的键(多机部署时常用环境变量表达机器差异)。环境变量应随 dsh web 启动方式设置(如启动脚本里 export),不宜写进代码仓库。
| 环境变量 | cordis.patch.yml 键 |
默认 | 说明 |
|---|---|---|---|
DSH_ASK_TIMEOUT_MINUTES |
timeoutMinutes |
60 |
多少分钟未答算超时(正整数,1–10080) |
DSH_NOTIFY_HUB_ENDPOINT |
endpoint |
无(必填) | notify-hub 地址 |
DSH_NOTIFY_HUB_TOKEN |
token |
无(必填) | 访问令牌,查询串 ?token=…,不写日志 |
DSH_ASK_NOTIFY_ENABLED |
enabled |
true |
false 可整体关闭 |
DSH_ASK_NOTIFY_REQUEST_TIMEOUT_MS |
requestTimeoutMs |
5000 |
单次 HTTP 投递超时(毫秒) |
| — | source |
dsh |
消息来源标识,供 notify-hub 规则匹配 |
覆盖配置应改 profile 自己的 ~/.dsh/profiles/web/cordis.patch.yml,不要改包内 node_modules/dsh-ask-timeout-notify/cordis.patch.yml。示例:
# ~/.dsh/profiles/web/cordis.patch.yml
- id: ask-timeout-notify
config:
timeoutMinutes: 15
典型用法与验证¶
日常无需额外 API:模型正常调用 ask_user_question 后,若你在阈值内不回答且前端仍由回答者接手,到点会自动投递待办。
快速验证:将 DSH_ASK_TIMEOUT_MINUTES 设为 1,重启 dsh web,让模型提问后不要回答,约一分钟后应在 notify-hub 侧看到待办;验证完改回 60。
判断是否在工作:
- 未配置端点或令牌:插件仍装载,启动日志会有 warn,超时后不会产生待办。
- 投递成功:DSH 日志可出现
ask-timeout-notify: 已投递待办 message_id=… todo_id=… dedup=ask:<会话>:<问题 id>(是否出现在 stdout 取决于 profile 日志配置)。 - 更可靠的旁证:notify-hub
/todos页面出现source=dsh的待办。
排障时可先用免鉴权的健康检查:
curl -sS "$ENDPOINT/healthz"
常见现象:无待办且无「已投递」日志多为端点或令牌未配;401 多为令牌与 notify-hub server.auth_token 不一致;「有 apply 但从不触发」需确认模型是否真的调用了 ask_user_question。
适用场景与注意¶
适合谁:本地或团队已跑 DSH Web 与 notify-hub,希望模型提问后长时间无人操作时,在飞书等渠道收到「DSH 在等你回答」类待办,而不是事后才发现会话空挂。
权限与安全:插件随当前 dsh web 进程运行,会向 notify-hub 发起 HTTP 请求;安装前请自行审阅 仓库源码 与 MIT 许可证,并按环境配置令牌,避免把 DSH_NOTIFY_HUB_TOKEN 提交到版本库。
生态说明:DSH 社区插件目录(如 SkillHub 上的条目)为独立站点,与 DeepSeek、幻方无官方从属关系;安装命令与行为以 GitHub README 为准。
结尾¶
dsh-ask-timeout-notify 在「问答仍在等、只是人还没回」的路径上补一层超时提醒,通过 notify-hub 统一待办与多渠道推送,且通知失败不影响 DSH 主流程。需要进一步了解安装细节、触发边界与排障表,可直接阅读官方文档:
- 目录页:https://www.skillhub.cn/plugins/SJTUMalPan/dsh-ask-timeout-notify
- GitHub:https://github.com/SJTUMalPan/dsh-ask-timeout-notify