@ruqinhu/dsh-weixin-link:把 DSH 回合结果自动投递到微信 iLink

前言

在 DeepSeek Harness(DSH)里跑定时任务或远程触发会话时,模型往往只在终端或 Web UI 里给出答案,不会主动把同一段文字发到手机。若依赖模型自己调用发送工具,常见结果是:会话里已有回复却未外发、误发元评论,或把错误栈当成「报告」推出去。微信 iLink 侧还有硬性约束:每次发送必须携带来自入站消息的 context_token,插件不能凭空造 token,长时间无人发消息时,待发内容只能暂存而不能改走别的通道。

下面介绍社区插件 @ruqinhu/dsh-weixin-link(维护者 ruqinhu,分类:客户端)。它在 DSH 与微信 iLink API 之间做通道:收消息、在合适回合结束时自动投递结果,并记录投递回执与决策轨迹。

这是什么

@ruqinhu/dsh-weixin-link 是面向 DeepSeek Harness 的 Weixin(iLink)通道插件。简介原文为:bidirectional send/receive with delivery receipts——即双向收发,并对每次发送尝试留痕。

插件通过 Cordis patch 订阅 session/event,在 turn/end 时决定是否把本回合文本发到微信,而不是把「记得调用发送工具」交给模型。凭证经 DSH 的 credential store(ctx.credentials.resolve())读取,不直接读 process.env,以免覆盖 $DSH_HOME/.credentials.yaml 与项目 .env 的分层规则。

核心功能

约束 后果
每次发送必须带 context_token token 只能来自入站消息
不能 mint token 长时间无入站时,例如 07:00 定时报告会暂存,直到机主再发消息
不做 fallback 通道 失败不转路由;暂存文本在条件允许时重放
单条文本上限 2,200 字 在代码里截断,不交给模型自行控制

哪些回合会被自动投递

插件按 source.kind 过滤。只有部分来源会外发:

source.kind 来源 是否投递
schedule cron 任务 是
weixin-link 机主从微信发来消息触发的回合 是
user 终端 / Web UI 输入 否(答案已在屏幕上)
runtime-context / skill-catalog / time-context 等 注入上下文 否
compact-checkpoint / provider / fallback 等 压缩、标题等内部流程 否

README 说明:只有第一条用户消息标定来源;后续回合会注入上下文,若用「最后一条消息」判断,会把所有回合都当成上下文而不投递。

机制要点

  • 谁负责发:通道在 turn/end 自动发送;备选方案是让模型调用 weixin_push,实测会出现已回答但未外发、乱推说明文字等问题。模型若不想说话,可使用 [SILENT]。
  • 去重:10 分钟内相同正文视为已投递;窗口外重复仍会发出。手动 weixin_push 会压制同内容的自动投递。
  • 空回合:发送 本次无产出(timestamp),避免「跑了但失败」与「没跑」无法区分。
  • 失败回合:可发送 ⚠️ 回合未完成(reason,timestamp):本次没有可投递的内容。;每个 session 每小时最多一条失败通知(内存计数,进程重启可能多一条)。
  • 入站与重放:独立定时器重放 outbox,单线程 serial;长轮询 bootstrap 不阻塞重放,避免 30/60/120 秒退避叠加成数分钟 deaf。
  • 存活检测:每轮更新 state/heartbeat.json,默认每 60 秒检查;若连续 3 个 budget(≥ 90 秒)没有任何发送尝试,则重启 poll 循环。

工具与本地文件

工具 用途
weixin_push 立即发送;无法投递时自动暂存(park)
weixin_status 登录状态、token 年龄、最近投递、outbox 深度、poll 是否存活
路径(默认 dataDir 为 ~/.dsh/weixin-link) 内容
receipts/YYYY-MM-DD.jsonl 每次发送尝试一行,按东八区日期分文件
delivery-trace.log 每个 turn 的投递决策,含 skip 及原因
outbox/ 等待 token 的暂存消息
state/heartbeat.json 最近尝试/成功、失败次数、入站计数、重启次数

delivery-trace.log 示例形态(README 摘录):

send session=... turn=12 kind=turn len=63
ok   session=... turn=12 msgid=7521135910923441000
skip session=... turn=13 reason=source-not-deliverable

兼容性与体量

项 值
DSH(peer) 0.2.1-rc.5
插件版本(package.json) 0.4.2
Runtime Node 22+,无 native 模块
依赖服务 tools、credentials、sessionController;agents 可选
载荷 仅文本,≤ 2,200 字符
许可证 MIT
单元测试 README 称 248 条、21 个文件,tsc --noEmit 通过

安装与配置

安装

官方安装命令如下:

dsh plugin add @ruqinhu/dsh-weixin-link

安装前请自行查看 GitHub 仓库 源码与 MIT 许可证。插件以当前 DSH 进程权限运行,凭证与 dataDir 会落在本机,部署前确认 token 与数据目录权限可接受。

凭证

在 credential store 中配置 bot token 与 account id。默认 credential 名称:

  • WEIXIN_BOT_TOKEN(配置项 tokenEnv)
  • WEIXIN_BOT_ACCOUNT_ID(配置项 accountIdEnv)

主要配置项

Key 默认值 含义
baseUrl https://ilinkai.weixin.qq.com iLink 端点
dataDir ~/.dsh/weixin-link token、outbox、receipts、trace
poll true 是否运行入站长轮询
pollTimeoutMs 40000 客户端超时,须大于服务端 35 s hold
defaultUserId "" 收件人;空则用最 recent 入站发送者
echoOwnMessages false 是否把机器人自己的消息当入站
sessionId "" 入站路由到的 session,冷启动可恢复
replayIntervalMs 300000 outbox 重试间隔
dedupeWindowMs 600000 相同正文去重窗口
notifyTurnFailures true 回合未完成时是否通知
watchdogIntervalMs 60000 存活检查间隔;0 关闭

典型用法

  1. 安装插件并在 DSH credential store 中写入 WEIXIN_BOT_TOKEN 与 WEIXIN_BOT_ACCOUNT_ID。
  2. 保持 poll: true,从微信向机器人发一条消息,为后续发送换取 context_token。
  3. 配置 cron(source.kind 为 schedule)或继续通过微信触发会话;回合结束后查看手机是否收到自动投递,必要时读 delivery-trace.log 与 receipts/。
  4. 需要主动推送或排查队列时,在会话中调用 weixin_status 查看 token 年龄与 outbox 深度;无法立即发送时用 weixin_push(会 park 到 outbox)。

README 记录的实测:入站 10:00:04 → 回合完成 10:00:24 → 同秒 ok msgid=...;14 小时运行 watchdog restarts: 0。配额耗尽(429 AccountQuotaExceeded)时,旧构建连续 skip not-completed,新构建在约四分钟沉默后发出一条说明回合未完成的短消息。

适用场景与注意

适合:希望 DSH 定时报告、微信触发的会话结果自动回到同一微信对话;需要 JSONL 回执与 trace 审计发送尝试的场景。

限制(README 开放问题摘要):

  • Token 无法由插件刷新;约 12 小时无入站会 park 发送。
  • 单 poll 循环、单收件人;多账号需额外路由层。
  • Outbox 重放串行;富媒体 / 卡片未支持,仅文本。
  • 调试器暂停或长 GC 可能被 watchdog 判为 stall 并重启(无害但会记入 heartbeat)。

DSH 生态强调「一切皆插件」;SkillHub 目录页 为社区站点,与 DeepSeek / 幻方无官方从属关系。

结尾

@ruqinhu/dsh-weixin-link 把微信 iLink 的 token 约束、回合来源过滤和 turn/end 自动投递合在一起,减少「模型忘了发微信」类问题,并用 outbox、trace 与 receipts 把失败与 skip 原因留在磁盘上。进一步细节见 GitHub README(含中文 README.zh-CN.md)与目录页 skillhub.cn/plugins/ruqinhu/dsh-weixin-link。

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

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

Xiaoye