openclaw/plugin-sdk/channel-outbound 暴露出站消息行为。使用
openclaw/plugin-sdk/channel-inbound 进行接收、上下文和分派
编排。
核心负责队列处理、持久性、持久化的入口监控和排空
(createChannelIngressMonitor、createChannelIngressDrain 和
openChannelIngressDrain)、通用重试策略、轮次接管生命周期
(turnAdoptionLifecycle / bindIngressLifecycleToReplyOptions)、钩子、
回执以及共享的 message 工具。插件负责原生
发送、编辑和删除调用、目标规范化、平台线程处理、选定的
引用、通知标志、账户状态、入口检查和有效载荷
编码、通道键、不可重试谓词、可选的取代
授权以及平台特定的副作用。
持久化入口监控
当渠道必须在分派前持久化已接受的 传输事件时,使用createChannelIngressMonitor(...)。它将渠道入口队列和排空机制
与共享的准入、轮询、清理、投递和关闭生命周期组合起来。
仅当传输层拥有实质不同的准入或泵送契约时,才使用较低层级的
createChannelIngressDrain(...)。
必需选项如下:
监控会串行化准入,确保追加退避不会颠倒通道内的顺序。
默认的有界追加延迟为
0、100 和 300 ms;重试耗尽时会拒绝
传输回调,而不是分派一个尚未持久化的事件。
认领时,它会解码带版本的有效载荷,重新运行 inspect,并在投递前
拒绝 ID 或通道不匹配的情况。
deliver 接收 onAdopted、onDeferred、onAdoptionFinalizing、
onAbandoned 和 abortSignal。在没有显式移交的情况下返回,会将
终止且未分派的事件标记为已接管。admission 始终为 exclusive。
延迟移交会保持认领,而关闭或中止会使未接管的
工作保持可重试状态。监控独立跟踪投递和认领结算,
因为接管可能会在渠道的投递 Promise
返回前将行标记为墓碑。
可选设置包括自定义追加延迟、用于
高级排空顺序、并发和重试策略的 drain 选项块、外部 abortSignal、
时钟、泵送错误报告、已停止错误工厂以及准入策略。
返回的监控暴露 admit、start、pause、stop、waitForIdle、
isRunning 和 isStopped。stop 首先结算已接受的准入,然后
中止并释放排空器,等待泵和活跃投递完成,并
再次释放以消除惰性创建竞态。
将传输特定的脱敏、原始信封验证、不可重试
分类和持久化有效载荷形态保留在插件中。Webhook 传输
应仅在 admit 完成后确认;不可重放的传输应
暴露持久化追加耗尽错误,而不是静默分派。
适配器
大多数插件会定义一个message 适配器:
出站回显抑制
当平台可能将插件自身的出站消息重新投递为入站消息时,使用渠道、账户、会话以及稳定的平台消息或来源身份调用recordOutboundMessageIdentity(...)。共享入站轮次路径会在会话记录或智能体分派前,于有界的 30 秒窗口内丢弃匹配身份;可以在发送前预留来源身份,或在移除渠道路由时刷新它,以消除投递竞态。isRecentOutboundMessageIdentity(...) 为渠道诊断和测试暴露相同的查询。不要为同一稳定身份维护并行的渠道本地 TTL 缓存。
纯文本清理
当出站适配器需要将支持的 HTML 格式标签转换为 轻量级文本标记时,使用sanitizeForPlainText(...)。默认情况下保留
现有聊天风格的粗体和删除线标记。仅当渠道会将结果重新解析为 Markdown 时,
才传递 { style: "markdown" }:
**bold** 和 ~~strikethrough~~;斜体和行内
代码在两种样式中都保留 _italic_ 和反引号标记。应在
渠道边界选择样式,而不是在清理后重写标记文本。
投递证据
MessageReceipt 记录渠道适配器返回的结果。具体的
平台消息标识符表明平台发送路径已接受
消息;它们并不能证明接收方设备已显示或读取该消息。
没有平台消息标识符的回执仅属于本地回执元数据。
具有已读回执或设备投递状态的渠道应通过独立的
渠道特定路径跟踪这些事实。
如果渠道适配器能够证明重试失败不会造成
接收方可见消息重复,并且尚未开始任何可完成最终处理的调用,则从
openclaw/plugin-sdk/error-runtime 抛出
new PlatformMessageNotDispatchedError("...", { cause: error })。这样核心便可清除过时的发送尝试
证据,并安全地重试已排队的意图。只有拥有最终
分派边界的适配器才能做出此断言。最终处理/发送调用一旦开始或返回
不明确的结果,绝不能使用该标记;错误标记可能导致
消息重复。
现有出站适配器
如果渠道已有兼容的outbound 适配器,请基于它派生
消息适配器,而不要重复发送代码:
持久化发送
运行时发送辅助函数也位于channel-outbound:
sendDurableMessageBatch(...)withDurableMessageSendContext(...)deliverInboundReplyWithMessageSendContext(...)- 草稿流式传输/进度辅助函数,例如
resolveChannelDraftStreamingChunking(...)
sendDurableMessageBatch(...) 返回一个显式结果:
当批次混合已发送、已抑制和失败的
有效载荷时,使用
payloadOutcomes。不要根据空的旧版
直接投递结果推断钩子取消。
延迟投递准入
当已解析的账户无法安全接受核心管理的出站或延迟投递时, 使用message.durableFinal.admitDeferredDelivery(...)。核心会在实时出站工作前同步调用
此钩子,包括跳过队列持久化的路径,并在重放恢复的意图前再次调用。
上下文包含 cfg、channel、to、accountId,以及值为 live 或
recovery 的 phase。
返回 { status: "allowed" } 以继续。当投递不得
持久化、直接发送或重放时,返回
{ status: "permanent_rejection", reason }。实时拒绝会在创建队列、
消息钩子或平台工作之前失败。恢复拒绝会将
排队记录标记为失败,并跳过协调和重放。省略该钩子
即表示允许。
该钩子用于执行同步准入决策,而非发送路径。只读取
已加载的配置或运行时状态;不要执行网络、文件系统或
其他异步 I/O。契约测试应通过
openclaw/plugin-sdk/channel-outbound 中的 ChannelMessageDurableFinalAdapter
覆盖两个阶段和两种结果变体。
兼容性分派
通过channel-inbound 中的 dispatchChannelInboundReply(...)
组装入站回复分派。将平台投递保留在投递适配器中;使用
channel-outbound 处理消息适配器、持久化发送、回执、实时
预览和回复流水线选项。