ltl0312/my-dsh-plugins--packages-tlnotify ↗★ 0
dsh-plugin-tlnotify
把 DSH 会话事件(中断 / 结束 / 报错 / 等待操作)聚合到一个 IM 通道,推到 QQ / 飞书,带可点按钮与定向回复
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:ltl0312/my-dsh-plugins#9666eb5f4a0ebf028e0496b4ee0e1bb9bafb8fae&path:packages/tlnotifyドキュメント
README 全文を読む ↗⚙️ 配置
配置有三条路径,权威性从高到低:
- Web 设置页(推荐,见下面「设置页(GUI)」一节)——侧边栏 →「设置」→ 「通知助手」,改完即时热生效,不需要重启,也不需要手改文件。
$DSH_HOME/tlnotify/config.json(字段见下)——设置页写的就是这份文件, 两者永远一致;习惯手改的可以直接编辑它。- 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 不再写它们。)
顶层
| 配置项 | 默认值 | 说明 |
|---|---|---|
enabled | true | 总开关。false 时不连任何通道 |
mode | global | 已弃用:0.1.4 起「推哪些会话」由每台机器人各自的 sessionScope 决定,这里只留给老配置读取 |
channels[] | [] | 通道列表,见上 |
defaultChannelId | '' | 默认通道;留空用第一个启用的通道 |
logLevel | info | debug / info / warn / error |
dataDir | $DSH_HOME/tlnotify | 配置 / 状态 / 日志的落盘目录 |
events —— 哪些事件要推
| 配置项 | 默认值 | 说明 |
|---|---|---|
onTurnEnd | true | 任务完成 |
onError | true | 执行错误;同时控制「执行被阻塞」与「异常中断」 |
onAborted | true | 手动中止 |
onPending | true | 等待我回答 / 权限请求 / 等待计划确认 |
onMaxTokens | true | Token 达到上限 |
includeSubagent | false | 是否也推子 Agent 的事件。默认 false——子 Agent 一多会刷屏 |
content —— 正文放什么
| 配置项 | 默认值 | 说明 |
|---|---|---|
includeMetadata | true | 是否带耗时 / 工具数 / token 等元信息 |
includeUserPrompt | true | 是否回显触发这一轮的提问 |
maxBodyChars | 1800 | 正文硬上限,超出截断并标注 |
正文出两版,同一个事件渲染两遍。 助手回复、计划、提问选项、工具报错这些自由文本 会先过一遍
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 —— 回复怎么找到会话
| 配置项 | 默认值 | 说明 |
|---|---|---|
allowPrefix | true | 是否允许 519cc141 继续 这种显式前缀定向 |
fallback | latest | 没有引用时发给谁:latest(最新一条通知的会话)或 intervention(最近一次需要人介入的会话) |
tableTtlDays | 7 | 路由表条目存活天数 |
echoTarget | true | 投递后是否回显「已发给 X」。强烈建议保持开启,否则投错会话你无从察觉 |
session / global —— 正文的形态
会话范围(推哪些会话)是每台机器人各自的,写在通道的 sessionScope /
sessionId / sessionFilter 上(见上一节)。下面这两组只管正文怎么渲染。
当某台机器人的范围是「只关心一个会话」时,它收到的通知带完整上下文:
| 配置项 | 默认值 | 说明 |
|---|---|---|
context.includeAssistant | true | 是否包含助手回复正文 |
context.includeTools | true | 是否列出工具调用 |
context.includeTiming | true | 是否带耗时 |
context.previousTurns | 3 | 附带前 N 轮的摘要(每台机器人可用 historyTurns 覆盖) |
context.includeUserPrompt | true | 是否回显提问 |
targetSessionId | '' | 已弃用:全局单会话开关的遗留字段,改由每台机器人的 sessionId 承担 |
范围是「全部 / 名单」的机器人保持精简:
| 配置项 | 默认值 | 说明 |
|---|---|---|
verbosity | brief | brief 固定精简;normal 让所有会话都按详细正文渲染(不推荐,会刷屏) |
includeSessionLabel | true | 标题里带「项目 · 短id」 |
includeSummaryLine | true | 是否附一行结果摘要 |
includeSubagent | false | 同 events.includeSubagent |
精简模式的正文保留行结构:元信息单独占一行,正文另起一段,段落、【小节】、
· 列表、缩进都原样留着,一个字符都不截——长度只由 content.maxBodyChars 控制
(默认 1800,可在设置页调,范围 200–20000)。早先版本为了「一行讲清楚」把正文折成
一行,助手回复一长就是一堵没有换行、没有分节的墙,所以改掉了。
单元测试(零网络:全部使用假宿主对象)
pnpm --filter dsh-plugin-tlnotify run test