消息如何流转
L1~L2 推荐阅读。读完这一页即可理解「回复该写在哪、事件什么时候触发」,无需先读架构长文。
Endpoint 入站/出站能力
每个 Endpoint 实例可声明 capabilities: ['inbound']、['outbound'] 或两者(默认继承 Adapter 上限)。能力与方法的对应关系:
| 能力 | 方法 |
|---|---|
inbound | $connect、$disconnect、$formatMessage |
outbound | $sendMessage、$recallMessage;入站 Message 上可绑定 $reply |
| 双向 | 全部 |
纯入站 endpoint(如仅 webhook 的 IoT)不实现出站方法;跨平台回复请 inject(outboundAdapter).sendMessage(...)。纯出站 endpoint(如通知推送)跳过 $connect,启动后 $connected 默认为 true。Endpoint 连接状态变化会通过 Plugin endpoint.connect / endpoint.disconnect / endpoint.error 与 Notice(endpoint.lifecycle)双通道发出。
入站(用户 → 机器人)
- 平台 SDK / Endpoint 收到原始事件,组装为框架的
Message,通常调用adapter.emit('message.receive', message)。 Adapter对message.receive的处理是串行的:- 先
await根插件注入的MessageDispatcher.dispatch(message)(若未注册dispatch会记错误日志,命令/AI 主路由不会执行)。 - 再
await根插件dispatch('message.receive', message),触发插件生命周期(例如你在根插件上的plugin.on('message.receive')、统一收件箱等)。 - 最后按注册顺序同步调用本适配器上
adapter.on('message.receive', ...)注册的函数——适用于控制台 UI、调试观测,不要用来做业务路由(业务请用 Dispatcher + 命令/AI 或 Guardrail)。
- 先
MessageDispatcher内部(进阶):Guardrail → Route(默认exclusive:命令与 AI 互斥)→ Handle(CommandFeature/ AI Handler);需要「双轨」时在配置中设dispatcher.mode: dual等,见 AI 模块。
更完整的流程图见 架构概览 - 消息处理流程。实现细节见仓库根目录 AGENTS.md。
出站(机器人 → 用户)
业务与框架应统一走:
message.$reply(...),或adapter.sendMessage(options)。Adapter.sendMessage内先renderSendMessage:- 依次执行根插件上所有
before.sendMessage(可改写即将发出的内容)。 - 链尾将仍未转换的
html消息段自动剥离为text段(htmlToFallbackText)。
- 依次执行根插件上所有
- 再调用具体
bot.$sendMessage发到平台。
由 Dispatcher 发起的润色会通过 replyWithPolish 与异步上下文配合 before.sendMessage,与手写 $reply 共用同一管道;细节见 AI 模块 - 出站润色。
HTML 卡片出站(可选出图)
业务插件只需返回 segment.html({ html }),不必手写文本回退:
ts
import { segment } from 'zhin.js';
return segment.html({
html: buildMyCardHtml(data),
width: 540,
backgroundColor: '#d8dce3',
});| 场景 | 行为 |
|---|---|
已安装 @zhin.js/plugin-html-renderer | before.sendMessage 将 html 段转为 PNG image 段 |
| 未安装或转图失败 | renderSendMessage 链尾自动从 HTML 剥离可读纯文本发出 |
| 需要高质量回退 | 可选传 text 覆盖自动剥离(高级用法) |
卡片 HTML 建议用 @zhin.js/satori 的 h() 与内置组件构建(与 IM 的 zhin.js JSX 分离)。详见 plugin-html-renderer README 与 plugin-group-suite README。