ltl0312/my-dsh-plugins--packages-tlnotify ↗★ 0

dsh-plugin-tlnotify

把 DSH 会话事件(中断 / 结束 / 报错 / 等待操作)聚合到一个 IM 通道,推到 QQ / 飞书,带可点按钮与定向回复

套件
dsh-plugin-tlnotify
相容性
待驗證
版本
0.2.0
授權
MIT
最近更新
2026年10月5日

安裝

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:ltl0312/my-dsh-plugins#9666eb5f4a0ebf028e0496b4ee0e1bb9bafb8fae&path:packages/tlnotify

⚙️ 配置

配置有三条路径,权威性从高到低:

  1. Web 设置页(推荐,见下面「设置页(GUI)」一节)——侧边栏 →「设置」→ 「通知助手」,改完即时热生效,不需要重启,也不需要手改文件。
  2. $DSH_HOME/tlnotify/config.json(字段见下)——设置页写的就是这份文件, 两者永远一致;习惯手改的可以直接编辑它。
  3. profile 的 ~/.dsh/profiles/web/cordis.patch.yml 里按 id 覆盖 (注意是覆盖,不是再插一条 - insert:——挂载已由 bundle 完成,重复插入会挂载两次):
- id: dsh-plugin-tlnotify
  config:
    enabled: true
    channels: []

权威性规则:显式配置 > $DSH_HOME/tlnotify/config.json > 内置默认值。 唯一的例外是每台机器人各自的 sessionScope / sessionId——它们是运行时权威: 在 IM 里发 /mode 写入的值会盖过配置文件 / 补丁,否则用户改完范围一重启就丢。 (mode 与 session.targetSessionId 是 0.1.4 之前的全局开关,如今只剩兼容读写, /mode 不再写它们。)

顶层

配置项默认值说明
enabledtrue总开关。false 时不连任何通道
modeglobal已弃用:0.1.4 起「推哪些会话」由每台机器人各自的 sessionScope 决定,这里只留给老配置读取
channels[][]通道列表,见上
defaultChannelId''默认通道;留空用第一个启用的通道
logLevelinfodebug / info / warn / error
dataDir$DSH_HOME/tlnotify配置 / 状态 / 日志的落盘目录

events —— 哪些事件要推

配置项默认值说明
onTurnEndtrue任务完成
onErrortrue执行错误;同时控制「执行被阻塞」与「异常中断」
onAbortedtrue手动中止
onPendingtrue等待我回答 / 权限请求 / 等待计划确认
onMaxTokenstrueToken 达到上限
includeSubagentfalse是否也推子 Agent 的事件。默认 false——子 Agent 一多会刷屏

content —— 正文放什么

配置项默认值说明
includeMetadatatrue是否带耗时 / 工具数 / token 等元信息
includeUserPrompttrue是否回显触发这一轮的提问
maxBodyChars1800正文硬上限,超出截断并标注

正文出两版,同一个事件渲染两遍。 助手回复、计划、提问选项、工具报错这些自由文本 会先过一遍 src/markdown.ts 的 toPlainText() 得到纯文本 body(标题 ## X → 【X】,表格 | a | b | → · a:b,列表 - x → · x,加粗 / 斜体 / 删除线 / 链接 / 行内代码去掉标记留文字,围栏代码块内容原样保留、只丢掉围栏);同一套渲染代码 换个转换器再跑一遍,得到原样的 markdown。转换器由调用方(通道)自己挑:

  • QQ 默认发纯文本(msg_type: 0 + content,用 body 版);把通道的 markdown 打开才发原生 Markdown(msg_type: 2 + markdown.content,用 markdown 版), 标题加粗并与正文之间空一行(Markdown 里单个换行是软换行,会被并进同一段)。默认关的 原因见上面 QQ 一节:卡片宽度由客户端写死,电脑上比普通气泡窄一截;
  • 飞书 与其它通道用 body:飞书的 lark_md 只认内联子集,不渲染标题与表格, 不压平的话用户看到的就是 | 分类 | 记忆条目 | 这种源码。

两版同源同上限(都受 maxBodyChars 截断、都要分片),所以不会各自漂移。

routing —— 回复怎么找到会话

配置项默认值说明
allowPrefixtrue是否允许 519cc141 继续 这种显式前缀定向
fallbacklatest没有引用时发给谁:latest(最新一条通知的会话)或 intervention(最近一次需要人介入的会话)
tableTtlDays7路由表条目存活天数
echoTargettrue投递后是否回显「已发给 X」。强烈建议保持开启,否则投错会话你无从察觉

session / global —— 正文的形态

会话范围(推哪些会话)是每台机器人各自的,写在通道的 sessionScope / sessionId / sessionFilter 上(见上一节)。下面这两组只管正文怎么渲染。

当某台机器人的范围是「只关心一个会话」时,它收到的通知带完整上下文:

配置项默认值说明
context.includeAssistanttrue是否包含助手回复正文
context.includeToolstrue是否列出工具调用
context.includeTimingtrue是否带耗时
context.previousTurns3附带前 N 轮的摘要(每台机器人可用 historyTurns 覆盖)
context.includeUserPrompttrue是否回显提问
targetSessionId''已弃用:全局单会话开关的遗留字段,改由每台机器人的 sessionId 承担

范围是「全部 / 名单」的机器人保持精简:

配置项默认值说明
verbositybriefbrief 固定精简;normal 让所有会话都按详细正文渲染(不推荐,会刷屏)
includeSessionLabeltrue标题里带「项目 · 短id」
includeSummaryLinetrue是否附一行结果摘要
includeSubagentfalse同 events.includeSubagent

精简模式的正文保留行结构:元信息单独占一行,正文另起一段,段落、【小节】、 · 列表、缩进都原样留着,一个字符都不截——长度只由 content.maxBodyChars 控制 (默认 1800,可在设置页调,范围 200–20000)。早先版本为了「一行讲清楚」把正文折成 一行,助手回复一长就是一堵没有换行、没有分节的墙,所以改掉了。


单元测试(零网络:全部使用假宿主对象)

pnpm --filter dsh-plugin-tlnotify run test