Web interfaces

Інтерфейс керування

Control UI — це невеликий односторінковий застосунок Vite + Lit, який обслуговує Gateway:

  • за замовчуванням: http://<host>:18789/
  • необов'язковий префікс: задайте gateway.controlUi.basePath (наприклад, /openclaw)

Він взаємодіє напряму з Gateway WebSocket на тому самому порту.

Швидке відкриття (локально)

Якщо Gateway запущено на тому самому комп'ютері, відкрийте:

Якщо сторінка не завантажується, спочатку запустіть Gateway: openclaw gateway.

Автентифікація передається під час WebSocket-рукостискання через:

  • connect.params.auth.token
  • connect.params.auth.password
  • заголовки ідентичності Tailscale Serve, коли gateway.auth.allowTailscale: true
  • заголовки ідентичності довіреного проксі, коли gateway.auth.mode: "trusted-proxy"

Панель налаштувань дашборда зберігає токен для поточної сесії вкладки браузера та вибраної URL-адреси gateway; паролі не зберігаються. Onboarding зазвичай генерує токен gateway для автентифікації зі спільним секретом під час першого підключення, але автентифікація паролем також працює, коли gateway.auth.mode має значення "password".

Сполучення пристрою (перше підключення)

Коли ви підключаєтеся до Control UI з нового браузера або пристрою, Gateway зазвичай вимагає одноразового підтвердження сполучення. Це захід безпеки для запобігання несанкціонованому доступу.

Що ви побачите: "disconnected (1008): pairing required"

  • Список запитів, що очікують

    openclaw devices list
    
  • Схвалити за ID запиту

    openclaw devices approve <requestId>
    
  • Якщо браузер повторює сполучення зі зміненими даними автентифікації (роль/області доступу/публічний ключ), попередній запит, що очікує, замінюється, і створюється новий requestId. Перед схваленням повторно виконайте openclaw devices list.

    Якщо браузер уже сполучено, і ви змінюєте його доступ із читання на запис/адміністрування, це вважається підвищенням схвалення, а не тихим повторним підключенням. OpenClaw зберігає старе схвалення активним, блокує ширше повторне підключення і просить явно схвалити новий набір областей доступу.

    Після схвалення пристрій запам'ятовується і не вимагатиме повторного схвалення, якщо ви не відкличете його за допомогою openclaw devices revoke --device <id> --role <role>. Див. CLI пристроїв щодо ротації та відкликання токенів.

    Особиста ідентичність (локальна для браузера)

    Control UI підтримує особисту ідентичність для кожного браузера (відображуване ім'я та аватар), яка додається до вихідних повідомлень для атрибуції у спільних сесіях. Вона зберігається у сховищі браузера, обмежена поточним профілем браузера і не синхронізується з іншими пристроями та не зберігається на сервері, окрім звичайних метаданих авторства стенограми для повідомлень, які ви фактично надсилаєте. Очищення даних сайту або перемикання браузерів скидає її до порожнього стану.

    Та сама локальна для браузера схема застосовується до перевизначення аватара асистента. Завантажені аватари асистента накладаються на визначену gateway ідентичність лише в локальному браузері й ніколи не проходять зворотний шлях через config.patch. Спільне поле конфігурації ui.assistant.avatar усе ще доступне для клієнтів не з UI, які записують поле напряму (наприклад, скриптові gateway або кастомні дашборди).

    Ендпойнт конфігурації середовища виконання

    Control UI отримує свої налаштування середовища виконання з /__openclaw/control-ui-config.json. Цей ендпойнт захищений тією самою автентифікацією gateway, що й решта HTTP-поверхні: неавтентифіковані браузери не можуть його отримати, а успішне отримання потребує або вже чинного токена/пароля gateway, ідентичності Tailscale Serve, або ідентичності довіреного проксі.

    Підтримка мов

    Control UI може локалізувати себе під час першого завантаження на основі локалі вашого браузера. Щоб змінити це пізніше, відкрийте Огляд -> Доступ до Gateway -> Мова. Вибір локалі розташований у картці Доступ до Gateway, а не в розділі Зовнішній вигляд.

    • Підтримувані локалі: en, zh-CN, zh-TW, pt-BR, de, es, ja-JP, ko, fr, ar, it, tr, uk, id, pl, th, vi, nl, fa
    • Переклади неанглійськими мовами ліниво завантажуються в браузері.
    • Вибрана локаль зберігається у сховищі браузера і використовується повторно під час наступних відвідувань.
    • Відсутні ключі перекладу повертаються до англійської.

    Переклади документації генеруються для того самого набору неанглійських локалей, але вбудований у сайт документації перемикач мов Mintlify обмежений кодами локалей, які приймає Mintlify. Документація тайською (th) та перською (fa) все ще генерується в репозиторії публікації; вона може не з'являтися в цьому перемикачі, доки Mintlify не підтримуватиме ці коди.

    Теми зовнішнього вигляду

    Панель Зовнішній вигляд зберігає вбудовані теми Claw, Knot і Dash, а також один локальний для браузера слот імпорту tweakcn. Щоб імпортувати тему, відкрийте редактор tweakcn, виберіть або створіть тему, натисніть Поділитися і вставте скопійоване посилання на тему в Зовнішній вигляд. Імпортер також приймає URL-адреси реєстру https://tweakcn.com/r/themes/<id>, URL-адреси редактора на кшталт https://tweakcn.com/editor/theme?theme=amethyst-haze, відносні шляхи /themes/<id>, сирі ID тем і назви тем за замовчуванням, як-от amethyst-haze.

    Імпортовані теми зберігаються лише в поточному профілі браузера. Вони не записуються до конфігурації gateway і не синхронізуються між пристроями. Заміна імпортованої теми оновлює один локальний слот; очищення перемикає активну тему назад на Claw, якщо було вибрано імпортовану тему.

    Що він може робити (сьогодні)

    Чат і розмова
    • Спілкуватися з моделлю через Gateway WS (chat.history, chat.send, chat.abort, chat.inject).
    • Оновлення історії чату запитують обмежене нещодавнє вікно з обмеженнями тексту для кожного повідомлення, щоб великі сесії не змушували браузер рендерити повне корисне навантаження стенограми до того, як чат стане придатним до використання.
    • Розмовляти через браузерні realtime-сесії. OpenAI використовує прямий WebRTC, Google Live використовує обмежений одноразовий браузерний токен через WebSocket, а backend-only realtime голосові plugins використовують транспорт ретрансляції Gateway. Сесії провайдера, якими володіє клієнт, починаються з talk.client.create; сесії ретрансляції Gateway починаються з talk.session.create. Ретрансляція зберігає облікові дані провайдера на Gateway, поки браузер транслює PCM мікрофона через talk.session.appendAudio і пересилає виклики інструментів провайдера openclaw_agent_consult через talk.client.toolCall для політики Gateway та більшої налаштованої моделі OpenClaw.
    • Транслювати виклики інструментів і живі картки виводу інструментів у Чаті (події агента).
    Канали, екземпляри, сесії, сни
    • Канали: вбудовані та bundled/зовнішні plugin-канали, статус, QR-вхід і конфігурація для кожного каналу (channels.status, web.login.*, config.patch).
    • Оновлення перевірки каналів зберігають попередній знімок видимим, доки повільні перевірки провайдера завершуються, а часткові знімки позначаються, коли перевірка або аудит перевищує свій UI-бюджет.
    • Екземпляри: список присутності + оновлення (system-presence).
    • Сесії: список + перевизначення моделі/мислення/швидкого режиму/детальності/трасування/reasoning для кожної сесії (sessions.list, sessions.patch).
    • Сни: статус Dreaming, перемикач увімкнення/вимкнення та читач Dream Diary (doctor.memory.status, doctor.memory.dreamDiary, config.patch).
    Cron, skills, nodes, схвалення exec
    • Завдання Cron: список/додавання/редагування/запуск/увімкнення/вимкнення + історія запусків (cron.*).
    • Skills: статус, увімкнення/вимкнення, встановлення, оновлення API-ключів (skills.*).
    • Nodes: список + можливості (node.list).
    • Схвалення exec: редагування списків дозволів gateway або node + політика запиту для exec host=gateway/node (exec.approvals.*).
    Конфігурація
    • Перегляд/редагування ~/.openclaw/openclaw.json (config.get, config.set).
    • Застосування + перезапуск із валідацією (config.apply) і пробудження останньої активної сесії.
    • Записи містять захист base-hash, щоб запобігти перезапису одночасних редагувань.
    • Записи (config.set/config.apply/config.patch) попередньо перевіряють розв'язання активних SecretRef для посилань у надісланому корисному навантаженні конфігурації; нерозв'язані активні надіслані посилання відхиляються до запису.
    • Рендеринг схеми та форми (config.schema / config.schema.lookup, включно з полями title / description, відповідними UI-підказками, негайними підсумками дочірніх елементів, метаданими документації на вузлах вкладених об'єктів/wildcard/масивів/композиції, а також схемами plugin + каналів, коли вони доступні); редактор Raw JSON доступний лише тоді, коли знімок має безпечний сирий round-trip.
    • Якщо знімок не може безпечно виконати round-trip сирого тексту, Control UI примусово вмикає режим Форми та вимикає режим Raw для цього знімка.
    • У редакторі Raw JSON "Скинути до збереженого" зберігається сиро-авторська форма (форматування, коментарі, макет $include) замість повторного рендерингу сплощеного знімка, тому зовнішні редагування переживають скидання, коли знімок може безпечно пройти round-trip.
    • Структуровані значення об'єктів SecretRef відображаються лише для читання в текстових полях форми, щоб запобігти випадковому пошкодженню об'єкта в рядок.
    Налагодження, журнали, оновлення
    • Налагодження: знімки статусу/стану/моделей + журнал подій + ручні RPC-виклики (status, health, models.list).
    • Журнал подій містить таймінги оновлення/RPC Control UI, таймінги повільного рендерингу чату/конфігурації та записи про чутливість браузера для довгих кадрів анімації або довгих завдань, коли браузер надає ці типи записів PerformanceObserver.
    • Журнали: live tail файлових журналів gateway із фільтром/експортом (logs.tail).
    • Оновлення: запуск package/git-оновлення + перезапуск (update.run) зі звітом про перезапуск, потім опитування update.status після повторного підключення, щоб перевірити запущену версію gateway.
    Нотатки панелі завдань Cron
    • Для ізольованих завдань доставка за замовчуванням оголошує підсумок. Ви можете перемкнути на none, якщо хочете внутрішні-only запуски.
    • Поля каналу/цілі з'являються, коли вибрано оголошення.
    • Режим Webhook використовує delivery.mode = "webhook" із delivery.to, встановленим на чинну HTTP(S) webhook URL-адресу.
    • Для завдань main-session доступні режими доставки webhook і none.
    • Розширені елементи керування редагуванням містять delete-after-run, очищення перевизначення агента, точні/з розкиданням параметри cron, перевизначення моделі/мислення агента та перемикачі доставки best-effort.
    • Валідація форми вбудована з помилками на рівні полів; недійсні значення вимикають кнопку збереження, доки їх не буде виправлено.
    • Задайте cron.webhookToken, щоб надсилати окремий bearer-токен; якщо його пропущено, webhook надсилається без заголовка автентифікації.
    • Застарілий fallback: збережені legacy-завдання з notify: true усе ще можуть використовувати cron.webhook, доки їх не мігрують.

    Поведінка чату

    Семантика надсилання та історії
    • chat.send є неблокувальним: він одразу підтверджує запит із { runId, status: "started" }, а відповідь передається потоком через події chat.
    • Завантаження в чат приймають зображення та невідеофайли. Зображення зберігають нативний шлях до зображення; інші файли зберігаються як керовані медіа й показуються в історії як посилання на вкладення.
    • Повторне надсилання з тим самим idempotencyKey повертає { status: "in_flight" } під час виконання і { status: "ok" } після завершення.
    • Відповіді chat.history обмежені за розміром для безпеки інтерфейсу. Коли записи стенограми завеликі, Gateway може обрізати довгі текстові поля, пропускати важкі блоки метаданих і замінювати надмірно великі повідомлення заповнювачем ([chat.history omitted: message too large]).
    • Згенеровані асистентом зображення зберігаються як посилання на керовані медіа й повертаються через автентифіковані медіа-URL Gateway, тому перезавантаження не залежать від того, чи сирі payload-и зображень base64 залишаються у відповіді історії чату.
    • Під час відтворення chat.history Control UI прибирає з видимого тексту асистента лише-відображальні inline-теги директив (наприклад, [[reply_to_*]] і [[audio_as_voice]]), plain-text XML payload-и викликів інструментів (зокрема <tool_call>...</tool_call>, <function_call>...</function_call>, <tool_calls>...</tool_calls>, <function_calls>...</function_calls> і обрізані блоки викликів інструментів), а також витеклі ASCII/повноширинні керівні токени моделі, і пропускає записи асистента, весь видимий текст яких є лише точним тихим токеном NO_REPLY / no_reply або токеном підтвердження Heartbeat HEARTBEAT_OK.
    • Під час активного надсилання й фінального оновлення історії подання чату залишає локальні оптимістичні повідомлення користувача/асистента видимими, якщо chat.history на мить повертає старіший знімок; канонічна стенограма замінює ці локальні повідомлення, щойно історія Gateway наздоганяє актуальний стан.
    • Live-події chat є станом доставки, тоді як chat.history перебудовується зі сталої стенограми сесії. Після фінальних подій інструментів Control UI перезавантажує історію й об'єднує лише невеликий оптимістичний хвіст; межу стенограми задокументовано в WebChat.
    • chat.inject додає нотатку асистента до стенограми сесії та транслює подію chat для оновлень лише інтерфейсу (без запуску агента й без доставки в канал).
    • Заголовок чату показує фільтр агента перед вибором сесії, а вибір сесії обмежується вибраним агентом. Перемикання агентів показує лише сесії, пов'язані з цим агентом, і повертається до головної сесії цього агента, якщо в нього ще немає збережених сесій панелі керування.
    • На desktop-ширинах елементи керування чатом залишаються в одному компактному рядку та згортаються під час прокручування стенограми вниз; прокручування вгору, повернення до верху або досягнення низу відновлює елементи керування.
    • Послідовні дублікати текстових повідомлень відображаються як одна бульбашка з бейджем кількості. Повідомлення, що містять зображення, вкладення, вивід інструментів або попередні перегляди полотна, не згортаються.
    • Вибір моделі чату та режиму мислення одразу змінює активну сесію через sessions.patch; це сталі перевизначення сесії, а не параметри надсилання лише для одного ходу.
    • Введення /new у Control UI створює й перемикає на ту саму нову сесію панелі керування, що й New Chat. Введення /reset зберігає явне скидання на місці Gateway для поточної сесії.
    • Вибір моделі чату запитує налаштоване подання моделей Gateway. Якщо присутній agents.defaults.models, цей allowlist керує вибором. Інакше вибір показує явні записи models.providers.*.models плюс провайдерів із придатною автентифікацією. Повний каталог залишається доступним через налагоджувальний RPC models.list із view: "all".
    • Коли свіжі звіти про використання сесії Gateway показують високий тиск контексту, область композитора чату показує повідомлення про контекст і, на рекомендованих рівнях Compaction, компактну кнопку, що запускає звичайний шлях Compaction для сесії. Застарілі знімки токенів приховуються, доки Gateway знову не повідомить свіже використання.
    Режим розмови (браузерний realtime)

    Режим розмови використовує зареєстрованого realtime-провайдера голосу. Налаштуйте OpenAI з talk.realtime.provider: "openai" плюс talk.realtime.providers.openai.apiKey або налаштуйте Google з talk.realtime.provider: "google" плюс talk.realtime.providers.google.apiKey. Браузер ніколи не отримує стандартний API-ключ провайдера. OpenAI отримує ефемерний клієнтський секрет Realtime для WebRTC. Google Live отримує одноразовий обмежений auth-токен Live API для браузерної WebSocket-сесії, з інструкціями та деклараціями інструментів, зафіксованими в токені Gateway. Провайдери, що надають лише backend realtime bridge, працюють через relay-транспорт Gateway, тому облікові дані й vendor-сокети залишаються на сервері, а аудіо браузера проходить через автентифіковані RPC Gateway. Підказку Realtime-сесії формує Gateway; talk.client.create не приймає наданих викликачем перевизначень інструкцій.

    У композиторі чату елемент керування Talk — це кнопка з хвилями поруч із кнопкою диктування через мікрофон. Коли Talk запускається, рядок стану композитора показує Connecting Talk..., потім Talk live, поки аудіо під'єднане, або Asking OpenClaw..., поки realtime-виклик інструмента консультується з налаштованою більшою моделлю через talk.client.toolCall.

    Maintainer live smoke: OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts перевіряє обмін SDP OpenAI browser WebRTC, налаштування Google Live constrained-token browser WebSocket і браузерний адаптер relay Gateway із фейковим мікрофонним медіа. Команда друкує лише стан провайдера й не логує секрети.

    Зупинка та скасування
    • Натисніть Stop (викликає chat.abort).
    • Поки запуск активний, звичайні подальші повідомлення стають у чергу. Натисніть Steer на повідомленні в черзі, щоб вставити це подальше повідомлення в поточний хід.
    • Введіть /stop (або окремі фрази скасування, як-от stop, stop action, stop run, stop openclaw, please stop), щоб скасувати поза основним потоком.
    • chat.abort підтримує { sessionKey } (без runId), щоб скасувати всі активні запуски для цієї сесії.
    Збереження часткових даних після скасування
    • Коли запуск скасовано, частковий текст асистента все одно може показуватися в інтерфейсі.
    • Gateway зберігає скасований частковий текст асистента в історію стенограми, коли існує буферизований вивід.
    • Збережені записи містять метадані скасування, щоб споживачі стенограми могли відрізняти часткові дані після скасування від звичайного виводу завершення.

    Встановлення PWA та web push

    Control UI постачається з manifest.webmanifest і service worker, тому сучасні браузери можуть установлювати його як окрему PWA. Web Push дає Gateway змогу будити встановлену PWA сповіщеннями, навіть коли вкладка або вікно браузера не відкриті.

    Поверхня Що вона робить
    ui/public/manifest.webmanifest Маніфест PWA. Браузери пропонують "Install app", щойно він доступний.
    ui/public/sw.js Service worker, який обробляє події push і кліки сповіщень.
    push/vapid-keys.json (у каталозі стану OpenClaw) Автоматично згенерована пара ключів VAPID, що використовується для підписування payload-ів Web Push.
    push/web-push-subscriptions.json Збережені endpoint-и браузерних підписок.

    Перевизначте пару ключів VAPID через env vars у процесі Gateway, коли потрібно зафіксувати ключі (для multi-host розгортань, ротації секретів або тестів):

    • OPENCLAW_VAPID_PUBLIC_KEY
    • OPENCLAW_VAPID_PRIVATE_KEY
    • OPENCLAW_VAPID_SUBJECT (типово mailto:openclaw@localhost)

    Control UI використовує ці методи Gateway з обмеженням scope, щоб реєструвати й тестувати браузерні підписки:

    • push.web.vapidPublicKey — отримує активний публічний ключ VAPID.
    • push.web.subscribe — реєструє endpoint плюс keys.p256dh/keys.auth.
    • push.web.unsubscribe — видаляє зареєстрований endpoint.
    • push.web.test — надсилає тестове сповіщення до підписки викликача.

    Hosted embeds

    Повідомлення асистента можуть відтворювати розміщений вебвміст inline за допомогою shortcode [embed ...]. Політикою sandbox для iframe керує gateway.controlUi.embedSandbox:

    strict

    Вимикає виконання скриптів усередині розміщених embed-ів.

    scripts (типово)

    Дозволяє інтерактивні embed-и, зберігаючи ізоляцію origin; це типовий режим, і його зазвичай достатньо для самодостатніх браузерних ігор/віджетів.

    trusted

    Додає allow-same-origin поверх allow-scripts для same-site документів, яким навмисно потрібні сильніші привілеї.

    Приклад:

    {
      gateway: {
        controlUi: {
          embedSandbox: "scripts",
        },
      },
    }
    

    Абсолютні зовнішні http(s) URL для embed залишаються заблокованими типово. Якщо ви навмисно хочете, щоб [embed url="https://..."] завантажував сторонні сторінки, установіть gateway.controlUi.allowExternalEmbedUrls: true.

    Ширина повідомлень чату

    Згруповані повідомлення чату використовують читабельну типову максимальну ширину. Розгортання на широких моніторах можуть перевизначити її без patching bundled CSS, задавши gateway.controlUi.chatMessageMaxWidth:

    {
      gateway: {
        controlUi: {
          chatMessageMaxWidth: "min(1280px, 82%)",
        },
      },
    }
    

    Значення перевіряється перед тим, як потрапить до браузера. Підтримувані значення включають прості довжини й відсотки, як-от 960px або 82%, а також обмежені вирази ширини min(...), max(...), clamp(...), calc(...) і fit-content(...).

    Доступ до tailnet (рекомендовано)

    Інтегрований Tailscale Serve (бажано)

    Тримайте Gateway на loopback і дозвольте Tailscale Serve проксувати його через HTTPS:

    openclaw gateway --tailscale serve
    

    Відкрийте:

    • https://<magicdns>/ (або ваш налаштований gateway.controlUi.basePath)

    Типово запити Control UI/WebSocket Serve можуть автентифікуватися через заголовки ідентичності Tailscale (tailscale-user-login), коли gateway.auth.allowTailscale має значення true. OpenClaw перевіряє ідентичність, розв'язуючи адресу x-forwarded-for за допомогою tailscale whois і зіставляючи її із заголовком, і приймає їх лише тоді, коли запит потрапляє на loopback із заголовками x-forwarded-* від Tailscale. Для операторських сесій Control UI з ідентичністю браузерного пристрою цей перевірений шлях Serve також пропускає round trip pairing пристрою; браузери без пристрою та підключення з роллю node все одно проходять звичайні перевірки пристрою. Установіть gateway.auth.allowTailscale: false, якщо хочете вимагати явні облікові дані shared-secret навіть для трафіку Serve. Потім використовуйте gateway.auth.mode: "token" або "password".

    Для цього асинхронного шляху ідентичності Serve невдалі спроби автентифікації для тієї самої IP-адреси клієнта й auth scope серіалізуються перед записами rate-limit. Тому одночасні погані повторні спроби з того самого браузера можуть показати retry later на другому запиті замість двох простих невідповідностей, що виконуються паралельно.

    Прив'язка до tailnet + token

    openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
    

    Потім відкрийте:

    • http://<tailscale-ip>:18789/ (або ваш налаштований gateway.controlUi.basePath)

    Вставте відповідний спільний секрет у налаштування UI (надсилається як connect.params.auth.token або connect.params.auth.password).

    Незахищений HTTP

    Якщо відкрити панель керування через звичайний HTTP (http://<lan-ip> або http://<tailscale-ip>), браузер працює в незахищеному контексті й блокує WebCrypto. За замовчуванням OpenClaw блокує підключення Control UI без ідентичності пристрою.

    Задокументовані винятки:

    • сумісність небезпечного HTTP лише для localhost із gateway.controlUi.allowInsecureAuth=true
    • успішна автентифікація оператора Control UI через gateway.auth.mode: "trusted-proxy"
    • аварійний режим gateway.controlUi.dangerouslyDisableDeviceAuth=true

    Рекомендоване виправлення: використовуйте HTTPS (Tailscale Serve) або відкрийте UI локально:

    • https://<magicdns>/ (Serve)
    • http://127.0.0.1:18789/ (на хості Gateway)
    Поведінка перемикача небезпечної автентифікації
    {
      gateway: {
        controlUi: { allowInsecureAuth: true },
        bind: "tailnet",
        auth: { mode: "token", token: "replace-me" },
      },
    }
    

    allowInsecureAuth — це лише локальний перемикач сумісності:

    • Він дозволяє сеансам localhost Control UI продовжувати роботу без ідентичності пристрою в незахищених HTTP-контекстах.
    • Він не обходить перевірки спарювання.
    • Він не послаблює вимоги до ідентичності віддаленого (не localhost) пристрою.
    Лише аварійний режим
    {
      gateway: {
        controlUi: { dangerouslyDisableDeviceAuth: true },
        bind: "tailnet",
        auth: { mode: "token", token: "replace-me" },
      },
    }
    
    Примітка щодо trusted-proxy
    • Успішна автентифікація trusted-proxy може допускати операторські сеанси Control UI без ідентичності пристрою.
    • Це не поширюється на сеанси Control UI з роллю Node.
    • Зворотні проксі loopback на тому самому хості все одно не задовольняють автентифікацію trusted-proxy; див. Автентифікація довіреного проксі.

    Див. Tailscale, щоб отримати вказівки з налаштування HTTPS.

    Політика безпеки вмісту

    Control UI постачається зі строгою політикою img-src: дозволені лише ресурси того самого origin, URL data: і локально згенеровані URL blob:. Віддалені URL зображень http(s) і URL відносно протоколу відхиляються браузером і не спричиняють мережевих запитів.

    Що це означає на практиці:

    • Аватари й зображення, які обслуговуються за відносними шляхами (наприклад, /avatars/<id>), усе ще відображаються, зокрема автентифіковані маршрути аватарів, які UI отримує і перетворює на локальні URL blob:.
    • Вбудовані URL data:image/... усе ще відображаються (корисно для корисних навантажень усередині протоколу).
    • Локальні URL blob:, створені Control UI, усе ще відображаються.
    • URL віддалених аватарів, згенеровані метаданими каналу, вилучаються допоміжними засобами аватарів Control UI і замінюються вбудованим логотипом/бейджем, тому скомпрометований або зловмисний канал не може змусити браузер оператора виконувати довільні віддалені запити зображень.

    Вам не потрібно нічого змінювати, щоб отримати таку поведінку — вона завжди ввімкнена і не налаштовується.

    Автентифікація маршруту аватарів

    Коли автентифікацію Gateway налаштовано, кінцева точка аватарів Control UI вимагає той самий токен Gateway, що й решта API:

    • GET /avatar/<agentId> повертає зображення аватара лише автентифікованим викликам. GET /avatar/<agentId>?meta=1 повертає метадані аватара за тим самим правилом.
    • Неавтентифіковані запити до будь-якого з цих маршрутів відхиляються (відповідно до спорідненого маршруту assistant-media). Це запобігає витоку ідентичності агента через маршрут аватара на хостах, які інакше захищені.
    • Сам Control UI пересилає токен Gateway як bearer-заголовок під час отримання аватарів і використовує автентифіковані URL blob, щоб зображення все одно відображалося на панелях керування.

    Якщо вимкнути автентифікацію Gateway (не рекомендовано на спільних хостах), маршрут аватара також стає неавтентифікованим, відповідно до решти Gateway.

    Автентифікація маршруту медіа асистента

    Коли автентифікацію Gateway налаштовано, локальні медіапрев’ю асистента використовують двоетапний маршрут:

    • GET /__openclaw__/assistant-media?meta=1&source=<path> вимагає звичайної операторської автентифікації Control UI. Браузер надсилає токен Gateway як bearer-заголовок під час перевірки доступності.
    • Успішні відповіді з метаданими містять короткочасний mediaTicket, обмежений цим точним шляхом джерела.
    • URL зображень, аудіо, відео й документів, які відображає браузер, використовують mediaTicket=<ticket> замість активного токена або пароля Gateway. Квиток швидко спливає і не може авторизувати інше джерело.

    Це зберігає сумісність звичайного відтворення медіа з нативними медіаелементами браузера, не розміщуючи багаторазові облікові дані Gateway у видимих медіа-URL.

    Збирання UI

    Gateway обслуговує статичні файли з dist/control-ui. Зберіть їх за допомогою:

    pnpm ui:build
    

    Необов’язкова абсолютна база (коли потрібні фіксовані URL ресурсів):

    OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build
    

    Для локальної розробки (окремий сервер розробки):

    pnpm ui:dev
    

    Потім спрямуйте UI на ваш WS URL Gateway (наприклад, ws://127.0.0.1:18789).

    Налагодження/тестування: сервер розробки + віддалений Gateway

    Control UI — це статичні файли; ціль WebSocket налаштовується і може відрізнятися від HTTP origin. Це зручно, коли ви хочете використовувати Vite dev server локально, а Gateway працює в іншому місці.

  • Запустіть сервер розробки UI

    pnpm ui:dev
    
  • Відкрийте з gatewayUrl

    http://localhost:5173/?gatewayUrl=ws%3A%2F%2F<gateway-host>%3A18789
    

    Необов’язкова одноразова автентифікація (за потреби):

    http://localhost:5173/?gatewayUrl=wss%3A%2F%2F<gateway-host>%3A18789#token=<gateway-token>
    
  • Примітки
    • gatewayUrl зберігається в localStorage після завантаження і видаляється з URL.
    • Якщо ви передаєте повну кінцеву точку ws:// або wss:// через gatewayUrl, URL-кодуйте значення gatewayUrl, щоб браузер правильно розібрав рядок запиту.
    • token за можливості слід передавати через фрагмент URL (#token=...). Фрагменти не надсилаються на сервер, що запобігає витоку в журналах запитів і Referer. Застарілі параметри запиту ?token= усе ще імпортуються один раз для сумісності, але лише як резервний варіант, і негайно видаляються після bootstrap.
    • password зберігається лише в пам’яті.
    • Коли gatewayUrl задано, UI не повертається до облікових даних із конфігурації або середовища. Надайте token (або password) явно. Відсутність явних облікових даних є помилкою.
    • Використовуйте wss://, коли Gateway знаходиться за TLS (Tailscale Serve, HTTPS-проксі тощо).
    • gatewayUrl приймається лише у вікні верхнього рівня (не у вбудованому), щоб запобігти clickjacking.
    • Розгортання Control UI не через loopback повинні явно задавати gateway.controlUi.allowedOrigins (повні origins). Це стосується і віддалених середовищ розробки.
    • Під час запуску Gateway може додавати локальні origins, як-от http://localhost:<port> і http://127.0.0.1:<port>, на основі фактичних runtime bind і порту, але віддалені browser origins все одно потребують явних записів.
    • Не використовуйте gateway.controlUi.allowedOrigins: ["*"], окрім жорстко контрольованого локального тестування. Це означає дозволити будь-який browser origin, а не «зіставити з будь-яким хостом, який я використовую».
    • gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true вмикає режим резервного використання Host-header origin, але це небезпечний режим безпеки.

    Приклад:

    {
      gateway: {
        controlUi: {
          allowedOrigins: ["http://localhost:5173"],
        },
      },
    }
    

    Подробиці налаштування віддаленого доступу: Віддалений доступ.

    Пов’язане