Plugin maintainer reference
Внутрішня архітектура Plugin
Для публічної моделі можливостей, форм Plugin і контрактів володіння/виконання див. архітектуру Plugin. На цій сторінці описано внутрішні механізми: конвеєр завантаження, реєстр, перехоплювачі середовища виконання, HTTP-маршрути Gateway, шляхи імпорту й таблиці схем.
Конвеєр завантаження
Під час запуску OpenClaw виконує приблизно такі дії:
- виявляє корені кандидатів Plugin
- читає маніфести нативних або сумісних пакетів і метадані пакетів
- відхиляє небезпечних кандидатів
- нормалізує конфігурацію Plugin (
plugins.enabled,allow,deny,entries,slots,load.paths) - визначає, чи слід увімкнути кожного кандидата
- завантажує ввімкнені нативні модулі: зібрані вбудовані модулі використовують нативний завантажувач; локальний вихідний код TypeScript сторонніх розробників використовує аварійний резервний механізм Jiti
- викликає нативні перехоплювачі
register(api)і збирає реєстрації в реєстр Plugin - надає реєстр командам і поверхням середовища виконання
Перевірки безпеки виконуються до виконання в середовищі виконання. Виявлення блокує кандидата, якщо:
- його визначена точка входу виходить за межі кореня Plugin
- його шлях (або кореневий каталог) доступний для запису всім користувачам
- для невбудованих Plugin власник шляху не відповідає поточному uid (або root)
Для вбудованих каталогів, доступних для запису всім користувачам, спочатку виконується спроба виправлення chmod на місці
(інсталяції npm/глобальні інсталяції можуть постачати каталоги пакетів із правами 0777), після чого перевірка
виконується повторно; для вбудованого походження перевірки власника повністю пропускаються.
Заблоковані кандидати все одно містять свій ідентифікатор Plugin у сформованій діагностиці, якщо він відомий (зокрема ідентифікатори, визначені з маніфесту всередині каталогу, який інакше було б відхилено), тому конфігурація, що посилається на цей ідентифікатор, бачить заблокований Plugin, пов’язаний із попередженням про безпеку шляху, а не непов’язану помилку «невідомий Plugin».
Поведінка з пріоритетом маніфесту
Маніфест є джерелом істини площини керування. OpenClaw використовує його, щоб:
- ідентифікувати Plugin
- виявляти оголошені канали/Skills/схему конфігурації або можливості пакета
- перевіряти
plugins.entries.<id>.config - доповнювати підписи/заповнювачі Control UI
- показувати метадані інсталяції/каталогу
- зберігати легковагові дескриптори активації та налаштування без завантаження середовища виконання Plugin
Для нативних Plugin модуль середовища виконання є частиною площини даних. Він реєструє фактичну поведінку, як-от перехоплювачі, інструменти, команди або потоки постачальника.
Необов’язкові блоки маніфесту activation і setup залишаються в площині керування.
Це дескриптори лише з метаданими для планування активації та виявлення налаштування;
вони не замінюють реєстрацію середовища виконання, register(...) або setupEntry.
Активні споживачі активації використовують підказки маніфесту щодо команд, каналів і постачальників, щоб
звузити завантаження Plugin до ширшої матеріалізації реєстру:
- завантаження CLI звужується до Plugin, яким належить запитана основна команда
- налаштування каналу/визначення Plugin звужується до Plugin, яким належить запитаний ідентифікатор каналу
- явне налаштування постачальника/визначення середовища виконання звужується до Plugin, яким належить запитаний ідентифікатор постачальника
- планування запуску Gateway використовує
activation.onStartupдля явних імпортів під час запуску; Plugin без метаданих запуску завантажуються лише через вужчі тригери активації
Планувальник активації надає як API лише з ідентифікаторами для наявних викликачів, так і
API плану для діагностики. Записи плану повідомляють, чому було вибрано Plugin,
відокремлюючи явні підказки activation.* від резервного визначення за належністю маніфесту:
Причина (з підказок activation.*) |
Причина (з належності маніфесту) |
|---|---|
activation-agent-harness-hint |
— |
activation-capability-hint |
— |
activation-channel-hint |
manifest-channel-owner (channels) |
activation-command-hint |
manifest-command-alias (commandAliases) |
activation-provider-hint |
manifest-provider-owner (providers), manifest-setup-provider-owner (setup.providers) |
activation-route-hint |
— |
| — (тригер перехоплювача не має варіанта підказки) | manifest-hook-owner (hooks), manifest-tool-contract (contracts.tools) |
Цей поділ причин є межею сумісності: наявні метадані Plugin продовжують працювати, а новий код може виявляти широкі підказки або резервну поведінку без зміни семантики завантаження середовища виконання.
Попередні завантаження середовища виконання під час запиту, які запитують широку область all, усе одно формують
явний ефективний набір ідентифікаторів Plugin із конфігурації, планування запуску, налаштованих
каналів, слотів і правил автоматичного ввімкнення
(resolveEffectivePluginIds у src/plugins/effective-plugin-ids.ts). Якщо цей
сформований набір порожній, OpenClaw залишає область порожньою, а не розширює її до
кожного доступного для виявлення Plugin.
Виявлення налаштування віддає перевагу ідентифікаторам, що належать дескрипторам, як-от setup.providers і
setup.cliBackends, щоб звузити кандидатів Plugin перед переходом до резервного
setup-api для Plugin, яким усе ще потрібні перехоплювачі середовища виконання під час налаштування. Списки налаштування
постачальників використовують providerAuthChoices із маніфесту, варіанти налаштування,
отримані з дескрипторів, і метадані каталогу інсталяцій без завантаження середовища виконання постачальника. Явне
setup.requiresRuntime: false є межею, що дозволяє використовувати лише дескриптори; якщо
requiresRuntime пропущено, для сумісності зберігається застарілий резервний механізм setup-api. Якщо
кілька виявлених Plugin заявляють той самий нормалізований ідентифікатор постачальника налаштування або
бекенду CLI, пошук налаштування відхиляє неоднозначного власника, а не покладається на
порядок виявлення. Коли середовище виконання налаштування все ж виконується, діагностика реєстру повідомляє
про розбіжності між setup.providers / setup.cliBackends і постачальниками або бекендами CLI,
фактично зареєстрованими через setup-api, не блокуючи застарілі Plugin.
Межа кешу Plugin
OpenClaw не кешує результати виявлення Plugin або безпосередні дані реєстру маніфестів за часовими вікнами. Інсталяції, зміни маніфестів і зміни шляхів завантаження мають ставати видимими під час наступного явного читання метаданих або перебудови знімка. Парсер файлів маніфестів підтримує обмежений кеш сигнатур файлів із ключем за шляхом відкритого маніфесту разом із пристроєм/inode, розміром і mtime/ctime; цей кеш лише запобігає повторному аналізу незмінених байтів і не повинен кешувати відповіді щодо виявлення, реєстру, власника або політик.
Безпечний швидкий шлях метаданих — це явне володіння об’єктами, а не прихований кеш.
Гарячі шляхи запуску Gateway мають передавати поточний PluginMetadataSnapshot,
похідний PluginLookUpTable або явний реєстр маніфестів через ланцюжок
викликів. Перевірка конфігурації, автоматичне ввімкнення під час запуску, початкова ініціалізація Plugin і вибір
постачальника можуть повторно використовувати ці об’єкти, доки вони представляють поточну конфігурацію та
інвентар Plugin. Пошук налаштування все одно відновлює метадані маніфесту на вимогу,
якщо конкретний шлях налаштування не отримує явний реєстр маніфестів; залишайте
це резервним варіантом для холодного шляху, а не додавайте приховані кеші пошуку. Коли
вхідні дані змінюються, перебудовуйте й замінюйте знімок замість його зміни або
зберігання історичних копій. Представлення активного реєстру Plugin і допоміжні засоби
початкової ініціалізації вбудованих каналів слід обчислювати повторно з поточного
реєстру/кореня. Короткоживучі мапи допустимі в межах одного виклику для усунення дублювання роботи або
запобігання повторному входу; вони не повинні ставати кешами метаданих процесу.
Для завантаження Plugin постійним рівнем кешування є завантаження середовища виконання. Він може повторно використовувати стан завантажувача, коли код або встановлені артефакти фактично завантажуються, наприклад:
PluginLoaderCacheStateі сумісні активні реєстри середовища виконання- кеші jiti/модулів і кеші завантажувачів публічних поверхонь, що використовуються для уникнення повторного імпорту тієї самої поверхні середовища виконання
- кеші файлової системи для встановлених артефактів Plugin
- короткоживучі мапи на один виклик для нормалізації шляхів або усунення дублікатів
Ці кеші є деталями реалізації площини даних. Вони не повинні відповідати на запитання площини керування, як-от «якому Plugin належить цей постачальник?», якщо викликач навмисно не запросив завантаження середовища виконання.
Не додавайте постійні або часові кеші для:
- результатів виявлення
- безпосередніх реєстрів маніфестів
- реєстрів маніфестів, відновлених з індексу встановлених Plugin
- пошуку власника постачальника, приховування моделей, політик постачальника або метаданих публічних артефактів
- будь-якої іншої відповіді, отриманої з маніфесту, для якої змінений маніфест, індекс установлених компонентів або шлях завантаження має бути видимим під час наступного читання метаданих
Викликачі, які перебудовують метадані маніфесту зі збереженого індексу встановлених Plugin, відновлюють цей реєстр на вимогу. Встановлений індекс є довговічним станом площини джерел; це не прихований внутрішньопроцесний кеш метаданих.
Модель реєстру
Завантажені Plugin не змінюють безпосередньо випадкові глобальні змінні ядра. Вони реєструються в
центральному реєстрі Plugin (PluginRegistry у src/plugins/registry-types.ts),
який відстежує записи Plugin (ідентичність, джерело, походження, стан, діагностику),
а також масиви для кожної можливості: інструменти, застарілі й типізовані перехоплювачі,
канали, постачальники, обробники RPC Gateway, HTTP-маршрути, реєстратори CLI,
фонові служби, команди, що належать Plugin, і десятки інших типізованих сімейств постачальників
(мовлення, вбудовування, генерування зображень/відео/музики, отримання/пошук
у вебі, агентські оболонки, дії сеансів тощо).
Потім основні функції читають дані з цього реєстру замість безпосередньої взаємодії з модулями Plugin. Це зберігає односпрямованість завантаження:
- модуль Plugin -> реєстрація в реєстрі
- середовище виконання ядра -> використання реєстру
Це розділення важливе для супроводжуваності. Завдяки йому більшості поверхонь ядра потрібна лише одна точка інтеграції: «читати реєстр», а не «додавати окрему обробку для кожного модуля Plugin».
Зворотні виклики прив’язування розмови
Plugin, які прив’язують розмову, можуть реагувати на вирішення запиту на схвалення.
Використовуйте api.onConversationBindingResolved(...), щоб отримати зворотний виклик після схвалення
або відхилення запиту на прив’язування:
export default { id: "my-plugin", register(api) { api.onConversationBindingResolved(async (event) => { if (event.status === "approved") { // A binding now exists for this plugin + conversation. console.log(event.binding?.conversationId); return; } // The request was denied; clear any local pending state. console.log(event.request.conversation.conversationId); }); },};Поля корисного навантаження зворотного виклику:
status:"approved"або"denied"decision:"allow-once","allow-always"або"deny"binding: визначена прив’язка для схвалених запитівrequest: початковий підсумок запиту, підказка щодо від’єднання, ідентифікатор відправника та метадані розмови
Цей зворотний виклик призначений лише для сповіщення. Він не змінює, кому дозволено прив’язувати розмову, і виконується після завершення обробки схвалення ядром.
Перехоплювачі середовища виконання постачальника
Plugin постачальників мають три рівні:
- Метадані маніфесту для швидкого пошуку до запуску середовища виконання:
setup.providers[].envVars, застарілий сумісний параметрproviderAuthEnvVars,providerAuthAliases,providerAuthChoicesіchannelEnvVars. - Перехоплювачі етапу конфігурації:
catalog(застарілийdiscovery) іapplyConfigDefaults. - Перехоплювачі середовища виконання: понад 40 необов’язкових перехоплювачів, що охоплюють автентифікацію, визначення моделей, обгортання потоків, рівні міркування, політику повторного відтворення й кінцеві точки використання. Див. Порядок перехоплювачів і використання.
OpenClaw і надалі відповідає за загальний цикл агента, перемикання після відмови, обробку транскриптів і політику інструментів. Ці перехоплювачі є поверхнею розширення для поведінки, специфічної для постачальника, без потреби в повністю власному транспорті логічного виведення.
Використовуйте setup.providers[].envVars у маніфесті, коли постачальник має облікові дані на основі змінних середовища, які мають бути доступні загальним шляхам автентифікації, перевірки стану та вибору моделі без завантаження середовища виконання плагіна. Застаріле поле providerAuthEnvVars усе ще зчитується адаптером сумісності протягом періоду вилучення, а сторонні плагіни, які його використовують, отримують діагностичне повідомлення маніфесту. Використовуйте providerAuthAliases у маніфесті, коли один ідентифікатор постачальника має повторно використовувати змінні середовища, профілі автентифікації, автентифікацію на основі конфігурації та варіант підключення за допомогою ключа API іншого ідентифікатора постачальника. Використовуйте providerAuthChoices у маніфесті, коли інтерфейсам CLI для підключення та вибору автентифікації потрібно знати ідентифікатор варіанта постачальника, мітки груп і просте налаштування автентифікації одним прапорцем без завантаження середовища виконання постачальника. Залишайте envVars середовища виконання постачальника для підказок операторам, як-от мітки підключення або змінні налаштування ідентифікатора та секрету клієнта OAuth.
Використовуйте channelEnvVars у маніфесті, коли канал має автентифікацію або налаштування на основі змінних середовища, які мають бути доступні загальному резервному механізму змінних середовища оболонки, перевіркам конфігурації та стану або запитам налаштування без завантаження середовища виконання каналу.
Порядок і використання обробників
Для плагінів моделей і постачальників OpenClaw викликає обробники приблизно в такому порядку.
Стовпець «Коли використовувати» є коротким посібником із вибору.
Поля постачальника, призначені лише для сумісності, які OpenClaw більше не викликає, як-от ProviderPlugin.capabilities і suppressBuiltInModel, навмисно тут не наведено.
| Хук | Що він робить | Коли використовувати |
|---|---|---|
catalog |
Публікує конфігурацію провайдера в models.providers під час генерування models.json |
Провайдер володіє каталогом або типовими значеннями базової URL-адреси |
applyConfigDefaults |
Застосовує глобальні типові значення конфігурації, що належать провайдеру, під час матеріалізації конфігурації | Типові значення залежать від режиму автентифікації, середовища або семантики сімейства моделей провайдера |
| (вбудований пошук моделі) | OpenClaw спочатку намагається використати звичайний шлях реєстру/каталогу | (не хук плагіна) |
normalizeModelId |
Нормалізує застарілі псевдоніми або псевдоніми попередніх версій ідентифікаторів моделей перед пошуком | Провайдер відповідає за очищення псевдонімів перед канонічним визначенням моделі |
normalizeTransport |
Нормалізує api / baseUrl сімейства провайдера перед загальним збиранням моделі |
Провайдер відповідає за очищення транспорту для власних ідентифікаторів провайдера в межах того самого сімейства транспортів |
normalizeConfig |
Нормалізує models.providers.<id> перед визначенням середовища виконання/провайдера |
Провайдер потребує очищення конфігурації, яке має належати плагіну; вбудовані допоміжні засоби сімейства Google також підстраховують підтримувані записи конфігурації Google |
applyNativeStreamingUsageCompat |
Застосовує до провайдерів конфігурації перетворення сумісності для нативного потокового обліку використання | Провайдер потребує виправлень метаданих нативного потокового обліку використання залежно від кінцевої точки |
resolveConfigApiKey |
Визначає автентифікацію через маркер середовища для провайдерів конфігурації перед завантаженням автентифікації середовища виконання | Провайдери надають власні хуки визначення ключа API через маркер середовища |
resolveSyntheticAuth |
Надає локальну/самостійно розміщену або засновану на конфігурації автентифікацію без збереження відкритого тексту | Провайдер може працювати із синтетичним/локальним маркером облікових даних |
resolveExternalAuthProfiles |
Накладає зовнішні профілі автентифікації, що належать провайдеру; типове значення persistence — runtime-only для облікових даних, якими керує CLI/застосунок |
Провайдер повторно використовує зовнішні облікові дані автентифікації без збереження скопійованих токенів оновлення; оголосіть contracts.externalAuthProviders у маніфесті |
shouldDeferSyntheticProfileAuth |
Знижує пріоритет збережених синтетичних заповнювачів профілів порівняно з автентифікацією на основі середовища/конфігурації | Провайдер зберігає синтетичні профілі-заповнювачі, які не повинні мати вищий пріоритет |
resolveDynamicModel |
Синхронний резервний механізм для ідентифікаторів моделей провайдера, яких ще немає в локальному реєстрі | Провайдер приймає довільні ідентифікатори моделей від вищого рівня |
prepareDynamicModel |
Виконує асинхронну підготовку, після чого resolveDynamicModel запускається знову |
Провайдеру потрібні мережеві метадані перед визначенням невідомих ідентифікаторів |
normalizeResolvedModel |
Остаточне перетворення перед використанням визначеної моделі вбудованим засобом запуску | Провайдер потребує перетворення транспорту, але все одно використовує основний транспорт |
normalizeToolSchemas |
Нормалізує схеми інструментів до того, як їх отримає вбудований засіб запуску | Провайдер потребує очищення схем сімейства транспортів |
inspectToolSchemas |
Надає діагностику схем, що належить провайдеру, після нормалізації | Провайдер хоче отримувати попередження щодо ключових слів без додавання до ядра правил, специфічних для провайдера |
resolveReasoningOutputMode |
Вибирає нативний або позначений тегами контракт виведення міркувань | Провайдер потребує позначених тегами міркувань/остаточного виведення замість нативних полів |
prepareExtraParams |
Нормалізує параметри запиту перед загальними обгортками параметрів потоку | Провайдер потребує типових параметрів запиту або очищення параметрів для окремого провайдера |
createStreamFn |
Повністю замінює звичайний шлях потоку власним транспортом | Провайдер потребує власного мережевого протоколу, а не лише обгортки |
wrapStreamFn |
Обгортка потоку після застосування загальних обгорток | Провайдер потребує обгорток сумісності заголовків/тіла запиту/моделі без власного транспорту |
resolveTransportTurnState |
Додає нативні заголовки або метадані транспорту для кожного ходу | Провайдер хоче, щоб загальні транспорти надсилали нативну для провайдера ідентичність ходу |
resolveWebSocketSessionPolicy |
Додає нативні заголовки WebSocket або політику періоду очікування сеансу | Провайдер хоче налаштовувати заголовки сеансу або резервну політику для загальних транспортів WS |
formatApiKey |
Форматувальник профілю автентифікації: збережений профіль перетворюється на рядок apiKey середовища виконання |
Провайдер зберігає додаткові метадані автентифікації та потребує власної форми токена середовища виконання |
refreshOAuth |
Перевизначає оновлення OAuth для власних кінцевих точок оновлення або політики обробки помилок оновлення | Провайдер не відповідає спільним механізмам оновлення OpenClaw |
buildAuthDoctorHint |
Підказка щодо виправлення, яка додається в разі невдалого оновлення OAuth | Провайдер потребує власних рекомендацій щодо виправлення автентифікації після помилки оновлення |
matchesContextOverflowError |
Власний засіб провайдера для зіставлення помилок переповнення контекстного вікна | Провайдер має необроблені помилки переповнення, які не виявляються загальними евристиками |
classifyFailoverReason |
Власна класифікація причин перемикання після відмови, що належить провайдеру | Провайдер може зіставляти необроблені помилки API/транспорту з обмеженням частоти/перевантаженням тощо |
isCacheTtlEligible |
Політика кешування запитів для проксі-провайдерів/провайдерів транспортної мережі | Провайдер потребує специфічного для проксі контролю TTL кешу |
buildMissingAuthMessage |
Заміна загального повідомлення про відновлення в разі відсутності автентифікації | Провайдер потребує специфічної підказки щодо відновлення в разі відсутності автентифікації |
augmentModelCatalog |
Синтетичні/остаточні рядки каталогу, що додаються після виявлення (застаріло, див. нижче) | Провайдер потребує синтетичних рядків випереджальної сумісності в models list та засобах вибору |
resolveThinkingProfile |
Специфічний для моделі набір рівнів /think, підписів для відображення та типового значення |
Провайдер надає власну градацію міркувань або двійковий підпис для вибраних моделей |
isBinaryThinking |
Хук сумісності для ввімкнення/вимкнення міркувань | Провайдер надає лише двійкове ввімкнення/вимкнення міркувань |
supportsXHighThinking |
Хук сумісності з підтримкою рівня міркувань xhigh |
Провайдер хоче надавати xhigh лише для підмножини моделей |
resolveDefaultThinkingLevel |
Хук сумісності типового рівня /think |
Провайдер визначає типову політику /think для сімейства моделей |
isModernModelRef |
Засіб зіставлення сучасних моделей для фільтрів активних профілів і вибору для перевірки працездатності | Провайдер визначає зіставлення бажаних моделей для активного використання/перевірки працездатності |
prepareRuntimeAuth |
Обмінює налаштовані облікові дані на фактичний токен/ключ середовища виконання безпосередньо перед виведенням | Провайдер потребує обміну токенів або короткочасних облікових даних запиту |
resolveUsageAuth |
Визначає облікові дані використання/виставлення рахунків для /usage і пов’язаних поверхонь стану |
Провайдер потребує власного розбору токенів використання/квоти або окремих облікових даних використання |
fetchUsageSnapshot |
Отримує та нормалізує специфічні для провайдера знімки використання/квоти після визначення автентифікації | Провайдер потребує специфічної кінцевої точки використання або аналізатора корисного навантаження |
createEmbeddingProvider |
Створити адаптер вбудовувань для пам’яті/пошуку, яким керує провайдер | Поведінка вбудовувань пам’яті належить Plugin провайдера |
buildReplayPolicy |
Повернути політику повторного відтворення, що керує обробкою історії взаємодії для провайдера | Провайдеру потрібна власна політика історії взаємодії (наприклад, вилучення блоків міркувань) |
sanitizeReplayHistory |
Переписати історію повторного відтворення після загального очищення історії взаємодії | Провайдеру потрібні специфічні для нього перетворення повторного відтворення на додачу до спільних допоміжних засобів Compaction |
validateReplayTurns |
Виконати остаточну перевірку або зміну форми ходів повторного відтворення перед вбудованим засобом виконання | Транспорту провайдера потрібна суворіша перевірка ходів після загального очищення |
onModelSelected |
Виконати побічні ефекти після вибору, якими керує провайдер | Провайдеру потрібна телеметрія або керований ним стан, коли модель стає активною |
normalizeModelId, normalizeTransport і normalizeConfig спочатку перевіряють
відповідний Plugin постачальника, а потім переходять до інших Plugin постачальників,
що підтримують хуки, доки один із них справді не змінить ідентифікатор моделі або
транспорт/конфігурацію. Це дає змогу сумісним адаптерам і псевдонімам постачальників
працювати без потреби для викликового коду знати, якому вбудованому Plugin належить
перетворення. Якщо жоден хук постачальника не перетворює підтримуваний запис
конфігурації сімейства Google, вбудований нормалізатор конфігурації Google усе одно
виконує це очищення для сумісності.
Якщо постачальнику потрібен повністю власний мережевий протокол або власний виконавець запитів, це інший клас розширення. Ці хуки призначені для поведінки постачальника, яка й надалі працює у звичайному циклі інференсу OpenClaw.
resolveUsageAuth визначає, чи має OpenClaw викликати fetchUsageSnapshot, чи
повернутися до загального визначення облікових даних для інтерфейсів використання/стану.
Повертайте { token, accountId?, subscriptionType?, rateLimitTier? }, коли
постачальник має облікові дані для отримання даних про використання (необов’язкові
метадані тарифного плану передаються до fetchUsageSnapshot), повертайте
{ handled: true }, коли автентифікація використання, якою керує постачальник,
обробила запит і має запобігти загальному резервному переходу до ключа API/OAuth,
і повертайте null або undefined, коли постачальник не обробив автентифікацію
використання.
Оголошуйте облікові дані організації або платіжного обліку в
providerUsageAuthEnvVars маніфесту. Це дає змогу загальним механізмам виявлення
та очищення секретів розпізнавати їх, не перетворюючи на кандидатів для автентифікації
інференсу.
Приклад постачальника
api.registerProvider({ id: "example-proxy", label: "Example Proxy", auth: [], catalog: { order: "simple", run: async (ctx) => { const apiKey = ctx.resolveProviderApiKey("example-proxy").apiKey; if (!apiKey) { return null; } return { provider: { baseUrl: "https://proxy.example.com/v1", apiKey, api: "openai-completions", models: [{ id: "auto", name: "Auto" }], }, }; }, }, resolveDynamicModel: (ctx) => ({ id: ctx.modelId, name: ctx.modelId, provider: "example-proxy", api: "openai-completions", baseUrl: "https://proxy.example.com/v1", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128000, maxTokens: 8192, }), prepareRuntimeAuth: async (ctx) => { const exchanged = await exchangeToken(ctx.apiKey); return { apiKey: exchanged.token, baseUrl: exchanged.baseUrl, expiresAt: exchanged.expiresAt, }; }, resolveUsageAuth: async (ctx) => { const auth = await ctx.resolveOAuthToken(); return auth ? { token: auth.token } : null; }, fetchUsageSnapshot: async (ctx) => { return await fetchExampleProxyUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn); },});Вбудовані приклади
Вбудовані Plugin постачальників поєднують наведені вище хуки відповідно до потреб
кожного постачальника щодо каталогу, автентифікації, міркування, повторного відтворення
та використання. Авторитетний набір хуків міститься в кожному Plugin у
extensions/; ця сторінка ілюструє їхню структуру, а не дублює перелік.
Постачальники каталогів із наскрізним передаванням
OpenRouter, Kilocode, Z.AI, xAI реєструють catalog разом із
resolveDynamicModel / prepareDynamicModel, щоб показувати ідентифікатори
моделей вищого рівня раніше за статичний каталог OpenClaw.
Постачальники кінцевих точок OAuth і використання
GitHub Copilot, Gemini CLI, ChatGPT Codex, MiniMax, Xiaomi, z.ai поєднують
prepareRuntimeAuth або formatApiKey із resolveUsageAuth +
fetchUsageSnapshot, щоб керувати обміном токенів та інтеграцією /usage.
Сімейства очищення повторного відтворення та транскриптів
Спільні іменовані сімейства (google-gemini, passthrough-gemini,
anthropic-by-model, hybrid-anthropic-openai) дають змогу постачальникам
підключатися до політики транскриптів через buildReplayPolicy, замість того
щоб кожен Plugin повторно реалізовував очищення.
Постачальники лише каталогів
byteplus, cloudflare-ai-gateway, huggingface, kimi-coding, nvidia,
qianfan, synthetic, together, venice, vercel-ai-gateway і
volcengine реєструють лише catalog та використовують спільний цикл інференсу.
Спеціалізовані допоміжні засоби потоків Anthropic
Бета-заголовки, /fast / serviceTier і context1m містяться у публічній
межі api.ts / contract-api.ts Plugin Anthropic
(wrapAnthropicProviderStream, resolveAnthropicBetas,
resolveAnthropicFastMode, resolveAnthropicServiceTier), а не в
загальному SDK.
Допоміжні засоби середовища виконання
Plugin можуть отримувати доступ до вибраних допоміжних засобів ядра через
api.runtime. Для TTS:
const clip = await api.runtime.tts.textToSpeech({ text: "Hello from OpenClaw", cfg: api.config,}); const result = await api.runtime.tts.textToSpeechTelephony({ text: "Hello from OpenClaw", cfg: api.config,}); const voices = await api.runtime.tts.listVoices({ provider: "elevenlabs", cfg: api.config,});Примітки:
textToSpeechповертає звичайне корисне навантаження результату TTS ядра для інтерфейсів файлів/голосових нотаток.- Використовує конфігурацію
messages.ttsядра та вибір постачальника. - Повертає аудіобуфер PCM і частоту дискретизації. Plugin мають передискретизувати/закодувати дані для постачальників.
listVoicesє необов’язковим для кожного постачальника. Використовуйте його для засобів вибору голосу або процесів налаштування, якими керує постачальник.- Ядро передає визначений кінцевий термін запиту до хуків
listVoicesпостачальника; параметри часу очікування конкретного постачальника можуть його перевизначити. - Списки голосів можуть містити докладніші метадані, як-от локаль, стать і теги характеру, для засобів вибору з урахуванням постачальника.
- OpenAI та ElevenLabs наразі підтримують телефонію. Microsoft — ні.
Plugin також можуть реєструвати постачальників мовлення через api.registerSpeechProvider(...).
api.registerSpeechProvider({ id: "acme-speech", label: "Acme Speech", isConfigured: ({ config }) => Boolean(config.messages?.tts), synthesize: async (req) => { return { audioBuffer: Buffer.from([]), outputFormat: "mp3", fileExtension: ".mp3", voiceCompatible: false, }; },});Примітки:
- Зберігайте політику TTS, резервний перехід і доставку відповіді в ядрі.
- Використовуйте постачальників мовлення для керованої постачальником поведінки синтезу.
- Застаріле вхідне значення Microsoft
edgeнормалізується до ідентифікатора постачальникаmicrosoft. - Бажана модель володіння орієнтована на компанію: один Plugin постачальника може керувати постачальниками тексту, мовлення, зображень і майбутніх медіа, коли OpenClaw додаватиме відповідні контракти можливостей.
Для розпізнавання зображень, аудіо та відео Plugin реєструють одного типізованого постачальника розпізнавання медіа замість загального набору ключів і значень:
api.registerMediaUnderstandingProvider({ id: "google", capabilities: ["image", "audio", "video"], describeImage: async (req) => ({ text: "..." }), transcribeAudio: async (req) => ({ text: "..." }), describeVideo: async (req) => ({ text: "..." }),});Примітки:
- Зберігайте оркестрацію, резервний перехід, конфігурацію та підключення каналів у ядрі.
- Зберігайте поведінку постачальника в його Plugin.
- Адитивне розширення має залишатися типізованим: нові необов’язкові методи, нові необов’язкові поля результату, нові необов’язкові можливості.
- Генерування відео вже відповідає такому самому шаблону:
- ядро володіє контрактом можливості та допоміжним засобом середовища виконання
- Plugin постачальників реєструють
api.registerVideoGenerationProvider(...) - Plugin функцій/каналів використовують
api.runtime.videoGeneration.*
Для допоміжних засобів розпізнавання медіа в середовищі виконання Plugin можуть викликати:
const image = await api.runtime.mediaUnderstanding.describeImageFile({ filePath: "/tmp/inbound-photo.jpg", cfg: api.config, agentDir: "/tmp/agent",}); const video = await api.runtime.mediaUnderstanding.describeVideoFile({ filePath: "/tmp/inbound-video.mp4", cfg: api.config,}); const extraction = await api.runtime.mediaUnderstanding.extractStructuredWithModel({ provider: "codex", model: "gpt-5.6-sol", input: [ { type: "image", buffer: receiptImageBuffer, fileName: "receipt.png", mime: "image/png", }, { type: "text", text: "Use the printed fields as the source of truth." }, ], instructions: "Return entities and searchable tags.", schemaName: "example.evidence", jsonSchema: { type: "object", properties: { entities: { type: "array", items: { type: "string" } }, tags: { type: "array", items: { type: "string" } }, }, }, cfg: api.config,});Для транскрибування аудіо Plugin можуть використовувати середовище виконання розпізнавання медіа або старіший псевдонім STT:
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ filePath: "/tmp/inbound-audio.ogg", cfg: api.config, // Optional when MIME cannot be inferred reliably: mime: "audio/ogg",});Примітки:
api.runtime.mediaUnderstanding.*є бажаним спільним інтерфейсом для розпізнавання зображень, аудіо та відео.extractStructuredWithModel(...)є доступною для Plugin межею обмеженого видобування даних із пріоритетом зображень, яким керує постачальник. Додайте принаймні одне вхідне зображення; текстові вхідні дані є додатковим контекстом. Plugin продукту володіють своїми маршрутами та схемами, а OpenClaw — межею постачальника/середовища виконання.- Використовує аудіоконфігурацію розпізнавання медіа ядра (
tools.media.audio) і порядок резервного переходу між постачальниками. - Повертає
{ text: undefined }, коли результат транскрибування відсутній (наприклад, для пропущених/непідтримуваних вхідних даних). api.runtime.stt.transcribeAudioFile(...)залишається псевдонімом для сумісності.
Plugin також можуть запускати фонові виконання підагентів через api.runtime.subagent:
const result = await api.runtime.subagent.run({ sessionKey: "agent:main:subagent:search-helper", message: "Expand this query into focused follow-up searches.", provider: "openai", model: "gpt-4.1-mini", deliver: false,});Примітки:
providerіmodelє необов’язковими перевизначеннями для окремого виконання, а не постійними змінами сеансу.- OpenClaw враховує ці поля перевизначення лише для довірених викликових сторін.
- Для резервних виконань, якими керує Plugin, оператори мають явно дозволити їх за допомогою
plugins.entries.<id>.subagent.allowModelOverride: true. - Використовуйте
plugins.entries.<id>.subagent.allowedModels, щоб обмежити довірені Plugin конкретними канонічними цілямиprovider/model, або"*", щоб явно дозволити будь-яку ціль. - Виконання підагентів від недовірених Plugin і надалі працюють, але запити на перевизначення відхиляються замість непомітного резервного переходу.
- Створені Plugin сеанси підагентів позначаються ідентифікатором Plugin, що їх створив. Резервний
api.runtime.subagent.deleteSession(...)може видаляти лише ці власні сеанси; видалення довільних сеансів і надалі потребує запиту Gateway з областю адміністратора.
Для вебпошуку Plugin можуть використовувати спільний допоміжний засіб середовища виконання замість прямого доступу до підключення інструментів агента:
const providers = api.runtime.webSearch.listProviders({ config: api.config,}); const result = await api.runtime.webSearch.search({ config: api.config, args: { query: "OpenClaw plugin runtime helpers", count: 5, },});Plugin також можуть реєструвати постачальників вебпошуку через
api.registerWebSearchProvider(...).
Примітки:
- Зберігайте вибір постачальника, визначення облікових даних і спільну семантику запитів у ядрі.
- Використовуйте постачальників вебпошуку для специфічних для постачальника транспортів пошуку.
api.runtime.webSearch.*є бажаним спільним інтерфейсом для Plugin функцій/каналів, яким потрібна поведінка пошуку без залежності від оболонки інструменту агента.
api.runtime.imageGeneration
const result = await api.runtime.imageGeneration.generate({ config: api.config, args: { prompt: "A friendly lobster mascot", size: "1024x1024" },}); const providers = api.runtime.imageGeneration.listProviders({ config: api.config,});generate(...): генерує зображення за допомогою налаштованого ланцюжка постачальників генерування зображень.listProviders(...): перелічує доступних постачальників генерування зображень та їхні можливості.
HTTP-маршрути Gateway
Plugin можуть надавати кінцеві точки HTTP за допомогою api.registerHttpRoute(...).
api.registerHttpRoute({ path: "/acme/webhook", auth: "plugin", match: "exact", handler: async (_req, res) => { res.statusCode = 200; res.end("ok"); return true; },});Поля маршруту:
path: шлях маршруту на HTTP-сервері Gateway.auth: обов’язкове поле,"gateway"або"plugin". Використовуйте"gateway", щоб вимагати звичайну автентифікацію Gateway, або"plugin"для автентифікації чи перевірки вебхуків, якими керує плагін.match: необов’язкове поле."exact"(типове значення) або"prefix".handleUpgrade: необов’язковий обробник запитів оновлення WebSocket на тому самому маршруті.replaceExisting: необов’язкове поле. Дає змогу тому самому плагіну замінити власну наявну реєстрацію маршруту.handler: повернітьtrue, коли маршрут обробив запит.
Примітки:
api.registerHttpHandler(...)видалено, і його використання спричинить помилку завантаження плагіна. Натомість використовуйтеapi.registerHttpRoute(...).- Маршрути плагінів мають явно оголошувати
auth. - Конфлікти однакових
path + matchвідхиляються, якщо не вказаноreplaceExisting: true, а один плагін не може замінити маршрут іншого плагіна. - Маршрути, що перекриваються та мають різні рівні
auth, відхиляються. Ланцюжки переходуexact/prefixмають використовувати лише один рівень автентифікації. - Маршрути з
auth: "plugin"не отримують автоматично області дії середовища виконання оператора. Вони призначені для вебхуків і перевірки підписів, якими керує плагін, а не для привілейованих викликів допоміжних функцій Gateway. - Маршрути з
auth: "gateway"виконуються в області середовища виконання запиту Gateway. Типова поверхня (gatewayRuntimeScopeSurface: "write-default") навмисно обмежена:- автентифікація за допомогою спільного секрету в токені носія (
gateway.auth.mode = "token"/"password") і будь-який метод автентифікації, відмінний від довіреного проксі, отримують одну область діїoperator.write, навіть якщо викликач надсилаєx-openclaw-scopes - викликачі
trusted-proxyбез явно заданого заголовкаx-openclaw-scopesтакож зберігають застарілу поверхню лише зoperator.write - викликачі
trusted-proxy, які надсилаютьx-openclaw-scopes, натомість отримують оголошені області дії - маршрут може вибрати
gatewayRuntimeScopeSurface: "trusted-operator", щоб завжди враховуватиx-openclaw-scopesдля режимів автентифікації з ідентичністю (а за відсутності заголовка використовувати повний типовий набір областей дії CLI)
- автентифікація за допомогою спільного секрету в токені носія (
- Практичне правило: не вважайте маршрут плагіна з автентифікацією Gateway неявною адміністративною поверхнею. Якщо маршруту потрібна поведінка лише для адміністраторів, виберіть поверхню областей дії
trusted-operator, вимагайте режим автентифікації з ідентичністю та задокументуйте явний контракт заголовкаx-openclaw-scopes. - Після зіставлення маршруту й автентифікації звичайні обробники беруть участь у допуску кореневої роботи Gateway. Підготовлений Gateway або Gateway, що перезапускається, повертає
503до виклику обробника. Вузьким винятком є дозволений маніфестом маршрут зauth: "gateway", який також вибирає специфічну для маршруту поверхнюtrusted-operator; він залишається доступним, щоб диспетчеризація керування призупиненням не могла залишитися заблокованою, тоді як звичайні споріднені маршрути того самого плагіна залишаються за межею допуску. Володіння WebSockethandleUpgradeвикористовує ту саму атомарну межу допуску; щойно обробник приймає сокет, подальшим життєвим циклом сокета керує плагін, і ця межа його не відстежує.
Шляхи імпорту SDK плагінів
Під час створення нових плагінів використовуйте вузькі підшляхи SDK замість
монолітного кореневого модуля реекспорту openclaw/plugin-sdk. Основні підшляхи:
| Підшлях | Призначення |
|---|---|
openclaw/plugin-sdk/plugin-entry |
Примітиви реєстрації плагінів |
openclaw/plugin-sdk/channel-core |
Допоміжні засоби входу та побудови каналів |
openclaw/plugin-sdk/core |
Загальні спільні допоміжні засоби та всеохопний контракт |
openclaw/plugin-sdk/config-schema |
Коренева схема Zod для openclaw.json (OpenClawSchema) |
Плагіни каналів вибирають із сімейства вузьких інтерфейсів — channel-setup,
setup-runtime, setup-tools, channel-pairing,
channel-contract, channel-feedback, channel-inbound, channel-outbound,
command-auth, secret-input, webhook-ingress,
channel-targets і channel-actions. Поведінку схвалення слід зосередити
в одному контракті approvalCapability, а не розподіляти між не пов’язаними
полями плагіна. Див. Плагіни каналів.
Допоміжні засоби середовища виконання й конфігурації розміщено у відповідних
спеціалізованих підшляхах *-runtime (approval-runtime, agent-runtime,
lazy-runtime, directory-runtime, text-runtime, runtime-store,
system-event-runtime, heartbeat-runtime, channel-activity-runtime тощо).
Віддавайте перевагу config-contracts, plugin-config-runtime,
runtime-config-snapshot і config-mutation замість широкого сумісного
модуля реекспорту config-runtime.
Внутрішні точки входу репозиторію (відносно кореня пакета кожного вбудованого плагіна):
index.js— точка входу вбудованого плагінаapi.js— модуль реекспорту допоміжних засобів і типівruntime-api.js— модуль реекспорту лише для середовища виконанняsetup-entry.js— точка входу плагіна налаштування
Зовнішні плагіни мають імпортувати лише підшляхи openclaw/plugin-sdk/*. Ніколи
не імпортуйте src/* пакета іншого плагіна з ядра або іншого плагіна.
Точки входу, завантажені через фасад, віддають перевагу активному знімку
конфігурації середовища виконання, якщо він існує, а потім переходять до
визначеного файла конфігурації на диску.
Підшляхи для окремих можливостей, як-от image-generation, media-understanding
і speech, існують, оскільки вбудовані плагіни використовують їх зараз. Вони
не стають автоматично довгостроковими незмінними зовнішніми контрактами —
перевіряйте відповідну довідкову сторінку SDK, якщо покладаєтеся на них.
Схеми інструмента повідомлень
Плагіни мають володіти специфічними для каналів внесками
describeMessageTool(...) до схеми для примітивів, що не є повідомленнями,
як-от реакції, прочитання й опитування. Спільне подання надсилання має
використовувати загальний контракт MessagePresentation замість нативних
для постачальника полів кнопок, компонентів, блоків або карток.
Контракт, правила резервного відтворення, зіставлення постачальників і
контрольний список автора плагіна див. у розділі
Подання повідомлень.
Плагіни з можливістю надсилання оголошують, що вони можуть відтворювати, за допомогою можливостей повідомлень:
presentationдля семантичних блоків подання (text,context,divider,chart,table,buttons,select)delivery-pinдля запитів закріпленої доставки
Ядро вирішує, чи відтворювати подання нативно, чи спрощувати його до тексту. Не надавайте через загальний інструмент повідомлень обхідні механізми для нативного інтерфейсу постачальника. Застарілі допоміжні засоби SDK для успадкованих нативних схем і далі експортуються для наявних сторонніх плагінів, але нові плагіни не повинні їх використовувати.
Визначення цілі каналу
Плагіни каналів мають володіти специфічною для каналів семантикою цілей. Зберігайте спільний хост вихідних повідомлень загальним і використовуйте поверхню адаптера обміну повідомленнями для правил постачальника:
messaging.inferTargetChatType({ to })визначає, чи слід вважати нормалізовану цільdirect,groupабоchannelдо пошуку в каталозі.messaging.targetResolver.looksLikeId(raw, normalized)повідомляє ядру, чи слід для введеного значення одразу перейти до визначення за подобою ідентифікатора замість пошуку в каталозі.messaging.targetResolver.reservedLiteralsмістить прості слова, які є посиланнями на канал або сеанс для цього постачальника. Під час визначення спочатку зберігаються налаштовані записи каталогу, а вже потім відхиляються зарезервовані літерали; якщо в каталозі немає збігу, операція безпечно завершується помилкою.messaging.targetResolver.resolveTarget(...)є резервним механізмом плагіна, коли ядру потрібне остаточне визначення, яким керує постачальник, після нормалізації або відсутності збігу в каталозі.messaging.resolveOutboundSessionRoute(...)відповідає за побудову специфічного для постачальника маршруту сеансу після визначення цілі.
Рекомендований розподіл:
- Використовуйте
inferTargetChatTypeдля рішень щодо категорії, які мають відбуватися до пошуку співрозмовників або груп. - Використовуйте
looksLikeIdдля перевірок «вважати це явним або нативним ідентифікатором цілі». - Використовуйте
resolveTargetдля специфічного для постачальника резервного механізму нормалізації, а не для широкого пошуку в каталозі. - Зберігайте нативні ідентифікатори постачальника, як-от ідентифікатори чатів,
потоків, JID, псевдоніми й ідентифікатори кімнат, усередині значень
targetабо специфічних для постачальника параметрів, а не в загальних полях SDK.
Каталоги на основі конфігурації
Плагіни, які формують записи каталогу з конфігурації, мають зберігати цю логіку
в плагіні та повторно використовувати спільні допоміжні засоби з
openclaw/plugin-sdk/directory-runtime.
Використовуйте це, коли каналу потрібні визначені конфігурацією співрозмовники або групи, як-от:
- співрозмовники приватних повідомлень, визначені списком дозволених
- налаштовані зіставлення каналів або груп
- статичні резервні каталоги в межах облікового запису
Спільні допоміжні засоби в directory-runtime виконують лише загальні операції:
- фільтрування запитів
- застосування обмежень
- допоміжні засоби усунення дублікатів і нормалізації
- побудову
ChannelDirectoryEntry[]
Специфічна для каналу перевірка облікових записів і нормалізація ідентифікаторів мають залишатися в реалізації плагіна.
Каталоги постачальників
Плагіни постачальників можуть визначати каталоги моделей для інференсу за
допомогою registerProvider({ catalog: { run(...) { ... } } }).
catalog.run(...) повертає ту саму структуру, яку OpenClaw записує в
models.providers:
{ provider }для одного запису постачальника{ providers }для кількох записів постачальників
Використовуйте catalog, коли плагін володіє специфічними для постачальника
ідентифікаторами моделей, типовими базовими URL-адресами або метаданими моделей,
доступ до яких залежить від автентифікації.
catalog.order визначає, коли каталог плагіна об’єднується відносно вбудованих
неявних постачальників OpenClaw:
simple: звичайні постачальники на основі ключа API або змінних середовищаprofile: постачальники, які з’являються за наявності профілів автентифікаціїpaired: постачальники, які синтезують кілька пов’язаних записів постачальниківlate: останній прохід після інших неявних постачальників
Пізніші постачальники мають перевагу в разі конфлікту ключів, тому плагіни можуть навмисно перевизначати вбудований запис постачальника з тим самим ідентифікатором постачальника.
Плагіни також можуть публікувати доступні лише для читання рядки моделей через
api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog }). Це перспективний шлях для поверхонь списків, довідки й вибору, який
підтримує рядки text, voice, image_generation, video_generation і
music_generation. Плагіни постачальників і далі відповідають за виклики
активних кінцевих точок, обмін токенами та зіставлення відповідей постачальника;
ядро відповідає за спільну структуру рядків, позначки джерел і форматування
довідки інструментів мультимедіа. Реєстрації постачальників генерації
мультимедіа автоматично синтезують статичні рядки каталогу з defaultModel,
models і capabilities.
Сумісність:
discoveryі далі працює як застарілий псевдонім, але виводить попередження про застарілість- якщо зареєстровано і
catalog, іdiscovery, OpenClaw використовуєcatalogта виводить попередження augmentModelCatalogзастарів; вбудовані постачальники мають публікувати додаткові рядки черезregisterModelCatalogProvider
Перевірка каналу лише для читання
Якщо ваш плагін реєструє канал, бажано реалізувати
plugin.config.inspectAccount(cfg, accountId) разом із resolveAccount(...).
Чому:
resolveAccount(...)є шляхом середовища виконання. Він може припускати, що облікові дані повністю матеріалізовано, і швидко завершуватися помилкою, якщо потрібні секрети відсутні.- Шляхи команд лише для читання, як-от
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolve, а також потоки виправлення doctor або конфігурації не повинні матеріалізувати облікові дані середовища виконання лише для опису конфігурації.
Рекомендована поведінка inspectAccount(...):
- Повертайте лише описовий стан облікового запису.
- Зберігайте
enabledіconfigured. - За потреби включайте поля джерела/стану облікових даних, наприклад:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Щоб повідомити про доступність лише для читання, не потрібно повертати необроблені значення токенів. Для команд перевірки стану достатньо повернути
tokenStatus: "available"(і відповідне поле джерела). - Використовуйте
configured_unavailable, коли облікові дані налаштовано через SecretRef, але вони недоступні в поточному шляху виконання команди.
Завдяки цьому команди лише для читання можуть повідомляти «налаштовано, але недоступно в цьому шляху виконання команди» замість аварійного завершення або помилкового визначення облікового запису як неналаштованого.
Пакети розширень
Каталог Plugin може містити package.json із openclaw.extensions:
{ "name": "my-pack", "openclaw": { "extensions": ["./src/safety.ts", "./src/tools.ts"], "setupEntry": "./src/setup-entry.ts" }}Кожен запис стає Plugin. Якщо пакет містить кілька розширень, ідентифікатор Plugin набуває вигляду <manifestOrPackageName>/<fileBase> (за наявності перевагу має ідентифікатор маніфесту; інакше використовується ім’я package.json без області видимості).
Якщо ваш Plugin імпортує залежності npm, установіть їх у цьому каталозі, щоб був доступний node_modules (npm install / pnpm install).
Захисне обмеження: після розв’язання символічних посилань кожен запис openclaw.extensions має залишатися в межах каталогу Plugin. Записи, що виходять за межі каталогу пакета, відхиляються.
Примітка щодо безпеки: openclaw plugins install установлює залежності Plugin за допомогою локальної для проєкту команди npm install --omit=dev --ignore-scripts (без сценаріїв життєвого циклу та без залежностей для розробки під час виконання), ігноруючи успадковані глобальні налаштування встановлення npm. Підтримуйте дерева залежностей Plugin у вигляді «чистого JS/TS» й уникайте пакетів, що потребують складання через postinstall.
Необов’язково: openclaw.setupEntry може вказувати на легкий модуль, призначений лише для налаштування. Коли OpenClaw потрібні поверхні налаштування для вимкненого Plugin каналу або коли Plugin каналу ввімкнено, але ще не налаштовано, він завантажує setupEntry замість повної точки входу Plugin. Це полегшує запуск і налаштування, якщо основна точка входу Plugin також підключає інструменти, перехоплювачі або інший код, потрібний лише під час виконання.
Необов’язково: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen дає змогу Plugin каналу використовувати той самий шлях setupEntry на етапі запуску Gateway до початку прослуховування, навіть якщо канал уже налаштовано.
Використовуйте це лише тоді, коли setupEntry повністю охоплює поверхню запуску, яка має існувати до того, як Gateway почне прослуховування. На практиці це означає, що точка входу налаштування має реєструвати кожну належну каналу можливість, від якої залежить запуск, зокрема:
- саму реєстрацію каналу
- усі HTTP-маршрути, які мають бути доступні до того, як Gateway почне прослуховування
- усі методи Gateway, інструменти або служби, які мають існувати впродовж цього самого проміжку часу
Якщо повна точка входу все ще володіє будь-якою необхідною можливістю запуску, не вмикайте цей прапорець. Залиште для Plugin типову поведінку й дозвольте OpenClaw завантажити повну точку входу під час запуску.
Вбудовані канали також можуть публікувати допоміжні засоби поверхні контракту, призначені лише для налаштування, до яких ядро може звертатися до завантаження повного середовища виконання каналу. Поточна поверхня перенесення налаштувань:
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
Ядро використовує цю поверхню, коли потрібно перенести застарілу конфігурацію каналу з одним обліковим записом до channels.<id>.accounts.* без завантаження повної точки входу Plugin. Matrix є поточним вбудованим прикладом: коли іменовані облікові записи вже існують, він переносить до іменованого цільового облікового запису лише ключі автентифікації/початкового налаштування, а також може зберегти налаштований неканонічний ключ типового облікового запису замість того, щоб завжди створювати accounts.default.
Ці адаптери виправлень налаштування зберігають відкладене виявлення вбудованої поверхні контракту. Час імпорту залишається коротким; поверхня перенесення завантажується лише під час першого використання замість повторного запуску вбудованого каналу під час імпорту модуля.
Коли ці поверхні запуску включають методи RPC Gateway, використовуйте для них префікс, специфічний для Plugin. Простори імен адміністрування ядра (config.*, exec.approvals.*, wizard.*, update.*) залишаються зарезервованими та завжди відповідають operator.admin, навіть якщо Plugin запитує вужчу область дозволів.
Приклад:
{ "name": "@scope/my-channel", "openclaw": { "extensions": ["./index.ts"], "setupEntry": "./setup-entry.ts", "startup": { "deferConfiguredChannelFullLoadUntilAfterListen": true } }}Метадані каталогу каналів
Plugin каналів можуть оголошувати метадані налаштування/виявлення через openclaw.channel, а підказки зі встановлення — через openclaw.install. Завдяки цьому каталог ядра не містить даних.
Приклад:
{ "name": "@openclaw/nextcloud-talk", "openclaw": { "extensions": ["./index.ts"], "channel": { "id": "nextcloud-talk", "label": "Nextcloud Talk", "selectionLabel": "Nextcloud Talk (self-hosted)", "docsPath": "/channels/nextcloud-talk", "docsLabel": "nextcloud-talk", "blurb": "Self-hosted chat via Nextcloud Talk webhook bots.", "order": 65, "aliases": ["nc-talk", "nc"] }, "install": { "npmSpec": "@openclaw/nextcloud-talk", "localPath": "<bundled-plugin-local-path>", "defaultChoice": "npm" } }}Корисні поля openclaw.channel, окрім мінімального прикладу:
detailLabel: додаткова мітка для докладніших поверхонь каталогу/стануdocsLabel: перевизначення тексту посилання на документаціюpreferOver: ідентифікатори Plugin/каналів із нижчим пріоритетом, які цей запис каталогу має випереджатиselectionDocsPrefix,selectionDocsOmitLabel,selectionExtras: елементи керування текстом поверхні виборуmarkdownCapable: позначає канал як сумісний із Markdown для ухвалення рішень щодо форматування вихідних повідомленьexposure.configured: якщо встановленоfalse, приховує канал із поверхонь переліку налаштованих каналівexposure.setup: якщо встановленоfalse, приховує канал з інтерактивних засобів вибору налаштування/конфігураціїexposure.docs: позначає канал як внутрішній/приватний для поверхонь навігації документацієюshowConfigured/showInSetup: застарілі псевдоніми, які досі приймаються для сумісності; віддавайте перевагуexposurequickstartAllowFrom: долучає канал до стандартного процесу швидкого запускуallowFromforceAccountBinding: вимагає явного прив’язування облікового запису, навіть якщо існує лише один обліковий записpreferSessionLookupForAnnounceTarget: надає перевагу пошуку сеансу під час визначення цілей оголошень
OpenClaw також може об’єднувати зовнішні каталоги каналів (наприклад, експорт реєстру MPM). Розмістіть файл JSON в одному з таких місць:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
Або вкажіть в OPENCLAW_PLUGIN_CATALOG_PATHS (чи OPENCLAW_MPM_CATALOG_PATHS) один або кілька файлів JSON (розділених комами, крапками з комою або роздільником PATH). Кожен файл має містити { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }. Синтаксичний аналізатор також приймає "packages" або "plugins" як застарілі псевдоніми ключа "entries".
Згенеровані записи каталогу каналів і записи каталогу встановлення постачальників надають нормалізовані відомості про джерело встановлення поряд із необробленим блоком openclaw.install. Нормалізовані відомості визначають, чи є специфікація npm точною версією або плаваючим селектором, чи наявні очікувані метадані цілісності та чи доступний також локальний шлях до джерела. Коли ідентичність каталогу/пакета відома, нормалізовані відомості попереджають, якщо проаналізоване ім’я пакета npm відрізняється від цієї ідентичності. Вони також попереджають, коли defaultChoice недійсний або вказує на недоступне джерело, а також коли метадані цілісності npm наявні без дійсного джерела npm. Споживачі мають розглядати installSource як додаткове необов’язкове поле, щоб створені вручну записи та адаптери каталогу не мусили його синтезувати.
Завдяки цьому початкове налаштування та діагностика можуть пояснювати стан площини джерел без імпорту середовища виконання Plugin.
Для офіційних зовнішніх записів npm слід віддавати перевагу точному npmSpec разом із expectedIntegrity. Самі імена пакетів і теги розповсюдження досі працюють для сумісності, але вони спричиняють попередження площини джерел, щоб каталог міг перейти до закріплених установлень із перевіркою цілісності без порушення роботи наявних Plugin.
Коли під час початкового налаштування встановлення виконується з локального шляху каталогу, створюється керований запис індексу Plugin із source: "path" і, коли можливо, відносним щодо робочого простору sourcePath. Абсолютний робочий шлях завантаження залишається в plugins.load.paths; запис установлення не дублює шляхи локальної робочої станції в довготривалій конфігурації. Завдяки цьому локальні встановлення для розробки залишаються видимими для діагностики площини джерел без додавання другої поверхні розкриття необроблених шляхів файлової системи. Збережена таблиця SQLite installed_plugin_index є джерелом істини щодо джерел установлення й може оновлюватися без завантаження модулів середовища виконання Plugin. Її мапа installRecords зберігається навіть тоді, коли маніфест Plugin відсутній або недійсний; її вміст plugins є відновлюваним представленням маніфесту.
Plugin рушія контексту
Plugin рушія контексту керують оркестрацією контексту сеансу для приймання, складання та Compaction. Зареєструйте їх зі свого Plugin за допомогою api.registerContextEngine(id, factory), а потім виберіть активний рушій через plugins.slots.contextEngine.
Використовуйте це, коли ваш Plugin має замінити або розширити типовий конвеєр контексту, а не лише додати пошук у пам’яті чи перехоплювачі.
export default function (api) { api.registerContextEngine("lossless-claw", (ctx) => ({ info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true }, async ingest() { return { ingested: true }; }, async assemble({ messages, sessionKey, availableTools, citationsMode }) { return { messages, estimatedTokens: 0, systemPromptAddition: buildMemorySystemPromptAddition({ availableTools: availableTools ?? new Set(), citationsMode, agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }), agentSessionKey: sessionKey, }), }; }, async compact() { return { ok: true, compacted: false }; }, }));}Фабрика ctx надає необов’язкові значення config, agentDir і workspaceDir для ініціалізації під час створення.
assemble() може повертати contextProjection, коли активне середовище має постійний серверний потік. Не вказуйте його для застарілої проєкції на кожен хід. Повертайте { mode: "thread_bootstrap", epoch }, коли зібраний контекст потрібно один раз упровадити в серверний потік і повторно використовувати, доки не зміниться епоха. Змінюйте епоху після зміни семантичного контексту рушія, наприклад після проходу Compaction, яким керує рушій. Хости можуть зберігати метадані викликів інструментів, форму вхідних даних і відредаговані результати інструментів у проєкції початкового завантаження потоку, щоб нові серверні потоки зберігали безперервність роботи інструментів без копіювання необроблених даних, що містять секрети.
Якщо ваш рушій не володіє алгоритмом Compaction, залиште compact() реалізованим і явно делегуйте його:
buildMemorySystemPromptAddition, delegateCompactionToRuntime,} from "openclaw/plugin-sdk/core"; export default function (api) { api.registerContextEngine("my-memory-engine", (ctx) => ({ info: { id: "my-memory-engine", name: "My Memory Engine", ownsCompaction: false, }, async ingest() { return { ingested: true }; }, async assemble({ messages, sessionKey, availableTools, citationsMode }) { return { messages, estimatedTokens: 0, systemPromptAddition: buildMemorySystemPromptAddition({ availableTools: availableTools ?? new Set(), citationsMode, agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }), agentSessionKey: sessionKey, }), }; }, async compact(params) { return await delegateCompactionToRuntime(params); }, }));}Додавання нової можливості
Коли Plugin потребує поведінки, яка не вписується в поточний API, не обходьте систему Plugin за допомогою приватного прямого доступу. Додайте відсутню можливість.
Рекомендована послідовність:
- Визначте контракт ядра. Вирішіть, за яку спільну поведінку має відповідати ядро: політику, резервний варіант, об’єднання конфігурації, життєвий цикл, семантику для каналів і форму допоміжних засобів середовища виконання.
- Додайте типізовані поверхні реєстрації Plugin і середовища виконання. Розширте
OpenClawPluginApiта/абоapi.runtimeнайменшою корисною типізованою поверхнею можливості. - Під’єднайте ядро та споживачів каналів/функцій. Канали й Plugin функцій мають використовувати нову можливість через ядро, а не імпортувати реалізацію постачальника безпосередньо.
- Зареєструйте реалізації постачальників. Потім Plugin постачальників реєструють свої серверні реалізації для цієї можливості.
- Додайте покриття контракту. Додайте тести, щоб структура володіння та реєстрації залишалася явною з часом.
Саме так OpenClaw зберігає чітку позицію, не стаючи жорстко прив’язаним до світогляду одного постачальника. Конкретний контрольний список файлів і опрацьований приклад наведено в Збірнику рецептів можливостей.
Контрольний список можливості
Коли ви додаєте нову можливість, реалізація зазвичай має одночасно охоплювати такі поверхні:
- типи контракту ядра в
src/<capability>/types.ts - засіб виконання ядра або допоміжний засіб середовища виконання в
src/<capability>/runtime.ts - поверхню реєстрації API Plugin у
src/plugins/types.ts - під’єднання реєстру Plugin у
src/plugins/registry.ts - надання середовища виконання Plugin у
src/plugins/runtime/*, коли Plugin функцій або каналів мають його використовувати - допоміжні засоби захоплення/тестування в
src/test-utils/plugin-registration.ts - перевірки володіння/контракту в
src/plugins/contracts/registry.ts - документацію для операторів/Plugin у
docs/
Якщо одна з цих поверхонь відсутня, це зазвичай означає, що можливість ще не повністю інтегрована.
Шаблон можливості
Мінімальний шаблон:
// core contractexport type VideoGenerationProviderPlugin = { id: string; label: string; generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;}; // plugin APIapi.registerVideoGenerationProvider({ id: "openai", label: "OpenAI", async generateVideo(req) { return await generateOpenAiVideo(req); },}); // shared runtime helper for feature/channel pluginsconst clip = await api.runtime.videoGeneration.generate({ prompt: "Show the robot walking through the lab.", cfg,});Шаблон тесту контракту (src/plugins/contracts/registry.ts надає засоби пошуку
володіння, як-от providerContractPluginIds; тести перевіряють, що список
contracts.videoGenerationProviders Plugin відповідає тому, що він фактично реєструє):
expect(pluginManifest.contracts?.videoGenerationProviders).toEqual(["openai"]);Це робить правило простим:
- ядро відповідає за контракт можливості та оркестрацію
- Plugin постачальників відповідають за реалізації постачальників
- Plugin функцій/каналів використовують допоміжні засоби середовища виконання
- тести контрактів зберігають володіння явним
Пов’язані матеріали
- Архітектура Plugin — публічна модель і форми можливостей
- Підшляхи SDK Plugin
- Налаштування SDK Plugin
- Створення Plugin