Vai al contenuto principale

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.

Questa guida illustra come creare un provider Plugin che aggiunge un provider di modelli (LLM) a OpenClaw. Alla fine avrai un provider con un catalogo di modelli, autenticazione con chiave API e risoluzione dinamica dei modelli.
Se non hai mai creato alcun OpenClaw Plugin prima, leggi prima Guida introduttiva per la struttura di base del pacchetto e la configurazione del manifest.
I provider Plugin aggiungono modelli al normale ciclo di inferenza di OpenClaw. Se il modello deve essere eseguito tramite un demone agent nativo che possiede thread, compaction o eventi degli strumenti, abbina il provider a un agent harness invece di inserire i dettagli del protocollo del demone nel core.

Procedura guidata

1

Package and manifest

Passaggio 1: Pacchetto e 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"
    }
  }
}
Il manifest dichiara providerAuthEnvVars in modo che OpenClaw possa rilevare le credenziali senza caricare il runtime del tuo Plugin. Aggiungi providerAuthAliases quando una variante del provider deve riutilizzare l’autenticazione dell’id di un altro provider. modelSupport è facoltativo e consente a OpenClaw di caricare automaticamente il tuo provider Plugin dagli id modello abbreviati come acme-large prima che esistano hook runtime. Se pubblichi il provider su ClawHub, quei campi openclaw.compat e openclaw.build sono obbligatori in package.json.
2

Register the provider

Un provider di testo minimale richiede id, label, auth e catalog. catalog è l’hook runtime/config di proprietà del provider; può chiamare API live del vendor e restituisce voci 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 è la superficie di catalogo control-plane più recente per UI di elenco/aiuto/selettore. Usala per righe di testo, generazione di immagini, generazione di video e generazione di musica. Mantieni le chiamate agli endpoint del vendor e il mapping delle risposte nel Plugin; OpenClaw possiede la forma condivisa delle righe, le etichette di origine e il rendering dell’aiuto.Questo è un provider funzionante. Gli utenti ora possono openclaw onboard --acme-ai-api-key <key> e selezionare acme-ai/acme-large come loro modello.Se il provider upstream usa token di controllo diversi da OpenClaw, aggiungi una piccola trasformazione testuale bidirezionale invece di sostituire il percorso dello stream:
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 riscrive il prompt di sistema finale e il contenuto dei messaggi di testo prima del trasporto. output riscrive i delta di testo dell’assistant e il testo finale prima che OpenClaw analizzi i propri marcatori di controllo o la consegna al canale.Per i provider integrati che registrano un solo provider di testo con autenticazione tramite chiave API più un singolo runtime basato su catalogo, preferisci l’helper più ristretto 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 è il percorso del catalogo live usato quando OpenClaw può risolvere l’autenticazione reale del provider. Può eseguire discovery specifica del provider. Usa buildStaticProvider solo per righe offline che è sicuro mostrare prima che l’autenticazione sia configurata; non deve richiedere credenziali né effettuare richieste di rete. La visualizzazione models list --all di OpenClaw attualmente esegue cataloghi statici solo per provider Plugin integrati, con una config vuota, env vuoto e nessun percorso agent/workspace.Se il tuo flusso di autenticazione deve anche aggiornare models.providers.*, alias e il modello predefinito dell’agent durante l’onboarding, usa gli helper preset da openclaw/plugin-sdk/provider-onboard. Gli helper più ristretti sono createDefaultModelPresetAppliers(...), createDefaultModelsPresetAppliers(...) e createModelCatalogPresetAppliers(...).Quando l’endpoint nativo di un provider supporta blocchi di usage in streaming sul normale trasporto openai-completions, preferisci gli helper di catalogo condivisi in openclaw/plugin-sdk/provider-catalog-shared invece di codificare controlli sugli id provider. supportsNativeStreamingUsageCompat(...) e applyProviderNativeStreamingUsageCompat(...) rilevano il supporto dalla mappa delle capacità dell’endpoint, quindi gli endpoint nativi in stile Moonshot/DashScope aderiscono comunque anche quando un Plugin usa un id provider personalizzato.
3

Add dynamic model resolution

Se il tuo provider accetta ID modello arbitrari (come un proxy o un router), aggiungi 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,
  }),
});
Se la risoluzione richiede una chiamata di rete, usa prepareDynamicModel per il warm-up asincrono - resolveDynamicModel viene eseguito di nuovo al completamento.
4

Add runtime hooks (as needed)

La maggior parte dei provider richiede solo catalog + resolveDynamicModel. Aggiungi hook in modo incrementale man mano che il tuo provider li richiede.I builder helper condivisi ora coprono le famiglie replay/tool-compat più comuni, quindi i Plugin di solito non devono collegare manualmente ogni hook uno per uno:
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,
});
Famiglie replay disponibili oggi:
FamigliaCosa collegaEsempi inclusi
openai-compatiblePolicy di replay condivisa in stile OpenAI per trasporti compatibili con OpenAI, inclusa la sanitizzazione degli ID di chiamata strumento, correzioni dell’ordinamento con assistant per primo e validazione generica dei turni Gemini dove il trasporto ne ha bisognomoonshot, ollama, xai, zai
anthropic-by-modelPolicy di replay consapevole di Claude scelta da modelId, così i trasporti con messaggi Anthropic ricevono la pulizia dei blocchi di pensiero specifica di Claude solo quando il modello risolto è effettivamente un ID Claudeamazon-bedrock, anthropic-vertex
google-geminiPolicy di replay Gemini nativa più sanitizzazione del replay di bootstrap e modalità di output di ragionamento con taggoogle, google-gemini-cli
passthrough-geminiSanitizzazione delle firme di pensiero Gemini per modelli Gemini eseguiti tramite trasporti proxy compatibili con OpenAI; non abilita la validazione del replay Gemini nativa né le riscritture di bootstrapopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openaiPolicy ibrida per provider che combinano superfici di modello con messaggi Anthropic e compatibili con OpenAI in un unico plugin; l’eliminazione opzionale dei blocchi di pensiero solo per Claude resta limitata al lato Anthropicminimax
Famiglie di stream disponibili oggi:
FamigliaCosa collegaEsempi inclusi
google-thinkingNormalizzazione dei payload di pensiero Gemini sul percorso di stream condivisogoogle, google-gemini-cli
kilocode-thinkingWrapper di ragionamento Kilo sul percorso di stream proxy condiviso, con kilo/auto e ID di ragionamento proxy non supportati che saltano il pensiero iniettatokilocode
moonshot-thinkingMappatura del payload di pensiero nativo binario Moonshot dalla configurazione + livello /thinkmoonshot
minimax-fast-modeRiscrittura del modello in modalità rapida MiniMax sul percorso di stream condivisominimax, minimax-portal
openai-responses-defaultsWrapper Responses nativi condivisi OpenAI/Codex: intestazioni di attribuzione, /fast/serviceTier, verbosità del testo, ricerca web nativa Codex, modellazione del payload compatibile con il ragionamento e gestione del contesto Responsesopenai, openai-codex
openrouter-thinkingWrapper di ragionamento OpenRouter per rotte proxy, con salti per modelli non supportati/auto gestiti centralmenteopenrouter
tool-stream-default-onWrapper tool_stream abilitato di default per provider come Z.AI che vogliono lo streaming degli strumenti salvo disabilitazione esplicitazai
Ogni costruttore di famiglia è composto da helper pubblici di livello inferiore esportati dallo stesso pacchetto, a cui puoi ricorrere quando un provider deve discostarsi dal pattern comune:
  • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamily, buildProviderReplayFamilyHooks(...) e i costruttori di replay grezzi (buildOpenAICompatibleReplayPolicy, buildAnthropicReplayPolicyForModel, buildGoogleGeminiReplayPolicy, buildHybridAnthropicOrOpenAIReplayPolicy). Esporta anche helper di replay Gemini (sanitizeGoogleGeminiReplayHistory, resolveTaggedReasoningOutputMode) e helper per endpoint/modelli (resolveProviderEndpoint, normalizeProviderId, normalizeGooglePreviewModelId).
  • openclaw/plugin-sdk/provider-stream - ProviderStreamFamily, buildProviderStreamFamilyHooks(...), composeProviderStreamWrappers(...), più i wrapper OpenAI/Codex condivisi (createOpenAIAttributionHeadersWrapper, createOpenAIFastModeWrapper, createOpenAIServiceTierWrapper, createOpenAIResponsesContextManagementWrapper, createCodexNativeWebSearchWrapper), il wrapper compatibile con OpenAI DeepSeek V4 (createDeepSeekV4OpenAICompatibleThinkingWrapper), la pulizia del prefill di pensiero Anthropic Messages (createAnthropicThinkingPrefillPayloadWrapper) e i wrapper proxy/provider condivisi (createOpenRouterWrapper, createToolStreamWrapper, createMinimaxFastModeWrapper).
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamily, buildProviderToolCompatFamilyHooks("gemini") e gli helper di schema Gemini sottostanti (normalizeGeminiToolSchemas, inspectGeminiToolSchemas).
Alcuni helper di stream restano intenzionalmente locali al provider. @openclaw/anthropic-provider mantiene wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier e i costruttori di wrapper Anthropic di livello inferiore nel proprio seam pubblico api.ts / contract-api.ts, perché codificano la gestione beta OAuth Claude e il gating context1m. Il plugin xAI mantiene in modo analogo la modellazione nativa xAI Responses nel proprio wrapStreamFn (alias /fast, tool_stream predefinito, pulizia degli strumenti strict non supportati, rimozione del payload di ragionamento specifica di xAI).Lo stesso pattern alla radice del pacchetto supporta anche @openclaw/openai-provider (costruttori di provider, helper per modelli predefiniti, costruttori di provider realtime) e @openclaw/openrouter-provider (costruttore di provider più helper di onboarding/configurazione).
Per i provider che richiedono uno scambio di token prima di ogni chiamata di inferenza:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw chiama gli hook in questo ordine. La maggior parte dei provider ne usa solo 2-3: i campi provider solo per compatibilità che OpenClaw non chiama più, come ProviderPlugin.capabilities e suppressBuiltInModel, non sono elencati qui.
#HookQuando usarlo
1catalogCatalogo dei modelli o valori predefiniti dell’URL di base
2applyConfigDefaultsValori predefiniti globali di proprietà del provider durante la materializzazione della configurazione
3normalizeModelIdPulizia di alias legacy/anteprima degli ID modello prima della ricerca
4normalizeTransportPulizia di api / baseUrl della famiglia provider prima dell’assemblaggio generico del modello
5normalizeConfigNormalizza la configurazione models.providers.<id>
6applyNativeStreamingUsageCompatRiscritture di compatibilità dell’utilizzo streaming nativo per provider di configurazione
7resolveConfigApiKeyRisoluzione dell’autenticazione tramite marker env di proprietà del provider
8resolveSyntheticAuthAutenticazione sintetica locale/self-hosted o basata su configurazione
9shouldDeferSyntheticProfileAuthAbbassa la priorità dei placeholder sintetici dei profili salvati rispetto all’autenticazione env/config
10resolveDynamicModelAccetta ID modello upstream arbitrari
11prepareDynamicModelRecupero asincrono dei metadati prima della risoluzione
12normalizeResolvedModelRiscritture del trasporto prima del runner
13contributeResolvedModelCompatFlag di compatibilità per modelli vendor dietro un altro trasporto compatibile
14normalizeToolSchemasPulizia degli schemi degli strumenti di proprietà del provider prima della registrazione
15inspectToolSchemasDiagnostica degli schemi degli strumenti di proprietà del provider
16resolveReasoningOutputModeContratto dell’output di ragionamento con tag vs nativo
17prepareExtraParamsParametri di richiesta predefiniti
18createStreamFnTrasporto StreamFn completamente personalizzato
19wrapStreamFnWrapper personalizzati per intestazioni/corpo sul normale percorso di stream
20resolveTransportTurnStateIntestazioni/metadati nativi per turno
21resolveWebSocketSessionPolicyIntestazioni/cool-down della sessione WS nativi
22formatApiKeyForma personalizzata del token runtime
23refreshOAuthRefresh OAuth personalizzato
24buildAuthDoctorHintIndicazioni per la riparazione dell’autenticazione
25matchesContextOverflowErrorRilevamento dell’overflow di proprietà del provider
26classifyFailoverReasonClassificazione di rate limit/sovraccarico di proprietà del provider
27isCacheTtlEligibleGating del TTL della cache del prompt
28buildMissingAuthMessageSuggerimento personalizzato per autenticazione mancante
29augmentModelCatalogRighe sintetiche per compatibilità futura
30resolveThinkingProfileSet di opzioni /think specifico del modello
31isBinaryThinkingCompatibilità pensiero binario on/off
32supportsXHighThinkingCompatibilità del supporto di ragionamento xhigh
33resolveDefaultThinkingLevelCompatibilità della policy /think predefinita
34isModernModelRefCorrispondenza dei modelli live/smoke
35prepareRuntimeAuthScambio di token prima dell’inferenza
36resolveUsageAuthParsing personalizzato delle credenziali di utilizzo
37fetchUsageSnapshotEndpoint di utilizzo personalizzato
38createEmbeddingProviderAdattatore embedding di proprietà del provider per memoria/ricerca
39buildReplayPolicyPolicy personalizzata di replay/Compaction della trascrizione
40sanitizeReplayHistoryRiscritture di replay specifiche del provider dopo la pulizia generica
41validateReplayTurnsValidazione rigorosa dei turni di replay prima del runner incorporato
42onModelSelectedCallback post-selezione (ad es. telemetria)
Note sul fallback runtime:
  • normalizeConfig controlla prima il provider corrispondente, poi altri plugin provider con hook finché uno non modifica effettivamente la configurazione. Se nessun hook provider riscrive una voce di configurazione supportata della famiglia Google, viene comunque applicato il normalizzatore di configurazione Google incluso.
  • resolveConfigApiKey usa l’hook provider quando esposto. Anche il percorso amazon-bedrock incluso ha qui un resolver integrato per marker env AWS, anche se l’autenticazione runtime di Bedrock continua a usare la catena predefinita dell’SDK AWS.
  • resolveSystemPromptContribution consente a un provider di iniettare indicazioni per il prompt di sistema consapevoli della cache per una famiglia di modelli. Preferiscilo a before_prompt_build quando il comportamento appartiene a una famiglia provider/modello e dovrebbe preservare la separazione stabile/dinamica della cache.
Per descrizioni dettagliate ed esempi reali, vedi Interni: hook runtime provider.
5

Aggiungi funzionalità extra (opzionale)

Passaggio 5: Aggiungi funzionalità extra

Un plugin provider può registrare speech, trascrizione realtime, voce realtime, comprensione dei media, generazione di immagini, generazione di video, web fetch e web search insieme all’inferenza testuale. OpenClaw lo classifica come plugin con capacità ibride: il pattern consigliato per i plugin aziendali (un plugin per vendor). Vedi Internals: Proprietà delle capacità.Registra ogni capacità dentro register(api) insieme alla tua chiamata api.registerProvider(...) esistente. Scegli solo le schede di cui hai bisogno:
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();
    }
  },
});
Usa assertOkOrThrowProviderError(...) per gli errori HTTP del provider, così i plugin condividono letture limitate del corpo dell’errore, parsing degli errori JSON e suffissi degli ID richiesta.
6

Test

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

Pubblicare su ClawHub

I plugin provider si pubblicano nello stesso modo di qualsiasi altro plugin di codice esterno:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
Non usare qui l’alias di pubblicazione legacy solo per skill; i pacchetti plugin dovrebbero usare clawhub package publish.

Struttura dei file

<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 controlla quando il tuo catalogo viene unito rispetto ai provider integrati:
OrdineQuandoCaso d’uso
simplePrimo passaggioProvider con semplice chiave API
profileDopo simpleProvider vincolati ai profili di autenticazione
pairedDopo profileSintetizzare più voci correlate
lateUltimo passaggioSovrascrivere provider esistenti (vince in caso di collisione)

Passaggi successivi

Correlati