Get started
План рефакторингу представлення каналів
Стан
Реалізовано для спільних поверхонь агента, CLI, можливостей плагінів і вихідної доставки:
ReplyPayload.presentationпереносить семантичний інтерфейс повідомлення.ReplyPayload.delivery.pinпереносить запити на закріплення надісланого повідомлення.- Спільні дії з повідомленнями надають
presentation,deliveryіpinзамість нативних для провайдераcomponents,blocks,buttonsабоcard. - Ядро відтворює представлення або автоматично спрощує його відповідно до заявлених плагіном можливостей вихідної доставки.
- Рендерери Discord, Slack, Telegram, Mattermost, MS Teams і Feishu використовують універсальний контракт.
- Код площини керування каналом Discord більше не імпортує контейнери інтерфейсу на основі Carbon.
Канонічна документація тепер міститься в розділі Представлення повідомлень. Зберігайте цей план як історичний контекст реалізації; у разі змін контракту, рендерера або поведінки резервного варіанта оновлюйте канонічний посібник.
Проблема
Наразі інтерфейс каналів розділений між кількома несумісними поверхнями:
- Ядро володіє міжконтекстним хуком рендерера у формі Discord через
buildCrossContextComponents. channel.tsDiscord може імпортувати нативний інтерфейс Carbon черезDiscordUiContainer, що додає залежності інтерфейсу середовища виконання до площини керування плагіном каналу.- Агент і CLI надають обхідні шляхи для нативних корисних даних, як-от
componentsDiscord,blocksSlack,buttonsTelegram або Mattermost іcardTeams або Feishu. ReplyPayload.channelDataмістить як транспортні підказки, так і нативні оболонки інтерфейсу.- Універсальна модель
interactiveіснує, але вона вужча за розвиненіші макети, які вже використовують Discord, Slack, Teams, Feishu, LINE, Telegram і Mattermost.
Через це ядро знає про форми нативних інтерфейсів, послаблюється ліниве завантаження середовища виконання плагінів, а агенти отримують забагато специфічних для провайдерів способів виразити той самий намір повідомлення.
Цілі
- Ядро визначає найкраще семантичне представлення повідомлення на основі заявлених можливостей.
- Розширення заявляють можливості та перетворюють семантичне представлення на нативні транспортні корисні дані.
- Вебінтерфейс керування залишається відокремленим від нативного інтерфейсу чату.
- Нативні корисні дані каналів не надаються через спільну поверхню повідомлень агента або CLI.
- Непідтримувані функції представлення автоматично спрощуються до найкращого текстового представлення.
- Поведінка доставки, як-от закріплення надісланого повідомлення, є універсальними метаданими доставки, а не представленням.
Нецілі
- Без шару зворотної сумісності для
buildCrossContextComponents. - Без публічних обхідних шляхів до нативних
components,blocks,buttonsабоcard. - Без імпортів бібліотек нативного інтерфейсу каналів у ядро.
- Без специфічних для провайдерів поверхонь SDK для вбудованих каналів.
Цільова модель
Додайте до ReplyPayload поле presentation, яким володіє ядро.
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger"; type MessagePresentation = { tone?: MessagePresentationTone; 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[] }; type MessagePresentationButton = { label: string; value?: string; url?: string; style?: "primary" | "secondary" | "success" | "danger";}; type MessagePresentationOption = { label: string; value: string;};Під час міграції interactive стає підмножиною presentation:
- Текстовий блок
interactiveзіставляється зpresentation.blocks[].type = "text". - Блок кнопок
interactiveзіставляється зpresentation.blocks[].type = "buttons". - Блок вибору
interactiveзіставляється зpresentation.blocks[].type = "select".
Зовнішні схеми агента та CLI тепер використовують presentation; interactive залишається внутрішнім застарілим допоміжним засобом аналізу й рендерингу для наявних виробників відповідей.
У публічному API для виробників interactive вважається застарілим. Підтримка в
середовищі виконання зберігається, щоб наявні допоміжні засоби схвалення та старіші плагіни продовжували
працювати, тоді як новий код формує presentation.
Метадані доставки
Додайте поле delivery, яким володіє ядро, для поведінки надсилання, що не стосується інтерфейсу.
type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};Семантика:
delivery.pin = trueозначає закріпити перше успішно доставлене повідомлення.- Типове значення
notify—false. - Типове значення
required—false; непідтримувані канали або невдале закріплення автоматично спрощують поведінку, продовжуючи доставку. - Ручні дії з повідомленнями
pin,unpinіlist-pinsзберігаються для наявних повідомлень.
Поточне прив’язування теми Telegram ACP слід перенести з channelData.telegram.pin = true до delivery.pin = true.
Контракт можливостей середовища виконання
Додайте хуки рендерингу представлення та доставки до вихідного адаптера середовища виконання, а не до плагіна каналу площини керування.
type ChannelPresentationCapabilities = { supported: boolean; buttons?: boolean; selects?: boolean; context?: boolean; divider?: boolean; tones?: MessagePresentationTone[]; limits?: { actions?: { maxActions?: number; maxActionsPerRow?: number; maxRows?: number; maxLabelLength?: number; maxValueBytes?: number; supportsStyles?: boolean; supportsDisabled?: boolean; supportsLayoutHints?: boolean; }; selects?: { maxOptions?: number; maxLabelLength?: number; maxValueBytes?: number; }; text?: { maxLength?: number; encoding?: "characters" | "utf8-bytes" | "utf16-units"; markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown"; supportsEdit?: boolean; }; };}; type ChannelDeliveryCapabilities = { pinSentMessage?: boolean;}; type ChannelOutboundAdapter = { presentationCapabilities?: ChannelPresentationCapabilities; renderPresentation?: (params: { payload: ReplyPayload; presentation: MessagePresentation; ctx: ChannelOutboundSendContext; }) => ReplyPayload | null; deliveryCapabilities?: ChannelDeliveryCapabilities; pinDeliveredMessage?: (params: { cfg: OpenClawConfig; accountId?: string | null; to: string; threadId?: string | number | null; messageId: string; notify: boolean; }) => Promise<void>;};Поведінка ядра:
- Визначити цільовий канал і адаптер середовища виконання.
- Запросити можливості представлення.
- Спростити непідтримувані блоки та застосувати універсальні обмеження можливостей перед рендерингом.
- Викликати
renderPresentation. - Якщо рендерера немає, перетворити представлення на резервний текст.
- Після успішного надсилання викликати
pinDeliveredMessage, коли запитаноdelivery.pinі ця можливість підтримується.
Зіставлення каналів
Discord:
- Перетворювати
presentationна компоненти v2 та контейнери Carbon у модулях лише для середовища виконання. - Зберігати допоміжні засоби кольорів акценту в легких модулях.
- Видалити імпорти
DiscordUiContainerз коду площини керування плагіном каналу.
Slack:
- Перетворювати
presentationна Block Kit. - Видалити вхідний параметр
blocksагента та CLI.
Telegram:
- Відтворювати текст, контекст і роздільники як текст.
- Відтворювати дії та вибір як вбудовані клавіатури, якщо це налаштовано й дозволено для цільової поверхні.
- Використовувати резервний текст, коли вбудовані кнопки вимкнено.
- Перенести закріплення тем ACP до
delivery.pin.
Mattermost:
- Відтворювати дії як інтерактивні кнопки, якщо це налаштовано.
- Відтворювати інші блоки як резервний текст.
MS Teams:
- Перетворювати
presentationна Adaptive Cards. - Зберегти ручні дії закріплення, відкріплення та перегляду списку закріплень.
- За потреби реалізувати
pinDeliveredMessage, якщо підтримка Graph надійна для цільової розмови.
Feishu:
- Перетворювати
presentationна інтерактивні картки. - Зберегти ручні дії закріплення, відкріплення та перегляду списку закріплень.
- За потреби реалізувати
pinDeliveredMessageдля закріплення надісланого повідомлення, якщо поведінка API надійна.
LINE:
- За можливості перетворювати
presentationна повідомлення Flex або шаблонні повідомлення. - Для непідтримуваних блоків повертатися до тексту.
- Видалити корисні дані інтерфейсу LINE з
channelData.
Прості або обмежені канали:
- Перетворювати представлення на текст із консервативним форматуванням.
Етапи рефакторингу
- Повторно застосувати виправлення випуску Discord, яке відокремлює
ui-colors.tsвід інтерфейсу на основі Carbon і видаляєDiscordUiContainerзextensions/discord/src/channel.ts. - Додати
presentationіdeliveryдоReplyPayload, нормалізації вихідних корисних даних, зведень доставки та корисних даних хуків. - Додати схему
MessagePresentationі допоміжні засоби аналізу у вузькому підшляху SDK/середовища виконання. - Замінити можливості повідомлень
buttons,cards,componentsіblocksна можливості семантичного представлення. - Додати до вихідного адаптера середовища виконання хуки для рендерингу представлення та закріплення доставленого повідомлення.
- Замінити побудову міжконтекстних компонентів на
buildCrossContextPresentation. - Видалити
src/infra/outbound/channel-adapters.tsі вилучитиbuildCrossContextComponentsіз типів плагіна каналу. - Змінити
maybeApplyCrossContextMarker, щоб він додававpresentationзамість нативних параметрів. - Оновити шляхи надсилання диспетчеризації плагінів, щоб вони використовували лише семантичне представлення та метадані доставки.
- Видалити нативні параметри корисних даних агента та CLI:
components,blocks,buttonsіcard. - Видалити допоміжні засоби SDK, які створюють нативні схеми інструментів повідомлень, замінивши їх допоміжними засобами схеми представлення.
- Видалити інтерфейсні/нативні оболонки з
channelData; зберігати лише транспортні метадані, доки не буде перевірено кожне решту полів. - Мігрувати рендерери Discord, Slack, Telegram, Mattermost, MS Teams, Feishu і LINE.
- Оновити документацію для CLI повідомлень, сторінок каналів, SDK плагінів і збірника рецептів можливостей.
- Виконати профілювання розгалуження імпортів для Discord і зачеплених точок входу каналів.
Етапи 1–11 і 13–14 реалізовано в цьому рефакторингу для спільних контрактів агента, CLI, можливостей плагінів і вихідного адаптера. Етап 12 залишається глибшим проходом внутрішнього очищення приватних для провайдерів транспортних оболонок channelData. Етап 15 залишається подальшою перевіркою, якщо потрібні кількісні показники розгалуження імпортів поза межами перевірки типів і тестів.
Тести
Додати або оновити:
- Тести нормалізації представлення.
- Тести автоматичного спрощення представлення для непідтримуваних блоків.
- Тести міжконтекстних маркерів для диспетчеризації плагінів і основних шляхів доставки.
- Матричні тести рендерингу каналів для Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE і резервного тексту.
- Тести схеми інструментів повідомлень, які доводять, що нативні поля вилучено.
- Тести CLI, які доводять, що нативні прапорці вилучено.
- Регресійний тест лінивості імпортів точки входу Discord, що охоплює Carbon.
- Тести закріплення доставки, що охоплюють Telegram і універсальний резервний варіант.
Відкриті питання
- Чи слід у першому проході реалізувати
delivery.pinдля Discord, Slack, MS Teams і Feishu, чи спочатку лише для Telegram? - Чи має
deliveryзгодом увібрати наявні поля, як-отreplyToId,replyToCurrent,silentіaudioAsVoice, чи залишитися зосередженим на поведінці після надсилання? - Чи має представлення безпосередньо підтримувати зображення або посилання на файли, чи наразі медіа мають залишатися відокремленими від макета інтерфейсу?