dsh-ask-timeout-notify:ask 超时无人答时经 notify-hub 推送待办

前言

在 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 脚本、监控告警走同一入口。

前置条件

  1. DSH 已安装,且能跑 dsh web(profile 名为 web)。
  2. notify-hub 在运行,并知晓地址与访问令牌:
    - 默认地址示例:http://127.0.0.1:8000;
    - 令牌:notify-hub config.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
羽毛球分组比赛记分
小程序二维码

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

小夜