diff --git a/docs/uk/channels/msteams.md b/docs/uk/channels/msteams.md
index 88762e6af..13ddbaaf9 100644
--- a/docs/uk/channels/msteams.md
+++ b/docs/uk/channels/msteams.md
@@ -1,34 +1,30 @@
---
read_when:
- Робота над функціями каналу Microsoft Teams
-summary: Статус підтримки, можливості та конфігурація бота Microsoft Teams
+summary: Стан підтримки, можливості та налаштування бота Microsoft Teams
title: Microsoft Teams
x-i18n:
- generated_at: "2026-04-29T07:51:49Z"
+ generated_at: "2026-04-30T00:42:15Z"
model: gpt-5.5
provider: openai
- source_hash: 535bd7f9713f221572a99ae3a7a39d7acdd5a1e41c2d79a43d4caf9c2ce2b159
+ source_hash: c2c8cd13a72941a18d609b1f7263d9b9ed3284873f9b1483975ca1356b543979
source_path: channels/msteams.md
workflow: 16
---
-Статус: підтримуються текст + вкладення в DM; надсилання файлів у канали/групи потребує `sharePointSiteId` + дозволів Graph (див. [Надсилання файлів у групових чатах](#sending-files-in-group-chats)). Опитування надсилаються через Adaptive Cards. Дії повідомлень надають явний `upload-file` для надсилання, де файл є основним.
+Стан: підтримуються текст і вкладення в DM; надсилання файлів у канал/групу потребує `sharePointSiteId` + дозволів Graph (див. [Надсилання файлів у групових чатах](#sending-files-in-group-chats)). Опитування надсилаються через Adaptive Cards. Дії з повідомленнями надають явний `upload-file` для надсилань, де файл є першим.
## Вбудований Plugin
-Microsoft Teams постачається як вбудований Plugin у поточних випусках OpenClaw, тому
-окреме встановлення у звичайній пакетній збірці не потрібне.
+Microsoft Teams постачається як вбудований Plugin у поточних випусках OpenClaw, тому в звичайній пакетованій збірці окреме встановлення не потрібне.
-Якщо ви використовуєте старішу збірку або власне встановлення, що виключає вбудований Teams,
-встановіть поточний npm-пакет, коли його буде опубліковано:
+Якщо ви використовуєте старішу збірку або власне встановлення, яке виключає вбудований Teams, встановіть поточний npm-пакет, коли його буде опубліковано:
```bash
openclaw plugins install @openclaw/msteams
```
-Якщо npm повідомляє, що пакет, яким володіє OpenClaw, застарілий, використовуйте поточну пакетну
-збірку OpenClaw або локальний шлях checkout, доки не буде
-опубліковано новіший npm-пакет.
+Якщо npm повідомляє, що пакет, який належить OpenClaw, застарілий, використовуйте поточну пакетовану збірку OpenClaw або шлях до локального checkout, доки не буде опубліковано новіший npm-пакет.
Локальний checkout (під час запуску з git-репозиторію):
@@ -36,7 +32,7 @@ openclaw plugins install @openclaw/msteams
openclaw plugins install ./path/to/local/msteams-plugin
```
-Докладніше: [Plugins](/uk/tools/plugin)
+Докладно: [Plugins](/uk/tools/plugin)
## Швидке налаштування
@@ -51,12 +47,12 @@ teams status # verify you're logged in and see your tenant info
```
-Teams CLI зараз перебуває в preview. Команди та прапорці можуть змінюватися між випусками.
+Teams CLI наразі перебуває в preview. Команди й прапорці можуть змінюватися між випусками.
-**2. Запустіть тунель** (Teams не може дістатися до localhost)
+**2. Запустіть тунель** (Teams не може дістатися localhost)
-Встановіть і автентифікуйте devtunnel CLI, якщо ще цього не зробили ([посібник із початку роботи](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started)).
+Встановіть і автентифікуйте devtunnel CLI, якщо ви ще цього не зробили ([посібник із початку роботи](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started)).
```bash
# One-time setup (persistent URL across sessions):
@@ -69,10 +65,10 @@ devtunnel host my-openclaw-bot
```
-`--allow-anonymous` потрібен, бо Teams не може автентифікуватися з devtunnels. Кожен вхідний запит бота все одно автоматично перевіряється Teams SDK.
+`--allow-anonymous` потрібен, оскільки Teams не може автентифікуватися з devtunnels. Кожен вхідний запит бота все одно автоматично перевіряється Teams SDK.
-Альтернативи: `ngrok http 3978` або `tailscale funnel 3978` (але вони можуть змінювати URL у кожній сесії).
+Альтернативи: `ngrok http 3978` або `tailscale funnel 3978` (але вони можуть змінювати URL кожної сесії).
**3. Створіть застосунок**
@@ -85,9 +81,9 @@ teams app create \
Ця одна команда:
- Створює застосунок Entra ID (Azure AD)
-- Генерує клієнтський секрет
-- Збирає та завантажує маніфест застосунку Teams (з іконками)
-- Реєструє бота (типово керований Teams — передплата Azure не потрібна)
+- Генерує client secret
+- Збирає й завантажує маніфест застосунку Teams (з іконками)
+- Реєструє бота (типово керується Teams — підписка Azure не потрібна)
Вивід покаже `CLIENT_ID`, `CLIENT_SECRET`, `TENANT_ID` і **Teams App ID** — занотуйте їх для наступних кроків. Він також запропонує встановити застосунок безпосередньо в Teams.
@@ -111,7 +107,7 @@ teams app create \
**5. Встановіть застосунок у Teams**
-`teams app create` запропонує встановити застосунок — виберіть "Встановити в Teams". Якщо ви пропустили це, посилання можна отримати пізніше:
+`teams app create` запропонує встановити застосунок — виберіть "Install in Teams". Якщо ви пропустили це, можете отримати посилання пізніше:
```bash
teams app get --install-link
@@ -123,23 +119,23 @@ teams app get --install-link
teams app doctor
```
-Це запускає діагностику реєстрації бота, конфігурації застосунку AAD, чинності маніфесту та налаштування SSO.
+Це запускає діагностику реєстрації бота, конфігурації застосунку AAD, чинності маніфесту й налаштування SSO.
-Для production-розгортань розгляньте використання [федеративної автентифікації](/uk/channels/msteams#federated-authentication-certificate-plus-managed-identity) (сертифікат або керована ідентичність) замість клієнтських секретів.
+Для production-розгортань розгляньте використання [федеративної автентифікації](/uk/channels/msteams#federated-authentication-certificate-plus-managed-identity) (сертифікат або managed identity) замість client secrets.
-Групові чати типово заблоковані (`channels.msteams.groupPolicy: "allowlist"`). Щоб дозволити відповіді в групах, задайте `channels.msteams.groupAllowFrom` або використайте `groupPolicy: "open"`, щоб дозволити будь-якому учаснику (з вимогою згадки).
+Групові чати типово заблоковані (`channels.msteams.groupPolicy: "allowlist"`). Щоб дозволити відповіді в групах, задайте `channels.msteams.groupAllowFrom` або використайте `groupPolicy: "open"`, щоб дозволити будь-якого учасника (з обмеженням за згадкою).
## Цілі
- Спілкуватися з OpenClaw через DM, групові чати або канали Teams.
-- Зберігати детерміновану маршрутизацію: відповіді завжди повертаються до каналу, з якого вони надійшли.
+- Зберігати детермінізм маршрутизації: відповіді завжди повертаються в канал, з якого надійшли.
- Типово використовувати безпечну поведінку каналів (згадки обов’язкові, якщо не налаштовано інакше).
## Записи конфігурації
-Типово Microsoft Teams дозволено записувати оновлення конфігурації, спричинені `/config set|unset` (потребує `commands.config: true`).
+Типово Microsoft Teams дозволено записувати оновлення конфігурації, ініційовані `/config set|unset` (потребує `commands.config: true`).
Вимкніть за допомогою:
@@ -153,16 +149,16 @@ teams app doctor
**Доступ до DM**
-- Типово: `channels.msteams.dmPolicy = "pairing"`. Невідомі відправники ігноруються, доки їх не схвалять.
-- `channels.msteams.allowFrom` має використовувати стабільні object ID AAD.
-- Не покладайтеся на зіставлення UPN/відображуваного імені для allowlist — вони можуть змінюватися. OpenClaw типово вимикає пряме зіставлення імен; увімкніть його явно через `channels.msteams.dangerouslyAllowNameMatching: true`.
-- Майстер може зіставляти імена з ID через Microsoft Graph, коли облікові дані це дозволяють.
+- Типово: `channels.msteams.dmPolicy = "pairing"`. Невідомі відправники ігноруються, доки їх не схвалено.
+- `channels.msteams.allowFrom` має використовувати стабільні object IDs AAD.
+- Не покладайтеся на зіставлення UPN/display-name для allowlists — вони можуть змінюватися. OpenClaw типово вимикає пряме зіставлення імен; увімкніть його явно через `channels.msteams.dangerouslyAllowNameMatching: true`.
+- Майстер може зіставляти імена з IDs через Microsoft Graph, коли облікові дані це дозволяють.
-**Доступ до груп**
+**Доступ груп**
-- Типово: `channels.msteams.groupPolicy = "allowlist"` (заблоковано, якщо ви не додасте `groupAllowFrom`). Використайте `channels.defaults.groupPolicy`, щоб перевизначити типове значення, коли воно не задане.
-- `channels.msteams.groupAllowFrom` контролює, які відправники можуть запускати обробку в групових чатах/каналах (із fallback до `channels.msteams.allowFrom`).
-- Задайте `groupPolicy: "open"`, щоб дозволити будь-якому учаснику (типово все одно з вимогою згадки).
+- Типово: `channels.msteams.groupPolicy = "allowlist"` (заблоковано, якщо ви не додасте `groupAllowFrom`). Використовуйте `channels.defaults.groupPolicy`, щоб перевизначити типове значення, коли воно не задане.
+- `channels.msteams.groupAllowFrom` керує тим, які відправники можуть запускати дії в групових чатах/каналах (із fallback до `channels.msteams.allowFrom`).
+- Задайте `groupPolicy: "open"`, щоб дозволити будь-якого учасника (типово все одно з обмеженням за згадкою).
- Щоб не дозволяти **жодних каналів**, задайте `channels.msteams.groupPolicy: "disabled"`.
Приклад:
@@ -180,12 +176,12 @@ teams app doctor
**Teams + allowlist каналів**
-- Обмежуйте відповіді в групах/каналах, перелічуючи команди та канали в `channels.msteams.teams`.
-- Ключі мають використовувати стабільні ID команд і conversation ID каналів.
-- Коли `groupPolicy="allowlist"` і наявний allowlist Teams, приймаються лише перелічені команди/канали (з вимогою згадки).
+- Обмежуйте відповіді в групах/каналах, перелічуючи команди й канали в `channels.msteams.teams`.
+- Ключі мають використовувати стабільні Teams conversation IDs із посилань Teams, а не змінні відображувані назви.
+- Коли `groupPolicy="allowlist"` і наявний allowlist команд, приймаються лише перелічені команди/канали (з обмеженням за згадкою).
- Майстер налаштування приймає записи `Team/Channel` і зберігає їх для вас.
-- Під час запуску OpenClaw зіставляє імена команд/каналів та імена allowlist користувачів з ID (коли дозволи Graph це дозволяють)
- і записує зіставлення в журнал; нерозв’язані імена команд/каналів зберігаються як введені, але типово ігноруються для маршрутизації, якщо не ввімкнено `channels.msteams.dangerouslyAllowNameMatching: true`.
+- Під час запуску OpenClaw зіставляє назви team/channel і user allowlist з IDs (коли дозволи Graph це дозволяють)
+ і логує мапінг; нерозв’язані назви team/channel зберігаються так, як введені, але типово ігноруються для маршрутизації, якщо не ввімкнено `channels.msteams.dangerouslyAllowNameMatching: true`.
Приклад:
@@ -209,7 +205,7 @@ teams app doctor
Ручне налаштування (без Teams CLI)
-Якщо ви не можете використовувати Teams CLI, ви можете налаштувати бота вручну через Azure Portal.
+Якщо ви не можете використовувати Teams CLI, можете налаштувати бота вручну через Azure Portal.
### Як це працює
@@ -217,25 +213,25 @@ teams app doctor
2. Створіть **Azure Bot** (App ID + secret + tenant ID).
3. Зберіть **пакет застосунку Teams**, який посилається на бота й містить дозволи RSC нижче.
4. Завантажте/встановіть застосунок Teams у команду (або personal scope для DM).
-5. Налаштуйте `msteams` у `~/.openclaw/openclaw.json` (або змінних середовища) і запустіть Gateway.
-6. Gateway типово слухає трафік Webhook Bot Framework на `/api/messages`.
+5. Налаштуйте `msteams` у `~/.openclaw/openclaw.json` (або env vars) і запустіть Gateway.
+6. Gateway типово слухає трафік Bot Framework Webhook на `/api/messages`.
### Крок 1: Створіть Azure Bot
-1. Перейдіть до [Створити Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot)
-2. Заповніть вкладку **Основи**:
+1. Перейдіть до [Create Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot)
+2. Заповніть вкладку **Basics**:
| Поле | Значення |
| ------------------ | -------------------------------------------------------- |
- | **Дескриптор бота** | Ім’я вашого бота, напр., `openclaw-msteams` (має бути унікальним) |
- | **Передплата** | Виберіть вашу передплату Azure |
- | **Група ресурсів** | Створіть нову або використайте наявну |
- | **Ціновий рівень** | **Free** для розробки/тестування |
- | **Тип застосунку** | **Single Tenant** (рекомендовано - див. примітку нижче) |
- | **Тип створення** | **Create new Microsoft App ID** |
+ | **Bot handle** | Назва вашого бота, напр., `openclaw-msteams` (має бути унікальною) |
+ | **Subscription** | Виберіть вашу підписку Azure |
+ | **Resource group** | Створіть нову або використайте наявну |
+ | **Pricing tier** | **Free** для розробки/тестування |
+ | **Type of App** | **Single Tenant** (рекомендовано - див. примітку нижче) |
+ | **Creation type** | **Create new Microsoft App ID** |
-Створення нових мультитенантних ботів застаріло після 2025-07-31. Використовуйте **Single Tenant** для нових ботів.
+Створення нових multi-tenant ботів було застарілим після 2025-07-31. Використовуйте **Single Tenant** для нових ботів.
3. Натисніть **Review + create** → **Create** (зачекайте ~1-2 хвилини)
@@ -253,7 +249,7 @@ teams app doctor
1. В Azure Bot → **Configuration**
2. Задайте **Messaging endpoint** як URL вашого Webhook:
- Production: `https://your-domain.com/api/messages`
- - Локальна розробка: використайте тунель (див. [Локальна розробка](#local-development-tunneling) нижче)
+ - Локальна розробка: використовуйте тунель (див. [Локальна розробка](#local-development-tunneling) нижче)
### Крок 4: Увімкніть канал Teams
@@ -263,12 +259,12 @@ teams app doctor
### Крок 5: Зберіть маніфест застосунку Teams
-- Додайте запис `bot` з `botId = `.
+- Додайте запис `bot` із `botId = `.
- Scopes: `personal`, `team`, `groupChat`.
- `supportsFiles: true` (потрібно для обробки файлів у personal scope).
- Додайте дозволи RSC (див. [Дозволи RSC](#current-teams-rsc-permissions-manifest)).
- Створіть іконки: `outline.png` (32x32) і `color.png` (192x192).
-- Заархівуйте всі три файли разом: `manifest.json`, `outline.png`, `color.png`.
+- Запакуйте всі три файли разом у zip: `manifest.json`, `outline.png`, `color.png`.
### Крок 6: Налаштуйте OpenClaw
@@ -294,19 +290,19 @@ teams app doctor
-## Федеративна автентифікація (сертифікат плюс керована ідентичність)
+## Федеративна автентифікація (сертифікат плюс managed identity)
> Додано у 2026.4.11
-Для production-розгортань OpenClaw підтримує **федеративну автентифікацію** як безпечнішу альтернативу клієнтським секретам. Доступні два методи:
+Для production-розгортань OpenClaw підтримує **федеративну автентифікацію** як безпечнішу альтернативу client secrets. Доступні два методи:
### Варіант A: Автентифікація на основі сертифіката
-Використайте PEM-сертифікат, зареєстрований у вашій реєстрації застосунку Entra ID.
+Використовуйте PEM-сертифікат, зареєстрований у вашій реєстрації застосунку Entra ID.
**Налаштування:**
-1. Згенеруйте або отримайте сертифікат (PEM-формат із приватним ключем).
+1. Згенеруйте або отримайте сертифікат (формат PEM із приватним ключем).
2. В Entra ID → App Registration → **Certificates & secrets** → **Certificates** → завантажте публічний сертифікат.
**Конфігурація:**
@@ -326,26 +322,26 @@ teams app doctor
}
```
-**Змінні середовища:**
+**Env vars:**
- `MSTEAMS_AUTH_TYPE=federated`
- `MSTEAMS_CERTIFICATE_PATH=/path/to/cert.pem`
### Варіант B: Azure Managed Identity
-Використовуйте Azure Managed Identity для автентифікації без пароля. Це ідеально для розгортань в інфраструктурі Azure (AKS, App Service, Azure VMs), де доступна керована ідентичність.
+Використовуйте Azure Managed Identity для автентифікації без пароля. Це ідеально для розгортань в інфраструктурі Azure (AKS, App Service, Azure VMs), де доступна managed identity.
**Як це працює:**
-1. Pod/VM бота має керовану ідентичність (system-assigned або user-assigned).
-2. **Федеративні облікові дані ідентичності** зв’язують керовану ідентичність із реєстрацією застосунку Entra ID.
-3. Під час виконання OpenClaw використовує `@azure/identity`, щоб отримувати токени з endpoint Azure IMDS (`169.254.169.254`).
-4. Токен передається до Teams SDK для автентифікації бота.
+1. Pod/VM бота має managed identity (system-assigned або user-assigned).
+2. **Federated identity credential** пов’язує managed identity із реєстрацією застосунку Entra ID.
+3. Під час виконання OpenClaw використовує `@azure/identity`, щоб отримувати токени з Azure IMDS endpoint (`169.254.169.254`).
+4. Токен передається в Teams SDK для автентифікації бота.
**Передумови:**
-- Інфраструктура Azure з увімкненою керованою ідентичністю (AKS workload identity, App Service, VM)
-- Федеративні облікові дані ідентичності, створені в реєстрації застосунку Entra ID
+- Інфраструктура Azure з увімкненою managed identity (AKS workload identity, App Service, VM)
+- Federated identity credential, створений у реєстрації застосунку Entra ID
- Мережевий доступ до IMDS (`169.254.169.254:80`) з pod/VM
**Конфігурація (system-assigned managed identity):**
@@ -365,7 +361,7 @@ teams app doctor
}
```
-**Конфігурація (керована ідентичність, призначена користувачем):**
+**Конфігурація (призначена користувачем керована ідентичність):**
```json5
{
@@ -389,12 +385,12 @@ teams app doctor
- `MSTEAMS_USE_MANAGED_IDENTITY=true`
- `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID=` (лише для призначеної користувачем)
-### Налаштування AKS Workload Identity
+### Налаштування ідентичності робочого навантаження AKS
Для розгортань AKS, що використовують ідентичність робочого навантаження:
1. **Увімкніть ідентичність робочого навантаження** у вашому кластері AKS.
-2. **Створіть облікові дані федеративної ідентичності** для реєстрації застосунку Entra ID:
+2. **Створіть облікові дані федеративної ідентичності** у реєстрації застосунку Entra ID:
```bash
az ad app federated-credential create --id --parameters '{
@@ -405,7 +401,7 @@ teams app doctor
}'
```
-3. **Додайте анотацію до сервісного облікового запису Kubernetes** з клієнтським ID застосунку:
+3. **Додайте анотацію до сервісного облікового запису Kubernetes** з ID клієнта застосунку:
```yaml
apiVersion: v1
@@ -416,7 +412,7 @@ teams app doctor
azure.workload.identity/client-id: ""
```
-4. **Додайте мітку до pod** для ін’єкції ідентичності робочого навантаження:
+4. **Додайте мітку до пода** для інʼєкції ідентичності робочого навантаження:
```yaml
metadata:
@@ -424,17 +420,17 @@ teams app doctor
azure.workload.identity/use: "true"
```
-5. **Забезпечте мережевий доступ** до IMDS (`169.254.169.254`) — якщо використовуєте NetworkPolicy, додайте правило вихідного трафіку, що дозволяє трафік до `169.254.169.254/32` на порту 80.
+5. **Забезпечте мережевий доступ** до IMDS (`169.254.169.254`) — якщо використовується NetworkPolicy, додайте правило вихідного трафіку, яке дозволяє трафік до `169.254.169.254/32` на порті 80.
### Порівняння типів автентифікації
-| Метод | Конфігурація | Переваги | Недоліки |
-| ---------------------- | --------------------------------------------- | ------------------------------------- | ----------------------------------------------- |
-| **Клієнтський секрет** | `appPassword` | Просте налаштування | Потрібна ротація секрету, менш безпечно |
-| **Сертифікат** | `authType: "federated"` + `certificatePath` | Немає спільного секрету через мережу | Додаткове керування сертифікатами |
-| **Керована ідентичність** | `authType: "federated"` + `useManagedIdentity` | Без паролів, не потрібно керувати секретами | Потрібна інфраструктура Azure |
+| Метод | Конфігурація | Переваги | Недоліки |
+| ------------------------ | --------------------------------------------- | ------------------------------------- | --------------------------------------------- |
+| **Секрет клієнта** | `appPassword` | Просте налаштування | Потрібна ротація секрету, менш безпечно |
+| **Сертифікат** | `authType: "federated"` + `certificatePath` | Немає спільного секрету через мережу | Додаткове керування сертифікатами |
+| **Керована ідентичність** | `authType: "federated"` + `useManagedIdentity` | Без пароля, не потрібно керувати секретами | Потрібна інфраструктура Azure |
-**Поведінка за замовчуванням:** Якщо `authType` не задано, OpenClaw за замовчуванням використовує автентифікацію через клієнтський секрет. Наявні конфігурації продовжують працювати без змін.
+**Поведінка за замовчуванням:** Коли `authType` не задано, OpenClaw за замовчуванням використовує автентифікацію через секрет клієнта. Наявні конфігурації продовжують працювати без змін.
## Локальна розробка (тунелювання)
@@ -451,7 +447,7 @@ devtunnel host my-openclaw-bot
Альтернативи: `ngrok http 3978` або `tailscale funnel 3978` (URL-адреси можуть змінюватися в кожному сеансі).
-Якщо URL-адреса вашого тунелю змінилася, оновіть endpoint:
+Якщо URL-адреса вашого тунелю зміниться, оновіть кінцеву точку:
```bash
teams app update --endpoint "https:///api/messages"
@@ -470,49 +466,49 @@ teams app doctor
**Надішліть тестове повідомлення:**
1. Установіть застосунок Teams (скористайтеся посиланням для встановлення з `teams app get --install-link`)
-2. Знайдіть бота в Teams і надішліть приватне повідомлення
+2. Знайдіть бота в Teams і надішліть йому DM
3. Перевірте журнали Gateway на наявність вхідної активності
## Змінні середовища
-Усі ключі конфігурації можна натомість задати через змінні середовища:
+Усі ключі конфігурації натомість можна задавати через змінні середовища:
- `MSTEAMS_APP_ID`
- `MSTEAMS_APP_PASSWORD`
- `MSTEAMS_TENANT_ID`
-- `MSTEAMS_AUTH_TYPE` (необов’язково: `"secret"` або `"federated"`)
-- `MSTEAMS_CERTIFICATE_PATH` (федеративна + сертифікат)
-- `MSTEAMS_CERTIFICATE_THUMBPRINT` (необов’язково, не потрібне для автентифікації)
-- `MSTEAMS_USE_MANAGED_IDENTITY` (федеративна + керована ідентичність)
-- `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID` (лише MI, призначена користувачем)
+- `MSTEAMS_AUTH_TYPE` (необовʼязково: `"secret"` або `"federated"`)
+- `MSTEAMS_CERTIFICATE_PATH` (федеративна автентифікація + сертифікат)
+- `MSTEAMS_CERTIFICATE_THUMBPRINT` (необовʼязково, не потрібно для автентифікації)
+- `MSTEAMS_USE_MANAGED_IDENTITY` (федеративна автентифікація + керована ідентичність)
+- `MSTEAMS_MANAGED_IDENTITY_CLIENT_ID` (лише призначена користувачем керована ідентичність)
## Дія з інформацією про учасника
-OpenClaw надає дію `member-info` на основі Graph для Microsoft Teams, щоб агенти й автоматизації могли отримувати відомості про учасників каналу (відображуване ім’я, електронну пошту, роль) безпосередньо з Microsoft Graph.
+OpenClaw надає дію `member-info` на основі Graph для Microsoft Teams, щоб агенти й автоматизації могли отримувати відомості про учасників каналу (відображуване імʼя, електронна пошта, роль) безпосередньо з Microsoft Graph.
Вимоги:
- Дозвіл RSC `Member.Read.Group` (уже є в рекомендованому маніфесті)
-- Для пошуків між командами: дозвіл Graph Application `User.Read.All` зі згодою адміністратора
+- Для пошуку між командами: дозвіл Graph Application `User.Read.All` зі згодою адміністратора
-Дію обмежує `channels.msteams.actions.memberInfo` (за замовчуванням: увімкнено, коли доступні облікові дані Graph).
+Дія керується параметром `channels.msteams.actions.memberInfo` (за замовчуванням: увімкнено, коли доступні облікові дані Graph).
## Контекст історії
-- `channels.msteams.historyLimit` керує тим, скільки останніх повідомлень каналу/групи загортаються в prompt.
-- Якщо не задано, використовується `messages.groupChat.historyLimit`. Установіть `0`, щоб вимкнути (за замовчуванням 50).
-- Отримана історія thread фільтрується за списками дозволених відправників (`allowFrom` / `groupAllowFrom`), тому ініціалізація контексту thread включає лише повідомлення від дозволених відправників.
-- Контекст цитованих вкладень (`ReplyTo*`, отриманий із HTML-відповіді Teams) наразі передається як отримано.
-- Іншими словами, списки дозволених відправників визначають, хто може запускати агента; сьогодні фільтруються лише окремі додаткові шляхи контексту.
-- Історію приватних повідомлень можна обмежити за допомогою `channels.msteams.dmHistoryLimit` (ходи користувача). Перевизначення для окремих користувачів: `channels.msteams.dms[""].historyLimit`.
+- `channels.msteams.historyLimit` керує тим, скільки останніх повідомлень каналу/групи загортається в запит.
+- Має резервне значення `messages.groupChat.historyLimit`. Установіть `0`, щоб вимкнути (за замовчуванням 50).
+- Отримана історія треду фільтрується за списками дозволених відправників (`allowFrom` / `groupAllowFrom`), тому початкове наповнення контексту треду містить лише повідомлення від дозволених відправників.
+- Контекст цитованих вкладень (отриманий із HTML-відповіді Teams `ReplyTo*`) наразі передається як отримано.
+- Іншими словами, списки дозволених визначають, хто може запускати агента; сьогодні фільтруються лише окремі шляхи додаткового контексту.
+- Історію DM можна обмежити за допомогою `channels.msteams.dmHistoryLimit` (ходи користувача). Перевизначення для окремих користувачів: `channels.msteams.dms[""].historyLimit`.
-## Поточні дозволи Teams RSC (маніфест)
+## Поточні дозволи RSC Teams (маніфест)
-Це **наявні resourceSpecific дозволи** у нашому маніфесті застосунку Teams. Вони застосовуються лише всередині команди/чату, де встановлено застосунок.
+Це **наявні ресурсно-специфічні дозволи** в маніфесті нашого застосунку Teams. Вони застосовуються лише всередині команди/чату, де встановлено застосунок.
**Для каналів (область команди):**
-- `ChannelMessage.Read.Group` (Application) - отримувати всі повідомлення каналу без @mention
+- `ChannelMessage.Read.Group` (Application) - отримувати всі повідомлення каналу без @згадки
- `ChannelMessage.Send.Group` (Application)
- `Member.Read.Group` (Application)
- `Owner.Read.Group` (Application)
@@ -522,7 +518,7 @@ OpenClaw надає дію `member-info` на основі Graph для Microsof
**Для групових чатів:**
-- `ChatMessage.Read.Chat` (Application) - отримувати всі повідомлення групового чату без @mention
+- `ChatMessage.Read.Chat` (Application) - отримувати всі повідомлення групового чату без @згадки
Щоб додати дозволи RSC через Teams CLI:
@@ -532,7 +528,7 @@ teams app rsc add ChannelMessage.Read.Group --type Application
## Приклад маніфесту Teams (відредаговано)
-Мінімальний дійсний приклад із потрібними полями. Замініть ID та URL-адреси.
+Мінімальний, чинний приклад із потрібними полями. Замініть ID та URL-адреси.
```json5
{
@@ -580,17 +576,17 @@ teams app rsc add ChannelMessage.Read.Group --type Application
}
```
-### Застереження щодо маніфесту (обов’язкові поля)
+### Застереження щодо маніфесту (обовʼязкові поля)
- `bots[].botId` **має** збігатися з Azure Bot App ID.
- `webApplicationInfo.id` **має** збігатися з Azure Bot App ID.
- `bots[].scopes` має включати поверхні, які ви плануєте використовувати (`personal`, `team`, `groupChat`).
-- `bots[].supportsFiles: true` потрібне для обробки файлів в особистій області.
-- `authorization.permissions.resourceSpecific` має включати читання/надсилання каналів, якщо вам потрібен трафік каналів.
+- `bots[].supportsFiles: true` потрібен для обробки файлів в особистій області.
+- `authorization.permissions.resourceSpecific` має включати читання/надсилання для каналів, якщо вам потрібен трафік каналів.
### Оновлення наявного застосунку
-Щоб оновити вже встановлений застосунок Teams (наприклад, додати дозволи RSC):
+Щоб оновити вже встановлений застосунок Teams (наприклад, щоб додати дозволи RSC):
```bash
# Download, edit, and re-upload the manifest
@@ -603,11 +599,11 @@ teams app manifest upload manifest.json
Після оновлення перевстановіть застосунок у кожній команді, щоб нові дозволи набули чинності, і **повністю закрийте та перезапустіть Teams** (не просто закрийте вікно), щоб очистити кешовані метадані застосунку.
-Оновлення маніфесту вручну (без CLI)
+Ручне оновлення маніфесту (без CLI)
1. Оновіть ваш `manifest.json` новими налаштуваннями
2. **Збільште поле `version`** (наприклад, `1.0.0` → `1.1.0`)
-3. **Повторно запакуйте в zip** маніфест з іконками (`manifest.json`, `outline.png`, `color.png`)
+3. **Заново запакуйте в zip** маніфест з іконками (`manifest.json`, `outline.png`, `color.png`)
4. Завантажте новий zip:
- **Teams Admin Center:** застосунки Teams → Керування застосунками → знайдіть ваш застосунок → Завантажити нову версію
- **Sideload:** у Teams → Застосунки → Керування вашими застосунками → Завантажити власний застосунок
@@ -622,57 +618,57 @@ teams app manifest upload manifest.json
- Читання **текстового** вмісту повідомлень каналу.
- Надсилання **текстового** вмісту повідомлень каналу.
-- Отримання файлових вкладень у **особистих (DM)** повідомленнях.
+- Отримання файлових вкладень **особистих (DM)** повідомлень.
Не працює:
-- **Вміст зображень або файлів** у каналах/групах (payload містить лише HTML-заглушку).
+- **Вміст зображень або файлів** у каналі/групі (корисне навантаження містить лише HTML-заглушку).
- Завантаження вкладень, збережених у SharePoint/OneDrive.
-- Читання історії повідомлень (поза live-подією Webhook).
+- Читання історії повідомлень (поза межами події live Webhook).
### З **Teams RSC + дозволами Microsoft Graph Application**
Додає:
-- Завантаження hosted contents (зображень, вставлених у повідомлення).
+- Завантаження розміщеного вмісту (зображень, вставлених у повідомлення).
- Завантаження файлових вкладень, збережених у SharePoint/OneDrive.
-- Читання історії повідомлень каналів/чатів через Graph.
+- Читання історії повідомлень каналу/чату через Graph.
### RSC проти Graph API
-| Можливість | Дозволи RSC | Graph API |
-| ----------------------- | -------------------- | -------------------------------------- |
-| **Повідомлення в реальному часі** | Так (через Webhook) | Ні (лише опитування) |
-| **Історичні повідомлення** | Ні | Так (можна запитувати історію) |
-| **Складність налаштування** | Лише маніфест застосунку | Потрібна згода адміністратора + token flow |
-| **Працює офлайн** | Ні (має бути запущено) | Так (запит у будь-який час) |
+| Можливість | Дозволи RSC | Graph API |
+| --------------------------- | ------------------- | ------------------------------------------ |
+| **Повідомлення в реальному часі** | Так (через Webhook) | Ні (лише опитування) |
+| **Історичні повідомлення** | Ні | Так (можна запитувати історію) |
+| **Складність налаштування** | Лише маніфест застосунку | Потрібна згода адміністратора + потік токенів |
+| **Працює офлайн** | Ні (має бути запущено) | Так (запит у будь-який час) |
-**Підсумок:** RSC призначений для прослуховування в реальному часі; Graph API — для доступу до історії. Щоб наздогнати пропущені повідомлення під час офлайну, потрібен Graph API з `ChannelMessage.Read.All` (потрібна згода адміністратора).
+**Підсумок:** RSC призначено для прослуховування в реальному часі; Graph API — для доступу до історії. Щоб наздоганяти пропущені повідомлення під час офлайну, потрібен Graph API з `ChannelMessage.Read.All` (потрібна згода адміністратора).
-## Медіа й історія з увімкненим Graph (потрібно для каналів)
+## Медіа та історія з увімкненим Graph (потрібно для каналів)
Якщо вам потрібні зображення/файли в **каналах** або ви хочете отримувати **історію повідомлень**, потрібно ввімкнути дозволи Microsoft Graph і надати згоду адміністратора.
-1. У **реєстрації застосунку** Entra ID (Azure AD) додайте **дозволи Application** Microsoft Graph:
- - `ChannelMessage.Read.All` (вкладення каналів + історія)
+1. В **реєстрації застосунку** Entra ID (Azure AD) додайте **дозволи Application** Microsoft Graph:
+ - `ChannelMessage.Read.All` (вкладення каналу + історія)
- `Chat.Read.All` або `ChatMessage.Read.All` (групові чати)
-2. **Надайте згоду адміністратора** для tenant.
-3. Збільште **версію маніфесту** застосунку Teams, повторно завантажте його та **перевстановіть застосунок у Teams**.
+2. **Надайте згоду адміністратора** для клієнта.
+3. Підвищте **версію маніфесту** застосунку Teams, повторно завантажте його та **перевстановіть застосунок у Teams**.
4. **Повністю закрийте та перезапустіть Teams**, щоб очистити кешовані метадані застосунку.
-**Додатковий дозвіл для згадок користувачів:** User @mentions працюють одразу для користувачів у розмові. Однак, якщо ви хочете динамічно шукати й згадувати користувачів, яких **немає в поточній розмові**, додайте дозвіл `User.Read.All` (Application) і надайте згоду адміністратора.
+**Додатковий дозвіл для згадок користувачів:** @згадки користувачів працюють одразу для користувачів у розмові. Однак, якщо ви хочете динамічно шукати й згадувати користувачів, яких **немає в поточній розмові**, додайте дозвіл `User.Read.All` (Application) і надайте згоду адміністратора.
## Відомі обмеження
### Тайм-аути Webhook
-Teams доставляє повідомлення через HTTP Webhook. Якщо обробка триває занадто довго (наприклад, повільні відповіді LLM), ви можете побачити:
+Teams доставляє повідомлення через HTTP Webhook. Якщо обробка триває надто довго (наприклад, повільні відповіді LLM), ви можете побачити:
- Тайм-аути Gateway
-- Teams повторно надсилає повідомлення (що спричиняє дублікати)
+- Повторні спроби Teams надіслати повідомлення (що спричиняє дублікати)
- Відкинуті відповіді
-OpenClaw обробляє це, швидко повертаючи відповідь і проактивно надсилаючи відповіді, але дуже повільні відповіді все одно можуть спричиняти проблеми.
+OpenClaw обробляє це, швидко повертаючи відповідь і проактивно надсилаючи повідомлення, але дуже повільні відповіді все одно можуть спричиняти проблеми.
### Форматування
@@ -680,28 +676,28 @@ Markdown у Teams обмеженіший, ніж у Slack або Discord:
- Базове форматування працює: **жирний**, _курсив_, `code`, посилання
- Складний markdown (таблиці, вкладені списки) може відображатися некоректно
-- Adaptive Cards підтримуються для опитувань і надсилання семантичних презентацій (див. нижче)
+- Adaptive Cards підтримуються для опитувань і семантичних presentation-відправлень (див. нижче)
## Конфігурація
-Ключові налаштування (спільні шаблони каналів див. у `/gateway/configuration`):
+Ключові налаштування (див. `/gateway/configuration` для спільних патернів каналів):
- `channels.msteams.enabled`: увімкнути/вимкнути канал.
- `channels.msteams.appId`, `channels.msteams.appPassword`, `channels.msteams.tenantId`: облікові дані бота.
-- `channels.msteams.webhook.port` (за замовчуванням `3978`)
-- `channels.msteams.webhook.path` (за замовчуванням `/api/messages`)
-- `channels.msteams.dmPolicy`: `pairing | allowlist | open | disabled` (за замовчуванням: pairing)
-- `channels.msteams.allowFrom`: allowlist для особистих повідомлень (рекомендовано AAD object IDs). Майстер під час налаштування зіставляє імена з ID, коли доступний Graph.
-- `channels.msteams.dangerouslyAllowNameMatching`: аварійний перемикач для повторного ввімкнення змінного зіставлення за UPN/відображуваним іменем і прямої маршрутизації за назвою команди/каналу.
+- `channels.msteams.webhook.port` (типово `3978`)
+- `channels.msteams.webhook.path` (типово `/api/messages`)
+- `channels.msteams.dmPolicy`: `pairing | allowlist | open | disabled` (типово: pairing)
+- `channels.msteams.allowFrom`: allowlist для DM (рекомендовано AAD object IDs). Майстер зіставляє імена з ID під час налаштування, коли доступний доступ до Graph.
+- `channels.msteams.dangerouslyAllowNameMatching`: аварійний перемикач для повторного ввімкнення зіставлення за змінними UPN/display-name і прямої маршрутизації за назвою команди/каналу.
- `channels.msteams.textChunkLimit`: розмір фрагмента вихідного тексту.
-- `channels.msteams.chunkMode`: `length` (за замовчуванням) або `newline`, щоб розділяти за порожніми рядками (межами абзаців) перед поділом за довжиною.
-- `channels.msteams.mediaAllowHosts`: allowlist для хостів вхідних вкладень (за замовчуванням домени Microsoft/Teams).
-- `channels.msteams.mediaAuthAllowHosts`: allowlist для додавання заголовків Authorization під час повторних спроб медіа (за замовчуванням хости Graph + Bot Framework).
-- `channels.msteams.requireMention`: вимагати @mention у каналах/групах (за замовчуванням true).
+- `channels.msteams.chunkMode`: `length` (типово) або `newline`, щоб ділити за порожніми рядками (межами абзаців) перед поділом за довжиною.
+- `channels.msteams.mediaAllowHosts`: allowlist для хостів вхідних вкладень (типово домени Microsoft/Teams).
+- `channels.msteams.mediaAuthAllowHosts`: allowlist для додавання заголовків Authorization під час повторних спроб роботи з медіа (типово хости Graph + Bot Framework).
+- `channels.msteams.requireMention`: вимагати @mention у каналах/групах (типово true).
- `channels.msteams.replyStyle`: `thread | top-level` (див. [Стиль відповіді](#reply-style-threads-vs-posts)).
- `channels.msteams.teams..replyStyle`: перевизначення для окремої команди.
- `channels.msteams.teams..requireMention`: перевизначення для окремої команди.
-- `channels.msteams.teams..tools`: стандартні перевизначення політики інструментів для окремої команди (`allow`/`deny`/`alsoAllow`), які використовуються, коли перевизначення каналу відсутнє.
+- `channels.msteams.teams..tools`: стандартні перевизначення політики інструментів для окремої команди (`allow`/`deny`/`alsoAllow`), що використовуються, коли немає перевизначення для каналу.
- `channels.msteams.teams..toolsBySender`: стандартні перевизначення політики інструментів для окремої команди й окремого відправника (підтримується wildcard `"*"`).
- `channels.msteams.teams..channels..replyStyle`: перевизначення для окремого каналу.
- `channels.msteams.teams..channels..requireMention`: перевизначення для окремого каналу.
@@ -709,35 +705,35 @@ Markdown у Teams обмеженіший, ніж у Slack або Discord:
- `channels.msteams.teams..channels..toolsBySender`: перевизначення політики інструментів для окремого каналу й окремого відправника (підтримується wildcard `"*"`).
- Ключі `toolsBySender` мають використовувати явні префікси:
`id:`, `e164:`, `username:`, `name:` (застарілі ключі без префікса все ще зіставляються лише з `id:`).
-- `channels.msteams.actions.memberInfo`: увімкнути або вимкнути дію інформації про учасника на основі Graph (за замовчуванням: увімкнено, коли доступні облікові дані Graph).
-- `channels.msteams.authType`: тип автентифікації — `"secret"` (за замовчуванням) або `"federated"`.
-- `channels.msteams.certificatePath`: шлях до файлу PEM-сертифіката (федеративна автентифікація + автентифікація за сертифікатом).
-- `channels.msteams.certificateThumbprint`: відбиток сертифіката (необов’язково, не потрібен для автентифікації).
-- `channels.msteams.useManagedIdentity`: увімкнути автентифікацію через керовану ідентичність (федеративний режим).
-- `channels.msteams.managedIdentityClientId`: client ID для user-assigned managed identity.
+- `channels.msteams.actions.memberInfo`: увімкнути або вимкнути дію отримання інформації про учасника на основі Graph (типово: увімкнено, коли доступні облікові дані Graph).
+- `channels.msteams.authType`: тип автентифікації — `"secret"` (типово) або `"federated"`.
+- `channels.msteams.certificatePath`: шлях до PEM-файлу сертифіката (федеративна автентифікація + автентифікація сертифікатом).
+- `channels.msteams.certificateThumbprint`: відбиток сертифіката (необов’язково, не потрібно для автентифікації).
+- `channels.msteams.useManagedIdentity`: увімкнути автентифікацію managed identity (федеративний режим).
+- `channels.msteams.managedIdentityClientId`: client ID для призначеної користувачем managed identity.
- `channels.msteams.sharePointSiteId`: SharePoint site ID для завантаження файлів у групових чатах/каналах (див. [Надсилання файлів у групових чатах](#sending-files-in-group-chats)).
-## Маршрутизація та сеанси
+## Маршрутизація та сесії
-- Ключі сеансів відповідають стандартному формату агента (див. [/concepts/session](/uk/concepts/session)):
- - Особисті повідомлення спільно використовують головний сеанс (`agent::`).
+- Ключі сесій відповідають стандартному формату агента (див. [/concepts/session](/uk/concepts/session)):
+ - Прямі повідомлення спільно використовують основну сесію (`agent::`).
- Повідомлення каналів/груп використовують conversation id:
- `agent::msteams:channel:`
- `agent::msteams:group:`
-## Стиль відповіді: гілки проти дописів
+## Стиль відповіді: треди проти дописів
-Teams нещодавно запровадив два стилі інтерфейсу каналів поверх тієї самої базової моделі даних:
+Teams нещодавно запровадив два стилі UI каналу поверх тієї самої базової моделі даних:
| Стиль | Опис | Рекомендований `replyStyle` |
| ------------------------ | --------------------------------------------------------- | ------------------------ |
-| **Posts** (класичний) | Повідомлення відображаються як картки з гілковими відповідями під ними | `thread` (за замовчуванням) |
+| **Posts** (класичний) | Повідомлення відображаються як картки з тредовими відповідями під ними | `thread` (типово) |
| **Threads** (як у Slack) | Повідомлення йдуть лінійно, більше схоже на Slack | `top-level` |
-**Проблема:** Teams API не показує, який стиль інтерфейсу використовує канал. Якщо використати неправильний `replyStyle`:
+**Проблема:** Teams API не показує, який стиль UI використовує канал. Якщо використати неправильний `replyStyle`:
-- `thread` у каналі зі стилем Threads → відповіді виглядають незручно вкладеними
-- `top-level` у каналі зі стилем Posts → відповіді відображаються як окремі дописи верхнього рівня, а не в гілці
+- `thread` у каналі стилю Threads → відповіді виглядають незручно вкладеними
+- `top-level` у каналі стилю Posts → відповіді відображаються як окремі дописи верхнього рівня, а не всередині треду
**Рішення:** Налаштуйте `replyStyle` для кожного каналу залежно від того, як налаштовано канал:
@@ -764,33 +760,33 @@ Teams нещодавно запровадив два стилі інтерфей
**Поточні обмеження:**
-- **Особисті повідомлення:** Зображення та файлові вкладення працюють через файлові API бота Teams.
-- **Канали/групи:** Вкладення зберігаються в сховищі M365 (SharePoint/OneDrive). Корисне навантаження Webhook містить лише HTML-заглушку, а не фактичні байти файлу. **Для завантаження вкладень каналів потрібні дозволи Graph API**.
-- Для явного надсилання, де файл є основним вмістом, використовуйте `action=upload-file` з `media` / `filePath` / `path`; необов’язковий `message` стає супровідним текстом/коментарем, а `filename` перевизначає назву завантаженого файлу.
+- **DM:** Зображення й файлові вкладення працюють через файлові API бота Teams.
+- **Канали/групи:** Вкладення зберігаються в сховищі M365 (SharePoint/OneDrive). Webhook payload містить лише HTML-заглушку, а не фактичні байти файлу. **Для завантаження вкладень каналів потрібні дозволи Graph API**.
+- Для явних надсилань, де файл є основним вмістом, використовуйте `action=upload-file` з `media` / `filePath` / `path`; необов’язковий `message` стає супровідним текстом/коментарем, а `filename` перевизначає назву завантаженого файлу.
-Без дозволів Graph повідомлення каналу із зображеннями будуть отримані лише як текст (вміст зображення недоступний боту).
-За замовчуванням OpenClaw завантажує медіа лише з імен хостів Microsoft/Teams. Перевизначте через `channels.msteams.mediaAllowHosts` (використовуйте `["*"]`, щоб дозволити будь-який хост).
-Заголовки Authorization додаються лише для хостів у `channels.msteams.mediaAuthAllowHosts` (за замовчуванням хости Graph + Bot Framework). Тримайте цей список суворим (уникайте суфіксів для кількох tenant).
+Без дозволів Graph повідомлення каналів із зображеннями надходитимуть лише як текст (вміст зображення недоступний боту).
+Типово OpenClaw завантажує медіа лише з імен хостів Microsoft/Teams. Перевизначте це за допомогою `channels.msteams.mediaAllowHosts` (використовуйте `["*"]`, щоб дозволити будь-який хост).
+Заголовки Authorization додаються лише для хостів у `channels.msteams.mediaAuthAllowHosts` (типово хости Graph + Bot Framework). Тримайте цей список суворим (уникайте багатотенантних суфіксів).
## Надсилання файлів у групових чатах
-Боти можуть надсилати файли в особистих повідомленнях за допомогою потоку FileConsentCard (вбудовано). Однак **надсилання файлів у групових чатах/каналах** потребує додаткового налаштування:
+Боти можуть надсилати файли в DM за допомогою потоку FileConsentCard (вбудовано). Однак **надсилання файлів у групових чатах/каналах** потребує додаткового налаштування:
| Контекст | Як надсилаються файли | Потрібне налаштування |
| ------------------------ | -------------------------------------------- | ----------------------------------------------- |
-| **Особисті повідомлення** | FileConsentCard → користувач приймає → бот завантажує | Працює одразу |
+| **DM** | FileConsentCard → користувач приймає → бот завантажує | Працює одразу |
| **Групові чати/канали** | Завантаження в SharePoint → поширення посилання | Потрібні `sharePointSiteId` + дозволи Graph |
-| **Зображення (будь-який контекст)** | Inline у кодуванні Base64 | Працює одразу |
+| **Зображення (будь-який контекст)** | Вбудовано з кодуванням Base64 | Працює одразу |
### Чому груповим чатам потрібен SharePoint
-Боти не мають персонального диска OneDrive (endpoint Graph API `/me/drive` не працює для application identities). Щоб надсилати файли в групових чатах/каналах, бот завантажує їх на **сайт SharePoint** і створює посилання для спільного доступу.
+Боти не мають особистого диска OneDrive (endpoint Graph API `/me/drive` не працює для ідентичностей застосунків). Щоб надсилати файли в групові чати/канали, бот завантажує їх на **сайт SharePoint** і створює посилання для поширення.
### Налаштування
1. **Додайте дозволи Graph API** в Entra ID (Azure AD) → App Registration:
- `Sites.ReadWrite.All` (Application) - завантаження файлів у SharePoint
- - `Chat.Read.All` (Application) - необов’язково, вмикає посилання для спільного доступу на рівні користувача
+ - `Chat.Read.All` (Application) - необов’язково, вмикає посилання для поширення для окремих користувачів
2. **Надайте згоду адміністратора** для tenant.
@@ -821,40 +817,40 @@ Teams нещодавно запровадив два стилі інтерфей
}
```
-### Поведінка спільного доступу
+### Поведінка поширення
-| Дозвіл | Поведінка спільного доступу |
+| Дозвіл | Поведінка поширення |
| --------------------------------------- | --------------------------------------------------------- |
-| Лише `Sites.ReadWrite.All` | Посилання для спільного доступу в межах організації (доступ має будь-хто в організації) |
-| `Sites.ReadWrite.All` + `Chat.Read.All` | Посилання для спільного доступу на рівні користувача (доступ мають лише учасники чату) |
+| лише `Sites.ReadWrite.All` | Посилання для поширення на всю організацію (доступ має будь-хто в організації) |
+| `Sites.ReadWrite.All` + `Chat.Read.All` | Посилання для поширення для окремих користувачів (доступ мають лише учасники чату) |
-Спільний доступ на рівні користувача безпечніший, оскільки лише учасники чату можуть отримати доступ до файлу. Якщо дозволу `Chat.Read.All` немає, бот повертається до спільного доступу в межах організації.
+Поширення для окремих користувачів безпечніше, оскільки доступ до файлу мають лише учасники чату. Якщо дозволу `Chat.Read.All` бракує, бот повертається до поширення на всю організацію.
### Резервна поведінка
| Сценарій | Результат |
| ------------------------------------------------- | -------------------------------------------------- |
-| Груповий чат + файл + налаштований `sharePointSiteId` | Завантаження в SharePoint, надсилання посилання для спільного доступу |
-| Груповий чат + файл + без `sharePointSiteId` | Спроба завантаження в OneDrive (може завершитися помилкою), надсилання лише тексту |
+| Груповий чат + файл + налаштовано `sharePointSiteId` | Завантаження в SharePoint, надсилання посилання для поширення |
+| Груповий чат + файл + немає `sharePointSiteId` | Спроба завантаження в OneDrive (може завершитися помилкою), надсилання лише тексту |
| Особистий чат + файл | Потік FileConsentCard (працює без SharePoint) |
-| Будь-який контекст + зображення | Inline у кодуванні Base64 (працює без SharePoint) |
+| Будь-який контекст + зображення | Вбудовано з кодуванням Base64 (працює без SharePoint) |
-### Місце зберігання файлів
+### Розташування збережених файлів
Завантажені файли зберігаються в папці `/OpenClawShared/` у стандартній бібліотеці документів налаштованого сайту SharePoint.
## Опитування (Adaptive Cards)
-OpenClaw надсилає опитування Teams як Adaptive Cards (нативного Teams poll API немає).
+OpenClaw надсилає опитування Teams як Adaptive Cards (нативного API опитувань Teams немає).
- CLI: `openclaw message poll --channel msteams --target conversation: ...`
- Голоси записуються Gateway у `~/.openclaw/msteams-polls.json`.
- Gateway має залишатися онлайн, щоб записувати голоси.
-- Опитування поки що не публікують підсумки результатів автоматично (за потреби перегляньте файл сховища).
+- Опитування поки що не публікують автоматично підсумки результатів (за потреби перегляньте файл сховища).
-## Картки презентацій
+## Presentation-картки
-Надсилайте семантичні презентаційні payload користувачам або розмовам Teams за допомогою інструмента `message` або CLI. OpenClaw відтворює їх як Teams Adaptive Cards із загального контракту презентацій.
+Надсилайте семантичні presentation payloads користувачам або conversations Teams за допомогою інструмента `message` або CLI. OpenClaw рендерить їх як Teams Adaptive Cards із загального presentation-контракту.
Параметр `presentation` приймає семантичні блоки. Коли надано `presentation`, текст повідомлення необов’язковий.
@@ -880,13 +876,13 @@ openclaw message send --channel msteams \
--presentation '{"title":"Hello","blocks":[{"type":"text","text":"Hello!"}]}'
```
-Докладніше про формат цілі див. у [Формати цілей](#target-formats) нижче.
+Докладніше про формат target див. у розділі [Формати target](#target-formats) нижче.
-## Формати цілей
+## Формати target
-Цілі MSTeams використовують префікси, щоб розрізняти користувачів і розмови:
+Targets MSTeams використовують префікси, щоб розрізняти користувачів і conversations:
-| Тип цілі | Формат | Приклад |
+| Тип target | Формат | Приклад |
| ------------------- | -------------------------------- | --------------------------------------------------- |
| Користувач (за ID) | `user:` | `user:40a1a0ed-4ff2-4164-a219-55518990c197` |
| Користувач (за іменем) | `user:` | `user:John Smith` (потрібен Graph API) |
@@ -934,24 +930,24 @@ openclaw message send --channel msteams --target "conversation:19:abc...@thread.
```
-Без префікса `user:` імена за замовчуванням розпізнаються як групи або команди. Завжди використовуйте `user:`, коли націлюєтеся на людей за відображуваним іменем.
+Без префікса `user:` імена за замовчуванням обробляються як групи або команди. Завжди використовуйте `user:`, коли вказуєте людей за відображуваним іменем.
-## Проактивний обмін повідомленнями
+## Проактивні повідомлення
- Проактивні повідомлення можливі лише **після** взаємодії користувача, оскільки в цей момент ми зберігаємо посилання на розмову.
-- Див. `/gateway/configuration` щодо `dmPolicy` і керування списком дозволених.
+- Див. `/gateway/configuration` для `dmPolicy` і керування allowlist.
-## Ідентифікатори команд і каналів (поширена пастка)
+## ID команди та каналу (поширена помилка)
-Параметр запиту `groupId` в URL Teams **НЕ** є ідентифікатором команди, який використовується для конфігурації. Натомість витягайте ідентифікатори зі шляху URL:
+Параметр запиту `groupId` в URL Teams **НЕ** є ID команди, що використовується для конфігурації. Натомість витягуйте ID зі шляху URL:
**URL команди:**
```
https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?groupId=...
└────────────────────────────┘
- Team ID (URL-decode this)
+ ID розмови команди (URL-декодуйте це)
```
**URL каналу:**
@@ -959,46 +955,46 @@ https://teams.microsoft.com/l/team/19%3ABk4j...%40thread.tacv2/conversations?gro
```
https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?groupId=...
└─────────────────────────┘
- Channel ID (URL-decode this)
+ ID каналу (URL-декодуйте це)
```
**Для конфігурації:**
-- Ідентифікатор команди = сегмент шляху після `/team/` (URL-декодований, наприклад, `19:Bk4j...@thread.tacv2`)
-- Ідентифікатор каналу = сегмент шляху після `/channel/` (URL-декодований)
-- **Ігноруйте** параметр запиту `groupId`
+- Ключ команди = сегмент шляху після `/team/` (URL-декодований, напр., `19:Bk4j...@thread.tacv2`; старіші тенанти можуть показувати `@thread.skype`, що також є чинним)
+- Ключ каналу = сегмент шляху після `/channel/` (URL-декодований)
+- **Ігноруйте** параметр запиту `groupId` для маршрутизації OpenClaw. Це ID групи Microsoft Entra, а не ID розмови Bot Framework, що використовується у вхідних активностях Teams.
## Приватні канали
Боти мають обмежену підтримку в приватних каналах:
-| Функція | Стандартні канали | Приватні канали |
-| ---------------------------- | ----------------- | ------------------------------- |
-| Встановлення бота | Так | Обмежено |
-| Повідомлення в реальному часі (webhook) | Так | Може не працювати |
-| Дозволи RSC | Так | Можуть поводитися інакше |
-| @згадки | Так | Якщо бот доступний |
-| Історія Graph API | Так | Так (за наявності дозволів) |
+| Функція | Стандартні канали | Приватні канали |
+| ----------------------------- | ----------------- | ---------------------------- |
+| Встановлення бота | Так | Обмежено |
+| Повідомлення в реальному часі (Webhook) | Так | Може не працювати |
+| Дозволи RSC | Так | Можуть поводитися інакше |
+| @mentions | Так | Якщо бот доступний |
+| Історія Graph API | Так | Так (з дозволами) |
-**Обхідні рішення, якщо приватні канали не працюють:**
+**Обхідні варіанти, якщо приватні канали не працюють:**
1. Використовуйте стандартні канали для взаємодії з ботом
-2. Використовуйте DM - користувачі завжди можуть написати боту напряму
+2. Використовуйте приватні повідомлення - користувачі завжди можуть написати боту напряму
3. Використовуйте Graph API для доступу до історії (потрібен `ChannelMessage.Read.All`)
-## Усунення несправностей
+## Усунення неполадок
### Поширені проблеми
-- **Зображення не відображаються в каналах:** відсутні дозволи Graph або згода адміністратора. Перевстановіть застосунок Teams і повністю закрийте/знову відкрийте Teams.
-- **Немає відповідей у каналі:** за замовчуванням потрібні згадки; встановіть `channels.msteams.requireMention=false` або налаштуйте окремо для команди/каналу.
-- **Невідповідність версії (Teams усе ще показує старий маніфест):** видаліть і повторно додайте застосунок, а потім повністю закрийте Teams, щоб оновити дані.
-- **401 Unauthorized від webhook:** очікувано під час ручного тестування без Azure JWT - це означає, що кінцева точка доступна, але автентифікація не вдалася. Використовуйте Azure Web Chat для коректного тестування.
+- **Зображення не відображаються в каналах:** відсутні дозволи Graph або згода адміністратора. Перевстановіть застосунок Teams і повністю закрийте та знову відкрийте Teams.
+- **Немає відповідей у каналі:** згадки потрібні за замовчуванням; задайте `channels.msteams.requireMention=false` або налаштуйте для конкретної команди/каналу.
+- **Невідповідність версії (Teams досі показує старий маніфест):** видаліть і повторно додайте застосунок, а також повністю закрийте Teams для оновлення.
+- **401 Unauthorized від Webhook:** очікувано під час ручного тестування без Azure JWT - це означає, що endpoint доступний, але автентифікація не пройшла. Використовуйте Azure Web Chat для коректного тестування.
### Помилки завантаження маніфесту
-- **"Icon file cannot be empty":** маніфест посилається на файли піктограм розміром 0 байтів. Створіть коректні PNG-піктограми (32x32 для `outline.png`, 192x192 для `color.png`).
-- **"webApplicationInfo.Id already in use":** застосунок усе ще встановлено в іншій команді/чаті. Спочатку знайдіть і видаліть його або зачекайте 5-10 хвилин на поширення змін.
+- **"Icon file cannot be empty":** маніфест посилається на файли іконок розміром 0 байтів. Створіть коректні PNG-іконки (32x32 для `outline.png`, 192x192 для `color.png`).
+- **"webApplicationInfo.Id already in use":** застосунок досі встановлений в іншій команді/чаті. Спершу знайдіть і видаліть його або зачекайте 5-10 хвилин на поширення змін.
- **"Something went wrong" під час завантаження:** натомість завантажте через [https://admin.teams.microsoft.com](https://admin.teams.microsoft.com), відкрийте DevTools браузера (F12) → вкладку Network і перевірте тіло відповіді на фактичну помилку.
- **Sideload не вдається:** спробуйте "Upload an app to your org's app catalog" замість "Upload a custom app" - це часто обходить обмеження sideload.
@@ -1007,23 +1003,23 @@ https://teams.microsoft.com/l/channel/19%3A15bc...%40thread.tacv2/ChannelName?gr
1. Переконайтеся, що `webApplicationInfo.id` точно збігається з App ID вашого бота
2. Повторно завантажте застосунок і перевстановіть його в команді/чаті
3. Перевірте, чи адміністратор вашої організації не заблокував дозволи RSC
-4. Підтвердьте, що використовуєте правильну область: `ChannelMessage.Read.Group` для команд, `ChatMessage.Read.Chat` для групових чатів
+4. Підтвердьте, що використовуєте правильний scope: `ChannelMessage.Read.Group` для команд, `ChatMessage.Read.Chat` для групових чатів
## Посилання
-- [Створити Azure Bot](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-quickstart-registration) - посібник із налаштування Azure Bot
-- [Портал розробника Teams](https://dev.teams.microsoft.com/apps) - створення й керування застосунками Teams
+- [Створення Azure Bot](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-quickstart-registration) - посібник із налаштування Azure Bot
+- [Teams Developer Portal](https://dev.teams.microsoft.com/apps) - створення й керування застосунками Teams
- [Схема маніфесту застосунку Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema)
-- [Отримання повідомлень каналу за допомогою RSC](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/channel-messages-with-rsc)
+- [Отримання повідомлень каналу з RSC](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/channel-messages-with-rsc)
- [Довідник дозволів RSC](https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/resource-specific-consent)
-- [Обробка файлів ботом Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4) (канал/група потребує Graph)
-- [Проактивний обмін повідомленнями](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages)
-- [@microsoft/teams.cli](https://www.npmjs.com/package/@microsoft/teams.cli) - Teams CLI для керування ботом
+- [Обробка файлів ботом Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4) (для каналу/групи потрібен Graph)
+- [Проактивні повідомлення](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages)
+- [@microsoft/teams.cli](https://www.npmjs.com/package/@microsoft/teams.cli) - Teams CLI для керування ботами
## Пов’язане
- [Огляд каналів](/uk/channels) — усі підтримувані канали
-- [Сполучення](/uk/channels/pairing) — автентифікація DM і процес сполучення
+- [Сполучення](/uk/channels/pairing) — автентифікація в приватних повідомленнях і потік сполучення
- [Групи](/uk/channels/groups) — поведінка групового чату та керування згадками
-- [Маршрутизація каналів](/uk/channels/channel-routing) — маршрутизація сеансів для повідомлень
-- [Безпека](/uk/gateway/security) — модель доступу та зміцнення безпеки
+- [Маршрутизація каналів](/uk/channels/channel-routing) — маршрутизація сесій для повідомлень
+- [Безпека](/uk/gateway/security) — модель доступу та посилення захисту
diff --git a/docs/uk/plugins/sdk-channel-plugins.md b/docs/uk/plugins/sdk-channel-plugins.md
index 6d3ec6da2..c23405eaf 100644
--- a/docs/uk/plugins/sdk-channel-plugins.md
+++ b/docs/uk/plugins/sdk-channel-plugins.md
@@ -2,129 +2,129 @@
read_when:
- Ви створюєте новий Plugin каналу обміну повідомленнями
- Ви хочете підключити OpenClaw до платформи обміну повідомленнями
- - Потрібно зрозуміти поверхню адаптера ChannelPlugin
+ - Потрібно розуміти інтерфейс адаптера ChannelPlugin
sidebarTitle: Channel Plugins
summary: Покроковий посібник зі створення Plugin каналу обміну повідомленнями для OpenClaw
-title: Створення Plugin-ів каналів
+title: Створення Plugin для каналів
x-i18n:
- generated_at: "2026-04-29T15:39:41Z"
+ generated_at: "2026-04-30T00:42:36Z"
model: gpt-5.5
provider: openai
- source_hash: 03384057a4316b87c6088d3859d16ed4546c803f7c64639cd12be293f4841258
+ source_hash: 068cd797f7761efa54f4fdeb7cb4aa784ceace959f1af12bc549c16ed2776b72
source_path: plugins/sdk-channel-plugins.md
workflow: 16
---
-Цей посібник покроково показує, як створити Plugin каналу, що підключає OpenClaw до
+Цей посібник показує, як створити Plugin каналу, який підключає OpenClaw до
платформи обміну повідомленнями. Наприкінці ви матимете робочий канал із безпекою DM,
-спарюванням, ланцюжками відповідей і вихідними повідомленнями.
+сполученням, гілкуванням відповідей і вихідними повідомленнями.
- Якщо ви ще не створювали жодного Plugin OpenClaw, спершу прочитайте
- [Початок роботи](/uk/plugins/building-plugins), щоб дізнатися про базову структуру
- пакета та налаштування маніфесту.
+ Якщо ви раніше не створювали жодного Plugin OpenClaw, спершу прочитайте
+ [Початок роботи](/uk/plugins/building-plugins), щоб дізнатися базову структуру
+ пакета й налаштування маніфесту.
-## Як працюють Plugins каналів
+## Як працюють Plugin каналів
-Plugins каналів не потребують власних інструментів надсилання/редагування/реакцій. OpenClaw тримає один
+Plugin для каналів не потребують власних інструментів надсилання, редагування чи реакцій. OpenClaw тримає один
спільний інструмент `message` у ядрі. Ваш Plugin відповідає за:
-- **Конфігурація** — визначення акаунта та майстер налаштування
-- **Безпека** — політика DM та списки дозволених
-- **Спарювання** — потік підтвердження через DM
-- **Граматика сесії** — як ідентифікатори розмов конкретного провайдера відображаються на базові чати, ідентифікатори ланцюжків і батьківські резервні варіанти
-- **Вихідні повідомлення** — надсилання тексту, медіа та опитувань на платформу
-- **Ланцюжки** — як групуються відповіді
-- **Heartbeat typing** — необов'язкові сигнали набору/зайнятості для цілей доставки Heartbeat
+- **Конфігурація** — визначення акаунта й майстер налаштування
+- **Безпека** — політика DM і списки дозволених
+- **Сполучення** — потік схвалення через DM
+- **Граматика сеансів** — як специфічні для провайдера ідентифікатори розмов зіставляються з базовими чатами, ідентифікаторами гілок і батьківськими резервними варіантами
+- **Вихідні повідомлення** — надсилання тексту, медіа й опитувань на платформу
+- **Гілкування** — як відповіді потрапляють у гілки
+- **Набір для Heartbeat** — необов'язкові сигнали набору/зайнятості для цілей доставки Heartbeat
-Ядро відповідає за спільний інструмент повідомлень, підключення промптів, зовнішню форму ключа сесії,
+Ядро відповідає за спільний інструмент повідомлень, підключення промптів, зовнішню форму ключа сеансу,
загальний облік `:thread:` і диспетчеризацію.
Якщо ваш канал підтримує індикатори набору поза вхідними відповідями, експонуйте
`heartbeat.sendTyping(...)` у Plugin каналу. Ядро викликає його з
-визначеною ціллю доставки Heartbeat перед початком запуску моделі Heartbeat і
-використовує спільний життєвий цикл підтримання/очищення індикатора набору. Додайте `heartbeat.clearTyping(...)`,
+розв'язаною ціллю доставки Heartbeat перед початком запуску моделі Heartbeat і
+використовує спільний життєвий цикл підтримання та очищення набору. Додайте `heartbeat.clearTyping(...)`,
коли платформі потрібен явний сигнал зупинки.
-Якщо ваш канал додає параметри інструмента повідомлень, що несуть джерела медіа, експонуйте ці
+Якщо ваш канал додає параметри інструмента повідомлень, які несуть джерела медіа, експонуйте ці
назви параметрів через `describeMessageTool(...).mediaSourceParams`. Ядро використовує
-цей явний список для нормалізації шляхів sandbox і політики доступу до вихідних медіа,
-тож Plugins не потребують спеціальних випадків у спільному ядрі для параметрів аватарів,
-вкладень або обкладинок, специфічних для провайдера.
-Бажано повертати мапу за ключами дій, наприклад
+цей явний список для нормалізації шляхів пісочниці й політики доступу до вихідних медіа,
+тому Plugin не потребують спеціальних випадків у спільному ядрі для специфічних для провайдера
+параметрів аватара, вкладення або зображення обкладинки.
+Надавайте перевагу поверненню мапи з ключами за діями, наприклад
`{ "set-profile": ["avatarUrl", "avatarPath"] }`, щоб непов'язані дії не
успадковували медіааргументи іншої дії. Плоский масив також працює для параметрів, які
-навмисно спільні для всіх експонованих дій.
+навмисно спільні для кожної експонованої дії.
-Якщо ваша платформа зберігає додатковий scope всередині ідентифікаторів розмов, тримайте цей парсинг
+Якщо ваша платформа зберігає додаткову область усередині ідентифікаторів розмов, тримайте цей розбір
у Plugin через `messaging.resolveSessionConversation(...)`. Це
-канонічний хук для відображення `rawId` на базовий ідентифікатор розмови, необов'язковий ідентифікатор ланцюжка,
-явний `baseConversationId` і будь-які `parentConversationCandidates`.
-Коли повертаєте `parentConversationCandidates`, тримайте їх упорядкованими від
-найвужчого батьківського елемента до найширшої/базової розмови.
+канонічний хук для зіставлення `rawId` з базовим ідентифікатором розмови, необов'язковим ідентифікатором гілки,
+явним `baseConversationId` і будь-якими `parentConversationCandidates`.
+Коли ви повертаєте `parentConversationCandidates`, зберігайте їх упорядкованими від
+найвужчого батька до найширшої/базової розмови.
Використовуйте `openclaw/plugin-sdk/channel-route`, коли коду Plugin потрібно нормалізувати
-поля, схожі на маршрути, порівняти дочірній ланцюжок із його батьківським маршрутом або побудувати
-стабільний ключ дедуплікації з `{ channel, to, accountId, threadId }`. Помічник
-нормалізує числові ідентифікатори ланцюжків так само, як це робить ядро, тому Plugins мають віддавати
-йому перевагу над ситуативними порівняннями `String(threadId)`.
-Plugins із граматикою цілей, специфічною для провайдера, можуть інжектувати свій парсер у
-`resolveChannelRouteTargetWithParser(...)` і все одно отримувати ту саму форму цілі маршруту
-та семантику резервного ланцюжка, яку використовує ядро.
+поля, схожі на маршрути, порівняти дочірню гілку з її батьківським маршрутом або побудувати
+стабільний ключ дедуплікації з `{ channel, to, accountId, threadId }`. Допоміжний засіб
+нормалізує числові ідентифікатори гілок так само, як це робить ядро, тому Plugin мають надавати
+йому перевагу перед спеціальними порівняннями `String(threadId)`.
+Plugin із специфічною для провайдера граматикою цілей можуть ін'єктувати свій парсер у
+`resolveChannelRouteTargetWithParser(...)` і все одно отримати ту саму форму цілі маршруту
+та семантику резервних гілок, яку використовує ядро.
-Вбудовані Plugins, яким потрібен той самий парсинг до запуску реєстру каналів,
-також можуть експонувати файл верхнього рівня `session-key-api.ts` з відповідним
-експортом `resolveSessionConversation(...)`. Ядро використовує цю безпечну для bootstrap поверхню
-лише тоді, коли runtime-реєстр Plugin ще недоступний.
+Вбудовані Plugin, яким потрібен той самий розбір до завантаження реєстру каналів,
+також можуть експонувати файл верхнього рівня `session-key-api.ts` із відповідним
+експортом `resolveSessionConversation(...)`. Ядро використовує цю безпечну для початкового завантаження поверхню
+лише тоді, коли реєстр Plugin часу виконання ще недоступний.
`messaging.resolveParentConversationCandidates(...)` залишається доступним як
-застарілий резерв сумісності, коли Plugin потребує лише батьківських резервних варіантів поверх
-загального/raw ідентифікатора. Якщо існують обидва хуки, ядро спершу використовує
-`resolveSessionConversation(...).parentConversationCandidates` і лише
+застарілий резервний механізм сумісності, коли Plugin потребує лише батьківських резервних варіантів поверх
+загального/сирого ідентифікатора. Якщо існують обидва хуки, ядро спочатку використовує
+`resolveSessionConversation(...).parentConversationCandidates` і лише потім
переходить до `resolveParentConversationCandidates(...)`, коли канонічний хук
-їх пропускає.
+їх не надає.
-## Підтвердження та можливості каналу
+## Схвалення та можливості каналів
-Більшості Plugins каналів не потрібен код, специфічний для підтверджень.
+Більшість Plugin для каналів не потребують коду, специфічного для схвалень.
-- Ядро відповідає за same-chat `/approve`, спільні payload підтверджувальних кнопок і загальну резервну доставку.
-- Віддавайте перевагу одному об'єкту `approvalCapability` у Plugin каналу, коли каналу потрібна поведінка, специфічна для підтверджень.
-- `ChannelPlugin.approvals` видалено. Розміщуйте факти доставки/native/render/auth для підтверджень у `approvalCapability`.
-- `plugin.auth` призначений лише для входу/виходу; ядро більше не читає хуки auth підтверджень із цього об'єкта.
-- `approvalCapability.authorizeActorAction` і `approvalCapability.getActionAvailabilityState` є канонічним seam auth підтверджень.
-- Використовуйте `approvalCapability.getActionAvailabilityState` для доступності auth same-chat підтверджень.
-- Якщо ваш канал експонує native exec підтвердження, використовуйте `approvalCapability.getExecInitiatingSurfaceState` для стану initiating-surface/native-client, коли він відрізняється від auth same-chat підтверджень. Ядро використовує цей exec-специфічний хук, щоб розрізняти `enabled` і `disabled`, вирішувати, чи підтримує початковий канал native exec підтвердження, і включати канал у fallback-підказки native-client. `createApproverRestrictedNativeApprovalCapability(...)` заповнює це для типового випадку.
-- Використовуйте `outbound.shouldSuppressLocalPayloadPrompt` або `outbound.beforeDeliverPayload` для поведінки життєвого циклу payload, специфічної для каналу, наприклад приховування дубльованих локальних промптів підтвердження або надсилання індикаторів набору перед доставкою.
-- Використовуйте `approvalCapability.delivery` лише для маршрутизації native підтверджень або пригнічення fallback.
-- Використовуйте `approvalCapability.nativeRuntime` для фактів native підтверджень, якими володіє канал. Тримайте його lazy на гарячих entrypoints каналу за допомогою `createLazyChannelApprovalNativeRuntimeAdapter(...)`, який може імпортувати ваш runtime-модуль на вимогу, водночас дозволяючи ядру зібрати життєвий цикл підтвердження.
-- Використовуйте `approvalCapability.render` лише тоді, коли каналу справді потрібні власні payload підтвердження замість спільного renderer.
-- Використовуйте `approvalCapability.describeExecApprovalSetup`, коли канал хоче, щоб відповідь disabled-path пояснювала точні перемикачі конфігурації, потрібні для ввімкнення native exec підтверджень. Хук отримує `{ channel, channelLabel, accountId }`; канали з іменованими акаунтами мають рендерити шляхи в межах акаунта, як-от `channels..accounts..execApprovals.*`, замість top-level defaults.
-- Якщо канал може вивести стабільні owner-like DM ідентичності з наявної конфігурації, використовуйте `createResolvedApproverActionAuthAdapter` з `openclaw/plugin-sdk/approval-runtime`, щоб обмежити same-chat `/approve` без додавання логіки ядра, специфічної для підтверджень.
-- Якщо каналу потрібна доставка native підтверджень, зосередьте код каналу на нормалізації цілі та фактах транспорту/представлення. Використовуйте `createChannelExecApprovalProfile`, `createChannelNativeOriginTargetResolver`, `createChannelApproverDmTargetResolver` і `createApproverRestrictedNativeApprovalCapability` з `openclaw/plugin-sdk/approval-runtime`. Розміщуйте специфічні для каналу факти за `approvalCapability.nativeRuntime`, бажано через `createChannelApprovalNativeRuntimeAdapter(...)` або `createLazyChannelApprovalNativeRuntimeAdapter(...)`, щоб ядро могло зібрати handler і відповідати за фільтрацію запитів, маршрутизацію, дедуплікацію, завершення терміну дії, підписку Gateway і сповіщення про маршрутизацію в інше місце. `nativeRuntime` розділено на кілька менших seam:
-- `createChannelNativeOriginTargetResolver` за замовчуванням використовує спільний matcher channel-route для цілей `{ to, accountId, threadId }`. Передавайте `targetsMatch` лише тоді, коли канал має специфічні для провайдера правила еквівалентності, наприклад зіставлення префікса timestamp у Slack.
-- Передавайте `normalizeTargetForMatch` у `createChannelNativeOriginTargetResolver`, коли каналу потрібно канонізувати ідентифікатори провайдера перед запуском стандартного route matcher або власного callback `targetsMatch`, зберігаючи оригінальну ціль для доставки. Використовуйте `normalizeTarget` лише тоді, коли саму визначену ціль доставки потрібно канонізувати.
+- Ядро відповідає за `/approve` у тому самому чаті, спільні корисні навантаження кнопок схвалення й загальну резервну доставку.
+- Надавайте перевагу одному об'єкту `approvalCapability` у Plugin каналу, коли каналу потрібна поведінка, специфічна для схвалень.
+- `ChannelPlugin.approvals` видалено. Розміщуйте факти про доставку, нативність, рендеринг і автентифікацію схвалень у `approvalCapability`.
+- `plugin.auth` призначений лише для входу/виходу; ядро більше не читає хуки автентифікації схвалень із цього об'єкта.
+- `approvalCapability.authorizeActorAction` і `approvalCapability.getActionAvailabilityState` є канонічною точкою інтеграції для автентифікації схвалень.
+- Використовуйте `approvalCapability.getActionAvailabilityState` для доступності автентифікації схвалень у тому самому чаті.
+- Якщо ваш канал експонує нативні exec-схвалення, використовуйте `approvalCapability.getExecInitiatingSurfaceState` для стану поверхні ініціювання/нативного клієнта, коли він відрізняється від автентифікації схвалень у тому самому чаті. Ядро використовує цей специфічний для exec хук, щоб відрізняти `enabled` від `disabled`, вирішувати, чи канал ініціювання підтримує нативні exec-схвалення, і включати канал у підказки щодо резервного переходу для нативного клієнта. `createApproverRestrictedNativeApprovalCapability(...)` заповнює це для типового випадку.
+- Використовуйте `outbound.shouldSuppressLocalPayloadPrompt` або `outbound.beforeDeliverPayload` для специфічної для каналу поведінки життєвого циклу корисного навантаження, наприклад приховування дубльованих локальних запитів на схвалення або надсилання індикаторів набору перед доставкою.
+- Використовуйте `approvalCapability.delivery` лише для маршрутизації нативних схвалень або пригнічення резервної доставки.
+- Використовуйте `approvalCapability.nativeRuntime` для належних каналу фактів про нативні схвалення. Тримайте його лінивим на гарячих точках входу каналу за допомогою `createLazyChannelApprovalNativeRuntimeAdapter(...)`, який може імпортувати ваш модуль часу виконання на вимогу й водночас дозволяє ядру зібрати життєвий цикл схвалень.
+- Використовуйте `approvalCapability.render` лише тоді, коли каналу справді потрібні власні корисні навантаження схвалень замість спільного рендерера.
+- Використовуйте `approvalCapability.describeExecApprovalSetup`, коли канал хоче, щоб відповідь для вимкненого шляху пояснювала точні параметри конфігурації, потрібні для ввімкнення нативних exec-схвалень. Хук отримує `{ channel, channelLabel, accountId }`; канали з іменованими акаунтами мають рендерити шляхи, обмежені акаунтом, наприклад `channels..accounts..execApprovals.*`, замість типових значень верхнього рівня.
+- Якщо канал може вивести стабільні DM-ідентичності на кшталт власника з наявної конфігурації, використовуйте `createResolvedApproverActionAuthAdapter` з `openclaw/plugin-sdk/approval-runtime`, щоб обмежити `/approve` у тому самому чаті без додавання специфічної для схвалень логіки ядра.
+- Якщо каналу потрібна доставка нативних схвалень, тримайте код каналу зосередженим на нормалізації цілей і фактах транспорту/представлення. Використовуйте `createChannelExecApprovalProfile`, `createChannelNativeOriginTargetResolver`, `createChannelApproverDmTargetResolver` і `createApproverRestrictedNativeApprovalCapability` з `openclaw/plugin-sdk/approval-runtime`. Розмістіть специфічні для каналу факти за `approvalCapability.nativeRuntime`, в ідеалі через `createChannelApprovalNativeRuntimeAdapter(...)` або `createLazyChannelApprovalNativeRuntimeAdapter(...)`, щоб ядро могло зібрати обробник і відповідати за фільтрацію запитів, маршрутизацію, дедуплікацію, строк дії, підписку Gateway і повідомлення про маршрутизацію в інше місце. `nativeRuntime` поділено на кілька менших точок інтеграції:
+- `createChannelNativeOriginTargetResolver` типово використовує спільний зіставлювач channel-route для цілей `{ to, accountId, threadId }`. Передавайте `targetsMatch` лише тоді, коли канал має специфічні для провайдера правила еквівалентності, наприклад зіставлення префікса часової мітки Slack.
+- Передавайте `normalizeTargetForMatch` до `createChannelNativeOriginTargetResolver`, коли каналу потрібно канонізувати ідентифікатори провайдера перед запуском типового зіставлювача маршрутів або власного callback `targetsMatch`, зберігаючи початкову ціль для доставки. Використовуйте `normalizeTarget` лише тоді, коли сама розв'язана ціль доставки має бути канонізована.
- `availability` — чи налаштовано акаунт і чи потрібно обробляти запит
-- `presentation` — відображає спільну view model підтвердження в pending/resolved/expired native payload або фінальні дії
-- `transport` — готує цілі та надсилає/оновлює/видаляє native повідомлення підтвердження
-- `interactions` — необов'язкові хуки bind/unbind/clear-action для native кнопок або реакцій
+- `presentation` — зіставлення спільної моделі подання схвалення з очікуваними/вирішеними/простроченими нативними корисними навантаженнями або фінальними діями
+- `transport` — підготовка цілей і надсилання/оновлення/видалення нативних повідомлень схвалення
+- `interactions` — необов'язкові хуки прив'язування/відв'язування/очищення дії для нативних кнопок або реакцій
- `observe` — необов'язкові хуки діагностики доставки
-- Якщо каналу потрібні runtime-об'єкти, якими він володіє, наприклад client, token, Bolt app або webhook receiver, реєструйте їх через `openclaw/plugin-sdk/channel-runtime-context`. Загальний реєстр runtime-context дає ядру змогу bootstrap capability-driven handlers зі стану запуску каналу без додавання glue wrapper, специфічного для підтверджень.
-- Звертайтеся до нижчорівневих `createChannelApprovalHandler` або `createChannelNativeApprovalRuntime` лише тоді, коли capability-driven seam ще недостатньо виразний.
-- Канали native підтверджень мають маршрутизувати і `accountId`, і `approvalKind` через ці helpers. `accountId` утримує політику підтверджень для кількох акаунтів у межах правильного bot account, а `approvalKind` зберігає поведінку exec і plugin підтверджень доступною для каналу без hardcoded branches у ядрі.
-- Тепер ядро також відповідає за сповіщення про reroute підтверджень. Plugins каналів не мають надсилати власні follow-up повідомлення "підтвердження пішло в DM / інший канал" із `createChannelNativeApprovalRuntime`; натомість експонуйте точну маршрутизацію origin + approver-DM через спільні helpers capability підтверджень і дозвольте ядру агрегувати фактичні доставки перед публікацією будь-якого сповіщення назад у початковий чат.
-- Зберігайте тип доставленого ідентифікатора підтвердження end-to-end. Native clients не повинні
- вгадувати або переписувати маршрутизацію exec vs plugin підтверджень зі стану, локального для каналу.
-- Різні типи підтверджень можуть навмисно експонувати різні native поверхні.
+- Якщо каналу потрібні об'єкти, що належать часу виконання, як-от клієнт, токен, застосунок Bolt або Webhook-приймач, реєструйте їх через `openclaw/plugin-sdk/channel-runtime-context`. Загальний реєстр контексту часу виконання дозволяє ядру початково завантажувати обробники, керовані можливостями, зі стану запуску каналу без додавання специфічного для схвалень зв'язувального коду обгортки.
+- Звертайтеся до нижчорівневих `createChannelApprovalHandler` або `createChannelNativeApprovalRuntime` лише тоді, коли точка інтеграції, керована можливостями, ще недостатньо виразна.
+- Канали нативних схвалень мають маршрутизувати і `accountId`, і `approvalKind` через ці допоміжні засоби. `accountId` утримує політику схвалень для кількох акаунтів у межах правильного акаунта бота, а `approvalKind` зберігає доступність поведінки exec-схвалень і схвалень Plugin для каналу без жорстко заданих розгалужень у ядрі.
+- Ядро тепер також відповідає за повідомлення про перемаршрутизацію схвалень. Plugin каналів не мають надсилати власні подальші повідомлення "схвалення пішло в DM / інший канал" з `createChannelNativeApprovalRuntime`; натомість експонуйте точну маршрутизацію джерела + DM схвалювача через спільні допоміжні засоби можливостей схвалення й дозвольте ядру агрегувати фактичні доставки перед публікацією будь-якого повідомлення назад у чат ініціювання.
+- Зберігайте тип доставленого ідентифікатора схвалення наскрізно. Нативні клієнти не повинні
+ вгадувати або переписувати маршрутизацію exec-схвалень і схвалень Plugin з локального стану каналу.
+- Різні типи схвалень можуть навмисно експонувати різні нативні поверхні.
Поточні вбудовані приклади:
- - Slack зберігає native маршрутизацію підтверджень доступною і для exec, і для plugin ids.
- - Matrix зберігає ту саму native маршрутизацію DM/каналу та UX реакцій для exec
- і plugin підтверджень, водночас дозволяючи auth відрізнятися за типом підтвердження.
-- `createApproverRestrictedNativeApprovalAdapter` все ще існує як wrapper сумісності, але новий код має віддавати перевагу builder capability і експонувати `approvalCapability` у Plugin.
+ - Slack зберігає доступність маршрутизації нативних схвалень і для exec, і для ідентифікаторів Plugin.
+ - Matrix зберігає ту саму нативну маршрутизацію DM/каналу й UX реакцій для exec
+ і схвалень Plugin, водночас дозволяючи автентифікації відрізнятися за типом схвалення.
+- `createApproverRestrictedNativeApprovalAdapter` усе ще існує як обгортка сумісності, але новий код має надавати перевагу побудовувачу можливостей і експонувати `approvalCapability` у Plugin.
-Для гарячих entrypoints каналу віддавайте перевагу вужчим runtime subpaths, коли вам потрібна лише
-одна частина цієї родини:
+Для гарячих точок входу каналу надавайте перевагу вужчим підшляхам часу виконання, коли вам потрібна лише
+одна частина цього сімейства:
- `openclaw/plugin-sdk/approval-auth-runtime`
- `openclaw/plugin-sdk/approval-client-runtime`
@@ -136,125 +136,128 @@ Plugins із граматикою цілей, специфічною для пр
- `openclaw/plugin-sdk/approval-reply-runtime`
- `openclaw/plugin-sdk/channel-runtime-context`
-Так само віддавайте перевагу `openclaw/plugin-sdk/setup-runtime`,
+Так само надавайте перевагу `openclaw/plugin-sdk/setup-runtime`,
`openclaw/plugin-sdk/setup-adapter-runtime`,
`openclaw/plugin-sdk/reply-runtime`,
`openclaw/plugin-sdk/reply-dispatch-runtime`,
`openclaw/plugin-sdk/reply-reference` і
-`openclaw/plugin-sdk/reply-chunking`, коли вам не потрібна ширша umbrella
+`openclaw/plugin-sdk/reply-chunking`, коли вам не потрібна ширша загальна
поверхня.
-Зокрема для налаштування:
+Для налаштування зокрема:
-- `openclaw/plugin-sdk/setup-runtime` охоплює runtime-safe helpers налаштування:
- import-safe setup patch adapters (`createPatchedAccountSetupAdapter`,
+- `openclaw/plugin-sdk/setup-runtime` охоплює безпечні для часу виконання допоміжні засоби налаштування:
+ безпечні для імпорту адаптери патчів налаштування (`createPatchedAccountSetupAdapter`,
`createEnvPatchedAccountSetupAdapter`,
- `createSetupInputPresenceValidator`), виведення lookup-note,
+ `createSetupInputPresenceValidator`), вивід lookup-note,
`promptResolvedAllowFrom`, `splitSetupEntries` і делеговані
- builders setup-proxy
-- `openclaw/plugin-sdk/setup-adapter-runtime` — це вузький env-aware adapter
- seam для `createEnvPatchedAccountSetupAdapter`
-- `openclaw/plugin-sdk/channel-setup` охоплює builders налаштування optional-install
- плюс кілька setup-safe primitives:
+ побудовувачі проксі налаштування
+- `openclaw/plugin-sdk/setup-adapter-runtime` — це вузька, обізнана про змінні середовища
+ точка інтеграції адаптера для `createEnvPatchedAccountSetupAdapter`
+- `openclaw/plugin-sdk/channel-setup` охоплює побудовувачі налаштування
+ необов'язкового встановлення плюс кілька безпечних для налаштування примітивів:
`createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`,
-Якщо ваш канал підтримує налаштування або auth на основі env і загальні потоки startup/config
-мають знати ці env назви до завантаження runtime, оголосіть їх у
-маніфесті Plugin через `channelEnvVars`. Тримайте runtime `envVars` каналу або локальні
-константи лише для operator-facing copy.
+Якщо ваш канал підтримує налаштування або автентифікацію, керовані змінними середовища, і загальні потоки запуску/конфігурації
+мають знати ці назви змінних середовища до завантаження часу виконання, оголосіть їх у
+маніфесті Plugin через `channelEnvVars`. Тримайте `envVars` часу виконання каналу або локальні
+константи лише для текстів, звернених до операторів.
Якщо ваш канал може з’являтися в `status`, `channels list`, `channels status` або
-скануваннях SecretRef до запуску середовища виконання plugin, додайте `openclaw.setupEntry` у
+скануваннях SecretRef до запуску середовища виконання Plugin, додайте `openclaw.setupEntry` у
`package.json`. Ця точка входу має бути безпечною для імпорту в шляхах команд
-лише для читання й має повертати метадані каналу, безпечний для налаштування адаптер конфігурації, адаптер статусу
-та метадані цілі секретів каналу, потрібні для цих зведень. Не
-запускайте клієнти, слухачі або транспортні середовища виконання з точки входу налаштування.
+лише для читання і має повертати метадані каналу, безпечний для налаштування
+адаптер конфігурації, адаптер статусу та метадані цілі секретів каналу, потрібні
+для цих зведень. Не запускайте клієнти, слухачі або транспортні середовища
+виконання з точки входу налаштування.
-Також тримайте шлях імпорту основної точки входу каналу вузьким. Виявлення може оцінити
-точку входу й модуль channel plugin, щоб зареєструвати можливості без активації
-каналу. Файли на кшталт `channel-plugin-api.ts` мають експортувати об’єкт channel
-plugin без імпорту майстрів налаштування, транспортних клієнтів, socket
-listeners, засобів запуску підпроцесів або модулів запуску сервісу. Розміщуйте ці runtime
-частини в модулях, завантажених із `registerFull(...)`, runtime setters або lazy
-capability adapters.
+Шлях імпорту головної точки входу каналу також має бути вузьким. Виявлення може
+оцінювати точку входу й модуль Plugin каналу, щоб зареєструвати можливості без
+активації каналу. Файли на кшталт `channel-plugin-api.ts` мають експортувати
+об’єкт Plugin каналу без імпорту майстрів налаштування, транспортних клієнтів,
+слухачів сокетів, запускувачів підпроцесів або модулів запуску сервісів.
+Розміщуйте ці частини середовища виконання в модулях, що завантажуються з
+`registerFull(...)`, сетерах середовища виконання або лінивих адаптерах
+можливостей.
`createOptionalChannelSetupWizard`, `DEFAULT_ACCOUNT_ID`,
-`createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, і
+`createTopLevelChannelDmPolicy`, `setSetupChannelEnabled` і
`splitSetupEntries`
-- використовуйте ширший seam `openclaw/plugin-sdk/setup` лише тоді, коли вам також потрібні
- важчі спільні помічники налаштування/конфігурації, такі як
+- використовуйте ширший шов `openclaw/plugin-sdk/setup` лише тоді, коли вам
+ також потрібні важчі спільні помічники налаштування/конфігурації, як-от
`moveSingleAccountChannelSectionToDefaultAccount(...)`
-Якщо ваш канал хоче лише показувати "спершу встановіть цей plugin" на поверхнях
-налаштування, віддайте перевагу `createOptionalChannelSetupSurface(...)`. Згенерований
-адаптер/майстер fail closed під час записів конфігурації та фіналізації, і вони повторно використовують
-те саме повідомлення про обов’язкове встановлення у валідації, фіналізації та тексті
-посилання на документацію.
+Якщо ваш канал лише хоче показувати «спершу встановіть цей Plugin» у поверхнях
+налаштування, надайте перевагу `createOptionalChannelSetupSurface(...)`.
+Згенерований адаптер/майстер безпечно відмовляється від записів конфігурації та
+фіналізації, і вони повторно використовують одне й те саме повідомлення про
+потрібне встановлення у валідації, фіналізації та тексті посилання на документацію.
-Для інших гарячих шляхів каналів віддавайте перевагу вузьким помічникам замість ширших застарілих
-поверхонь:
+Для інших гарячих шляхів каналу надавайте перевагу вузьким помічникам над
+ширшими застарілими поверхнями:
- `openclaw/plugin-sdk/account-core`,
`openclaw/plugin-sdk/account-id`,
- `openclaw/plugin-sdk/account-resolution`, і
- `openclaw/plugin-sdk/account-helpers` для багаторахункової конфігурації та
- fallback для стандартного акаунта
+ `openclaw/plugin-sdk/account-resolution` і
+ `openclaw/plugin-sdk/account-helpers` для конфігурації кількох облікових
+ записів і резервного переходу до стандартного облікового запису
- `openclaw/plugin-sdk/inbound-envelope` і
- `openclaw/plugin-sdk/inbound-reply-dispatch` для inbound route/envelope та
- зв’язування record-and-dispatch
+ `openclaw/plugin-sdk/inbound-reply-dispatch` для вхідного маршруту/конверта та
+ зв’язування запису й диспетчеризації
- `openclaw/plugin-sdk/messaging-targets` для розбору/зіставлення цілей
- `openclaw/plugin-sdk/outbound-media` і
- `openclaw/plugin-sdk/outbound-runtime` для завантаження медіа плюс outbound
- identity/send delegates і планування payload
+ `openclaw/plugin-sdk/outbound-runtime` для завантаження медіа, а також
+ вихідних делегатів ідентичності/надсилання та планування корисного
+ навантаження
- `buildThreadAwareOutboundSessionRoute(...)` з
- `openclaw/plugin-sdk/channel-core`, коли outbound route має зберігати явний
- `replyToId`/`threadId` або відновлювати поточну сесію `:thread:`
- після того, як базовий ключ сесії все ще збігається. Provider plugins можуть перевизначати
- пріоритет, поведінку суфікса та нормалізацію thread id, коли їхня платформа
- має нативну семантику доставки в thread.
-- `openclaw/plugin-sdk/thread-bindings-runtime` для життєвого циклу thread-binding
- і реєстрації адаптера
-- `openclaw/plugin-sdk/agent-media-payload` лише тоді, коли все ще потрібна застаріла розкладка полів agent/media
- payload
-- `openclaw/plugin-sdk/telegram-command-config` для нормалізації користувацьких команд Telegram,
- валідації дублікатів/конфліктів і fallback-stable контракту конфігурації
- команд
+ `openclaw/plugin-sdk/channel-core`, коли вихідний маршрут має зберігати явний
+ `replyToId`/`threadId` або відновлювати поточну сесію `:thread:` після того,
+ як базовий ключ сесії все ще збігається. Plugin провайдера можуть
+ перевизначати пріоритет, поведінку суфіксів і нормалізацію ідентифікаторів
+ гілок, коли їхня платформа має нативну семантику доставки в гілки.
+- `openclaw/plugin-sdk/thread-bindings-runtime` для життєвого циклу прив’язок
+ гілок і реєстрації адаптерів
+- `openclaw/plugin-sdk/agent-media-payload` лише тоді, коли все ще потрібна
+ застаріла схема полів корисного навантаження агента/медіа
+- `openclaw/plugin-sdk/telegram-command-config` для нормалізації користувацьких
+ команд Telegram, валідації дублікатів/конфліктів і стабільного за резервним
+ переходом контракту конфігурації команд
-Канали лише з автентифікацією зазвичай можуть зупинитися на стандартному шляху: core обробляє approvals, а plugin лише відкриває outbound/auth можливості. Нативні канали approval, такі як Matrix, Slack, Telegram і користувацькі chat transports, мають використовувати спільні нативні помічники замість написання власного життєвого циклу approval.
+Канали лише для автентифікації зазвичай можуть зупинитися на стандартному шляху: ядро обробляє схвалення, а Plugin лише надає вихідні/автентифікаційні можливості. Нативні канали схвалення, як-от Matrix, Slack, Telegram і користувацькі чат-транспорти, мають використовувати спільні нативні помічники замість власноручної реалізації життєвого циклу схвалень.
-## Політика inbound згадок
+## Політика вхідних згадок
-Тримайте обробку inbound згадок розділеною на два шари:
+Тримайте обробку вхідних згадок розділеною на два рівні:
-- збирання доказів, що належить plugin
+- збирання доказів, яким володіє Plugin
- оцінювання спільної політики
-Використовуйте `openclaw/plugin-sdk/channel-mention-gating` для рішень mention-policy.
-Використовуйте `openclaw/plugin-sdk/channel-inbound` лише тоді, коли вам потрібен ширший inbound
-barrel помічників.
+Використовуйте `openclaw/plugin-sdk/channel-mention-gating` для рішень політики
+згадок. Використовуйте `openclaw/plugin-sdk/channel-inbound` лише тоді, коли вам
+потрібен ширший barrel вхідних помічників.
-Добре підходить для plugin-local логіки:
+Добре підходить для локальної логіки Plugin:
-- виявлення reply-to-bot
-- виявлення quoted-bot
-- перевірки thread-participation
-- виключення service/system-message
-- platform-native кеші, потрібні для доведення участі bot
+- виявлення відповіді боту
+- виявлення процитованого бота
+- перевірки участі в гілці
+- виключення сервісних/системних повідомлень
+- нативні для платформи кеші, потрібні для підтвердження участі бота
Добре підходить для спільного помічника:
- `requireMention`
-- явний результат згадки
-- allowlist неявних згадок
+- результат явної згадки
+- список дозволених неявних згадок
- обхід команд
-- остаточне рішення про пропуск
+- остаточне рішення пропустити
-Бажаний потік:
+Рекомендований потік:
-1. Обчисліть локальні факти згадок.
+1. Обчисліть локальні факти згадки.
2. Передайте ці факти в `resolveInboundMentionDecision({ facts, policy })`.
-3. Використовуйте `decision.effectiveWasMentioned`, `decision.shouldBypassMention` і `decision.shouldSkip` у вашому inbound gate.
+3. Використовуйте `decision.effectiveWasMentioned`, `decision.shouldBypassMention` і `decision.shouldSkip` у вашому вхідному шлюзі.
```typescript
import {
@@ -293,8 +296,8 @@ const decision = resolveInboundMentionDecision({
if (decision.shouldSkip) return;
```
-`api.runtime.channel.mentions` відкриває ті самі спільні помічники згадок для
-вбудованих channel plugins, які вже залежать від runtime injection:
+`api.runtime.channel.mentions` надає ті самі спільні помічники згадок для
+вбудованих Plugin каналів, які вже залежать від ін’єкції середовища виконання:
- `buildMentionRegexes`
- `matchesMentionPatterns`
@@ -304,21 +307,21 @@ if (decision.shouldSkip) return;
Якщо вам потрібні лише `implicitMentionKindWhen` і
`resolveInboundMentionDecision`, імпортуйте з
-`openclaw/plugin-sdk/channel-mention-gating`, щоб уникнути завантаження не пов’язаних inbound
-runtime helpers.
+`openclaw/plugin-sdk/channel-mention-gating`, щоб уникнути завантаження
+непов’язаних вхідних помічників середовища виконання.
Старіші помічники `resolveMentionGating*` залишаються в
-`openclaw/plugin-sdk/channel-inbound` лише як експорти сумісності. Новий код
-має використовувати `resolveInboundMentionDecision({ facts, policy })`.
+`openclaw/plugin-sdk/channel-inbound` лише як експорти сумісності. Новий код має
+використовувати `resolveInboundMentionDecision({ facts, policy })`.
## Покроковий огляд
- Створіть стандартні файли plugin. Поле `channel` у `package.json` — це
- те, що робить це channel plugin. Повну поверхню package-metadata див.
- у [Налаштування й конфігурація Plugin](/uk/plugins/sdk-setup#openclaw-channel):
+ Створіть стандартні файли Plugin. Поле `channel` у `package.json` — це те,
+ що робить його Plugin каналу. Повну поверхню метаданих пакета див. у
+ [Налаштування та конфігурація Plugin](/uk/plugins/sdk-setup#openclaw-channel):
```json package.json
@@ -375,16 +378,17 @@ runtime helpers.
```
- `configSchema` валідує `plugins.entries.acme-chat.config`. Використовуйте його для
- налаштувань, що належать plugin і не є конфігурацією акаунта каналу. `channelConfigs`
- валідує `channels.acme-chat` і є cold-path джерелом, яке використовують schema конфігурації,
- налаштування та UI поверхні до завантаження runtime plugin.
+ `configSchema` валідує `plugins.entries.acme-chat.config`. Використовуйте її
+ для налаштувань, якими володіє Plugin і які не є конфігурацією облікового
+ запису каналу. `channelConfigs` валідує `channels.acme-chat` і є джерелом
+ холодного шляху, яке використовують схема конфігурації, налаштування та
+ UI-поверхні до завантаження середовища виконання Plugin.
-
- Інтерфейс `ChannelPlugin` має багато необов’язкових поверхонь адаптерів. Почніть із
- мінімуму — `id` і `setup` — і додавайте адаптери за потреби.
+
+ Інтерфейс `ChannelPlugin` має багато необов’язкових поверхонь адаптерів.
+ Почніть із мінімуму — `id` і `setup` — і додавайте адаптери за потреби.
Створіть `src/channel.ts`:
@@ -479,35 +483,42 @@ runtime helpers.
});
```
- Для каналів, які приймають і канонічні top-level DM keys, і застарілі вкладені ключі, використовуйте помічники з `plugin-sdk/channel-config-helpers`: `resolveChannelDmAccess`, `resolveChannelDmPolicy`, `resolveChannelDmAllowFrom` і `normalizeChannelDmPolicy` тримають account-local значення попереду успадкованих root значень. Поєднайте той самий resolver із doctor repair через `normalizeLegacyDmAliases`, щоб runtime і migration читали той самий контракт.
+ Для каналів, які приймають і канонічні DM-ключі верхнього рівня, і
+ застарілі вкладені ключі, використовуйте помічники з
+ `plugin-sdk/channel-config-helpers`: `resolveChannelDmAccess`,
+ `resolveChannelDmPolicy`, `resolveChannelDmAllowFrom` і
+ `normalizeChannelDmPolicy` зберігають локальні для облікового запису
+ значення перед успадкованими кореневими значеннями. Поєднайте той самий
+ резолвер із ремонтом doctor через `normalizeLegacyDmAliases`, щоб
+ середовище виконання й міграція читали один і той самий контракт.
-
- Замість того, щоб реалізовувати низькорівневі інтерфейси адаптерів вручну, ви передаєте
- декларативні параметри, а builder компонуватиме їх:
+
+ Замість ручної реалізації низькорівневих інтерфейсів адаптерів ви передаєте
+ декларативні параметри, а builder компонує їх:
| Параметр | Що він зв’язує |
| --- | --- |
- | `security.dm` | Scoped DM security resolver з полів конфігурації |
- | `pairing.text` | Текстовий потік DM pairing з обміном кодом |
- | `threading` | Resolver режиму reply-to (фіксований, account-scoped або користувацький) |
- | `outbound.attachedResults` | Функції надсилання, які повертають result metadata (message IDs) |
+ | `security.dm` | Обмежений DM-резолвер безпеки з полів конфігурації |
+ | `pairing.text` | Текстовий потік DM-сполучення з обміном кодом |
+ | `threading` | Резолвер режиму відповіді (фіксований, scoped за обліковим записом або користувацький) |
+ | `outbound.attachedResults` | Функції надсилання, що повертають метадані результату (ідентифікатори повідомлень) |
- Ви також можете передати необроблені об’єкти адаптерів замість декларативних параметрів,
- якщо вам потрібен повний контроль.
+ Ви також можете передати сирі об’єкти адаптерів замість декларативних
+ параметрів, якщо вам потрібен повний контроль.
- Raw outbound adapters may define a `chunker(text, limit, ctx)` function.
- The optional `ctx.formatting` carries delivery-time formatting decisions
- such as `maxLinesPerMessage`; apply it before sending so reply threading
- and chunk boundaries are resolved once by shared outbound delivery.
- Send contexts also include `replyToIdSource` (`implicit` or `explicit`)
- when a native reply target was resolved, so payload helpers can preserve
- explicit reply tags without consuming an implicit single-use reply slot.
+ Адаптери сирого вихідного доставлення можуть визначати функцію `chunker(text, limit, ctx)`.
+ Необов’язкове `ctx.formatting` передає рішення щодо форматування під час доставлення,
+ як-от `maxLinesPerMessage`; застосовуйте його перед надсиланням, щоб гілкування відповідей
+ і межі фрагментів один раз визначалися спільним вихідним доставленням.
+ Контексти надсилання також містять `replyToIdSource` (`implicit` або `explicit`),
+ коли було визначено нативну ціль відповіді, тож допоміжні функції корисного навантаження можуть зберігати
+ явні теги відповіді, не витрачаючи неявний одноразовий слот відповіді.
- Create `index.ts`:
+ Створіть `index.ts`:
```typescript index.ts
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
@@ -544,12 +555,12 @@ runtime helpers.
Розмістіть CLI-дескриптори, що належать каналу, у `registerCliMetadata(...)`, щоб OpenClaw
міг показувати їх у кореневій довідці без активації повного runtime каналу,
- тоді як звичайні повні завантаження й надалі підхоплюватимуть ті самі дескриптори для справжньої
+ тоді як звичайні повні завантаження все одно підхоплюватимуть ті самі дескриптори для справжньої
реєстрації команд. Залиште `registerFull(...)` для роботи, потрібної лише під час runtime.
Якщо `registerFull(...)` реєструє RPC-методи Gateway, використовуйте
- префікс, специфічний для Plugin. Основні адміністративні простори імен (`config.*`,
+ префікс, специфічний для Plugin. Простори імен адміністрування ядра (`config.*`,
`exec.approvals.*`, `wizard.*`, `update.*`) залишаються зарезервованими й завжди
- розв’язуються як `operator.admin`.
+ розв’язуються в `operator.admin`.
`defineChannelPluginEntry` автоматично обробляє розділення режимів реєстрації. Див.
[Точки входу](/uk/plugins/sdk-entrypoints#definechannelpluginentry) для всіх
параметрів.
@@ -557,7 +568,7 @@ runtime helpers.
- Створіть `setup-entry.ts` для легкого завантаження під час onboarding:
+ Створіть `setup-entry.ts` для легкого завантаження під час онбордингу:
```typescript setup-entry.ts
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
@@ -567,20 +578,20 @@ runtime helpers.
```
OpenClaw завантажує це замість повної точки входу, коли канал вимкнений
- або не налаштований. Це дає змогу не підтягувати важкий runtime-код під час потоків налаштування.
- Докладніше див. [Налаштування та конфігурація](/uk/plugins/sdk-setup#setup-entry).
+ або не налаштований. Це запобігає підтягуванню важкого runtime-коду під час потоків налаштування.
+ Докладніше див. [Налаштування й конфігурація](/uk/plugins/sdk-setup#setup-entry).
- Канали bundled workspace, які виносять setup-safe експорти в sidecar
+ Канали з комплектного робочого простору, які виокремлюють безпечні для налаштування експорти в допоміжні
модулі, можуть використовувати `defineBundledChannelSetupEntry(...)` з
`openclaw/plugin-sdk/channel-entry-contract`, коли їм також потрібен
- явний setter runtime під час setup.
+ явний runtime-сетер на етапі налаштування.
- Ваш Plugin має отримувати повідомлення з платформи й пересилати їх до
- OpenClaw. Типовий патерн — Webhook, який перевіряє запит і
- передає його через inbound-обробник вашого каналу:
+ Ваш Plugin має отримувати повідомлення з платформи та пересилати їх до
+ OpenClaw. Типовий шаблон — це Webhook, який перевіряє запит і
+ передає його через вхідний обробник вашого каналу:
```typescript
registerFull(api) {
@@ -604,16 +615,16 @@ runtime helpers.
```
- Обробка inbound-повідомлень є специфічною для каналу. Кожен channel Plugin володіє
- власним inbound pipeline. Перегляньте bundled channel Plugins
- (наприклад, пакет Plugin для Microsoft Teams або Google Chat) для реальних патернів.
+ Обробка вхідних повідомлень залежить від каналу. Кожен канальний Plugin володіє
+ власним вхідним конвеєром. Перегляньте комплектні канальні Plugins
+ (наприклад, пакет Plugin для Microsoft Teams або Google Chat), щоб побачити реальні шаблони.
-Пишіть colocated тести в `src/channel.test.ts`:
+Пишіть колоковані тести в `src/channel.test.ts`:
```typescript src/channel.test.ts
import { describe, it, expect } from "vitest";
@@ -651,7 +662,7 @@ runtime helpers.
pnpm test -- /acme-chat/
```
- Для спільних test helpers див. [Тестування](/uk/plugins/sdk-testing).
+ Про спільні допоміжні засоби тестування див. [Тестування](/uk/plugins/sdk-testing).
@@ -677,7 +688,7 @@ runtime helpers.
- Фіксовані, account-scoped або користувацькі режими відповіді
+ Фіксовані, прив’язані до облікового запису або користувацькі режими відповіді
describeMessageTool і виявлення дій
@@ -686,26 +697,29 @@ runtime helpers.
inferTargetChatType, looksLikeId, resolveTarget
- TTS, STT, медіа, subagent через api.runtime
+ TTS, STT, медіа, підагент через api.runtime
+
+
+ Спільний життєвий цикл вхідного ходу: приймання, розв’язання, запис, передавання, завершення
-Деякі bundled helper seams досі існують для супроводу bundled-plugin і
-сумісності. Вони не є рекомендованим патерном для нових channel Plugins;
-віддавайте перевагу generic channel/setup/reply/runtime subpaths зі спільної поверхні SDK,
-якщо ви не супроводжуєте цю сім’ю bundled Plugins безпосередньо.
+Деякі комплектні допоміжні шви все ще існують для обслуговування комплектних Plugins і
+сумісності. Вони не є рекомендованим шаблоном для нових канальних Plugins;
+віддавайте перевагу загальним підшляхам channel/setup/reply/runtime зі спільної поверхні SDK,
+якщо ви не підтримуєте цю родину комплектних Plugins напряму.
## Наступні кроки
- [Provider Plugins](/uk/plugins/sdk-provider-plugins) — якщо ваш Plugin також надає моделі
-- [Огляд SDK](/uk/plugins/sdk-overview) — повний довідник імпортів subpath
-- [Тестування SDK](/uk/plugins/sdk-testing) — тестові утиліти й contract tests
+- [Огляд SDK](/uk/plugins/sdk-overview) — повна довідка щодо імпорту підшляхів
+- [Тестування SDK](/uk/plugins/sdk-testing) — тестові утиліти та контрактні тести
- [Маніфест Plugin](/uk/plugins/manifest) — повна схема маніфесту
## Пов’язане
- [Налаштування Plugin SDK](/uk/plugins/sdk-setup)
- [Створення Plugins](/uk/plugins/building-plugins)
-- [Agent harness Plugins](/uk/plugins/sdk-agent-harness)
+- [Plugins агентного стенда](/uk/plugins/sdk-agent-harness)
diff --git a/docs/uk/plugins/sdk-channel-turn.md b/docs/uk/plugins/sdk-channel-turn.md
new file mode 100644
index 000000000..71283bede
--- /dev/null
+++ b/docs/uk/plugins/sdk-channel-turn.md
@@ -0,0 +1,400 @@
+---
+read_when:
+ - Ви створюєте Plugin каналу й хочете використовувати спільний життєвий цикл вхідного кроку взаємодії
+ - Ви переносите монітор каналу з самописного коду-зв’язки для запису/диспетчеризації
+ - Потрібно розуміти етапи допуску, приймання, класифікації, попередньої перевірки, розв’язання, запису, диспетчеризації та завершення
+sidebarTitle: Channel turn
+summary: runtime.channel.turn -- спільне ядро вхідних ходів, яке вбудовані та сторонні плагіни каналів використовують для запису, диспетчеризації та фіналізації ходів агента
+title: Ядро ходу каналу
+x-i18n:
+ generated_at: "2026-04-30T00:42:46Z"
+ model: gpt-5.5
+ provider: openai
+ source_hash: dc918da4c43f955f509aed18a93129db26efe21686c30f9328a5639f3e700984
+ source_path: plugins/sdk-channel-turn.md
+ workflow: 16
+---
+
+Ядро обробки ходу каналу — це спільна вхідна машина станів, яка перетворює нормалізовану подію платформи на хід агента. Плагіни каналів надають факти платформи й callback доставлення. Core володіє оркестрацією: приймання, класифікація, попередня перевірка, розв’язання, авторизація, складання, запис, dispatch і фіналізація.
+
+Використовуйте це, коли ваш плагін перебуває на гарячому шляху вхідного повідомлення. Для подій, що не є повідомленнями (slash-команди, модальні вікна, взаємодії з кнопками, події життєвого циклу, реакції, стан голосу), залишайте їх локальними для плагіна. Ядро володіє лише подіями, які можуть стати текстовим ходом агента.
+
+
+ До ядра звертаються через інʼєктований runtime плагіна як `runtime.channel.turn.*`. Тип runtime плагіна експортується з `openclaw/plugin-sdk/core`, тож сторонні нативні плагіни можуть використовувати ці точки входу так само, як це роблять bundled-плагіни каналів.
+
+
+## Навіщо спільне ядро
+
+Плагіни каналів повторюють той самий вхідний потік: нормалізувати, маршрутизувати, пропустити через gates, побудувати контекст, записати метадані сесії, dispatch ходу агента, фіналізувати стан доставлення. Без спільного ядра зміну в gating згадок, видимих відповідях лише для інструментів, метаданих сесії, pending-історії або фіналізації dispatch потрібно застосовувати окремо для кожного каналу.
+
+Ядро навмисно тримає чотири поняття окремими:
+
+- `ConversationFacts`: звідки надійшло повідомлення
+- `RouteFacts`: який агент і яка сесія мають його обробити
+- `ReplyPlanFacts`: куди мають іти видимі відповіді
+- `MessageFacts`: яке тіло й додатковий контекст має бачити агент
+
+Slack DM, теми Telegram, потоки Matrix і topic-сесії Feishu на практиці розрізняють усе це. Якщо трактувати їх як один ідентифікатор, з часом виникає drift.
+
+## Життєвий цикл етапів
+
+Ядро виконує той самий фіксований pipeline незалежно від каналу:
+
+1. `ingest` -- адаптер перетворює raw-подію платформи на `NormalizedTurnInput`
+2. `classify` -- адаптер оголошує, чи може ця подія почати хід агента
+3. `preflight` -- адаптер виконує dedupe, self-echo, hydration, debounce, decryption, часткове попереднє заповнення фактів
+4. `resolve` -- адаптер повертає повністю зібраний хід (route, reply plan, message, delivery)
+5. `authorize` -- політика DM, group, mention і command застосовується до зібраних фактів
+6. `assemble` -- `FinalizedMsgContext` будується з фактів через `buildContext`
+7. `record` -- зберігаються метадані вхідної сесії та останній route
+8. `dispatch` -- хід агента виконується через buffered block dispatcher
+9. `finalize` -- adapter `onFinalize` виконується навіть у разі помилки dispatch
+
+Кожен етап emits структуровану подію журналу, коли надано callback `log`. Див. [Спостережуваність](#observability).
+
+## Види допуску
+
+Ядро не кидає помилку, коли хід відхиляється gate. Воно повертає `ChannelTurnAdmission`:
+
+| Вид | Коли |
+| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
+| `dispatch` | Хід допущено. Хід агента запускається, і шлях видимої відповіді виконується. |
+| `observeOnly` | Хід виконується end-to-end, але delivery-адаптер не надсилає нічого видимого. Використовується для broadcast observer-агентів та інших пасивних multi-agent потоків. |
+| `handled` | Подію платформи було оброблено локально (життєвий цикл, реакція, кнопка, модальне вікно). Ядро пропускає dispatch. |
+| `drop` | Шлях пропуску. Опційно `recordHistory: true` зберігає повідомлення в pending group history, щоб майбутня згадка мала контекст. |
+
+Допуск може надходити з `classify` (клас події сказав, що вона не може почати хід), з `preflight` (dedupe, self-echo, відсутня згадка із записом історії) або безпосередньо з `resolveTurn`.
+
+## Точки входу
+
+Runtime надає три бажані точки входу, щоб адаптери могли підключатися на рівні, який відповідає каналу.
+
+```typescript
+runtime.channel.turn.run(...) // adapter-driven full pipeline
+runtime.channel.turn.runPrepared(...) // channel owns dispatch; kernel runs record + finalize
+runtime.channel.turn.buildContext(...) // pure facts to FinalizedMsgContext mapping
+```
+
+Два старіші runtime helpers залишаються доступними для сумісності з Plugin SDK:
+
+```typescript
+runtime.channel.turn.runResolved(...) // deprecated compatibility alias; prefer run
+runtime.channel.turn.dispatchAssembled(...) // deprecated compatibility alias; prefer run or runPrepared
+```
+
+### run
+
+Використовуйте, коли ваш канал може виразити свій вхідний потік як `ChannelTurnAdapter`. Адаптер має callbacks для `ingest`, необовʼязкового `classify`, необовʼязкового `preflight`, обовʼязкового `resolveTurn` і необовʼязкового `onFinalize`.
+
+```typescript
+await runtime.channel.turn.run({
+ channel: "tlon",
+ accountId,
+ raw: platformEvent,
+ adapter: {
+ ingest(raw) {
+ return {
+ id: raw.messageId,
+ timestamp: raw.timestamp,
+ rawText: raw.body,
+ textForAgent: raw.body,
+ };
+ },
+ classify(input) {
+ return { kind: "message", canStartAgentTurn: input.rawText.length > 0 };
+ },
+ async preflight(input, eventClass) {
+ if (await isDuplicate(input.id)) {
+ return { admission: { kind: "drop", reason: "dedupe" } };
+ }
+ return {};
+ },
+ resolveTurn(input) {
+ return buildAssembledTurn(input);
+ },
+ onFinalize(result) {
+ clearPendingGroupHistory(result);
+ },
+ },
+});
+```
+
+`run` — правильна форма, коли канал має невелику логіку адаптера й виграє від володіння життєвим циклом через hooks.
+
+### runPrepared
+
+Використовуйте, коли канал має складний локальний dispatcher із previews, retries, edits або thread bootstrap, які мають залишатися у власності каналу. Ядро все одно записує вхідну сесію перед dispatch і повертає уніфікований `DispatchedChannelTurnResult`.
+
+```typescript
+const { dispatchResult } = await runtime.channel.turn.runPrepared({
+ channel: "matrix",
+ accountId,
+ routeSessionKey,
+ storePath,
+ ctxPayload,
+ recordInboundSession,
+ record: {
+ onRecordError,
+ updateLastRoute,
+ },
+ onPreDispatchFailure: async (err) => {
+ await stopStatusReactions();
+ },
+ runDispatch: async () => {
+ return await runMatrixOwnedDispatcher();
+ },
+});
+```
+
+Rich channels (Matrix, Mattermost, Microsoft Teams, Feishu, QQ Bot) використовують `runPrepared`, тому що їхній dispatcher оркеструє platform-specific поведінку, про яку ядро не повинно знати.
+
+### buildContext
+
+Чиста функція, яка відображає bundles фактів у `FinalizedMsgContext`. Використовуйте її, коли ваш канал hand-rolls частину pipeline, але хоче узгоджену форму контексту.
+
+```typescript
+const ctxPayload = runtime.channel.turn.buildContext({
+ channel: "googlechat",
+ accountId,
+ messageId,
+ timestamp,
+ from,
+ sender,
+ conversation,
+ route,
+ reply,
+ message,
+ access,
+ media,
+ supplemental,
+});
+```
+
+`buildContext` також корисний усередині callbacks `resolveTurn` під час складання ходу для `run`.
+
+
+ Застарілі SDK helpers, як-от `dispatchInboundReplyWithBase`, досі bridge through assembled-turn helper. Новий код плагіна має використовувати `run` або `runPrepared`.
+
+
+## Типи фактів
+
+Факти, які ядро споживає з вашого адаптера, не залежать від платформи. Перекладайте обʼєкти платформи в ці форми, перш ніж передавати їх ядру.
+
+### NormalizedTurnInput
+
+| Поле | Призначення |
+| ---------------- | ---------------------------------------------------------------------------- |
+| `id` | Стабільний message id, що використовується для dedupe і журналів |
+| `timestamp` | Необовʼязкові epoch ms |
+| `rawText` | Тіло в тому вигляді, у якому його отримано від платформи |
+| `textForAgent` | Необовʼязкове очищене тіло для агента (mention strip, typing trim) |
+| `textForCommands` | Необовʼязкове тіло, що використовується для парсингу `/command` |
+| `raw` | Необовʼязкове pass-through посилання для callbacks адаптера, яким потрібен оригінал |
+
+### ChannelEventClass
+
+| Поле | Призначення |
+| ---------------------- | ---------------------------------------------------------------------- |
+| `kind` | `message`, `command`, `interaction`, `reaction`, `lifecycle`, `unknown` |
+| `canStartAgentTurn` | Якщо false, ядро повертає `{ kind: "handled" }` |
+| `requiresImmediateAck` | Підказка для адаптерів, яким потрібно ACK перед dispatch |
+
+### SenderFacts
+
+| Поле | Призначення |
+| ------------- | ---------------------------------------------------------------------- |
+| `id` | Стабільний sender id платформи |
+| `name` | Відображуване імʼя |
+| `username` | Handle, якщо відрізняється від `name` |
+| `tag` | Дискримінатор у стилі Discord або тег платформи |
+| `roles` | Role ids, що використовуються для зіставлення member-role allowlist |
+| `isBot` | True, коли відправник є відомим ботом (ядро використовує для dropping) |
+| `isSelf` | True, коли відправник є самим налаштованим агентом |
+| `displayLabel` | Попередньо відрендерений label для envelope-тексту |
+
+### ConversationFacts
+
+| Поле | Призначення |
+| ----------------- | ---------------------------------------------------------------------- |
+| `kind` | `direct`, `group` або `channel` |
+| `id` | Conversation id, що використовується для routing |
+| `label` | Людський label для envelope |
+| `spaceId` | Необовʼязковий outer space identifier (Slack workspace, Matrix homeserver) |
+| `parentId` | Outer conversation id, коли це thread |
+| `threadId` | Thread id, коли це повідомлення всередині thread |
+| `nativeChannelId` | Platform-native channel id, коли відрізняється від routing id |
+| `routePeer` | Peer, що використовується для lookup `resolveAgentRoute` |
+
+### RouteFacts
+
+| Поле | Призначення |
+| ----------------------- | -------------------------------------------------------------- |
+| `agentId` | Агент, який має обробити цей хід |
+| `accountId` | Необовʼязковий override (multi-account channels) |
+| `routeSessionKey` | Session key, що використовується для routing |
+| `dispatchSessionKey` | Session key, що використовується під час dispatch, коли відрізняється від route key |
+| `persistedSessionKey` | Session key, що записується в persisted session metadata |
+| `parentSessionKey` | Parent для branched/threaded sessions |
+| `modelParentSessionKey` | Model-side parent для branched sessions |
+| `mainSessionKey` | Main DM owner pin для direct conversations |
+| `createIfMissing` | Дозволити етапу record створити відсутній session row |
+
+### ReplyPlanFacts
+
+| Поле | Призначення |
+| ------------------------- | -------------------------------------------------------------- |
+| `to` | Логічна ціль відповіді, записана в контекст `To` |
+| `originatingTo` | Початкова ціль контексту (`OriginatingTo`) |
+| `nativeChannelId` | Нативний для платформи ідентифікатор каналу для доставлення |
+| `replyTarget` | Кінцеве місце призначення видимої відповіді, якщо воно відрізняється від `to` |
+| `deliveryTarget` | Нижчорівневе перевизначення доставлення |
+| `replyToId` | Ідентифікатор процитованого/прив’язаного повідомлення |
+| `replyToIdFull` | Повна форма процитованого ідентифікатора, коли платформа має обидві |
+| `messageThreadId` | Ідентифікатор треду на момент доставлення |
+| `threadParentId` | Ідентифікатор батьківського повідомлення треду |
+| `sourceReplyDeliveryMode` | `thread`, `reply`, `channel`, `direct` або `none` |
+
+### AccessFacts
+
+`AccessFacts` містить булеві значення, потрібні етапу авторизації. Зіставлення ідентичності залишається в каналі: ядро лише споживає результат.
+
+| Поле | Призначення |
+| ---------- | ------------------------------------------------------------------------- |
+| `dm` | Рішення дозволити/спарувати/заборонити DM і список `allowFrom` |
+| `group` | Політика групи, дозвіл маршруту, дозвіл відправника, allowlist, вимога згадки |
+| `commands` | Авторизація команд у налаштованих авторизаторах |
+| `mentions` | Чи можливе виявлення згадки та чи було згадано агента |
+
+### MessageFacts
+
+| Поле | Призначення |
+| ---------------- | -------------------------------------------------------------- |
+| `body` | Кінцеве тіло конверта (відформатоване) |
+| `rawBody` | Сире вхідне тіло |
+| `bodyForAgent` | Тіло, яке бачить агент |
+| `commandBody` | Тіло, використане для розбору команд |
+| `envelopeFrom` | Попередньо відрендерена мітка відправника для конверта |
+| `senderLabel` | Необов’язкове перевизначення для відрендереного відправника |
+| `preview` | Короткий редагований попередній перегляд для журналів |
+| `inboundHistory` | Останні записи вхідної історії, коли канал зберігає буфер |
+
+### SupplementalContextFacts
+
+Додатковий контекст охоплює контекст цитати, пересланого повідомлення та початкового завантаження треду. Ядро застосовує налаштовану політику `contextVisibility`. Адаптер каналу надає лише факти та прапорці `senderAllowed`, щоб політика між каналами залишалася узгодженою.
+
+### InboundMediaFacts
+
+Медіа мають форму фактів. Завантаження з платформи, авторизація, політика SSRF, правила CDN і розшифрування залишаються локальними для каналу. Ядро перетворює факти на `MediaPath`, `MediaUrl`, `MediaType`, `MediaPaths`, `MediaUrls`, `MediaTypes` і `MediaTranscribedIndexes`.
+
+## Контракт адаптера
+
+Для повного `run` форма адаптера така:
+
+```typescript
+type ChannelTurnAdapter = {
+ ingest(raw: TRaw): Promise | NormalizedTurnInput | null;
+ classify?(input: NormalizedTurnInput): Promise | ChannelEventClass;
+ preflight?(
+ input: NormalizedTurnInput,
+ eventClass: ChannelEventClass,
+ ): Promise;
+ resolveTurn(
+ input: NormalizedTurnInput,
+ eventClass: ChannelEventClass,
+ preflight: PreflightFacts,
+ ): Promise | ChannelTurnResolved;
+ onFinalize?(result: ChannelTurnResult): Promise | void;
+};
+```
+
+`resolveTurn` повертає `ChannelTurnResolved`, тобто `AssembledChannelTurn` з необов’язковим типом допуску. Повернення `{ admission: { kind: "observeOnly" } }` запускає хід без створення видимого виводу. Адаптер усе ще володіє callback доставлення; для цього ходу він просто стає no-op.
+
+`onFinalize` виконується для кожного результату, включно з помилками диспетчеризації. Використовуйте його, щоб очищати очікувану групову історію, прибирати реакції підтвердження, зупиняти індикатори стану та скидати локальний стан.
+
+## Адаптер доставлення
+
+Ядро не викликає платформу напряму. Канал передає ядру `ChannelTurnDeliveryAdapter`:
+
+```typescript
+type ChannelTurnDeliveryAdapter = {
+ deliver(payload: ReplyPayload, info: ChannelDeliveryInfo): Promise;
+ onError?(err: unknown, info: { kind: string }): void;
+};
+
+type ChannelDeliveryResult = {
+ messageIds?: string[];
+ threadId?: string;
+ replyToId?: string;
+ visibleReplySent?: boolean;
+};
+```
+
+`deliver` викликається один раз для кожного буферизованого фрагмента відповіді. Повертайте ідентифікатори повідомлень платформи, коли канал їх має, щоб диспетчер міг зберігати прив’язки тредів і редагувати пізніші фрагменти. Для ходів лише зі спостереженням повертайте `{ visibleReplySent: false }` або використовуйте `createNoopChannelTurnDeliveryAdapter()`.
+
+## Параметри запису
+
+Етап запису обгортає `recordInboundSession`. Більшість каналів можуть використовувати типові значення. Перевизначайте через `record`:
+
+```typescript
+record: {
+ groupResolution,
+ createIfMissing: true,
+ updateLastRoute,
+ onRecordError: (err) => log.warn("record failed", err),
+ trackSessionMetaTask: (task) => pendingTasks.push(task),
+}
+```
+
+Диспетчер очікує завершення етапу запису. Якщо запис викидає помилку, ядро запускає `onPreDispatchFailure` (коли його передано до `runPrepared`) і повторно викидає помилку.
+
+## Спостережуваність
+
+Кожен етап випромінює структуровану подію, коли надано callback `log`:
+
+```typescript
+await runtime.channel.turn.run({
+ channel: "twitch",
+ accountId,
+ raw,
+ adapter,
+ log: (event) => {
+ runtime.log?.debug?.(`turn.${event.stage}:${event.event}`, {
+ channel: event.channel,
+ accountId: event.accountId,
+ messageId: event.messageId,
+ sessionKey: event.sessionKey,
+ admission: event.admission,
+ reason: event.reason,
+ });
+ },
+});
+```
+
+Етапи журналювання: `ingest`, `classify`, `preflight`, `resolve`, `authorize`, `assemble`, `record`, `dispatch`, `finalize`. Уникайте журналювання сирих тіл; використовуйте `MessageFacts.preview` для коротких редагованих попередніх переглядів.
+
+## Що залишається локальним для каналу
+
+Ядро володіє оркестрацією. Канал усе ще володіє:
+
+- Транспортами платформи (gateway, REST, websocket, polling, webhooks)
+- Розв’язанням ідентичності та зіставленням відображуваних імен
+- Нативними командами, slash-командами, автодоповненням, модальними вікнами, кнопками, голосовим станом
+- Рендерингом карток, модальних вікон і adaptive-card
+- Авторизацією медіа, правилами CDN, зашифрованими медіа, транскрипцією
+- API редагування, реакцій, редагування/приховування та присутності
+- Backfill і отриманням історії на боці платформи
+- Потоками спарування, які потребують специфічної для платформи перевірки
+
+Якщо двом каналам починає бути потрібен той самий helper для одного з цих пунктів, винесіть спільний SDK helper замість проштовхування його в ядро.
+
+## Стабільність
+
+`runtime.channel.turn.*` є частиною публічної поверхні runtime Plugin. Типи фактів (`SenderFacts`, `ConversationFacts`, `RouteFacts`, `ReplyPlanFacts`, `AccessFacts`, `MessageFacts`, `SupplementalContextFacts`, `InboundMediaFacts`) і форми допуску (`ChannelTurnAdmission`, `ChannelEventClass`) доступні через `PluginRuntime` з `openclaw/plugin-sdk/core`.
+
+Застосовуються правила зворотної сумісності: нові поля фактів є додатковими, типи допуску не перейменовуються, а назви точок входу залишаються стабільними. Нові потреби каналу, які вимагають неадитивної зміни, мають проходити через процес міграції SDK Plugin.
+
+## Пов’язане
+
+- [Створення plugins каналів](/uk/plugins/sdk-channel-plugins) для ширшого контракту plugin каналу
+- [Runtime helpers Plugin](/uk/plugins/sdk-runtime) для інших поверхонь `runtime.*`
+- [Внутрішня архітектура Plugin](/uk/plugins/architecture-internals) для конвеєра завантаження та механіки реєстру