---
read_when:
    - Додавання або змінення рендерингу картки повідомлення, кнопки або списку вибору
    - Створення плагіна каналу, який підтримує розширені вихідні повідомлення
    - Змінення представлення інструмента повідомлень або можливостей доставки
    - Налагодження регресій рендерингу карток/блоків/компонентів, специфічних для провайдера
summary: Семантичні картки повідомлень, кнопки, списки вибору, резервний текст і підказки щодо доставки для плагінів каналів
title: Представлення повідомлень
x-i18n:
    generated_at: "2026-04-27T06:55:58Z"
    model: gpt-5.4
    provider: openai
    source_hash: 23ef0eab890ee174c1433f72e84932a84a481f2bcf4b69bc793a2660ec94b10c
    source_path: plugins/message-presentation.md
    workflow: 15
---

Представлення повідомлень — це спільний контракт OpenClaw для розширеного інтерфейсу вихідного чату.
Він дає змогу агентам, командам CLI, потокам погодження та плагінам один раз описати
намір повідомлення, тоді як кожен плагін каналу рендерить найкращу нативну форму, яку може.

Використовуйте представлення для переносного інтерфейсу повідомлень:

- текстові секції
- невеликий контекстний текст/текст нижнього колонтитула
- роздільники
- кнопки
- меню вибору
- заголовок картки та тон

Не додавайте нові нативні для провайдера поля, як-от Discord `components`, Slack
`blocks`, Telegram `buttons`, Teams `card` або Feishu `card`, до спільного
інструмента повідомлень. Це результати рендерингу, якими володіє плагін каналу.

## Контракт

Автори плагінів імпортують публічний контракт із:

```ts
import type {
  MessagePresentation,
  ReplyPayloadDelivery,
} from "openclaw/plugin-sdk/interactive-runtime";
```

Форма:

```ts
type MessagePresentation = {
  title?: string;
  tone?: "neutral" | "info" | "success" | "warning" | "danger";
  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;
};

type ReplyPayloadDelivery = {
  pin?:
    | boolean
    | {
        enabled: boolean;
        notify?: boolean;
        required?: boolean;
      };
};
```

Семантика кнопок:

- `value` — це значення дії застосунку, яке повертається через
  наявний шлях взаємодії каналу, коли канал підтримує елементи керування, що можна натискати.
- `url` — це кнопка-посилання. Вона може існувати без `value`.
- `label` є обов’язковим і також використовується в текстовому резервному варіанті.
- `style` є рекомендаційним. Рендерери мають зіставляти непідтримувані стилі з безпечним
  значенням за замовчуванням, а не завершувати надсилання з помилкою.

Семантика меню вибору:

- `options[].value` — це вибране значення застосунку.
- `placeholder` є рекомендаційним і може ігноруватися каналами без нативної
  підтримки меню вибору.
- Якщо канал не підтримує меню вибору, резервний текст перелічує мітки.

## Приклади відправника

Проста картка:

```json
{
  "title": "Deploy approval",
  "tone": "warning",
  "blocks": [
    { "type": "text", "text": "Canary is ready to promote." },
    { "type": "context", "text": "Build 1234, staging passed." },
    {
      "type": "buttons",
      "buttons": [
        { "label": "Approve", "value": "deploy:approve", "style": "success" },
        { "label": "Decline", "value": "deploy:decline", "style": "danger" }
      ]
    }
  ]
}
```

Кнопка-посилання лише з URL:

```json
{
  "blocks": [
    { "type": "text", "text": "Release notes are ready." },
    {
      "type": "buttons",
      "buttons": [{ "label": "Open notes", "url": "https://example.com/release" }]
    }
  ]
}
```

Меню вибору:

```json
{
  "title": "Choose environment",
  "blocks": [
    {
      "type": "select",
      "placeholder": "Environment",
      "options": [
        { "label": "Canary", "value": "env:canary" },
        { "label": "Production", "value": "env:prod" }
      ]
    }
  ]
}
```

Надсилання через CLI:

```bash
openclaw message send --channel slack \
  --target channel:C123 \
  --message "Deploy approval" \
  --presentation '{"title":"Deploy approval","tone":"warning","blocks":[{"type":"text","text":"Canary is ready."},{"type":"buttons","buttons":[{"label":"Approve","value":"deploy:approve","style":"success"},{"label":"Decline","value":"deploy:decline","style":"danger"}]}]}'
```

Закріплена доставка:

```bash
openclaw message send --channel telegram \
  --target -1001234567890 \
  --message "Topic opened" \
  --pin
```

Закріплена доставка з явним JSON:

```json
{
  "pin": {
    "enabled": true,
    "notify": true,
    "required": false
  }
}
```

## Контракт рендерера

Плагіни каналів оголошують підтримку рендерингу у своєму outbound-адаптері:

```ts
const adapter: ChannelOutboundAdapter = {
  deliveryMode: "direct",
  presentationCapabilities: {
    supported: true,
    buttons: true,
    selects: true,
    context: true,
    divider: true,
  },
  deliveryCapabilities: {
    pin: true,
  },
  renderPresentation({ payload, presentation, ctx }) {
    return renderNativePayload(payload, presentation, ctx);
  },
  async pinDeliveredMessage({ target, messageId, pin }) {
    await pinNativeMessage(target, messageId, { notify: pin.notify === true });
  },
};
```

Поля можливостей навмисно зведені до простих булевих значень. Вони описують, які
інтерактивні елементи може відобразити рендерер, а не кожне нативне обмеження платформи. Рендерери все одно
володіють специфічними для платформи обмеженнями, як-от максимальна кількість кнопок, кількість блоків і
розмір картки.

## Основний потік рендерингу

Коли `ReplyPayload` або дія повідомлення містить `presentation`, ядро:

1. Нормалізує корисне навантаження представлення.
2. Визначає outbound-адаптер цільового каналу.
3. Зчитує `presentationCapabilities`.
4. Викликає `renderPresentation`, коли адаптер може відрендерити корисне навантаження.
5. Повертається до консервативного тексту, коли адаптер відсутній або не може виконати рендеринг.
6. Надсилає результативне корисне навантаження через звичайний шлях доставки каналу.
7. Застосовує метадані доставки, як-от `delivery.pin`, після першого успішно
   надісланого повідомлення.

Ядро володіє поведінкою резервного варіанта, щоб відправники могли залишатися незалежними від каналів. Плагіни
каналів володіють нативним рендерингом і обробкою взаємодії.

## Правила деградації

Представлення має бути безпечним для надсилання в обмежених каналах.

Резервний текст містить:

- `title` як перший рядок
- блоки `text` як звичайні абзаци
- блоки `context` як компактні контекстні рядки
- блоки `divider` як візуальний роздільник
- мітки кнопок, включно з URL для кнопок-посилань
- мітки варіантів меню вибору

Непідтримувані нативні елементи керування мають деградувати, а не спричиняти збій усього надсилання.
Приклади:

- Telegram із вимкненими вбудованими кнопками надсилає текстовий резервний варіант.
- Канал без підтримки меню вибору перелічує варіанти вибору як текст.
- Кнопка лише з URL стає або нативною кнопкою-посиланням, або резервним рядком з URL.
- Необов’язкові помилки закріплення не спричиняють збою вже доставленого повідомлення.

Головний виняток — `delivery.pin.required: true`; якщо запитано закріплення як
обов’язкове і канал не може закріпити надіслане повідомлення, доставка повідомляє про помилку.

## Відображення на провайдерів

Поточні вбудовані рендерери:

| Канал           | Нативна ціль рендерингу             | Примітки                                                                                                                                          |
| --------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Discord         | Components and component containers | Зберігає застаріле `channelData.discord.components` для наявних відправників корисного навантаження, нативного для провайдера, але нові спільні надсилання мають використовувати `presentation`. |
| Slack           | Block Kit                           | Зберігає застаріле `channelData.slack.blocks` для наявних відправників корисного навантаження, нативного для провайдера, але нові спільні надсилання мають використовувати `presentation`.       |
| Telegram        | Текст і вбудовані клавіатури        | Кнопки/меню вибору потребують можливості вбудованих кнопок для цільової поверхні; інакше використовується текстовий резервний варіант.          |
| Mattermost      | Текст та інтерактивні props         | Інші блоки деградують до тексту.                                                                                                                  |
| Microsoft Teams | Adaptive Cards                      | Звичайний текст `message` включається разом із карткою, якщо надано обидва.                                                                      |
| Feishu          | Інтерактивні картки                 | Заголовок картки може використовувати `title`; тіло уникає дублювання цього заголовка.                                                           |
| Plain channels  | Текстовий резервний варіант         | Канали без рендерера все одно отримують читабельний вивід.                                                                                        |

Сумісність із корисним навантаженням, нативним для провайдера, є перехідною можливістю для наявних
відправників відповідей. Це не причина додавати нові спільні нативні поля.

## Представлення проти InteractiveReply

`InteractiveReply` — це старіша внутрішня підмножина, що використовується допоміжними
засобами погодження та взаємодії. Вона підтримує:

- текст
- кнопки
- меню вибору

`MessagePresentation` — це канонічний спільний контракт надсилання. Він додає:

- заголовок
- тон
- контекст
- роздільник
- кнопки лише з URL
- загальні метадані доставки через `ReplyPayload.delivery`

Використовуйте допоміжні функції з `openclaw/plugin-sdk/interactive-runtime` під час адаптації старішого
коду:

```ts
import {
  interactiveReplyToPresentation,
  normalizeMessagePresentation,
  presentationToInteractiveReply,
  renderMessagePresentationFallbackText,
} from "openclaw/plugin-sdk/interactive-runtime";
```

Новий код має безпосередньо приймати або створювати `MessagePresentation`.

## Закріплення доставки

Закріплення — це поведінка доставки, а не представлення. Використовуйте `delivery.pin` замість
нативних для провайдера полів, як-от `channelData.telegram.pin`.

Семантика:

- `pin: true` закріплює перше успішно доставлене повідомлення.
- `pin.notify` за замовчуванням дорівнює `false`.
- `pin.required` за замовчуванням дорівнює `false`.
- Необов’язкові помилки закріплення деградують і залишають надіслане повідомлення без змін.
- Обов’язкові помилки закріплення призводять до збою доставки.
- Для фрагментованих повідомлень закріплюється перший доставлений фрагмент, а не кінцевий.

Ручні дії повідомлень `pin`, `unpin` і `pins` усе ще існують для наявних
повідомлень, де провайдер підтримує ці операції.

## Контрольний список автора плагіна

- Оголосіть `presentation` у `describeMessageTool(...)`, коли канал може
  рендерити або безпечно деградувати семантичне представлення.
- Додайте `presentationCapabilities` до runtime outbound-адаптера.
- Реалізуйте `renderPresentation` у runtime-коді, а не в коді налаштування плагіна
  площини керування.
- Не допускайте нативних UI-бібліотек у гарячі шляхи налаштування/каталогу.
- Зберігайте обмеження платформи в рендерері та тестах.
- Додайте резервні тести для непідтримуваних кнопок, меню вибору, кнопок з URL, дублювання заголовка/тексту
  та змішаних надсилань `message` плюс `presentation`.
- Додайте підтримку закріплення доставки через `deliveryCapabilities.pin` і
  `pinDeliveredMessage` лише тоді, коли провайдер може закріпити id надісланого повідомлення.
- Не відкривайте нові нативні для провайдера поля карток/блоків/компонентів/кнопок через
  спільну схему дій повідомлення.

## Пов’язана документація

- [CLI повідомлень](/uk/cli/message)
- [Огляд Plugin SDK](/uk/plugins/sdk-overview)
- [Архітектура плагінів](/uk/plugins/architecture-internals#message-tool-schemas)
- [План рефакторингу представлення каналів](/uk/plan/ui-channels)
