Plugin maintainer reference

Внутрішня архітектура Plugin

Для публічної моделі можливостей, форм Plugin і контрактів володіння/виконання див. архітектуру Plugin. На цій сторінці описано внутрішні механізми: конвеєр завантаження, реєстр, перехоплювачі середовища виконання, HTTP-маршрути Gateway, шляхи імпорту й таблиці схем.

Конвеєр завантаження

Під час запуску OpenClaw виконує приблизно такі дії:

  1. виявляє корені кандидатів Plugin
  2. читає маніфести нативних або сумісних пакетів і метадані пакетів
  3. відхиляє небезпечних кандидатів
  4. нормалізує конфігурацію Plugin (plugins.enabled, allow, deny, entries, slots, load.paths)
  5. визначає, чи слід увімкнути кожного кандидата
  6. завантажує ввімкнені нативні модулі: зібрані вбудовані модулі використовують нативний завантажувач; локальний вихідний код TypeScript сторонніх розробників використовує аварійний резервний механізм Jiti
  7. викликає нативні перехоплювачі register(api) і збирає реєстрації в реєстр Plugin
  8. надає реєстр командам і поверхням середовища виконання

Перевірки безпеки виконуються до виконання в середовищі виконання. Виявлення блокує кандидата, якщо:

  • його визначена точка входу виходить за межі кореня 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(...), щоб отримати зворотний виклик після схвалення або відхилення запиту на прив’язування:

ts
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 Накладає зовнішні профілі автентифікації, що належать провайдеру; типове значення persistenceruntime-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 маніфесту. Це дає змогу загальним механізмам виявлення та очищення секретів розпізнавати їх, не перетворюючи на кандидатів для автентифікації інференсу.

Приклад постачальника

ts
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:

ts
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(...).

ts
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 реєструють одного типізованого постачальника розпізнавання медіа замість загального набору ключів і значень:

ts
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 можуть викликати:

ts
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:

ts
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:

ts
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 можуть використовувати спільний допоміжний засіб середовища виконання замість прямого доступу до підключення інструментів агента:

ts
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

ts
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(...).

ts
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; він залишається доступним, щоб диспетчеризація керування призупиненням не могла залишитися заблокованою, тоді як звичайні споріднені маршрути того самого плагіна залишаються за межею допуску. Володіння WebSocket handleUpgrade використовує ту саму атомарну межу допуску; щойно обробник приймає сокет, подальшим життєвим циклом сокета керує плагін, і ця межа його не відстежує.

Шляхи імпорту 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, tokenStatus
    • botTokenSource, botTokenStatus
    • appTokenSource, appTokenStatus
    • signingSecretSource, signingSecretStatus
  • Щоб повідомити про доступність лише для читання, не потрібно повертати необроблені значення токенів. Для команд перевірки стану достатньо повернути tokenStatus: "available" (і відповідне поле джерела).
  • Використовуйте configured_unavailable, коли облікові дані налаштовано через SecretRef, але вони недоступні в поточному шляху виконання команди.

Завдяки цьому команди лише для читання можуть повідомляти «налаштовано, але недоступно в цьому шляху виконання команди» замість аварійного завершення або помилкового визначення облікового запису як неналаштованого.

Пакети розширень

Каталог Plugin може містити package.json із openclaw.extensions:

json
{  "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 завантажити повну точку входу під час запуску.

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

  • singleAccountKeysToMove
  • namedAccountPromotionKeys
  • resolveSingleAccountPromotionTarget(...)

Ядро використовує цю поверхню, коли потрібно перенести застарілу конфігурацію каналу з одним обліковим записом до channels.<id>.accounts.* без завантаження повної точки входу Plugin. Matrix є поточним вбудованим прикладом: коли іменовані облікові записи вже існують, він переносить до іменованого цільового облікового запису лише ключі автентифікації/початкового налаштування, а також може зберегти налаштований неканонічний ключ типового облікового запису замість того, щоб завжди створювати accounts.default.

Ці адаптери виправлень налаштування зберігають відкладене виявлення вбудованої поверхні контракту. Час імпорту залишається коротким; поверхня перенесення завантажується лише під час першого використання замість повторного запуску вбудованого каналу під час імпорту модуля.

Коли ці поверхні запуску включають методи RPC Gateway, використовуйте для них префікс, специфічний для Plugin. Простори імен адміністрування ядра (config.*, exec.approvals.*, wizard.*, update.*) залишаються зарезервованими та завжди відповідають operator.admin, навіть якщо Plugin запитує вужчу область дозволів.

Приклад:

json
{  "name": "@scope/my-channel",  "openclaw": {    "extensions": ["./index.ts"],    "setupEntry": "./setup-entry.ts",    "startup": {      "deferConfiguredChannelFullLoadUntilAfterListen": true    }  }}

Метадані каталогу каналів

Plugin каналів можуть оголошувати метадані налаштування/виявлення через openclaw.channel, а підказки зі встановлення — через openclaw.install. Завдяки цьому каталог ядра не містить даних.

Приклад:

json
{  "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: застарілі псевдоніми, які досі приймаються для сумісності; віддавайте перевагу exposure
  • quickstartAllowFrom: долучає канал до стандартного процесу швидкого запуску allowFrom
  • forceAccountBinding: вимагає явного прив’язування облікового запису, навіть якщо існує лише один обліковий запис
  • 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 має замінити або розширити типовий конвеєр контексту, а не лише додати пошук у пам’яті чи перехоплювачі.

ts
  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() реалізованим і явно делегуйте його:

ts
   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 за допомогою приватного прямого доступу. Додайте відсутню можливість.

Рекомендована послідовність:

  1. Визначте контракт ядра. Вирішіть, за яку спільну поведінку має відповідати ядро: політику, резервний варіант, об’єднання конфігурації, життєвий цикл, семантику для каналів і форму допоміжних засобів середовища виконання.
  2. Додайте типізовані поверхні реєстрації Plugin і середовища виконання. Розширте OpenClawPluginApi та/або api.runtime найменшою корисною типізованою поверхнею можливості.
  3. Під’єднайте ядро та споживачів каналів/функцій. Канали й Plugin функцій мають використовувати нову можливість через ядро, а не імпортувати реалізацію постачальника безпосередньо.
  4. Зареєструйте реалізації постачальників. Потім Plugin постачальників реєструють свої серверні реалізації для цієї можливості.
  5. Додайте покриття контракту. Додайте тести, щоб структура володіння та реєстрації залишалася явною з часом.

Саме так 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/

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

Шаблон можливості

Мінімальний шаблон:

ts
// core contractexport type VideoGenerationProviderPlugin = {  id: string;  label: string;  generateVideo: (req: VideoGenerationRequest) => Promise&lt;VideoGenerationResult&gt;;}; // 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 відповідає тому, що він фактично реєструє):

ts
expect(pluginManifest.contracts?.videoGenerationProviders).toEqual(["openai"]);

Це робить правило простим:

  • ядро відповідає за контракт можливості та оркестрацію
  • Plugin постачальників відповідають за реалізації постачальників
  • Plugin функцій/каналів використовують допоміжні засоби середовища виконання
  • тести контрактів зберігають володіння явним

Пов’язані матеріали

Was this useful?
On this page

On this page