diff --git a/docs/uk/gateway/protocol.md b/docs/uk/gateway/protocol.md index 7d77ee234..38694c572 100644 --- a/docs/uk/gateway/protocol.md +++ b/docs/uk/gateway/protocol.md @@ -1,29 +1,29 @@ --- read_when: - - Реалізація або оновлення клієнтів Gateway WS + - Реалізація або оновлення WS-клієнтів Gateway - Налагодження невідповідностей протоколу або збоїв підключення - - Повторне генерування схеми/моделей протоколу -summary: 'Протокол Gateway WebSocket: рукостискання, кадри, версіонування' + - Повторна генерація схем/моделей протоколу +summary: 'Протокол WebSocket Gateway: рукостискання, кадри, версіонування' title: Протокол Gateway x-i18n: - generated_at: "2026-04-10T06:30:21Z" + generated_at: "2026-04-16T00:43:06Z" model: gpt-5.4 provider: openai - source_hash: 83c820c46d4803d571c770468fd6782619eaa1dca253e156e8087dec735c127f + source_hash: 683e61ebe993a2d739bc34860060b0e3eda36b5c57267a2bcc03d177ec612fb3 source_path: gateway/protocol.md workflow: 15 --- # Протокол Gateway (WebSocket) -Протокол Gateway WS — це **єдина control plane + node transport** для -OpenClaw. Усі клієнти (CLI, веб-UI, застосунок macOS, вузли iOS/Android, headless -вузли) підключаються через WebSocket і оголошують свою **role** + **scope** під -час рукостискання. +Протокол WS Gateway — це **єдина контрольна площина + транспорт вузлів** для +OpenClaw. Усі клієнти (CLI, вебінтерфейс, застосунок macOS, вузли iOS/Android, +безголові вузли) підключаються через WebSocket і оголошують свою **роль** + +**область дії** під час рукостискання. ## Транспорт -- WebSocket, текстові кадри з JSON payload. +- WebSocket, текстові кадри з корисним навантаженням JSON. - Перший кадр **має** бути запитом `connect`. ## Рукостискання (connect) @@ -80,10 +80,24 @@ Gateway → Client: "type": "res", "id": "…", "ok": true, - "payload": { "type": "hello-ok", "protocol": 3, "policy": { "tickIntervalMs": 15000 } } + "payload": { + "type": "hello-ok", + "protocol": 3, + "server": { "version": "…", "connId": "…" }, + "features": { "methods": ["…"], "events": ["…"] }, + "snapshot": { "…": "…" }, + "policy": { + "maxPayload": 26214400, + "maxBufferedBytes": 52428800, + "tickIntervalMs": 15000 + } + } } ``` +`server`, `features`, `snapshot` і `policy` є обов’язковими згідно зі схемою +(`src/gateway/protocol/schema/frames.ts`). `auth` і `canvasHostUrl` є необов’язковими. + Коли видається токен пристрою, `hello-ok` також містить: ```json @@ -96,8 +110,8 @@ Gateway → Client: } ``` -Під час передавання довіреного bootstrap `hello-ok.auth` також може містити -додаткові обмежені записи ролей у `deviceTokens`: +Під час передавання в межах довіреного початкового завантаження `hello-ok.auth` +також може містити додаткові обмежені записи ролей у `deviceTokens`: ```json { @@ -116,15 +130,15 @@ Gateway → Client: } ``` -Для вбудованого потоку bootstrap node/operator основний токен вузла залишається -`scopes: []`, а будь-який переданий токен оператора залишається обмеженим -дозволеним списком bootstrap operator (`operator.approvals`, `operator.read`, -`operator.talk.secrets`, `operator.write`). Перевірки scope bootstrap -залишаються з префіксом role: записи operator задовольняють лише запити -operator, а ролі, що не є operator, усе одно потребують scope під власним -префіксом role. +Для вбудованого потоку початкового завантаження вузла/оператора основний токен +вузла зберігає `scopes: []`, а будь-який переданий токен оператора залишається +обмеженим списком дозволів bootstrap-оператора (`operator.approvals`, `operator.read`, +`operator.talk.secrets`, `operator.write`). Перевірки областей дії bootstrap +залишаються прив’язаними до префікса ролі: записи оператора задовольняють лише +запити оператора, а ролі, що не є оператором, усе одно потребують областей дії +у межах префікса власної ролі. -### Приклад node +### Приклад вузла ```json { @@ -165,18 +179,18 @@ operator, а ролі, що не є operator, усе одно потребуют - **Відповідь**: `{type:"res", id, ok, payload|error}` - **Подія**: `{type:"event", event, payload, seq?, stateVersion?}` -Методи з побічними ефектами потребують **idempotency keys** (див. схему). +Методи з побічними ефектами вимагають **ключі ідемпотентності** (див. схему). -## Roles + scopes +## Ролі + області дії -### Roles +### Ролі -- `operator` = клієнт control plane (CLI/UI/automation). +- `operator` = клієнт контрольної площини (CLI/UI/автоматизація). - `node` = хост можливостей (camera/screen/canvas/system.run). -### Scopes (operator) +### Області дії (operator) -Поширені scope: +Поширені області дії: - `operator.read` - `operator.write` @@ -188,427 +202,475 @@ operator, а ролі, що не є operator, усе одно потребуют Для `talk.config` з `includeSecrets: true` потрібен `operator.talk.secrets` (або `operator.admin`). -Зареєстровані plugin методи gateway RPC можуть вимагати власний scope operator, -але зарезервовані префікси core admin (`config.*`, `exec.approvals.*`, `wizard.*`, -`update.*`) завжди зводяться до `operator.admin`. +RPC-методи Gateway, зареєстровані плагінами, можуть вимагати власну область дії +оператора, але зарезервовані префікси основного адміністратора (`config.*`, `exec.approvals.*`, `wizard.*`, +`update.*`) завжди зіставляються з `operator.admin`. -Scope методу — лише перший бар’єр. Деякі slash-команди, до яких звертаються через -`chat.send`, застосовують додаткові суворіші перевірки на рівні команди. -Наприклад, постійні записи `/config set` і `/config unset` потребують `operator.admin`. +Область дії методу — лише перший рівень перевірки. Для деяких slash-команд, +доступних через `chat.send`, поверх цього застосовуються суворіші перевірки на +рівні команди. Наприклад, постійні записи `/config set` і `/config unset` +вимагають `operator.admin`. -`node.pair.approve` також має додаткову перевірку scope під час схвалення понад -базовий scope методу: +`node.pair.approve` також має додаткову перевірку області дії під час +затвердження поверх базової області дії методу: -- запити без команди: `operator.pairing` -- запити з командами вузла, що не є exec: `operator.pairing` + `operator.write` -- запити, які містять `system.run`, `system.run.prepare` або `system.which`: +- запити без команд: `operator.pairing` +- запити з не-exec-командами вузла: `operator.pairing` + `operator.write` +- запити, що включають `system.run`, `system.run.prepare` або `system.which`: `operator.pairing` + `operator.admin` ### Caps/commands/permissions (node) -Вузли оголошують claims можливостей під час підключення: +Вузли оголошують заявлені можливості під час підключення: - `caps`: високорівневі категорії можливостей. -- `commands`: allowlist команд для invoke. +- `commands`: список дозволених команд для invoke. - `permissions`: детальні перемикачі (наприклад, `screen.record`, `camera.capture`). -Gateway розглядає їх як **claims** і застосовує серверні allowlist. +Gateway розглядає їх як **заяви** і застосовує списки дозволів на боці сервера. ## Presence -- `system-presence` повертає записи, ключовані за ідентичністю пристрою. +- `system-presence` повертає записи, ключовані ідентичністю пристрою. - Записи presence містять `deviceId`, `roles` і `scopes`, щоб UI могли - показувати один рядок на пристрій, навіть якщо він підключений і як **operator**, + показувати один рядок на пристрій, навіть якщо він підключається і як **operator**, і як **node**. ## Поширені сімейства RPC-методів -Ця сторінка не є згенерованим повним дампом, але публічна поверхня WS ширша, -ніж наведені вище приклади рукостискання/автентифікації. Це основні сімейства +Ця сторінка не є згенерованим повним дампом, але публічна WS-поверхня ширша, +ніж наведені вище приклади рукостискання/автентифікації. Ось основні сімейства методів, які Gateway надає сьогодні. -`hello-ok.features.methods` — це консервативний список виявлення, зібраний із -`src/gateway/server-methods-list.ts` плюс експорти методів завантажених plugin/channel. -Сприймайте його як виявлення можливостей, а не як згенерований дамп кожного -викличного helper, реалізованого в `src/gateway/server-methods/*.ts`. +`hello-ok.features.methods` — це консервативний список виявлення, побудований з +`src/gateway/server-methods-list.ts` плюс експортів методів завантажених плагінів/каналів. +Сприймайте його як механізм виявлення можливостей, а не як згенерований дамп +кожного викликаного допоміжного методу, реалізованого в `src/gateway/server-methods/*.ts`. ### Система та ідентичність -- `health` повертає кешований або щойно перевірений знімок стану gateway. -- `status` повертає зведення gateway у стилі `/status`; чутливі поля - включаються лише для клієнтів operator з admin scope. -- `gateway.identity.get` повертає ідентичність пристрою gateway, яка - використовується в relay і потоках pairing. +- `health` повертає кешований або щойно перевірений знімок стану Gateway. +- `status` повертає зведення Gateway у стилі `/status`; чутливі поля + включаються лише для клієнтів operator з областю дії admin. +- `gateway.identity.get` повертає ідентичність пристрою Gateway, яка + використовується потоками relay і pairing. - `system-presence` повертає поточний знімок presence для підключених пристроїв operator/node. - `system-event` додає системну подію та може оновлювати/транслювати контекст presence. -- `last-heartbeat` повертає останню збережену подію heartbeat. -- `set-heartbeats` перемикає обробку heartbeat у gateway. +- `last-heartbeat` повертає останню збережену подію Heartbeat. +- `set-heartbeats` перемикає обробку Heartbeat на Gateway. ### Моделі та використання -- `models.list` повертає каталог моделей, дозволених під час виконання. -- `usage.status` повертає вікна використання провайдерів/зведення залишкової квоти. -- `usage.cost` повертає агреговані зведення використання вартості для діапазону дат. -- `doctor.memory.status` повертає готовність vector-memory / embedding для - активного робочого простору агента за замовчуванням. -- `sessions.usage` повертає зведення використання за сеансами. -- `sessions.usage.timeseries` повертає часовий ряд використання для одного сеансу. -- `sessions.usage.logs` повертає записи журналу використання для одного сеансу. +- `models.list` повертає каталог моделей, дозволених у середовищі виконання. +- `usage.status` повертає зведення вікон використання постачальника/залишку квоти. +- `usage.cost` повертає агреговані зведення вартості використання за діапазон дат. +- `doctor.memory.status` повертає стан готовності векторної пам’яті / embeddings + для активного робочого простору агента за замовчуванням. +- `sessions.usage` повертає зведення використання по сесіях. +- `sessions.usage.timeseries` повертає часовий ряд використання для однієї сесії. +- `sessions.usage.logs` повертає записи журналу використання для однієї сесії. -### Канали та помічники входу +### Канали та допоміжні засоби входу -- `channels.status` повертає зведення стану вбудованих і bundled channel/plugin. +- `channels.status` повертає зведення стану вбудованих і bundled каналів/плагінів. - `channels.logout` виходить із конкретного каналу/облікового запису, якщо канал підтримує вихід. -- `web.login.start` запускає QR/web потік входу для поточного провайдера - web-каналу з підтримкою QR. -- `web.login.wait` очікує завершення цього QR/web потоку входу та запускає - канал у разі успіху. -- `push.test` надсилає тестовий push APNs до зареєстрованого вузла iOS. -- `voicewake.get` повертає збережені тригери wake-word. -- `voicewake.set` оновлює тригери wake-word і транслює зміну. +- `web.login.start` запускає потік входу через QR/web для поточного QR-сумісного + постачальника вебканалу. +- `web.login.wait` очікує завершення цього потоку входу через QR/web і в разі + успіху запускає канал. +- `push.test` надсилає тестовий APNs push до зареєстрованого вузла iOS. +- `voicewake.get` повертає збережені тригери слів пробудження. +- `voicewake.set` оновлює тригери слів пробудження та транслює зміну. ### Повідомлення та журнали -- `send` — це прямий RPC outbound-delivery для надсилання з націлюванням на - channel/account/thread поза chat runner. -- `logs.tail` повертає tail налаштованого файлового журналу gateway з контролем - cursor/limit і max-byte. +- `send` — це прямий RPC доставки назовні для надсилання в канал/обліковий + запис/тему поза межами виконувача чату. +- `logs.tail` повертає хвіст налаштованого файлового журналу Gateway з + керуванням курсором/лімітом і максимальним розміром у байтах. ### Talk і TTS -- `talk.config` повертає ефективний payload конфігурації Talk; `includeSecrets` - потребує `operator.talk.secrets` (або `operator.admin`). +- `talk.config` повертає корисне навантаження ефективної конфігурації Talk; для + `includeSecrets` потрібен `operator.talk.secrets` (або `operator.admin`). - `talk.mode` встановлює/транслює поточний стан режиму Talk для клієнтів WebChat/Control UI. -- `talk.speak` синтезує мовлення через активного speech-провайдера Talk. -- `tts.status` повертає стан увімкнення TTS, активного провайдера, резервних - провайдерів і стан конфігурації провайдера. -- `tts.providers` повертає видимий інвентар провайдерів TTS. +- `talk.speak` синтезує мовлення через активного постачальника мовлення Talk. +- `tts.status` повертає стан увімкнення TTS, активного постачальника, + резервних постачальників і стан конфігурації постачальника. +- `tts.providers` повертає видимий інвентар постачальників TTS. - `tts.enable` і `tts.disable` перемикають стан налаштувань TTS. -- `tts.setProvider` оновлює бажаного провайдера TTS. -- `tts.convert` виконує одноразове перетворення text-to-speech. +- `tts.setProvider` оновлює бажаного постачальника TTS. +- `tts.convert` виконує одноразове перетворення тексту на мовлення. -### Секрети, конфігурація, оновлення та wizard +### Секрети, конфігурація, оновлення та майстер -- `secrets.reload` повторно розв’язує активні SecretRef і замінює стан секретів - під час виконання лише за повного успіху. -- `secrets.resolve` розв’язує призначення секретів цілі команди для конкретного - набору command/target. +- `secrets.reload` повторно зіставляє активні SecretRef і замінює стан секретів + у середовищі виконання лише за повного успіху. +- `secrets.resolve` зіставляє призначення секретів для цільового набору + команд/цілей. - `config.get` повертає поточний знімок конфігурації та хеш. -- `config.set` записує валідований payload конфігурації. +- `config.set` записує валідоване корисне навантаження конфігурації. - `config.patch` об’єднує часткове оновлення конфігурації. -- `config.apply` валідує і замінює повний payload конфігурації. -- `config.schema` повертає payload живої схеми конфігурації, який використовують - Control UI та інструменти CLI: schema, `uiHints`, версію та метадані - генерування, включно з метаданими схеми plugin + channel, коли runtime може +- `config.apply` виконує валідацію + повну заміну корисного навантаження конфігурації. +- `config.schema` повертає корисне навантаження живої схеми конфігурації, яке + використовують Control UI і CLI: схема, `uiHints`, версія та метадані генерації, + включно з метаданими схем плагінів + каналів, коли середовище виконання може їх завантажити. Схема містить метадані полів `title` / `description`, - похідні від тих самих міток і довідкового тексту, які використовує UI, - включно з вкладеним object, wildcard, array-item і гілками композиції - `anyOf` / `oneOf` / `allOf`, коли існує відповідна документація поля. -- `config.schema.lookup` повертає payload lookup з обмеженням шляхом для одного - шляху конфігурації: нормалізований шлях, вузол поверхневої схеми, підібрану - підказку + `hintPath` і зведення безпосередніх дочірніх елементів для - поглибленого перегляду в UI/CLI. - - Вузли схеми lookup зберігають документацію, орієнтовану на користувача, і - поширені поля валідації: `title`, `description`, `type`, `enum`, `const`, `format`, + отримані з тих самих міток і довідкового тексту, що використовуються в UI, + включно з вкладеними об’єктами, wildcard, елементами масиву та гілками + композиції `anyOf` / `oneOf` / `allOf`, коли існує відповідна документація полів. +- `config.schema.lookup` повертає корисне навантаження пошуку в межах шляху для + одного шляху конфігурації: нормалізований шлях, вузол неглибокої схеми, + відповідний hint + `hintPath` і зведення безпосередніх дочірніх елементів + для деталізації в UI/CLI. + - Вузли схеми lookup зберігають користувацьку документацію та поширені поля + валідації: `title`, `description`, `type`, `enum`, `const`, `format`, `pattern`, числові/рядкові/масивні/об’єктні межі та булеві прапорці, як-от `additionalProperties`, `deprecated`, `readOnly`, `writeOnly`. - Зведення дочірніх елементів містять `key`, нормалізований `path`, `type`, `required`, - `hasChildren`, а також підібрані `hint` / `hintPath`. -- `update.run` запускає потік оновлення gateway і планує перезапуск лише тоді, - коли саме оновлення виконалося успішно. + `hasChildren`, а також відповідні `hint` / `hintPath`. +- `update.run` запускає потік оновлення Gateway і планує перезапуск лише тоді, + коли саме оновлення було успішним. - `wizard.start`, `wizard.next`, `wizard.status` і `wizard.cancel` надають - onboarding wizard через WS RPC. + майстер онбордингу через WS RPC. ### Наявні основні сімейства -#### Помічники агента та робочого простору +#### Допоміжні засоби агента та робочого простору - `agents.list` повертає налаштовані записи агентів. - `agents.create`, `agents.update` і `agents.delete` керують записами агентів і прив’язкою робочого простору. - `agents.files.list`, `agents.files.get` і `agents.files.set` керують файлами - робочого простору bootstrap, доступними для агента. -- `agent.identity.get` повертає ефективну ідентичність асистента для агента або сеансу. -- `agent.wait` очікує завершення запуску та повертає термінальний знімок, коли - він доступний. + bootstrap-робочого простору, доступними для агента. +- `agent.identity.get` повертає ефективну ідентичність помічника для агента або + сесії. +- `agent.wait` очікує завершення виконання та повертає фінальний знімок, якщо він доступний. -#### Керування сеансом +#### Керування сесією -- `sessions.list` повертає поточний індекс сеансів. -- `sessions.subscribe` і `sessions.unsubscribe` вмикають або вимикають підписки - на події зміни сеансів для поточного WS-клієнта. -- `sessions.messages.subscribe` і `sessions.messages.unsubscribe` вмикають або - вимикають підписки на події transcript/message для одного сеансу. -- `sessions.preview` повертає обмежені попередні перегляди transcript для - конкретних ключів сеансу. -- `sessions.resolve` розв’язує або канонікалізує ціль сеансу. -- `sessions.create` створює новий запис сеансу. -- `sessions.send` надсилає повідомлення в наявний сеанс. -- `sessions.steer` — це варіант interrupt-and-steer для активного сеансу. -- `sessions.abort` перериває активну роботу для сеансу. -- `sessions.patch` оновлює метадані/перевизначення сеансу. +- `sessions.list` повертає поточний індекс сесій. +- `sessions.subscribe` і `sessions.unsubscribe` перемикають підписки на події + змін сесій для поточного WS-клієнта. +- `sessions.messages.subscribe` і `sessions.messages.unsubscribe` перемикають + підписки на події транскрипту/повідомлень для однієї сесії. +- `sessions.preview` повертає обмежені попередні перегляди транскриптів для + конкретних ключів сесій. +- `sessions.resolve` зіставляє або канонізує ціль сесії. +- `sessions.create` створює новий запис сесії. +- `sessions.send` надсилає повідомлення до наявної сесії. +- `sessions.steer` — це варіант переривання та спрямування для активної сесії. +- `sessions.abort` перериває активну роботу для сесії. +- `sessions.patch` оновлює метадані/перевизначення сесії. - `sessions.reset`, `sessions.delete` і `sessions.compact` виконують - обслуговування сеансу. -- `sessions.get` повертає повний збережений рядок сеансу. -- виконання chat, як і раніше, використовує `chat.history`, `chat.send`, `chat.abort` і + обслуговування сесії. +- `sessions.get` повертає повний збережений рядок сесії. +- виконання чату, як і раніше, використовує `chat.history`, `chat.send`, `chat.abort` і `chat.inject`. - `chat.history` нормалізується для відображення для UI-клієнтів: вбудовані теги - directives видаляються з видимого тексту, XML payload plain-text tool-call - (включно з `...`, `...`, + директив видаляються з видимого тексту, простотекстові XML-корисні + навантаження викликів інструментів (включно з + `...`, `...`, `...`, `...` і - обрізаними блоками tool-call) та витоки ASCII/full-width керувальних токенів - моделі видаляються, чисті рядки assistant із silent-token, такі як точні - `NO_REPLY` / `no_reply`, пропускаються, а надто великі рядки можуть - замінюватися placeholder. + усіченими блоками викликів інструментів) та витеклі ASCII/повноширинні токени + керування моделлю видаляються, чисті рядки помічника з беззвучними токенами, + як-от точні `NO_REPLY` / `no_reply`, пропускаються, а надто великі рядки + можуть бути замінені заповнювачами. #### Pairing пристроїв і токени пристроїв -- `device.pair.list` повертає очікувальні та схвалені paired devices. +- `device.pair.list` повертає очікувані й затверджені спарені пристрої. - `device.pair.approve`, `device.pair.reject` і `device.pair.remove` керують записами pairing пристроїв. -- `device.token.rotate` ротує токен paired device в межах схвалених role і - scope. -- `device.token.revoke` відкликає токен paired device. +- `device.token.rotate` ротує токен спареного пристрою в межах затверджених + обмежень ролі та області дії. +- `device.token.revoke` відкликає токен спареного пристрою. #### Pairing вузлів, invoke і відкладена робота - `node.pair.request`, `node.pair.list`, `node.pair.approve`, - `node.pair.reject` і `node.pair.verify` охоплюють pairing вузлів і - bootstrap verification. + `node.pair.reject` і `node.pair.verify` охоплюють pairing вузлів і bootstrap + verification. - `node.list` і `node.describe` повертають стан відомих/підключених вузлів. -- `node.rename` оновлює мітку paired node. +- `node.rename` оновлює мітку спареного вузла. - `node.invoke` пересилає команду підключеному вузлу. - `node.invoke.result` повертає результат для запиту invoke. - `node.event` переносить події, що походять від вузла, назад у gateway. -- `node.canvas.capability.refresh` оновлює токени canvas-capability з - обмеженим scope. +- `node.canvas.capability.refresh` оновлює токени можливостей canvas з + обмеженою областю дії. - `node.pending.pull` і `node.pending.ack` — це API черги підключеного вузла. - `node.pending.enqueue` і `node.pending.drain` керують стійкою відкладеною - роботою для офлайн/відключених вузлів. + роботою для офлайн-/відключених вузлів. -#### Сімейства approval +#### Сімейства погоджень - `exec.approval.request`, `exec.approval.get`, `exec.approval.list` і - `exec.approval.resolve` охоплюють одноразові запити exec approval плюс - lookup/replay відкладених approval. -- `exec.approval.waitDecision` очікує на один відкладений exec approval і + `exec.approval.resolve` охоплюють одноразові запити погодження exec, а також + пошук/повторення відкладених погоджень. +- `exec.approval.waitDecision` очікує на одне відкладене погодження exec і повертає остаточне рішення (або `null` у разі тайм-ауту). -- `exec.approvals.get` і `exec.approvals.set` керують знімками політики exec approval - gateway. +- `exec.approvals.get` і `exec.approvals.set` керують знімками політики + погоджень exec у gateway. - `exec.approvals.node.get` і `exec.approvals.node.set` керують локальною - політикою exec approval вузла через relay-команди вузла. + політикою погоджень exec вузла через relay-команди вузла. - `plugin.approval.request`, `plugin.approval.list`, - `plugin.approval.waitDecision` і `plugin.approval.resolve` охоплюють - потоки approval, визначені plugin. + `plugin.approval.waitDecision` і `plugin.approval.resolve` охоплюють потоки + погодження, визначені плагінами. #### Інші основні сімейства - automation: - - `wake` планує негайне або наступне введення тексту 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, такі як `chat.inject` та інші події chat, що - стосуються лише transcript. -- `session.message` і `session.tool`: оновлення transcript/event-stream для - сеансу, на який оформлено підписку. -- `sessions.changed`: індекс сеансів або метадані змінилися. +- `chat`: оновлення UI-чату, як-от `chat.inject` та інші події чату лише для + транскрипту. +- `session.message` і `session.tool`: оновлення транскрипту/потоку подій для + сесії, на яку оформлено підписку. +- `sessions.changed`: змінився індекс сесій або метадані. - `presence`: оновлення знімка system presence. - `tick`: періодична подія keepalive / liveness. -- `health`: оновлення знімка стану gateway. -- `heartbeat`: оновлення потоку подій heartbeat. -- `cron`: подія зміни виконання/завдання cron. -- `shutdown`: сповіщення про завершення роботи gateway. +- `health`: оновлення знімка стану Gateway. +- `heartbeat`: оновлення потоку подій Heartbeat. +- `cron`: подія зміни запуску/завдання Cron. +- `shutdown`: сповіщення про вимкнення Gateway. - `node.pair.requested` / `node.pair.resolved`: життєвий цикл pairing вузла. - `node.invoke.request`: трансляція запиту invoke вузла. -- `device.pair.requested` / `device.pair.resolved`: життєвий цикл paired-device. -- `voicewake.changed`: змінено конфігурацію тригера wake-word. +- `device.pair.requested` / `device.pair.resolved`: життєвий цикл спареного пристрою. +- `voicewake.changed`: змінено конфігурацію тригерів слів пробудження. - `exec.approval.requested` / `exec.approval.resolved`: життєвий цикл - exec approval. + погодження exec. - `plugin.approval.requested` / `plugin.approval.resolved`: життєвий цикл - plugin approval. + погодження плагіна. -### Допоміжні методи node +### Допоміжні методи вузла -- Nodes можуть викликати `skills.bins`, щоб отримати поточний список виконуваних - файлів skill для перевірок auto-allow. +- Вузли можуть викликати `skills.bins`, щоб отримати поточний список + виконуваних файлів навичок для перевірок автодозволу. -### Допоміжні методи operator +### Допоміжні методи оператора -- Operators можуть викликати `commands.list` (`operator.read`), щоб отримати - інвентар команд під час виконання для агента. - - `agentId` є необов’язковим; опустіть його, щоб читати робочий простір +- Оператори можуть викликати `commands.list` (`operator.read`), щоб отримати + інвентар команд часу виконання для агента. + - `agentId` є необов’язковим; не вказуйте його, щоб читати робочий простір агента за замовчуванням. - - `scope` визначає, яку поверхню націлює основна `name`: + - `scope` керує тим, яку поверхню використовує основний `name`: - `text` повертає основний текстовий токен команди без початкового `/` - - `native` і шлях за замовчуванням `both` повертають native names, - залежні від провайдера, коли вони доступні - - `textAliases` містить точні slash-аліаси, такі як `/model` і `/m`. - - `nativeName` містить native command name, залежне від провайдера, коли воно є. - - `provider` є необов’язковим і впливає лише на native naming плюс - доступність native plugin command. - - `includeArgs=false` прибирає із відповіді серіалізовані метадані аргументів. -- Operators можуть викликати `tools.catalog` (`operator.read`), щоб отримати каталог інструментів під час виконання для - агента. Відповідь містить згруповані інструменти та метадані походження: + - `native` і типовий шлях `both` повертають нативні імена з урахуванням + постачальника, коли вони доступні + - `textAliases` містить точні slash-аліаси, як-от `/model` і `/m`. + - `nativeName` містить нативну назву команди з урахуванням постачальника, + коли така існує. + - `provider` є необов’язковим і впливає лише на нативне найменування та + доступність нативних команд плагіна. + - `includeArgs=false` не включає серіалізовані метадані аргументів із відповіді. +- Оператори можуть викликати `tools.catalog` (`operator.read`), щоб отримати каталог інструментів + часу виконання для агента. Відповідь містить згруповані інструменти та метадані походження: - `source`: `core` або `plugin` - - `pluginId`: власник plugin, коли `source="plugin"` - - `optional`: чи є plugin tool необов’язковим -- Operators можуть викликати `tools.effective` (`operator.read`), щоб отримати інвентар інструментів, ефективний під час виконання, - для сеансу. + - `pluginId`: власник плагіна, коли `source="plugin"` + - `optional`: чи є інструмент плагіна необов’язковим +- Оператори можуть викликати `tools.effective` (`operator.read`), щоб отримати ефективний інвентар інструментів + часу виконання для сесії. - `sessionKey` є обов’язковим. - - Gateway виводить довірений runtime context із сеансу на стороні сервера, - замість приймати auth або delivery context, наданий викликачем. - - Відповідь має scope сеансу й відображає, що активна розмова може - використовувати просто зараз, включно з core, plugin і channel tools. -- Operators можуть викликати `skills.status` (`operator.read`), щоб отримати - видимий інвентар skills для агента. - - `agentId` є необов’язковим; опустіть його, щоб читати робочий простір + - Gateway виводить довірений контекст часу виконання з сесії на боці сервера + замість того, щоб приймати наданий викликачем контекст автентифікації або доставки. + - Відповідь прив’язана до сесії та відображає, що активна розмова може + використовувати прямо зараз, включно з інструментами core, plugin і channel. +- Оператори можуть викликати `skills.status` (`operator.read`), щоб отримати + видимий інвентар Skills для агента. + - `agentId` є необов’язковим; не вказуйте його, щоб читати робочий простір агента за замовчуванням. - - Відповідь містить eligibility, відсутні вимоги, перевірки config і - очищені параметри встановлення без розкриття необроблених значень secret. -- Operators можуть викликати `skills.search` і `skills.detail` (`operator.read`) для - метаданих виявлення ClawHub. -- Operators можуть викликати `skills.install` (`operator.admin`) у двох режимах: + - Відповідь містить відповідність вимогам, відсутні вимоги, перевірки + конфігурації та санітизовані параметри встановлення без розкриття сирих + секретних значень. +- Оператори можуть викликати `skills.search` і `skills.detail` (`operator.read`) + для метаданих виявлення ClawHub. +- Оператори можуть викликати `skills.install` (`operator.admin`) у двох режимах: - Режим ClawHub: `{ source: "clawhub", slug, version?, force? }` встановлює - папку skill у каталог `skills/` робочого простору агента за замовчуванням. - - Режим installer gateway: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` + теку навички до каталогу `skills/` робочого простору агента за замовчуванням. + - Режим інсталятора Gateway: `{ name, installId, dangerouslyForceUnsafeInstall?, timeoutMs? }` запускає оголошену дію `metadata.openclaw.install` на хості gateway. -- Operators можуть викликати `skills.update` (`operator.admin`) у двох режимах: - - Режим ClawHub оновлює один відстежуваний slug або всі відстежувані встановлення ClawHub у - робочому просторі агента за замовчуванням. - - Режим Config вносить зміни в значення `skills.entries.`, такі як `enabled`, - `apiKey` і `env`. +- Оператори можуть викликати `skills.update` (`operator.admin`) у двох режимах: + - Режим ClawHub оновлює один відстежуваний slug або всі відстежувані + встановлення ClawHub у робочому просторі агента за замовчуванням. + - Режим конфігурації вносить зміни до значень `skills.entries.`, + таких як `enabled`, `apiKey` і `env`. -## Exec approval +## Погодження exec -- Коли запит exec потребує approval, gateway транслює `exec.approval.requested`. -- Клієнти operator виконують підтвердження, викликаючи `exec.approval.resolve` (потрібен scope `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` як авторитетний контекст - command/cwd/session. + команди/cwd/сесії. - Якщо викликач змінює `command`, `rawCommand`, `cwd`, `agentId` або - `sessionKey` між prepare і остаточним пересиланням схваленого `system.run`, - gateway відхиляє виконання, замість того щоб довіряти зміненому payload. + `sessionKey` між prepare і остаточним пересиланням погодженого `system.run`, + gateway відхиляє запуск замість того, щоб довіряти зміненому корисному + навантаженню. ## Резервна доставка агента -- Запити `agent` можуть містити `deliver=true`, щоб запитати outbound delivery. -- `bestEffortDeliver=false` зберігає сувору поведінку: нерозв’язані або лише внутрішні цілі delivery повертають `INVALID_REQUEST`. -- `bestEffortDeliver=true` дозволяє резервний перехід до виконання лише в межах сеансу, коли неможливо розв’язати зовнішній маршрут доставки (наприклад, internal/webchat сеанси або неоднозначні multi-channel config). +- Запити `agent` можуть включати `deliver=true`, щоб запросити вихідну доставку. +- `bestEffortDeliver=false` зберігає сувору поведінку: нерозв’язані або лише внутрішні цілі доставки повертають `INVALID_REQUEST`. +- `bestEffortDeliver=true` дозволяє резервний перехід до виконання лише в межах сесії, якщо неможливо визначити зовнішній маршрут доставки (наприклад, для внутрішніх/webchat-сесій або неоднозначних багатоканальних конфігурацій). ## Версіонування -- `PROTOCOL_VERSION` знаходиться в `src/gateway/protocol/schema.ts`. +- `PROTOCOL_VERSION` розташовано в `src/gateway/protocol/schema/protocol-schemas.ts`. - Клієнти надсилають `minProtocol` + `maxProtocol`; сервер відхиляє невідповідності. - Схеми + моделі генеруються з визначень TypeBox: - `pnpm protocol:gen` - `pnpm protocol:gen:swift` - `pnpm protocol:check` +### Константи клієнта + +Еталонний клієнт у `src/gateway/client.ts` використовує ці типові значення. Ці +значення стабільні в межах протоколу v3 і є очікуваною базовою лінією для +сторонніх клієнтів. + +| Константа | Типове значення | Джерело | +| ----------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- | +| `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` (обмеження `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` | +| Пільговий період примусової зупинки перед `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`; клієнти повинні дотримуватися цих значень, +а не типових значень до рукостискання. + ## Автентифікація -- Автентифікація gateway зі спільним секретом використовує `connect.params.auth.token` або - `connect.params.auth.password`, залежно від налаштованого режиму auth. -- Режими з передаванням ідентичності, такі як Tailscale Serve - (`gateway.auth.allowTailscale: true`) або не-loopback - `gateway.auth.mode: "trusted-proxy"`, задовольняють перевірку auth під час connect за - заголовками запиту, а не через `connect.params.auth.*`. -- Private-ingress `gateway.auth.mode: "none"` повністю пропускає автентифікацію connect зі спільним секретом; не відкривайте цей режим для публічного/недовіреного ingress. -- Після pairing Gateway видає **токен пристрою** з обмеженням на role + scopes - підключення. Він повертається в `hello-ok.auth.deviceToken` і має бути - збережений клієнтом для майбутніх підключень. -- Клієнти повинні зберігати основний `hello-ok.auth.deviceToken` після будь-якого +- Автентифікація Gateway через спільний секрет використовує `connect.params.auth.token` або + `connect.params.auth.password` залежно від налаштованого режиму автентифікації. +- Режими з ідентичністю, як-от Tailscale Serve + (`gateway.auth.allowTailscale: true`) або non-loopback + `gateway.auth.mode: "trusted-proxy"`, проходять перевірку автентифікації connect за + заголовками запиту замість `connect.params.auth.*`. +- `gateway.auth.mode: "none"` для приватного ingress повністю пропускає + автентифікацію connect через спільний секрет; не відкривайте цей режим для + публічного/ненадійного ingress. +- Після pairing Gateway видає **токен пристрою**, обмежений роллю + областями + дії підключення. Він повертається в `hello-ok.auth.deviceToken` і має + зберігатися клієнтом для майбутніх підключень. +- Клієнти повинні зберігати основний `hello-ok.auth.deviceToken` після кожного успішного підключення. - Повторне підключення з цим **збереженим** токеном пристрою також має - повторно використовувати збережений набір схвалених scope для цього токена. - Це зберігає вже наданий доступ на читання/перевірку/status і запобігає - тихому звуженню повторних підключень до вужчого неявного scope лише admin. -- Звичайний пріоритет auth під час connect: спочатку явний спільний token/password, потім - явний `deviceToken`, потім збережений токен для пристрою, потім bootstrap token. + повторно використовувати збережений затверджений набір областей дії для цього + токена. Це зберігає вже наданий доступ для читання/перевірок/статусу й + запобігає непомітному звуженню повторних підключень до вужчої неявної + області дії лише admin. +- Формування автентифікації connect на боці клієнта (`selectConnectAuth` у + `src/gateway/client.ts`): + - `auth.password` є ортогональним і завжди пересилається, якщо заданий. + - `auth.token` заповнюється в такому порядку пріоритету: спочатку явний + спільний токен, потім явний `deviceToken`, потім збережений токен + пристрою для конкретного пристрою (ключ: `deviceId` + `role`). + - `auth.bootstrapToken` надсилається лише тоді, коли жоден із наведених вище + варіантів не дав значення для `auth.token`. Спільний токен або будь-який + визначений токен пристрою його пригнічує. + - Автопідвищення збереженого токена пристрою під час одноразової повторної + спроби `AUTH_TOKEN_MISMATCH` обмежене **лише довіреними endpoint** — + loopback або `wss://` із закріпленим `tlsFingerprint`. Публічний `wss://` + без pinning не підходить. - Додаткові записи `hello-ok.auth.deviceTokens` — це токени передавання bootstrap. - Зберігайте їх лише тоді, коли connect використовував bootstrap auth через - довірений транспорт, такий як `wss://` або loopback/local pairing. -- Якщо клієнт надає **явний** `deviceToken` або явні `scopes`, цей набір scope, - запитаний викликачем, залишається авторитетним; кешовані scope повторно - використовуються лише тоді, коли клієнт повторно використовує збережений токен для пристрою. -- Токени пристрою можна ротувати/відкликати через `device.token.rotate` і - `device.token.revoke` (потрібен scope `operator.pairing`). -- Видача/ротація токенів залишається обмеженою схваленим набором role, - зафіксованим у записі pairing цього пристрою; ротація токена не може - розширити пристрій до role, яку pairing approval ніколи не надавав. -- Для сесій токенів paired-device керування пристроєм має власне scope, якщо - викликач також не має `operator.admin`: викликачі без admin можуть - видаляти/відкликати/ротувати лише **власний** запис пристрою. -- `device.token.rotate` також перевіряє запитаний набір scope operator щодо - поточних scope сесії викликача. Викликачі без admin не можуть ротувати - токен до ширшого набору scope operator, ніж уже мають. -- Збої auth містять `error.details.code` плюс підказки для відновлення: + Зберігайте їх лише тоді, коли підключення використовувало bootstrap auth через + довірений транспорт, наприклад `wss://` або loopback/local pairing. +- Якщо клієнт надає **явний** `deviceToken` або явні `scopes`, цей + запитаний викликачем набір областей дії залишається авторитетним; кешовані + області дії повторно використовуються лише тоді, коли клієнт повторно + використовує збережений токен пристрою для конкретного пристрою. +- Токени пристроїв можна ротувати/відкликати через `device.token.rotate` і + `device.token.revoke` (потрібна область дії `operator.pairing`). +- Видача/ротація токенів залишається обмеженою затвердженим набором ролей, + записаним у записі pairing цього пристрою; ротація токена не може розширити + пристрій до ролі, яку pairing approval ніколи не надавав. +- Для сесій токенів спарених пристроїв керування пристроями є самостійно + обмеженим, якщо тільки викликач також не має `operator.admin`: викликачі без + прав admin можуть видаляти/відкликати/ротувати лише **власний** запис пристрою. +- `device.token.rotate` також перевіряє запитаний набір областей дії оператора + щодо поточних областей дії сесії викликача. Викликачі без прав admin не + можуть ротувати токен до ширшого набору областей дії оператора, ніж вони вже мають. +- Збої автентифікації містять `error.details.code` плюс підказки для + відновлення: - `error.details.canRetryWithDeviceToken` (boolean) - `error.details.recommendedNextStep` (`retry_with_device_token`, `update_auth_configuration`, `update_auth_credentials`, `wait_then_retry`, `review_auth_configuration`) - Поведінка клієнта для `AUTH_TOKEN_MISMATCH`: - - Довірені клієнти можуть виконати одну обмежену повторну спробу з кешованим токеном для пристрою. - - Якщо ця повторна спроба не вдається, клієнти повинні зупинити автоматичні цикли перепідключення та показати вказівки для дій оператора. + - Довірені клієнти можуть виконати одну обмежену повторну спробу з кешованим + токеном пристрою для конкретного пристрою. + - Якщо ця повторна спроба не вдається, клієнти повинні припинити автоматичні + цикли повторного підключення й показати оператору вказівки щодо подальших дій. ## Ідентичність пристрою + pairing -- Nodes повинні включати стабільну ідентичність пристрою (`device.id`), похідну - від відбитка keypair. -- Gateways видають токени для кожного пристрою + role. -- Для нових device ID потрібні pairing approval, якщо не ввімкнено локальне auto-approval. -- Pairing auto-approval зосереджене на прямих локальних підключеннях local loopback. -- OpenClaw також має вузький backend/container-local шлях self-connect для - довірених helper-потоків зі спільним секретом. -- Підключення tailnet або LAN з того самого хоста все одно вважаються віддаленими для pairing і - потребують approval. +- Вузли повинні включати стабільну ідентичність пристрою (`device.id`), + похідну від відбитка keypair. +- Gateway видає токени для кожного пристрою + ролі. +- Для нових `device.id` потрібні pairing approvals, якщо не ввімкнено локальне + auto-approval. +- Pairing auto-approval зосереджене на прямих локальних loopback-підключеннях. +- OpenClaw також має вузький шлях self-connect для backend/container-local + довірених потоків helper зі спільним секретом. +- Підключення tailnet або LAN на тому самому хості однаково вважаються + віддаленими для pairing і потребують approval. - Усі WS-клієнти мають включати ідентичність `device` під час `connect` (operator + node). - Control UI може опускати її лише в таких режимах: + Control UI може пропустити її лише в таких режимах: - `gateway.controlUi.allowInsecureAuth=true` для сумісності з небезпечним HTTP лише на localhost. - - успішна автентифікація operator Control UI з `gateway.auth.mode: "trusted-proxy"`. + - успішна автентифікація operator Control UI через `gateway.auth.mode: "trusted-proxy"`. - `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (аварійний режим, серйозне зниження безпеки). - Усі підключення мають підписувати наданий сервером nonce `connect.challenge`. ### Діагностика міграції автентифікації пристрою Для застарілих клієнтів, які все ще використовують поведінку підписування до challenge, `connect` тепер повертає -коди деталей `DEVICE_AUTH_*` у `error.details.code` зі стабільним `error.details.reason`. +коди деталей `DEVICE_AUTH_*` у `error.details.code` разом зі стабільним `error.details.reason`. Поширені збої міграції: -| Повідомлення | 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` | Payload підпису не відповідає payload 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`. -- Підписуйте payload v2, який містить nonce сервера. +- Завжди чекайте на `connect.challenge`. +- Підписуйте корисне навантаження v2, яке містить server nonce. - Надсилайте той самий nonce у `connect.params.device.nonce`. -- Бажаний payload підпису — `v3`, який прив’язує `platform` і `deviceFamily` +- Бажаним корисним навантаженням підпису є `v3`, яке прив’язує `platform` і `deviceFamily` на додачу до полів device/client/role/scopes/token/nonce. - Застарілі підписи `v2` і далі приймаються для сумісності, але pinning - метаданих paired-device усе одно керує політикою команд під час повторного підключення. + метаданих спарених пристроїв усе одно керує політикою команд під час повторного підключення. ## TLS + pinning -- Для WS-підключень підтримується TLS. -- Клієнти за бажанням можуть закріплювати відбиток сертифіката gateway (див. конфігурацію `gateway.tls` +- TLS підтримується для WS-підключень. +- Клієнти за бажання можуть закріпити відбиток сертифіката gateway (див. конфігурацію `gateway.tls` плюс `gateway.remote.tlsFingerprint` або CLI `--tls-fingerprint`). -## Scope +## Область застосування -Цей протокол відкриває **повний API gateway** (status, channels, models, chat, -agent, sessions, nodes, approvals тощо). Точна поверхня визначається +Цей протокол надає **повний API gateway** (status, channels, models, chat, +agent, sessions, nodes, approvals тощо). Точна поверхня визначена схемами TypeBox у `src/gateway/protocol/schema.ts`.