Przejdź do głównej treści

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.

Ten przewodnik prowadzi przez tworzenie pluginu dostawcy, który dodaje dostawcę modelu (LLM) do OpenClaw. Na końcu będziesz mieć dostawcę z katalogiem modeli, uwierzytelnianiem kluczem API oraz dynamicznym rozwiązywaniem modeli.
Jeśli nie tworzono wcześniej żadnego pluginu OpenClaw, najpierw przeczytaj Pierwsze kroki, aby poznać podstawową strukturę pakietu i konfigurację manifestu.
Pluginy dostawców dodają modele do standardowej pętli inferencji OpenClaw. Jeśli model musi działać przez natywnego demona agenta, który zarządza wątkami, kompaktowaniem lub zdarzeniami narzędzi, połącz dostawcę z uprzężą agenta zamiast umieszczać szczegóły protokołu demona w core.

Przewodnik

1

Pakiet i manifest

Krok 1: Pakiet i 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"
    }
  }
}
Manifest deklaruje providerAuthEnvVars, dzięki czemu OpenClaw może wykrywać poświadczenia bez ładowania runtime pluginu. Dodaj providerAuthAliases, gdy wariant dostawcy powinien ponownie używać uwierzytelniania innego identyfikatora dostawcy. modelSupport jest opcjonalne i pozwala OpenClaw automatycznie ładować plugin dostawcy ze skróconych identyfikatorów modeli, takich jak acme-large, zanim będą dostępne haki runtime. Jeśli publikujesz dostawcę w ClawHub, pola openclaw.compat i openclaw.build są wymagane w package.json.
2

Zarejestruj dostawcę

Minimalny dostawca tekstu potrzebuje id, label, auth i catalog. catalog to hak runtime/konfiguracji należący do dostawcy; może wywoływać działające API dostawcy i zwraca wpisy 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 to nowsza powierzchnia katalogu płaszczyzny sterowania dla interfejsu list/pomocy/selektora. Używaj jej dla wierszy tekstu, generowania obrazów, generowania wideo i generowania muzyki. Zachowaj wywołania punktów końcowych dostawcy i mapowanie odpowiedzi w pluginie; OpenClaw odpowiada za wspólny kształt wiersza, etykiety źródeł i renderowanie pomocy.To jest działający dostawca. Użytkownicy mogą teraz uruchomić openclaw onboard --acme-ai-api-key <key> i wybrać acme-ai/acme-large jako swój model.Jeśli dostawca upstream używa innych tokenów sterujących niż OpenClaw, dodaj małą dwukierunkową transformację tekstu zamiast zastępować ścieżkę strumienia:
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 przepisuje końcowy prompt systemowy i treść wiadomości tekstowej przed transportem. output przepisuje delty tekstu asystenta i tekst końcowy, zanim OpenClaw przeanalizuje własne znaczniki sterujące lub dostarczanie do kanału.Dla wbudowanych dostawców, którzy rejestrują tylko jednego dostawcę tekstu z uwierzytelnianiem kluczem API oraz jednym runtime opartym na katalogu, preferuj węższy 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 to ścieżka katalogu na żywo używana, gdy OpenClaw może rozwiązać rzeczywiste uwierzytelnianie dostawcy. Może wykonywać wykrywanie specyficzne dla dostawcy. Używaj buildStaticProvider tylko dla wierszy offline, które można bezpiecznie pokazać przed skonfigurowaniem uwierzytelniania; nie może wymagać poświadczeń ani wykonywać żądań sieciowych. Widok models list --all w OpenClaw obecnie wykonuje katalogi statyczne tylko dla wbudowanych pluginów dostawców, z pustą konfiguracją, pustym środowiskiem i bez ścieżek agenta/przestrzeni roboczej.Jeśli przepływ uwierzytelniania musi również poprawiać models.providers.*, aliasy i domyślny model agenta podczas onboardingu, użyj helperów presetów z openclaw/plugin-sdk/provider-onboard. Najwęższe helpery to createDefaultModelPresetAppliers(...), createDefaultModelsPresetAppliers(...) i createModelCatalogPresetAppliers(...).Gdy natywny punkt końcowy dostawcy obsługuje strumieniowane bloki użycia w standardowym transporcie openai-completions, preferuj współdzielone helpery katalogu w openclaw/plugin-sdk/provider-catalog-shared zamiast kodować na stałe kontrole identyfikatorów dostawców. supportsNativeStreamingUsageCompat(...) i applyProviderNativeStreamingUsageCompat(...) wykrywają obsługę z mapy możliwości punktu końcowego, dzięki czemu natywne punkty końcowe w stylu Moonshot/DashScope nadal włączają się nawet wtedy, gdy plugin używa niestandardowego identyfikatora dostawcy.
3

Dodaj dynamiczne rozwiązywanie modeli

Jeśli dostawca akceptuje dowolne identyfikatory modeli (jak proxy lub router), dodaj 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,
  }),
});
Jeśli rozwiązywanie wymaga wywołania sieciowego, użyj prepareDynamicModel do asynchronicznego rozgrzewania - resolveDynamicModel uruchomi się ponownie po jego zakończeniu.
4

Dodaj haki runtime (w razie potrzeby)

Większość dostawców potrzebuje tylko catalog + resolveDynamicModel. Dodawaj haki stopniowo, zgodnie z wymaganiami dostawcy.Współdzielone kreatory helperów obejmują teraz najczęstsze rodziny zgodności replay/narzędzi, więc pluginy zwykle nie muszą ręcznie łączyć każdego haka osobno:
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,
});
Dostępne obecnie rodziny replay:
RodzinaCo podłączaDołączone przykłady
openai-compatibleWspólna polityka odtwarzania w stylu OpenAI dla transportów zgodnych z OpenAI, w tym oczyszczanie identyfikatorów wywołań narzędzi, poprawki kolejności z asystentem jako pierwszym oraz ogólna walidacja tur Gemini tam, gdzie transport jej wymagamoonshot, ollama, xai, zai
anthropic-by-modelPolityka odtwarzania świadoma Claude wybierana przez modelId, dzięki czemu transporty komunikatów Anthropic otrzymują czyszczenie bloków myślenia specyficzne dla Claude tylko wtedy, gdy rozwiązany model jest rzeczywiście identyfikatorem Claudeamazon-bedrock, anthropic-vertex
google-geminiNatywna polityka odtwarzania Gemini oraz oczyszczanie odtwarzania startowego i tryb oznaczonych wyników rozumowaniagoogle, google-gemini-cli
passthrough-geminiOczyszczanie sygnatur myśli Gemini dla modeli Gemini uruchamianych przez transporty proxy zgodne z OpenAI; nie włącza natywnej walidacji odtwarzania Gemini ani przepisań startowychopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openaiPolityka hybrydowa dla dostawców, którzy łączą powierzchnie modeli komunikatów Anthropic i zgodne z OpenAI w jednym pluginie; opcjonalne porzucanie bloków myślenia wyłącznie dla Claude pozostaje ograniczone do strony Anthropicminimax
Dostępne obecnie rodziny strumieni:
RodzinaCo podłączaDołączone przykłady
google-thinkingNormalizacja ładunku myślenia Gemini we wspólnej ścieżce strumieniagoogle, google-gemini-cli
kilocode-thinkingOpakowanie rozumowania Kilo we wspólnej ścieżce strumienia proxy, z pomijaniem wstrzykniętego myślenia dla kilo/auto i nieobsługiwanych identyfikatorów rozumowania proxykilocode
moonshot-thinkingMapowanie binarnego natywnego ładunku myślenia Moonshot z konfiguracji + poziomu /thinkmoonshot
minimax-fast-modePrzepisanie modelu trybu szybkiego MiniMax we wspólnej ścieżce strumieniaminimax, minimax-portal
openai-responses-defaultsWspólne natywne opakowania OpenAI/Codex Responses: nagłówki atrybucji, /fast/serviceTier, szczegółowość tekstu, natywne wyszukiwanie internetowe Codex, kształtowanie ładunku zgodności rozumowania oraz zarządzanie kontekstem Responsesopenai, openai-codex
openrouter-thinkingOpakowanie rozumowania OpenRouter dla tras proxy, z centralną obsługą pominięć nieobsługiwanego modelu/autoopenrouter
tool-stream-default-onDomyślnie włączone opakowanie tool_stream dla dostawców takich jak Z.AI, którzy chcą strumieniowania narzędzi, chyba że zostanie jawnie wyłączonezai
Każdy konstruktor rodziny składa się z publicznych pomocników niższego poziomu eksportowanych z tego samego pakietu, po które możesz sięgnąć, gdy dostawca musi odejść od wspólnego wzorca:
  • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamily, buildProviderReplayFamilyHooks(...) oraz surowe konstruktory odtwarzania (buildOpenAICompatibleReplayPolicy, buildAnthropicReplayPolicyForModel, buildGoogleGeminiReplayPolicy, buildHybridAnthropicOrOpenAIReplayPolicy). Eksportuje także pomocniki odtwarzania Gemini (sanitizeGoogleGeminiReplayHistory, resolveTaggedReasoningOutputMode) oraz pomocniki punktów końcowych/modeli (resolveProviderEndpoint, normalizeProviderId, normalizeGooglePreviewModelId).
  • openclaw/plugin-sdk/provider-stream - ProviderStreamFamily, buildProviderStreamFamilyHooks(...), composeProviderStreamWrappers(...), a także wspólne opakowania OpenAI/Codex (createOpenAIAttributionHeadersWrapper, createOpenAIFastModeWrapper, createOpenAIServiceTierWrapper, createOpenAIResponsesContextManagementWrapper, createCodexNativeWebSearchWrapper), opakowanie DeepSeek V4 zgodne z OpenAI (createDeepSeekV4OpenAICompatibleThinkingWrapper), czyszczenie wypełnienia myślenia Anthropic Messages (createAnthropicThinkingPrefillPayloadWrapper) oraz wspólne opakowania proxy/dostawcy (createOpenRouterWrapper, createToolStreamWrapper, createMinimaxFastModeWrapper).
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamily, buildProviderToolCompatFamilyHooks("gemini") oraz bazowe pomocniki schematów Gemini (normalizeGeminiToolSchemas, inspectGeminiToolSchemas).
Niektóre pomocniki strumieni celowo pozostają lokalne dla dostawcy. @openclaw/anthropic-provider trzyma wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier oraz konstruktory opakowań Anthropic niższego poziomu we własnym publicznym seamie api.ts / contract-api.ts, ponieważ kodują obsługę wersji beta OAuth Claude i bramkowanie context1m. Plugin xAI podobnie trzyma natywne kształtowanie xAI Responses we własnym wrapStreamFn (aliasy /fast, domyślny tool_stream, czyszczenie nieobsługiwanych narzędzi ścisłych, usuwanie ładunku rozumowania specyficzne dla xAI).Ten sam wzorzec katalogu głównego pakietu wspiera także @openclaw/openai-provider (konstruktory dostawcy, pomocniki modelu domyślnego, konstruktory dostawcy czasu rzeczywistego) oraz @openclaw/openrouter-provider (konstruktor dostawcy oraz pomocniki wdrażania/konfiguracji).
Dla dostawców, którzy wymagają wymiany tokenu przed każdym wywołaniem wnioskowania:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw wywołuje hooki w tej kolejności. Większość dostawców używa tylko 2-3: Pola dostawcy wyłącznie dla zgodności, których OpenClaw już nie wywołuje, takie jak ProviderPlugin.capabilities i suppressBuiltInModel, nie są tutaj wymienione.
#HookKiedy używać
1catalogKatalog modeli lub domyślne wartości bazowego URL
2applyConfigDefaultsGlobalne wartości domyślne należące do dostawcy podczas materializacji konfiguracji
3normalizeModelIdCzyszczenie aliasów starszych/podglądowych identyfikatorów modeli przed wyszukiwaniem
4normalizeTransportCzyszczenie api / baseUrl rodziny dostawcy przed ogólnym składaniem modelu
5normalizeConfigNormalizacja konfiguracji models.providers.<id>
6applyNativeStreamingUsageCompatPrzepisania zgodności natywnego użycia strumieniowego dla dostawców konfiguracyjnych
7resolveConfigApiKeyRozwiązywanie uwierzytelniania znaczników env należące do dostawcy
8resolveSyntheticAuthLokalne/samohostowane lub oparte na konfiguracji syntetyczne uwierzytelnianie
9shouldDeferSyntheticProfileAuthObniżanie syntetycznych symboli zastępczych zapisanego profilu za uwierzytelnianiem env/konfiguracyjnym
10resolveDynamicModelAkceptowanie dowolnych identyfikatorów modeli upstream
11prepareDynamicModelAsynchroniczne pobieranie metadanych przed rozwiązaniem
12normalizeResolvedModelPrzepisania transportu przed runnerem
13contributeResolvedModelCompatFlagi zgodności dla modeli dostawców za innym zgodnym transportem
14normalizeToolSchemasCzyszczenie schematów narzędzi należące do dostawcy przed rejestracją
15inspectToolSchemasDiagnostyka schematów narzędzi należąca do dostawcy
16resolveReasoningOutputModeKontrakt oznaczonego kontra natywnego wyniku rozumowania
17prepareExtraParamsDomyślne parametry żądania
18createStreamFnW pełni niestandardowy transport StreamFn
19wrapStreamFnNiestandardowe opakowania nagłówków/treści w normalnej ścieżce strumienia
20resolveTransportTurnStateNatywne nagłówki/metadane per tura
21resolveWebSocketSessionPolicyNatywne nagłówki sesji WS/czas odnowienia
22formatApiKeyNiestandardowy kształt tokenu uruchomieniowego
23refreshOAuthNiestandardowe odświeżanie OAuth
24buildAuthDoctorHintWskazówki naprawy uwierzytelniania
25matchesContextOverflowErrorWykrywanie przepełnienia należące do dostawcy
26classifyFailoverReasonKlasyfikacja limitu szybkości/przeciążenia należąca do dostawcy
27isCacheTtlEligibleBramkowanie TTL pamięci podręcznej promptu
28buildMissingAuthMessageNiestandardowa wskazówka brakującego uwierzytelniania
29augmentModelCatalogSyntetyczne wiersze zgodności w przód
30resolveThinkingProfileZestaw opcji /think specyficzny dla modelu
31isBinaryThinkingZgodność włączonego/wyłączonego myślenia binarnego
32supportsXHighThinkingZgodność obsługi rozumowania xhigh
33resolveDefaultThinkingLevelZgodność domyślnej polityki /think
34isModernModelRefDopasowanie modelu live/smoke
35prepareRuntimeAuthWymiana tokenu przed wnioskowaniem
36resolveUsageAuthNiestandardowe parsowanie poświadczeń użycia
37fetchUsageSnapshotNiestandardowy punkt końcowy użycia
38createEmbeddingProviderAdapter embeddingów należący do dostawcy dla pamięci/wyszukiwania
39buildReplayPolicyNiestandardowa polityka odtwarzania/Compaction transkryptu
40sanitizeReplayHistoryPrzepisania odtwarzania specyficzne dla dostawcy po ogólnym czyszczeniu
41validateReplayTurnsŚcisła walidacja tur odtwarzania przed osadzonym runnerem
42onModelSelectedWywołanie zwrotne po wyborze (np. telemetria)
Uwagi dotyczące rezerwowych zachowań uruchomieniowych:
  • normalizeConfig sprawdza najpierw dopasowanego dostawcę, a następnie inne pluginy dostawców obsługujące hooki, aż któryś faktycznie zmieni konfigurację. Jeśli żaden hook dostawcy nie przepisze obsługiwanego wpisu konfiguracji rodziny Google, nadal stosowany jest dołączony normalizator konfiguracji Google.
  • resolveConfigApiKey używa hooka dostawcy, gdy jest udostępniony. Dołączona ścieżka amazon-bedrock ma tutaj także wbudowany resolver znaczników env AWS, mimo że samo uwierzytelnianie uruchomieniowe Bedrock nadal używa domyślnego łańcucha AWS SDK.
  • resolveSystemPromptContribution pozwala dostawcy wstrzyknąć wskazówki promptu systemowego świadome pamięci podręcznej dla rodziny modeli. Preferuj to zamiast before_prompt_build, gdy zachowanie należy do jednego dostawcy/rodziny modeli i powinno zachować stabilny/dynamiczny podział pamięci podręcznej.
Szczegółowe opisy i rzeczywiste przykłady znajdziesz w Wewnętrzne mechanizmy: Hooki środowiska uruchomieniowego dostawcy.
5

Dodaj dodatkowe możliwości (opcjonalnie)

Krok 5: Dodaj dodatkowe możliwości

Plugin dostawcy może rejestrować mowę, transkrypcję w czasie rzeczywistym, głos w czasie rzeczywistym, rozumienie mediów, generowanie obrazów, generowanie wideo, pobieranie z sieci oraz wyszukiwanie w sieci obok wnioskowania tekstowego. OpenClaw klasyfikuje to jako Plugin o możliwościach hybrydowych - zalecany wzorzec dla firmowych Pluginów (jeden Plugin na dostawcę). Zobacz Wnętrze: własność możliwości.Zarejestruj każdą możliwość wewnątrz register(api) obok istniejącego wywołania api.registerProvider(...). Wybierz tylko potrzebne karty:
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();
    }
  },
});
Użyj assertOkOrThrowProviderError(...) w przypadku błędów HTTP dostawcy, aby Pluginy współdzieliły ograniczone odczyty treści błędów, parsowanie błędów JSON oraz sufiksy identyfikatorów żądań.
6

Test

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

Publikowanie w ClawHub

Pluginy dostawców publikuje się tak samo jak każdy inny zewnętrzny kodowy Plugin:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
Nie używaj tutaj starszego aliasu publikowania przeznaczonego tylko dla Skills; pakiety Pluginów powinny używać clawhub package publish.

Struktura plików

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

Odniesienie do kolejności katalogu

catalog.order kontroluje, kiedy Twój katalog jest scalany względem wbudowanych dostawców:
KolejnośćKiedyPrzypadek użycia
simplePierwsze przejścieZwykli dostawcy z kluczem API
profilePo simpleDostawcy zależni od profili uwierzytelniania
pairedPo profileSynteza wielu powiązanych wpisów
lateOstatnie przejścieNadpisywanie istniejących dostawców (wygrywa przy kolizji)

Następne kroki

Powiązane