将语义化消息展示与各 channel 原生 UI 渲染器解耦。该计划已在共享 agent、CLI、插件能力和出站投递面实现,此文件保留为历史实现上下文。
问题背景
原有 channel UI 分散在多个不兼容的面:
- Core 通过
buildCrossContextComponents持有 Discord 形状的跨上下文渲染钩子 - Discord
channel.ts可导入原生 Carbon UI(DiscordUiContainer),将运行时 UI 依赖拉入 channel 插件控制平面 - Agent 和 CLI 暴露原生 payload 逃生舱(Discord
components、Slackblocks、Telegrambuttons、Teams/Feishucard) ReplyPayload.channelData同时承载传输提示和原生 UI 信封
这导致 core 感知原生 UI 形状,削弱插件运行时懒加载,给 agent 提供了过多 provider 特定的表达方式。
目标模型
在 ReplyPayload 中添加 core 拥有的 presentation 字段:
type MessagePresentation = {
tone?: "neutral" | "info" | "success" | "warning" | "danger";
title?: string;
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };delivery 字段承载发送行为(非 UI):
type ReplyPayloadDelivery = {
pin?: boolean | { enabled: boolean; notify?: boolean; required?: boolean };
};运行时能力合约
展示和投递渲染钩子添加到运行时出站适配器,而非控制平面 channel 插件:
presentationCapabilities:声明支持的 block 类型renderPresentation:将语义展示渲染为原生 transport payloaddeliveryCapabilities:声明是否支持 pin 已发送消息pinDeliveredMessage:执行 pin 操作
Core 行为:解析目标 channel → 查询展示能力 → 降级不支持的 block → 调用 renderPresentation → 无渲染器时转为文本 fallback → 发送成功后执行 pin。
各 Channel 映射
| Channel | 渲染方式 |
|---|---|
| Discord | components v2 + Carbon containers(仅运行时模块) |
| Slack | Block Kit |
| Telegram | 文本/context/divider 为文本,actions/select 为 inline keyboard |
| Mattermost | 交互按钮(已配置时) |
| MS Teams | Adaptive Cards |
| Feishu | 交互卡片 |
| LINE | Flex 或模板消息,不支持时降级为文本 |
已实现内容
ReplyPayload.presentation承载语义消息 UIReplyPayload.delivery.pin承载 pin 请求- Discord、Slack、Telegram、Mattermost、MS Teams、Feishu 渲染器消费通用合约
- Discord channel 控制平面代码不再导入 Carbon UI 容器