diff --git a/docs/uk/channels/channel-routing.md b/docs/uk/channels/channel-routing.md index a9b991240..7ff8b34c9 100644 --- a/docs/uk/channels/channel-routing.md +++ b/docs/uk/channels/channel-routing.md @@ -1,41 +1,39 @@ --- read_when: - - Зміна маршрутизації каналу або поведінки вхідних повідомлень + - Зміна маршрутизації каналів або поведінки вхідних повідомлень summary: Правила маршрутизації для кожного каналу (WhatsApp, Telegram, Discord, Slack) і спільний контекст -title: Маршрутизація каналу +title: Маршрутизація каналів x-i18n: - generated_at: "2026-04-22T22:50:17Z" + generated_at: "2026-04-23T00:49:05Z" model: gpt-5.4 provider: openai - source_hash: 3296ab8428cb815d0cc297d0c6e7479c5554ec45e1d90eef89a68833f5979d8d + source_hash: e7d437d85d5edd3a0157fd683c6ec63d5d7e905e3e6bdce9a3ba11ddab97d3c2 source_path: channels/channel-routing.md workflow: 15 --- # Канали та маршрутизація -OpenClaw маршрутизує відповіді **назад до каналу, звідки надійшло повідомлення**. Модель не вибирає канал; маршрутизація є детермінованою та керується конфігурацією хоста. +OpenClaw маршрутизує відповіді **назад у той канал, звідки надійшло повідомлення**. Модель не вибирає канал; маршрутизація є детермінованою та контролюється конфігурацією хоста. ## Ключові терміни - **Канал**: `telegram`, `whatsapp`, `discord`, `irc`, `googlechat`, `slack`, `signal`, `imessage`, `line`, а також канали розширень. `webchat` — це внутрішній канал інтерфейсу WebChat і не є налаштовуваним вихідним каналом. -- **AccountId**: екземпляр облікового запису для каналу (якщо підтримується). -- Необов’язковий обліковий запис каналу за замовчуванням: `channels..defaultAccount` визначає, який обліковий запис використовується, коли вихідний шлях не вказує `accountId`. - - У конфігураціях із кількома обліковими записами встановіть явне значення за замовчуванням (`defaultAccount` або `accounts.default`), коли налаштовано два або більше облікових записів. Без цього резервна маршрутизація може вибрати перший нормалізований ідентифікатор облікового запису. -- **AgentId**: ізольоване робоче середовище + сховище сесій («мозок»). -- **SessionKey**: ключ бакета, який використовується для зберігання контексту та керування конкурентністю. +- **AccountId**: екземпляр облікового запису для певного каналу (якщо підтримується). +- Необов’язковий типовий обліковий запис каналу: `channels..defaultAccount` визначає, який обліковий запис використовується, коли вихідний шлях не вказує `accountId`. + - У конфігураціях із кількома обліковими записами задайте явний типовий обліковий запис (`defaultAccount` або `accounts.default`), якщо налаштовано два або більше облікових записів. Без цього резервна маршрутизація може вибрати перший нормалізований ID облікового запису. +- **AgentId**: ізольований робочий простір + сховище сесій («brain»). +- **SessionKey**: ключ сегмента, який використовується для збереження контексту та керування паралелізмом. -## Форми ключів сесій (приклади) +## Форми ключів сесії (приклади) -Більшість прямих повідомлень зводяться до **основної** сесії агента: +За замовчуванням прямі повідомлення згортаються в **основну** сесію агента: -- `agent::` (за замовчуванням: `agent:main:main`) +- `agent::` (типово: `agent:main:main`) -Прямі повідомлення Telegram-бота ізолюються за обліковим записом бота та відправником, навіть коли `session.dmScope` дорівнює `main`, щоб рішення щодо sandbox і політики інструментів могли розрізняти DM, що походять із каналу, від основної сесії агента: +Навіть коли історія розмови в прямих повідомленнях спільна з main, політика sandbox та інструментів використовує похідний ключ середовища виконання direct-chat для кожного облікового запису для зовнішніх DM, щоб повідомлення, що надійшли з каналу, не розглядалися як локальні запуски main-сесії. -- `agent::telegram::direct:` - -Групи й канали залишаються ізольованими для кожного каналу: +Групи та канали залишаються ізольованими для кожного каналу: - Групи: `agent:::group:` - Канали/кімнати: `agent:::channel:` @@ -52,16 +50,14 @@ OpenClaw маршрутизує відповіді **назад до канал ## Закріплення маршруту основних DM -Коли `session.dmScope` дорівнює `main`, прямі повідомлення можуть використовувати одну спільну основну сесію. -Щоб запобігти перезапису `lastRoute` сесії прямими повідомленнями від не-власника, -OpenClaw визначає закріпленого власника з `allowFrom`, якщо виконуються всі такі умови: +Коли `session.dmScope` має значення `main`, прямі повідомлення можуть використовувати одну спільну основну сесію. +Щоб `lastRoute` сесії не перезаписувався DM від не-власників, OpenClaw визначає закріпленого власника з `allowFrom`, якщо виконуються всі такі умови: - `allowFrom` містить рівно один запис без wildcard. - Запис можна нормалізувати до конкретного ID відправника для цього каналу. - Відправник вхідного DM не збігається з цим закріпленим власником. -У разі такої невідповідності OpenClaw усе одно записує метадані вхідної сесії, але -пропускає оновлення `lastRoute` основної сесії. +У разі такої невідповідності OpenClaw усе одно записує метадані вхідної сесії, але пропускає оновлення `lastRoute` основної сесії. ## Правила маршрутизації (як вибирається агент) @@ -69,20 +65,20 @@ OpenClaw визначає закріпленого власника з `allowFro 1. **Точний збіг peer** (`bindings` з `peer.kind` + `peer.id`). 2. **Збіг батьківського peer** (успадкування потоку). -3. **Збіг guild + ролей** (Discord) через `guildId` + `roles`. +3. **Збіг guild + roles** (Discord) через `guildId` + `roles`. 4. **Збіг guild** (Discord) через `guildId`. 5. **Збіг team** (Slack) через `teamId`. 6. **Збіг облікового запису** (`accountId` у каналі). 7. **Збіг каналу** (будь-який обліковий запис у цьому каналі, `accountId: "*"`). -8. **Агент за замовчуванням** (`agents.list[].default`, інакше перший запис у списку, резервно — `main`). +8. **Типовий агент** (`agents.list[].default`, інакше перший запис у списку, резервно — `main`). -Коли binding містить кілька полів збігу (`peer`, `guildId`, `teamId`, `roles`), **усі надані поля мають збігатися**, щоб цей binding було застосовано. +Коли binding містить кілька полів збігу (`peer`, `guildId`, `teamId`, `roles`), **усі надані поля мають збігатися**, щоб цей binding застосувався. -Вибраний агент визначає, яке робоче середовище та сховище сесій використовуються. +Вибраний агент визначає, який робочий простір і яке сховище сесій використовуються. -## Групи широкомовлення (запуск кількох агентів) +## Групи трансляції (запуск кількох агентів) -Групи широкомовлення дають змогу запускати **кількох агентів** для одного й того самого peer **коли OpenClaw зазвичай відповідав би** (наприклад, у групах WhatsApp після згадки/активаційного фільтра). +Групи трансляції дають змогу запускати **кількох агентів** для того самого peer, **коли OpenClaw зазвичай відповідає** (наприклад, у групах WhatsApp після проходження згадки/активації). Конфігурація: @@ -96,19 +92,19 @@ OpenClaw визначає закріпленого власника з `allowFro } ``` -Див.: [Групи широкомовлення](/uk/channels/broadcast-groups). +Див.: [Групи трансляції](/uk/channels/broadcast-groups). ## Огляд конфігурації -- `agents.list`: іменовані визначення агентів (робоче середовище, модель тощо). -- `bindings`: зіставляє вхідні канали/облікові записи/peer з агентами. +- `agents.list`: іменовані визначення агентів (робочий простір, модель тощо). +- `bindings`: зіставлення вхідних каналів/облікових записів/peer з агентами. Приклад: ```json5 { agents: { - list: [{ id: "support", name: "Підтримка", workspace: "~/.openclaw/workspace-support" }], + list: [{ id: "support", name: "Support", workspace: "~/.openclaw/workspace-support" }], }, bindings: [ { match: { channel: "slack", teamId: "T123" }, agentId: "support" }, @@ -119,23 +115,18 @@ OpenClaw визначає закріпленого власника з `allowFro ## Зберігання сесій -Сховища сесій розміщуються в каталозі стану (за замовчуванням `~/.openclaw`): +Сховища сесій розміщуються в каталозі стану (типово `~/.openclaw`): - `~/.openclaw/agents//sessions/sessions.json` -- JSONL-транскрипти зберігаються поруч зі сховищем +- Поруч зі сховищем розміщуються JSONL-транскрипти Ви можете перевизначити шлях до сховища через `session.store` і шаблонізацію `{agentId}`. -Gateway та ACP під час виявлення сесій також сканують дискові сховища агентів під -коренем `agents/` за замовчуванням і під коренями `session.store` з шаблонами. Виявлені -сховища мають залишатися в межах цього обчисленого кореня агента й використовувати звичайний -файл `sessions.json`. Символічні посилання та шляхи поза коренем ігноруються. +Виявлення сесій Gateway і ACP також сканує дискові сховища агентів під типовим коренем `agents/` і під коренями `session.store` з шаблонами. Виявлені сховища мають залишатися всередині відповідного кореня агента після розв’язання шляху та використовувати звичайний файл `sessions.json`. Символічні посилання та шляхи поза коренем ігноруються. ## Поведінка WebChat -WebChat прив’язується до **вибраного агента** і за замовчуванням використовує -основну сесію агента. Завдяки цьому WebChat дає змогу бачити міжканальний контекст -для цього агента в одному місці. +WebChat приєднується до **вибраного агента** і типово використовує основну сесію агента. Завдяки цьому WebChat дає змогу бачити міжканальний контекст для цього агента в одному місці. ## Контекст відповіді diff --git a/docs/uk/channels/telegram.md b/docs/uk/channels/telegram.md index d88ecc945..95816b870 100644 --- a/docs/uk/channels/telegram.md +++ b/docs/uk/channels/telegram.md @@ -1,30 +1,30 @@ --- read_when: - - Робота з функціями Telegram або Webhook -summary: Статус підтримки Telegram-бота, можливості та конфігурація + - Робота над функціями Telegram або Webhook-ами +summary: Статус підтримки бота Telegram, можливості та налаштування title: Telegram x-i18n: - generated_at: "2026-04-22T22:50:18Z" + generated_at: "2026-04-23T00:49:05Z" model: gpt-5.4 provider: openai - source_hash: 76ce8e1a588a0666501c907ced9e54de12add0255dfbbd9a3487cc8b630e870f + source_hash: 1575c4e5e932a4a6330d57fa0d1639336aecdb8fa70d37d92dccd0d466d2fccb source_path: channels/telegram.md workflow: 15 --- # Telegram (Bot API) -Статус: готовий до production для DM ботів і груп через grammY. Довге опитування є режимом за замовчуванням; режим Webhook є необов’язковим. +Статус: готовий до використання у production для бот-DM + груп через grammY. Long polling — режим за замовчуванням; режим Webhook — необов’язковий. - - Типова політика DM для Telegram — зв’язування. + + Політика DM за замовчуванням для Telegram — підключення. - + Міжканальна діагностика та сценарії відновлення. - - Повні шаблони та приклади конфігурації каналів. + + Повні шаблони та приклади конфігурації каналу. @@ -32,7 +32,7 @@ x-i18n: - Відкрийте Telegram і почніть чат із **@BotFather** (переконайтеся, що хендл точно `@BotFather`). + Відкрийте Telegram і почніть чат з **@BotFather** (переконайтеся, що це саме `@BotFather`). Виконайте `/newbot`, дотримуйтесь підказок і збережіть токен. @@ -53,7 +53,7 @@ x-i18n: } ``` - Резервне значення через змінну середовища: `TELEGRAM_BOT_TOKEN=...` (лише для типового облікового запису). + Резервний варіант через env: `TELEGRAM_BOT_TOKEN=...` (лише для облікового запису за замовчуванням). Telegram **не** використовує `openclaw channels login telegram`; налаштуйте токен у config/env, а потім запустіть gateway. @@ -66,7 +66,7 @@ openclaw pairing list telegram openclaw pairing approve telegram ``` - Коди зв’язування дійсні протягом 1 години. + Коди підключення діють 1 годину. @@ -76,68 +76,61 @@ openclaw pairing approve telegram -Порядок визначення токена враховує обліковий запис. На практиці значення з config мають пріоритет над резервним значенням із середовища, а `TELEGRAM_BOT_TOKEN` застосовується лише до типового облікового запису. +Порядок визначення токена враховує обліковий запис. На практиці значення з config мають пріоритет над резервним варіантом через env, а `TELEGRAM_BOT_TOKEN` застосовується лише до облікового запису за замовчуванням. -## Ізоляція сесій - -DM Telegram-бота використовують ключі сесій відправника для кожного облікового запису, наприклад -`agent:main:telegram:default:direct:814912386`. Це зберігає окрему політику інструментів і sandbox для Telegram-походження -від основної сесії агента, навіть коли глобальне -налаштування `session.dmScope` має значення `main`. - ## Налаштування на боці Telegram - Для ботів Telegram за замовчуванням увімкнено **Privacy Mode**, що обмежує, які повідомлення в групах вони отримують. + За замовчуванням боти Telegram працюють у **Privacy Mode**, який обмежує, які повідомлення в групах вони отримують. Якщо бот має бачити всі повідомлення в групі, зробіть одне з такого: - вимкніть режим приватності через `/setprivacy`, або - зробіть бота адміністратором групи. - Після перемикання режиму приватності видаліть бота й додайте його знову в кожній групі, щоб Telegram застосував зміну. + Після перемикання режиму приватності видаліть бота з кожної групи й додайте знову, щоб Telegram застосував зміну. - + Статус адміністратора керується в налаштуваннях групи Telegram. - Боти-адміністратори отримують усі повідомлення в групі, що корисно для постійно активної поведінки в групі. + Боти-адміністратори отримують усі повідомлення групи, що корисно для постійно активної поведінки в групі. - - `/setjoingroups`, щоб дозволити/заборонити додавання до груп - - `/setprivacy` для керування видимістю в групах + - `/setjoingroups` щоб дозволити/заборонити додавання до груп + - `/setprivacy` для поведінки видимості в групах -## Контроль доступу та активація +## Керування доступом та активація - `channels.telegram.dmPolicy` керує доступом до прямих повідомлень: + `channels.telegram.dmPolicy` керує доступом до приватних повідомлень: - `pairing` (за замовчуванням) - - `allowlist` (потрібен щонайменше один ID відправника в `allowFrom`) + - `allowlist` (потрібен принаймні один ID відправника в `allowFrom`) - `open` (потрібно, щоб `allowFrom` містив `"*"`) - `disabled` `channels.telegram.allowFrom` приймає числові ID користувачів Telegram. Префікси `telegram:` / `tg:` приймаються та нормалізуються. - `dmPolicy: "allowlist"` із порожнім `allowFrom` блокує всі DM і відхиляється перевіркою config. - Налаштування запитує лише числові ID користувачів. - Якщо ви оновилися і ваш config містить записи allowlist у вигляді `@username`, виконайте `openclaw doctor --fix`, щоб їх розв’язати (best-effort; потрібен токен Telegram-бота). - Якщо ви раніше покладалися на файли allowlist зі сховища зв’язування, `openclaw doctor --fix` може відновити записи в `channels.telegram.allowFrom` у сценаріях allowlist (наприклад, коли `dmPolicy: "allowlist"` ще не має явних ID). + `dmPolicy: "allowlist"` з порожнім `allowFrom` блокує всі DM і відхиляється перевіркою конфігурації. + Під час налаштування запитуються лише числові ID користувачів. + Якщо ви оновилися і ваша конфігурація містить записи allowlist у форматі `@username`, виконайте `openclaw doctor --fix`, щоб їх розв’язати (best-effort; потрібен токен Telegram bot). + Якщо ви раніше покладалися на файли allowlist у pairing-store, `openclaw doctor --fix` може відновити записи в `channels.telegram.allowFrom` для сценаріїв allowlist (наприклад, коли `dmPolicy: "allowlist"` ще не має явних ID). - Для ботів з одним власником віддавайте перевагу `dmPolicy: "allowlist"` з явними числовими ID в `allowFrom`, щоб політика доступу надійно зберігалася в config (замість залежності від попередніх схвалень зв’язування). + Для ботів з одним власником надавайте перевагу `dmPolicy: "allowlist"` з явними числовими ID у `allowFrom`, щоб політика доступу надійно зберігалася в config (замість залежності від попередніх схвалень підключення). - Поширена плутанина: схвалення DM-зв’язування не означає, що «цей відправник авторизований скрізь». - Зв’язування надає доступ лише до DM. Авторизація відправників у групах усе ще походить із явних allowlist у config. - Якщо ви хочете, щоб «я був авторизований один раз і працювали і DM, і команди в групі», додайте свій числовий ID користувача Telegram до `channels.telegram.allowFrom`. + Типова плутанина: схвалення підключення DM не означає, що «цей відправник авторизований всюди». + Підключення надає доступ лише до DM. Авторизація відправника в групах і далі визначається явними allowlist у config. + Якщо ви хочете, щоб «я один раз авторизувався, і працюють і DM, і команди в групі», додайте свій числовий ID користувача Telegram до `channels.telegram.allowFrom`. ### Як знайти свій ID користувача Telegram @@ -145,7 +138,7 @@ DM Telegram-бота використовують ключі сесій відп 1. Надішліть DM своєму боту. 2. Виконайте `openclaw logs --follow`. - 3. Зчитайте `from.id`. + 3. Прочитайте `from.id`. Офіційний метод Bot API: @@ -158,12 +151,12 @@ curl "https://api.telegram.org/bot/getUpdates" - Разом застосовуються два механізми контролю: + Разом застосовуються два механізми керування: 1. **Які групи дозволені** (`channels.telegram.groups`) - немає config `groups`: - з `groupPolicy: "open"`: будь-яка група може пройти перевірки ID групи - - з `groupPolicy: "allowlist"` (за замовчуванням): групи блокуються, доки ви не додасте записи в `groups` (або `"*"`) + - з `groupPolicy: "allowlist"` (за замовчуванням): групи блокуються, доки ви не додасте записи до `groups` (або `"*"`) - `groups` налаштовано: працює як allowlist (явні ID або `"*"`) 2. **Які відправники дозволені в групах** (`channels.telegram.groupPolicy`) @@ -171,17 +164,17 @@ curl "https://api.telegram.org/bot/getUpdates" - `allowlist` (за замовчуванням) - `disabled` - `groupAllowFrom` використовується для фільтрації відправників у групах. Якщо не вказано, Telegram використовує `allowFrom` як резервне значення. + `groupAllowFrom` використовується для фільтрації відправників у групах. Якщо не задано, Telegram використовує резервне значення з `allowFrom`. Записи `groupAllowFrom` мають бути числовими ID користувачів Telegram (`telegram:` / `tg:` префікси нормалізуються). - Не вказуйте ID Telegram-груп або супергруп у `groupAllowFrom`. Від’ємні ID чатів мають бути в `channels.telegram.groups`. - Нечислові записи ігноруються для авторизації відправників. - Межа безпеки (`2026.2.25+`): авторизація відправників у групах **не** успадковує схвалення зі сховища DM-зв’язування. - Зв’язування лишається лише для DM. Для груп налаштуйте `groupAllowFrom` або `allowFrom` на рівні групи/теми. - Якщо `groupAllowFrom` не задано, Telegram використовує резервне значення з config `allowFrom`, а не сховище зв’язування. - Практичний шаблон для ботів з одним власником: задайте свій ID користувача в `channels.telegram.allowFrom`, не задавайте `groupAllowFrom`, і дозвольте цільові групи в `channels.telegram.groups`. - Примітка про runtime: якщо `channels.telegram` повністю відсутній, runtime за замовчуванням використовує fail-closed `groupPolicy="allowlist"`, якщо тільки `channels.defaults.groupPolicy` не задано явно. + Не вказуйте ID груп або супергруп Telegram у `groupAllowFrom`. Від’ємні ID чатів мають бути в `channels.telegram.groups`. + Нечислові записи ігноруються під час авторизації відправника. + Межа безпеки (`2026.2.25+`): авторизація відправника в групі **не** успадковує схвалення pairing-store для DM. + Підключення залишається лише для DM. Для груп налаштуйте `groupAllowFrom` або `allowFrom` для конкретної групи/теми. + Якщо `groupAllowFrom` не задано, Telegram використовує резервне значення з config `allowFrom`, а не з pairing store. + Практичний шаблон для ботів з одним власником: вкажіть свій ID користувача в `channels.telegram.allowFrom`, не задавайте `groupAllowFrom` і дозвольте потрібні групи в `channels.telegram.groups`. + Примітка щодо runtime: якщо `channels.telegram` повністю відсутній, runtime за замовчуванням працює в fail-closed режимі з `groupPolicy="allowlist"`, якщо тільки `channels.defaults.groupPolicy` не задано явно. - Приклад: дозволити будь-якого учасника в одній конкретній групі: + Приклад: дозволити будь-якому учаснику в одній конкретній групі: ```json5 { @@ -216,17 +209,17 @@ curl "https://api.telegram.org/bot/getUpdates" ``` - Поширена помилка: `groupAllowFrom` — це не allowlist Telegram-груп. + Типова помилка: `groupAllowFrom` — це не allowlist груп Telegram. - - Вказуйте від’ємні ID Telegram-груп або супергруп, як-от `-1001234567890`, у `channels.telegram.groups`. - - Вказуйте ID користувачів Telegram, як-от `8734062810`, у `groupAllowFrom`, якщо хочете обмежити, які люди всередині дозволеної групи можуть активувати бота. - - Використовуйте `groupAllowFrom: ["*"]` лише якщо хочете, щоб будь-який учасник дозволеної групи міг говорити з ботом. + - Вказуйте від’ємні ID груп або супергруп Telegram, як-от `-1001234567890`, у `channels.telegram.groups`. + - Вказуйте ID користувачів Telegram, як-от `8734062810`, у `groupAllowFrom`, коли хочете обмежити, хто саме всередині дозволеної групи може звертатися до бота. + - Використовуйте `groupAllowFrom: ["*"]` лише тоді, коли хочете, щоб будь-який учасник дозволеної групи міг спілкуватися з ботом. - - Відповіді в групах за замовчуванням потребують згадування. + + Відповіді в групах за замовчуванням вимагають згадування. Згадування може надходити з: @@ -258,9 +251,9 @@ curl "https://api.telegram.org/bot/getUpdates" Як отримати ID групового чату: - - перешліть повідомлення з групи до `@userinfobot` / `@getidsbot` - - або зчитайте `chat.id` з `openclaw logs --follow` - - або перегляньте Bot API `getUpdates` + - переслати повідомлення з групи до `@userinfobot` / `@getidsbot` + - або прочитати `chat.id` з `openclaw logs --follow` + - або перевірити Bot API `getUpdates` @@ -268,67 +261,67 @@ curl "https://api.telegram.org/bot/getUpdates" ## Поведінка runtime - Telegram належить процесу gateway. -- Маршрутизація детермінована: вхідні відповіді з Telegram повертаються в Telegram (модель не вибирає канали). -- Вхідні повідомлення нормалізуються до спільної channel envelope з метаданими відповіді та заповнювачами медіа. -- Групові сесії ізольовані за ID групи. Для форумних тем додається `:topic:`, щоб теми були ізольовані. -- DM-повідомлення можуть містити `message_thread_id`; OpenClaw маршрутизує їх з thread-aware ключами сесії та зберігає ID потоку для відповідей. -- Довге опитування використовує grammY runner із послідовністю на рівні чату/потоку. Загальна конкурентність sink у runner використовує `agents.defaults.maxConcurrent`. -- Перезапуски watchdog для long polling спрацьовують після 120 секунд без завершеної перевірки живучості `getUpdates` за замовчуванням. Збільшуйте `channels.telegram.pollingStallThresholdMs` лише якщо у вашому розгортанні все ще трапляються хибні перезапуски через зависання polling під час довготривалої роботи. Значення задається в мілісекундах і допускається в межах від `30000` до `600000`; підтримуються перевизначення для окремих облікових записів. -- Telegram Bot API не підтримує квитанції про прочитання (`sendReadReceipts` не застосовується). +- Маршрутизація детермінована: вхідні відповіді з Telegram повертаються в Telegram (модель не обирає канали). +- Вхідні повідомлення нормалізуються до спільного envelope каналу з метаданими відповіді та заповнювачами медіа. +- Групові сесії ізольовані за ID групи. Теми форуму додають `:topic:`, щоб теми залишалися ізольованими. +- DM-повідомлення можуть містити `message_thread_id`; OpenClaw маршрутизує їх із thread-aware ключами сесій і зберігає ID потоку для відповідей. +- Long polling використовує grammY runner із послідовною обробкою для кожного чату/потоку. Загальна sink-конкурентність runner використовує `agents.defaults.maxConcurrent`. +- Перезапуски watchdog для long polling спрацьовують за замовчуванням після 120 секунд без завершеної liveness-перевірки `getUpdates`. Збільшуйте `channels.telegram.pollingStallThresholdMs` лише якщо у вашому розгортанні все ще виникають хибні перезапуски через зависання polling під час довготривалої роботи. Значення задається в мілісекундах і допускається в межах від `30000` до `600000`; підтримуються перевизначення для окремих облікових записів. +- Telegram Bot API не підтримує підтвердження прочитання (`sendReadReceipts` не застосовується). -## Довідник можливостей +## Довідка щодо функцій - - OpenClaw може передавати часткові відповіді в реальному часі: + + OpenClaw може транслювати часткові відповіді в реальному часі: - - прямі чати: повідомлення попереднього перегляду + `editMessageText` + - приватні чати: повідомлення попереднього перегляду + `editMessageText` - групи/теми: повідомлення попереднього перегляду + `editMessageText` Вимога: - `channels.telegram.streaming` має значення `off | partial | block | progress` (за замовчуванням: `partial`) - - `progress` у Telegram відображається як `partial` (сумісність із міжканальним найменуванням) - - `streaming.preview.toolProgress` керує тим, чи перевикористовують оновлення інструментів/прогресу те саме відредаговане повідомлення попереднього перегляду (за замовчуванням: `true`). Встановіть `false`, щоб зберігати окремі повідомлення інструментів/прогресу. - - застарілі `channels.telegram.streamMode` і булеві значення `streaming` автоматично відображаються + - `progress` у Telegram відповідає `partial` (сумісність із міжканальними назвами) + - `streaming.preview.toolProgress` керує тим, чи використовують оновлення інструментів/прогресу те саме відредаговане повідомлення попереднього перегляду (за замовчуванням: `true`). Встановіть `false`, щоб залишати окремі повідомлення інструментів/прогресу. + - застарілі значення `channels.telegram.streamMode` і булеві значення `streaming` автоматично зіставляються - Для відповідей лише з текстом: + Для відповідей, що містять лише текст: - DM: OpenClaw зберігає те саме повідомлення попереднього перегляду і виконує фінальне редагування на місці (без другого повідомлення) - група/тема: OpenClaw зберігає те саме повідомлення попереднього перегляду і виконує фінальне редагування на місці (без другого повідомлення) - Для складних відповідей (наприклад, з медіавмістом) OpenClaw повертається до звичайної фінальної доставки, а потім очищає повідомлення попереднього перегляду. + Для складних відповідей (наприклад, з медіапейлоадами) OpenClaw повертається до звичайної фінальної доставки, а потім очищає повідомлення попереднього перегляду. - Потоковий попередній перегляд відокремлений від block streaming. Коли для Telegram явно ввімкнено block streaming, OpenClaw пропускає потоковий попередній перегляд, щоб уникнути подвійного стримінгу. + Streaming попереднього перегляду відокремлений від block streaming. Коли для Telegram явно ввімкнено block streaming, OpenClaw пропускає попередній stream, щоб уникнути подвійного streaming. - Якщо нативний транспорт чернеток недоступний або відхиляється, OpenClaw автоматично повертається до `sendMessage` + `editMessageText`. + Якщо нативний транспорт чернетки недоступний/відхилений, OpenClaw автоматично використовує резервний варіант `sendMessage` + `editMessageText`. - Потік reasoning лише для Telegram: + Потік міркувань лише для Telegram: - - `/reasoning stream` надсилає reasoning до попереднього перегляду в реальному часі під час генерації - - фінальна відповідь надсилається без тексту reasoning + - `/reasoning stream` надсилає міркування в live preview під час генерації + - фінальна відповідь надсилається без тексту міркувань - + Вихідний текст використовує Telegram `parse_mode: "HTML"`. - - Текст у стилі Markdown рендериться у безпечний для Telegram HTML. - - Сирий HTML моделі екранується, щоб зменшити збої парсингу в Telegram. + - Текст у стилі Markdown рендериться в HTML, безпечний для Telegram. + - Необроблений HTML моделі екранується, щоб зменшити кількість помилок розбору в Telegram. - Якщо Telegram відхиляє розібраний HTML, OpenClaw повторює спробу як звичайний текст. Попередній перегляд посилань увімкнено за замовчуванням і його можна вимкнути через `channels.telegram.linkPreview: false`. - + Реєстрація меню команд Telegram виконується під час запуску через `setMyCommands`. - Типові значення для нативних команд: + Нативні команди за замовчуванням: - `commands.native: "auto"` вмикає нативні команди для Telegram - Додайте власні записи до меню команд: + Додавання користувацьких записів у меню команд: ```json5 { @@ -345,40 +338,40 @@ curl "https://api.telegram.org/bot/getUpdates" Правила: - - назви нормалізуються (забирається початковий `/`, перетворення до нижнього регістру) - - коректний шаблон: `a-z`, `0-9`, `_`, довжина `1..32` - - власні команди не можуть перевизначати нативні команди - - конфлікти/дублікати пропускаються та журналюються + - назви нормалізуються (видаляється початковий `/`, нижній регістр) + - допустимий шаблон: `a-z`, `0-9`, `_`, довжина `1..32` + - користувацькі команди не можуть перевизначати нативні команди + - конфлікти/дублікати пропускаються та логуються Примітки: - - власні команди — це лише записи меню; вони не реалізують поведінку автоматично - - команди Plugin/Skills усе одно можуть працювати при ручному введенні, навіть якщо вони не показані в меню Telegram + - користувацькі команди — це лише записи меню; вони не реалізують поведінку автоматично + - команди plugin/skill можуть і далі працювати при ручному введенні, навіть якщо вони не показані в меню Telegram - Якщо нативні команди вимкнено, вбудовані видаляються. Власні команди/команди Plugin усе ще можуть реєструватися, якщо це налаштовано. + Якщо нативні команди вимкнені, вбудовані команди видаляються. Користувацькі команди/команди plugin усе ще можуть реєструватися, якщо це налаштовано. - Типові збої налаштування: + Типові збої під час налаштування: - - `setMyCommands failed` з `BOT_COMMANDS_TOO_MUCH` означає, що меню Telegram усе ще переповнене після скорочення; зменште кількість команд Plugin/Skills/власних команд або вимкніть `channels.telegram.commands.native`. - - `setMyCommands failed` із помилками мережі/fetch зазвичай означає, що вихідні DNS/HTTPS-з’єднання до `api.telegram.org` заблоковані. + - `setMyCommands failed` з `BOT_COMMANDS_TOO_MUCH` означає, що меню Telegram все ще переповнене після скорочення; зменште кількість команд plugin/skill/користувацьких команд або вимкніть `channels.telegram.commands.native`. + - `setMyCommands failed` з помилками network/fetch зазвичай означає, що вихідний DNS/HTTPS до `api.telegram.org` заблокований. - ### Команди зв’язування пристроїв (`device-pair` Plugin) + ### Команди підключення пристрою (`device-pair` plugin) - Коли встановлено Plugin `device-pair`: + Коли встановлено plugin `device-pair`: 1. `/pair` генерує код налаштування - 2. вставте код у застосунок iOS - 3. `/pair pending` показує список очікуваних запитів (включно з роллю/scopes) + 2. вставте код у застосунку iOS + 3. `/pair pending` показує список запитів, що очікують підтвердження (включно з роллю/scopes) 4. схваліть запит: - `/pair approve ` для явного схвалення - - `/pair approve`, коли є лише один очікуваний запит + - `/pair approve`, коли є лише один запит, що очікує підтвердження - `/pair approve latest` для найновішого - Код налаштування містить короткоживучий bootstrap-токен. Вбудована передача bootstrap зберігає токен первинного Node на рівні `scopes: []`; будь-який переданий токен оператора лишається обмеженим до `operator.approvals`, `operator.read`, `operator.talk.secrets` і `operator.write`. Перевірки bootstrap scope мають префікс ролі, тож цей allowlist оператора задовольняє лише запити оператора; ролі, що не є operator, усе ще потребують scopes під власним префіксом ролі. + Код налаштування містить короткоживучий bootstrap token. Вбудована передача bootstrap зберігає token primary node на рівні `scopes: []`; будь-який переданий operator token залишається обмеженим `operator.approvals`, `operator.read`, `operator.talk.secrets` і `operator.write`. Перевірки bootstrap scope мають префікси ролей, тому цей allowlist operator задовольняє лише запити operator; ролям, що не є operator, усе ще потрібні scopes під власним префіксом ролі. - Якщо пристрій повторює спробу зі зміненими даними автентифікації (наприклад, роль/scopes/публічний ключ), попередній очікуваний запит замінюється, а новий запит отримує інший `requestId`. Перед схваленням знову виконайте `/pair pending`. + Якщо пристрій повторює спробу зі зміненими даними auth (наприклад роль/scopes/public key), попередній запит, що очікує підтвердження, заміщується, а новий запит використовує інший `requestId`. Перед схваленням знову виконайте `/pair pending`. - Докладніше: [Зв’язування](/uk/channels/pairing#pair-via-telegram-recommended-for-ios). + Докладніше: [Підключення](/uk/channels/pairing#pair-via-telegram-recommended-for-ios). @@ -423,7 +416,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `all` - `allowlist` (за замовчуванням) - Застаріле `capabilities: ["inlineButtons"]` відображається як `inlineButtons: "all"`. + Застарілий варіант `capabilities: ["inlineButtons"]` зіставляється з `inlineButtons: "all"`. Приклад дії повідомлення: @@ -432,13 +425,13 @@ curl "https://api.telegram.org/bot/getUpdates" action: "send", channel: "telegram", to: "123456789", - message: "Виберіть варіант:", + message: "Choose an option:", buttons: [ [ - { text: "Так", callback_data: "yes" }, - { text: "Ні", callback_data: "no" }, + { text: "Yes", callback_data: "yes" }, + { text: "No", callback_data: "no" }, ], - [{ text: "Скасувати", callback_data: "cancel" }], + [{ text: "Cancel", callback_data: "cancel" }], ], } ``` @@ -451,13 +444,13 @@ curl "https://api.telegram.org/bot/getUpdates" Дії інструментів Telegram включають: - - `sendMessage` (`to`, `content`, необов’язкові `mediaUrl`, `replyToMessageId`, `messageThreadId`) + - `sendMessage` (`to`, `content`, необов’язково `mediaUrl`, `replyToMessageId`, `messageThreadId`) - `react` (`chatId`, `messageId`, `emoji`) - `deleteMessage` (`chatId`, `messageId`) - `editMessage` (`chatId`, `messageId`, `content`) - - `createForumTopic` (`chatId`, `name`, необов’язкові `iconColor`, `iconCustomEmojiId`) + - `createForumTopic` (`chatId`, `name`, необов’язково `iconColor`, `iconCustomEmojiId`) - Дії channel message надають зручні псевдоніми (`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`). + Дії повідомлень каналу надають зручні псевдоніми (`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`). Керувальні параметри: @@ -466,8 +459,8 @@ curl "https://api.telegram.org/bot/getUpdates" - `channels.telegram.actions.reactions` - `channels.telegram.actions.sticker` (за замовчуванням: вимкнено) - Примітка: `edit` і `topic-create` зараз увімкнені за замовчуванням і не мають окремих перемикачів `channels.telegram.actions.*`. - Надсилання в runtime використовує активний знімок config/secrets (startup/reload), тому шляхи дій не виконують ad-hoc повторне визначення `SecretRef` для кожного надсилання. + Примітка: `edit` і `topic-create` наразі ввімкнені за замовчуванням і не мають окремих перемикачів `channels.telegram.actions.*`. + Надсилання під час runtime використовує активний знімок config/secrets (startup/reload), тому шляхи дій не виконують ad-hoc повторне розв’язання SecretRef для кожного надсилання. Семантика видалення реакцій: [/tools/reactions](/uk/tools/reactions) @@ -476,7 +469,7 @@ curl "https://api.telegram.org/bot/getUpdates" Telegram підтримує явні теги потоків відповідей у згенерованому виводі: - - `[[reply_to_current]]` відповідає на повідомлення, яке ініціювало запит + - `[[reply_to_current]]` відповідає на повідомлення, яке ініціювало взаємодію - `[[reply_to:]]` відповідає на конкретний ID повідомлення Telegram `channels.telegram.replyToMode` керує обробкою: @@ -485,27 +478,27 @@ curl "https://api.telegram.org/bot/getUpdates" - `first` - `all` - Примітка: `off` вимикає неявне прив’язування відповідей до потоку. Явні теги `[[reply_to_*]]` усе одно враховуються. + Примітка: `off` вимикає неявне threading відповідей. Явні теги `[[reply_to_*]]` усе ще враховуються. - - Форумні супергрупи: + + Супергрупи з форумом: - ключі сесій тем додають `:topic:` - - відповіді та індикатор набору спрямовуються в потік теми - - шлях config теми: + - відповіді та індикатори набору тексту спрямовуються в потік теми + - шлях конфігурації теми: `channels.telegram.groups..topics.` - Особливий випадок загальної теми (`threadId=1`): + Спеціальний випадок загальної теми (`threadId=1`): - - надсилання повідомлень не містить `message_thread_id` (Telegram відхиляє `sendMessage(...thread_id=1)`) - - дії індикатора набору все одно містять `message_thread_id` + - надсилання повідомлень пропускає `message_thread_id` (Telegram відхиляє `sendMessage(...thread_id=1)`) + - дії набору тексту все одно включають `message_thread_id` - Успадкування тем: записи тем успадковують налаштування групи, якщо не перевизначено (`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`). - `agentId` належить лише темі й не успадковується з типових налаштувань групи. + Успадкування тем: записи тем успадковують налаштування групи, якщо їх не перевизначено (`requireMention`, `allowFrom`, `skills`, `systemPrompt`, `enabled`, `groupPolicy`). + `agentId` належить лише темі й не успадковується з параметрів групи за замовчуванням. - **Маршрутизація агентів для окремих тем**: Кожна тема може маршрутизуватися до іншого агента, якщо задати `agentId` у config теми. Це надає кожній темі власний ізольований робочий простір, пам’ять і сесію. Приклад: + **Маршрутизація агентів для окремих тем**: Кожна тема може маршрутизуватися до іншого агента, якщо задати `agentId` у конфігурації теми. Це надає кожній темі власний ізольований workspace, пам’ять і сесію. Приклад: ```json5 { @@ -514,9 +507,9 @@ curl "https://api.telegram.org/bot/getUpdates" groups: { "-1001234567890": { topics: { - "1": { agentId: "main" }, // Загальна тема → агент main - "3": { agentId: "zu" }, // Тема розробки → агент zu - "5": { agentId: "coder" } // Рев’ю коду → агент coder + "1": { agentId: "main" }, // General topic → main agent + "3": { agentId: "zu" }, // Dev topic → zu agent + "5": { agentId: "coder" } // Code review → coder agent } } } @@ -527,7 +520,7 @@ curl "https://api.telegram.org/bot/getUpdates" Тоді кожна тема має власний ключ сесії: `agent:zu:telegram:group:-1001234567890:topic:3` - **Постійне прив’язування тем ACP**: Форумні теми можуть закріплювати сесії ACP harness через типізовані ACP bindings верхнього рівня: + **Постійна прив’язка тем ACP**: Теми форуму можуть закріплювати сесії ACP harness через типізовані ACP-прив’язки верхнього рівня: - `bindings[]` з `type: "acp"` і `match.channel: "telegram"` @@ -578,13 +571,13 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - Зараз це обмежено форумними темами в групах і супергрупах. + Наразі це обмежено темами форумів у групах і супергрупах. - **ACP spawn, прив’язаний до потоку, з чату**: + **Прив’язаний до потоку запуск ACP із чату**: - `/acp spawn --thread here|auto` може прив’язати поточну тему Telegram до нової сесії ACP. - Подальші повідомлення в темі маршрутизуються безпосередньо до прив’язаної сесії ACP (без потреби в `/acp steer`). - - Після успішного прив’язування OpenClaw закріплює повідомлення-підтвердження spawn у темі. + - Після успішної прив’язки OpenClaw закріплює повідомлення-підтвердження запуску в цій темі. - Потрібно `channels.telegram.threadBindings.spawnAcpSessions=true`. Контекст шаблону включає: @@ -592,9 +585,9 @@ curl "https://api.telegram.org/bot/getUpdates" - `MessageThreadId` - `IsForum` - Поведінка DM-потоків: + Поведінка потоку DM: - - приватні чати з `message_thread_id` зберігають маршрутизацію DM, але використовують thread-aware ключі сесії/цілі відповідей. + - приватні чати з `message_thread_id` зберігають маршрутизацію DM, але використовують thread-aware ключі сесій/цілі відповідей. @@ -620,7 +613,7 @@ curl "https://api.telegram.org/bot/getUpdates" ### Відеоповідомлення - Telegram розрізняє відеофайли та відеонотатки. + Telegram розрізняє відеофайли та video notes. Приклад дії повідомлення: @@ -634,13 +627,13 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - Відеонотатки не підтримують підписи; наданий текст повідомлення надсилається окремо. + Video notes не підтримують підписи; наданий текст повідомлення надсилається окремо. ### Стікери Обробка вхідних стікерів: - - статичний WEBP: завантажується й обробляється (заповнювач ``) + - статичний WEBP: завантажується та обробляється (заповнювач ``) - анімований TGS: пропускається - відео WEBM: пропускається @@ -658,7 +651,7 @@ curl "https://api.telegram.org/bot/getUpdates" Стікери описуються один раз (коли це можливо) і кешуються, щоб зменшити кількість повторних викликів vision. - Увімкнення дій зі стікерами: + Увімкніть дії зі стікерами: ```json5 { @@ -689,7 +682,7 @@ curl "https://api.telegram.org/bot/getUpdates" { action: "sticker-search", channel: "telegram", - query: "кіт махає лапою", + query: "cat waving", limit: 5, } ``` @@ -697,13 +690,13 @@ curl "https://api.telegram.org/bot/getUpdates" - Реакції Telegram надходять як оновлення `message_reaction` (окремо від корисного навантаження повідомлень). + Реакції Telegram надходять як оновлення `message_reaction` (окремо від пейлоадів повідомлень). Коли ввімкнено, OpenClaw ставить у чергу системні події на кшталт: - `Telegram reaction added: 👍 by Alice (@alice) on msg 42` - Config: + Конфігурація: - `channels.telegram.reactionNotifications`: `off | own | all` (за замовчуванням: `own`) - `channels.telegram.reactionLevel`: `off | ack | minimal | extensive` (за замовчуванням: `minimal`) @@ -711,39 +704,39 @@ curl "https://api.telegram.org/bot/getUpdates" Примітки: - `own` означає лише реакції користувачів на повідомлення, надіслані ботом (best-effort через кеш надісланих повідомлень). - - Події реакцій усе одно підпорядковуються контролю доступу Telegram (`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`); неавторизовані відправники відкидаються. - - Telegram не надає ID потоку в оновленнях реакцій. - - нефорумні групи маршрутизуються до сесії групового чату - - форумні групи маршрутизуються до сесії загальної теми групи (`:topic:1`), а не до точного початкового топіка + - Події реакцій усе ще враховують контроль доступу Telegram (`dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`); неавторизовані відправники відкидаються. + - Telegram не надає ID потоків в оновленнях реакцій. + - групи без форуму маршрутизуються до сесії групового чату + - групи форумів маршрутизуються до сесії загальної теми групи (`:topic:1`), а не до точної початкової теми - `allowed_updates` для polling/webhook автоматично включає `message_reaction`. + `allowed_updates` для polling/webhook автоматично включають `message_reaction`. - - `ackReaction` надсилає emoji-підтвердження, поки OpenClaw обробляє вхідне повідомлення. + + `ackReaction` надсилає emoji підтвердження, поки OpenClaw обробляє вхідне повідомлення. Порядок визначення: - `channels.telegram.accounts..ackReaction` - `channels.telegram.ackReaction` - `messages.ackReaction` - - резервне значення emoji ідентичності агента (`agents.list[].identity.emoji`, інакше "👀") + - резервне emoji ідентичності агента (`agents.list[].identity.emoji`, інакше "👀") Примітки: - - Telegram очікує unicode-emoji (наприклад, "👀"). + - Telegram очікує emoji у форматі unicode (наприклад, "👀"). - Використовуйте `""`, щоб вимкнути реакцію для каналу або облікового запису. - - Записи в config каналу ввімкнені за замовчуванням (`configWrites !== false`). + + Записи конфігурації каналу ввімкнені за замовчуванням (`configWrites !== false`). Записи, ініційовані Telegram, включають: - події міграції групи (`migrate_to_chat_id`) для оновлення `channels.telegram.groups` - - `/config set` і `/config unset` (потрібно ввімкнення команд) + - `/config set` і `/config unset` (потрібне ввімкнення команд) Вимкнення: @@ -759,46 +752,46 @@ curl "https://api.telegram.org/bot/getUpdates" - - За замовчуванням: довге опитування. + + За замовчуванням: long polling. Режим Webhook: - задайте `channels.telegram.webhookUrl` - - задайте `channels.telegram.webhookSecret` (обов’язково, коли задано webhook URL) + - задайте `channels.telegram.webhookSecret` (обов’язково, коли задано URL Webhook) - необов’язково `channels.telegram.webhookPath` (за замовчуванням `/telegram-webhook`) - необов’язково `channels.telegram.webhookHost` (за замовчуванням `127.0.0.1`) - необов’язково `channels.telegram.webhookPort` (за замовчуванням `8787`) - Типовий локальний listener для режиму Webhook прив’язується до `127.0.0.1:8787`. + Локальний listener за замовчуванням для режиму Webhook прив’язується до `127.0.0.1:8787`. - Якщо ваш публічний endpoint відрізняється, розмістіть перед ним reverse proxy і вкажіть `webhookUrl` на публічний URL. - Задайте `webhookHost` (наприклад, `0.0.0.0`), коли вам свідомо потрібен зовнішній вхідний доступ. + Якщо ваша публічна кінцева точка відрізняється, розмістіть перед нею reverse proxy і вкажіть публічний URL у `webhookUrl`. + Укажіть `webhookHost` (наприклад `0.0.0.0`), коли вам навмисно потрібен зовнішній вхідний доступ. - - - Типове значення `channels.telegram.textChunkLimit` — 4000. - - `channels.telegram.chunkMode="newline"` віддає перевагу межам абзаців (порожнім рядкам) перед розбиттям за довжиною. - - `channels.telegram.mediaMaxMb` (за замовчуванням 100) обмежує розмір вхідних і вихідних медіа Telegram. - - `channels.telegram.timeoutSeconds` перевизначає timeout клієнта Telegram API (якщо не задано, застосовується типовий timeout grammY). - - `channels.telegram.pollingStallThresholdMs` має типове значення `120000`; налаштовуйте в межах від `30000` до `600000` лише для хибнопозитивних перезапусків через зависання polling. + + - значення `channels.telegram.textChunkLimit` за замовчуванням — 4000. + - `channels.telegram.chunkMode="newline"` надає перевагу межам абзаців (порожнім рядкам) перед розбиттям за довжиною. + - `channels.telegram.mediaMaxMb` (за замовчуванням 100) обмежує розмір вхідних і вихідних медіафайлів Telegram. + - `channels.telegram.timeoutSeconds` перевизначає тайм-аут клієнта Telegram API (якщо не задано, використовується значення grammY за замовчуванням). + - `channels.telegram.pollingStallThresholdMs` за замовчуванням дорівнює `120000`; налаштовуйте в межах від `30000` до `600000` лише для хибнопозитивних перезапусків через зависання polling. - історія контексту групи використовує `channels.telegram.historyLimit` або `messages.groupChat.historyLimit` (за замовчуванням 50); `0` вимикає. - додатковий контекст reply/quote/forward наразі передається як отримано. - - allowlist Telegram насамперед керують тим, хто може активувати агента, а не є повною межею редагування додаткового контексту. + - allowlist у Telegram насамперед обмежують, хто може запускати агента, а не є повноцінною межею редагування додаткового контексту. - параметри історії DM: - `channels.telegram.dmHistoryLimit` - `channels.telegram.dms[""].historyLimit` - - config `channels.telegram.retry` застосовується до допоміжних функцій надсилання Telegram (CLI/tools/actions) для відновлюваних вихідних помилок API. + - конфігурація `channels.telegram.retry` застосовується до допоміжних засобів надсилання Telegram (CLI/tools/actions) для відновлюваних вихідних помилок API. - Ціллю CLI send може бути числовий ID чату або username: + Ціль CLI-надсилання може бути числовим ID чату або username: ```bash openclaw message send --channel telegram --target 123456789 --message "hi" openclaw message send --channel telegram --target @name --message "hi" ``` - Опитування Telegram використовують `openclaw message poll` і підтримують форумні теми: + Telegram poll використовують `openclaw message poll` і підтримують теми форуму: ```bash openclaw message poll --channel telegram --target 123456789 \ @@ -808,80 +801,80 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ --poll-duration-seconds 300 --poll-public ``` - Прапорці опитувань лише для Telegram: + Прапорці poll лише для Telegram: - `--poll-duration-seconds` (5-600) - `--poll-anonymous` - `--poll-public` - - `--thread-id` для форумних тем (або використовуйте ціль `:topic:`) + - `--thread-id` для тем форуму (або використовуйте ціль `:topic:`) Telegram send також підтримує: - `--presentation` з блоками `buttons` для вбудованих клавіатур, коли це дозволяє `channels.telegram.capabilities.inlineButtons` - - `--pin` або `--delivery '{"pin":true}'`, щоб запитати закріплену доставку, коли бот може закріплювати в цьому чаті - - `--force-document`, щоб надсилати вихідні зображення та GIF як документи замість стиснених фото або завантажень анімованих медіа + - `--pin` або `--delivery '{"pin":true}'`, щоб запросити закріплену доставку, якщо бот може закріплювати повідомлення в цьому чаті + - `--force-document`, щоб надсилати вихідні зображення та GIF як документи, а не як стиснені фото або завантаження анімованих медіа Керування діями: - - `channels.telegram.actions.sendMessage=false` вимикає вихідні повідомлення Telegram, включно з опитуваннями - - `channels.telegram.actions.poll=false` вимикає створення опитувань Telegram, залишаючи звичайне надсилання ввімкненим + - `channels.telegram.actions.sendMessage=false` вимикає вихідні повідомлення Telegram, включно з poll + - `channels.telegram.actions.poll=false` вимикає створення Telegram poll, залишаючи звичайне надсилання ввімкненим - - Telegram підтримує схвалення exec у DM схвалювачів і за потреби може публікувати запити на схвалення у вихідному чаті або темі. + + Telegram підтримує погодження exec у DM погоджувачів і за потреби може публікувати запити на погодження в початковому чаті або темі. - Шлях config: + Шлях конфігурації: - `channels.telegram.execApprovals.enabled` - - `channels.telegram.execApprovals.approvers` (необов’язково; як резервне значення використовуються числові ID власників, виведені з `allowFrom` і прямого `defaultTo`, коли це можливо) + - `channels.telegram.execApprovals.approvers` (необов’язково; резервно використовуються числові ID власників, визначені з `allowFrom` і прямого `defaultTo`, коли це можливо) - `channels.telegram.execApprovals.target` (`dm` | `channel` | `both`, за замовчуванням: `dm`) - `agentFilter`, `sessionFilter` - Схвалювачі мають бути числовими ID користувачів Telegram. Telegram автоматично вмикає нативні схвалення exec, коли `enabled` не задано або має значення `"auto"` і вдається визначити хоча б одного схвалювача — або з `execApprovals.approvers`, або з числової config власника облікового запису (`allowFrom` і DM `defaultTo`). Задайте `enabled: false`, щоб явно вимкнути Telegram як нативний клієнт схвалення. Інакше запити на схвалення повертаються до інших налаштованих маршрутів схвалення або до резервної політики схвалення exec. + Погоджувачі мають бути числовими ID користувачів Telegram. Telegram автоматично вмикає нативні погодження exec, коли `enabled` не задано або дорівнює `"auto"` і можна визначити принаймні одного погоджувача — або з `execApprovals.approvers`, або з числової конфігурації власника облікового запису (`allowFrom` і `defaultTo` для прямих повідомлень). Установіть `enabled: false`, щоб явно вимкнути Telegram як нативний клієнт погодження. В інших випадках запити на погодження резервно переходять до інших налаштованих маршрутів погодження або до політики fallback погодження exec. - Telegram також рендерить спільні кнопки схвалення, які використовуються іншими чат-каналами. Нативний адаптер Telegram головно додає маршрутизацію DM схвалювачів, fanout у канал/тему та підказки набору перед доставкою. - Коли ці кнопки присутні, вони є основним UX схвалення; OpenClaw - має включати ручну команду `/approve` лише тоді, коли результат інструмента каже, - що схвалення в чаті недоступні або ручне схвалення — єдиний шлях. + Telegram також відтворює спільні кнопки погодження, що використовуються іншими чат-каналами. Нативний адаптер Telegram переважно додає маршрутизацію DM погоджувача, fanout у канал/тему та підказки набору тексту перед доставкою. + Коли ці кнопки присутні, вони є основним UX погодження; OpenClaw + має включати ручну команду `/approve` лише тоді, коли результат tool вказує, + що погодження в чаті недоступні або ручне погодження є єдиним шляхом. Правила доставки: - - `target: "dm"` надсилає запити на схвалення лише в DM визначених схвалювачів - - `target: "channel"` надсилає запит назад у вихідний чат/тему Telegram - - `target: "both"` надсилає і в DM схвалювачів, і у вихідний чат/тему + - `target: "dm"` надсилає запити на погодження лише в DM визначеним погоджувачам + - `target: "channel"` надсилає запит назад у початковий чат/тему Telegram + - `target: "both"` надсилає і в DM погоджувачам, і в початковий чат/тему - Лише визначені схвалювачі можуть схвалювати або відхиляти. Не-схвалювачі не можуть використовувати `/approve` і не можуть використовувати кнопки схвалення Telegram. + Лише визначені погоджувачі можуть погодити або відхилити. Ті, хто не є погоджувачами, не можуть використовувати `/approve` і не можуть користуватися кнопками погодження Telegram. - Поведінка визначення схвалення: + Поведінка визначення погодження: - - ID з префіксом `plugin:` завжди визначаються через схвалення Plugin. - - Інші ID спершу пробують `exec.approval.resolve`. - - Якщо Telegram також авторизовано для схвалень Plugin і gateway повідомляє, - що схвалення exec невідоме/прострочене, Telegram ще раз пробує через + - ID з префіксом `plugin:` завжди визначаються через погодження plugin. + - Інші ID спочатку пробують `exec.approval.resolve`. + - Якщо Telegram також авторизований для погоджень plugin і gateway повідомляє, + що погодження exec невідоме/прострочене, Telegram ще раз пробує через `plugin.approval.resolve`. - - Справжні відмови/помилки схвалення exec не переходять мовчки до - визначення схвалення Plugin. + - Реальні відмови/помилки погодження exec не переходять мовчки до визначення + погодження plugin. - Доставка в channel показує текст команди в чаті, тому вмикайте `channel` або `both` лише в довірених групах/темах. Коли запит потрапляє у форумну тему, OpenClaw зберігає тему і для запиту на схвалення, і для подальшого повідомлення після схвалення. За замовчуванням схвалення exec спливають через 30 хвилин. + Доставка в канал показує текст команди в чаті, тому вмикайте `channel` або `both` лише в довірених групах/темах. Коли запит надходить у тему форуму, OpenClaw зберігає тему як для запиту на погодження, так і для подальших дій після погодження. За замовчуванням погодження exec діють 30 хвилин. - Вбудовані кнопки схвалення також залежать від того, чи `channels.telegram.capabilities.inlineButtons` дозволяє цільову поверхню (`dm`, `group` або `all`). + Вбудовані кнопки погодження також залежать від того, щоб `channels.telegram.capabilities.inlineButtons` дозволяв цільову поверхню (`dm`, `group` або `all`). - Пов’язана документація: [Схвалення exec](/uk/tools/exec-approvals) + Пов’язана документація: [Погодження exec](/uk/tools/exec-approvals) -## Керування відповідями про помилки +## Керування відповідями на помилки -Коли агент стикається з помилкою доставки або постачальника, Telegram може або відповісти текстом помилки, або придушити її. Цю поведінку контролюють два ключі config: +Коли агент стикається з помилкою доставки або помилкою провайдера, Telegram може або відповісти текстом помилки, або приховати його. Цю поведінку керують два ключі конфігурації: | Key | Values | Default | Description | | ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- | -| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` надсилає до чату дружнє повідомлення про помилку. `silent` повністю пригнічує відповіді про помилки. | -| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | Мінімальний час між відповідями про помилки в одному чаті. Запобігає спаму помилок під час збоїв. | +| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` надсилає до чату дружнє повідомлення про помилку. `silent` повністю пригнічує відповіді з помилками. | +| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | Мінімальний інтервал між відповідями з помилками в тому самому чаті. Запобігає спаму помилок під час збоїв. | -Підтримуються перевизначення для окремого облікового запису, групи й теми (те саме успадкування, що й для інших ключів config Telegram). +Підтримуються перевизначення для окремого облікового запису, окремої групи та окремої теми (те саме успадкування, що й для інших ключів конфігурації Telegram). ```json5 { @@ -891,7 +884,7 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ errorCooldownMs: 120000, groups: { "-1001234567890": { - errorPolicy: "silent", // приглушити помилки в цій групі + errorPolicy: "silent", // пригнічувати помилки в цій групі }, }, }, @@ -906,37 +899,37 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ - Якщо `requireMention=false`, режим приватності Telegram має дозволяти повну видимість. - BotFather: `/setprivacy` -> Disable - - потім видаліть і знову додайте бота до групи - - `openclaw channels status` попереджає, коли config очікує повідомлення групи без згадування. - - `openclaw channels status --probe` може перевіряти явні числові ID груп; wildcard `"*"` не можна перевірити на членство через probe. - - швидка перевірка сесії: `/activation always`. + - потім видаліть бота з групи й додайте знову + - `openclaw channels status` попереджає, коли config очікує повідомлень групи без згадування. + - `openclaw channels status --probe` може перевіряти явні числові ID груп; wildcard `"*"` не можна перевірити через membership probe. + - швидкий тест сесії: `/activation always`. - + - - коли існує `channels.telegram.groups`, групу треба вказати в списку (або включити `"*"`) - - перевірте членство бота в групі - - перегляньте журнали: `openclaw logs --follow`, щоб побачити причини пропуску + - коли існує `channels.telegram.groups`, група має бути вказана в списку (або має бути `"*"`) + - перевірте, що бот є учасником групи + - перегляньте логи: `openclaw logs --follow` для причин пропуску - + - - авторизуйте свою ідентичність відправника (зв’язування та/або числовий `allowFrom`) - - авторизація команд усе одно застосовується, навіть коли політика групи має значення `open` - - `setMyCommands failed` з `BOT_COMMANDS_TOO_MUCH` означає, що нативне меню має забагато записів; зменште кількість команд Plugin/Skills/власних команд або вимкніть нативні меню - - `setMyCommands failed` із помилками мережі/fetch зазвичай вказує на проблеми з доступністю DNS/HTTPS до `api.telegram.org` + - авторизуйте свою ідентичність відправника (підключення та/або числовий `allowFrom`) + - авторизація команд усе ще застосовується, навіть коли політика групи `open` + - `setMyCommands failed` з `BOT_COMMANDS_TOO_MUCH` означає, що нативне меню має забагато записів; зменште кількість команд plugin/skill/користувацьких команд або вимкніть нативні меню + - `setMyCommands failed` з помилками network/fetch зазвичай вказує на проблеми досяжності DNS/HTTPS до `api.telegram.org` - - Node 22+ + власний fetch/proxy може спричиняти негайне скасування, якщо типи AbortSignal не збігаються. - - Деякі хости спершу визначають `api.telegram.org` у IPv6; несправний вихідний IPv6 може спричиняти переривчасті збої Telegram API. - - Якщо журнали містять `TypeError: fetch failed` або `Network request for 'getUpdates' failed!`, OpenClaw тепер повторює такі випадки як відновлювані мережеві помилки. - - Якщо журнали містять `Polling stall detected`, OpenClaw перезапускає polling і перебудовує транспорт Telegram після 120 секунд без завершеної перевірки живучості long-poll за замовчуванням. - - Збільшуйте `channels.telegram.pollingStallThresholdMs` лише тоді, коли довготривалі виклики `getUpdates` є здоровими, але ваш хост усе ще повідомляє про хибні перезапуски через зависання polling. Стійкі зависання зазвичай вказують на проблеми proxy, DNS, IPv6 або TLS-виходу між хостом і `api.telegram.org`. + - Node 22+ + custom fetch/proxy можуть спричиняти негайне скасування, якщо типи AbortSignal не збігаються. + - На деяких хостах `api.telegram.org` спочатку резолвиться в IPv6; несправний вихідний IPv6 може спричиняти періодичні збої Telegram API. + - Якщо логи містять `TypeError: fetch failed` або `Network request for 'getUpdates' failed!`, OpenClaw тепер повторює такі помилки як відновлювані мережеві помилки. + - Якщо логи містять `Polling stall detected`, OpenClaw перезапускає polling і перебудовує транспорт Telegram після 120 секунд без завершеної liveness-перевірки long poll за замовчуванням. + - Збільшуйте `channels.telegram.pollingStallThresholdMs` лише тоді, коли довготривалі виклики `getUpdates` справні, але ваш хост усе ще повідомляє про хибні перезапуски через зависання polling. Стійкі зависання зазвичай вказують на проблеми з proxy, DNS, IPv6 або TLS-виходом між хостом і `api.telegram.org`. - На VPS-хостах із нестабільним прямим виходом/TLS маршрутизуйте виклики Telegram API через `channels.telegram.proxy`: ```yaml @@ -945,8 +938,8 @@ channels: proxy: socks5://:@proxy-host:1080 ``` - - Для Node 22+ типовими є `autoSelectFamily=true` (крім WSL2) і `dnsResultOrder=ipv4first`. - - Якщо ваш хост — WSL2 або явно краще працює в режимі лише IPv4, примусово задайте вибір сімейства: + - Node 22+ за замовчуванням використовує `autoSelectFamily=true` (крім WSL2) і `dnsResultOrder=ipv4first`. + - Якщо ваш хост — WSL2 або йому явно краще працювати лише з IPv4, примусово задайте вибір сімейства: ```yaml channels: @@ -955,11 +948,11 @@ channels: autoSelectFamily: false ``` - - Відповіді з діапазону RFC 2544 benchmark (`198.18.0.0/15`) уже дозволені - для завантажень медіа Telegram за замовчуванням. Якщо довірений fake-IP або + - Відповіді з benchmark-range RFC 2544 (`198.18.0.0/15`) уже дозволені + за замовчуванням для завантаження медіа Telegram. Якщо довірений fake-IP або transparent proxy переписує `api.telegram.org` на якусь іншу приватну/внутрішню/special-use адресу під час завантаження медіа, ви можете - увімкнути обхід лише для Telegram: + явно ввімкнути обхід лише для Telegram: ```yaml channels: @@ -970,19 +963,17 @@ channels: - Те саме явне ввімкнення доступне для окремого облікового запису в `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork`. - - Якщо ваш proxy визначає медіахости Telegram у `198.18.x.x`, спершу залиште - небезпечний прапорець вимкненим. Медіа Telegram уже дозволяють діапазон RFC 2544 - benchmark за замовчуванням. + - Якщо ваш proxy резолвить медіахости Telegram у `198.18.x.x`, спочатку залиште + небезпечний прапорець вимкненим. Медіа Telegram уже за замовчуванням дозволяють діапазон benchmark RFC 2544. - `channels.telegram.network.dangerouslyAllowPrivateNetwork` послаблює захисти SSRF - для медіа Telegram. Використовуйте це лише для довірених керованих оператором proxy-середовищ, - як-от fake-IP маршрутизація Clash, Mihomo або Surge, коли вони - синтезують приватні або special-use відповіді поза діапазоном RFC 2544 benchmark. - Для звичайного доступу до Telegram через публічний інтернет залишайте це вимкненим. + `channels.telegram.network.dangerouslyAllowPrivateNetwork` послаблює захист Telegram + media SSRF. Використовуйте це лише в довірених керованих оператором proxy-середовищах, + таких як Clash, Mihomo або Surge fake-IP routing, коли вони синтезують приватні + або special-use відповіді поза межами діапазону benchmark RFC 2544. Для звичайного публічного доступу Telegram через інтернет залишайте це вимкненим. - - Перевизначення через середовище (тимчасові): + - Перевизначення через змінні середовища (тимчасово): - `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first` @@ -996,85 +987,85 @@ dig +short api.telegram.org AAAA -Більше допомоги: [Усунення проблем із каналами](/uk/channels/troubleshooting). +Додаткова допомога: [Усунення проблем каналу](/uk/channels/troubleshooting). -## Вказівники на довідник config Telegram +## Вказівники на довідник конфігурації Telegram Основний довідник: - `channels.telegram.enabled`: увімкнути/вимкнути запуск каналу. - `channels.telegram.botToken`: токен бота (BotFather). -- `channels.telegram.tokenFile`: читати токен зі шляху до звичайного файлу. Символічні посилання відхиляються. +- `channels.telegram.tokenFile`: прочитати токен зі шляху до звичайного файла. Symlink-і відхиляються. - `channels.telegram.dmPolicy`: `pairing | allowlist | open | disabled` (за замовчуванням: pairing). -- `channels.telegram.allowFrom`: allowlist для DM (числові ID користувачів Telegram). `allowlist` вимагає щонайменше один ID відправника. `open` вимагає `"*"`. `openclaw doctor --fix` може розв’язати застарілі записи `@username` до ID і може відновити записи allowlist із файлів pairing-store у сценаріях міграції allowlist. -- `channels.telegram.actions.poll`: увімкнути або вимкнути створення опитувань Telegram (за замовчуванням: увімкнено; все одно потрібен `sendMessage`). -- `channels.telegram.defaultTo`: типова ціль Telegram, яку використовує CLI `--deliver`, коли явний `--reply-to` не задано. +- `channels.telegram.allowFrom`: allowlist DM (числові ID користувачів Telegram). `allowlist` вимагає принаймні один ID відправника. `open` вимагає `"*"`. `openclaw doctor --fix` може розв’язати застарілі записи `@username` до ID і може відновити записи allowlist з файлів pairing-store у сценаріях міграції allowlist. +- `channels.telegram.actions.poll`: увімкнути або вимкнути створення Telegram poll (за замовчуванням: увімкнено; усе ще потребує `sendMessage`). +- `channels.telegram.defaultTo`: ціль Telegram за замовчуванням, яку CLI `--deliver` використовує, коли не вказано явний `--reply-to`. - `channels.telegram.groupPolicy`: `open | allowlist | disabled` (за замовчуванням: allowlist). -- `channels.telegram.groupAllowFrom`: allowlist відправників у групах (числові ID користувачів Telegram). `openclaw doctor --fix` може розв’язати застарілі записи `@username` до ID. Нечислові записи ігноруються під час авторизації. Авторизація груп не використовує резервне значення зі сховища DM pairing (`2026.2.25+`). -- Пріоритет для кількох облікових записів: - - Коли налаштовано два або більше ID облікових записів, задайте `channels.telegram.defaultAccount` (або включіть `channels.telegram.accounts.default`), щоб явно визначити типову маршрутизацію. - - Якщо не задано жодного з них, OpenClaw використовує перший нормалізований ID облікового запису як резервне значення, а `openclaw doctor` показує попередження. +- `channels.telegram.groupAllowFrom`: allowlist відправників у групах (числові ID користувачів Telegram). `openclaw doctor --fix` може розв’язати застарілі записи `@username` до ID. Нечислові записи ігноруються під час auth. Авторизація груп не використовує fallback до pairing-store для DM (`2026.2.25+`). +- Пріоритетність multi-account: + - Коли налаштовано два або більше ID облікових записів, задайте `channels.telegram.defaultAccount` (або включіть `channels.telegram.accounts.default`), щоб явно визначити маршрутизацію за замовчуванням. + - Якщо не задано жодне з них, OpenClaw резервно використовує перший нормалізований ID облікового запису, а `openclaw doctor` показує попередження. - `channels.telegram.accounts.default.allowFrom` і `channels.telegram.accounts.default.groupAllowFrom` застосовуються лише до облікового запису `default`. - Іменовані облікові записи успадковують `channels.telegram.allowFrom` і `channels.telegram.groupAllowFrom`, коли значення на рівні облікового запису не задані. - Іменовані облікові записи не успадковують `channels.telegram.accounts.default.allowFrom` / `groupAllowFrom`. -- `channels.telegram.groups`: типові значення для груп + allowlist (використовуйте `"*"` для глобальних типових значень). - - `channels.telegram.groups..groupPolicy`: перевизначення `groupPolicy` для окремої групи (`open | allowlist | disabled`). - - `channels.telegram.groups..requireMention`: типове керування обов’язковістю згадування. - - `channels.telegram.groups..skills`: фільтр Skills (не вказано = усі Skills, порожньо = жодного). +- `channels.telegram.groups`: значення за замовчуванням для окремих груп + allowlist (використовуйте `"*"` для глобальних значень за замовчуванням). + - `channels.telegram.groups..groupPolicy`: перевизначення groupPolicy для окремої групи (`open | allowlist | disabled`). + - `channels.telegram.groups..requireMention`: значення за замовчуванням для керування згадуваннями. + - `channels.telegram.groups..skills`: фільтр Skills (пропущено = усі Skills, порожньо = жодного). - `channels.telegram.groups..allowFrom`: перевизначення allowlist відправників для окремої групи. - `channels.telegram.groups..systemPrompt`: додатковий системний prompt для групи. - - `channels.telegram.groups..enabled`: вимикає групу, коли `false`. - - `channels.telegram.groups..topics..*`: перевизначення для окремої теми (поля групи + лише для теми `agentId`). - - `channels.telegram.groups..topics..agentId`: маршрутизує цю тему до конкретного агента (перевизначає маршрутизацію рівня групи та binding). -- `channels.telegram.groups..topics..groupPolicy`: перевизначення `groupPolicy` для окремої теми (`open | allowlist | disabled`). -- `channels.telegram.groups..topics..requireMention`: перевизначення обов’язковості згадування для окремої теми. -- верхньорівневі `bindings[]` з `type: "acp"` і канонічним ID теми `chatId:topic:topicId` у `match.peer.id`: поля постійного прив’язування тем ACP (див. [ACP Agents](/uk/tools/acp-agents#channel-specific-settings)). -- `channels.telegram.direct..topics..agentId`: маршрутизує теми DM до конкретного агента (та сама поведінка, що й для форумних тем). -- `channels.telegram.execApprovals.enabled`: увімкнути Telegram як клієнт схвалення exec на основі чату для цього облікового запису. -- `channels.telegram.execApprovals.approvers`: ID користувачів Telegram, яким дозволено схвалювати або відхиляти запити exec. Необов’язково, якщо `channels.telegram.allowFrom` або прямий `channels.telegram.defaultTo` вже ідентифікує власника. -- `channels.telegram.execApprovals.target`: `dm | channel | both` (за замовчуванням: `dm`). `channel` і `both` зберігають вихідну тему Telegram, якщо вона є. -- `channels.telegram.execApprovals.agentFilter`: необов’язковий фільтр ID агента для пересланих запитів на схвалення. -- `channels.telegram.execApprovals.sessionFilter`: необов’язковий фільтр ключа сесії (підрядок або regex) для пересланих запитів на схвалення. -- `channels.telegram.accounts..execApprovals`: перевизначення маршрутизації схвалення exec Telegram та авторизації схвалювачів для окремого облікового запису. + - `channels.telegram.groups..enabled`: вимкнути групу, коли `false`. + - `channels.telegram.groups..topics..*`: перевизначення для окремої теми (поля групи + поле теми `agentId`). + - `channels.telegram.groups..topics..agentId`: маршрутизувати цю тему до конкретного агента (перевизначає маршрутизацію рівня групи та bindings). +- `channels.telegram.groups..topics..groupPolicy`: перевизначення groupPolicy для окремої теми (`open | allowlist | disabled`). +- `channels.telegram.groups..topics..requireMention`: перевизначення керування згадуваннями для окремої теми. +- верхньорівневий `bindings[]` з `type: "acp"` і канонічним ID теми `chatId:topic:topicId` у `match.peer.id`: поля постійної ACP-прив’язки теми (див. [ACP Agents](/uk/tools/acp-agents#channel-specific-settings)). +- `channels.telegram.direct..topics..agentId`: маршрутизувати теми DM до конкретного агента (та сама поведінка, що й у тем форуму). +- `channels.telegram.execApprovals.enabled`: увімкнути Telegram як chat-based клієнт погодження exec для цього облікового запису. +- `channels.telegram.execApprovals.approvers`: ID користувачів Telegram, яким дозволено погоджувати або відхиляти exec-запити. Необов’язково, якщо `channels.telegram.allowFrom` або прямий `channels.telegram.defaultTo` уже визначає власника. +- `channels.telegram.execApprovals.target`: `dm | channel | both` (за замовчуванням: `dm`). `channel` і `both` зберігають початкову тему Telegram, якщо вона є. +- `channels.telegram.execApprovals.agentFilter`: необов’язковий фільтр ID агента для переспрямованих запитів на погодження. +- `channels.telegram.execApprovals.sessionFilter`: необов’язковий фільтр ключа сесії (підрядок або regex) для переспрямованих запитів на погодження. +- `channels.telegram.accounts..execApprovals`: перевизначення маршрутизації погодження exec у Telegram і авторизації погоджувачів для окремого облікового запису. - `channels.telegram.capabilities.inlineButtons`: `off | dm | group | all | allowlist` (за замовчуванням: allowlist). - `channels.telegram.accounts..capabilities.inlineButtons`: перевизначення для окремого облікового запису. - `channels.telegram.commands.nativeSkills`: увімкнути/вимкнути нативні команди Skills у Telegram. - `channels.telegram.replyToMode`: `off | first | all` (за замовчуванням: `off`). -- `channels.telegram.textChunkLimit`: розмір вихідного фрагмента (символи). +- `channels.telegram.textChunkLimit`: розмір вихідного chunk (символи). - `channels.telegram.chunkMode`: `length` (за замовчуванням) або `newline`, щоб розбивати за порожніми рядками (межами абзаців) перед розбиттям за довжиною. - `channels.telegram.linkPreview`: перемикач попереднього перегляду посилань для вихідних повідомлень (за замовчуванням: true). -- `channels.telegram.streaming`: `off | partial | block | progress` (потоковий попередній перегляд у реальному часі; за замовчуванням: `partial`; `progress` відображається як `partial`; `block` — сумісність із застарілим режимом попереднього перегляду). Потоковий попередній перегляд у Telegram використовує одне повідомлення попереднього перегляду, яке редагується на місці. -- `channels.telegram.streaming.preview.toolProgress`: повторно використовувати повідомлення потокового попереднього перегляду для оновлень tool/progress, коли потоковий попередній перегляд активний (за замовчуванням: `true`). Задайте `false`, щоб залишити окремі повідомлення tool/progress. -- `channels.telegram.mediaMaxMb`: обмеження розміру вхідних/вихідних медіа Telegram (МБ, за замовчуванням: 100). -- `channels.telegram.retry`: політика повторних спроб для допоміжних функцій надсилання Telegram (CLI/tools/actions) у разі відновлюваних вихідних помилок API (attempts, minDelayMs, maxDelayMs, jitter). +- `channels.telegram.streaming`: `off | partial | block | progress` (попередній перегляд live stream; за замовчуванням: `partial`; `progress` зіставляється з `partial`; `block` — сумісність із застарілим режимом попереднього перегляду). Preview streaming у Telegram використовує одне повідомлення попереднього перегляду, яке редагується на місці. +- `channels.telegram.streaming.preview.toolProgress`: повторно використовувати повідомлення live preview для оновлень tool/progress, коли preview streaming активний (за замовчуванням: `true`). Встановіть `false`, щоб залишати окремі повідомлення tool/progress. +- `channels.telegram.mediaMaxMb`: обмеження медіа Telegram для вхідних/вихідних даних (МБ, за замовчуванням: 100). +- `channels.telegram.retry`: політика повторних спроб для допоміжних засобів надсилання Telegram (CLI/tools/actions) у разі відновлюваних вихідних помилок API (attempts, minDelayMs, maxDelayMs, jitter). - `channels.telegram.network.autoSelectFamily`: перевизначити Node autoSelectFamily (true=увімкнути, false=вимкнути). За замовчуванням увімкнено в Node 22+, а в WSL2 за замовчуванням вимкнено. -- `channels.telegram.network.dnsResultOrder`: перевизначити порядок результатів DNS (`ipv4first` або `verbatim`). У Node 22+ за замовчуванням `ipv4first`. -- `channels.telegram.network.dangerouslyAllowPrivateNetwork`: небезпечне явне ввімкнення для довірених середовищ fake-IP або transparent-proxy, де завантаження медіа Telegram визначають `api.telegram.org` у приватні/внутрішні/special-use адреси поза типовим дозволеним діапазоном RFC 2544 benchmark. +- `channels.telegram.network.dnsResultOrder`: перевизначити порядок DNS-результатів (`ipv4first` або `verbatim`). За замовчуванням у Node 22+ використовується `ipv4first`. +- `channels.telegram.network.dangerouslyAllowPrivateNetwork`: небезпечне явне ввімкнення для довірених середовищ fake-IP або transparent-proxy, де завантаження медіа Telegram резолвлять `api.telegram.org` у приватні/внутрішні/special-use адреси поза стандартно дозволеним діапазоном benchmark RFC 2544. - `channels.telegram.proxy`: URL proxy для викликів Bot API (SOCKS/HTTP). -- `channels.telegram.webhookUrl`: увімкнути режим Webhook (потрібен `channels.telegram.webhookSecret`). +- `channels.telegram.webhookUrl`: увімкнути режим Webhook (потребує `channels.telegram.webhookSecret`). - `channels.telegram.webhookSecret`: секрет Webhook (обов’язковий, коли задано webhookUrl). - `channels.telegram.webhookPath`: локальний шлях Webhook (за замовчуванням `/telegram-webhook`). -- `channels.telegram.webhookHost`: локальний хост прив’язування Webhook (за замовчуванням `127.0.0.1`). -- `channels.telegram.webhookPort`: локальний порт прив’язування Webhook (за замовчуванням `8787`). -- `channels.telegram.actions.reactions`: керування реакціями інструментів Telegram. -- `channels.telegram.actions.sendMessage`: керування надсиланням повідомлень інструментів Telegram. -- `channels.telegram.actions.deleteMessage`: керування видаленням повідомлень інструментів Telegram. -- `channels.telegram.actions.sticker`: керування діями зі стікерами Telegram — надсиланням і пошуком (за замовчуванням: false). -- `channels.telegram.reactionNotifications`: `off | own | all` — керує тим, які реакції запускають системні події (за замовчуванням: `own`, якщо не задано). -- `channels.telegram.reactionLevel`: `off | ack | minimal | extensive` — керує можливостями реакцій агента (за замовчуванням: `minimal`, якщо не задано). -- `channels.telegram.errorPolicy`: `reply | silent` — керує поведінкою відповідей про помилки (за замовчуванням: `reply`). Підтримуються перевизначення для окремого облікового запису/групи/теми. -- `channels.telegram.errorCooldownMs`: мінімальна кількість мс між відповідями про помилки в одному чаті (за замовчуванням: `60000`). Запобігає спаму помилок під час збоїв. +- `channels.telegram.webhookHost`: локальний host прив’язки Webhook (за замовчуванням `127.0.0.1`). +- `channels.telegram.webhookPort`: локальний port прив’язки Webhook (за замовчуванням `8787`). +- `channels.telegram.actions.reactions`: керування реакціями tool у Telegram. +- `channels.telegram.actions.sendMessage`: керування надсиланням повідомлень tool у Telegram. +- `channels.telegram.actions.deleteMessage`: керування видаленням повідомлень tool у Telegram. +- `channels.telegram.actions.sticker`: керування діями зі стікерами Telegram — надсилання і пошук (за замовчуванням: false). +- `channels.telegram.reactionNotifications`: `off | own | all` — керування тим, які реакції запускають системні події (за замовчуванням: `own`, якщо не задано). +- `channels.telegram.reactionLevel`: `off | ack | minimal | extensive` — керування можливістю агента працювати з реакціями (за замовчуванням: `minimal`, якщо не задано). +- `channels.telegram.errorPolicy`: `reply | silent` — керування поведінкою відповідей на помилки (за замовчуванням: `reply`). Підтримуються перевизначення для окремого облікового запису/групи/теми. +- `channels.telegram.errorCooldownMs`: мінімальна кількість мс між відповідями з помилками в тому самому чаті (за замовчуванням: `60000`). Запобігає спаму помилок під час збоїв. - [Довідник конфігурації - Telegram](/uk/gateway/configuration-reference#telegram) -Поля Telegram із високою інформаційною цінністю: +Поля Telegram з найвищим сигналом: -- запуск/автентифікація: `enabled`, `botToken`, `tokenFile`, `accounts.*` (`tokenFile` має вказувати на звичайний файл; символічні посилання відхиляються) -- контроль доступу: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, верхньорівневі `bindings[]` (`type: "acp"`) -- схвалення exec: `execApprovals`, `accounts.*.execApprovals` -- команда/меню: `commands.native`, `commands.nativeSkills`, `customCommands` +- запуск/auth: `enabled`, `botToken`, `tokenFile`, `accounts.*` (`tokenFile` має вказувати на звичайний файл; symlink-і відхиляються) +- керування доступом: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`, `groups.*.topics.*`, верхньорівневий `bindings[]` (`type: "acp"`) +- погодження exec: `execApprovals`, `accounts.*.execApprovals` +- команди/меню: `commands.native`, `commands.nativeSkills`, `customCommands` - потоки/відповіді: `replyToMode` -- streaming: `streaming` (попередній перегляд), `streaming.preview.toolProgress`, `blockStreaming` +- streaming: `streaming` (preview), `streaming.preview.toolProgress`, `blockStreaming` - форматування/доставка: `textChunkLimit`, `chunkMode`, `linkPreview`, `responsePrefix` - медіа/мережа: `mediaMaxMb`, `timeoutSeconds`, `pollingStallThresholdMs`, `retry`, `network.autoSelectFamily`, `network.dangerouslyAllowPrivateNetwork`, `proxy` - webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost` @@ -1085,9 +1076,9 @@ dig +short api.telegram.org AAAA ## Пов’язане -- [Зв’язування](/uk/channels/pairing) +- [Підключення](/uk/channels/pairing) - [Групи](/uk/channels/groups) - [Безпека](/uk/gateway/security) - [Маршрутизація каналів](/uk/channels/channel-routing) -- [Маршрутизація кількох агентів](/uk/concepts/multi-agent) +- [Маршрутизація між кількома агентами](/uk/concepts/multi-agent) - [Усунення проблем](/uk/channels/troubleshooting) diff --git a/docs/uk/gateway/health.md b/docs/uk/gateway/health.md index 056e99a7a..2dc2960a8 100644 --- a/docs/uk/gateway/health.md +++ b/docs/uk/gateway/health.md @@ -1,68 +1,70 @@ --- read_when: - - Діагностика підключення каналів або стану gateway - - Розуміння команд CLI для перевірки стану та їх параметрів -summary: Команди перевірки стану та моніторинг стану gateway + - Діагностика підключення каналу або стану Gateway + - Розуміння CLI-команд перевірки стану та їхніх параметрів +summary: Команди перевірки стану та моніторинг стану Gateway title: Перевірки стану x-i18n: - generated_at: "2026-04-05T18:03:16Z" + generated_at: "2026-04-23T00:49:06Z" model: gpt-5.4 provider: openai - source_hash: b8824bca34c4d1139f043481c75f0a65d83e54008898c34cf69c6f98fd04e819 + source_hash: 5ddcbe6fa913c5ba889f78cb417124c96b562cf8939410b1d6f66042dfb51a9f source_path: gateway/health.md workflow: 15 --- # Перевірки стану (CLI) -Короткий посібник, як перевірити підключення каналів без здогадок. +Короткий посібник, як перевірити підключення каналу без здогадок. ## Швидкі перевірки -- `openclaw status` — локальний підсумок: доступність/режим gateway, підказка про оновлення, давність автентифікації підключених каналів, сесії та нещодавня активність. +- `openclaw status` — локальне зведення: доступність/режим Gateway, підказка щодо оновлення, вік автентифікації пов’язаного каналу, сесії та нещодавня активність. - `openclaw status --all` — повна локальна діагностика (лише читання, кольоровий вивід, безпечно вставляти для налагодження). -- `openclaw status --deep` — звертається до запущеного gateway для живої перевірки стану (`health` з `probe:true`), включно з перевірками каналів для кожного облікового запису, якщо це підтримується. -- `openclaw health` — звертається до запущеного gateway за знімком його стану (лише WS; CLI не відкриває прямі сокети каналів). -- `openclaw health --verbose` — примусово запускає живу перевірку стану і виводить відомості про підключення gateway. +- `openclaw status --deep` — запитує у запущеного Gateway живу перевірку стану (`health` з `probe:true`), зокрема перевірки каналів для кожного облікового запису, якщо це підтримується. +- `openclaw health` — запитує у запущеного Gateway знімок його стану (лише WS; без прямих сокетів каналів із CLI). +- `openclaw health --verbose` — примусово запускає живу перевірку стану та виводить деталі підключення Gateway. - `openclaw health --json` — машинозчитуваний вивід знімка стану. -- Надішліть `/status` як окреме повідомлення у WhatsApp/WebChat, щоб отримати відповідь зі станом без запуску агента. -- Журнали: виконайте tail для `/tmp/openclaw/openclaw-*.log` і відфільтруйте `web-heartbeat`, `web-reconnect`, `web-auto-reply`, `web-inbound`. +- Надішліть `/status` як окреме повідомлення у WhatsApp/WebChat, щоб отримати відповідь зі станом без виклику агента. +- Логи: переглядайте `/tmp/openclaw/openclaw-*.log` і фільтруйте за `web-heartbeat`, `web-reconnect`, `web-auto-reply`, `web-inbound`. -## Глибока діагностика +## Поглиблена діагностика - Облікові дані на диску: `ls -l ~/.openclaw/credentials/whatsapp//creds.json` (`mtime` має бути нещодавнім). -- Сховище сесій: `ls -l ~/.openclaw/agents//sessions/sessions.json` (шлях можна перевизначити в конфігурації). Кількість і нещодавні отримувачі відображаються через `status`. -- Повторне прив’язування: `openclaw channels logout && openclaw channels login --verbose`, коли в журналах з’являються коди стану 409–515 або `loggedOut`. (Примітка: після сполучення потік входу через QR автоматично перезапускається один раз для статусу 515.) +- Сховище сесій: `ls -l ~/.openclaw/agents//sessions/sessions.json` (шлях можна перевизначити в конфігурації). Кількість і нещодавні одержувачі відображаються через `status`. +- Повторне пов’язування: `openclaw channels logout && openclaw channels login --verbose`, якщо в логах з’являються коди стану 409–515 або `loggedOut`. (Примітка: після прив’язки потік входу через QR автоматично перезапускається один раз для статусу 515.) +- Діагностика увімкнена за замовчуванням. Gateway записує операційні факти, якщо не встановлено `diagnostics.enabled: false`. Події пам’яті записують кількість байтів RSS/heap, тиск порога та тиск зростання. Події надто великих навантажень записують, що було відхилено, обрізано або розбито на частини, а також розміри й ліміти, якщо вони доступні. Вони не записують текст повідомлення, вміст вкладень, тіло Webhook, необроблене тіло запиту чи відповіді, токени, cookies або секретні значення. Той самий Heartbeat запускає обмежений засіб запису стабільності, доступний через `openclaw gateway stability` або Gateway RPC `diagnostics.stability`. Фатальні завершення Gateway, тайм-аути завершення роботи та збої запуску під час перезапуску зберігають останній знімок цього записувача в `~/.openclaw/logs/stability/`, якщо події існують; перегляньте найновіший збережений пакет за допомогою `openclaw gateway stability --bundle latest`. +- Для звітів про помилки виконайте `openclaw gateway diagnostics export` і додайте згенерований zip-файл. Експорт об’єднує підсумок у Markdown, найновіший пакет стабільності, очищені метадані логів, очищені знімки стану/здоров’я Gateway і форму конфігурації. Він призначений для поширення: текст чату, тіла Webhook, виводи інструментів, облікові дані, cookies, ідентифікатори облікових записів/повідомлень і секретні значення пропускаються або редагуються. ## Конфігурація монітора стану -- `gateway.channelHealthCheckMinutes`: як часто gateway перевіряє стан каналів. Типове значення: `5`. Установіть `0`, щоб глобально вимкнути перезапуски монітора стану. -- `gateway.channelStaleEventThresholdMinutes`: як довго підключений канал може залишатися без подій, перш ніж монітор стану вважатиме його застарілим і перезапустить. Типове значення: `30`. Зберігайте це значення більшим або рівним `gateway.channelHealthCheckMinutes`. -- `gateway.channelMaxRestartsPerHour`: ковзне обмеження на одну годину для перезапусків монітора стану на канал/обліковий запис. Типове значення: `10`. -- `channels..healthMonitor.enabled`: вимкнути перезапуски монітора стану для конкретного каналу, залишивши глобальний моніторинг увімкненим. +- `gateway.channelHealthCheckMinutes`: як часто Gateway перевіряє стан каналу. Типове значення: `5`. Встановіть `0`, щоб глобально вимкнути перезапуски монітора стану. +- `gateway.channelStaleEventThresholdMinutes`: як довго підключений канал може залишатися неактивним, перш ніж монітор стану вважатиме його застарілим і перезапустить. Типове значення: `30`. Тримайте це значення більшим або рівним `gateway.channelHealthCheckMinutes`. +- `gateway.channelMaxRestartsPerHour`: ковзне обмеження на одну годину для перезапусків монітором стану на канал/обліковий запис. Типове значення: `10`. +- `channels..healthMonitor.enabled`: вимикає перезапуски монітора стану для конкретного каналу, залишаючи глобальний моніторинг увімкненим. - `channels..accounts..healthMonitor.enabled`: перевизначення для кількох облікових записів, яке має пріоритет над налаштуванням на рівні каналу. -- Ці перевизначення для окремих каналів застосовуються до вбудованих моніторів каналів, які наразі їх підтримують: Discord, Google Chat, iMessage, Microsoft Teams, Signal, Slack, Telegram і WhatsApp. +- Ці перевизначення на рівні каналу застосовуються до вбудованих моніторів каналів, які наразі їх підтримують: Discord, Google Chat, iMessage, Microsoft Teams, Signal, Slack, Telegram і WhatsApp. -## Якщо щось не працює +## Коли щось не працює -- `logged out` або статус 409–515 → виконайте повторне прив’язування через `openclaw channels logout`, потім `openclaw channels login`. -- Gateway недоступний → запустіть його: `openclaw gateway --port 18789` (використовуйте `--force`, якщо порт зайнятий). -- Немає вхідних повідомлень → переконайтеся, що підключений телефон онлайн і відправника дозволено (`channels.whatsapp.allowFrom`); для групових чатів переконайтеся, що список дозволу + правила згадування налаштовано правильно (`channels.whatsapp.groups`, `agents.list[].groupChat.mentionPatterns`). +- `logged out` або статус 409–515 → виконайте повторне пов’язування через `openclaw channels logout`, а потім `openclaw channels login`. +- Gateway недоступний → запустіть його: `openclaw gateway --port 18789` (використайте `--force`, якщо порт зайнятий). +- Немає вхідних повідомлень → переконайтеся, що пов’язаний телефон онлайн і відправника дозволено (`channels.whatsapp.allowFrom`); для групових чатів переконайтеся, що правила allowlist і згадок збігаються (`channels.whatsapp.groups`, `agents.list[].groupChat.mentionPatterns`). ## Окрема команда "health" -`openclaw health` звертається до запущеного gateway за знімком його стану (CLI не відкриває прямі сокети -каналів). Типово вона може повертати свіжий кешований знімок gateway; після цього -gateway оновлює цей кеш у фоновому режимі. `openclaw health --verbose` натомість примусово -запускає живу перевірку. Команда повідомляє про вік підключених creds/auth, якщо доступно, -підсумки перевірок по каналах, підсумок сховища сесій і тривалість перевірки. Вона завершується -з ненульовим кодом, якщо gateway недоступний або перевірка не вдалася/перевищила час очікування. +`openclaw health` запитує у запущеного Gateway знімок його стану (без прямих сокетів +каналів із CLI). За замовчуванням вона може повертати свіжий кешований знімок Gateway; після цього +Gateway оновлює цей кеш у фоновому режимі. `openclaw health --verbose` натомість примусово виконує +живу перевірку. Команда повідомляє про пов’язані облікові дані/вік автентифікації, якщо доступно, +зведення перевірок для кожного каналу, зведення сховища сесій і тривалість перевірки. Вона завершується з ненульовим кодом, +якщо Gateway недоступний або перевірка не вдалася/перевищила час очікування. Параметри: - `--json`: машинозчитуваний JSON-вивід -- `--timeout `: перевизначити типове значення тайм-ауту перевірки 10 с -- `--verbose`: примусово запустити живу перевірку і вивести відомості про підключення gateway +- `--timeout `: перевизначає типовий тайм-аут перевірки 10 с +- `--verbose`: примусово запускає живу перевірку й виводить деталі підключення Gateway - `--debug`: псевдонім для `--verbose` -Знімок стану включає: `ok` (boolean), `ts` (часова позначка), `durationMs` (час перевірки), стан для кожного каналу, доступність агентів і підсумок сховища сесій. +Знімок стану містить: `ok` (boolean), `ts` (часова позначка), `durationMs` (час перевірки), стан для кожного каналу, доступність агента та зведення сховища сесій. diff --git a/docs/uk/gateway/protocol.md b/docs/uk/gateway/protocol.md index f03e3e9c3..c5cd33d82 100644 --- a/docs/uk/gateway/protocol.md +++ b/docs/uk/gateway/protocol.md @@ -1,34 +1,40 @@ --- read_when: - - Реалізація або оновлення клієнтів Gateway WS + - Реалізація або оновлення клієнтів шлюзу WS - Налагодження невідповідностей протоколу або збоїв підключення - - Повторне генерування схем/моделей протоколу + - Повторне генерування схеми/моделей протоколу summary: 'Протокол Gateway WebSocket: рукостискання, кадри, версіонування' title: Протокол Gateway x-i18n: - generated_at: "2026-04-21T20:16:17Z" + generated_at: "2026-04-23T00:49:07Z" model: gpt-5.4 provider: openai - source_hash: 6efa76f5f0faa6c10a8515b0cf457233e48551e3484a605dffaf6459ddff9231 + source_hash: 9d4ea65fbe31962ed8ece04a645cfe5aaff9fee8b5f89bc896b461cd45567634 source_path: gateway/protocol.md workflow: 15 --- # Протокол Gateway (WebSocket) -Протокол Gateway WS — це **єдина контрольна площина + транспорт вузлів** для -OpenClaw. Усі клієнти (CLI, веб-інтерфейс, програма macOS, вузли iOS/Android, headless -вузли) підключаються через WebSocket і оголошують свою **роль** + **область -доступу** під час рукостискання. +Протокол Gateway WS — це **єдина контрольна площина + транспорт Node** для +OpenClaw. Усі клієнти (CLI, веб-інтерфейс, застосунок macOS, Node iOS/Android, headless +Node) підключаються через WebSocket і оголошують свою **роль** + **область видимості** під час рукостискання. ## Транспорт -- WebSocket, текстові кадри з корисним навантаженням JSON. +- WebSocket, текстові кадри з JSON-корисним навантаженням. - Перший кадр **має** бути запитом `connect`. +- Кадри до підключення обмежені 64 KiB. Після успішного рукостискання клієнти + повинні дотримуватися обмежень `hello-ok.policy.maxPayload` і + `hello-ok.policy.maxBufferedBytes`. Коли діагностику ввімкнено, + надто великі вхідні кадри й повільні вихідні буфери генерують події `payload.large` + до того, як Gateway закриє з’єднання або відкине відповідний кадр. Ці події зберігають + розміри, обмеження, поверхні та безпечні коди причин. Вони не зберігають тіло повідомлення, + вміст вкладень, тіло необробленого кадру, токени, cookie або секретні значення. ## Рукостискання (connect) -Gateway → Клієнт (виклик перед підключенням): +Gateway → клієнт (виклик до підключення): ```json { @@ -73,7 +79,7 @@ Gateway → Клієнт (виклик перед підключенням): } ``` -Gateway → Клієнт: +Gateway → клієнт: ```json { @@ -95,13 +101,13 @@ Gateway → Клієнт: } ``` -`server`, `features`, `snapshot` і `policy` усі є обов’язковими за схемою +`server`, `features`, `snapshot` і `policy` — усі обов’язкові за схемою (`src/gateway/protocol/schema/frames.ts`). `canvasHostUrl` є необов’язковим. `auth` -повідомляє про погоджені роль/області доступу, коли вони доступні, а також включає `deviceToken`, -коли gateway його видає. +повідомляє про узгоджені роль/області видимості, коли вони доступні, і містить `deviceToken`, +коли Gateway його видає. -Коли токен пристрою не видається, `hello-ok.auth` все одно може повідомляти про -погоджені дозволи: +Коли токен пристрою не видається, `hello-ok.auth` усе одно може повідомляти про узгоджені +дозволи: ```json { @@ -112,7 +118,7 @@ Gateway → Клієнт: } ``` -Коли токен пристрою видається, `hello-ok` також включає: +Коли токен пристрою видається, `hello-ok` також містить: ```json { @@ -124,8 +130,8 @@ Gateway → Клієнт: } ``` -Під час довіреної передачі bootstrap `hello-ok.auth` також може включати додаткові -записи ролей з обмеженнями в `deviceTokens`: +Під час trusted bootstrap handoff `hello-ok.auth` також може містити додаткові +обмежені записи ролей у `deviceTokens`: ```json { @@ -144,15 +150,14 @@ Gateway → Клієнт: } ``` -Для вбудованого bootstrap-потоку node/operator основний токен вузла залишається -`scopes: []`, а будь-який переданий токен оператора залишається обмеженим списком -дозволених bootstrap-областей оператора (`operator.approvals`, `operator.read`, -`operator.talk.secrets`, `operator.write`). Перевірки bootstrap-областей доступу -залишаються прив’язаними до префікса ролі: записи оператора задовольняють лише -запити оператора, а ролям, які не є оператором, усе одно потрібні області доступу -під власним префіксом ролі. +Для вбудованого потоку bootstrap node/operator основний токен node лишається +`scopes: []`, а будь-який переданий токен operator лишається обмеженим списком дозволів +bootstrap operator (`operator.approvals`, `operator.read`, +`operator.talk.secrets`, `operator.write`). Перевірки областей видимості bootstrap лишаються +прив’язаними до префікса ролі: записи operator задовольняють лише запити operator, а ролі, що не є operator, +усе одно потребують областей видимості під власним префіксом ролі. -### Приклад node +### Приклад Node ```json { @@ -187,7 +192,7 @@ Gateway → Клієнт: } ``` -## Форматування кадрів +## Кадрування - **Запит**: `{type:"req", id, method, params}` - **Відповідь**: `{type:"res", id, ok, payload|error}` @@ -195,16 +200,16 @@ Gateway → Клієнт: Методи з побічними ефектами вимагають **ключі ідемпотентності** (див. схему). -## Ролі + області доступу +## Ролі + області видимості ### Ролі - `operator` = клієнт контрольної площини (CLI/UI/автоматизація). - `node` = хост можливостей (camera/screen/canvas/system.run). -### Області доступу (operator) +### Області видимості (operator) -Поширені області доступу: +Поширені області видимості: - `operator.read` - `operator.write` @@ -216,150 +221,154 @@ Gateway → Клієнт: `talk.config` з `includeSecrets: true` вимагає `operator.talk.secrets` (або `operator.admin`). -Зареєстровані Plugin методи Gateway RPC можуть запитувати власну область доступу -оператора, але зарезервовані префікси базового адміністрування (`config.*`, `exec.approvals.*`, `wizard.*`, +Методи Gateway RPC, зареєстровані Plugin, можуть запитувати власну область видимості operator, але +зарезервовані базові префікси адміністратора (`config.*`, `exec.approvals.*`, `wizard.*`, `update.*`) завжди зіставляються з `operator.admin`. -Область доступу методу — це лише перший рівень перевірки. Деякі slash-команди, -до яких звертаються через `chat.send`, застосовують суворіші перевірки на рівні -команди поверх цього. Наприклад, постійні записи -`/config set` і `/config unset` вимагають `operator.admin`. +Область видимості методу — лише перший бар’єр. Деякі slash-команди, доступні через +`chat.send`, додатково застосовують суворіші перевірки на рівні команд. Наприклад, сталі +записи `/config set` і `/config unset` вимагають `operator.admin`. -`node.pair.approve` також має додаткову перевірку області доступу під час -схвалення поверх базової області доступу методу: +`node.pair.approve` також має додаткову перевірку області видимості під час схвалення поверх +базової області видимості методу: -- запити без команд: `operator.pairing` -- запити з командами вузла, які не є exec: `operator.pairing` + `operator.write` -- запити, що включають `system.run`, `system.run.prepare` або `system.which`: +- запити без команди: `operator.pairing` +- запити з командами node, що не належать до exec: `operator.pairing` + `operator.write` +- запити, які містять `system.run`, `system.run.prepare` або `system.which`: `operator.pairing` + `operator.admin` ### Caps/commands/permissions (node) -Вузли оголошують заявлені можливості під час підключення: +Node оголошують твердження про можливості під час підключення: - `caps`: високорівневі категорії можливостей. - `commands`: список дозволених команд для invoke. - `permissions`: детальні перемикачі (наприклад, `screen.record`, `camera.capture`). -Gateway розглядає їх як **заяви** і застосовує списки дозволених значень на боці сервера. +Gateway трактує це як **заявлені можливості** та забезпечує примусові списки дозволів на боці сервера. ## Presence -- `system-presence` повертає записи з ключами за ідентичністю пристрою. -- Записи присутності включають `deviceId`, `roles` і `scopes`, щоб інтерфейси могли показувати один рядок на пристрій, - навіть коли він підключається і як **operator**, і як **node**. +- `system-presence` повертає записи, згруповані за ідентичністю пристрою. +- Записи presence містять `deviceId`, `roles` і `scopes`, щоб UI міг показувати один рядок на пристрій, + навіть коли він підключений і як **operator**, і як **node**. -## Обмеження областей доступу для широкомовних подій +## Обмеження областей видимості для broadcast-подій -Широкомовні події WebSocket, які надсилає сервер, обмежуються за областями доступу, щоб сесії з лише pairing-доступом або лише node-сесії не отримували пасивно вміст сесії. +Broadcast-події WebSocket, які сервер надсилає клієнтам, обмежуються областями видимості, щоб сесії лише з pairing-областю або сесії тільки для node не отримували пасивно вміст сесій. -- **Кадри chat, agent і результатів інструментів** (включно з потоковими подіями `agent` і результатами викликів інструментів) вимагають щонайменше `operator.read`. Сесії без `operator.read` повністю пропускають ці кадри. -- **Широкомовні події `plugin.*`, визначені Plugin**, обмежуються `operator.write` або `operator.admin` залежно від того, як Plugin їх зареєстрував. -- **Події стану та транспорту** (`heartbeat`, `presence`, `tick`, життєвий цикл connect/disconnect тощо) залишаються без обмежень, щоб стан транспорту залишався видимим для кожної автентифікованої сесії. -- **Невідомі сімейства широкомовних подій** за замовчуванням обмежуються за областями доступу (fail-closed), якщо зареєстрований обробник явно не послаблює це. +- **Кадри chat, agent і tool-result** (включно з потоковими подіями `agent` і результатами викликів інструментів) вимагають щонайменше `operator.read`. Сесії без `operator.read` повністю пропускають ці кадри. +- **Broadcast-події `plugin.*`, визначені Plugin**, обмежуються `operator.write` або `operator.admin` залежно від того, як Plugin їх зареєстрував. +- **Події стану й транспорту** (`heartbeat`, `presence`, `tick`, життєвий цикл connect/disconnect тощо) лишаються без обмежень, щоб стан транспорту залишався спостережуваним для кожної автентифікованої сесії. +- **Невідомі сімейства broadcast-подій** за замовчуванням обмежуються областями видимості (fail-closed), якщо зареєстрований обробник явно не послаблює це правило. -Кожне клієнтське підключення зберігає власний номер послідовності для цього клієнта, щоб широкомовні повідомлення зберігали монотонний порядок на цьому сокеті, навіть коли різні клієнти бачать різні підмножини потоку подій, відфільтровані за областями доступу. +Кожне клієнтське з’єднання підтримує власний номер послідовності для конкретного клієнта, тому broadcast-події зберігають монотонне впорядкування на цьому сокеті, навіть коли різні клієнти бачать різні підмножини потоку подій, відфільтровані за областями видимості. -## Поширені сімейства методів RPC +## Поширені сімейства RPC-методів Ця сторінка не є згенерованим повним дампом, але публічна поверхня WS ширша, -ніж приклади рукостискання/автентифікації вище. Це основні сімейства методів, -які Gateway надає сьогодні. +ніж наведені вище приклади рукостискання/автентифікації. Це основні сімейства методів, які +Gateway відкриває сьогодні. -`hello-ok.features.methods` — це консервативний список виявлення, побудований з -`src/gateway/server-methods-list.ts` плюс експортів методів завантажених plugin/channel. -Сприймайте його як виявлення можливостей, а не як згенерований дамп кожного допоміжного виклику, -реалізованого в `src/gateway/server-methods/*.ts`. +`hello-ok.features.methods` — це консервативний список виявлення можливостей, побудований із +`src/gateway/server-methods-list.ts` плюс експорту методів завантажених plugin/channel. +Сприймайте його як виявлення можливостей, а не як згенерований дамп усіх допоміжних викликів, +реалізованих у `src/gateway/server-methods/*.ts`. ### Система та ідентичність -- `health` повертає кешований або щойно перевірений знімок стану gateway. -- `status` повертає зведення gateway у стилі `/status`; чутливі поля - включаються лише для операторських клієнтів з admin-областю доступу. -- `gateway.identity.get` повертає ідентичність пристрою gateway, яка використовується в relay і - потоках pairing. -- `system-presence` повертає поточний знімок присутності для підключених +- `health` повертає кешований або щойно перевірений знімок стану Gateway. +- `diagnostics.stability` повертає нещодавній обмежений засіб запису діагностичної + стабільності. Він зберігає операційні метадані, такі як назви подій, кількість, розміри в байтах, + показники пам’яті, стан черги/сесії, назви channel/plugin і ідентифікатори сесій. + Він не зберігає текст chat, тіла webhook, вивід інструментів, необроблені тіла запитів або + відповідей, токени, cookie чи секретні значення. Потрібна область видимості operator read. +- `status` повертає підсумок Gateway у стилі `/status`; чутливі поля + включаються лише для клієнтів operator з областю видимості admin. +- `gateway.identity.get` повертає ідентичність пристрою Gateway, що використовується в потоках relay і + pairing. +- `system-presence` повертає поточний знімок presence для підключених пристроїв operator/node. -- `system-event` додає системну подію і може оновлювати/транслювати контекст - присутності. +- `system-event` додає системну подію та може оновлювати/транслювати контекст + presence. - `last-heartbeat` повертає останню збережену подію Heartbeat. -- `set-heartbeats` перемикає обробку Heartbeat на gateway. +- `set-heartbeats` перемикає обробку Heartbeat на Gateway. ### Моделі та використання -- `models.list` повертає каталог моделей, дозволених у середовищі виконання. -- `usage.status` повертає зведення вікон використання/залишкової квоти провайдерів. -- `usage.cost` повертає зведення агрегованої вартості використання за діапазон дат. -- `doctor.memory.status` повертає стан готовності vector-memory / embedding для +- `models.list` повертає каталог моделей, дозволених у поточному середовищі виконання. +- `usage.status` повертає зведення вікон використання/залишкових квот провайдера. +- `usage.cost` повертає зведення агрегованих витрат використання за діапазон дат. +- `doctor.memory.status` повертає готовність векторної пам’яті / вбудовувань для активного робочого простору агента за замовчуванням. -- `sessions.usage` повертає зведення використання для кожної сесії. +- `sessions.usage` повертає зведення використання за сесіями. - `sessions.usage.timeseries` повертає часовий ряд використання для однієї сесії. - `sessions.usage.logs` повертає записи журналу використання для однієї сесії. ### Канали та допоміжні засоби входу -- `channels.status` повертає зведення стану вбудованих і bundled каналів/plugin. -- `channels.logout` виходить із конкретного каналу/облікового запису, якщо канал +- `channels.status` повертає зведення стану вбудованих і bundled channel/plugin. +- `channels.logout` виходить із конкретного channel/account, якщо channel підтримує вихід. -- `web.login.start` запускає QR/web-потік входу для поточного QR-сумісного веб- - провайдера каналу. -- `web.login.wait` очікує завершення цього QR/web-потоку входу і запускає - канал у разі успіху. -- `push.test` надсилає тестовий APNs push до зареєстрованого вузла iOS. +- `web.login.start` запускає потік входу QR/web для поточного web + channel provider із підтримкою QR. +- `web.login.wait` очікує завершення цього потоку входу QR/web і запускає + channel у разі успіху. +- `push.test` надсилає тестовий APNs push на зареєстрований Node iOS. - `voicewake.get` повертає збережені тригери слова активації. -- `voicewake.set` оновлює тригери слова активації й транслює зміну. +- `voicewake.set` оновлює тригери слова активації та транслює зміну. ### Повідомлення та журнали -- `send` — це прямий RPC вихідної доставки для цільових надсилань - у канал/обліковий запис/гілку поза виконавцем чату. -- `logs.tail` повертає tail налаштованого файлового журналу gateway з курсором/лімітом і - керуванням максимальною кількістю байтів. +- `send` — це прямий RPC доставки назовні для + надсилання до channel/account/thread поза виконавцем chat. +- `logs.tail` повертає хвіст налаштованого файлового журналу Gateway з керуванням курсором/лімітом і + максимальним розміром у байтах. ### Talk і TTS - `talk.config` повертає ефективне корисне навантаження конфігурації Talk; `includeSecrets` вимагає `operator.talk.secrets` (або `operator.admin`). -- `talk.mode` встановлює/транслює поточний стан режиму Talk для клієнтів - WebChat/Control UI. -- `talk.speak` синтезує мовлення через активного провайдера мовлення Talk. +- `talk.mode` установлює/транслює поточний стан режиму Talk для + клієнтів WebChat/Control UI. +- `talk.speak` синтезує мовлення через активного мовленнєвого провайдера Talk. - `tts.status` повертає стан увімкнення TTS, активного провайдера, резервних провайдерів і стан конфігурації провайдера. -- `tts.providers` повертає видимий інвентар провайдерів TTS. +- `tts.providers` повертає видимий перелік провайдерів TTS. - `tts.enable` і `tts.disable` перемикають стан налаштувань TTS. - `tts.setProvider` оновлює бажаного провайдера TTS. -- `tts.convert` виконує одноразове перетворення тексту в мовлення. +- `tts.convert` виконує одноразове перетворення тексту на мовлення. -### Secrets, config, update і wizard +### Секрети, конфігурація, оновлення та майстер налаштування -- `secrets.reload` повторно визначає активні SecretRef і замінює стан секретів середовища виконання +- `secrets.reload` повторно розв’язує активні SecretRefs і замінює стан секретів у середовищі виконання лише за повного успіху. -- `secrets.resolve` визначає призначення секретів для цілі набору - команд/цілей. +- `secrets.resolve` розв’язує призначення секретів для цільових команд для конкретного + набору command/target. - `config.get` повертає поточний знімок конфігурації та хеш. - `config.set` записує перевірене корисне навантаження конфігурації. - `config.patch` об’єднує часткове оновлення конфігурації. -- `config.apply` перевіряє й замінює повне корисне навантаження конфігурації. -- `config.schema` повертає корисне навантаження активної схеми конфігурації, яке використовують Control UI і - інструменти CLI: схема, `uiHints`, версія і метадані генерації, - включно з метаданими схем plugin + channel, коли середовище виконання може їх завантажити. Схема - включає метадані полів `title` / `description`, отримані з тих самих міток - і довідкового тексту, що використовує UI, включно з вкладеними object, wildcard, array-item - і гілками композиції `anyOf` / `oneOf` / `allOf`, коли існує відповідна - документація полів. -- `config.schema.lookup` повертає корисне навантаження пошуку з областю шляху для одного шляху конфігурації: +- `config.apply` перевіряє + замінює повне корисне навантаження конфігурації. +- `config.schema` повертає корисне навантаження поточної схеми конфігурації, яке використовують Control UI і + інструменти CLI: схема, `uiHints`, версія та метадані генерації, зокрема + метадані схеми plugin + channel, коли середовище виконання може їх завантажити. Схема + містить метадані полів `title` / `description`, похідні від тих самих міток + і тексту довідки, які використовує UI, зокрема для вкладених об’єктів, wildcard, + елементів масиву та гілок композиції `anyOf` / `oneOf` / `allOf`, коли існує + відповідна документація для полів. +- `config.schema.lookup` повертає корисне навантаження пошуку з обмеженням шляхом для одного шляху конфігурації: нормалізований шлях, неглибокий вузол схеми, зіставлену підказку + `hintPath` і - зведення безпосередніх дочірніх елементів для детального перегляду UI/CLI. - - Вузли схеми пошуку зберігають документацію для користувача та поширені поля перевірки: + зведення безпосередніх дочірніх елементів для деталізації в UI/CLI. + - Вузли схеми пошуку зберігають орієнтовану на користувача документацію та типові поля перевірки: `title`, `description`, `type`, `enum`, `const`, `format`, `pattern`, - числові/рядкові/масивні/об’єктні межі й булеві прапорці, як-от + числові/рядкові/масивні/об’єктні межі та булеві прапорці, такі як `additionalProperties`, `deprecated`, `readOnly`, `writeOnly`. - Зведення дочірніх елементів показують `key`, нормалізований `path`, `type`, `required`, `hasChildren`, а також зіставлені `hint` / `hintPath`. -- `update.run` запускає потік оновлення gateway і планує перезапуск лише тоді, +- `update.run` запускає потік оновлення Gateway і планує перезапуск лише тоді, коли саме оновлення було успішним. -- `wizard.start`, `wizard.next`, `wizard.status` і `wizard.cancel` надають - майстер налаштування через WS RPC. +- `wizard.start`, `wizard.next`, `wizard.status` і `wizard.cancel` відкривають + майстер налаштування onboarding через WS RPC. ### Наявні основні сімейства @@ -369,10 +378,10 @@ Gateway розглядає їх як **заяви** і застосовує сп - `agents.create`, `agents.update` і `agents.delete` керують записами агентів і прив’язкою робочого простору. - `agents.files.list`, `agents.files.get` і `agents.files.set` керують файлами - bootstrap-робочого простору, доступними для агента. -- `agent.identity.get` повертає ефективну ідентичність помічника для агента або + bootstrap робочого простору, відкритими для агента. +- `agent.identity.get` повертає фактичну ідентичність помічника для агента або сесії. -- `agent.wait` очікує завершення запуску й повертає термінальний знімок, якщо +- `agent.wait` очікує завершення запуску й повертає термінальний знімок, коли він доступний. #### Керування сесіями @@ -382,162 +391,163 @@ Gateway розглядає їх як **заяви** і застосовує сп змін сесії для поточного WS-клієнта. - `sessions.messages.subscribe` і `sessions.messages.unsubscribe` перемикають підписки на події транскрипту/повідомлень для однієї сесії. -- `sessions.preview` повертає обмежені попередні перегляди транскрипту для - конкретних ключів сесій. -- `sessions.resolve` визначає або канонізує ціль сесії. +- `sessions.preview` повертає обмежені попередні перегляди транскрипту для конкретних + ключів сесій. +- `sessions.resolve` розв’язує або канонізує ціль сесії. - `sessions.create` створює новий запис сесії. - `sessions.send` надсилає повідомлення в наявну сесію. -- `sessions.steer` — це варіант переривання й перенаправлення для активної сесії. +- `sessions.steer` — це варіант переривання й спрямування для активної сесії. - `sessions.abort` перериває активну роботу для сесії. - `sessions.patch` оновлює метадані/перевизначення сесії. - `sessions.reset`, `sessions.delete` і `sessions.compact` виконують обслуговування сесії. - `sessions.get` повертає повний збережений рядок сесії. -- виконання чату, як і раніше, використовує `chat.history`, `chat.send`, `chat.abort` і +- виконання chat, як і раніше, використовує `chat.history`, `chat.send`, `chat.abort` і `chat.inject`. -- `chat.history` нормалізується для відображення для UI-клієнтів: вбудовані теги директив - видаляються з видимого тексту, корисні навантаження XML викликів інструментів у форматі простого тексту (включно з +- `chat.history` нормалізується для відображення клієнтам UI: вбудовані теги директив + прибираються з видимого тексту, XML-корисні навантаження викликів інструментів у звичайному тексті (зокрема `...`, `...`, `...`, `...` і - обрізаними блоками викликів інструментів), а також витеклі ASCII/повноширинні токени керування моделі - видаляються, чисті рядки помічника з мовчазними токенами, такі як точні `NO_REPLY` / - `no_reply`, пропускаються, а надмірно великі рядки можуть бути замінені заповнювачами. + обрізані блоки викликів інструментів), а також витеклі ASCII/повноширинні керівні токени моделі + прибираються, рядки помічника, що складаються лише з беззвучних токенів, такі як точні `NO_REPLY` / + `no_reply`, опускаються, а надто великі рядки можуть замінюватися заповнювачами. #### Pairing пристроїв і токени пристроїв -- `device.pair.list` повертає очікувальні й схвалені спарені пристрої. +- `device.pair.list` повертає очікувальні та схвалені спарені пристрої. - `device.pair.approve`, `device.pair.reject` і `device.pair.remove` керують записами pairing пристроїв. -- `device.token.rotate` ротує токен спареного пристрою в межах його схваленої ролі - та меж областей доступу. +- `device.token.rotate` обертає токен спареного пристрою в межах його схвалених + ролі та областей видимості. - `device.token.revoke` відкликає токен спареного пристрою. -#### Pairing вузлів, invoke і відкладена робота +#### Pairing Node, invoke і очікувальна робота - `node.pair.request`, `node.pair.list`, `node.pair.approve`, - `node.pair.reject` і `node.pair.verify` охоплюють pairing вузлів і bootstrap-перевірку. -- `node.list` і `node.describe` повертають стан відомого/підключеного вузла. -- `node.rename` оновлює мітку спареного вузла. -- `node.invoke` пересилає команду підключеному вузлу. + `node.pair.reject` і `node.pair.verify` охоплюють pairing Node і bootstrap + verification. +- `node.list` і `node.describe` повертають стан відомих/підключених Node. +- `node.rename` оновлює мітку спареного Node. +- `node.invoke` пересилає команду підключеному Node. - `node.invoke.result` повертає результат для запиту invoke. -- `node.event` переносить події, що походять від вузла, назад у gateway. +- `node.event` передає події, що походять від Node, назад у Gateway. - `node.canvas.capability.refresh` оновлює токени можливостей canvas з обмеженою областю дії. -- `node.pending.pull` і `node.pending.ack` — це API черги підключеного вузла. -- `node.pending.enqueue` і `node.pending.drain` керують стійкою відкладеною роботою - для офлайн/відключених вузлів. +- `node.pending.pull` і `node.pending.ack` — це API черги для підключених Node. +- `node.pending.enqueue` і `node.pending.drain` керують стійкою очікувальною роботою + для офлайн/відключених Node. -#### Сімейства approval +#### Сімейства схвалень - `exec.approval.request`, `exec.approval.get`, `exec.approval.list` і - `exec.approval.resolve` охоплюють одноразові запити approval для exec плюс - пошук/повторення очікувальних approval. -- `exec.approval.waitDecision` очікує на одне очікувальне approval для exec і повертає - остаточне рішення (або `null` у разі тайм-ауту). -- `exec.approvals.get` і `exec.approvals.set` керують знімками політики - approval exec у gateway. -- `exec.approvals.node.get` і `exec.approvals.node.set` керують локальною для вузла політикою - approval exec через команди relay вузла. + `exec.approval.resolve` охоплюють одноразові запити на схвалення exec плюс + пошук/повторення очікувальних схвалень. +- `exec.approval.waitDecision` очікує рішення щодо одного очікувального схвалення exec і повертає + фінальне рішення (або `null` у разі тайм-ауту). +- `exec.approvals.get` і `exec.approvals.set` керують знімками політики схвалення exec + Gateway. +- `exec.approvals.node.get` і `exec.approvals.node.set` керують локальною для Node політикою exec + approval через команди relay Node. - `plugin.approval.request`, `plugin.approval.list`, `plugin.approval.waitDecision` і `plugin.approval.resolve` охоплюють - потоки approval, визначені Plugin. + потоки схвалення, визначені Plugin. #### Інші основні сімейства - automation: - - `wake` планує негайне або наступне на Heartbeat вбудовування тексту пробудження + - `wake` планує негайне або на наступний Heartbeat введення тексту пробудження - `cron.list`, `cron.status`, `cron.add`, `cron.update`, `cron.remove`, `cron.run`, `cron.runs` - skills/tools: `commands.list`, `skills.*`, `tools.catalog`, `tools.effective` ### Поширені сімейства подій -- `chat`: оновлення UI-чату, такі як `chat.inject` та інші події чату - лише для транскрипту. +- `chat`: оновлення UI chat, такі як `chat.inject` та інші події chat, + пов’язані лише з транскриптом. - `session.message` і `session.tool`: оновлення транскрипту/потоку подій для - підписаної сесії. -- `sessions.changed`: індекс сесії або метадані змінено. -- `presence`: оновлення знімка системної присутності. + сесії, на яку оформлено підписку. +- `sessions.changed`: індекс сесій або метадані змінено. +- `presence`: оновлення знімка системного presence. - `tick`: періодична подія keepalive / перевірки доступності. -- `health`: оновлення знімка стану gateway. +- `health`: оновлення знімка стану Gateway. - `heartbeat`: оновлення потоку подій Heartbeat. - `cron`: подія зміни запуску/завдання Cron. -- `shutdown`: сповіщення про вимкнення gateway. -- `node.pair.requested` / `node.pair.resolved`: життєвий цикл pairing вузла. -- `node.invoke.request`: трансляція запиту invoke вузла. +- `shutdown`: сповіщення про завершення роботи Gateway. +- `node.pair.requested` / `node.pair.resolved`: життєвий цикл pairing Node. +- `node.invoke.request`: broadcast запиту invoke для Node. - `device.pair.requested` / `device.pair.resolved`: життєвий цикл спареного пристрою. -- `voicewake.changed`: конфігурацію тригерів слова активації змінено. +- `voicewake.changed`: змінено конфігурацію тригера слова активації. - `exec.approval.requested` / `exec.approval.resolved`: життєвий цикл - approval exec. + схвалення exec. - `plugin.approval.requested` / `plugin.approval.resolved`: життєвий цикл - approval Plugin. + схвалення plugin. -### Допоміжні методи node +### Допоміжні методи Node -- Вузли можуть викликати `skills.bins`, щоб отримати поточний список виконуваних файлів skill - для перевірок auto-allow. +- Node можуть викликати `skills.bins`, щоб отримати поточний список виконуваних файлів skill + для перевірок автоматичного дозволу. ### Допоміжні методи operator -- Оператори можуть викликати `commands.list` (`operator.read`), щоб отримати інвентар команд середовища виконання для агента. - - `agentId` необов’язковий; пропустіть його, щоб читати робочий простір агента за замовчуванням. - - `scope` керує тим, яку поверхню націлює основний `name`: +- Operator можуть викликати `commands.list` (`operator.read`), щоб отримати перелік команд середовища виконання для агента. + - `agentId` необов’язковий; не вказуйте його, щоб читати робочий простір агента за замовчуванням. + - `scope` керує тим, на яку поверхню націлений основний `name`: - `text` повертає основний текстовий токен команди без початкового `/` - - `native` і стандартний шлях `both` повертають залежні від провайдера native-імена, + - `native` і стандартний шлях `both` повертають орієнтовані на провайдера native-імена, коли вони доступні - `textAliases` містить точні slash-аліаси, такі як `/model` і `/m`. - - `nativeName` містить залежну від провайдера native-назву команди, коли вона існує. - - `provider` необов’язковий і впливає лише на native-іменування та доступність native-команд Plugin. + - `nativeName` містить орієнтовану на провайдера native-назву команди, коли вона існує. + - `provider` необов’язковий і впливає лише на native-іменування та доступність native-команд plugin. - `includeArgs=false` пропускає серіалізовані метадані аргументів у відповіді. -- Оператори можуть викликати `tools.catalog` (`operator.read`), щоб отримати каталог інструментів середовища виконання для - агента. Відповідь включає згруповані інструменти та метадані походження: +- Operator можуть викликати `tools.catalog` (`operator.read`), щоб отримати каталог інструментів середовища виконання для + агента. Відповідь містить згруповані інструменти та метадані походження: - `source`: `core` або `plugin` - `pluginId`: власник plugin, коли `source="plugin"` - `optional`: чи є інструмент plugin необов’язковим -- Оператори можуть викликати `tools.effective` (`operator.read`), щоб отримати фактичний інвентар інструментів - середовища виконання для сесії. +- Operator можуть викликати `tools.effective` (`operator.read`), щоб отримати фактичний перелік інструментів середовища виконання + для сесії. - `sessionKey` обов’язковий. - - Gateway виводить довірений контекст середовища виконання із сесії на боці сервера замість прийняття - auth або контексту доставки, наданих викликачем. - - Відповідь має область дії сесії та відображає те, що активна розмова може використовувати прямо зараз, - включно з інструментами core, plugin і channel. -- Оператори можуть викликати `skills.status` (`operator.read`), щоб отримати видимий - інвентар Skills для агента. - - `agentId` необов’язковий; пропустіть його, щоб читати робочий простір агента за замовчуванням. - - Відповідь включає придатність, відсутні вимоги, перевірки конфігурації та - санітизовані параметри встановлення без розкриття необроблених значень секретів. -- Оператори можуть викликати `skills.search` і `skills.detail` (`operator.read`) для + - Gateway виводить довірений контекст середовища виконання із сесії на боці сервера, замість того щоб приймати + наданий викликачем контекст автентифікації або доставки. + - Відповідь має область дії сесії та відображає те, що активна розмова може використовувати просто зараз, + зокрема core, plugin і channel tools. +- Operator можуть викликати `skills.status` (`operator.read`), щоб отримати видимий + перелік skills для агента. + - `agentId` необов’язковий; не вказуйте його, щоб читати робочий простір агента за замовчуванням. + - Відповідь містить відповідність вимогам, відсутні вимоги, перевірки конфігурації та + санітизовані параметри встановлення без розкриття необроблених секретних значень. +- Operator можуть викликати `skills.search` і `skills.detail` (`operator.read`) для метаданих виявлення ClawHub. -- Оператори можуть викликати `skills.install` (`operator.admin`) у двох режимах: - - Режим ClawHub: `{ source: "clawhub", slug, version?, force? }` встановлює - теку skill у каталог `skills/` робочого простору агента за замовчуванням. - - Режим встановлювача Gateway: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` - запускає оголошену дію `metadata.openclaw.install` на хості gateway. -- Оператори можуть викликати `skills.update` (`operator.admin`) у двох режимах: +- Operator можуть викликати `skills.install` (`operator.admin`) у двох режимах: + - Режим ClawHub: `{ source: "clawhub", slug, version?, force? }` установлює + папку skill у каталог `skills/` робочого простору агента за замовчуванням. + - Режим інсталятора Gateway: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` + запускає оголошену дію `metadata.openclaw.install` на хості Gateway. +- Operator можуть викликати `skills.update` (`operator.admin`) у двох режимах: - Режим ClawHub оновлює один відстежуваний slug або всі відстежувані встановлення ClawHub у робочому просторі агента за замовчуванням. - Режим Config вносить зміни до значень `skills.entries.`, таких як `enabled`, `apiKey` і `env`. -## Approval для exec +## Схвалення exec -- Коли запит exec потребує approval, gateway транслює `exec.approval.requested`. -- Клієнти operator вирішують це, викликаючи `exec.approval.resolve` (потрібна область доступу `operator.approvals`). -- Для `host=node` `exec.approval.request` має включати `systemRunPlan` (канонічні `argv`/`cwd`/`rawCommand`/метадані сесії). Запити без `systemRunPlan` відхиляються. -- Після approval переслані виклики `node.invoke system.run` повторно використовують цей канонічний +- Коли запит exec потребує схвалення, Gateway транслює `exec.approval.requested`. +- Клієнти operator виконують підтвердження, викликаючи `exec.approval.resolve` (потрібна область видимості `operator.approvals`). +- Для `host=node` `exec.approval.request` має містити `systemRunPlan` (канонічні метадані `argv`/`cwd`/`rawCommand`/сесії). Запити без `systemRunPlan` відхиляються. +- Після схвалення переслані виклики `node.invoke system.run` повторно використовують цей канонічний `systemRunPlan` як авторитетний контекст команди/cwd/сесії. - Якщо викликач змінює `command`, `rawCommand`, `cwd`, `agentId` або - `sessionKey` між prepare і фінальним пересиланням схваленого `system.run`, - gateway відхиляє запуск замість того, щоб довіряти зміненому корисному навантаженню. + `sessionKey` між prepare і остаточним пересиланням схваленого `system.run`, + Gateway відхиляє запуск замість того, щоб довіряти зміненому корисному навантаженню. ## Резервна доставка агента -- Запити `agent` можуть включати `deliver=true`, щоб запросити вихідну доставку. -- `bestEffortDeliver=false` зберігає сувору поведінку: цілі доставки, які неможливо визначити або які є лише внутрішніми, повертають `INVALID_REQUEST`. -- `bestEffortDeliver=true` дозволяє резервний перехід до виконання лише в сесії, коли неможливо визначити зовнішній маршрут доставки (наприклад, внутрішні/webchat сесії або неоднозначні конфігурації багатьох каналів). +- Запити `agent` можуть містити `deliver=true`, щоб запросити вихідну доставку. +- `bestEffortDeliver=false` зберігає сувору поведінку: нерозв’язані або лише внутрішні цілі доставки повертають `INVALID_REQUEST`. +- `bestEffortDeliver=true` дозволяє резервне виконання лише в межах сесії, коли неможливо розв’язати зовнішній маршрут доставки (наприклад, для внутрішніх/webchat сесій або неоднозначних багатоканальних конфігурацій). ## Версіонування -- `PROTOCOL_VERSION` міститься в `src/gateway/protocol/schema/protocol-schemas.ts`. +- `PROTOCOL_VERSION` розташовано в `src/gateway/protocol/schema/protocol-schemas.ts`. - Клієнти надсилають `minProtocol` + `maxProtocol`; сервер відхиляє невідповідності. - Схеми + моделі генеруються з визначень TypeBox: - `pnpm protocol:gen` @@ -546,22 +556,22 @@ Gateway розглядає їх як **заяви** і застосовує сп ### Константи клієнта -Еталонний клієнт у `src/gateway/client.ts` використовує ці значення за замовчуванням. Значення -стабільні в межах протоколу v3 і є очікуваною базовою лінією для сторонніх клієнтів. +Еталонний клієнт у `src/gateway/client.ts` використовує ці значення за замовчуванням. Вони +стабільні впродовж protocol v3 і є очікуваною базою для сторонніх клієнтів. -| Constant | Default | Source | -| ----------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | -| `PROTOCOL_VERSION` | `3` | `src/gateway/protocol/schema/protocol-schemas.ts` | -| Тайм-аут запиту (на один RPC) | `30_000` ms | `src/gateway/client.ts` (`requestTimeoutMs`) | -| Тайм-аут preauth / connect-challenge | `10_000` ms | `src/gateway/handshake-timeouts.ts` (clamp `250`–`10_000`) | -| Початковий backoff повторного підключення | `1_000` ms | `src/gateway/client.ts` (`backoffMs`) | -| Максимальний backoff повторного підключення | `30_000` ms | `src/gateway/client.ts` (`scheduleReconnect`) | -| Обмеження швидкого повтору після закриття токена пристрою | `250` ms | `src/gateway/client.ts` | -| Пільговий період force-stop перед `terminate()` | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` | -| Тайм-аут за замовчуванням для `stopAndWait()` | `1_000` ms | `STOP_AND_WAIT_TIMEOUT_MS` | -| Стандартний інтервал tick (до `hello-ok`) | `30_000` ms | `src/gateway/client.ts` | -| Закриття через тайм-аут tick | код `4000`, коли тиша перевищує `tickIntervalMs * 2` | `src/gateway/client.ts` | -| `MAX_PAYLOAD_BYTES` | `25 * 1024 * 1024` (25 MB) | `src/gateway/server-constants.ts` | +| Константа | Значення за замовчуванням | Джерело | +| ------------------------------------------ | ----------------------------------------------------- | ---------------------------------------------------------- | +| `PROTOCOL_VERSION` | `3` | `src/gateway/protocol/schema/protocol-schemas.ts` | +| Тайм-аут запиту (на RPC) | `30_000` ms | `src/gateway/client.ts` (`requestTimeoutMs`) | +| Тайм-аут preauth / connect-challenge | `10_000` ms | `src/gateway/handshake-timeouts.ts` (clamp `250`–`10_000`) | +| Початковий backoff повторного підключення | `1_000` ms | `src/gateway/client.ts` (`backoffMs`) | +| Максимальний backoff повторного підключення| `30_000` ms | `src/gateway/client.ts` (`scheduleReconnect`) | +| Fast-retry clamp після закриття device-token | `250` ms | `src/gateway/client.ts` | +| Пауза примусової зупинки перед `terminate()` | `250` ms | `FORCE_STOP_TERMINATE_GRACE_MS` | +| Тайм-аут `stopAndWait()` за замовчуванням | `1_000` ms | `STOP_AND_WAIT_TIMEOUT_MS` | +| Інтервал tick за замовчуванням (до `hello-ok`) | `30_000` ms | `src/gateway/client.ts` | +| Закриття через тайм-аут tick | код `4000`, коли тиша перевищує `tickIntervalMs * 2` | `src/gateway/client.ts` | +| `MAX_PAYLOAD_BYTES` | `25 * 1024 * 1024` (25 MB) | `src/gateway/server-constants.ts` | Сервер оголошує фактичні `policy.tickIntervalMs`, `policy.maxPayload` і `policy.maxBufferedBytes` у `hello-ok`; клієнти повинні дотримуватися цих значень, @@ -569,110 +579,110 @@ Gateway розглядає їх як **заяви** і застосовує сп ## Автентифікація -- Автентифікація gateway зі спільним секретом використовує `connect.params.auth.token` або - `connect.params.auth.password` залежно від налаштованого режиму автентифікації. +- Автентифікація Gateway за спільним секретом використовує `connect.params.auth.token` або + `connect.params.auth.password`, залежно від налаштованого режиму автентифікації. - Режими з ідентичністю, такі як Tailscale Serve (`gateway.auth.allowTailscale: true`) або не-loopback `gateway.auth.mode: "trusted-proxy"`, проходять перевірку автентифікації connect на основі - заголовків запиту замість `connect.params.auth.*`. -- Приватний ingress `gateway.auth.mode: "none"` повністю пропускає автентифікацію connect зі спільним секретом; не відкривайте цей режим для публічного або недовіреного ingress. -- Після pairing Gateway видає **токен пристрою** з областю дії, обмеженою роллю + областями доступу - підключення. Він повертається в `hello-ok.auth.deviceToken`, і клієнт повинен - зберігати його для майбутніх підключень. + заголовків запиту, а не `connect.params.auth.*`. +- Для private-ingress `gateway.auth.mode: "none"` повністю пропускає автентифікацію connect за спільним секретом; не відкривайте цей режим у публічному/недовіреному ingress. +- Після pairing Gateway видає **токен пристрою** з областю дії, обмеженою роллю + областями видимості + з’єднання. Він повертається в `hello-ok.auth.deviceToken` і має + зберігатися клієнтом для наступних підключень. - Клієнти повинні зберігати основний `hello-ok.auth.deviceToken` після будь-якого успішного підключення. - Повторне підключення з цим **збереженим** токеном пристрою також має повторно використовувати - збережений набір схвалених областей доступу для цього токена. Це зберігає доступ до - читання/перевірки/статусу, який уже було надано, і запобігає непомітному звуженню - повторних підключень до вужчої неявної області доступу лише для адміністрування. -- Побудова auth для connect на боці клієнта (`selectConnectAuth` у + збережений набір схвалених областей видимості для цього токена. Це зберігає вже наданий доступ + до читання/перевірок/стану й уникає непомітного звуження повторних підключень до + вужчої неявної області лише для admin. +- Формування client-side connect auth (`selectConnectAuth` у `src/gateway/client.ts`): - - `auth.password` є незалежним і завжди пересилається, якщо встановлено. + - `auth.password` ортогональний і завжди пересилається, якщо встановлений. - `auth.token` заповнюється в такому порядку пріоритету: спочатку явний спільний токен, - потім явний `deviceToken`, далі збережений токен для конкретного пристрою (з ключем за + потім явний `deviceToken`, потім збережений токен для конкретного пристрою (з ключем за `deviceId` + `role`). - - `auth.bootstrapToken` надсилається лише тоді, коли жоден із наведених вище варіантів не визначив - `auth.token`. Спільний токен або будь-який визначений токен пристрою його пригнічує. + - `auth.bootstrapToken` надсилається лише тоді, коли жоден із наведених вище варіантів не розв’язав + `auth.token`. Спільний токен або будь-який розв’язаний токен пристрою його пригнічує. - Автопідвищення збереженого токена пристрою під час одноразової - повторної спроби `AUTH_TOKEN_MISMATCH` обмежене **лише довіреними кінцевими точками** — + спроби повтору `AUTH_TOKEN_MISMATCH` обмежене лише **довіреними кінцевими точками** — loopback або `wss://` із закріпленим `tlsFingerprint`. Публічний `wss://` без pinning не підходить. - Додаткові записи `hello-ok.auth.deviceTokens` — це токени передачі bootstrap. - Зберігайте їх лише тоді, коли підключення використовувало bootstrap-auth через довірений транспорт, - такий як `wss://` або loopback/local pairing. + Зберігайте їх лише тоді, коли підключення використовувало bootstrap auth у довіреному транспорті, + такому як `wss://` або loopback/local pairing. - Якщо клієнт надає **явний** `deviceToken` або явні `scopes`, цей - набір областей доступу, запитаний викликачем, залишається авторитетним; кешовані області доступу + набір областей видимості, запитаний викликачем, лишається авторитетним; кешовані області видимості повторно використовуються лише тоді, коли клієнт повторно використовує збережений токен для конкретного пристрою. -- Токени пристроїв можна ротувати/відкликати через `device.token.rotate` і - `device.token.revoke` (потрібна область доступу `operator.pairing`). -- Видача/ротація токенів залишається обмеженою схваленим набором ролей, записаним у - записі pairing цього пристрою; ротація токена не може розширити пристрій до - ролі, яку схвалення pairing ніколи не надавало. -- Для сесій токенів спарених пристроїв керування пристроями має власну область дії, якщо лише - викликач також не має `operator.admin`: викликачі без адміністраторських прав можуть видаляти/відкликати/ротувати +- Токени пристроїв можна обертати/відкликати через `device.token.rotate` і + `device.token.revoke` (потрібна область видимості `operator.pairing`). +- Видача/обертання токенів лишається обмеженою схваленим набором ролей, записаним у + записі pairing цього пристрою; обертання токена не може розширити пристрій до + ролі, яку ніколи не надав дозвіл pairing. +- Для сесій з токеном спареного пристрою керування пристроєм має власну область дії, якщо тільки + викликач також не має `operator.admin`: викликачі без admin можуть видаляти/відкликати/обертати лише **власний** запис пристрою. -- `device.token.rotate` також перевіряє запитаний набір областей доступу оператора щодо - поточних областей доступу сесії викликача. Викликачі без адміністраторських прав не можуть ротувати токен у - ширший набір областей доступу оператора, ніж той, який вони вже мають. -- Збої автентифікації включають `error.details.code` плюс підказки щодо відновлення: - - `error.details.canRetryWithDeviceToken` (boolean) +- `device.token.rotate` також перевіряє запитаний набір областей видимості operator щодо + поточних областей видимості сесії викликача. Викликачі без admin не можуть обертати токен до + ширшого набору областей видимості operator, ніж вони вже мають. +- Збої автентифікації містять `error.details.code` плюс підказки щодо відновлення: + - `error.details.canRetryWithDeviceToken` (булеве значення) - `error.details.recommendedNextStep` (`retry_with_device_token`, `update_auth_configuration`, `update_auth_credentials`, `wait_then_retry`, `review_auth_configuration`) - Поведінка клієнта для `AUTH_TOKEN_MISMATCH`: - - Довірені клієнти можуть зробити одну обмежену повторну спробу з кешованим токеном для конкретного пристрою. - - Якщо ця повторна спроба не вдається, клієнти повинні припинити цикли автоматичного повторного підключення і показати вказівки для дій оператора. + - Довірені клієнти можуть виконати одну обмежену повторну спробу із кешованим токеном для конкретного пристрою. + - Якщо ця повторна спроба не вдається, клієнти повинні зупинити цикли автоматичного повторного підключення та показати вказівки для дій operator. ## Ідентичність пристрою + pairing -- Вузли повинні включати стабільну ідентичність пристрою (`device.id`), похідну від - відбитка keypair. +- Node повинні містити стабільну ідентичність пристрою (`device.id`), похідну від + відбитка ключової пари. - Gateway видає токени для кожного пристрою + ролі. - Для нових `device.id` потрібні схвалення pairing, якщо не ввімкнено локальне автоматичне схвалення. - Автоматичне схвалення pairing зосереджене на прямих локальних loopback-підключеннях. -- OpenClaw також має вузький шлях backend/container-local self-connect для +- OpenClaw також має вузький шлях самопідключення backend/container-local для довірених допоміжних потоків зі спільним секретом. -- Підключення tailnet або LAN з того самого хоста все одно вважаються віддаленими для pairing і +- Підключення tailnet або LAN на тому самому хості все одно вважаються віддаленими для pairing і потребують схвалення. -- Усі WS-клієнти повинні включати ідентичність `device` під час `connect` (operator + node). +- Усі WS-клієнти мають включати ідентичність `device` під час `connect` (operator + node). Control UI може пропускати її лише в таких режимах: - `gateway.controlUi.allowInsecureAuth=true` для сумісності з небезпечним HTTP лише на localhost. - успішна автентифікація operator Control UI через `gateway.auth.mode: "trusted-proxy"`. - - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (аварійний варіант, критичне зниження безпеки). -- Усі підключення повинні підписувати наданий сервером nonce `connect.challenge`. + - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (аварійний режим, серйозне зниження безпеки). +- Усі з’єднання мають підписувати nonce `connect.challenge`, наданий сервером. ### Діагностика міграції автентифікації пристрою -Для застарілих клієнтів, які досі використовують поведінку підпису до challenge, `connect` тепер повертає +Для застарілих клієнтів, які все ще використовують поведінку підписування до challenge, `connect` тепер повертає коди деталей `DEVICE_AUTH_*` у `error.details.code` зі стабільним `error.details.reason`. Поширені збої міграції: -| Message | details.code | details.reason | Meaning | -| --------------------------- | -------------------------------- | ------------------------ | -------------------------------------------------- | -| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | Клієнт пропустив `device.nonce` (або надіслав порожнє значення). | -| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | Клієнт підписав застарілим/неправильним nonce. | -| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | Корисне навантаження підпису не відповідає корисному навантаженню v2. | -| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | Підписана позначка часу поза межами дозволеного зсуву. | -| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` не відповідає відбитку публічного ключа. | -| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | Формат публічного ключа/канонізація не пройшли перевірку. | +| Повідомлення | details.code | details.reason | Значення | +| ---------------------------- | -------------------------------- | ------------------------ | --------------------------------------------------- | +| `device nonce required` | `DEVICE_AUTH_NONCE_REQUIRED` | `device-nonce-missing` | Клієнт пропустив `device.nonce` (або надіслав порожнє значення). | +| `device nonce mismatch` | `DEVICE_AUTH_NONCE_MISMATCH` | `device-nonce-mismatch` | Клієнт підписав застарілим/неправильним nonce. | +| `device signature invalid` | `DEVICE_AUTH_SIGNATURE_INVALID` | `device-signature` | Корисне навантаження підпису не відповідає корисному навантаженню v2. | +| `device signature expired` | `DEVICE_AUTH_SIGNATURE_EXPIRED` | `device-signature-stale` | Часова мітка підпису поза межами дозволеного зсуву. | +| `device identity mismatch` | `DEVICE_AUTH_DEVICE_ID_MISMATCH` | `device-id-mismatch` | `device.id` не відповідає відбитку публічного ключа. | +| `device public key invalid` | `DEVICE_AUTH_PUBLIC_KEY_INVALID` | `device-public-key` | Збій формату/канонізації публічного ключа. | Ціль міграції: -- Завжди чекайте на `connect.challenge`. -- Підписуйте корисне навантаження v2, яке включає server nonce. +- Завжди очікуйте `connect.challenge`. +- Підписуйте корисне навантаження v2, яке містить серверний nonce. - Надсилайте той самий nonce у `connect.params.device.nonce`. - Бажане корисне навантаження підпису — `v3`, яке прив’язує `platform` і `deviceFamily` на додачу до полів device/client/role/scopes/token/nonce. -- Застарілі підписи `v2` і далі приймаються для сумісності, але закріплення - метаданих спарених пристроїв усе одно керує політикою команд під час повторного підключення. +- Застарілі підписи `v2` і далі приймаються для сумісності, але pinning метаданих + спареного пристрою все одно керує політикою команд під час повторного підключення. ## TLS + pinning -- TLS підтримується для WS-підключень. -- Клієнти можуть за бажанням закріплювати відбиток сертифіката gateway (див. конфігурацію `gateway.tls` +- Для WS-з’єднань підтримується TLS. +- Клієнти можуть за бажанням закріпити відбиток сертифіката Gateway (див. конфігурацію `gateway.tls` плюс `gateway.remote.tlsFingerprint` або CLI `--tls-fingerprint`). ## Область дії -Цей протокол відкриває **повний API gateway** (status, channels, models, chat, -agent, sessions, nodes, approvals тощо). Точна поверхня визначається -схемами TypeBox у `src/gateway/protocol/schema.ts`. +Цей протокол відкриває **повний API Gateway** (status, channels, models, chat, +agent, sessions, nodes, approvals тощо). Точна поверхня визначається схемами +TypeBox у `src/gateway/protocol/schema.ts`. diff --git a/docs/uk/help/testing.md b/docs/uk/help/testing.md index cc7aeec72..883f0063e 100644 --- a/docs/uk/help/testing.md +++ b/docs/uk/help/testing.md @@ -1,15 +1,15 @@ --- read_when: - Запуск тестів локально або в CI - - Додавання регресійних тестів для помилок моделей/провайдерів - - Налагодження поведінки Gateway + агентів -summary: 'Набір для тестування: набори unit/e2e/live, Docker-ранери та що охоплює кожен тест' + - Додавання регресій для помилок моделі/провайдера + - Налагодження поведінки Gateway + агента +summary: 'Набір для тестування: unit/e2e/live набори, Docker-ранери та що охоплює кожен тест' title: Тестування x-i18n: - generated_at: "2026-04-22T23:49:17Z" + generated_at: "2026-04-23T00:49:09Z" model: gpt-5.4 provider: openai - source_hash: 7d1392e0a46c5d142d65852e9d05179cce6bb1cd93df2fb372fdf13de6681a8a + source_hash: 5e77b1e4eb5e750f732655c9dc4047b1cc07b4057e75a4cde042bf26410ce927 source_path: help/testing.md workflow: 15 --- @@ -23,109 +23,115 @@ OpenClaw має три набори Vitest (unit/integration, e2e, live) і не - Що охоплює кожен набір (і що він навмисно _не_ охоплює) - Які команди запускати для типових сценаріїв роботи (локально, перед push, налагодження) - Як live-тести знаходять облікові дані та вибирають моделі/провайдерів -- Як додавати регресійні тести для реальних проблем моделей/провайдерів +- Як додавати регресії для реальних проблем із моделями/провайдерами ## Швидкий старт У більшості випадків: -- Повний gate (очікується перед push): `pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- Швидший локальний запуск повного набору на потужній машині: `pnpm test:max` +- Повна перевірка (очікується перед push): `pnpm build && pnpm check && pnpm check:test-types && pnpm test` +- Швидший локальний запуск повного набору на машині з достатніми ресурсами: `pnpm test:max` - Прямий цикл спостереження Vitest: `pnpm test:watch` -- Пряме націлювання на файл тепер також маршрутизує шляхи extension/channel: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- Пряме націлювання на файл тепер також маршрутизує шляхи extensions/channel: `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` - Коли ітеруєтеся над однією помилкою, спочатку віддавайте перевагу цільовим запускам. - QA-сайт на базі Docker: `pnpm qa:lab:up` -- QA-ланка на базі Linux VM: `pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` +- QA-смуга на базі Linux VM: `pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -Коли ви змінюєте тести або хочете більше впевненості: +Коли ви змінюєте тести або хочете додаткової впевненості: -- Gate покриття: `pnpm test:coverage` +- Перевірка покриття: `pnpm test:coverage` - Набір E2E: `pnpm test:e2e` Під час налагодження реальних провайдерів/моделей (потрібні реальні облікові дані): -- Live-набір (моделі + Gateway tool/image probes): `pnpm test:live` +- Live-набір (моделі + Gateway перевірки інструментів/зображень): `pnpm test:live` - Тихо націлитися на один live-файл: `pnpm test:live -- src/agents/models.profiles.live.test.ts` -- Smoke-перевірка вартості Moonshot/Kimi: якщо встановлено `MOONSHOT_API_KEY`, виконайте - `openclaw models list --provider moonshot --json`, потім виконайте ізольований +- Перевірка вартості Moonshot/Kimi: коли встановлено `MOONSHOT_API_KEY`, виконайте + `openclaw models list --provider moonshot --json`, а потім ізольований запуск `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json` - для `moonshot/kimi-k2.6`. Переконайтеся, що JSON містить Moonshot/K2.6, а - транскрипт помічника зберігає нормалізований `usage.cost`. + для `moonshot/kimi-k2.6`. Переконайтеся, що JSON показує Moonshot/K2.6, а + транскрипт помічника зберігає нормалізоване `usage.cost`. Порада: коли вам потрібен лише один збійний випадок, віддавайте перевагу звуженню live-тестів через змінні середовища allowlist, описані нижче. -## QA-специфічні ранери +## Ранери, специфічні для QA -Ці команди розташовані поруч із основними наборами тестів, коли вам потрібен реалізм qa-lab: +Ці команди розташовані поруч з основними наборами тестів, коли вам потрібна реалістичність qa-lab: - `pnpm openclaw qa suite` - Запускає QA-сценарії з репозиторію безпосередньо на хості. - - За замовчуванням запускає кілька вибраних сценаріїв паралельно з ізольованими Gateway workers. `qa-channel` за замовчуванням має concurrency 4 (обмежується кількістю вибраних сценаріїв). Використовуйте `--concurrency `, щоб налаштувати кількість workers, або `--concurrency 1` для старішої послідовної ланки. - - Повертає ненульовий код завершення, якщо будь-який сценарій завершується помилкою. Використовуйте `--allow-failures`, якщо вам потрібні артефакти без коду завершення з помилкою. - - Підтримує режими провайдерів `live-frontier`, `mock-openai` і `aimock`. - `aimock` запускає локальний сервер провайдера на базі AIMock для експериментального покриття fixture і protocol-mock без заміни ланки `mock-openai`, яка враховує сценарії. + - За замовчуванням запускає кілька вибраних сценаріїв паралельно з ізольованими Gateway-воркерами. Для `qa-channel` за замовчуванням використовується concurrency 4 (обмежується кількістю вибраних сценаріїв). Використовуйте `--concurrency `, щоб налаштувати кількість воркерів, або `--concurrency 1` для старішої послідовної смуги. + - Завершується з ненульовим кодом, якщо будь-який сценарій завершується помилкою. Використовуйте `--allow-failures`, якщо вам потрібні артефакти без коду завершення з помилкою. + - Підтримує режими провайдера `live-frontier`, `mock-openai` і `aimock`. + `aimock` запускає локальний сервер провайдера на базі AIMock для експериментального + покриття фікстур і протокольних моків без заміни сценарно-орієнтованої + смуги `mock-openai`. - `pnpm openclaw qa suite --runner multipass` - - Запускає той самий QA-набір у тимчасовій Linux VM Multipass. + - Запускає той самий QA-набір усередині тимчасової Linux VM Multipass. - Зберігає ту саму поведінку вибору сценаріїв, що й `qa suite` на хості. - Повторно використовує ті самі прапорці вибору провайдера/моделі, що й `qa suite`. - - Live-запуски передають підтримувані QA-входи автентифікації, які практичні для guest: - ключі провайдерів на основі env, шлях до конфігурації QA live provider і `CODEX_HOME`, якщо він присутній. - - Каталоги виводу мають залишатися в межах кореня репозиторію, щоб guest міг записувати назад через змонтований workspace. - - Записує звичайний QA-звіт + підсумок, а також логи Multipass у + - Live-запуски передають підтримувані QA-входи автентифікації, які практичні для гостьової системи: + ключі провайдера через env, шлях до конфігурації QA live provider і `CODEX_HOME`, якщо він присутній. + - Каталоги виводу мають залишатися в межах кореня репозиторію, щоб гостьова система могла записувати назад через змонтований робочий простір. + - Записує звичайний QA-звіт + підсумок, а також логи Multipass до `.artifacts/qa-e2e/...`. - `pnpm qa:lab:up` - Запускає QA-сайт на базі Docker для QA-роботи в операторському стилі. - `pnpm test:docker:bundled-channel-deps` - - Пакує та встановлює поточну збірку OpenClaw у Docker, запускає Gateway - з налаштованим OpenAI, а потім вмикає Telegram і Discord через редагування конфігурації. - - Перевіряє, що перший перезапуск Gateway встановлює runtime-залежності кожного bundled channel plugin на вимогу, а другий перезапуск не перевстановлює залежності, які вже були активовані. - - Також встановлює відому старішу базову версію npm, вмикає Telegram перед запуском - `openclaw update --tag ` і перевіряє, що post-update doctor у кандидата відновлює runtime-залежності bundled channels без postinstall-відновлення з боку harness. + - Пакує і встановлює поточну збірку OpenClaw у Docker, запускає Gateway + з налаштованим OpenAI, потім вмикає Telegram і Discord через редагування конфігурації. + - Перевіряє, що перший перезапуск Gateway встановлює runtime-залежності кожного вбудованого channel Plugin на вимогу, а другий перезапуск не перевстановлює залежності, які вже були активовані. + - Також встановлює відомий старіший базовий npm, вмикає Telegram перед запуском + `openclaw update --tag ` і перевіряє, що post-update doctor + у кандидата відновлює runtime-залежності вбудованих channel без + postinstall-виправлення з боку harness. - `pnpm openclaw qa aimock` - Запускає лише локальний сервер провайдера AIMock для прямого smoke-тестування протоколу. - `pnpm openclaw qa matrix` - - Запускає live QA-ланку Matrix проти тимчасового homeserver Tuwunel на базі Docker. - - Цей QA-хост наразі призначений лише для repo/dev. Упаковані встановлення OpenClaw не постачають `qa-lab`, тому вони не відкривають `openclaw qa`. - - Checkout-и репозиторію завантажують bundled runner безпосередньо; окремий крок встановлення plugin не потрібен. - - Надає три тимчасові користувачі Matrix (`driver`, `sut`, `observer`) плюс одну приватну кімнату, а потім запускає дочірній QA gateway з реальним Matrix plugin як transport SUT. + - Запускає live QA-смугу Matrix проти тимчасового homeserver Tuwunel на базі Docker. + - Цей QA-хост наразі призначений лише для репозиторію/розробки. Паковані встановлення OpenClaw не постачають `qa-lab`, тож вони не надають `openclaw qa`. + - Checkout-и репозиторію завантажують вбудований ранер безпосередньо; окремий крок встановлення Plugin не потрібен. + - Налаштовує трьох тимчасових користувачів Matrix (`driver`, `sut`, `observer`) плюс одну приватну кімнату, а потім запускає дочірній процес QA gateway з реальним Plugin Matrix як транспортом SUT. - За замовчуванням використовує закріплений стабільний образ Tuwunel `ghcr.io/matrix-construct/tuwunel:v1.5.1`. Перевизначте через `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE`, якщо потрібно протестувати інший образ. - - Matrix не надає спільних прапорців джерела облікових даних, оскільки ця ланка локально створює тимчасових користувачів. - - Записує QA-звіт Matrix, підсумок, артефакт observed-events і комбінований журнал виводу stdout/stderr у `.artifacts/qa-e2e/...`. + - Matrix не надає спільних прапорців джерела облікових даних, оскільки ця смуга локально створює тимчасових користувачів. + - Записує QA-звіт Matrix, підсумок, артефакт observed-events і комбінований лог stdout/stderr до `.artifacts/qa-e2e/...`. - `pnpm openclaw qa telegram` - - Запускає live QA-ланку Telegram проти реальної приватної групи, використовуючи токени driver і SUT bot із env. - - Потрібні `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` і `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`. Ідентифікатор групи має бути числовим Telegram chat id. - - Підтримує `--credential-source convex` для спільних пулових облікових даних. За замовчуванням використовуйте режим env або встановіть `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`, щоб увімкнути pooled leases. - - Повертає ненульовий код завершення, якщо будь-який сценарій завершується помилкою. Використовуйте `--allow-failures`, якщо вам потрібні артефакти без коду завершення з помилкою. - - Потрібні два різні боти в одній приватній групі, причому SUT bot має мати Telegram username. - - Для стабільного спостереження bot-to-bot увімкніть Bot-to-Bot Communication Mode у `@BotFather` для обох ботів і переконайтеся, що driver bot може спостерігати трафік ботів у групі. - - Записує QA-звіт Telegram, підсумок і артефакт observed-messages у `.artifacts/qa-e2e/...`. + - Запускає live QA-смугу Telegram проти реальної приватної групи, використовуючи токени ботів driver і SUT з env. + - Потребує `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` і `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`. Ідентифікатор групи має бути числовим Telegram chat id. + - Підтримує `--credential-source convex` для спільних пулінгових облікових даних. За замовчуванням використовуйте режим env або встановіть `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`, щоб перейти на пулінгові оренди. + - Завершується з ненульовим кодом, якщо будь-який сценарій завершується помилкою. Використовуйте `--allow-failures`, якщо вам потрібні артефакти без коду завершення з помилкою. + - Потребує двох різних ботів в одній приватній групі, причому бот SUT має надавати Telegram username. + - Для стабільного спостереження бот-за-ботом увімкніть Bot-to-Bot Communication Mode в `@BotFather` для обох ботів і переконайтеся, що бот driver може спостерігати груповий трафік ботів. + - Записує QA-звіт Telegram, підсумок і артефакт observed-messages до `.artifacts/qa-e2e/...`. -Live transport lanes мають один спільний стандартний контракт, щоб нові transports не відхилялися: +Live transport-смуги використовують один стандартний контракт, щоб нові транспорти не розходилися: `qa-channel` залишається широким синтетичним QA-набором і не входить до матриці покриття live transport. -| Ланка | Canary | Гейтінг згадок | Блокування allowlist | Відповідь верхнього рівня | Відновлення після перезапуску | Продовження в треді | Ізоляція тредів | Спостереження за реакціями | Команда help | -| -------- | ------ | -------------- | -------------------- | ------------------------- | ----------------------------- | ------------------- | --------------- | -------------------------- | ------------ | -| Matrix | x | x | x | x | x | x | x | x | | -| Telegram | x | | | | | | | | x | +| Lane | Canary | Mention gating | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command | +| -------- | ------ | -------------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | +| Matrix | x | x | x | x | x | x | x | x | | +| Telegram | x | | | | | | | | x | ### Спільні облікові дані Telegram через Convex (v1) -Коли для `openclaw qa telegram` увімкнено `--credential-source convex` (або `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`), QA lab отримує ексклюзивну оренду з пулу на базі Convex, надсилає Heartbeat цієї оренди, поки ланка працює, і звільняє оренду під час завершення роботи. +Коли для `openclaw qa telegram` увімкнено `--credential-source convex` (або `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`), +QA lab отримує ексклюзивну оренду з пулу на базі Convex, надсилає Heartbeat +для цієї оренди під час роботи смуги та звільняє оренду під час завершення роботи. -Еталонний scaffold проєкту Convex: +Каркас довідкового проєкту Convex: - `qa/convex-credential-broker/` Обов’язкові змінні середовища: -- `OPENCLAW_QA_CONVEX_SITE_URL` (наприклад, `https://your-deployment.convex.site`) +- `OPENCLAW_QA_CONVEX_SITE_URL` (наприклад `https://your-deployment.convex.site`) - Один секрет для вибраної ролі: - `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` для `maintainer` - `OPENCLAW_QA_CONVEX_SECRET_CI` для `ci` - Вибір ролі облікових даних: - CLI: `--credential-role maintainer|ci` - - Типове значення env: `OPENCLAW_QA_CREDENTIAL_ROLE` (типово `ci` у CI, інакше `maintainer`) + - Типове значення з env: `OPENCLAW_QA_CREDENTIAL_ROLE` (типово `ci` у CI, інакше `maintainer`) Необов’язкові змінні середовища: @@ -135,13 +141,14 @@ Live transport lanes мають один спільний стандартний - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS` (типово `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX` (типово `/qa-credentials/v1`) - `OPENCLAW_QA_CREDENTIAL_OWNER_ID` (необов’язковий trace id) -- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` дозволяє loopback `http://` URL-адреси Convex лише для локальної розробки. +- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` дозволяє loopback `http://` URL Convex лише для локальної розробки. -У нормальному режимі `OPENCLAW_QA_CONVEX_SITE_URL` має використовувати `https://`. +У звичайному режимі `OPENCLAW_QA_CONVEX_SITE_URL` має використовувати `https://`. -Адміністративні команди maintainer (додавання/видалення/список пулу) вимагають саме `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`. +Адміністративні команди підтримувача (додавання/видалення/список пулу) вимагають +саме `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`. -CLI-хелпери для maintainers: +CLI-хелпери для підтримувачів: ```bash pnpm openclaw qa credentials add --kind telegram --payload-file qa/telegram-credential.json @@ -151,7 +158,7 @@ pnpm openclaw qa credentials remove --credential-id Використовуйте `--json` для машиночитаного виводу в скриптах і CI-утилітах. -Контракт типового endpoint (`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): +Контракт endpoint за замовчуванням (`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): - `POST /acquire` - Запит: `{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs }` @@ -169,12 +176,12 @@ pnpm openclaw qa credentials remove --credential-id - `POST /admin/remove` (лише секрет maintainer) - Запит: `{ credentialId, actorId }` - Успіх: `{ status: "ok", changed, credential }` - - Захист активної оренди: `{ status: "error", code: "LEASE_ACTIVE", ... }` + - Захист від активної оренди: `{ status: "error", code: "LEASE_ACTIVE", ... }` - `POST /admin/list` (лише секрет maintainer) - Запит: `{ kind?, status?, includePayload?, limit? }` - Успіх: `{ status: "ok", credentials, count }` -Форма payload для виду Telegram: +Форма payload для типу Telegram: - `{ groupId: string, driverToken: string, sutToken: string }` - `groupId` має бути рядком із числовим Telegram chat id. @@ -182,52 +189,53 @@ pnpm openclaw qa credentials remove --credential-id ### Додавання каналу до QA -Додавання каналу до markdown QA system вимагає рівно двох речей: +Додавання каналу до markdown QA-системи вимагає рівно двох речей: -1. Адаптер transport для каналу. -2. Набір сценаріїв, який перевіряє контракт каналу. +1. Транспортний адаптер для каналу. +2. Набір сценаріїв, що перевіряє контракт каналу. -Не додавайте новий кореневий QA-командний простір верхнього рівня, коли спільний хост `qa-lab` може керувати цим потоком. +Не додавайте новий top-level корінь QA-команд, коли спільний хост `qa-lab` може +володіти цим потоком. -`qa-lab` керує спільною механікою хоста: +`qa-lab` відповідає за спільну механіку хоста: -- кореневим командним простором `openclaw qa` -- запуском і завершенням набору -- concurrency workers -- записом артефактів -- генерацією звітів -- виконанням сценаріїв +- корінь команд `openclaw qa` +- запуск і завершення набору +- concurrency воркерів +- запис артефактів +- генерацію звітів +- виконання сценаріїв - aliases сумісності для старіших сценаріїв `qa-channel` -Плагіни раннерів керують контрактом transport: +Runner Plugin відповідають за транспортний контракт: - як `openclaw qa ` монтується під спільним коренем `qa` -- як Gateway налаштовується для цього transport +- як Gateway налаштовується для цього транспорту - як перевіряється готовність -- як ін’єктуються вхідні події +- як інжектуються вхідні події - як спостерігаються вихідні повідомлення -- як відкриваються транскрипти й нормалізований стан transport -- як виконуються дії на основі transport -- як обробляються скидання або очищення, специфічні для transport +- як надаються транскрипти й нормалізований стан транспорту +- як виконуються дії, підкріплені транспортом +- як обробляється специфічне для транспорту скидання або очищення -Мінімальний поріг прийняття для нового каналу: +Мінімальна планка впровадження для нового каналу: 1. Залишайте `qa-lab` власником спільного кореня `qa`. -2. Реалізуйте transport runner на спільному host seam `qa-lab`. -3. Залишайте transport-специфічну механіку всередині runner plugin або channel harness. -4. Монтуйте runner як `openclaw qa ` замість реєстрації конкуруючого кореневого command. - Runner plugins мають оголошувати `qaRunners` у `openclaw.plugin.json` і експортувати відповідний масив `qaRunnerCliRegistrations` із `runtime-api.ts`. - Залишайте `runtime-api.ts` легким; ліниві CLI і виконання runner мають залишатися за окремими entrypoints. +2. Реалізуйте транспортний ранер на спільному seam хоста `qa-lab`. +3. Зберігайте транспортно-специфічну механіку всередині runner Plugin або channel harness. +4. Монтуйте ранер як `openclaw qa ` замість реєстрації конкуруючої кореневої команди. + Runner Plugin мають оголошувати `qaRunners` у `openclaw.plugin.json` і експортувати відповідний масив `qaRunnerCliRegistrations` із `runtime-api.ts`. + Зберігайте `runtime-api.ts` легким; ліниві CLI і виконання раннера мають залишатися за окремими entrypoint. 5. Створюйте або адаптуйте markdown-сценарії в тематичних каталогах `qa/scenarios/`. -6. Використовуйте загальні scenario helpers для нових сценаріїв. -7. Підтримуйте наявні aliases сумісності, якщо тільки репозиторій не виконує навмисну міграцію. +6. Використовуйте загальні helper для сценаріїв у нових сценаріях. +7. Зберігайте наявні aliases сумісності працездатними, якщо тільки репозиторій не виконує навмисну міграцію. Правило ухвалення рішення суворе: - Якщо поведінку можна один раз виразити в `qa-lab`, розміщуйте її в `qa-lab`. -- Якщо поведінка залежить від одного channel transport, залишайте її в цьому runner plugin або plugin harness. -- Якщо сценарію потрібна нова можливість, яку може використовувати більше ніж один канал, додайте загальний helper замість channel-специфічної гілки в `suite.ts`. -- Якщо поведінка має сенс лише для одного transport, залишайте сценарій transport-специфічним і явно зазначайте це в контракті сценарію. +- Якщо поведінка залежить від одного channel transport, залишайте її в цьому runner Plugin або plugin harness. +- Якщо сценарію потрібна нова можливість, яку може використовувати більш ніж один channel, додайте загальний helper замість channel-специфічної гілки в `suite.ts`. +- Якщо поведінка має сенс лише для одного transport, залишайте сценарій transport-специфічним і явно відображайте це в контракті сценарію. Бажані назви загальних helper для нових сценаріїв: @@ -252,222 +260,236 @@ Aliases сумісності залишаються доступними для - `formatConversationTranscript` - `resetBus` -Нова робота з каналами має використовувати загальні назви helper. -Aliases сумісності існують, щоб уникнути міграції за прапорцевим днем, а не як модель для +Нова робота над channel має використовувати загальні назви helper. +Aliases сумісності існують, щоб уникнути міграції одним днем, а не як модель для створення нових сценаріїв. -## Набори тестів (що де запускається) +## Набори тестів (що запускається де) -Думайте про набори як про «зростання реалізму» (і зростання нестабільності/вартості): +Сприймайте набори як «зростання реалістичності» (і зростання нестабільності/вартості): ### Unit / integration (типово) - Команда: `pnpm test` -- Конфігурація: десять послідовних shard-запусків (`vitest.full-*.config.ts`) по наявних scoped Vitest projects -- Файли: інвентарі core/unit у `src/**/*.test.ts`, `packages/**/*.test.ts`, `test/**/*.test.ts` і дозволені node-тести `ui`, що охоплюються `vitest.unit.config.ts` +- Конфіг: десять послідовних shard-запусків (`vitest.full-*.config.ts`) поверх наявних scoped Vitest project +- Файли: інвентарі core/unit у `src/**/*.test.ts`, `packages/**/*.test.ts`, `test/**/*.test.ts` і whitelist-нуті node-тести `ui`, що покриваються `vitest.unit.config.ts` - Обсяг: - Чисті unit-тести - - In-process integration-тести (автентифікація gateway, маршрутизація, tooling, парсинг, конфігурація) - - Детерміновані регресійні тести для відомих помилок + - In-process integration-тести (автентифікація gateway, маршрутизація, tooling, парсинг, конфіг) + - Детерміновані регресії для відомих помилок - Очікування: - Запускається в CI - Реальні ключі не потрібні - Має бути швидким і стабільним -- Примітка щодо projects: - - Ненацілений `pnpm test` тепер запускає одинадцять менших shard-конфігурацій (`core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`) замість одного гігантського native root-project process. Це зменшує піковий RSS на завантажених машинах і не дає роботі auto-reply/extension виснажувати не пов’язані набори. - - `pnpm test --watch` і далі використовує native root граф project із `vitest.config.ts`, тому що multi-shard watch loop непрактичний. +- Примітка щодо project: + - Ненацілений `pnpm test` тепер запускає одинадцять менших shard-конфігів (`core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`) замість одного гігантського native root-project process. Це зменшує піковий RSS на завантажених машинах і не дає роботі auto-reply/extension виснажувати не пов’язані набори. + - `pnpm test --watch` усе ще використовує native root `vitest.config.ts` project graph, оскільки multi-shard watch-цикл непрактичний. - `pnpm test`, `pnpm test:watch` і `pnpm test:perf:imports` спочатку маршрутизують явні цілі файлів/каталогів через scoped lanes, тож `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` уникає повної вартості запуску root project. - - `pnpm test:changed` розгортає змінені git-шляхи в ті самі scoped lanes, коли diff торкається лише routable source/test files; редагування config/setup усе ще повертаються до широкого повторного запуску root-project. - - `pnpm check:changed` — це звичайний розумний локальний gate для вузької роботи. Він класифікує diff на core, core tests, extensions, extension tests, apps, docs, release metadata і tooling, а потім запускає відповідні lanes typecheck/lint/test. Зміни публічного Plugin SDK і plugin-contract включають перевірку extensions, тому що extensions залежать від цих core-контрактів. Підвищення версії лише в release metadata запускають цільові перевірки version/config/root-dependency замість повного набору, із захистом, що відхиляє зміни пакунків поза полем версії верхнього рівня. - - Легкі за імпортом unit-тести з agents, commands, plugins, helpers auto-reply, `plugin-sdk` та подібних чистих utility-областей маршрутизуються через lane `unit-fast`, яка пропускає `test/setup-openclaw-runtime.ts`; stateful/runtime-heavy files залишаються на наявних lanes. - - Деякі helper source files у `plugin-sdk` і `commands` також зіставляють запуски changed-mode з явними sibling tests у цих легких lanes, тож редагування helper уникають повторного запуску повного важкого набору для цього каталогу. - - `auto-reply` тепер має три окремі buckets: helpers core верхнього рівня, integration-тести верхнього рівня `reply.*` і піддерево `src/auto-reply/reply/**`. Це утримує найважчу роботу harness reply подалі від дешевих тестів status/chunk/token. -- Примітка про embedded runner: - - Коли ви змінюєте входи виявлення message-tool або runtime context Compaction, + - `pnpm test:changed` розгортає змінені git-шляхи в ті самі scoped lanes, коли diff торкається лише routable source/test-файлів; редагування config/setup усе ще повертаються до широкого повторного запуску root-project. + - `pnpm check:changed` — звичайна розумна локальна перевірка для вузької роботи. Вона класифікує diff на core, core tests, extensions, extension tests, apps, docs, release metadata і tooling, а потім запускає відповідні typecheck/lint/test-lanes. Зміни публічного Plugin SDK і plugin-contract включають перевірку extension, оскільки extensions залежать від цих core-контрактів. Зміни лише release metadata з version bump запускають цільові перевірки version/config/root-dependency замість повного набору, із guard, що відхиляє зміни package поза top-level полем version. + - Import-light unit-тести з agents, commands, plugins, helper auto-reply, `plugin-sdk` та подібних суто утилітарних зон маршрутизуються через lane `unit-fast`, який пропускає `test/setup-openclaw-runtime.ts`; stateful/runtime-heavy файли залишаються в наявних lanes. + - Вибрані helper source-файли `plugin-sdk` і `commands` також маплять запуски changed-mode на явні sibling-тести в цих легких lanes, тож редагування helper уникають повторного запуску повного важкого набору для цього каталогу. + - `auto-reply` тепер має три окремі buckets: top-level core helper, top-level integration-тести `reply.*` і піддерево `src/auto-reply/reply/**`. Це утримує найважчу роботу reply harness подалі від дешевих тестів status/chunk/token. +- Примітка щодо embedded runner: + - Коли ви змінюєте входи виявлення message-tool або runtime context для Compaction, зберігайте обидва рівні покриття. - Додавайте сфокусовані helper-регресії для чистих меж routing/normalization. - Також підтримуйте здоровими integration-набори embedded runner: `src/agents/pi-embedded-runner/compact.hooks.test.ts`, - `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, і + `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts` і `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`. - - Ці набори перевіряють, що scoped ids і поведінка Compaction і далі проходять - через реальні шляхи `run.ts` / `compact.ts`; лише helper-тести не є - достатньою заміною для цих integration-шляхів. -- Примітка про pool: + - Ці набори перевіряють, що scoped id і поведінка Compaction усе ще проходять + через реальні шляхи `run.ts` / `compact.ts`; одних лише helper-тестів + недостатньо як заміни для цих integration-шляхів. +- Примітка щодо pool: - Базова конфігурація Vitest тепер типово використовує `threads`. - - Спільна конфігурація Vitest також фіксує `isolate: false` і використовує non-isolated runner у root projects, e2e і live configs. - - Root lane UI зберігає своє налаштування `jsdom` і optimizer, але тепер теж працює на спільному non-isolated runner. + - Спільна конфігурація Vitest також фіксує `isolate: false` і використовує non-isolated runner у root project, конфігах e2e і live. + - Коренева UI lane зберігає своє налаштування `jsdom` і optimizer, але тепер також працює на спільному non-isolated runner. - Кожен shard `pnpm test` успадковує ті самі типові значення `threads` + `isolate: false` зі спільної конфігурації Vitest. - - Спільний launcher `scripts/run-vitest.mjs` тепер також типово додає `--no-maglev` для дочірніх Node-processes Vitest, щоб зменшити churn компіляції V8 під час великих локальних запусків. Установіть `OPENCLAW_VITEST_ENABLE_MAGLEV=1`, якщо потрібно порівняти зі стандартною поведінкою V8. -- Примітка про швидку локальну ітерацію: + - Спільний launcher `scripts/run-vitest.mjs` тепер також типово додає `--no-maglev` для дочірніх Node-process Vitest, щоб зменшити churn компіляції V8 під час великих локальних запусків. Встановіть `OPENCLAW_VITEST_ENABLE_MAGLEV=1`, якщо потрібно порівняти зі стандартною поведінкою V8. +- Примітка щодо швидкої локальної ітерації: - `pnpm changed:lanes` показує, які архітектурні lanes запускає diff. - - Pre-commit hook запускає `pnpm check:changed --staged` після staged formatting/linting, тож коміти лише core не оплачують вартість extension tests, якщо вони не торкаються публічних контрактів, орієнтованих на extensions. Коміти лише з release metadata залишаються на цільовій lane version/config/root-dependency. - - `pnpm test:changed` маршрутизується через scoped lanes, коли змінені шляхи чисто зіставляються з меншим набором. - - `pnpm test:max` і `pnpm test:changed:max` зберігають ту саму поведінку маршрутизації, лише з вищим лімітом workers. - - Автомасштабування локальних workers тепер навмисно консервативне й також зменшує навантаження, коли середнє завантаження хоста вже високе, тож кілька одночасних запусків Vitest за замовчуванням завдають менше шкоди. - - Базова конфігурація Vitest позначає projects/config files як `forceRerunTriggers`, щоб повторні запуски changed-mode залишалися коректними, коли змінюється wiring тестів. - - Конфігурація тримає `OPENCLAW_VITEST_FS_MODULE_CACHE` увімкненим на підтримуваних хостах; установіть `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`, якщо хочете одну явну локацію кешу для прямого профілювання. -- Примітка про налагодження продуктивності: - - `pnpm test:perf:imports` вмикає звітування Vitest про тривалість імпорту та вивід import-breakdown. - - `pnpm test:perf:imports:changed` обмежує той самий профільований огляд файлами, зміненими від `origin/main`. -- `pnpm test:perf:changed:bench -- --ref ` порівнює маршрутизований `test:changed` із native root-project path для цього зафіксованого diff і виводить wall time та macOS max RSS. -- `pnpm test:perf:changed:bench -- --worktree` виконує benchmark поточного брудного дерева, маршрутизуючи список змінених файлів через `scripts/test-projects.mjs` і root конфігурацію Vitest. - - `pnpm test:perf:profile:main` записує профіль CPU main-thread для накладних витрат запуску й трансформації Vitest/Vite. - - `pnpm test:perf:profile:runner` записує профілі CPU+heap runner для unit-набору з вимкненим паралелізмом файлів. + - Pre-commit hook запускає `pnpm check:changed --staged` після staged formatting/linting, тож core-only commits не оплачують вартість extension-тестів, якщо не торкаються публічних contract extension-facing. Коміти лише з release metadata залишаються на цільовій lane version/config/root-dependency. + - `pnpm test:changed` маршрутизує через scoped lanes, коли змінені шляхи чисто мапляться на менший набір. + - `pnpm test:max` і `pnpm test:changed:max` зберігають ту саму поведінку маршрутизації, лише з вищою межею воркерів. + - Автомасштабування локальних воркерів тепер навмисно консервативне й також відступає, коли середнє навантаження хоста вже високе, тож кілька одночасних запусків Vitest за замовчуванням завдають менше шкоди. + - Базова конфігурація Vitest позначає project/config-файли як `forceRerunTriggers`, щоб повторні запуски changed-mode залишалися коректними, коли змінюється wiring тестів. + - Конфіг зберігає ввімкненим `OPENCLAW_VITEST_FS_MODULE_CACHE` на підтримуваних хостах; встановіть `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`, якщо хочете одну явну локацію кешу для прямого профілювання. +- Примітка щодо perf-debug: + - `pnpm test:perf:imports` вмикає звітність Vitest про тривалість import плюс вивід розбивки import. + - `pnpm test:perf:imports:changed` звужує той самий профілювальний перегляд до файлів, змінених від `origin/main`. +- `pnpm test:perf:changed:bench -- --ref ` порівнює маршрутизований `test:changed` із native root-project path для цього зафіксованого diff і виводить wall time плюс macOS max RSS. +- `pnpm test:perf:changed:bench -- --worktree` виконує benchmark поточного брудного дерева, маршрутизуючи список змінених файлів через `scripts/test-projects.mjs` і root Vitest config. + - `pnpm test:perf:profile:main` записує main-thread CPU profile для накладних витрат запуску й transform у Vitest/Vite. + - `pnpm test:perf:profile:runner` записує runner CPU+heap profile для unit-набору з вимкненим file parallelism. + +### Stability (gateway) + +- Команда: `pnpm test:stability:gateway` +- Конфіг: `vitest.gateway.config.ts`, примусово один воркер +- Обсяг: + - Запускає реальний loopback Gateway із діагностикою, увімкненою за замовчуванням + - Проганяє синтетичне churn повідомлень gateway, пам’яті та великих payload через шлях діагностичних подій + - Виконує запити до `diagnostics.stability` через WS RPC Gateway + - Покриває helper персистентності bundle діагностики стабільності + - Перевіряє, що recorder залишається обмеженим, синтетичні вибірки RSS лишаються в межах бюджету тиску, а глибини черг на сеанс повертаються до нуля +- Очікування: + - Безпечно для CI і без ключів + - Вузька lane для подальшої роботи над регресіями стабільності, а не заміна повного набору Gateway ### E2E (gateway smoke) - Команда: `pnpm test:e2e` -- Конфігурація: `vitest.e2e.config.ts` +- Конфіг: `vitest.e2e.config.ts` - Файли: `src/**/*.e2e.test.ts`, `test/**/*.e2e.test.ts` -- Типові параметри runtime: - - Використовує Vitest `threads` з `isolate: false`, як і решта репозиторію. - - Використовує адаптивних workers (CI: до 2, локально: 1 за замовчуванням). - - За замовчуванням працює в silent mode, щоб зменшити накладні витрати на console I/O. +- Типові значення runtime: + - Використовує `threads` Vitest з `isolate: false`, узгоджено з рештою репозиторію. + - Використовує adaptive workers (CI: до 2, локально: 1 за замовчуванням). + - За замовчуванням запускається в silent mode, щоб зменшити накладні витрати на console I/O. - Корисні перевизначення: - - `OPENCLAW_E2E_WORKERS=`, щоб примусово задати кількість workers (обмеження 16). - - `OPENCLAW_E2E_VERBOSE=1`, щоб знову ввімкнути докладний вивід у консоль. + - `OPENCLAW_E2E_WORKERS=`, щоб примусово задати кількість воркерів (обмежено 16). + - `OPENCLAW_E2E_VERBOSE=1`, щоб знову ввімкнути докладний консольний вивід. - Обсяг: - - End-to-end-поведінка gateway з кількома інстансами - - Поверхні WebSocket/HTTP, pairing вузлів і важчі мережеві сценарії + - End-to-end поведінка gateway з кількома інстансами + - Поверхні WebSocket/HTTP, спарювання node і важче мережеве навантаження - Очікування: - Запускається в CI (коли увімкнено в pipeline) - Реальні ключі не потрібні - - Більше рухомих частин, ніж у unit-тестах (може бути повільніше) + - Більше рухомих частин, ніж у unit-тестів (може бути повільніше) ### E2E: smoke OpenShell backend - Команда: `pnpm test:e2e:openshell` - Файл: `test/openshell-sandbox.e2e.test.ts` - Обсяг: - - Запускає ізольований gateway OpenShell на хості через Docker + - Запускає ізольований Gateway OpenShell на хості через Docker - Створює sandbox із тимчасового локального Dockerfile - - Перевіряє backend OpenShell в OpenClaw через реальні `sandbox ssh-config` + SSH exec - - Перевіряє remote-canonical-поведінку файлової системи через sandbox fs bridge + - Перевіряє OpenShell backend OpenClaw через реальні `sandbox ssh-config` + SSH exec + - Перевіряє canonical-поведінку віддаленої файлової системи через fs bridge sandbox - Очікування: - Лише opt-in; не входить до типового запуску `pnpm test:e2e` - - Потрібні локальний CLI `openshell` і робочий Docker daemon - - Використовує ізольовані `HOME` / `XDG_CONFIG_HOME`, потім знищує test gateway і sandbox + - Потребує локальний CLI `openshell` і справний Docker daemon + - Використовує ізольовані `HOME` / `XDG_CONFIG_HOME`, а потім знищує тестовий Gateway і sandbox - Корисні перевизначення: - `OPENCLAW_E2E_OPENSHELL=1`, щоб увімкнути тест під час ручного запуску ширшого e2e-набору - - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`, щоб вказати нестандартний CLI binary або wrapper script + - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell`, щоб указати нестандартний бінарний файл CLI або wrapper-скрипт ### Live (реальні провайдери + реальні моделі) - Команда: `pnpm test:live` -- Конфігурація: `vitest.live.config.ts` +- Конфіг: `vitest.live.config.ts` - Файли: `src/**/*.live.test.ts` - Типово: **увімкнено** через `pnpm test:live` (встановлює `OPENCLAW_LIVE_TEST=1`) - Обсяг: - «Чи справді цей провайдер/модель працює _сьогодні_ з реальними обліковими даними?» - - Виявлення змін формату провайдера, особливостей виклику tool, проблем автентифікації та поведінки rate limit + - Виявлення змін формату провайдера, особливостей виклику інструментів, проблем автентифікації та поведінки rate limit - Очікування: - - Навмисно не стабільний для CI (реальні мережі, реальні політики провайдерів, квоти, збої) - - Коштує грошей / використовує rate limits - - Переважно запускайте звужені підмножини, а не «все» + - Навмисно нестабільно для CI (реальні мережі, реальні політики провайдера, квоти, збої) + - Коштує грошей / витрачає rate limit + - Краще запускати звужені підмножини, а не «все» - Live-запуски використовують `~/.profile`, щоб підхопити відсутні API-ключі. -- За замовчуванням live-запуски все ще ізолюють `HOME` і копіюють конфігурацію/матеріали автентифікації в тимчасовий test home, щоб unit-fixtures не могли змінити ваш реальний `~/.openclaw`. -- Установлюйте `OPENCLAW_LIVE_USE_REAL_HOME=1` лише тоді, коли вам навмисно потрібно, щоб live-тести використовували ваш реальний home directory. -- `pnpm test:live` тепер типово працює в тихішому режимі: він зберігає вивід прогресу `[live] ...`, але приховує додаткове повідомлення `~/.profile` і приглушує логи bootstrap Gateway/шум Bonjour. Установіть `OPENCLAW_LIVE_TEST_QUIET=0`, якщо хочете повернути повні логи запуску. -- Ротація API-ключів (специфічна для провайдера): встановіть `*_API_KEYS` у форматі comma/semicolon або `*_API_KEY_1`, `*_API_KEY_2` (наприклад, `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`) або перевизначення для конкретного live через `OPENCLAW_LIVE_*_KEY`; тести повторюються при відповідях rate limit. -- Вивід progress/heartbeat: - - Live-набори тепер виводять рядки прогресу в stderr, щоб довгі виклики провайдера було видно як активні, навіть коли захоплення консолі Vitest тихе. - - `vitest.live.config.ts` вимикає перехоплення консолі Vitest, тож рядки progress провайдера/Gateway передаються негайно під час live-запусків. +- За замовчуванням live-запуски все ще ізолюють `HOME` і копіюють матеріали config/auth у тимчасовий тестовий home, щоб unit-фікстури не могли змінити ваш реальний `~/.openclaw`. +- Встановлюйте `OPENCLAW_LIVE_USE_REAL_HOME=1` лише тоді, коли вам навмисно потрібно, щоб live-тести використовували ваш реальний домашній каталог. +- `pnpm test:live` тепер за замовчуванням працює в тихішому режимі: він зберігає вивід прогресу `[live] ...`, але приглушує додаткове повідомлення `~/.profile` і вимикає логи bootstrap Gateway/шум Bonjour. Встановіть `OPENCLAW_LIVE_TEST_QUIET=0`, якщо хочете знову отримати повні стартові логи. +- Ротація API-ключів (залежно від провайдера): встановіть `*_API_KEYS` у форматі через кому/крапку з комою або `*_API_KEY_1`, `*_API_KEY_2` (наприклад `OPENAI_API_KEYS`, `ANTHROPIC_API_KEYS`, `GEMINI_API_KEYS`) або використайте перевизначення для конкретного live-запуску через `OPENCLAW_LIVE_*_KEY`; тести повторюють спробу у відповідь на rate limit. +- Вивід прогресу/Heartbeat: + - Live-набори тепер виводять рядки прогресу в stderr, тож довгі виклики провайдера помітно активні, навіть коли перехоплення консолі Vitest працює тихо. + - `vitest.live.config.ts` вимикає перехоплення консолі Vitest, щоб рядки прогресу провайдера/Gateway передавалися негайно під час live-запусків. - Налаштовуйте Heartbeat direct-model через `OPENCLAW_LIVE_HEARTBEAT_MS`. - Налаштовуйте Heartbeat gateway/probe через `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS`. ## Який набір мені запускати? -Скористайтеся цією таблицею рішень: +Використовуйте цю таблицю рішень: -- Редагування логіки/тестів: запустіть `pnpm test` (і `pnpm test:coverage`, якщо ви багато чого змінили) -- Якщо торкалися мережевої взаємодії gateway / протоколу WS / pairing: додайте `pnpm test:e2e` -- Під час налагодження «мій бот не працює» / збоїв, специфічних для провайдера / виклику tool: запустіть звужений `pnpm test:live` +- Редагуєте логіку/тести: запускайте `pnpm test` (і `pnpm test:coverage`, якщо ви багато змінили) +- Торкаєтеся мережі Gateway / протоколу WS / спарювання: додайте `pnpm test:e2e` +- Налагоджуєте «мій бот не працює» / специфічні для провайдера збої / виклик інструментів: запускайте звужений `pnpm test:live` -## Live: перевірка можливостей Android Node +## Live: sweep можливостей Android node - Тест: `src/gateway/android-node.capabilities.live.test.ts` - Скрипт: `pnpm android:test:integration` -- Мета: викликати **кожну команду, яку наразі оголошує** підключений Android Node, і перевірити поведінку контракту команди. +- Мета: викликати **кожну команду, яку зараз оголошує** підключений Android node, і перевірити поведінку контракту команди. - Обсяг: - - Попередньо підготовлене/ручне налаштування (набір не встановлює/не запускає/не pair-ить застосунок). - - Перевірка `node.invoke` у gateway для вибраного Android Node, команда за командою. -- Обов’язкове попереднє налаштування: - - Android-застосунок уже підключено та спарено з gateway. - - Застосунок утримується на передньому плані. - - Для можливостей, які ви очікуєте як успішні, надано дозволи/згоду на захоплення. + - Попередньо підготовлене/ручне налаштування (набір не встановлює, не запускає і не спаровує app). + - Перевірка gateway `node.invoke` для вибраного Android node, команда за командою. +- Потрібне попереднє налаштування: + - Android app уже підключений і спарений із gateway. + - App утримується на передньому плані. + - Дозволи/згода на захоплення надані для можливостей, які ви очікуєте пройти. - Необов’язкові перевизначення цілі: - `OPENCLAW_ANDROID_NODE_ID` або `OPENCLAW_ANDROID_NODE_NAME`. - `OPENCLAW_ANDROID_GATEWAY_URL` / `OPENCLAW_ANDROID_GATEWAY_TOKEN` / `OPENCLAW_ANDROID_GATEWAY_PASSWORD`. -- Повні подробиці налаштування Android: [Android App](/uk/platforms/android) +- Повні відомості про налаштування Android: [Android App](/uk/platforms/android) -## Live: smoke-тест моделей (ключі профілів) +## Live: smoke моделі (ключі профілю) Live-тести поділено на два шари, щоб можна було ізолювати збої: -- «Direct model» показує, чи провайдер/модель взагалі може відповідати з наданим ключем. -- «Gateway smoke» показує, чи працює повний конвеєр gateway+agent для цієї моделі (сесії, історія, tools, policy sandbox тощо). +- «Direct model» показує, чи може провайдер/модель взагалі відповісти з наданим ключем. +- «Gateway smoke» показує, що повний конвеєр gateway+agent працює для цієї моделі (сеанси, історія, інструменти, політика sandbox тощо). -### Шар 1: пряме завершення моделі (без gateway) +### Шар 1: Direct model completion (без gateway) - Тест: `src/agents/models.profiles.live.test.ts` - Мета: - Перелічити виявлені моделі - - Використовувати `getApiKeyForModel`, щоб вибрати моделі, для яких у вас є облікові дані - - Виконати невелике завершення для кожної моделі (і цільові регресії, де потрібно) + - Використати `getApiKeyForModel`, щоб вибрати моделі, для яких у вас є облікові дані + - Виконати невелике completion для кожної моделі (і цільові регресії там, де потрібно) - Як увімкнути: - - `pnpm test:live` (або `OPENCLAW_LIVE_TEST=1`, якщо викликаєте Vitest напряму) -- Установіть `OPENCLAW_LIVE_MODELS=modern` (або `all`, alias для modern), щоб справді запустити цей набір; інакше він пропускається, щоб `pnpm test:live` залишався зосередженим на gateway smoke + - `pnpm test:live` (або `OPENCLAW_LIVE_TEST=1`, якщо запускаєте Vitest безпосередньо) +- Встановіть `OPENCLAW_LIVE_MODELS=modern` (або `all`, псевдонім для modern), щоб справді запустити цей набір; інакше він буде пропущений, щоб `pnpm test:live` залишався сфокусованим на gateway smoke - Як вибирати моделі: - - `OPENCLAW_LIVE_MODELS=modern`, щоб запустити сучасний allowlist (Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4) - - `OPENCLAW_LIVE_MODELS=all` — це alias для сучасного allowlist + - `OPENCLAW_LIVE_MODELS=modern`, щоб запустити modern allowlist (Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4) + - `OPENCLAW_LIVE_MODELS=all` є псевдонімом для modern allowlist - або `OPENCLAW_LIVE_MODELS="openai/gpt-5.4,anthropic/claude-opus-4-6,..."` (allowlist через кому) - - Розгортки modern/all за замовчуванням мають curated high-signal cap; установіть `OPENCLAW_LIVE_MAX_MODELS=0` для вичерпної сучасної розгортки або додатне число для меншого обмеження. + - Sweep modern/all за замовчуванням використовують curated high-signal cap; установіть `OPENCLAW_LIVE_MAX_MODELS=0` для вичерпного modern sweep або додатне число для меншого ліміту. - Як вибирати провайдерів: - `OPENCLAW_LIVE_PROVIDERS="google,google-antigravity,google-gemini-cli"` (allowlist через кому) - Звідки беруться ключі: - - За замовчуванням: сховище профілів і резервні значення env - - Установіть `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати **лише сховище профілів** + - За замовчуванням: profile store і резервні значення env + - Встановіть `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати **лише profile store** - Навіщо це існує: - - Відокремлює «API провайдера зламане / ключ недійсний» від «конвеєр gateway agent зламаний» - - Містить невеликі ізольовані регресії (приклад: OpenAI Responses/Codex Responses reasoning replay + потоки tool-call) + - Відокремлює «API провайдера зламаний / ключ недійсний» від «зламаний конвеєр gateway agent» + - Містить малі ізольовані регресії (приклад: потоки reasoning replay + tool-call для OpenAI Responses/Codex Responses) ### Шар 2: Gateway + smoke dev agent (що насправді робить "@openclaw") - Тест: `src/gateway/gateway-models.profiles.live.test.ts` - Мета: - Підняти in-process gateway - - Створити/оновити сесію `agent:dev:*` (перевизначення моделі для кожного запуску) - - Ітерувати моделі з ключами та перевіряти: - - «осмислену» відповідь (без tools) - - що реальний виклик tool працює (probe читання) - - необов’язкові додаткові probes tools (probe exec+read) - - що шляхи регресії OpenAI (лише tool-call → подальший запит) і далі працюють -- Подробиці probe (щоб ви могли швидко пояснювати збої): - - probe `read`: тест записує nonce-файл у workspace і просить agent `read` його та повернути nonce. - - probe `exec+read`: тест просить agent через `exec` записати nonce у тимчасовий файл, а потім прочитати його через `read`. + - Створити/пропатчити сеанс `agent:dev:*` (перевизначення моделі для кожного запуску) + - Перебрати моделі-з-ключами і перевірити: + - «осмислену» відповідь (без інструментів) + - що реальний виклик інструмента працює (read probe) + - необов’язкові додаткові перевірки інструментів (exec+read probe) + - що шляхи регресії OpenAI (лише tool-call → follow-up) продовжують працювати +- Деталі probe (щоб можна було швидко пояснювати збої): + - `read` probe: тест записує nonce-файл у workspace і просить агента `read` його та повернути nonce. + - `exec+read` probe: тест просить агента через `exec` записати nonce у тимчасовий файл, а потім через `read` прочитати його назад. - image probe: тест прикріплює згенерований PNG (cat + рандомізований код) і очікує, що модель поверне `cat `. - - Еталон реалізації: `src/gateway/gateway-models.profiles.live.test.ts` і `src/gateway/live-image-probe.ts`. + - Довідка щодо реалізації: `src/gateway/gateway-models.profiles.live.test.ts` і `src/gateway/live-image-probe.ts`. - Як увімкнути: - - `pnpm test:live` (або `OPENCLAW_LIVE_TEST=1`, якщо викликаєте Vitest напряму) + - `pnpm test:live` (або `OPENCLAW_LIVE_TEST=1`, якщо запускаєте Vitest безпосередньо) - Як вибирати моделі: - - За замовчуванням: сучасний allowlist (Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4) - - `OPENCLAW_LIVE_GATEWAY_MODELS=all` — це alias для сучасного allowlist - - Або встановіть `OPENCLAW_LIVE_GATEWAY_MODELS="provider/model"` (або список через кому), щоб звузити набір - - Розгортки modern/all для gateway за замовчуванням мають curated high-signal cap; установіть `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=0` для вичерпної сучасної розгортки або додатне число для меншого обмеження. -- Як вибирати провайдерів (уникати «всього OpenRouter»): + - Типово: modern allowlist (Opus/Sonnet 4.6+, GPT-5.x + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4) + - `OPENCLAW_LIVE_GATEWAY_MODELS=all` є псевдонімом для modern allowlist + - Або встановіть `OPENCLAW_LIVE_GATEWAY_MODELS="provider/model"` (або список через кому), щоб звузити вибір + - Sweep modern/all для gateway за замовчуванням використовують curated high-signal cap; установіть `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=0` для вичерпного modern sweep або додатне число для меншого ліміту. +- Як вибирати провайдерів (уникаючи «все через OpenRouter»): - `OPENCLAW_LIVE_GATEWAY_PROVIDERS="google,google-antigravity,google-gemini-cli,openai,anthropic,zai,minimax"` (allowlist через кому) -- Probes tool + image у цьому live-тесті завжди увімкнені: - - probe `read` + probe `exec+read` (навантаження на tools) - - image probe виконується, коли модель оголошує підтримку входу зображень - - Потік (високорівнево): - - Тест генерує маленький PNG із «CAT» + випадковим кодом (`src/gateway/live-image-probe.ts`) +- Probe інструментів і зображень у цьому live-тесті завжди увімкнені: + - `read` probe + `exec+read` probe (навантаження на інструменти) + - image probe запускається, коли модель оголошує підтримку вхідних зображень + - Потік (на високому рівні): + - Тест генерує крихітний PNG із «CAT» + випадковим кодом (`src/gateway/live-image-probe.ts`) - Надсилає його через `agent` `attachments: [{ mimeType: "image/png", content: "" }]` - Gateway парсить attachments у `images[]` (`src/gateway/server-methods/agent.ts` + `src/gateway/chat-attachments.ts`) - - Embedded agent передає моделі мультимодальне повідомлення користувача + - Embedded agent пересилає моделі мультимодальне повідомлення користувача - Перевірка: відповідь містить `cat` + код (допуск OCR: незначні помилки дозволені) -Порада: щоб побачити, що саме можна тестувати на вашій машині (і точні id `provider/model`), виконайте: +Порада: щоб побачити, що можна протестувати на вашій машині (і точні id `provider/model`), виконайте: ```bash openclaw models list @@ -478,22 +500,22 @@ openclaw models list --json - Тест: `src/gateway/gateway-cli-backend.live.test.ts` - Мета: перевірити конвеєр Gateway + agent, використовуючи локальний CLI backend, не торкаючись вашої типової конфігурації. -- Типові налаштування smoke для конкретного backend розміщено у визначенні `cli-backend.ts` відповідного extension. +- Типові значення smoke для конкретного backend живуть у визначенні `cli-backend.ts` extension-власника. - Увімкнення: - - `pnpm test:live` (або `OPENCLAW_LIVE_TEST=1`, якщо викликаєте Vitest напряму) + - `pnpm test:live` (або `OPENCLAW_LIVE_TEST=1`, якщо запускаєте Vitest безпосередньо) - `OPENCLAW_LIVE_CLI_BACKEND=1` - Типові значення: - - Типовий провайдер/модель: `claude-cli/claude-sonnet-4-6` - - Поведінка command/args/image береться з метаданих plugin CLI backend, якому вона належить. -- Перевизначення (необов’язково): + - Типові провайдер/модель: `claude-cli/claude-sonnet-4-6` + - Команда/аргументи/поведінка зображень беруться з метаданих Plugin CLI backend-власника. +- Перевизначення (необов’язкові): - `OPENCLAW_LIVE_CLI_BACKEND_MODEL="codex-cli/gpt-5.4"` - `OPENCLAW_LIVE_CLI_BACKEND_COMMAND="/full/path/to/codex"` - `OPENCLAW_LIVE_CLI_BACKEND_ARGS='["exec","--json","--color","never","--sandbox","read-only","--skip-git-repo-check"]'` - - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_PROBE=1`, щоб надіслати реальне вкладення-зображення (шляхи ін’єктуються в prompt). - - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG="--image"`, щоб передавати шляхи до файлів зображень як CLI args замість ін’єкції в prompt. - - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE="repeat"` (або `"list"`), щоб керувати тим, як передаються args зображень, коли встановлено `IMAGE_ARG`. - - `OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE=1`, щоб надіслати другий хід і перевірити потік resume. - - `OPENCLAW_LIVE_CLI_BACKEND_MODEL_SWITCH_PROBE=0`, щоб вимкнути типову перевірку безперервності тієї самої сесії Claude Sonnet -> Opus (установіть `1`, щоб примусово її ввімкнути, коли вибрана модель підтримує ціль перемикання). + - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_PROBE=1`, щоб надіслати реальне вкладення-зображення (шляхи інжектуються в prompt). + - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG="--image"`, щоб передавати шляхи до файлів зображень як аргументи CLI замість інжекції в prompt. + - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE="repeat"` (або `"list"`), щоб керувати передачею аргументів зображень, коли встановлено `IMAGE_ARG`. + - `OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE=1`, щоб надіслати другий хід і перевірити flow відновлення. + - `OPENCLAW_LIVE_CLI_BACKEND_MODEL_SWITCH_PROBE=0`, щоб вимкнути типовий probe безперервності одного сеансу Claude Sonnet -> Opus (установіть `1`, щоб примусово увімкнути його, коли вибрана модель підтримує ціль перемикання). Приклад: @@ -520,28 +542,28 @@ pnpm test:docker:live-cli-backend:gemini Примітки: -- Docker-runner розташований у `scripts/test-live-cli-backend-docker.sh`. -- Він запускає smoke CLI-backend live всередині Docker-образу репозиторію як непривілейований користувач `node`. -- Він визначає метадані smoke CLI з extension-власника, а потім встановлює відповідний Linux CLI package (`@anthropic-ai/claude-code`, `@openai/codex` або `@google/gemini-cli`) у кешований записуваний prefix за адресою `OPENCLAW_DOCKER_CLI_TOOLS_DIR` (типово: `~/.cache/openclaw/docker-cli-tools`). -- `pnpm test:docker:live-cli-backend:claude-subscription` вимагає portable OAuth підписки Claude Code через або `~/.claude/.credentials.json` з `claudeAiOauth.subscriptionType`, або `CLAUDE_CODE_OAUTH_TOKEN` із `claude setup-token`. Спочатку він перевіряє прямий `claude -p` у Docker, а потім запускає два ходи Gateway CLI-backend без збереження змінних середовища ключа Anthropic API. Ця ланка підписки типово вимикає probes Claude MCP/tool та image, оскільки Claude наразі маршрутизує використання сторонніх застосунків через billing додаткового використання замість звичайних лімітів плану підписки. -- Smoke CLI-backend live тепер перевіряє той самий end-to-end-потік для Claude, Codex і Gemini: текстовий хід, хід класифікації зображення, потім виклик tool `cron` через MCP, перевірений через CLI gateway. -- Типовий smoke Claude також оновлює сесію із Sonnet до Opus і перевіряє, що відновлена сесія все ще пам’ятає попередню нотатку. +- Docker-ранер розміщений у `scripts/test-live-cli-backend-docker.sh`. +- Він запускає live smoke CLI-backend усередині Docker-образу репозиторію від імені непривілейованого користувача `node`. +- Він визначає метадані smoke CLI з extension-власника, а потім встановлює відповідний Linux CLI-пакет (`@anthropic-ai/claude-code`, `@openai/codex` або `@google/gemini-cli`) у кешований writable-префікс за адресою `OPENCLAW_DOCKER_CLI_TOOLS_DIR` (типово: `~/.cache/openclaw/docker-cli-tools`). +- `pnpm test:docker:live-cli-backend:claude-subscription` вимагає portable OAuth підписки Claude Code через або `~/.claude/.credentials.json` із `claudeAiOauth.subscriptionType`, або `CLAUDE_CODE_OAUTH_TOKEN` із `claude setup-token`. Спочатку він доводить прямий `claude -p` у Docker, а потім запускає два ходи Gateway CLI-backend без збереження env-змінних API-ключа Anthropic. Ця смуга підписки за замовчуванням вимикає probe MCP/tool Claude та зображень, оскільки Claude наразі маршрутизує використання сторонніх app через виставлення рахунків за додаткове використання замість звичайних лімітів плану підписки. +- Live smoke CLI-backend тепер перевіряє той самий end-to-end flow для Claude, Codex і Gemini: текстовий хід, хід класифікації зображення, потім виклик інструмента MCP `cron`, перевірений через CLI Gateway. +- Типовий smoke Claude також патчить сеанс із Sonnet на Opus і перевіряє, що відновлений сеанс усе ще пам’ятає раніше записану нотатку. ## Live: smoke ACP bind (`/acp spawn ... --bind here`) - Тест: `src/gateway/gateway-acp-bind.live.test.ts` -- Мета: перевірити реальний потік bind розмови ACP з live ACP agent: +- Мета: перевірити реальний flow прив’язки розмови ACP з live ACP agent: - надіслати `/acp spawn --bind here` - - прив’язати синтетичну conversation message-channel на місці - - надіслати звичайний подальший запит у тій самій conversation - - перевірити, що подальший запит потрапляє в transcript прив’язаної сесії ACP + - прив’язати синтетичну розмову message-channel на місці + - надіслати звичайне follow-up у тій самій розмові + - перевірити, що follow-up потрапляє в транскрипт прив’язаного сеансу ACP - Увімкнення: - `pnpm test:live src/gateway/gateway-acp-bind.live.test.ts` - `OPENCLAW_LIVE_ACP_BIND=1` - Типові значення: - - ACP agents у Docker: `claude,codex,gemini` + - ACP agent у Docker: `claude,codex,gemini` - ACP agent для прямого `pnpm test:live ...`: `claude` - - Синтетичний канал: контекст conversation у стилі Slack DM + - Синтетичний channel: контекст розмови у стилі Slack DM - ACP backend: `acpx` - Перевизначення: - `OPENCLAW_LIVE_ACP_BIND_AGENT=claude` @@ -550,8 +572,8 @@ pnpm test:docker:live-cli-backend:gemini - `OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex,gemini` - `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND='npx -y @agentclientprotocol/claude-agent-acp@'` - Примітки: - - Ця ланка використовує поверхню `chat.send` у gateway з admin-only synthetic полями originating-route, щоб тести могли приєднувати контекст message-channel, не вдаючи зовнішню доставку. - - Коли `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND` не встановлено, тест використовує вбудований реєстр agent плагіна `acpx` для вибраного ACP harness agent. + - Ця смуга використовує поверхню gateway `chat.send` з синтетичними полями originating-route, доступними лише адміністратору, щоб тести могли прикріпити контекст message-channel, не вдаючи зовнішню доставку. + - Коли `OPENCLAW_LIVE_ACP_BIND_AGENT_COMMAND` не встановлено, тест використовує вбудований реєстр agent Plugin `acpx` для вибраного ACP harness agent. Приклад: @@ -577,35 +599,35 @@ pnpm test:docker:live-acp-bind:gemini Примітки щодо Docker: -- Docker-runner розташований у `scripts/test-live-acp-bind-docker.sh`. -- За замовчуванням він запускає smoke ACP bind послідовно для всіх підтримуваних live CLI agents: `claude`, `codex`, потім `gemini`. +- Docker-ранер розміщений у `scripts/test-live-acp-bind-docker.sh`. +- За замовчуванням він запускає smoke ACP bind послідовно для всіх підтримуваних live CLI agent: `claude`, `codex`, потім `gemini`. - Використовуйте `OPENCLAW_LIVE_ACP_BIND_AGENTS=claude`, `OPENCLAW_LIVE_ACP_BIND_AGENTS=codex` або `OPENCLAW_LIVE_ACP_BIND_AGENTS=gemini`, щоб звузити матрицю. -- Він використовує `~/.profile`, передає відповідні auth-матеріали CLI у контейнер, встановлює `acpx` у записуваний npm prefix, а потім встановлює потрібний live CLI (`@anthropic-ai/claude-code`, `@openai/codex` або `@google/gemini-cli`), якщо його немає. -- Усередині Docker runner встановлює `OPENCLAW_LIVE_ACP_BIND_ACPX_COMMAND=$HOME/.npm-global/bin/acpx`, щоб acpx зберігав змінні середовища провайдера з підключеного профілю доступними для дочірнього harness CLI. +- Він використовує `~/.profile`, переносить відповідні матеріали автентифікації CLI в контейнер, встановлює `acpx` у writable npm-префікс, а потім за потреби встановлює запитуваний live CLI (`@anthropic-ai/claude-code`, `@openai/codex` або `@google/gemini-cli`). +- Усередині Docker ранер встановлює `OPENCLAW_LIVE_ACP_BIND_ACPX_COMMAND=$HOME/.npm-global/bin/acpx`, щоб acpx зберігав змінні середовища провайдера зі source-профілю доступними для дочірнього CLI harness. -## Live: smoke harness Codex app-server +## Live: smoke Codex app-server harness -- Мета: перевірити harness Codex, якому належить plugin, через звичайний gateway - метод `agent`: - - завантажити bundled plugin `codex` +- Мета: перевірити Plugin-власний harness Codex через звичайний метод gateway + `agent`: + - завантажити вбудований Plugin `codex` - вибрати `OPENCLAW_AGENT_RUNTIME=codex` - надіслати перший хід gateway agent до `codex/gpt-5.4` - - надіслати другий хід до тієї самої сесії OpenClaw і перевірити, що thread + - надіслати другий хід до того самого сеансу OpenClaw і перевірити, що thread app-server може відновитися - - запустити `/codex status` і `/codex models` через той самий шлях gateway - command - - за потреби виконати дві escalated shell probes, перевірені Guardian: одну нешкідливу - command, яку слід схвалити, і одне фальшиве вивантаження секрету, яке має бути + - запустити `/codex status` і `/codex models` через той самий командний шлях + gateway + - за потреби запустити дві escalated shell probe, переглянуті Guardian: одну нешкідливу + команду, яку слід схвалити, і одне фальшиве вивантаження секрету, яке має бути відхилене, щоб agent перепитав - Тест: `src/gateway/gateway-codex-harness.live.test.ts` - Увімкнення: `OPENCLAW_LIVE_CODEX_HARNESS=1` - Типова модель: `codex/gpt-5.4` - Необов’язковий image probe: `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=1` -- Необов’язковий MCP/tool probe: `OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=1` -- Необов’язковий Guardian probe: `OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=1` -- Smoke встановлює `OPENCLAW_AGENT_HARNESS_FALLBACK=none`, щоб зламаний Codex - harness не міг пройти, тихо переключившись назад на Pi. -- Auth: `OPENAI_API_KEY` із shell/profile, а також необов’язково скопійовані +- Необов’язковий probe MCP/tool: `OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=1` +- Необов’язковий probe Guardian: `OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=1` +- Smoke встановлює `OPENCLAW_AGENT_HARNESS_FALLBACK=none`, щоб зламаний harness Codex + не міг пройти, непомітно переключившись назад на PI. +- Auth: `OPENAI_API_KEY` із shell/profile плюс необов’язково скопійовані `~/.codex/auth.json` і `~/.codex/config.toml` Локальний рецепт: @@ -629,21 +651,22 @@ pnpm test:docker:live-codex-harness Примітки щодо Docker: -- Docker-runner розташований у `scripts/test-live-codex-harness-docker.sh`. -- Він використовує змонтований `~/.profile`, передає `OPENAI_API_KEY`, копіює файли auth Codex CLI - за наявності, встановлює `@openai/codex` у записуваний змонтований npm - prefix, готує дерево вихідного коду, а потім запускає лише live-тест Codex-harness. -- Docker типово вмикає probes image, MCP/tool і Guardian. Установіть +- Docker-ранер розміщений у `scripts/test-live-codex-harness-docker.sh`. +- Він використовує змонтований `~/.profile`, передає `OPENAI_API_KEY`, копіює файли + автентифікації Codex CLI, якщо вони присутні, встановлює `@openai/codex` у writable змонтований npm- + префікс, переносить дерево вихідного коду, а потім запускає лише live-тест harness Codex. +- Docker за замовчуванням вмикає probe зображення, MCP/tool і Guardian. Установіть `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0` або `OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0` або - `OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0`, коли вам потрібен вужчий запуск для налагодження. -- Docker також експортує `OPENCLAW_AGENT_HARNESS_FALLBACK=none`, як і live - test config, тож fallback `openai-codex/*` або Pi не може приховати регресію - Codex harness. + `OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0`, коли потрібен вужчий запуск + для налагодження. +- Docker також експортує `OPENCLAW_AGENT_HARNESS_FALLBACK=none`, узгоджено з конфігом + live-тесту, тож fallback `openai-codex/*` або PI не може приховати регресію + harness Codex. ### Рекомендовані live-рецепти -Вузькі, явні allowlist — найшвидші та найменш нестабільні: +Вузькі явні allowlist — найшвидші й найменш нестабільні: - Одна модель, direct (без gateway): - `OPENCLAW_LIVE_MODELS="openai/gpt-5.4" pnpm test:live src/agents/models.profiles.live.test.ts` @@ -651,7 +674,7 @@ pnpm test:docker:live-codex-harness - Одна модель, gateway smoke: - `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.4" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` -- Виклик tool у кількох провайдерів: +- Виклик інструментів у кількох провайдерів: - `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.4,anthropic/claude-opus-4-6,google/gemini-3-flash-preview,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` - Фокус на Google (API key Gemini + Antigravity): @@ -660,22 +683,22 @@ pnpm test:docker:live-codex-harness Примітки: -- `google/...` використовує API Gemini (API key). -- `google-antigravity/...` використовує OAuth-міст Antigravity (endpoint agent у стилі Cloud Code Assist). -- `google-gemini-cli/...` використовує локальний Gemini CLI на вашій машині (окрема auth + особливості tooling). +- `google/...` використовує Gemini API (API key). +- `google-antigravity/...` використовує OAuth-міст Antigravity (agent endpoint у стилі Cloud Code Assist). +- `google-gemini-cli/...` використовує локальний Gemini CLI на вашій машині (окрема автентифікація + особливості tooling). - Gemini API проти Gemini CLI: - - API: OpenClaw викликає розміщений Gemini API від Google через HTTP (API key / auth профілю); саме це більшість користувачів мають на увазі під «Gemini». - - CLI: OpenClaw викликає локальний binary `gemini`; він має власну auth і може поводитися інакше (підтримка streaming/tool/розбіжність версій). + - API: OpenClaw викликає розміщений Google Gemini API через HTTP (API key / автентифікація профілю); саме це більшість користувачів мають на увазі під «Gemini». + - CLI: OpenClaw викликає локальний бінарний файл `gemini`; він має власну автентифікацію і може поводитися інакше (підтримка streaming/tool/version skew). -## Live: матриця моделей (що ми охоплюємо) +## Live: матриця моделей (що ми покриваємо) -Фіксованого «списку моделей CI» не існує (live — opt-in), але це **рекомендовані** моделі, які варто регулярно покривати на машині розробника з ключами. +Фіксованого «списку моделей CI» немає (live — opt-in), але це **рекомендовані** моделі для регулярного покриття на машині розробника з ключами. -### Сучасний набір smoke (виклик tool + image) +### Сучасний smoke-набір (виклик інструментів + зображення) -Це запуск «поширених моделей», який ми очікуємо підтримувати в робочому стані: +Це запуск «поширених моделей», який ми очікуємо підтримувати працездатним: -- OpenAI (не Codex): `openai/gpt-5.4` (необов’язково: `openai/gpt-5.4-mini`) +- OpenAI (не-Codex): `openai/gpt-5.4` (необов’язково: `openai/gpt-5.4-mini`) - OpenAI Codex: `openai-codex/gpt-5.4` - Anthropic: `anthropic/claude-opus-4-6` (або `anthropic/claude-sonnet-4-6`) - Google (Gemini API): `google/gemini-3.1-pro-preview` і `google/gemini-3-flash-preview` (уникайте старіших моделей Gemini 2.x) @@ -683,12 +706,12 @@ pnpm test:docker:live-codex-harness - Z.AI (GLM): `zai/glm-4.7` - MiniMax: `minimax/MiniMax-M2.7` -Запустіть gateway smoke з tools + image: +Запуск smoke gateway з інструментами + зображенням: `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.4,openai-codex/gpt-5.4,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3-flash-preview,google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-flash,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts` -### Базовий рівень: виклик tool (Read + необов’язково Exec) +### Базовий рівень: виклик інструментів (Read + необов’язково Exec) -Виберіть щонайменше одну модель на сімейство провайдерів: +Виберіть принаймні одну модель для кожної родини провайдерів: - OpenAI: `openai/gpt-5.4` (або `openai/gpt-5.4-mini`) - Anthropic: `anthropic/claude-opus-4-6` (або `anthropic/claude-sonnet-4-6`) @@ -696,81 +719,81 @@ pnpm test:docker:live-codex-harness - Z.AI (GLM): `zai/glm-4.7` - MiniMax: `minimax/MiniMax-M2.7` -Необов’язкове додаткове покриття (було б добре мати): +Необов’язкове додаткове покриття (бажано мати): - xAI: `xai/grok-4` (або найновіша доступна) -- Mistral: `mistral/`… (виберіть одну модель із підтримкою `tools`, яку у вас увімкнено) -- Cerebras: `cerebras/`… (якщо маєте доступ) -- LM Studio: `lmstudio/`… (локально; виклик tool залежить від режиму API) +- Mistral: `mistral/`… (виберіть одну модель із підтримкою інструментів, яку у вас ввімкнено) +- Cerebras: `cerebras/`… (якщо у вас є доступ) +- LM Studio: `lmstudio/`… (локально; виклик інструментів залежить від режиму API) -### Vision: надсилання image (вкладення → мультимодальне повідомлення) +### Vision: надсилання зображення (вкладення → мультимодальне повідомлення) -Додайте принаймні одну модель із підтримкою image у `OPENCLAW_LIVE_GATEWAY_MODELS` (Claude/Gemini/OpenAI-варіанти з підтримкою vision тощо), щоб перевірити image probe. +Додайте принаймні одну модель із підтримкою зображень до `OPENCLAW_LIVE_GATEWAY_MODELS` (Claude/Gemini/OpenAI варіанти з підтримкою vision тощо), щоб перевірити image probe. -### Aggregators / alternate gateways +### Aggregators / альтернативні gateway Якщо у вас увімкнені ключі, ми також підтримуємо тестування через: -- OpenRouter: `openrouter/...` (сотні моделей; використовуйте `openclaw models scan`, щоб знайти відповідних кандидатів із підтримкою tool+image) -- OpenCode: `opencode/...` для Zen і `opencode-go/...` для Go (auth через `OPENCODE_API_KEY` / `OPENCODE_ZEN_API_KEY`) +- OpenRouter: `openrouter/...` (сотні моделей; використовуйте `openclaw models scan`, щоб знайти придатні кандидати з підтримкою інструментів і зображень) +- OpenCode: `opencode/...` для Zen і `opencode-go/...` для Go (автентифікація через `OPENCODE_API_KEY` / `OPENCODE_ZEN_API_KEY`) -Більше провайдерів, які можна включити до live-матриці (якщо маєте creds/config): +Більше провайдерів, які можна включити в live-матрицю (якщо у вас є облікові дані/конфіг): - Вбудовані: `openai`, `openai-codex`, `anthropic`, `google`, `google-vertex`, `google-antigravity`, `google-gemini-cli`, `zai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `groq`, `cerebras`, `mistral`, `github-copilot` -- Через `models.providers` (custom endpoints): `minimax` (cloud/API), а також будь-який проксі, сумісний з OpenAI/Anthropic (LM Studio, vLLM, LiteLLM тощо) +- Через `models.providers` (власні endpoint): `minimax` (cloud/API), а також будь-який проксі, сумісний з OpenAI/Anthropic (LM Studio, vLLM, LiteLLM тощо) -Порада: не намагайтеся жорстко закодувати в документації «всі моделі». Авторитетним списком є все, що повертає `discoverModels(...)` на вашій машині, плюс усі доступні ключі. +Порада: не намагайтеся жорстко закодувати в документації «усі моделі». Авторитетний список — це те, що повертає `discoverModels(...)` на вашій машині, плюс доступні ключі. ## Облікові дані (ніколи не комітьте) -Live-тести виявляють облікові дані так само, як це робить CLI. Практичні наслідки: +Live-тести знаходять облікові дані так само, як і CLI. Практичні наслідки: -- Якщо CLI працює, live-тести мають знаходити ті самі ключі. -- Якщо live-тест каже «немає creds», налагоджуйте це так само, як налагоджували б `openclaw models list` / вибір моделі. +- Якщо CLI працює, live-тести мають знайти ті самі ключі. +- Якщо live-тест каже «немає облікових даних», налагоджуйте це так само, як ви налагоджували б `openclaw models list` / вибір моделі. -- Auth-профілі для кожного агента: `~/.openclaw/agents//agent/auth-profiles.json` (саме це означають «ключі профілів» у live-тестах) -- Конфігурація: `~/.openclaw/openclaw.json` (або `OPENCLAW_CONFIG_PATH`) -- Каталог legacy state: `~/.openclaw/credentials/` (копіюється в staged live home за наявності, але це не основне сховище ключів профілів) -- Локальні live-запуски типово копіюють активну конфігурацію, файли `auth-profiles.json` для кожного агента, legacy `credentials/` і підтримувані зовнішні каталоги auth CLI у тимчасовий test home; staged live homes пропускають `workspace/` і `sandboxes/`, а перевизначення шляхів `agents.*.workspace` / `agentDir` видаляються, щоб probes не торкалися вашого реального host workspace. +- Профілі автентифікації для окремих agent: `~/.openclaw/agents//agent/auth-profiles.json` (саме це означає «profile keys» у live-тестах) +- Конфіг: `~/.openclaw/openclaw.json` (або `OPENCLAW_CONFIG_PATH`) +- Каталог застарілого стану: `~/.openclaw/credentials/` (копіюється в staged live home, якщо присутній, але це не основне сховище ключів профілю) +- Локальні live-запуски за замовчуванням копіюють активний конфіг, файли `auth-profiles.json` для окремих agent, застарілий `credentials/` і підтримувані зовнішні каталоги автентифікації CLI в тимчасовий test home; staged live home пропускають `workspace/` і `sandboxes/`, а перевизначення шляхів `agents.*.workspace` / `agentDir` прибираються, щоб probe не торкалися вашого реального host workspace. -Якщо ви хочете покладатися на env-ключі (наприклад, експортовані у вашому `~/.profile`), запускайте локальні тести після `source ~/.profile` або використовуйте Docker-ранери нижче (вони можуть монтувати `~/.profile` у контейнер). +Якщо ви хочете покладатися на ключі env (наприклад, експортовані у вашому `~/.profile`), запускайте локальні тести після `source ~/.profile` або використовуйте Docker-ранери нижче (вони можуть монтувати `~/.profile` у контейнер). -## Deepgram live (транскрибування аудіо) +## Live Deepgram (аудіотранскрипція) - Тест: `src/media-understanding/providers/deepgram/audio.live.test.ts` - Увімкнення: `DEEPGRAM_API_KEY=... DEEPGRAM_LIVE_TEST=1 pnpm test:live src/media-understanding/providers/deepgram/audio.live.test.ts` -## BytePlus live для coding plan +## Live BytePlus coding plan - Тест: `src/agents/byteplus.live.test.ts` - Увімкнення: `BYTEPLUS_API_KEY=... BYTEPLUS_LIVE_TEST=1 pnpm test:live src/agents/byteplus.live.test.ts` - Необов’язкове перевизначення моделі: `BYTEPLUS_CODING_MODEL=ark-code-latest` -## ComfyUI live для workflow медіа +## Live ComfyUI workflow media - Тест: `extensions/comfy/comfy.live.test.ts` - Увімкнення: `OPENCLAW_LIVE_TEST=1 COMFY_LIVE_TEST=1 pnpm test:live -- extensions/comfy/comfy.live.test.ts` - Обсяг: - - Перевіряє bundled шляхи comfy image, video і `music_generate` + - Перевіряє вбудовані шляхи comfy для зображень, відео та `music_generate` - Пропускає кожну можливість, якщо не налаштовано `models.providers.comfy.` - - Корисно після змін у надсиланні workflow comfy, polling, завантаженнях або реєстрації plugin + - Корисно після змін у надсиланні workflow comfy, polling, завантаженнях або реєстрації Plugin -## Live для генерації image +## Live: генерація зображень - Тест: `src/image-generation/runtime.live.test.ts` - Команда: `pnpm test:live src/image-generation/runtime.live.test.ts` - Harness: `pnpm test:live:media image` - Обсяг: - - Перелічує кожен зареєстрований plugin провайдера генерації image - - Перед probing завантажує відсутні env vars провайдерів із вашого shell входу (`~/.profile`) - - За замовчуванням використовує live/env API keys раніше, ніж збережені auth-профілі, щоб застарілі тестові ключі в `auth-profiles.json` не маскували реальні облікові дані shell - - Пропускає провайдерів без придатних auth/profile/model - - Запускає стандартні варіанти генерації image через спільну runtime-можливість: + - Перелічує кожен зареєстрований Plugin провайдера генерації зображень + - Завантажує відсутні env-змінні провайдера з вашої login shell (`~/.profile`) перед перевіркою + - За замовчуванням використовує live/env API-ключі раніше за збережені профілі автентифікації, щоб застарілі тестові ключі в `auth-profiles.json` не маскували реальні облікові дані shell + - Пропускає провайдерів без придатної автентифікації/профілю/моделі + - Проганяє стандартні варіанти генерації зображень через спільну runtime-можливість: - `google:flash-generate` - `google:pro-generate` - `google:pro-edit` - `openai:default-generate` -- Поточні bundled провайдери, що охоплюються: +- Поточні вбудовані провайдери, що покриваються: - `openai` - `google` - `xai` @@ -778,76 +801,76 @@ Live-тести виявляють облікові дані так само, я - `OPENCLAW_LIVE_IMAGE_GENERATION_PROVIDERS="openai,google,xai"` - `OPENCLAW_LIVE_IMAGE_GENERATION_MODELS="openai/gpt-image-2,google/gemini-3.1-flash-image-preview,xai/grok-imagine-image"` - `OPENCLAW_LIVE_IMAGE_GENERATION_CASES="google:flash-generate,google:pro-edit,xai:default-generate,xai:default-edit"` -- Необов’язкова поведінка auth: - - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати auth зі сховища профілів та ігнорувати перевизначення лише через env +- Необов’язкова поведінка автентифікації: + - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати автентифікацію через сховище профілів і ігнорувати перевизначення лише з env -## Live для генерації музики +## Live: генерація музики - Тест: `extensions/music-generation-providers.live.test.ts` - Увімкнення: `OPENCLAW_LIVE_TEST=1 pnpm test:live -- extensions/music-generation-providers.live.test.ts` - Harness: `pnpm test:live:media music` - Обсяг: - - Перевіряє спільний bundled шлях провайдера генерації музики + - Перевіряє спільний шлях вбудованого провайдера генерації музики - Наразі охоплює Google і MiniMax - - Перед probing завантажує env vars провайдерів із вашого shell входу (`~/.profile`) - - За замовчуванням використовує live/env API keys раніше, ніж збережені auth-профілі, щоб застарілі тестові ключі в `auth-profiles.json` не маскували реальні облікові дані shell - - Пропускає провайдерів без придатних auth/profile/model + - Завантажує env-змінні провайдера з вашої login shell (`~/.profile`) перед перевіркою + - За замовчуванням використовує live/env API-ключі раніше за збережені профілі автентифікації, щоб застарілі тестові ключі в `auth-profiles.json` не маскували реальні облікові дані shell + - Пропускає провайдерів без придатної автентифікації/профілю/моделі - Запускає обидва оголошені runtime-режими, коли вони доступні: - `generate` з вхідними даними лише prompt - `edit`, коли провайдер оголошує `capabilities.edit.enabled` - - Поточне покриття спільної ланки: + - Поточне покриття спільної смуги: - `google`: `generate`, `edit` - `minimax`: `generate` - - `comfy`: окремий live-файл Comfy, а не ця спільна розгортка + - `comfy`: окремий live-файл Comfy, не цей спільний sweep - Необов’язкове звуження: - `OPENCLAW_LIVE_MUSIC_GENERATION_PROVIDERS="google,minimax"` - `OPENCLAW_LIVE_MUSIC_GENERATION_MODELS="google/lyria-3-clip-preview,minimax/music-2.5+"` -- Необов’язкова поведінка auth: - - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати auth зі сховища профілів та ігнорувати перевизначення лише через env +- Необов’язкова поведінка автентифікації: + - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати автентифікацію через сховище профілів і ігнорувати перевизначення лише з env -## Live для генерації відео +## Live: генерація відео - Тест: `extensions/video-generation-providers.live.test.ts` - Увімкнення: `OPENCLAW_LIVE_TEST=1 pnpm test:live -- extensions/video-generation-providers.live.test.ts` - Harness: `pnpm test:live:media video` - Обсяг: - - Перевіряє спільний bundled шлях провайдера генерації відео - - За замовчуванням використовує release-safe smoke path: провайдери без FAL, один запит text-to-video на провайдера, односекундний lobster prompt і обмеження операції на провайдера через `OPENCLAW_LIVE_VIDEO_GENERATION_TIMEOUT_MS` (`180000` типово) - - За замовчуванням пропускає FAL, оскільки затримка черги на боці провайдера може домінувати в часі релізу; передайте `--video-providers fal` або `OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS="fal"`, щоб запустити його явно - - Перед probing завантажує env vars провайдерів із вашого shell входу (`~/.profile`) - - За замовчуванням використовує live/env API keys раніше, ніж збережені auth-профілі, щоб застарілі тестові ключі в `auth-profiles.json` не маскували реальні облікові дані shell - - Пропускає провайдерів без придатних auth/profile/model + - Перевіряє спільний шлях вбудованого провайдера генерації відео + - За замовчуванням використовує release-safe шлях smoke: не-FAL провайдери, один запит text-to-video на провайдера, prompt із односекундним lobster і обмеження операції для кожного провайдера з `OPENCLAW_LIVE_VIDEO_GENERATION_TIMEOUT_MS` (`180000` за замовчуванням) + - За замовчуванням пропускає FAL, оскільки затримка черги на стороні провайдера може домінувати над часом release; передайте `--video-providers fal` або `OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS="fal"`, щоб запустити його явно + - Завантажує env-змінні провайдера з вашої login shell (`~/.profile`) перед перевіркою + - За замовчуванням використовує live/env API-ключі раніше за збережені профілі автентифікації, щоб застарілі тестові ключі в `auth-profiles.json` не маскували реальні облікові дані shell + - Пропускає провайдерів без придатної автентифікації/профілю/моделі - За замовчуванням запускає лише `generate` - - Установіть `OPENCLAW_LIVE_VIDEO_GENERATION_FULL_MODES=1`, щоб також запускати оголошені режими transform, коли вони доступні: - - `imageToVideo`, коли провайдер оголошує `capabilities.imageToVideo.enabled`, а вибраний провайдер/модель приймає локальний вхід image на основі buffer у спільній розгортці - - `videoToVideo`, коли провайдер оголошує `capabilities.videoToVideo.enabled`, а вибраний провайдер/модель приймає локальний вхід video на основі buffer у спільній розгортці - - Поточні провайдери `imageToVideo`, оголошені, але пропущені у спільній розгортці: - - `vydra`, тому що bundled `veo3` підтримує лише текст, а bundled `kling` вимагає віддалений image URL - - Специфічне для провайдера покриття Vydra: + - Встановіть `OPENCLAW_LIVE_VIDEO_GENERATION_FULL_MODES=1`, щоб також запускати оголошені режими transform, коли вони доступні: + - `imageToVideo`, коли провайдер оголошує `capabilities.imageToVideo.enabled`, а вибрані провайдер/модель приймають локальний вхід зображення на основі buffer у спільному sweep + - `videoToVideo`, коли провайдер оголошує `capabilities.videoToVideo.enabled`, а вибрані провайдер/модель приймають локальний відеовхід на основі buffer у спільному sweep + - Поточні оголошені, але пропущені провайдери `imageToVideo` у спільному sweep: + - `vydra`, оскільки вбудований `veo3` підтримує лише текст, а вбудований `kling` вимагає віддалений URL зображення + - Покриття Vydra, специфічне для провайдера: - `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_VYDRA_VIDEO=1 pnpm test:live -- extensions/vydra/vydra.live.test.ts` - - цей файл запускає `veo3` text-to-video плюс ланку `kling`, яка за замовчуванням використовує fixture із віддаленим image URL + - цей файл запускає `veo3` text-to-video плюс смугу `kling`, яка за замовчуванням використовує фікстуру з віддаленим URL зображення - Поточне live-покриття `videoToVideo`: - - лише `runway`, коли вибраною моделлю є `runway/gen4_aleph` - - Поточні провайдери `videoToVideo`, оголошені, але пропущені у спільній розгортці: - - `alibaba`, `qwen`, `xai`, оскільки ці шляхи наразі вимагають віддалені reference URL `http(s)` / MP4 - - `google`, оскільки поточна спільна ланка Gemini/Veo використовує локальний вхід на основі buffer, а цей шлях не приймається у спільній розгортці - - `openai`, оскільки поточна спільна ланка не гарантує доступ до video inpaint/remix, специфічний для org + - лише `runway`, коли вибрана модель — `runway/gen4_aleph` + - Поточні оголошені, але пропущені провайдери `videoToVideo` у спільному sweep: + - `alibaba`, `qwen`, `xai`, оскільки ці шляхи наразі вимагають віддалених URL-посилань `http(s)` / MP4 + - `google`, оскільки поточна спільна смуга Gemini/Veo використовує локальний вхід на основі buffer, і цей шлях не приймається у спільному sweep + - `openai`, оскільки поточна спільна смуга не гарантує доступ до video inpaint/remix, специфічний для org - Необов’язкове звуження: - `OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS="google,openai,runway"` - `OPENCLAW_LIVE_VIDEO_GENERATION_MODELS="google/veo-3.1-fast-generate-preview,openai/sora-2,runway/gen4_aleph"` - - `OPENCLAW_LIVE_VIDEO_GENERATION_SKIP_PROVIDERS=""`, щоб включити кожного провайдера до типової розгортки, включно з FAL - - `OPENCLAW_LIVE_VIDEO_GENERATION_TIMEOUT_MS=60000`, щоб зменшити обмеження операції для кожного провайдера під час агресивного smoke-запуску -- Необов’язкова поведінка auth: - - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати auth зі сховища профілів та ігнорувати перевизначення лише через env + - `OPENCLAW_LIVE_VIDEO_GENERATION_SKIP_PROVIDERS=""`, щоб включити кожного провайдера в типовий sweep, включно з FAL + - `OPENCLAW_LIVE_VIDEO_GENERATION_TIMEOUT_MS=60000`, щоб зменшити обмеження операції для кожного провайдера для агресивного smoke-запуску +- Необов’язкова поведінка автентифікації: + - `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб примусово використовувати автентифікацію через сховище профілів і ігнорувати перевизначення лише з env ## Media live harness - Команда: `pnpm test:live:media` - Призначення: - - Запускає спільні live-набори image, music і video через один repo-native entrypoint - - Автоматично завантажує відсутні env vars провайдерів із `~/.profile` - - За замовчуванням автоматично звужує кожен набір до провайдерів, які наразі мають придатну auth - - Повторно використовує `scripts/test-live.mjs`, тому поведінка Heartbeat і quiet mode залишається узгодженою + - Запускає спільні live-набори для зображень, музики й відео через один repo-native entrypoint + - Автоматично завантажує відсутні env-змінні провайдера з `~/.profile` + - За замовчуванням автоматично звужує кожен набір до провайдерів, які наразі мають придатну автентифікацію + - Повторно використовує `scripts/test-live.mjs`, тож поведінка Heartbeat і quiet mode залишається узгодженою - Приклади: - `pnpm test:live:media` - `pnpm test:live:media image video --providers openai,google,minimax` @@ -858,180 +881,180 @@ Live-тести виявляють облікові дані так само, я Ці Docker-ранери поділяються на дві групи: -- Live-model runners: `test:docker:live-models` і `test:docker:live-gateway` запускають лише відповідний live-файл ключів профілю всередині Docker-образу репозиторію (`src/agents/models.profiles.live.test.ts` і `src/gateway/gateway-models.profiles.live.test.ts`), монтують ваш локальний каталог конфігурації та workspace (і використовують `~/.profile`, якщо його змонтовано). Відповідні локальні entrypoints: `test:live:models-profiles` і `test:live:gateway-profiles`. -- Docker live runners за замовчуванням мають менше обмеження smoke, щоб повна Docker-розгортка залишалася практичною: - `test:docker:live-models` типово використовує `OPENCLAW_LIVE_MAX_MODELS=12`, а - `test:docker:live-gateway` типово використовує `OPENCLAW_LIVE_GATEWAY_SMOKE=1`, +- Live-model ранери: `test:docker:live-models` і `test:docker:live-gateway` запускають лише відповідний їм live-файл profile-key усередині Docker-образу репозиторію (`src/agents/models.profiles.live.test.ts` і `src/gateway/gateway-models.profiles.live.test.ts`), монтуючи ваш локальний каталог config і workspace (і використовуючи `~/.profile`, якщо він змонтований). Відповідні локальні entrypoint — `test:live:models-profiles` і `test:live:gateway-profiles`. +- Docker live-ранери за замовчуванням використовують менший smoke cap, щоб повний Docker sweep залишався практичним: + `test:docker:live-models` за замовчуванням використовує `OPENCLAW_LIVE_MAX_MODELS=12`, а + `test:docker:live-gateway` за замовчуванням використовує `OPENCLAW_LIVE_GATEWAY_SMOKE=1`, `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`, `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` і - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`. Перевизначайте ці env vars, коли + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`. Перевизначайте ці env-змінні, коли вам явно потрібне більше вичерпне сканування. -- `test:docker:all` один раз збирає live Docker image через `test:docker:live-build`, а потім повторно використовує його для двох Docker-ланок live. -- Container smoke runners: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:gateway-network`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools` і `test:docker:plugins` запускають один або кілька реальних контейнерів і перевіряють інтеграційні шляхи вищого рівня. +- `test:docker:all` один раз збирає live Docker image через `test:docker:live-build`, а потім повторно використовує його для двох Docker-смуг live. +- Smoke-ранери контейнерів: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:gateway-network`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools` і `test:docker:plugins` підіймають один або кілька реальних контейнерів і перевіряють високорівневі integration-шляхи. -Docker-ранери live-model також bind-mount-ять лише потрібні домівки auth CLI (або всі підтримувані, коли запуск не звужено), а потім копіюють їх у home контейнера перед запуском, щоб OAuth зовнішнього CLI міг оновлювати токени без зміни auth-сховища хоста: +Docker-ранери live-model також bind-mount лише потрібні home-каталоги автентифікації CLI (або всі підтримувані, коли запуск не звужений), а потім копіюють їх у home контейнера перед запуском, щоб OAuth зовнішнього CLI міг оновлювати токени, не змінюючи сховище автентифікації хоста: - Direct models: `pnpm test:docker:live-models` (скрипт: `scripts/test-live-models-docker.sh`) - Smoke ACP bind: `pnpm test:docker:live-acp-bind` (скрипт: `scripts/test-live-acp-bind-docker.sh`) - Smoke CLI backend: `pnpm test:docker:live-cli-backend` (скрипт: `scripts/test-live-cli-backend-docker.sh`) -- Smoke harness Codex app-server: `pnpm test:docker:live-codex-harness` (скрипт: `scripts/test-live-codex-harness-docker.sh`) +- Smoke Codex app-server harness: `pnpm test:docker:live-codex-harness` (скрипт: `scripts/test-live-codex-harness-docker.sh`) - Gateway + dev agent: `pnpm test:docker:live-gateway` (скрипт: `scripts/test-live-gateway-models-docker.sh`) - Live smoke Open WebUI: `pnpm test:docker:openwebui` (скрипт: `scripts/e2e/openwebui-docker.sh`) -- Wizard onboarding (TTY, повне scaffolding): `pnpm test:docker:onboard` (скрипт: `scripts/e2e/onboard-docker.sh`) -- Мережева взаємодія Gateway (два контейнери, auth + health WS): `pnpm test:docker:gateway-network` (скрипт: `scripts/e2e/gateway-network-docker.sh`) -- Міст каналу MCP (seeded Gateway + міст stdio + raw smoke notification-frame Claude): `pnpm test:docker:mcp-channels` (скрипт: `scripts/e2e/mcp-channels-docker.sh`) -- Pi bundle MCP tools (реальний stdio MCP server + embedded smoke allow/deny профілю Pi): `pnpm test:docker:pi-bundle-mcp-tools` (скрипт: `scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- Plugins (smoke встановлення + alias `/plugin` + semantics перезапуску Claude-bundle): `pnpm test:docker:plugins` (скрипт: `scripts/e2e/plugins-docker.sh`) -- Runtime-залежності bundled plugins: `pnpm test:docker:bundled-channel-deps` за замовчуванням збирає невеликий Docker-runner image, один раз збирає та пакує OpenClaw на хості, а потім монтує цей tarball у кожен сценарій встановлення Linux. Повторно використовуйте image через `OPENCLAW_SKIP_DOCKER_BUILD=1`, пропустіть повторну збірку хоста після свіжої локальної збірки через `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` або вкажіть наявний tarball через `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz`. -- Звужуйте runtime-залежності bundled plugins під час ітерацій, вимикаючи не пов’язані сценарії, наприклад: +- Onboarding wizard (TTY, повне scaffold): `pnpm test:docker:onboard` (скрипт: `scripts/e2e/onboard-docker.sh`) +- Мережа Gateway (два контейнери, автентифікація WS + health): `pnpm test:docker:gateway-network` (скрипт: `scripts/e2e/gateway-network-docker.sh`) +- MCP channel bridge (seeded Gateway + stdio bridge + raw smoke notification-frame Claude): `pnpm test:docker:mcp-channels` (скрипт: `scripts/e2e/mcp-channels-docker.sh`) +- Інструменти MCP пакета Pi (реальний stdio MCP server + вбудований smoke allow/deny профілю Pi): `pnpm test:docker:pi-bundle-mcp-tools` (скрипт: `scripts/e2e/pi-bundle-mcp-tools-docker.sh`) +- Plugins (install smoke + alias `/plugin` + семантика перезапуску пакета Claude): `pnpm test:docker:plugins` (скрипт: `scripts/e2e/plugins-docker.sh`) +- Runtime-залежності вбудованих Plugin: `pnpm test:docker:bundled-channel-deps` за замовчуванням збирає невеликий образ Docker-ранера, один раз збирає й пакує OpenClaw на хості, а потім монтує цей tarball у кожен сценарій встановлення Linux. Повторно використовуйте образ з `OPENCLAW_SKIP_DOCKER_BUILD=1`, пропускайте перебудову на хості після свіжої локальної збірки через `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0` або вкажіть наявний tarball через `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz`. +- Під час ітерації звужуйте runtime-залежності вбудованих Plugin, вимикаючи не пов’язані сценарії, наприклад: `OPENCLAW_BUNDLED_CHANNEL_SCENARIOS=0 OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO=0 pnpm test:docker:bundled-channel-deps`. -Docker-ранери live-model також bind-mount-ять поточний checkout у режимі лише читання і -готує його в тимчасовий workdir усередині контейнера. Це зберігає runtime -image компактним, водночас дозволяючи запускати Vitest точно проти вашого локального source/config. -Крок підготовки пропускає великі локальні кеші та виводи збірок застосунків, такі як -`.pnpm-store`, `.worktrees`, `__openclaw_vitest__` і локальні для застосунків каталоги `.build` або -виводу Gradle, щоб Docker live-запуски не витрачали хвилини на копіювання +Docker-ранери live-model також bind-mount поточний checkout у режимі лише для читання і +переносять його в тимчасовий workdir усередині контейнера. Це зберігає runtime- +image компактним, водночас запускаючи Vitest точно на вашому локальному source/config. +Крок перенесення пропускає великі локальні кеші й результати збірки app, такі як +`.pnpm-store`, `.worktrees`, `__openclaw_vitest__` і локальні для app каталоги `.build` або +виводу Gradle, щоб live-запуски Docker не витрачали хвилини на копіювання артефактів, специфічних для машини. -Вони також встановлюють `OPENCLAW_SKIP_CHANNELS=1`, щоб live-probes gateway не запускали -реальні workers каналів Telegram/Discord тощо всередині контейнера. +Вони також встановлюють `OPENCLAW_SKIP_CHANNELS=1`, щоб live-probe gateway не запускали +реальні channel-воркери Telegram/Discord тощо всередині контейнера. `test:docker:live-models` усе ще запускає `pnpm test:live`, тож також передавайте -`OPENCLAW_LIVE_GATEWAY_*`, коли потрібно звузити або виключити gateway -live-покриття з цієї Docker-ланки. -`test:docker:openwebui` — це smoke перевірка сумісності вищого рівня: вона запускає -контейнер Gateway OpenClaw з увімкненими HTTP endpoints, сумісними з OpenAI, -запускає контейнер Open WebUI із закріпленою версією проти цього gateway, виконує вхід через -Open WebUI, перевіряє, що `/api/models` відкриває `openclaw/default`, а потім надсилає -реальний chat-запит через проксі `/api/chat/completions` Open WebUI. -Перший запуск може бути помітно повільнішим, оскільки Docker може потребувати завантажити -image Open WebUI, а Open WebUI може потребувати завершити власне холодне налаштування запуску. -Ця ланка очікує придатний live-ключ моделі, а `OPENCLAW_PROFILE_FILE` -(`~/.profile` за замовчуванням) — основний спосіб надати його в Dockerized-запусках. -Успішні запуски виводять невеликий JSON payload на кшталт `{ "ok": true, "model": +`OPENCLAW_LIVE_GATEWAY_*`, коли потрібно звузити або виключити coverage gateway +live із цієї Docker-смуги. +`test:docker:openwebui` — це суміснісний smoke вищого рівня: він запускає +контейнер gateway OpenClaw з увімкненими HTTP-endpoint, сумісними з OpenAI, +запускає закріплений контейнер Open WebUI проти цього gateway, виконує вхід через +Open WebUI, перевіряє, що `/api/models` показує `openclaw/default`, а потім надсилає +реальний chat-запит через proxy `/api/chat/completions` Open WebUI. +Перший запуск може бути помітно повільнішим, оскільки Docker може потребувати завантаження +image Open WebUI, а самому Open WebUI може знадобитися завершити власне налаштування холодного старту. +Ця смуга очікує придатний ключ live-моделі, а `OPENCLAW_PROFILE_FILE` +(`~/.profile` за замовчуванням) є основним способом надати його в Dockerized-запусках. +Успішні запуски друкують невеликий JSON-payload на кшталт `{ "ok": true, "model": "openclaw/default", ... }`. `test:docker:mcp-channels` навмисно детермінований і не потребує -реального облікового запису Telegram, Discord або iMessage. Він запускає seeded контейнер -Gateway, запускає другий контейнер, який піднімає `openclaw mcp serve`, а потім -перевіряє виявлення conversation із маршрутизацією, читання transcript, metadata вкладень, -поведінку черги live events, маршрутизацію outbound send і channel Claude-style + -сповіщення про дозволи через реальний міст stdio MCP. Перевірка сповіщень -безпосередньо перевіряє raw frames stdio MCP, тож smoke перевіряє те, що -міст справді видає, а не лише те, що випадково відкриває певний client SDK. -`test:docker:pi-bundle-mcp-tools` є детермінованим і не потребує live -ключа моделі. Він збирає Docker image репозиторію, запускає реальний probe server stdio MCP -усередині контейнера, матеріалізує цей server через embedded runtime Pi bundle -MCP, виконує tool, а потім перевіряє, що `coding` і `messaging` зберігають -tools `bundle-mcp`, тоді як `minimal` і `tools.deny: ["bundle-mcp"]` їх фільтрують. +реального облікового запису Telegram, Discord або iMessage. Він запускає seeded Gateway- +контейнер, запускає другий контейнер, який стартує `openclaw mcp serve`, а потім +перевіряє виявлення маршрутизованих розмов, читання транскриптів, метадані вкладень, +поведінку черги live-подій, маршрутизацію вихідного надсилання та сповіщення про channel + +дозволи у стилі Claude через реальний міст stdio MCP. Перевірка сповіщень +безпосередньо інспектує сирі кадри stdio MCP, тож smoke перевіряє, що +міст фактично випромінює, а не лише те, що певний SDK клієнта випадково показує. +`test:docker:pi-bundle-mcp-tools` детермінований і не потребує +ключа live-моделі. Він збирає Docker-image репозиторію, запускає реальний probe-server stdio MCP +усередині контейнера, матеріалізує цей server через вбудований runtime MCP пакета Pi, +виконує інструмент, а потім перевіряє, що `coding` і `messaging` зберігають +інструменти `bundle-mcp`, тоді як `minimal` і `tools.deny: ["bundle-mcp"]` їх фільтрують. Ручний smoke plain-language thread ACP (не CI): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- Зберігайте цей скрипт для робочих процесів регресії/налагодження. Він може знову знадобитися для перевірки маршрутизації ACP thread, тому не видаляйте його. +- Зберігайте цей скрипт для робочих процесів регресії/налагодження. Він може знову знадобитися для перевірки маршрутизації ACP thread, тож не видаляйте його. -Корисні env vars: +Корисні env-змінні: -- `OPENCLAW_CONFIG_DIR=...` (типово: `~/.openclaw`) монтується в `/home/node/.openclaw` -- `OPENCLAW_WORKSPACE_DIR=...` (типово: `~/.openclaw/workspace`) монтується в `/home/node/.openclaw/workspace` -- `OPENCLAW_PROFILE_FILE=...` (типово: `~/.profile`) монтується в `/home/node/.profile` і використовується перед запуском тестів -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1`, щоб перевіряти лише env vars, використані з `OPENCLAW_PROFILE_FILE`, із тимчасовими каталогами config/workspace і без зовнішніх монтувань auth CLI -- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...` (типово: `~/.cache/openclaw/docker-cli-tools`) монтується в `/home/node/.npm-global` для кешованих встановлень CLI усередині Docker -- Зовнішні каталоги/файли auth CLI під `$HOME` монтуються лише для читання в `/host-auth...`, а потім копіюються в `/home/node/...` перед початком тестів +- `OPENCLAW_CONFIG_DIR=...` (за замовчуванням: `~/.openclaw`) монтується в `/home/node/.openclaw` +- `OPENCLAW_WORKSPACE_DIR=...` (за замовчуванням: `~/.openclaw/workspace`) монтується в `/home/node/.openclaw/workspace` +- `OPENCLAW_PROFILE_FILE=...` (за замовчуванням: `~/.profile`) монтується в `/home/node/.profile` і підключається через source перед запуском тестів +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1`, щоб перевіряти лише env-змінні, підключені через source з `OPENCLAW_PROFILE_FILE`, використовуючи тимчасові каталоги config/workspace і без mount зовнішньої автентифікації CLI +- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...` (за замовчуванням: `~/.cache/openclaw/docker-cli-tools`) монтується в `/home/node/.npm-global` для кешованих встановлень CLI всередині Docker +- Зовнішні каталоги/файли автентифікації CLI під `$HOME` монтуються лише для читання під `/host-auth...`, а потім копіюються в `/home/node/...` перед стартом тестів - Типові каталоги: `.minimax` - Типові файли: `~/.codex/auth.json`, `~/.codex/config.toml`, `.claude.json`, `~/.claude/.credentials.json`, `~/.claude/settings.json`, `~/.claude/settings.local.json` - - Звужені запуски провайдерів монтують лише потрібні каталоги/файли, виведені з `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` + - Звужені запуски провайдера монтують лише потрібні каталоги/файли, виведені з `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` - Перевизначайте вручну через `OPENCLAW_DOCKER_AUTH_DIRS=all`, `OPENCLAW_DOCKER_AUTH_DIRS=none` або список через кому, наприклад `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` - `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...`, щоб звузити запуск - `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...`, щоб фільтрувати провайдерів усередині контейнера -- `OPENCLAW_SKIP_DOCKER_BUILD=1`, щоб повторно використати наявний image `openclaw:local-live` для повторних запусків, які не потребують перебудови -- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб переконатися, що creds походять зі сховища профілів (а не з env) -- `OPENCLAW_OPENWEBUI_MODEL=...`, щоб вибрати модель, яку Gateway відкриває для smoke Open WebUI -- `OPENCLAW_OPENWEBUI_PROMPT=...`, щоб перевизначити nonce-check prompt, який використовує smoke Open WebUI +- `OPENCLAW_SKIP_DOCKER_BUILD=1`, щоб повторно використати наявний image `openclaw:local-live` для повторних запусків, яким не потрібна перебудова +- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1`, щоб переконатися, що облікові дані походять зі сховища профілів (а не з env) +- `OPENCLAW_OPENWEBUI_MODEL=...`, щоб вибрати модель, яку gateway показує для smoke Open WebUI +- `OPENCLAW_OPENWEBUI_PROMPT=...`, щоб перевизначити prompt перевірки nonce, який використовує smoke Open WebUI - `OPENWEBUI_IMAGE=...`, щоб перевизначити закріплений тег image Open WebUI ## Перевірка документації Після редагування документації запускайте перевірки docs: `pnpm check:docs`. -Запускайте повну перевірку якорів Mintlify, коли вам також потрібні перевірки заголовків у межах сторінки: `pnpm docs:check-links:anchors`. +Запускайте повну перевірку прив’язок Mintlify, коли вам також потрібні перевірки заголовків у межах сторінки: `pnpm docs:check-links:anchors`. ## Офлайн-регресія (безпечна для CI) Це регресії «реального конвеєра» без реальних провайдерів: -- Виклик tool у Gateway (mock OpenAI, реальний цикл gateway + agent): `src/gateway/gateway.test.ts` (випадок: "runs a mock OpenAI tool call end-to-end via gateway agent loop") -- Wizard Gateway (WS `wizard.start`/`wizard.next`, запис config + примусове застосування auth): `src/gateway/gateway.test.ts` (випадок: "runs wizard over ws and writes auth token config") +- Виклик інструментів Gateway (mock OpenAI, реальний цикл gateway + agent): `src/gateway/gateway.test.ts` (випадок: "runs a mock OpenAI tool call end-to-end via gateway agent loop") +- Майстер Gateway (WS `wizard.start`/`wizard.next`, запис config + примусова auth): `src/gateway/gateway.test.ts` (випадок: "runs wizard over ws and writes auth token config") -## Оцінювання надійності агентів (Skills) +## Оцінювання надійності agent (Skills) -У нас уже є кілька безпечних для CI тестів, які поводяться як «оцінювання надійності агентів»: +У нас уже є кілька безпечних для CI тестів, які поводяться як «оцінювання надійності agent»: -- Mock-виклик tool через реальний цикл gateway + agent (`src/gateway/gateway.test.ts`). -- End-to-end-потоки wizard, які перевіряють wiring сесії та ефекти конфігурації (`src/gateway/gateway.test.ts`). +- Mock-виклик інструментів через реальний цикл gateway + agent (`src/gateway/gateway.test.ts`). +- End-to-end потоки майстра, які перевіряють session wiring і ефекти config (`src/gateway/gateway.test.ts`). -Що ще відсутнє для Skills (див. [Skills](/uk/tools/skills)): +Чого ще бракує для Skills (див. [Skills](/uk/tools/skills)): -- **Вибір рішення:** коли Skills перелічені в prompt, чи вибирає агент правильний skill (або уникає нерелевантних)? -- **Відповідність:** чи читає агент `SKILL.md` перед використанням і чи дотримується потрібних кроків/args? -- **Контракти workflow:** багатокрокові сценарії, які перевіряють порядок tools, перенесення історії сесії та межі sandbox. +- **Вибір рішень:** коли Skills перелічено в prompt, чи вибирає agent правильний skill (або уникає нерелевантних)? +- **Відповідність:** чи читає agent `SKILL.md` перед використанням і чи виконує потрібні кроки/аргументи? +- **Контракти робочих процесів:** багатокрокові сценарії, які перевіряють порядок інструментів, перенесення історії сеансу та межі sandbox. -Майбутні оцінювання мають насамперед залишатися детермінованими: +Майбутні eval мають спершу залишатися детермінованими: -- Runner сценаріїв, який використовує mock-провайдери для перевірки викликів tools + порядку, читання skill files і wiring сесії. -- Невеликий набір сценаріїв, орієнтованих на skills (використати чи уникнути, gating, prompt injection). -- Необов’язкові live-оцінювання (opt-in, із gating через env) — лише після того, як буде готовий безпечний для CI набір. +- Ранер сценаріїв із mock-провайдерами для перевірки викликів інструментів + порядку, читання skill-файлів і wiring сеансів. +- Невеликий набір сценаріїв, сфокусованих на skill (використовувати чи уникати, gatekeeping, prompt injection). +- Необов’язкові live eval (opt-in, керовані env) лише після того, як буде готовий безпечний для CI набір. ## Контрактні тести (форма plugin і channel) Контрактні тести перевіряють, що кожен зареєстрований plugin і channel відповідає своєму -контракту інтерфейсу. Вони ітерують усі виявлені plugins і запускають набір -перевірок форми та поведінки. Типова unit-ланка `pnpm test` навмисно -пропускає ці shared seam і smoke files; запускайте контрактні команди явно, -коли торкаєтеся спільних поверхонь channel або provider. +контракту інтерфейсу. Вони перебирають усі виявлені plugins і запускають набір +перевірок форми та поведінки. Типова unit-смуга `pnpm test` навмисно +пропускає ці спільні seam- і smoke-файли; запускайте контрактні команди явно, +коли торкаєтеся спільних поверхонь channel або провайдера. ### Команди - Усі контракти: `pnpm test:contracts` - Лише контракти channel: `pnpm test:contracts:channels` -- Лише контракти provider: `pnpm test:contracts:plugins` +- Лише контракти провайдерів: `pnpm test:contracts:plugins` ### Контракти channel -Розташовані в `src/channels/plugins/contracts/*.contract.test.ts`: +Розміщені в `src/channels/plugins/contracts/*.contract.test.ts`: - **plugin** - Базова форма plugin (id, name, capabilities) -- **setup** - Контракт wizard налаштування -- **session-binding** - Поведінка прив’язування сесії +- **setup** - Контракт майстра налаштування +- **session-binding** - Поведінка прив’язки session - **outbound-payload** - Структура payload повідомлення - **inbound** - Обробка вхідних повідомлень - **actions** - Обробники дій channel - **threading** - Обробка ID thread - **directory** - API каталогу/реєстру -- **group-policy** - Застосування політики групи +- **group-policy** - Примусове застосування group policy -### Контракти статусу provider +### Контракти статусу провайдера -Розташовані в `src/plugins/contracts/*.contract.test.ts`. +Розміщені в `src/plugins/contracts/*.contract.test.ts`. -- **status** - Probes статусу channel -- **registry** - Форма реєстру plugin +- **status** - Probe статусу channel +- **registry** - Форма реєстру Plugin -### Контракти provider +### Контракти провайдера -Розташовані в `src/plugins/contracts/*.contract.test.ts`: +Розміщені в `src/plugins/contracts/*.contract.test.ts`: - **auth** - Контракт потоку auth -- **auth-choice** - Вибір/відбір auth +- **auth-choice** - Вибір/селектор auth - **catalog** - API каталогу моделей -- **discovery** - Виявлення plugin -- **loader** - Завантаження plugin -- **runtime** - Runtime provider -- **shape** - Форма/інтерфейс plugin -- **wizard** - Wizard налаштування +- **discovery** - Виявлення Plugin +- **loader** - Завантаження Plugin +- **runtime** - Runtime провайдера +- **shape** - Форма/інтерфейс Plugin +- **wizard** - Майстер налаштування ### Коли запускати -- Після зміни експортів або subpaths Plugin SDK -- Після додавання або зміни plugin channel або provider -- Після рефакторингу реєстрації або виявлення plugin +- Після зміни export або subpath у plugin-sdk +- Після додавання або зміни channel чи provider Plugin +- Після рефакторингу реєстрації Plugin або виявлення Контрактні тести запускаються в CI і не потребують реальних API-ключів. @@ -1039,11 +1062,11 @@ tools `bundle-mcp`, тоді як `minimal` і `tools.deny: ["bundle-mcp"]` їх Коли ви виправляєте проблему провайдера/моделі, виявлену в live: -- За можливості додайте безпечну для CI регресію (mock/stub провайдера або захопіть точну трансформацію форми запиту) -- Якщо вона за своєю природою лише live (rate limits, політики auth), залишайте live-тест вузьким і opt-in через env vars -- Віддавайте перевагу найменшому шару, який виявляє помилку: - - помилка перетворення/повторення запиту provider → direct models test - - помилка конвеєра сесії/історії/tool у gateway → gateway live smoke або безпечний для CI mock-тест gateway -- Захисна межа обходу SecretRef: - - `src/secrets/exec-secret-ref-id-parity.test.ts` виводить одну вибіркову ціль на клас SecretRef з метаданих реєстру (`listSecretTargetRegistryEntries()`), а потім перевіряє, що exec ids сегментів обходу відхиляються. - - Якщо ви додаєте нову родину цілей SecretRef `includeInPlan` у `src/secrets/target-registry-data.ts`, оновіть `classifyTargetClass` у цьому тесті. Тест навмисно завершується помилкою на некласифікованих target ids, щоб нові класи не могли бути пропущені безшумно. +- Якщо можливо, додавайте безпечну для CI регресію (mock/stub провайдера або фіксацію точної трансформації форми запиту) +- Якщо вона за своєю природою лише live (rate limit, політики auth), залишайте live-тест вузьким і opt-in через env-змінні +- Віддавайте перевагу найменшому шару, який ловить помилку: + - помилка конвертації/повтору запиту провайдера → direct models test + - помилка конвеєра session/history/tool gateway → gateway live smoke або безпечний для CI mock-тест gateway +- Guardrail для обходу SecretRef: + - `src/secrets/exec-secret-ref-id-parity.test.ts` виводить одну вибіркову ціль для кожного класу SecretRef з метаданих реєстру (`listSecretTargetRegistryEntries()`), а потім перевіряє, що exec-id сегментів обходу відхиляються. + - Якщо ви додаєте нову родину цілей SecretRef `includeInPlan` у `src/secrets/target-registry-data.ts`, оновіть `classifyTargetClass` у цьому тесті. Тест навмисно завершується помилкою для некласифікованих target id, щоб нові класи не можна було тихо пропустити.