Pular para o conteúdo principal

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.

Este guia percorre a criação de um Plugin de provedor que adiciona um provedor de modelo (LLM) ao OpenClaw. Ao final, você terá um provedor com um catálogo de modelos, autenticação por chave de API e resolução dinâmica de modelos.
Se você ainda não criou nenhum Plugin do OpenClaw, leia Primeiros passos primeiro para entender a estrutura básica do pacote e a configuração do manifesto.
Plugins de provedor adicionam modelos ao loop de inferência normal do OpenClaw. Se o modelo precisar executar por meio de um daemon de agente nativo que controla threads, compaction ou eventos de ferramenta, combine o provedor com um harness de agente em vez de colocar detalhes do protocolo do daemon no core.

Passo a passo

1

Pacote e manifesto

Etapa 1: Pacote e manifesto

{
  "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"
    }
  }
}
O manifesto declara providerAuthEnvVars para que o OpenClaw consiga detectar credenciais sem carregar o runtime do seu Plugin. Adicione providerAuthAliases quando uma variante de provedor deve reutilizar a autenticação do ID de outro provedor. modelSupport é opcional e permite que o OpenClaw carregue automaticamente seu Plugin de provedor a partir de IDs de modelo abreviados como acme-large antes que existam hooks de runtime. Se você publicar o provedor no ClawHub, esses campos openclaw.compat e openclaw.build serão obrigatórios em package.json.
2

Registre o provedor

Um provedor de texto mínimo precisa de id, label, auth e catalog. catalog é o hook de runtime/configuração pertencente ao provedor; ele pode chamar APIs de fornecedores ao vivo e retorna entradas 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 é a superfície de catálogo de plano de controle mais recente para IU de lista/ajuda/seletor. Use-a para linhas de texto, geração de imagem, geração de vídeo e geração de música. Mantenha as chamadas aos endpoints do fornecedor e o mapeamento de respostas no Plugin; o OpenClaw controla o formato compartilhado das linhas, os rótulos de origem e a renderização de ajuda.Isso é um provedor funcional. Os usuários agora podem executar openclaw onboard --acme-ai-api-key <key> e selecionar acme-ai/acme-large como modelo.Se o provedor upstream usar tokens de controle diferentes dos do OpenClaw, adicione uma pequena transformação bidirecional de texto em vez de substituir o caminho de 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 reescreve o prompt de sistema final e o conteúdo das mensagens de texto antes do transporte. output reescreve deltas de texto do assistente e o texto final antes que o OpenClaw analise seus próprios marcadores de controle ou a entrega pelo canal.Para provedores incluídos que registram apenas um provedor de texto com autenticação por chave de API mais um único runtime respaldado por catálogo, prefira o helper mais restrito 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 é o caminho de catálogo ao vivo usado quando o OpenClaw consegue resolver a autenticação real do provedor. Ele pode executar descoberta específica do provedor. Use buildStaticProvider apenas para linhas offline que sejam seguras para exibir antes que a autenticação seja configurada; ele não deve exigir credenciais nem fazer solicitações de rede. A exibição models list --all do OpenClaw atualmente executa catálogos estáticos apenas para Plugins de provedor incluídos, com configuração vazia, env vazio e nenhum caminho de agente/workspace.Se seu fluxo de autenticação também precisar corrigir models.providers.*, aliases e o modelo padrão do agente durante o onboarding, use os helpers de preset de openclaw/plugin-sdk/provider-onboard. Os helpers mais restritos são createDefaultModelPresetAppliers(...), createDefaultModelsPresetAppliers(...) e createModelCatalogPresetAppliers(...).Quando o endpoint nativo de um provedor oferecer suporte a blocos de uso transmitidos por stream no transporte normal openai-completions, prefira os helpers de catálogo compartilhados em openclaw/plugin-sdk/provider-catalog-shared em vez de codificar verificações de IDs de provedor. supportsNativeStreamingUsageCompat(...) e applyProviderNativeStreamingUsageCompat(...) detectam suporte a partir do mapa de capacidades do endpoint, então endpoints nativos no estilo Moonshot/DashScope ainda optam por participar mesmo quando um Plugin está usando um ID de provedor personalizado.
3

Adicione resolução dinâmica de modelos

Se seu provedor aceitar IDs de modelo arbitrários (como um proxy ou roteador), adicione 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 a resolução exigir uma chamada de rede, use prepareDynamicModel para aquecimento assíncrono
  • resolveDynamicModel executa novamente depois que ela é concluída.
4

Adicione hooks de runtime (conforme necessário)

A maioria dos provedores precisa apenas de catalog + resolveDynamicModel. Adicione hooks incrementalmente conforme seu provedor precisar deles.Os builders de helpers compartilhados agora cobrem as famílias mais comuns de replay/compatibilidade de ferramentas, então os Plugins geralmente não precisam conectar manualmente cada hook, um por um:
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,
});
Famílias de replay disponíveis hoje:
FamíliaO que ela conectaExemplos incluídos
openai-compatiblePolítica compartilhada de repetição no estilo OpenAI para transportes compatíveis com OpenAI, incluindo sanitização de ids de chamadas de ferramenta, correções de ordenação com assistente primeiro e validação genérica de turnos do Gemini quando o transporte precisa dissomoonshot, ollama, xai, zai
anthropic-by-modelPolítica de repetição ciente do Claude escolhida por modelId, para que transportes de mensagens da Anthropic recebam limpeza de blocos de pensamento específica do Claude somente quando o modelo resolvido for de fato um id do Claudeamazon-bedrock, anthropic-vertex
google-geminiPolítica de repetição nativa do Gemini mais sanitização de repetição de bootstrap e modo de saída de raciocínio marcadagoogle, google-gemini-cli
passthrough-geminiSanitização de assinatura de pensamento do Gemini para modelos Gemini executados por transportes proxy compatíveis com OpenAI; não habilita validação de repetição nativa do Gemini nem reescritas de bootstrapopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openaiPolítica híbrida para provedores que misturam superfícies de modelo de mensagens da Anthropic e compatíveis com OpenAI em um Plugin; a remoção opcional de blocos de pensamento apenas do Claude permanece limitada ao lado Anthropicminimax
Famílias de fluxo disponíveis hoje:
FamíliaO que ela conectaExemplos incluídos
google-thinkingNormalização de payload de pensamento do Gemini no caminho de fluxo compartilhadogoogle, google-gemini-cli
kilocode-thinkingWrapper de raciocínio do Kilo no caminho de fluxo proxy compartilhado, com kilo/auto e ids de raciocínio proxy sem suporte ignorando pensamento injetadokilocode
moonshot-thinkingMapeamento de payload de pensamento nativo binário do Moonshot a partir da configuração + nível /thinkmoonshot
minimax-fast-modeReescrita de modelo de modo rápido MiniMax no caminho de fluxo compartilhadominimax, minimax-portal
openai-responses-defaultsWrappers compartilhados nativos de Responses da OpenAI/Codex: cabeçalhos de atribuição, /fast/serviceTier, verbosidade de texto, pesquisa web nativa do Codex, formatação de payload de compatibilidade de raciocínio e gerenciamento de contexto de Responsesopenai, openai-codex
openrouter-thinkingWrapper de raciocínio do OpenRouter para rotas proxy, com ignoros de modelo sem suporte/auto tratados centralmenteopenrouter
tool-stream-default-onWrapper tool_stream ativado por padrão para provedores como Z.AI que querem streaming de ferramenta salvo quando explicitamente desabilitadozai
Cada construtor de família é composto a partir de auxiliares públicos de nível mais baixo exportados pelo mesmo pacote, que você pode usar quando um provedor precisa sair do padrão comum:
  • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamily, buildProviderReplayFamilyHooks(...) e os construtores brutos de repetição (buildOpenAICompatibleReplayPolicy, buildAnthropicReplayPolicyForModel, buildGoogleGeminiReplayPolicy, buildHybridAnthropicOrOpenAIReplayPolicy). Também exporta auxiliares de repetição do Gemini (sanitizeGoogleGeminiReplayHistory, resolveTaggedReasoningOutputMode) e auxiliares de endpoint/modelo (resolveProviderEndpoint, normalizeProviderId, normalizeGooglePreviewModelId).
  • openclaw/plugin-sdk/provider-stream - ProviderStreamFamily, buildProviderStreamFamilyHooks(...), composeProviderStreamWrappers(...), mais os wrappers compartilhados da OpenAI/Codex (createOpenAIAttributionHeadersWrapper, createOpenAIFastModeWrapper, createOpenAIServiceTierWrapper, createOpenAIResponsesContextManagementWrapper, createCodexNativeWebSearchWrapper), wrapper compatível com OpenAI do DeepSeek V4 (createDeepSeekV4OpenAICompatibleThinkingWrapper), limpeza de preenchimento antecipado de pensamento de Anthropic Messages (createAnthropicThinkingPrefillPayloadWrapper) e wrappers compartilhados de proxy/provedor (createOpenRouterWrapper, createToolStreamWrapper, createMinimaxFastModeWrapper).
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamily, buildProviderToolCompatFamilyHooks("gemini") e auxiliares subjacentes de schema do Gemini (normalizeGeminiToolSchemas, inspectGeminiToolSchemas).
Alguns auxiliares de fluxo permanecem locais ao provedor de propósito. @openclaw/anthropic-provider mantém wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier e os construtores de wrapper Anthropic de nível mais baixo em sua própria interface pública api.ts / contract-api.ts porque eles codificam o tratamento beta de OAuth do Claude e o controle de context1m. O Plugin xAI, de modo semelhante, mantém a formatação nativa de Responses xAI em seu próprio wrapStreamFn (aliases de /fast, tool_stream padrão, limpeza de ferramenta estrita sem suporte, remoção de payload de raciocínio específica da xAI).O mesmo padrão de raiz de pacote também sustenta @openclaw/openai-provider (construtores de provedor, auxiliares de modelo padrão, construtores de provedor em tempo real) e @openclaw/openrouter-provider (construtor de provedor mais auxiliares de integração/configuração).
Para provedores que precisam de uma troca de token antes de cada chamada de inferência:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw chama os ganchos nesta ordem. A maioria dos provedores usa apenas 2-3: Campos de provedor somente para compatibilidade que o OpenClaw não chama mais, como ProviderPlugin.capabilities e suppressBuiltInModel, não estão listados aqui.
#GanchoQuando usar
1catalogCatálogo de modelos ou padrões de URL base
2applyConfigDefaultsPadrões globais pertencentes ao provedor durante a materialização da configuração
3normalizeModelIdLimpeza de aliases legados/de pré-visualização de id de modelo antes da busca
4normalizeTransportLimpeza de api / baseUrl de família de provedor antes da montagem genérica do modelo
5normalizeConfigNormalizar configuração models.providers.<id>
6applyNativeStreamingUsageCompatReescritas de compatibilidade de uso de streaming nativo para provedores de configuração
7resolveConfigApiKeyResolução de autenticação por marcador de env pertencente ao provedor
8resolveSyntheticAuthAutenticação sintética local/auto-hospedada ou apoiada por configuração
9shouldDeferSyntheticProfileAuthRebaixar placeholders sintéticos de perfil armazenado atrás de autenticação por env/configuração
10resolveDynamicModelAceitar ids arbitrários de modelos upstream
11prepareDynamicModelBusca assíncrona de metadados antes da resolução
12normalizeResolvedModelReescritas de transporte antes do executor
13contributeResolvedModelCompatFlags de compatibilidade para modelos de fornecedor por trás de outro transporte compatível
14normalizeToolSchemasLimpeza de schema de ferramentas pertencente ao provedor antes do registro
15inspectToolSchemasDiagnósticos de schema de ferramentas pertencentes ao provedor
16resolveReasoningOutputModeContrato de saída de raciocínio marcada vs nativa
17prepareExtraParamsParâmetros de requisição padrão
18createStreamFnTransporte StreamFn totalmente personalizado
19wrapStreamFnWrappers personalizados de cabeçalhos/corpo no caminho de fluxo normal
20resolveTransportTurnStateCabeçalhos/metadados nativos por turno
21resolveWebSocketSessionPolicyCabeçalhos/cool-down nativos de sessão WS
22formatApiKeyFormato personalizado de token de runtime
23refreshOAuthAtualização OAuth personalizada
24buildAuthDoctorHintOrientação de reparo de autenticação
25matchesContextOverflowErrorDetecção de estouro pertencente ao provedor
26classifyFailoverReasonClassificação de limite de taxa/sobrecarga pertencente ao provedor
27isCacheTtlEligibleControle de elegibilidade de TTL do cache de prompt
28buildMissingAuthMessageDica personalizada de autenticação ausente
29augmentModelCatalogLinhas sintéticas de compatibilidade futura
30resolveThinkingProfileConjunto de opções /think específico do modelo
31isBinaryThinkingCompatibilidade de pensamento binário ligado/desligado
32supportsXHighThinkingCompatibilidade com suporte de raciocínio xhigh
33resolveDefaultThinkingLevelCompatibilidade da política padrão de /think
34isModernModelRefCorrespondência de modelo live/smoke
35prepareRuntimeAuthTroca de token antes da inferência
36resolveUsageAuthAnálise personalizada de credenciais de uso
37fetchUsageSnapshotEndpoint de uso personalizado
38createEmbeddingProviderAdaptador de embeddings pertencente ao provedor para memória/pesquisa
39buildReplayPolicyPolítica personalizada de repetição/compaction de transcrição
40sanitizeReplayHistoryReescritas de repetição específicas do provedor após a limpeza genérica
41validateReplayTurnsValidação estrita de turnos de repetição antes do executor incorporado
42onModelSelectedCallback pós-seleção (por exemplo, telemetria)
Observações sobre fallback de runtime:
  • normalizeConfig verifica primeiro o provedor correspondente, depois outros Plugins de provedor capazes de usar ganchos até que um realmente altere a configuração. Se nenhum gancho de provedor reescrever uma entrada de configuração da família Google compatível, o normalizador de configuração Google incluído ainda se aplica.
  • resolveConfigApiKey usa o gancho do provedor quando exposto. O caminho amazon-bedrock incluído também tem aqui um resolvedor integrado de marcador de env AWS, embora a autenticação de runtime do Bedrock em si ainda use a cadeia padrão do AWS SDK.
  • resolveSystemPromptContribution permite que um provedor injete orientação de prompt de sistema ciente de cache para uma família de modelos. Prefira-o a before_prompt_build quando o comportamento pertence a uma família de provedor/modelo e deve preservar a divisão estável/dinâmica do cache.
Para descrições detalhadas e exemplos reais, consulte Internos: Ganchos de Runtime de Provedor.
5

Adicionar capacidades extras (opcional)

Etapa 5: Adicionar capacidades extras

Um Plugin de provedor pode registrar fala, transcrição em tempo real, voz em tempo real, compreensão de mídia, geração de imagens, geração de vídeo, busca de páginas web e pesquisa na web junto com inferência de texto. O OpenClaw classifica isso como um Plugin de capacidade híbrida - o padrão recomendado para Plugins de empresa (um Plugin por fornecedor). Veja Internos: propriedade de capacidade.Registre cada capacidade dentro de register(api) junto com sua chamada existente api.registerProvider(...). Escolha apenas as abas necessárias:
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();
    }
  },
});
Use assertOkOrThrowProviderError(...) para falhas HTTP do provedor, para que os Plugins compartilhem leituras limitadas do corpo de erro, análise de erros JSON e sufixos de ID de solicitação.
6

Testar

Etapa 6: Testar

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

Publicar no ClawHub

Plugins de provedor são publicados da mesma forma que qualquer outro Plugin de código externo:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
Não use o alias legado de publicação somente para skill aqui; pacotes de Plugin devem usar clawhub package publish.

Estrutura de arquivos

<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 controla quando seu catálogo é mesclado em relação aos provedores integrados:
OrdemQuandoCaso de uso
simplePrimeiro passoProvedores simples com chave de API
profileApós simpleProvedores condicionados a perfis de autenticação
pairedApós profileSintetizar várias entradas relacionadas
lateÚltimo passoSubstituir provedores existentes (vence em colisão)

Próximas etapas

Relacionado