将语义化消息展示与 channel 原生 UI 渲染器解耦的重构实现记录。规范文档见 docs/plugins/message-presentation,此文件保留为历史实现上下文。
已实现状态
ReplyPayload.presentation承载语义消息 UIReplyPayload.delivery.pin承载已发送消息的 pin 请求- 共享消息 actions 暴露
presentation、delivery、pin,而非 provider 原生的components、blocks、buttons、card - Core 通过插件声明的出站能力渲染或自动降级 presentation
- Discord、Slack、Telegram、Mattermost、MS Teams、Feishu 渲染器消费通用合约
- Discord channel 控制平面代码不再导入 Carbon UI 容器
核心数据结构
type MessagePresentation = {
tone?: "neutral" | "info" | "success" | "warning" | "danger";
title?: string;
blocks: MessagePresentationBlock[];
};
type ReplyPayloadDelivery = {
pin?: boolean | { enabled: boolean; notify?: boolean; required?: boolean };
};delivery.pin = true 表示 pin 第一条成功投递的消息;notify 默认 false;required 默认 false(不支持时自动降级继续投递)。
运行时能力合约
type ChannelOutboundAdapter = {
presentationCapabilities?: ChannelPresentationCapabilities;
renderPresentation?: (params) => ReplyPayload | null;
deliveryCapabilities?: ChannelDeliveryCapabilities;
pinDeliveredMessage?: (params) => Promise<void>;
};Core 流程:解析目标 channel → 查询展示能力 → 降级不支持的 block → 调用 renderPresentation → 无渲染器时转文本 fallback → 发送成功后执行 pinDeliveredMessage。
各 Channel 渲染映射
| Channel | 渲染方式 |
|---|---|
| Discord | components v2 + Carbon containers(仅运行时模块) |
| Slack | Block Kit,移除 agent/CLI blocks 输入 |
| Telegram | 文本/context/divider 为文本;actions/select 为 inline keyboard(已配置且允许时) |
| Mattermost | 交互按钮(已配置时),其他 block 降级为文本 |
| MS Teams | Adaptive Cards |
| Feishu | 交互卡片 |
| LINE | Flex 或模板消息,不支持时降级为文本 |
未完成项
- Step 12:
channelData中 provider 私有传输信封的深度清理(后续 pass) - Step 15:Discord 和受影响 channel 入口点的 import fanout 量化分析