Plugin maintainer reference

Внутреннее устройство архитектуры плагинов

Для публичной модели возможностей, форм плагинов и контрактов владения/выполнения см. Архитектура плагинов. На этой странице рассматриваются внутренние механизмы: конвейер загрузки, реестр, перехватчики среды выполнения, HTTP-маршруты Gateway, пути импорта и таблицы схем.

Конвейер загрузки

При запуске OpenClaw выполняет примерно следующее:

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

Проверки безопасности выполняются до выполнения среды. Обнаружение блокирует кандидата, если:

  • его разрешённая точка входа находится за пределами корня плагина
  • его путь (или корневой каталог) доступен для записи всем пользователям
  • для невстроенных плагинов владелец пути не соответствует текущему uid (или root)

Для доступных всем на запись каталогов встроенных плагинов сначала предпринимается попытка исправления на месте с помощью chmod (при установке через npm или глобально каталоги пакетов могут поставляться с правами 0777), после чего проверка выполняется повторно; для встроенного источника проверка владельца полностью пропускается.

Заблокированные кандидаты всё равно содержат идентификатор плагина в выдаваемой диагностике, если он известен (включая идентификаторы, полученные из манифеста внутри каталога, отклонённого по другой причине), поэтому конфигурация, ссылающаяся на такой идентификатор, получает заблокированный плагин с предупреждением о безопасности пути вместо несвязанной ошибки «неизвестный плагин».

Приоритет манифеста

Манифест — источник истины уровня управления. OpenClaw использует его, чтобы:

  • идентифицировать плагин
  • обнаруживать объявленные каналы, Skills, схему конфигурации или возможности пакета
  • проверять plugins.entries.<id>.config
  • дополнять подписи и заполнители Control UI
  • показывать метаданные установки и каталога
  • сохранять недорогие дескрипторы активации и настройки без загрузки среды выполнения плагина

Для нативных плагинов модуль среды выполнения представляет уровень данных. Он регистрирует фактическое поведение, например перехватчики, инструменты, команды или потоки провайдера.

Необязательные блоки манифеста activation и setup остаются на уровне управления. Это исключительно метаданные для планирования активации и обнаружения настройки; они не заменяют регистрацию среды выполнения, register(...) или setupEntry. Активные потребители активации используют подсказки манифеста о командах, каналах и провайдерах, чтобы сузить загрузку плагинов до более широкой материализации реестра:

  • загрузка CLI ограничивается плагинами, которым принадлежит запрошенная основная команда
  • настройка канала и разрешение плагина ограничиваются плагинами, которым принадлежит запрошенный идентификатор канала
  • явная настройка провайдера и его разрешение во время выполнения ограничиваются плагинами, которым принадлежит запрошенный идентификатор провайдера
  • планирование запуска Gateway использует activation.onStartup для явных импортов при запуске; плагины без метаданных запуска загружаются только через более узкие триггеры активации

Планировщик активации предоставляет как API только с идентификаторами для существующих вызывающих сторон, так и API плана для диагностики. Записи плана сообщают, почему был выбран плагин, отделяя явные подсказки 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)

Это разделение причин служит границей совместимости: существующие метаданные плагинов продолжают работать, а новый код может обнаруживать широкие подсказки или резервное поведение, не изменяя семантику загрузки среды выполнения.

Предварительные загрузки среды выполнения во время запроса, запрашивающие широкую область all, всё равно формируют явный эффективный набор идентификаторов плагинов из конфигурации, планирования запуска, настроенных каналов, слотов и правил автоматического включения (resolveEffectivePluginIds в src/plugins/effective-plugin-ids.ts). Если этот производный набор пуст, OpenClaw оставляет область пустой, а не расширяет её до всех обнаруживаемых плагинов.

Обнаружение настройки предпочитает принадлежащие дескрипторам идентификаторы, такие как setup.providers и setup.cliBackends, чтобы сузить список плагинов-кандидатов перед переходом к резервному setup-api для плагинов, которым по-прежнему нужны перехватчики среды выполнения во время настройки. Списки настройки провайдеров используют providerAuthChoices из манифеста, полученные из дескрипторов варианты настройки и метаданные каталога установки без загрузки среды выполнения провайдера. Явный setup.requiresRuntime: false служит порогом только для дескрипторов; если requiresRuntime отсутствует, для совместимости сохраняется устаревший резервный механизм setup-api. Если более одного обнаруженного плагина заявляет один и тот же нормализованный идентификатор провайдера настройки или серверной части CLI, поиск настройки отклоняет неоднозначного владельца вместо зависимости от порядка обнаружения. Когда среда выполнения настройки всё же запускается, диагностика реестра сообщает о расхождениях между setup.providers / setup.cliBackends и провайдерами или серверными частями CLI, фактически зарегистрированными через setup-api, не блокируя устаревшие плагины.

Граница кеширования плагинов

OpenClaw не кеширует результаты обнаружения плагинов или непосредственные данные реестра манифестов на основе временных окон. Установки, изменения манифестов и путей загрузки должны становиться видимыми при следующем явном чтении метаданных или перестроении снимка. Парсер файла манифеста поддерживает ограниченный кеш сигнатур файлов, ключом которого служат путь к открытому манифесту, устройство и inode, размер, а также mtime/ctime; этот кеш лишь предотвращает повторный разбор неизменённых байтов и не должен кешировать результаты обнаружения, реестр, владельцев или решения политик.

Безопасный быстрый путь метаданных основан на явном владении объектами, а не на скрытом кеше. Горячие пути запуска Gateway должны передавать текущий PluginMetadataSnapshot, производный PluginLookUpTable или явный реестр манифестов по цепочке вызовов. Проверка конфигурации, автоматическое включение при запуске, начальная загрузка плагинов и выбор провайдера могут повторно использовать эти объекты, пока они представляют текущую конфигурацию и набор плагинов. Поиск настройки всё равно воссоздаёт метаданные манифеста по требованию, если конкретный путь настройки не получает явный реестр манифестов; сохраняйте это как резервный механизм холодного пути, а не добавляйте скрытые кеши поиска. При изменении входных данных перестраивайте и заменяйте снимок, не изменяя его на месте и не сохраняя исторические копии. Представления активного реестра плагинов и вспомогательные средства начальной загрузки встроенных каналов следует пересчитывать из текущего реестра/корня. Краткоживущие отображения допустимы внутри одного вызова для устранения повторной работы или защиты от повторного входа; они не должны превращаться в кеши метаданных процесса.

Для загрузки плагинов постоянным уровнем кеширования служит загрузка среды выполнения. Он может повторно использовать состояние загрузчика, когда код или установленные артефакты действительно загружаются, например:

  • PluginLoaderCacheState и совместимые активные реестры среды выполнения
  • кеши jiti/модулей и кеши загрузчика публичных поверхностей, позволяющие избежать повторного импорта одной и той же поверхности среды выполнения
  • кеши файловой системы для артефактов установленных плагинов
  • краткоживущие отображения на время вызова для нормализации путей или устранения дубликатов

Эти кеши — детали реализации уровня данных. Они не должны отвечать на вопросы уровня управления, такие как «какому плагину принадлежит этот провайдер?», если вызывающая сторона намеренно не запросила загрузку среды выполнения.

Не добавляйте постоянные или зависящие от времени кеши для:

  • результатов обнаружения
  • непосредственных реестров манифестов
  • реестров манифестов, воссозданных из индекса установленных плагинов
  • поиска владельца провайдера, подавления моделей, политики провайдера или метаданных публичных артефактов
  • любых других ответов, полученных из манифеста, для которых изменённый манифест, индекс установленных компонентов или путь загрузки должен быть виден при следующем чтении метаданных

Вызывающие стороны, которые перестраивают метаданные манифестов из сохранённого индекса установленных плагинов, воссоздают этот реестр по требованию. Установленный индекс — долговечное состояние исходного уровня, а не скрытый кеш метаданных внутри процесса.

Модель реестра

Загруженные плагины не изменяют напрямую произвольные глобальные объекты ядра. Они регистрируются в центральном реестре плагинов (PluginRegistry в src/plugins/registry-types.ts), который отслеживает записи плагинов (идентичность, источник, происхождение, состояние, диагностику), а также массивы для каждой возможности: инструменты, устаревшие и типизированные перехватчики, каналы, провайдеры, обработчики RPC Gateway, HTTP-маршруты, регистраторы CLI, фоновые службы, принадлежащие плагинам команды и множество других типизированных семейств провайдеров (речь, векторные представления, генерация изображений, видео и музыки, получение данных и поиск в интернете, среды агентов, действия сеансов и т. д.).

Затем основные функции читают данные из этого реестра, а не взаимодействуют с модулями плагинов напрямую. Благодаря этому загрузка остаётся однонаправленной:

  • модуль плагина -> регистрация в реестре
  • среда выполнения ядра -> использование реестра

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

Обратные вызовы привязки беседы

Плагины, привязывающие беседу, могут реагировать на результат запроса подтверждения.

Используйте api.onConversationBindingResolved(...), чтобы получить обратный вызов после одобрения или отклонения запроса на привязку:

ts
export default {  id: "my-plugin",  register(api) {    api.onConversationBindingResolved(async (event) => {      if (event.status === "approved") {        // Теперь для этого плагина и беседы существует привязка.        console.log(event.binding?.conversationId);        return;      }       // Запрос отклонён; очистите всё локальное состояние ожидания.      console.log(event.request.conversation.conversationId);    });  },};

Поля полезной нагрузки обратного вызова:

  • status: "approved" или "denied"
  • decision: "allow-once", "allow-always" или "deny"
  • binding: разрешённая привязка для одобренных запросов
  • request: исходная сводка запроса, подсказка отсоединения, идентификатор отправителя и метаданные беседы

Этот обратный вызов служит только для уведомления. Он не изменяет того, кому разрешено привязывать беседу, и выполняется после завершения основной обработки подтверждения.

Перехватчики среды выполнения провайдера

Плагины провайдеров состоят из трёх уровней:

  • Метаданные манифеста для быстрого и нетребовательного поиска до запуска: 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 Создать принадлежащий провайдеру адаптер эмбеддингов для памяти/поиска Логика работы эмбеддингов памяти относится к плагину провайдера
buildReplayPolicy Вернуть политику повторного воспроизведения, управляющую обработкой истории диалога для провайдера Провайдеру требуется пользовательская политика истории диалога (например, удаление блоков рассуждений)
sanitizeReplayHistory Перезаписать историю повторного воспроизведения после общей очистки истории диалога Провайдеру требуются специфичные для него преобразования повторного воспроизведения помимо общих вспомогательных средств Compaction
validateReplayTurns Выполнить окончательную проверку или преобразование хода повторного воспроизведения перед встроенным средством запуска Транспорту провайдера требуется более строгая проверка хода после общей очистки
onModelSelected Выполнить принадлежащие провайдеру побочные действия после выбора При активации модели провайдеру требуется телеметрия или принадлежащее провайдеру состояние

normalizeModelId, normalizeTransport и normalizeConfig сначала проверяют соответствующий плагин провайдера, а затем последовательно обращаются к другим плагинам провайдеров, поддерживающим хуки, пока один из них фактически не изменит идентификатор модели или транспорт/конфигурацию. Это позволяет псевдонимам и совместимым адаптерам провайдеров работать без необходимости для вызывающей стороны знать, какой встроенный плагин отвечает за преобразование. Если ни один хук провайдера не преобразует поддерживаемую запись конфигурации семейства 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);  },});

Встроенные примеры

Встроенные плагины провайдеров сочетают приведённые выше хуки с учётом требований каждого поставщика к каталогу, авторизации, рассуждению, повторному воспроизведению и сведениям об использовании. Авторитетный набор хуков находится в каждом плагине в 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, вместо того чтобы каждый плагин заново реализовывал очистку.

Провайдеры только с каталогом

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 плагина Anthropic (wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier), а не в универсальном SDK.

Вспомогательные средства среды выполнения

Плагины могут обращаться к избранным вспомогательным средствам ядра через 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 и частоту дискретизации. Плагины должны передискретизировать/кодировать данные для провайдеров.
  • listVoices является необязательным для каждого провайдера. Используйте его для принадлежащих поставщику средств выбора голоса или процессов настройки.
  • Ядро передаёт рассчитанный крайний срок запроса в хуки провайдера listVoices; настройки тайм-аута конкретного провайдера могут его переопределить.
  • Списки голосов могут содержать более подробные метаданные, такие как локаль, пол и теги характера, для средств выбора с учётом провайдера.
  • OpenAI и ElevenLabs сейчас поддерживают телефонию. Microsoft — нет.

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

Для распознавания изображений/аудио/видео плагины регистрируют один типизированный провайдер анализа мультимедиа вместо универсального набора ключей и значений:

ts
api.registerMediaUnderstandingProvider({  id: "google",  capabilities: ["image", "audio", "video"],  describeImage: async (req) => ({ text: "..." }),  transcribeAudio: async (req) => ({ text: "..." }),  describeVideo: async (req) => ({ text: "..." }),});

Примечания:

  • Сохраняйте оркестрацию, резервный механизм, конфигурацию и подключение каналов в ядре.
  • Сохраняйте поведение поставщика в плагине провайдера.
  • Аддитивное расширение должно оставаться типизированным: новые необязательные методы, новые необязательные поля результатов, новые необязательные возможности.
  • Генерация видео уже следует тому же шаблону:
    • ядро управляет контрактом возможностей и вспомогательным средством среды выполнения
    • плагины поставщиков регистрируют api.registerVideoGenerationProvider(...)
    • плагины функций/каналов используют api.runtime.videoGeneration.*

Для вспомогательных средств анализа мультимедиа среды выполнения плагины могут вызывать:

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,});

Для транскрибирования аудио плагины могут использовать либо среду выполнения анализа мультимедиа, либо более старый псевдоним 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(...) — доступный плагинам интерфейс для ограниченного извлечения, принадлежащего провайдеру и ориентированного прежде всего на изображения. Включайте хотя бы один вход изображения; текстовые входы служат дополнительным контекстом. Продуктовые плагины управляют своими маршрутами и схемами, а OpenClaw — границей провайдера и среды выполнения.
  • Использует аудиоконфигурацию анализа мультимедиа ядра (tools.media.audio) и порядок резервного выбора провайдеров.
  • Возвращает { text: undefined }, если результат транскрибирования не создан (например, вход пропущен/не поддерживается).
  • api.runtime.stt.transcribeAudioFile(...) сохраняется как псевдоним совместимости.

Плагины также могут запускать фоновые выполнения подагентов через 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 учитывает эти поля переопределения только для доверенных вызывающих сторон.
  • Для принадлежащих плагину резервных выполнений операторы должны явно включить их с помощью plugins.entries.<id>.subagent.allowModelOverride: true.
  • Используйте plugins.entries.<id>.subagent.allowedModels, чтобы ограничить доверенные плагины конкретными каноническими целями provider/model, либо "*", чтобы явно разрешить любую цель.
  • Выполнения подагентов недоверенных плагинов по-прежнему работают, но запросы на переопределение отклоняются вместо неявного перехода к резервному варианту.
  • Сеансы подагентов, созданные плагином, помечаются идентификатором создавшего их плагина. Резервный механизм api.runtime.subagent.deleteSession(...) может удалять только эти принадлежащие ему сеансы; для удаления произвольных сеансов по-прежнему требуется запрос к Gateway с областью администратора.

Для веб-поиска плагины могут использовать общее вспомогательное средство среды выполнения вместо прямого обращения к подключению инструментов агента:

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,  },});

Плагины также могут регистрировать провайдеров веб-поиска через api.registerWebSearchProvider(...).

Примечания:

  • Сохраняйте выбор провайдера, разрешение учётных данных и общую семантику запросов в ядре.
  • Используйте провайдеров веб-поиска для специфичных для поставщика транспортов поиска.
  • api.runtime.webSearch.* — предпочтительная общая поверхность для плагинов функций/каналов, которым требуется поведение поиска без зависимости от оболочки инструмента агента.

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

Плагины могут предоставлять 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" для управляемой плагином аутентификации либо проверки Webhook.
  • match: необязательное поле. "exact" (по умолчанию) или "prefix".
  • handleUpgrade: необязательный обработчик запросов обновления соединения до WebSocket на том же маршруте.
  • replaceExisting: необязательное поле. Позволяет тому же плагину заменить собственную существующую регистрацию маршрута.
  • handler: верните true, если маршрут обработал запрос.

Примечания:

  • api.registerHttpHandler(...) удалён и вызовет ошибку загрузки плагина. Вместо него используйте api.registerHttpRoute(...).
  • Маршруты плагина должны явно объявлять auth.
  • Конфликты точных значений path + match отклоняются, если не задано replaceExisting: true; один плагин не может заменить маршрут другого плагина.
  • Перекрывающиеся маршруты с разными уровнями auth отклоняются. Цепочки перехода exact/prefix должны использовать только один уровень аутентификации.
  • Маршруты auth: "plugin" не получают области доступа среды выполнения оператора автоматически. Они предназначены для управляемых плагином Webhook и проверки подписей, а не для привилегированных вызовов вспомогательных функций 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 возвращает 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/config, не должны материализовывать учётные данные среды выполнения только для того, чтобы описать конфигурацию.

Рекомендуемое поведение inspectAccount(...):

  • Возвращайте только описательное состояние учётной записи.
  • Сохраняйте enabled и configured.
  • При необходимости включайте поля источника и состояния учётных данных, например:
    • tokenSource, tokenStatus
    • botTokenSource, botTokenStatus
    • appTokenSource, appTokenStatus
    • signingSecretSource, signingSecretStatus
  • Для сообщения о доступности в режиме только для чтения не нужно возвращать необработанные значения токенов. Для команд, отображающих состояние, достаточно вернуть tokenStatus: "available" (и соответствующее поле источника).
  • Используйте configured_unavailable, когда учётные данные настроены через SecretRef, но недоступны в текущем пути команды.

Благодаря этому команды только для чтения могут сообщать «настроено, но недоступно в этом пути команды», а не аварийно завершаться или ошибочно указывать, что учётная запись не настроена.

Пакеты плагинов

Каталог плагина может содержать package.json с openclaw.extensions:

json
{  "name": "my-pack",  "openclaw": {    "extensions": ["./src/safety.ts", "./src/tools.ts"],    "setupEntry": "./src/setup-entry.ts"  }}

Каждая запись становится плагином. Если пакет перечисляет несколько расширений, идентификатор плагина становится <manifestOrPackageName>/<fileBase> (при наличии приоритет имеет идентификатор манифеста; в противном случае используется имя package.json без области).

Если ваш плагин импортирует зависимости npm, установите их в этом каталоге, чтобы node_modules был доступен (npm install / pnpm install).

Ограничение безопасности: после разрешения символических ссылок каждая запись openclaw.extensions должна оставаться внутри каталога плагина. Записи, выходящие за пределы каталога пакета, отклоняются.

Примечание по безопасности: openclaw plugins install устанавливает зависимости плагина с помощью локального для проекта npm install --omit=dev --ignore-scripts (без сценариев жизненного цикла и без зависимостей для разработки во время выполнения), игнорируя унаследованные глобальные настройки установки npm. Поддерживайте деревья зависимостей плагина в виде «чистого JS/TS» и избегайте пакетов, которым требуются сборки postinstall.

Необязательно: openclaw.setupEntry может указывать на облегчённый модуль только для настройки. Когда OpenClaw требуются поверхности настройки для отключённого плагина канала или когда плагин канала включён, но ещё не настроен, загружается setupEntry вместо полной точки входа плагина. Это снижает нагрузку при запуске и настройке, если основная точка входа плагина также подключает инструменты, хуки или другой код, используемый только во время выполнения.

Необязательно: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen может включить для плагина канала тот же путь setupEntry на этапе запуска Gateway до начала прослушивания, даже если канал уже настроен.

Используйте это только тогда, когда setupEntry полностью покрывает поверхность запуска, которая должна существовать до того, как Gateway начнёт прослушивание. На практике это означает, что точка входа настройки должна регистрировать все принадлежащие каналу возможности, от которых зависит запуск, например:

  • саму регистрацию канала
  • все HTTP-маршруты, которые должны быть доступны до начала прослушивания Gateway
  • все методы Gateway, инструменты или службы, которые должны существовать в течение того же периода

Если полной точке входа всё ещё принадлежит какая-либо обязательная возможность запуска, не включайте этот флаг. Оставьте для плагина поведение по умолчанию и позвольте OpenClaw загрузить полную точку входа во время запуска.

Встроенные каналы также могут публиковать вспомогательные средства поверхности контракта только для настройки, к которым ядро может обращаться до загрузки полной среды выполнения канала. Текущая поверхность преобразования настройки:

  • singleAccountKeysToMove
  • namedAccountPromotionKeys
  • resolveSingleAccountPromotionTarget(...)

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

Эти адаптеры исправлений настройки сохраняют ленивое обнаружение встроенной поверхности контракта. Импорт остаётся лёгким; поверхность преобразования загружается только при первом использовании, а не повторно запускает встроенный канал при импорте модуля.

Если эти поверхности запуска включают RPC-методы Gateway, используйте для них префикс конкретного плагина. Административные пространства имён ядра (config.*, exec.approvals.*, wizard.*, update.*) остаются зарезервированными и всегда разрешаются в operator.admin, даже если плагин запрашивает более узкую область.

Пример:

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

Метаданные каталога каналов

Плагины каналов могут публиковать метаданные настройки и обнаружения через 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: идентификаторы плагинов или каналов с более низким приоритетом, которые эта запись каталога должна опережать
  • 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 как добавочное необязательное поле, чтобы созданным вручную записям и адаптерам каталога не требовалось его синтезировать. Это позволяет процессам первичной настройки и диагностики объяснять состояние уровня источников, не импортируя среду выполнения плагина.

Официальным внешним записям npm следует предпочитать точный npmSpec вместе с expectedIntegrity. Простые имена пакетов и dist-tags по-прежнему работают для совместимости, но вызывают предупреждения уровня источников, чтобы каталог мог перейти к закреплённым установкам с проверкой целостности без нарушения работы существующих плагинов. При установке в процессе первичной настройки из локального пути каталога создаётся управляемая запись индекса плагинов с source: "path" и, когда это возможно, относительным к рабочей области sourcePath. Абсолютный рабочий путь загрузки остаётся в plugins.load.paths; запись установки не дублирует пути локальной рабочей станции в долгоживущей конфигурации. Благодаря этому локальные установки для разработки остаются видимыми диагностике уровня источников без добавления второй поверхности раскрытия необработанного пути файловой системы. Сохранённая таблица SQLite installed_plugin_index является источником истины для установки и может обновляться без загрузки модулей среды выполнения плагина. Её карта installRecords сохраняется, даже если манифест плагина отсутствует или недействителен; её содержимое plugins представляет собой восстанавливаемое представление манифеста.

Плагины движка контекста

Плагины движка контекста управляют оркестрацией контекста сеанса для приёма, сборки и Compaction. Зарегистрируйте их из своего плагина с помощью api.registerContextEngine(id, factory), затем выберите активный движок с помощью plugins.slots.contextEngine.

Используйте это, когда вашему плагину требуется заменить или расширить стандартный конвейер контекста, а не просто добавить поиск по памяти или хуки.

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);    },  }));}

Добавление новой возможности

Когда плагину требуется поведение, не соответствующее текущему API, не обходите систему плагинов через приватный прямой доступ. Добавьте недостающую возможность.

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

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

Так OpenClaw сохраняет собственный подход, не становясь жёстко привязанным к представлению одного поставщика. Конкретный список файлов и подробный пример см. в Руководстве по возможностям.

Контрольный список возможности

При добавлении новой возможности реализация обычно должна одновременно затрагивать следующие поверхности:

  • типы контракта ядра в src/<capability>/types.ts
  • исполнитель или вспомогательную функцию среды выполнения ядра в src/<capability>/runtime.ts
  • поверхность регистрации API плагина в src/plugins/types.ts
  • подключение реестра плагинов в src/plugins/registry.ts
  • предоставление среды выполнения плагина в src/plugins/runtime/*, когда функциональным или канальным плагинам необходимо её использовать
  • вспомогательные средства захвата и тестирования в src/test-utils/plugin-registration.ts
  • проверки принадлежности и контракта в src/plugins/contracts/registry.ts
  • документацию для операторов и разработчиков плагинов в 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 плагина соответствует тому, что он фактически регистрирует):

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

Это позволяет сохранить правило простым:

  • ядро отвечает за контракт возможности и оркестрацию
  • плагины поставщиков отвечают за реализации поставщиков
  • функциональные и канальные плагины используют вспомогательные функции среды выполнения
  • тесты контрактов явно фиксируют принадлежность

Связанные материалы

Was this useful?
On this page

On this page