Naar hoofdinhoud gaan

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.

Deze handleiding loopt door het bouwen van een provider-Plugin dat een modelprovider (LLM) toevoegt aan OpenClaw. Aan het einde heb je een provider met een modelcatalogus, API-sleutelauthenticatie en dynamische modelresolutie.
Als je nog niet eerder een OpenClaw-Plugin hebt gebouwd, lees dan eerst Aan de slag voor de basispakketstructuur en manifestinstelling.
Provider-Plugins voegen modellen toe aan de normale inferentielus van OpenClaw. Als het model via een native agent-daemon moet draaien die threads, Compaction of toolgebeurtenissen beheert, combineer de provider dan met een agent-harnas in plaats van daemonprotocolgegevens in de kern te plaatsen.

Stappenplan

1

Package and manifest

{
  "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"
    }
  }
}
Het manifest declareert providerAuthEnvVars zodat OpenClaw referenties kan detecteren zonder je Plugin-runtime te laden. Voeg providerAuthAliases toe wanneer een providervariant de authenticatie van een andere provider-id moet hergebruiken. modelSupport is optioneel en laat OpenClaw je provider-Plugin automatisch laden vanuit verkorte model-id’s zoals acme-large voordat runtime-hooks bestaan. Als je de provider op ClawHub publiceert, zijn die velden openclaw.compat en openclaw.build vereist in package.json.
2

Register the provider

Een minimale provider heeft een id, label, auth en catalog nodig:
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,
                },
              ],
            },
          };
        },
      },
    });
  },
});
Dat is een werkende provider. Gebruikers kunnen nu openclaw onboard --acme-ai-api-key <key> uitvoeren en acme-ai/acme-large als hun model selecteren.Als de upstream-provider andere controletokens gebruikt dan OpenClaw, voeg dan een kleine bidirectionele teksttransformatie toe in plaats van het streampad te vervangen:
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 herschrijft de uiteindelijke systeemprompt en tekstberichtinhoud vóór transport. output herschrijft assistent-tekstdelta’s en definitieve tekst voordat OpenClaw zijn eigen controlemarkeringen of kanaalbezorging parseert.Voor gebundelde providers die slechts één tekstprovider met API-sleutel- authenticatie plus één catalogusgestuurde runtime registreren, geef je de voorkeur aan de smallere helper 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 is het live cataloguspad dat wordt gebruikt wanneer OpenClaw echte providerauthenticatie kan oplossen. Het mag providerspecifieke detectie uitvoeren. Gebruik buildStaticProvider alleen voor offline rijen die veilig kunnen worden getoond voordat authenticatie is geconfigureerd; het mag geen referenties vereisen of netwerkverzoeken doen. De weergave van OpenClaw’s models list --all voert momenteel statische catalogi alleen uit voor gebundelde provider-Plugins, met een lege configuratie, lege env en geen agent-/werkruimtepaden.Als je authenticatiestroom ook models.providers.*, aliassen en het standaardmodel van de agent tijdens onboarding moet patchen, gebruik dan de presethelpers uit openclaw/plugin-sdk/provider-onboard. De smalste helpers zijn createDefaultModelPresetAppliers(...), createDefaultModelsPresetAppliers(...) en createModelCatalogPresetAppliers(...).Wanneer een native endpoint van een provider gestreamde gebruiksblokken ondersteunt op het normale openai-completions-transport, geef dan de voorkeur aan de gedeelde catalogushelpers in openclaw/plugin-sdk/provider-catalog-shared in plaats van provider-id-controles hard te coderen. supportsNativeStreamingUsageCompat(...) en applyProviderNativeStreamingUsageCompat(...) detecteren ondersteuning vanuit de endpoint-capabilitymap, zodat native Moonshot/DashScope-achtige endpoints zich nog steeds aanmelden, zelfs wanneer een Plugin een aangepaste provider-id gebruikt.
3

Add dynamic model resolution

Als je provider willekeurige model-id’s accepteert (zoals een proxy of router), voeg dan resolveDynamicModel toe:
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,
  }),
});
Als oplossen een netwerkoproep vereist, gebruik dan prepareDynamicModel voor asynchrone warm-up — resolveDynamicModel wordt opnieuw uitgevoerd nadat dit is voltooid.
4

Add runtime hooks (as needed)

De meeste providers hebben alleen catalog + resolveDynamicModel nodig. Voeg hooks stapsgewijs toe naarmate je provider ze nodig heeft.Gedeelde helperbouwers dekken nu de meest voorkomende replay-/tool-compat- families, dus Plugins hoeven meestal niet elke hook een voor een handmatig te bedraden:
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,
});
Beschikbare replayfamilies vandaag:
FamilieWat het bedraadtGebundelde voorbeelden
openai-compatibleGedeeld OpenAI-stijl replaybeleid voor OpenAI-compatibele transporten, inclusief tool-call-id-sanering, fixes voor assistant-first-volgorde en generieke Gemini-turnvalidatie waar het transport die nodig heeftmoonshot, ollama, xai, zai
anthropic-by-modelClaude-bewust replaybeleid gekozen door modelId, zodat Anthropic-message-transporten alleen Claude-specifieke thinking-block-opruiming krijgen wanneer het opgeloste model daadwerkelijk een Claude-id isamazon-bedrock, anthropic-vertex
google-geminiNative Gemini-replaybeleid plus bootstrap-replaysanering en gelabelde reasoning-outputmodusgoogle, google-gemini-cli
passthrough-geminiGemini thought-signature-sanering voor Gemini-modellen die via OpenAI-compatibele proxytransporten draaien; schakelt geen native Gemini-replayvalidatie of bootstrapherschrijvingen inopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openaiHybride beleid voor providers die Anthropic-message- en OpenAI-compatibele modeloppervlakken in één Plugin combineren; optioneel Claude-only thinking-block-droppen blijft beperkt tot de Anthropic-kantminimax
Beschikbare streamfamilies vandaag:
FamilieWat het aansluitGebundelde voorbeelden
google-thinkingNormalisatie van Gemini-denkpayloads op het gedeelde streampadgoogle, google-gemini-cli
kilocode-thinkingKilo-redeneerwrapper op het gedeelde proxy-streampad, waarbij kilo/auto en niet-ondersteunde proxy-redeneer-id’s geinjecteerd denken overslaankilocode
moonshot-thinkingMapping van Moonshot binaire native-thinking-payloads vanuit config + /think-niveaumoonshot
minimax-fast-modeMiniMax fast-mode-modelherschrijving op het gedeelde streampadminimax, minimax-portal
openai-responses-defaultsGedeelde native OpenAI/Codex Responses-wrappers: attributieheaders, /fast/serviceTier, tekstuitvoerigheid, native Codex-webzoekfunctie, vormgeving van reasoning-compat-payloads en Responses-contextbeheeropenai, openai-codex
openrouter-thinkingOpenRouter-redeneerwrapper voor proxyroutes, waarbij overslaan van niet-ondersteunde modellen/auto centraal wordt afgehandeldopenrouter
tool-stream-default-onStandaard ingeschakelde tool_stream-wrapper voor providers zoals Z.AI die toolstreaming willen, tenzij expliciet uitgeschakeldzai
Elke familiebouwer is samengesteld uit publieke helpers op lager niveau die vanuit hetzelfde pakket worden geexporteerd; je kunt die gebruiken wanneer een provider van het gemeenschappelijke patroon moet afwijken:
  • openclaw/plugin-sdk/provider-model-sharedProviderReplayFamily, buildProviderReplayFamilyHooks(...) en de ruwe replaybouwers (buildOpenAICompatibleReplayPolicy, buildAnthropicReplayPolicyForModel, buildGoogleGeminiReplayPolicy, buildHybridAnthropicOrOpenAIReplayPolicy). Exporteert ook Gemini-replayhelpers (sanitizeGoogleGeminiReplayHistory, resolveTaggedReasoningOutputMode) en endpoint-/modelhelpers (resolveProviderEndpoint, normalizeProviderId, normalizeGooglePreviewModelId, normalizeNativeXaiModelId).
  • openclaw/plugin-sdk/provider-streamProviderStreamFamily, buildProviderStreamFamilyHooks(...), composeProviderStreamWrappers(...), plus de gedeelde OpenAI/Codex-wrappers (createOpenAIAttributionHeadersWrapper, createOpenAIFastModeWrapper, createOpenAIServiceTierWrapper, createOpenAIResponsesContextManagementWrapper, createCodexNativeWebSearchWrapper), DeepSeek V4 OpenAI-compatibele wrapper (createDeepSeekV4OpenAICompatibleThinkingWrapper), opschoning van Anthropic Messages-denkvoorinvulling (createAnthropicThinkingPrefillPayloadWrapper) en gedeelde proxy-/providerwrappers (createOpenRouterWrapper, createToolStreamWrapper, createMinimaxFastModeWrapper).
  • openclaw/plugin-sdk/provider-toolsProviderToolCompatFamily, buildProviderToolCompatFamilyHooks("gemini"), onderliggende Gemini-schemahelpers (normalizeGeminiToolSchemas, inspectGeminiToolSchemas) en xAI-compathelpers (resolveXaiModelCompatPatch(), applyXaiModelCompat(model)). De gebundelde xAI-Plugin gebruikt normalizeResolvedModel + contributeResolvedModelCompat hiermee om xAI-regels eigendom van de provider te houden.
Sommige streamhelpers blijven bewust provider-lokaal. @openclaw/anthropic-provider houdt wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier en de Anthropic-wrapperbouwers op lager niveau in zijn eigen publieke api.ts / contract-api.ts-seam, omdat ze Claude OAuth-beta-afhandeling en context1m-gating coderen. De xAI-Plugin houdt native vormgeving van xAI Responses eveneens in zijn eigen wrapStreamFn (/fast-aliassen, standaard tool_stream, opschoning van niet-ondersteunde strikte tools, xAI-specifieke verwijdering van redeneerpayloads).Hetzelfde package-rootpatroon ondersteunt ook @openclaw/openai-provider (providerbouwers, helpers voor standaardmodellen, realtime-providerbouwers) en @openclaw/openrouter-provider (providerbouwer plus onboarding-/confighelpers).
Voor providers die voor elke inferentieaanroep een tokenuitwisseling nodig hebben:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw roept hooks in deze volgorde aan. De meeste providers gebruiken er slechts 2-3: Provider-velden die alleen voor compatibiliteit bestaan en die OpenClaw niet meer aanroept, zoals ProviderPlugin.capabilities en suppressBuiltInModel, staan hier niet vermeld.
#HookWanneer te gebruiken
1catalogModelcatalogus of standaardwaarden voor basis-URL
2applyConfigDefaultsProvider-eigen globale standaardwaarden tijdens config-materialisatie
3normalizeModelIdOpschonen van legacy-/preview-model-ID-aliassen voor lookup
4normalizeTransportOpschonen van provider-familie api / baseUrl voor generieke modelassemblage
5normalizeConfigConfig voor models.providers.<id> normaliseren
6applyNativeStreamingUsageCompatCompat-herschrijvingen voor native streaming-gebruik voor config-providers
7resolveConfigApiKeyProvider-eigen auth-resolutie voor env-markers
8resolveSyntheticAuthSynthetische auth voor lokale/self-hosted of config-ondersteunde omgevingen
9shouldDeferSyntheticProfileAuthSynthetische placeholders voor opgeslagen profielen lager prioriteren dan env-/config-auth
10resolveDynamicModelWillekeurige upstream-model-ID’s accepteren
11prepareDynamicModelAsynchrone metadata ophalen voor resolutie
12normalizeResolvedModelTransport-herschrijvingen voor de runner
13contributeResolvedModelCompatCompat-flags voor vendormodellen achter een ander compatibel transport
14normalizeToolSchemasProvider-eigen opschoning van toolschema’s voor registratie
15inspectToolSchemasProvider-eigen diagnostiek voor toolschema’s
16resolveReasoningOutputModeGetagd versus native reasoning-outputcontract
17prepareExtraParamsStandaard aanvraagparameters
18createStreamFnVolledig aangepast StreamFn-transport
19wrapStreamFnAangepaste headers/body-wrappers op het normale streampad
20resolveTransportTurnStateNative headers/metadata per beurt
21resolveWebSocketSessionPolicyNative WS-sessieheaders/cooldown
22formatApiKeyAangepaste runtime-tokenvorm
23refreshOAuthAangepaste OAuth-vernieuwing
24buildAuthDoctorHintRichtlijnen voor auth-herstel
25matchesContextOverflowErrorProvider-eigen overflowdetectie
26classifyFailoverReasonProvider-eigen classificatie van rate-limit/overbelasting
27isCacheTtlEligibleTTL-gating voor promptcache
28buildMissingAuthMessageAangepaste hint voor ontbrekende auth
29augmentModelCatalogSynthetische rijen voor forward compatibility
30resolveThinkingProfileModelspecifieke /think-optieset
31isBinaryThinkingCompatibiliteit voor binair denken aan/uit
32supportsXHighThinkingCompatibiliteit voor xhigh reasoning-ondersteuning
33resolveDefaultThinkingLevelCompatibiliteit voor standaard /think-beleid
34isModernModelRefLive-/smoke-modelmatching
35prepareRuntimeAuthTokenuitwisseling voor inferentie
36resolveUsageAuthAangepaste parsing van gebruiksreferenties
37fetchUsageSnapshotAangepast gebruikseindpunt
38createEmbeddingProviderProvider-eigen embeddingadapter voor geheugen/zoeken
39buildReplayPolicyAangepast beleid voor transcriptherhaling/Compaction
40sanitizeReplayHistoryProvider-specifieke replay-herschrijvingen na generieke opschoning
41validateReplayTurnsStrikte validatie van replay-beurten voor de ingebedde runner
42onModelSelectedCallback na selectie (bijv. telemetrie)
Opmerkingen over runtime-fallback:
  • normalizeConfig controleert eerst de gematchte provider, daarna andere hook-geschikte provider-plugins totdat er een de config daadwerkelijk wijzigt. Als geen provider-hook een ondersteunde Google-familieconfig herschrijft, wordt de gebundelde Google-config-normalizer nog steeds toegepast.
  • resolveConfigApiKey gebruikt de provider-hook wanneer die beschikbaar is. Het gebundelde amazon-bedrock-pad heeft hier ook een ingebouwde AWS env-marker-resolver, ook al gebruikt Bedrock-runtime-auth zelf nog steeds de standaardketen van de AWS SDK.
  • resolveSystemPromptContribution laat een provider cachebewuste system-prompt-richtlijnen injecteren voor een modelfamilie. Gebruik dit bij voorkeur boven before_prompt_build wanneer het gedrag bij een provider-/modelfamilie hoort en de stabiele/dynamische cache-splitsing moet behouden.
Zie Internals: Provider Runtime Hooks voor gedetailleerde beschrijvingen en praktijkvoorbeelden.
5

Add extra capabilities (optional)

Een provider-plugin kan spraak, realtime transcriptie, realtime stem, media-inzicht, afbeeldingsgeneratie, videogeneratie, web-fetch, en webzoekopdrachten registreren naast tekstinferentie. OpenClaw classificeert dit als een hybrid-capability-plugin — het aanbevolen patroon voor bedrijfsplugins (één plugin per vendor). Zie Internals: Capability Ownership.Registreer elke capability binnen register(api) naast je bestaande api.registerProvider(...)-aanroep. Kies alleen de tabbladen die je nodig hebt:
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();
    }
  },
});
Gebruik assertOkOrThrowProviderError(...) voor HTTP-fouten van providers zodat plugins gedeelde begrensde reads van fout-bodies, JSON-foutparsing en request-id-achtervoegsels gebruiken.
6

Test

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

Publiceren naar ClawHub

Provider-plugins publiceert u op dezelfde manier als elke andere externe code-Plugin:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
Gebruik hier niet de verouderde alias voor alleen skills; Plugin-pakketten moeten clawhub package publish gebruiken.

Bestandsstructuur

<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)

Referentie voor catalogusvolgorde

catalog.order bepaalt wanneer je catalogus wordt samengevoegd ten opzichte van ingebouwde providers:
VolgordeWanneerGebruikssituatie
simpleEerste passGewone API-key-providers
profileNa simpleProviders die afhankelijk zijn van auth-profielen
pairedNa profileMeerdere gerelateerde entries synthetiseren
lateLaatste passBestaande providers overschrijven (wint bij botsing)

Volgende stappen

Gerelateerd