- текстовые разделы
- небольшой текст контекста/нижнего колонтитула
- разделители
- кнопки
- меню выбора
- заголовок карточки и тон
components, Slack
blocks, Telegram buttons, Teams card или Feishu card, в общий
инструмент сообщений. Это выходные данные рендерера, которыми владеет channel plugin.
Контракт
Авторы Plugin импортируют публичный контракт из:action.type: "command"запускает нативную slash-команду через командный путь ядра. Используйте это для встроенных командных кнопок и меню.action.type: "callback"переносит непрозрачные данные Plugin через путь взаимодействий канала. Channel plugins не должны переинтерпретировать callback-данные как slash-команды.value— устаревшее непрозрачное callback-значение. Новые элементы управления должны использоватьaction, чтобы channel plugins могли сопоставлять команды и callbacks без догадок по тексту.url— кнопка-ссылка. Она может существовать безvalue.webAppописывает кнопку channel-native веб-приложения. Telegram отрисовывает ее какweb_appи поддерживает только в приватных чатах.web_appпо-прежнему принимается в свободных JSON-пейлоадах для совместимости, но TypeScript-производители должны использоватьwebApp.labelобязателен и также используется в текстовом fallback.styleносит рекомендательный характер. Рендереры должны сопоставлять неподдерживаемые стили с безопасным значением по умолчанию, а не прерывать отправку.priorityнеобязателен. Когда канал объявляет ограничения действий и элементы управления нужно отбросить, ядро сначала сохраняет кнопки с более высоким приоритетом и сохраняет исходный порядок среди кнопок с одинаковым приоритетом. Когда все элементы управления помещаются, сохраняется авторский порядок.disabledнеобязателен. Каналы должны явно включить это черезsupportsDisabled; иначе ядро понижает отключенный элемент управления до неинтерактивного fallback-текста.reusableнеобязателен. Каналы, поддерживающие повторно используемые нативные callbacks, могут оставить действие доступным после успешного взаимодействия. Используйте это для повторяемых или идемпотентных действий, таких как обновить, проверить или подробнее; не задавайте его для обычных одноразовых подтверждений и разрушительных действий.
options[].actionимеет то же значение команды/callback, что и кнопочныйaction.options[].value— устаревшее выбранное значение приложения.placeholderносит рекомендательный характер и может игнорироваться каналами без нативной поддержки выбора.- Если канал не поддерживает выбор, fallback-текст перечисляет метки.
Примеры производителей
Простая карточка:Контракт рендерера
Channel plugins объявляют поддержку рендеринга в своем outbound-адаптере:limits описывают общий конверт, который ядро может адаптировать перед вызовом
рендерера:
Поток рендеринга ядра
КогдаReplyPayload или действие сообщения включает presentation, ядро:
- Нормализует пейлоад представления.
- Разрешает outbound-адаптер целевого канала.
- Читает
presentationCapabilities. - Применяет общие ограничения возможностей, такие как количество действий, длина меток и количество вариантов выбора, когда адаптер их объявляет.
- Вызывает
renderPresentation, когда адаптер может отрисовать пейлоад. - Возвращается к консервативному тексту, когда адаптер отсутствует или не может выполнить рендеринг.
- Отправляет получившийся пейлоад через обычный путь доставки канала.
- Применяет метаданные доставки, такие как
delivery.pin, после первого успешно отправленного сообщения.
Правила деградации
Представление должно быть безопасно отправлять в каналах с ограниченными возможностями. Fallback-текст включает:titleпервой строкой- блоки
textкак обычные абзацы - блоки
contextкак компактные строки контекста - блоки
dividerкак визуальный разделитель - метки кнопок, включая URL для кнопок-ссылок
- метки вариантов выбора
- Telegram с отключенными inline-кнопками отправляет текстовый fallback.
- Канал без поддержки выбора перечисляет варианты выбора как текст.
- Кнопка только с URL становится либо нативной кнопкой-ссылкой, либо fallback-строкой URL.
- Необязательные ошибки закрепления не приводят к сбою доставленного сообщения.
delivery.pin.required: true; если закрепление запрошено как
обязательное и канал не может закрепить отправленное сообщение, доставка сообщает об ошибке.
Сопоставление провайдеров
Текущие встроенные рендереры:| Канал | Нативная цель рендеринга | Примечания |
|---|---|---|
| Discord | Компоненты и контейнеры компонентов | Сохраняет устаревшие channelData.discord.components для существующих производителей provider-native пейлоадов, но новые общие отправки должны использовать presentation. |
| Slack | Block Kit | Сохраняет устаревшие channelData.slack.blocks для существующих производителей provider-native пейлоадов, но новые общие отправки должны использовать presentation. |
| Telegram | Текст плюс inline-клавиатуры | Кнопки/выбор требуют возможности inline-кнопок для целевой поверхности; иначе используется текстовый fallback. |
| Mattermost | Текст плюс интерактивные props | Остальные блоки деградируют до текста. |
| Microsoft Teams | Adaptive Cards | Обычный текст message включается в карточку, когда предоставлены оба. |
| Feishu | Интерактивные карточки | Заголовок карточки может использовать title; тело избегает дублирования этого заголовка. |
| Простые каналы | Текстовый fallback | Каналы без рендерера все равно получают читаемый вывод. |
Представление и InteractiveReply
InteractiveReply — более старое внутреннее подмножество, используемое вспомогательными
функциями подтверждения и взаимодействия. Оно поддерживает:
- текст
- кнопки
- списки выбора
MessagePresentation — канонический общий контракт отправки. Он добавляет:
- заголовок
- тон
- контекст
- разделитель
- кнопки только с URL
- общие метаданные доставки через
ReplyPayload.delivery
openclaw/plugin-sdk/interactive-runtime при соединении со старым
кодом:
MessagePresentation напрямую. Существующие
payload interactive являются устаревшим подмножеством presentation; поддержка в runtime
сохраняется для старых производителей.
Устаревшие типы InteractiveReply* и вспомогательные функции преобразования помечены
@deprecated в SDK:
InteractiveReply,InteractiveReplyBlock,InteractiveReplyButton,InteractiveReplyOption,InteractiveReplySelectBlockиInteractiveReplyTextBlocknormalizeInteractiveReply(...)hasInteractiveReplyBlocks(...)interactiveReplyToPresentation(...)presentationToInteractiveReply(...)presentationToInteractiveControlsReply(...)resolveInteractiveTextFallback(...)reduceInteractiveReply(...)
presentationToInteractiveReply(...) и
presentationToInteractiveControlsReply(...) остаются доступными как мосты рендеринга
для устаревших реализаций каналов. Новый код производителей не должен вызывать
их; отправляйте presentation и позвольте адаптации в core/канале обработать рендеринг.
У вспомогательных функций подтверждения также есть замены, где приоритет у представления:
- используйте
buildApprovalPresentationFromActionDescriptors(...)вместоbuildApprovalInteractiveReplyFromActionDescriptors(...) - используйте
buildApprovalPresentation(...)вместоbuildApprovalInteractiveReply(...) - используйте
buildExecApprovalPresentation(...)вместоbuildExecApprovalInteractiveReply(...)
renderMessagePresentationFallbackText(...) возвращает пустую строку для
блоков представления, у которых нет текстового fallback, например для представления
только с разделителем. Транспорты, которым требуется непустое тело отправки, могут передать
emptyFallback, чтобы включить минимальное тело без изменения контракта fallback по умолчанию.
Закрепление доставки
Закрепление — это поведение доставки, а не представления. Используйтеdelivery.pin вместо
нативных полей провайдера, таких как channelData.telegram.pin.
Семантика:
pin: trueзакрепляет первое успешно доставленное сообщение.pin.notifyпо умолчанию равноfalse.pin.requiredпо умолчанию равноfalse.- Необязательные ошибки закрепления деградируют и оставляют отправленное сообщение без изменений.
- Обязательные ошибки закрепления приводят к сбою доставки.
- Для сообщений, разбитых на части, закрепляется первая доставленная часть, а не последняя.
pin, unpin и pins по-прежнему существуют для существующих
сообщений, если провайдер поддерживает эти операции.
Контрольный список автора Plugin
- Объявляйте
presentationизdescribeMessageTool(...), когда канал может отрендерить или безопасно деградировать семантическое представление. - Добавьте
presentationCapabilitiesв runtime-адаптер исходящих сообщений. - Реализуйте
renderPresentationв runtime-коде, а не в коде настройки Plugin на уровне управления. - Не допускайте попадания нативных UI-библиотек в горячие пути настройки/каталога.
- Объявляйте общие ограничения возможностей в
presentationCapabilities.limits, когда они известны. - Сохраняйте окончательные ограничения платформы в рендерере и тестах.
- Добавьте fallback-тесты для неподдерживаемых кнопок, списков выбора, URL-кнопок, дублирования заголовка/текста
и смешанных отправок
messageплюсpresentation. - Добавляйте поддержку закрепления доставки через
deliveryCapabilities.pinиpinDeliveredMessageтолько тогда, когда провайдер может закрепить id отправленного сообщения. - Не раскрывайте новые нативные для провайдера поля карточек/блоков/компонентов/кнопок через общую схему действий сообщений.