Перейти до основного вмісту

Documentation Index

Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt

Use this file to discover all available pages before exploring further.

Цей посібник показує, як створити Plugin провайдера, який додає провайдера моделей (LLM) до OpenClaw. Наприкінці у вас буде провайдер із каталогом моделей, автентифікацією через API-ключ і динамічним визначенням моделей.
Якщо ви ще не створювали жоден Plugin для OpenClaw, спершу прочитайте Початок роботи, щоб ознайомитися з базовою структурою пакета та налаштуванням маніфесту.
Plugin-и провайдерів додають моделі до звичайного циклу інференсу OpenClaw. Якщо модель має запускатися через нативний демон агента, який володіє потоками, Compaction або подіями інструментів, поєднайте провайдера з обв’язкою агента, а не додавайте деталі протоколу демона в ядро.

Покроковий посібник

1

Пакет і маніфест

Крок 1: Пакет і маніфест

{
  "name": "@myorg/openclaw-acme-ai",
  "version": "1.0.0",
  "type": "module",
  "openclaw": {
    "extensions": ["./index.ts"],
    "providers": ["acme-ai"],
    "compat": {
      "pluginApi": ">=2026.3.24-beta.2",
      "minGatewayVersion": "2026.3.24-beta.2"
    },
    "build": {
      "openclawVersion": "2026.3.24-beta.2",
      "pluginSdkVersion": "2026.3.24-beta.2"
    }
  }
}
Маніфест оголошує providerAuthEnvVars, щоб OpenClaw міг виявляти облікові дані без завантаження runtime вашого Plugin. Додайте providerAuthAliases, коли варіант провайдера має повторно використовувати автентифікацію ідентифікатора іншого провайдера. modelSupport є необов’язковим і дає OpenClaw змогу автоматично завантажувати Plugin вашого провайдера за скороченими ідентифікаторами моделей на кшталт acme-large ще до появи runtime-хуків. Якщо ви публікуєте провайдера на ClawHub, ці поля openclaw.compat і openclaw.build є обов’язковими в package.json.
2

Зареєструйте провайдера

Мінімальному текстовому провайдеру потрібні id, label, auth і catalog. catalog — це runtime/config-хук, яким володіє провайдер; він може викликати live API постачальника та повертати записи models.providers.
index.ts
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth";

export default definePluginEntry({
  id: "acme-ai",
  name: "Acme AI",
  description: "Acme AI model provider",
  register(api) {
    api.registerProvider({
      id: "acme-ai",
      label: "Acme AI",
      docsPath: "/providers/acme-ai",
      envVars: ["ACME_AI_API_KEY"],

      auth: [
        createProviderApiKeyAuthMethod({
          providerId: "acme-ai",
          methodId: "api-key",
          label: "Acme AI API key",
          hint: "API key from your Acme AI dashboard",
          optionKey: "acmeAiApiKey",
          flagName: "--acme-ai-api-key",
          envVar: "ACME_AI_API_KEY",
          promptMessage: "Enter your Acme AI API key",
          defaultModel: "acme-ai/acme-large",
        }),
      ],

      catalog: {
        order: "simple",
        run: async (ctx) => {
          const apiKey =
            ctx.resolveProviderApiKey("acme-ai").apiKey;
          if (!apiKey) return null;
          return {
            provider: {
              baseUrl: "https://api.acme-ai.com/v1",
              apiKey,
              api: "openai-completions",
              models: [
                {
                  id: "acme-large",
                  name: "Acme Large",
                  reasoning: true,
                  input: ["text", "image"],
                  cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
                  contextWindow: 200000,
                  maxTokens: 32768,
                },
                {
                  id: "acme-small",
                  name: "Acme Small",
                  reasoning: false,
                  input: ["text"],
                  cost: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
                  contextWindow: 128000,
                  maxTokens: 8192,
                },
              ],
            },
          };
        },
      },
    });

    api.registerModelCatalogProvider({
      provider: "acme-ai",
      kinds: ["text"],
      liveCatalog: async (ctx) => {
        const apiKey = ctx.resolveProviderApiKey("acme-ai").apiKey;
        if (!apiKey) return null;
        return [
          {
            kind: "text",
            provider: "acme-ai",
            model: "acme-large",
            label: "Acme Large",
            source: "live",
          },
        ];
      },
    });
  },
});
registerModelCatalogProvider — це новіша поверхня каталогу рівня керування для інтерфейсу списків, довідки та вибору. Використовуйте її для рядків text, image-generation, video-generation і music-generation. Залишайте виклики endpoint постачальника та мапінг відповідей у Plugin; OpenClaw володіє спільною формою рядків, мітками джерел і рендерингом довідки.Це вже робочий провайдер. Тепер користувачі можуть виконати openclaw onboard --acme-ai-api-key <key> і вибрати acme-ai/acme-large як свою модель.Якщо upstream-провайдер використовує інші керівні токени, ніж OpenClaw, додайте невелике двонапрямне текстове перетворення замість заміни шляху стримінгу:
api.registerTextTransforms({
  input: [
    { from: /red basket/g, to: "blue basket" },
    { from: /paper ticket/g, to: "digital ticket" },
    { from: /left shelf/g, to: "right shelf" },
  ],
  output: [
    { from: /blue basket/g, to: "red basket" },
    { from: /digital ticket/g, to: "paper ticket" },
    { from: /right shelf/g, to: "left shelf" },
  ],
});
input переписує фінальний системний prompt і вміст текстових повідомлень перед передаванням. output переписує текстові дельти асистента та фінальний текст до того, як OpenClaw розбере власні керівні маркери або доставку каналом.Для вбудованих провайдерів, які реєструють лише одного текстового провайдера з автентифікацією через API-ключ і одним runtime на базі каталогу, віддавайте перевагу вужчому допоміжному методу defineSingleProviderPluginEntry(...):
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";

export default defineSingleProviderPluginEntry({
  id: "acme-ai",
  name: "Acme AI",
  description: "Acme AI model provider",
  provider: {
    label: "Acme AI",
    docsPath: "/providers/acme-ai",
    auth: [
      {
        methodId: "api-key",
        label: "Acme AI API key",
        hint: "API key from your Acme AI dashboard",
        optionKey: "acmeAiApiKey",
        flagName: "--acme-ai-api-key",
        envVar: "ACME_AI_API_KEY",
        promptMessage: "Enter your Acme AI API key",
        defaultModel: "acme-ai/acme-large",
      },
    ],
    catalog: {
      buildProvider: () => ({
        api: "openai-completions",
        baseUrl: "https://api.acme-ai.com/v1",
        models: [{ id: "acme-large", name: "Acme Large" }],
      }),
      buildStaticProvider: () => ({
        api: "openai-completions",
        baseUrl: "https://api.acme-ai.com/v1",
        models: [{ id: "acme-large", name: "Acme Large" }],
      }),
    },
  },
});
buildProvider — це шлях live-каталогу, який використовується, коли OpenClaw може визначити реальну автентифікацію провайдера. Він може виконувати специфічне для провайдера виявлення. Використовуйте buildStaticProvider лише для офлайн-рядків, які безпечно показувати до налаштування автентифікації; він не повинен вимагати облікових даних або виконувати мережеві запити. Відображення OpenClaw models list --all наразі виконує статичні каталоги лише для вбудованих Plugin-ів провайдерів, із порожньою конфігурацією, порожнім env і без шляхів агента/робочого простору.Якщо вашому потоку автентифікації також потрібно змінювати models.providers.*, псевдоніми та модель агента за замовчуванням під час onboarding, використовуйте preset-допоміжні методи з openclaw/plugin-sdk/provider-onboard. Найвужчі допоміжні методи: createDefaultModelPresetAppliers(...), createDefaultModelsPresetAppliers(...) і createModelCatalogPresetAppliers(...).Коли нативний endpoint провайдера підтримує блоки використання у стримінгу на звичайному транспорті openai-completions, віддавайте перевагу спільним допоміжним методам каталогу в openclaw/plugin-sdk/provider-catalog-shared замість жорстко закодованих перевірок ідентифікатора провайдера. supportsNativeStreamingUsageCompat(...) і applyProviderNativeStreamingUsageCompat(...) визначають підтримку з мапи можливостей endpoint, тож нативні endpoint-и у стилі Moonshot/DashScope усе ще вмикаються, навіть коли Plugin використовує власний ідентифікатор провайдера.
3

Додайте динамічне визначення моделей

Якщо ваш провайдер приймає довільні ідентифікатори моделей (як proxy або router), додайте resolveDynamicModel:
api.registerProvider({
  // ... id, label, auth, catalog from above

  resolveDynamicModel: (ctx) => ({
    id: ctx.modelId,
    name: ctx.modelId,
    provider: "acme-ai",
    api: "openai-completions",
    baseUrl: "https://api.acme-ai.com/v1",
    reasoning: false,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 128000,
    maxTokens: 8192,
  }),
});
Якщо для визначення потрібен мережевий виклик, використовуйте prepareDynamicModel для асинхронного прогрівання — resolveDynamicModel запускається знову після його завершення.
4

Додайте runtime-хуки (за потреби)

Більшості провайдерів потрібні лише catalog + resolveDynamicModel. Додавайте хуки поступово, коли вони потрібні вашому провайдеру.Спільні допоміжні builder-и тепер покривають найпоширеніші сімейства replay/tool-compat, тож Plugin-ам зазвичай не потрібно вручну під’єднувати кожен хук окремо:
import { buildProviderReplayFamilyHooks } from "openclaw/plugin-sdk/provider-model-shared";
import { buildProviderStreamFamilyHooks } from "openclaw/plugin-sdk/provider-stream";
import { buildProviderToolCompatFamilyHooks } from "openclaw/plugin-sdk/provider-tools";

const GOOGLE_FAMILY_HOOKS = {
  ...buildProviderReplayFamilyHooks({ family: "google-gemini" }),
  ...buildProviderStreamFamilyHooks("google-thinking"),
  ...buildProviderToolCompatFamilyHooks("gemini"),
};

api.registerProvider({
  id: "acme-gemini-compatible",
  // ...
  ...GOOGLE_FAMILY_HOOKS,
});
Доступні сьогодні сімейства replay:
СімействоЩо підключаєВбудовані приклади
openai-compatibleСпільна політика повторного відтворення у стилі OpenAI для OpenAI-сумісних транспортів, зокрема очищення tool-call-id, виправлення порядку assistant-first і загальна валідація ходів Gemini там, де вона потрібна транспортуmoonshot, ollama, xai, zai
anthropic-by-modelПолітика повторного відтворення з урахуванням Claude, вибрана за modelId, щоб транспорти Anthropic-message отримували очищення блоків мислення, специфічне для Claude, лише коли розв’язана модель справді має ідентифікатор Claudeamazon-bedrock, anthropic-vertex
google-geminiНативна політика повторного відтворення Gemini, а також очищення початкового повторного відтворення і режим позначеного виводу reasoninggoogle, google-gemini-cli
passthrough-geminiОчищення thought-signature Gemini для моделей Gemini, що працюють через OpenAI-сумісні проксі-транспорти; не вмикає нативну валідацію повторного відтворення Gemini або переписування початкового завантаженняopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openaiГібридна політика для провайдерів, які поєднують поверхні моделей Anthropic-message і OpenAI-сумісні поверхні моделей в одному plugin; необов’язкове скидання блоків мислення лише для Claude залишається обмеженим стороною Anthropicminimax
Доступні сьогодні сімейства потоків:
СімействоЩо підключаєВбудовані приклади
google-thinkingНормалізація payload мислення Gemini на спільному шляху потокуgoogle, google-gemini-cli
kilocode-thinkingОбгортка reasoning Kilo на спільному шляху проксі-потоку, де kilo/auto і непідтримувані ідентифікатори proxy reasoning пропускають ін’єктоване мисленняkilocode
moonshot-thinkingВідображення бінарного нативного payload мислення Moonshot з конфігурації + рівня /thinkmoonshot
minimax-fast-modeПереписування моделі fast-mode MiniMax на спільному шляху потокуminimax, minimax-portal
openai-responses-defaultsСпільні нативні обгортки OpenAI/Codex Responses: заголовки атрибуції, /fast/serviceTier, докладність тексту, нативний вебпошук Codex, формування payload сумісності reasoning і керування контекстом Responsesopenai, openai-codex
openrouter-thinkingОбгортка reasoning OpenRouter для проксі-маршрутів, із централізованою обробкою пропусків для непідтримуваних моделей/autoopenrouter
tool-stream-default-onОбгортка tool_stream, увімкнена за замовчуванням, для провайдерів на кшталт Z.AI, які хочуть потокове передавання інструментів, якщо його явно не вимкненоzai
Кожен побудовник сімейства складений із нижчорівневих публічних допоміжних функцій, експортованих із того самого пакета, до яких можна звернутися, коли провайдеру потрібно відійти від спільного шаблону:
  • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamily, buildProviderReplayFamilyHooks(...), і сирі побудовники повторного відтворення (buildOpenAICompatibleReplayPolicy, buildAnthropicReplayPolicyForModel, buildGoogleGeminiReplayPolicy, buildHybridAnthropicOrOpenAIReplayPolicy). Також експортує допоміжні функції повторного відтворення Gemini (sanitizeGoogleGeminiReplayHistory, resolveTaggedReasoningOutputMode) і допоміжні функції endpoint/model (resolveProviderEndpoint, normalizeProviderId, normalizeGooglePreviewModelId).
  • openclaw/plugin-sdk/provider-stream - ProviderStreamFamily, buildProviderStreamFamilyHooks(...), composeProviderStreamWrappers(...), а також спільні обгортки OpenAI/Codex (createOpenAIAttributionHeadersWrapper, createOpenAIFastModeWrapper, createOpenAIServiceTierWrapper, createOpenAIResponsesContextManagementWrapper, createCodexNativeWebSearchWrapper), OpenAI-сумісна обгортка DeepSeek V4 (createDeepSeekV4OpenAICompatibleThinkingWrapper), очищення префілу мислення Anthropic Messages (createAnthropicThinkingPrefillPayloadWrapper) і спільні проксі/провайдерські обгортки (createOpenRouterWrapper, createToolStreamWrapper, createMinimaxFastModeWrapper).
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamily, buildProviderToolCompatFamilyHooks("gemini") і базові допоміжні функції схем Gemini (normalizeGeminiToolSchemas, inspectGeminiToolSchemas).
Деякі допоміжні функції потоків навмисно залишаються локальними для провайдера. @openclaw/anthropic-provider тримає wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier і нижчорівневі побудовники обгорток Anthropic у власному публічному шві api.ts / contract-api.ts, тому що вони кодують обробку Claude OAuth beta і gating context1m. Plugin xAI так само тримає нативне формування xAI Responses у власному wrapStreamFn (аліаси /fast, стандартний tool_stream, очищення непідтримуваного strict-tool, вилучення reasoning-payload, специфічне для xAI).Такий самий шаблон package-root також підтримує @openclaw/openai-provider (побудовники провайдера, допоміжні функції моделі за замовчуванням, побудовники realtime-провайдера) і @openclaw/openrouter-provider (побудовник провайдера плюс допоміжні функції onboarding/config).
Для провайдерів, яким потрібен обмін токена перед кожним викликом inference:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw викликає hooks у такому порядку. Більшість провайдерів використовують лише 2-3: Поля провайдера лише для сумісності, які OpenClaw більше не викликає, як-от ProviderPlugin.capabilities і suppressBuiltInModel, тут не перелічені.
#HookКоли використовувати
1catalogКаталог моделей або стандартні значення базового URL
2applyConfigDefaultsГлобальні стандартні значення, якими володіє провайдер, під час матеріалізації конфігурації
3normalizeModelIdОчищення застарілих/preview псевдонімів model-id перед пошуком
4normalizeTransportОчищення api / baseUrl сімейства провайдера перед загальною збіркою моделі
5normalizeConfigНормалізація конфігурації models.providers.<id>
6applyNativeStreamingUsageCompatПереписування сумісності нативного streaming-usage для конфігураційних провайдерів
7resolveConfigApiKeyРозв’язання auth env-marker, яким володіє провайдер
8resolveSyntheticAuthСинтетичний auth для локальних/self-hosted або config-backed випадків
9shouldDeferSyntheticProfileAuthПониження synthetic stored-profile placeholders після env/config auth
10resolveDynamicModelПриймати довільні ідентифікатори upstream моделей
11prepareDynamicModelАсинхронне отримання метаданих перед розв’язанням
12normalizeResolvedModelПереписування транспорту перед runner
13contributeResolvedModelCompatПрапорці сумісності для vendor моделей за іншим сумісним транспортом
14normalizeToolSchemasОчищення tool-schema, яким володіє провайдер, перед реєстрацією
15inspectToolSchemasДіагностика tool-schema, якою володіє провайдер
16resolveReasoningOutputModeКонтракт tagged vs native reasoning-output
17prepareExtraParamsСтандартні параметри запиту
18createStreamFnПовністю власний транспорт StreamFn
19wrapStreamFnВласні обгортки заголовків/тіла на звичайному шляху потоку
20resolveTransportTurnStateНативні заголовки/метадані для кожного ходу
21resolveWebSocketSessionPolicyНативні заголовки сеансу WS/cool-down
22formatApiKeyВласна форма runtime-токена
23refreshOAuthВласне оновлення OAuth
24buildAuthDoctorHintПідказки щодо відновлення auth
25matchesContextOverflowErrorВиявлення overflow, яким володіє провайдер
26classifyFailoverReasonКласифікація rate-limit/overload, якою володіє провайдер
27isCacheTtlEligibleGating TTL кешу prompt
28buildMissingAuthMessageВласна підказка щодо відсутнього auth
29augmentModelCatalogСинтетичні рядки forward-compat
30resolveThinkingProfileНабір опцій /think, специфічний для моделі
31isBinaryThinkingСумісність двійкового увімкнення/вимкнення мислення
32supportsXHighThinkingСумісність підтримки reasoning xhigh
33resolveDefaultThinkingLevelСумісність стандартної політики /think
34isModernModelRefЗіставлення моделей live/smoke
35prepareRuntimeAuthОбмін токена перед inference
36resolveUsageAuthВласний розбір облікових даних usage
37fetchUsageSnapshotВласний endpoint usage
38createEmbeddingProviderАдаптер embeddings для memory/search, яким володіє провайдер
39buildReplayPolicyВласна політика повторного відтворення/Compaction transcript
40sanitizeReplayHistoryСпецифічні для провайдера переписування replay після загального очищення
41validateReplayTurnsСувора валідація replay-turn перед вбудованим runner
42onModelSelectedCallback після вибору (наприклад, telemetry)
Примітки щодо runtime fallback:
  • normalizeConfig спершу перевіряє зіставленого провайдера, а потім інші provider plugins із підтримкою hooks, доки один із них справді не змінить конфігурацію. Якщо жоден hook провайдера не переписує підтримуваний запис конфігурації сімейства Google, вбудований нормалізатор конфігурації Google усе одно застосовується.
  • resolveConfigApiKey використовує hook провайдера, коли його надано. Вбудований шлях amazon-bedrock також має тут вбудований resolver AWS env-marker, хоча сам runtime auth Bedrock усе ще використовує стандартний ланцюг AWS SDK.
  • resolveSystemPromptContribution дає провайдеру змогу вставити cache-aware підказки system-prompt для сімейства моделей. Віддавайте йому перевагу над before_prompt_build, коли поведінка належить одному провайдеру/сімейству моделей і має зберегти стабільне/динамічне розділення кешу.
Докладні описи та реальні приклади див. у Внутрішня архітектура: Provider Runtime Hooks.
5

Додайте додаткові можливості (необов’язково)

Крок 5: Додайте додаткові можливості

Плагін провайдера може реєструвати мовлення, транскрипцію в реальному часі, голос у реальному часі, розуміння медіа, генерацію зображень, генерацію відео, веботримання та вебпошук разом із текстовим інференсом. OpenClaw класифікує це як плагін із гібридними можливостями — рекомендований патерн для плагінів компаній (один плагін на постачальника). Див. Внутрішнє: володіння можливостями.Реєструйте кожну можливість у register(api) поруч із наявним викликом api.registerProvider(...). Виберіть лише потрібні вкладки:
import {
  assertOkOrThrowProviderError,
  postJsonRequest,
} from "openclaw/plugin-sdk/provider-http";

api.registerSpeechProvider({
  id: "acme-ai",
  label: "Acme Speech",
  isConfigured: ({ config }) => Boolean(config.messages?.tts),
  synthesize: async (req) => {
    const { response, release } = await postJsonRequest({
      url: "https://api.example.com/v1/speech",
      headers: new Headers({ "Content-Type": "application/json" }),
      body: { text: req.text },
      timeoutMs: req.timeoutMs,
      fetchFn: fetch,
      auditContext: "acme speech",
    });
    try {
      await assertOkOrThrowProviderError(response, "Acme Speech API error");
      return {
        audioBuffer: Buffer.from(await response.arrayBuffer()),
        outputFormat: "mp3",
        fileExtension: ".mp3",
        voiceCompatible: false,
      };
    } finally {
      await release();
    }
  },
});
Використовуйте assertOkOrThrowProviderError(...) для HTTP-збоїв провайдера, щоб плагіни спільно використовували обмежене читання тіла помилки, парсинг помилок JSON і суфікси ідентифікаторів запитів.
6

Тест

Крок 6: Тест

src/provider.test.ts
import { describe, it, expect } from "vitest";
// Export your provider config object from index.ts or a dedicated file
import { acmeProvider } from "./provider.js";

describe("acme-ai provider", () => {
  it("resolves dynamic models", () => {
    const model = acmeProvider.resolveDynamicModel!({
      modelId: "acme-beta-v3",
    } as any);
    expect(model.id).toBe("acme-beta-v3");
    expect(model.provider).toBe("acme-ai");
  });

  it("returns catalog when key is available", async () => {
    const result = await acmeProvider.catalog!.run({
      resolveProviderApiKey: () => ({ apiKey: "test-key" }),
    } as any);
    expect(result?.provider?.models).toHaveLength(2);
  });

  it("returns null catalog when no key", async () => {
    const result = await acmeProvider.catalog!.run({
      resolveProviderApiKey: () => ({ apiKey: undefined }),
    } as any);
    expect(result).toBeNull();
  });
});

Публікація в ClawHub

Плагіни провайдерів публікуються так само, як і будь-який інший зовнішній кодовий плагін:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
Не використовуйте тут застарілий псевдонім публікації лише для skill; пакети плагінів мають використовувати clawhub package publish.

Структура файлів

<bundled-plugin-root>/acme-ai/
├── package.json              # openclaw.providers metadata
├── openclaw.plugin.json      # Manifest with provider auth metadata
├── index.ts                  # definePluginEntry + registerProvider
└── src/
    ├── provider.test.ts      # Tests
    └── usage.ts              # Usage endpoint (optional)

Довідник порядку каталогу

catalog.order контролює, коли ваш каталог об’єднується відносно вбудованих провайдерів:
ПорядокКолиВипадок використання
simpleПерший прохідЗвичайні провайдери API-ключів
profileПісля simpleПровайдери, обмежені профілями автентифікації
pairedПісля profileСинтез кількох пов’язаних записів
lateОстанній прохідПеревизначення наявних провайдерів (перемагає в разі конфлікту)

Наступні кроки

Пов’язане