Zum Hauptinhalt springen

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.

Diese Anleitung führt Sie durch das Erstellen eines Provider-Plugins, das OpenClaw einen Modell-Provider (LLM) hinzufügt. Am Ende verfügen Sie über einen Provider mit einem Modellkatalog, API-Schlüssel-Authentifizierung und dynamischer Modellauflösung.
Wenn Sie noch kein OpenClaw-Plugin erstellt haben, lesen Sie zuerst Erste Schritte für die grundlegende Paketstruktur und Manifest-Einrichtung.
Provider-Plugins fügen Modelle zur normalen Inferenzschleife von OpenClaw hinzu. Wenn das Modell über einen nativen Agent-Daemon ausgeführt werden muss, der Threads, Compaction oder Tool- Ereignisse besitzt, kombinieren Sie den Provider mit einem Agent-Harness, anstatt Daemon-Protokolldetails in den Kern zu legen.

Exemplarische Anleitung

1

Paket und Manifest

Schritt 1: Paket und 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"
    }
  }
}
Das Manifest deklariert providerAuthEnvVars, damit OpenClaw Zugangsdaten erkennen kann, ohne die Runtime Ihres Plugins zu laden. Fügen Sie providerAuthAliases hinzu, wenn eine Provider-Variante die Authentifizierung einer anderen Provider-ID wiederverwenden soll. modelSupport ist optional und ermöglicht OpenClaw, Ihr Provider-Plugin aus Kurzform- Modell-IDs wie acme-large automatisch zu laden, bevor Runtime-Hooks vorhanden sind. Wenn Sie den Provider auf ClawHub veröffentlichen, sind diese Felder openclaw.compat und openclaw.build in package.json erforderlich.
2

Provider registrieren

Ein minimaler Text-Provider benötigt eine id, ein label, auth und catalog. catalog ist der providerseitige Runtime-/Konfigurations-Hook; er kann Live- Hersteller-APIs aufrufen und gibt models.providers-Einträge zurück.
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 ist die neuere Control-Plane-Katalogoberfläche für Listen-, Hilfe- und Auswahl-UI. Verwenden Sie sie für Zeilen zu Text, Bilderzeugung, Videoerzeugung und Musikerzeugung. Belassen Sie Hersteller-Endpunktaufrufe und Antwortzuordnung im Plugin; OpenClaw besitzt die gemeinsame Zeilenform, Quell- Labels und Hilfe-Rendering.Damit ist ein funktionsfähiger Provider vorhanden. Benutzer können nun openclaw onboard --acme-ai-api-key <key> ausführen und acme-ai/acme-large als Modell auswählen.Wenn der vorgelagerte Provider andere Steuerungstokens als OpenClaw verwendet, fügen Sie eine kleine bidirektionale Texttransformation hinzu, anstatt den Stream-Pfad zu ersetzen:
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 schreibt den endgültigen System-Prompt und den Inhalt von Textnachrichten vor dem Transport um. output schreibt Assistenten-Text-Deltas und den endgültigen Text um, bevor OpenClaw seine eigenen Steuerungsmarker oder die Kanalauslieferung parst.Für gebündelte Provider, die nur einen Text-Provider mit API-Schlüssel- Authentifizierung sowie einer einzelnen kataloggestützten Runtime registrieren, verwenden Sie bevorzugt den enger gefassten 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 ist der Live-Katalogpfad, der verwendet wird, wenn OpenClaw echte Provider-Authentifizierung auflösen kann. Er kann providerspezifische Erkennung durchführen. Verwenden Sie buildStaticProvider nur für Offline-Zeilen, die vor der Konfiguration der Authentifizierung sicher angezeigt werden können; er darf keine Zugangsdaten erfordern und keine Netzwerkanfragen stellen. Die Anzeige models list --all von OpenClaw führt statische Kataloge derzeit nur für gebündelte Provider-Plugins aus, mit leerer Konfiguration, leerer Umgebung und ohne Agent-/Workspace-Pfade.Wenn Ihr Authentifizierungsablauf außerdem models.providers.*, Aliasse und das Standardmodell des Agents während des Onboardings patchen muss, verwenden Sie die Preset-Helper aus openclaw/plugin-sdk/provider-onboard. Die engsten Helper sind createDefaultModelPresetAppliers(...), createDefaultModelsPresetAppliers(...) und createModelCatalogPresetAppliers(...).Wenn ein nativer Endpunkt eines Providers gestreamte Nutzungsblöcke über den normalen openai-completions-Transport unterstützt, verwenden Sie bevorzugt die gemeinsamen Katalog-Helper in openclaw/plugin-sdk/provider-catalog-shared, anstatt Provider-ID-Prüfungen fest zu codieren. supportsNativeStreamingUsageCompat(...) und applyProviderNativeStreamingUsageCompat(...) erkennen Unterstützung anhand der Endpunkt-Capability-Map, sodass native Endpunkte im Moonshot-/DashScope-Stil weiterhin opt-in verwenden, selbst wenn ein Plugin eine benutzerdefinierte Provider-ID nutzt.
3

Dynamische Modellauflösung hinzufügen

Wenn Ihr Provider beliebige Modell-IDs akzeptiert (wie ein Proxy oder Router), fügen Sie resolveDynamicModel hinzu:
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,
  }),
});
Wenn die Auflösung einen Netzwerkaufruf erfordert, verwenden Sie prepareDynamicModel für asynchrone Vorbereitung - resolveDynamicModel wird nach Abschluss erneut ausgeführt.
4

Runtime-Hooks hinzufügen (bei Bedarf)

Die meisten Provider benötigen nur catalog + resolveDynamicModel. Fügen Sie Hooks schrittweise hinzu, wenn Ihr Provider sie benötigt.Gemeinsame Helper-Builder decken inzwischen die häufigsten Replay-/Tool-Kompatibilitäts- Familien ab, sodass Plugins normalerweise nicht jeden Hook einzeln verdrahten müssen:
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,
});
Heute verfügbare Replay-Familien:
FamilieWas sie einbindetMitgelieferte Beispiele
openai-compatibleGemeinsame OpenAI-artige Replay-Policy für OpenAI-kompatible Transporte, einschließlich Bereinigung von Tool-Call-IDs, Korrekturen für Assistant-First-Reihenfolge und generischer Gemini-Turn-Validierung, wo der Transport sie benötigtmoonshot, ollama, xai, zai
anthropic-by-modelClaude-bewusste Replay-Policy, ausgewählt per modelId, sodass Anthropic-Message-Transporte Claude-spezifische Thinking-Block-Bereinigung nur erhalten, wenn das aufgelöste Modell tatsächlich eine Claude-ID istamazon-bedrock, anthropic-vertex
google-geminiNative Gemini-Replay-Policy plus Bootstrap-Replay-Bereinigung und Modus für getaggte Reasoning-Ausgabegoogle, google-gemini-cli
passthrough-geminiGemini-Thought-Signature-Bereinigung für Gemini-Modelle, die über OpenAI-kompatible Proxy-Transporte laufen; aktiviert keine native Gemini-Replay-Validierung oder Bootstrap-Neuschreibungenopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openaiHybride Policy für Provider, die Anthropic-Message- und OpenAI-kompatible Modelloberflächen in einem Plugin mischen; optionales Entfernen von Thinking-Blocks nur für Claude bleibt auf die Anthropic-Seite beschränktminimax
Heute verfügbare Stream-Familien:
FamilieWas sie einbindetMitgelieferte Beispiele
google-thinkingNormalisierung von Gemini-Thinking-Payloads im gemeinsamen Stream-Pfadgoogle, google-gemini-cli
kilocode-thinkingKilo-Reasoning-Wrapper im gemeinsamen Proxy-Stream-Pfad, wobei kilo/auto und nicht unterstützte Proxy-Reasoning-IDs injiziertes Thinking überspringenkilocode
moonshot-thinkingZuordnung nativer Moonshot-Binary-Thinking-Payloads aus Konfiguration + /think-Stufemoonshot
minimax-fast-modeMiniMax-Fast-Mode-Modellumschreibung im gemeinsamen Stream-Pfadminimax, minimax-portal
openai-responses-defaultsGemeinsame native OpenAI/Codex-Responses-Wrapper: Attributions-Header, /fast/serviceTier, Text-Ausführlichkeit, native Codex-Websuche, Reasoning-kompatible Payload-Formung und Responses-Kontextverwaltungopenai, openai-codex
openrouter-thinkingOpenRouter-Reasoning-Wrapper für Proxy-Routen, wobei Überspringen bei nicht unterstützten Modellen/auto zentral gehandhabt wirdopenrouter
tool-stream-default-onStandardmäßig aktivierter tool_stream-Wrapper für Provider wie Z.AI, die Tool-Streaming wünschen, sofern es nicht explizit deaktiviert istzai
Jeder Family Builder besteht aus öffentlichen Low-Level-Helfern, die aus demselben Paket exportiert werden und auf die Sie zurückgreifen können, wenn ein Provider vom gemeinsamen Muster abweichen muss:
  • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamily, buildProviderReplayFamilyHooks(...) und die rohen Replay-Builder (buildOpenAICompatibleReplayPolicy, buildAnthropicReplayPolicyForModel, buildGoogleGeminiReplayPolicy, buildHybridAnthropicOrOpenAIReplayPolicy). Exportiert außerdem Gemini-Replay-Helfer (sanitizeGoogleGeminiReplayHistory, resolveTaggedReasoningOutputMode) und Endpunkt-/Modell-Helfer (resolveProviderEndpoint, normalizeProviderId, normalizeGooglePreviewModelId).
  • openclaw/plugin-sdk/provider-stream - ProviderStreamFamily, buildProviderStreamFamilyHooks(...), composeProviderStreamWrappers(...) sowie die gemeinsamen OpenAI/Codex-Wrapper (createOpenAIAttributionHeadersWrapper, createOpenAIFastModeWrapper, createOpenAIServiceTierWrapper, createOpenAIResponsesContextManagementWrapper, createCodexNativeWebSearchWrapper), DeepSeek-V4-OpenAI-kompatibler Wrapper (createDeepSeekV4OpenAICompatibleThinkingWrapper), Anthropic-Messages-Thinking-Prefill-Bereinigung (createAnthropicThinkingPrefillPayloadWrapper) und gemeinsame Proxy-/Provider-Wrapper (createOpenRouterWrapper, createToolStreamWrapper, createMinimaxFastModeWrapper).
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamily, buildProviderToolCompatFamilyHooks("gemini") und zugrunde liegende Gemini-Schema-Helfer (normalizeGeminiToolSchemas, inspectGeminiToolSchemas).
Einige Stream-Helfer bleiben absichtlich providerlokal. @openclaw/anthropic-provider behält wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier und die Low-Level-Anthropic-Wrapper-Builder in seinem eigenen öffentlichen api.ts-/contract-api.ts-Seam, weil sie Claude-OAuth-Beta-Behandlung und context1m-Gating kodieren. Das xAI-Plugin behält ähnlich die native xAI-Responses-Formung in seinem eigenen wrapStreamFn (/fast-Aliasse, Standard-tool_stream, Bereinigung nicht unterstützter Strict-Tools, xAI-spezifisches Entfernen von Reasoning-Payloads).Dasselbe Package-Root-Muster stützt auch @openclaw/openai-provider (Provider-Builder, Default-Model-Helfer, Realtime-Provider-Builder) und @openclaw/openrouter-provider (Provider-Builder plus Onboarding-/Konfigurationshelfer).
Für Provider, die vor jedem Inferenzaufruf einen Token-Austausch benötigen:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw ruft Hooks in dieser Reihenfolge auf. Die meisten Provider verwenden nur 2-3: Nur der Kompatibilität dienende Provider-Felder, die OpenClaw nicht mehr aufruft, wie ProviderPlugin.capabilities und suppressBuiltInModel, sind hier nicht aufgeführt.
#HookWann verwenden
1catalogModellkatalog oder Standardwerte für die Basis-URL
2applyConfigDefaultsProvider-eigene globale Standardwerte während der Konfigurationsmaterialisierung
3normalizeModelIdBereinigung von Aliasen für Legacy-/Preview-Modell-IDs vor dem Lookup
4normalizeTransportBereinigung von api / baseUrl der Provider-Familie vor der generischen Modellassemblierung
5normalizeConfigmodels.providers.<id>-Konfiguration normalisieren
6applyNativeStreamingUsageCompatKompatibilitäts-Umschreibungen für native Streaming-Nutzung bei Konfigurations-Providern
7resolveConfigApiKeyProvider-eigene Authentifizierungsauflösung für Env-Marker
8resolveSyntheticAuthLokale/selbst gehostete oder konfigurationsgestützte synthetische Authentifizierung
9shouldDeferSyntheticProfileAuthSynthetische Platzhalter für gespeicherte Profile hinter Env-/Konfigurationsauthentifizierung zurückstufen
10resolveDynamicModelBeliebige Upstream-Modell-IDs akzeptieren
11prepareDynamicModelAsynchroner Metadatenabruf vor der Auflösung
12normalizeResolvedModelTransport-Umschreibungen vor dem Runner
13contributeResolvedModelCompatKompatibilitäts-Flags für Vendor-Modelle hinter einem anderen kompatiblen Transport
14normalizeToolSchemasProvider-eigene Bereinigung von Tool-Schemata vor der Registrierung
15inspectToolSchemasProvider-eigene Diagnosen für Tool-Schemata
16resolveReasoningOutputModeVertrag für getaggte vs. native Reasoning-Ausgabe
17prepareExtraParamsStandard-Anfrageparameter
18createStreamFnVollständig benutzerdefinierter StreamFn-Transport
19wrapStreamFnBenutzerdefinierte Header-/Body-Wrapper auf dem normalen Stream-Pfad
20resolveTransportTurnStateNative Header/Metadaten pro Turn
21resolveWebSocketSessionPolicyNative WS-Sitzungs-Header/Cool-down
22formatApiKeyBenutzerdefinierte Runtime-Token-Form
23refreshOAuthBenutzerdefinierte OAuth-Aktualisierung
24buildAuthDoctorHintAnleitung zur Authentifizierungsreparatur
25matchesContextOverflowErrorProvider-eigene Overflow-Erkennung
26classifyFailoverReasonProvider-eigene Klassifizierung von Rate-Limits/Überlastung
27isCacheTtlEligiblePrompt-Cache-TTL-Gating
28buildMissingAuthMessageBenutzerdefinierter Hinweis bei fehlender Authentifizierung
29augmentModelCatalogSynthetische Forward-Compat-Zeilen
30resolveThinkingProfileModellspezifisches /think-Optionsset
31isBinaryThinkingBinäre Thinking-Ein/Aus-Kompatibilität
32supportsXHighThinkingKompatibilität für xhigh-Reasoning-Unterstützung
33resolveDefaultThinkingLevelKompatibilität der Standard-/think-Richtlinie
34isModernModelRefLive-/Smoke-Modellabgleich
35prepareRuntimeAuthToken-Austausch vor der Inferenz
36resolveUsageAuthBenutzerdefiniertes Parsen von Nutzungsanmeldedaten
37fetchUsageSnapshotBenutzerdefinierter Nutzungs-Endpunkt
38createEmbeddingProviderProvider-eigener Embedding-Adapter für Speicher/Suche
39buildReplayPolicyBenutzerdefinierte Richtlinie für Transcript-Replay/Compaction
40sanitizeReplayHistoryProvider-spezifische Replay-Umschreibungen nach generischer Bereinigung
41validateReplayTurnsStrikte Replay-Turn-Validierung vor dem eingebetteten Runner
42onModelSelectedCallback nach der Auswahl (z. B. Telemetrie)
Hinweise zu Runtime-Fallbacks:
  • normalizeConfig prüft zuerst den passenden Provider und dann andere hook-fähige Provider-Plugins, bis eines die Konfiguration tatsächlich ändert. Wenn kein Provider-Hook einen unterstützten Google-Family-Konfigurationseintrag umschreibt, greift weiterhin der gebündelte Google-Konfigurationsnormalisierer.
  • resolveConfigApiKey verwendet den Provider-Hook, wenn er bereitgestellt wird. Der gebündelte amazon-bedrock-Pfad hat hier außerdem einen integrierten AWS-Env-Marker-Resolver, obwohl die Bedrock-Runtime-Authentifizierung selbst weiterhin die Standardkette des AWS SDK verwendet.
  • resolveSystemPromptContribution ermöglicht einem Provider, cache-bewusste System-Prompt-Anleitung für eine Modellfamilie einzuschleusen. Bevorzugen Sie dies gegenüber before_prompt_build, wenn das Verhalten zu einem Provider/einer Modellfamilie gehört und die stabile/dynamische Cache-Aufteilung erhalten soll.
Detaillierte Beschreibungen und Beispiele aus der Praxis finden Sie unter Interna: Provider-Runtime-Hooks.
5

Add extra capabilities (optional)

Schritt 5: Zusätzliche Fähigkeiten hinzufügen

Ein Provider-Plugin kann Sprachausgabe, Echtzeittranskription, Echtzeit-Voice, Medienverständnis, Bildgenerierung, Videogenerierung, Web-Abruf und Websuche neben Textinferenz registrieren. OpenClaw klassifiziert dies als Hybrid-Capability-Plugin - das empfohlene Muster für Unternehmens-Plugins (ein Plugin pro Anbieter). Siehe Interna: Capability-Zuständigkeit.Registrieren Sie jede Capability in register(api) neben Ihrem bestehenden api.registerProvider(...)-Aufruf. Wählen Sie nur die Tabs aus, die Sie benötigen:
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();
    }
  },
});
Verwenden Sie assertOkOrThrowProviderError(...) für HTTP-Fehler von Providern, damit Plugins begrenzte Fehlertext-Lesevorgänge, JSON-Fehleranalyse und Request-ID-Suffixe gemeinsam nutzen.
6

Testen

Schritt 6: Testen

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

In ClawHub veröffentlichen

Provider-Plugins werden genauso veröffentlicht wie jedes andere externe Code-Plugin:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
Verwenden Sie hier nicht den alten Alias nur für Skills; Plugin-Pakete sollten clawhub package publish verwenden.

Dateistruktur

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

Referenz zur Katalogreihenfolge

catalog.order steuert, wann Ihr Katalog relativ zu integrierten Providern zusammengeführt wird:
ReihenfolgeZeitpunktAnwendungsfall
simpleErster DurchlaufEinfache API-Key-Provider
profileNach simpleProvider, die durch Auth-Profile gesteuert sind
pairedNach profileMehrere verwandte Einträge synthetisieren
lateLetzter DurchlaufBestehende Provider überschreiben (gewinnt bei Kollision)

Nächste Schritte

Verwandt