メインコンテンツへスキップ

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.

このガイドでは、モデルプロバイダー (LLM) を OpenClaw に追加する provider plugin の構築手順を説明します。最後まで進めると、モデルカタログ、APIキー認証、動的モデル解決を備えたプロバイダーができあがります。
まだ OpenClaw plugin を構築したことがない場合は、基本的なパッケージ 構造とマニフェスト設定について、まず はじめに を読んでください。
Provider plugins は OpenClaw の通常の推論ループにモデルを追加します。モデルが スレッド、Compaction、またはツールイベントを所有するネイティブエージェントデーモン 経由で実行される必要がある場合は、デーモンプロトコルの詳細をコアに入れるのではなく、 プロバイダーを agent harness と組み合わせてください。

チュートリアル

1

Package and manifest

ステップ 1: パッケージとマニフェスト

{
  "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"
    }
  }
}
マニフェストは providerAuthEnvVars を宣言することで、OpenClaw が Plugin ランタイムを読み込まずに認証情報を検出できるようにします。プロバイダーのバリアントが別のプロバイダー ID の認証を再利用する必要がある場合は、 providerAuthAliases を追加します。modelSupport は任意で、ランタイムフックが存在する前に acme-large のような短縮形の モデル ID から OpenClaw が provider plugin を自動読み込みできるようにします。プロバイダーを ClawHub で公開する場合、これらの openclaw.compatopenclaw.build フィールドは package.json で必須です。
2

Register the provider

最小限のテキストプロバイダーには idlabelauthcatalog が必要です。 catalog はプロバイダー所有のランタイム/設定フックです。ライブの ベンダー API を呼び出し、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 は、list/help/picker UI 向けの新しいコントロールプレーンのカタログサーフェスです。 テキスト、画像生成、 動画生成、音楽生成の行に使ってください。ベンダーエンドポイントの呼び出しと レスポンスのマッピングは Plugin 内に保ちます。OpenClaw は共有される行の形、 ソースラベル、ヘルプ表示を所有します。これで動作するプロバイダーになります。ユーザーは openclaw onboard --acme-ai-api-key <key> を実行し、 acme-ai/acme-large をモデルとして選択できるようになります。上流プロバイダーが OpenClaw とは異なる制御トークンを使う場合は、ストリームパスを置き換えるのではなく、 小さな双方向テキスト変換を追加してください。
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 は転送前に、最終的なシステムプロンプトとテキストメッセージの内容を書き換えます。 output は OpenClaw が自身の制御マーカーやチャンネル配信を解析する前に、 アシスタントのテキストデルタと最終テキストを書き換えます。APIキー認証付きのテキストプロバイダーを 1 つだけ登録し、カタログに基づくランタイムを 1 つだけ持つ バンドルプロバイダーでは、より絞り込まれた 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 は、OpenClaw が実際のプロバイダー認証を解決できる場合に使われるライブカタログパスです。 プロバイダー固有の検出を実行してもかまいません。 buildStaticProvider は、認証が設定される前に表示しても安全なオフライン行にのみ使ってください。 認証情報を必要としたり、ネットワークリクエストを行ったりしてはいけません。 OpenClaw の models list --all 表示は現在、空の設定、空の環境、エージェント/ワークスペースパスなしで、 バンドルされた provider plugins の静的カタログのみを実行します。認証フローで models.providers.*、エイリアス、オンボーディング中の エージェントのデフォルトモデルもパッチする必要がある場合は、 openclaw/plugin-sdk/provider-onboard のプリセットヘルパーを使ってください。最も絞り込まれたヘルパーは createDefaultModelPresetAppliers(...)createDefaultModelsPresetAppliers(...)、および createModelCatalogPresetAppliers(...) です。プロバイダーのネイティブエンドポイントが通常の openai-completions 転送でストリーミング使用量ブロックをサポートする場合は、プロバイダー ID チェックをハードコードするのではなく、 openclaw/plugin-sdk/provider-catalog-shared の共有カタログヘルパーを優先してください。 supportsNativeStreamingUsageCompat(...)applyProviderNativeStreamingUsageCompat(...) は エンドポイント能力マップからサポートを検出するため、Plugin がカスタムプロバイダー ID を使っている場合でも、 ネイティブの Moonshot/DashScope 形式のエンドポイントは引き続きオプトインできます。
3

Add dynamic model resolution

プロバイダーが任意のモデル ID (プロキシやルーターなど) を受け入れる場合は、 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,
  }),
});
解決にネットワーク呼び出しが必要な場合は、非同期ウォームアップに prepareDynamicModel を使ってください。 完了後に resolveDynamicModel が再度実行されます。
4

Add runtime hooks (as needed)

ほとんどのプロバイダーに必要なのは catalog + resolveDynamicModel だけです。プロバイダーで必要になった時点で、 フックを段階的に追加してください。共有ヘルパービルダーは現在、最も一般的なリプレイ/ツール互換の ファミリーをカバーしているため、通常 Plugin が各フックを 1 つずつ手作業で配線する必要はありません。
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,
});
現在利用可能なリプレイファミリー:
ファミリー組み込む内容バンドル例
openai-compatibleOpenAI 互換トランスポート向けの共有 OpenAI 形式リプレイポリシー。ツール呼び出し ID のサニタイズ、assistant-first の順序修正、トランスポートが必要とする場合の汎用 Gemini ターン検証を含むmoonshot, ollama, xai, zai
anthropic-by-modelmodelId によって選択される Claude 対応リプレイポリシー。解決済みモデルが実際に Claude ID の場合にのみ、Anthropic-message トランスポートへ Claude 固有の thinking-block クリーンアップを適用するamazon-bedrock, anthropic-vertex
google-geminiネイティブ Gemini リプレイポリシーに加え、ブートストラップリプレイのサニタイズとタグ付き reasoning-output モードgoogle, google-gemini-cli
passthrough-geminiOpenAI 互換プロキシトランスポート経由で実行される Gemini モデル向けの Gemini thought-signature サニタイズ。ネイティブ Gemini リプレイ検証やブートストラップ書き換えは有効にしないopenrouter, kilocode, opencode, opencode-go
hybrid-anthropic-openai1 つの Plugin 内で Anthropic-message と OpenAI 互換モデルサーフェスを混在させるプロバイダー向けのハイブリッドポリシー。任意の Claude 専用 thinking-block ドロップは Anthropic 側に限定されるminimax
現在利用可能なストリームファミリー:
ファミリー組み込む内容バンドル例
google-thinking共有ストリームパス上での Gemini thinking ペイロード正規化google, google-gemini-cli
kilocode-thinking共有プロキシストリームパス上の Kilo reasoning ラッパー。kilo/auto と未サポートのプロキシ reasoning ID では injected thinking をスキップするkilocode
moonshot-thinkingconfig + /think レベルから Moonshot のバイナリネイティブ thinking ペイロードへマッピングmoonshot
minimax-fast-mode共有ストリームパス上での MiniMax fast-mode モデル書き換えminimax, minimax-portal
openai-responses-defaults共有ネイティブ OpenAI/Codex Responses ラッパー: attribution ヘッダー、/fast/serviceTier、テキストの詳細度、ネイティブ Codex Web 検索、reasoning 互換ペイロード整形、Responses コンテキスト管理openai, openai-codex
openrouter-thinkingプロキシルート向け OpenRouter reasoning ラッパー。未サポートモデル/auto のスキップは中央で処理されるopenrouter
tool-stream-default-onZ.AI のように明示的に無効化されない限りツールストリーミングを必要とするプロバイダー向けのデフォルトオン tool_stream ラッパーzai
各ファミリービルダーは、同じパッケージからエクスポートされる下位レベルの公開ヘルパーから構成されています。プロバイダーが共通パターンから外れる必要がある場合に利用できます:
  • openclaw/plugin-sdk/provider-model-shared - ProviderReplayFamilybuildProviderReplayFamilyHooks(...)、および生のリプレイビルダー(buildOpenAICompatibleReplayPolicybuildAnthropicReplayPolicyForModelbuildGoogleGeminiReplayPolicybuildHybridAnthropicOrOpenAIReplayPolicy)。Gemini リプレイヘルパー(sanitizeGoogleGeminiReplayHistoryresolveTaggedReasoningOutputMode)と、エンドポイント/モデルヘルパー(resolveProviderEndpointnormalizeProviderIdnormalizeGooglePreviewModelId)もエクスポートする。
  • openclaw/plugin-sdk/provider-stream - ProviderStreamFamilybuildProviderStreamFamilyHooks(...)composeProviderStreamWrappers(...)、加えて共有 OpenAI/Codex ラッパー(createOpenAIAttributionHeadersWrappercreateOpenAIFastModeWrappercreateOpenAIServiceTierWrappercreateOpenAIResponsesContextManagementWrappercreateCodexNativeWebSearchWrapper)、DeepSeek V4 OpenAI 互換ラッパー(createDeepSeekV4OpenAICompatibleThinkingWrapper)、Anthropic Messages thinking プリフィルクリーンアップ(createAnthropicThinkingPrefillPayloadWrapper)、共有プロキシ/プロバイダーラッパー(createOpenRouterWrappercreateToolStreamWrappercreateMinimaxFastModeWrapper)。
  • openclaw/plugin-sdk/provider-tools - ProviderToolCompatFamilybuildProviderToolCompatFamilyHooks("gemini")、および基盤となる Gemini スキーマヘルパー(normalizeGeminiToolSchemasinspectGeminiToolSchemas)。
一部のストリームヘルパーは意図的にプロバイダー内に留めています。@openclaw/anthropic-provider は、Claude OAuth beta 処理と context1m ゲーティングを表現するため、wrapAnthropicProviderStreamresolveAnthropicBetasresolveAnthropicFastModeresolveAnthropicServiceTier、および下位レベルの Anthropic ラッパービルダーを、自身の公開 api.ts / contract-api.ts 接点に保持しています。xAI Plugin も同様に、ネイティブ xAI Responses 整形を自身の wrapStreamFn/fast エイリアス、デフォルト tool_stream、未サポート strict-tool クリーンアップ、xAI 固有 reasoning-payload 削除)に保持しています。同じパッケージルートパターンは、@openclaw/openai-provider(プロバイダービルダー、デフォルトモデルヘルパー、リアルタイムプロバイダービルダー)と @openclaw/openrouter-provider(プロバイダービルダー、およびオンボーディング/config ヘルパー)も支えています。
各推論呼び出しの前にトークン交換が必要なプロバイダー向け:
prepareRuntimeAuth: async (ctx) => {
  const exchanged = await exchangeToken(ctx.apiKey);
  return {
    apiKey: exchanged.token,
    baseUrl: exchanged.baseUrl,
    expiresAt: exchanged.expiresAt,
  };
},
OpenClaw はこの順序でフックを呼び出します。ほとんどのプロバイダーが使うのは 2〜3 個だけです: ProviderPlugin.capabilitiessuppressBuiltInModel など、OpenClaw が現在は呼び出さない互換性専用のプロバイダーフィールドはここに記載していません。
#フック使用する場面
1catalogモデルカタログまたはベース URL デフォルト
2applyConfigDefaultsconfig マテリアライズ時のプロバイダー所有グローバルデフォルト
3normalizeModelIdルックアップ前のレガシー/プレビューモデル ID エイリアスのクリーンアップ
4normalizeTransport汎用モデル組み立て前のプロバイダーファミリー api / baseUrl クリーンアップ
5normalizeConfigmodels.providers.<id> config の正規化
6applyNativeStreamingUsageCompatconfig プロバイダー向けネイティブ streaming-usage 互換書き換え
7resolveConfigApiKeyプロバイダー所有 env-marker auth 解決
8resolveSyntheticAuthローカル/セルフホストまたは config backed synthetic auth
9shouldDeferSyntheticProfileAuthenv/config auth の背後に synthetic stored-profile プレースホルダーを下げる
10resolveDynamicModel任意の upstream モデル ID を受け入れる
11prepareDynamicModel解決前の非同期メタデータ取得
12normalizeResolvedModelランナー前のトランスポート書き換え
13contributeResolvedModelCompat別の互換トランスポート背後にあるベンダーモデル用の互換フラグ
14normalizeToolSchemas登録前のプロバイダー所有ツールスキーマクリーンアップ
15inspectToolSchemasプロバイダー所有ツールスキーマ診断
16resolveReasoningOutputModeタグ付き vs ネイティブ reasoning-output コントラクト
17prepareExtraParamsデフォルトリクエストパラメータ
18createStreamFn完全にカスタムの StreamFn トランスポート
19wrapStreamFn通常のストリームパス上のカスタムヘッダー/ボディラッパー
20resolveTransportTurnStateネイティブ per-turn ヘッダー/メタデータ
21resolveWebSocketSessionPolicyネイティブ WS セッションヘッダー/クールダウン
22formatApiKeyカスタムランタイムトークン形状
23refreshOAuthカスタム OAuth 更新
24buildAuthDoctorHintauth 修復ガイダンス
25matchesContextOverflowErrorプロバイダー所有 overflow 検出
26classifyFailoverReasonプロバイダー所有 rate-limit/overload 分類
27isCacheTtlEligibleプロンプトキャッシュ TTL ゲーティング
28buildMissingAuthMessageカスタム missing-auth ヒント
29augmentModelCatalogsynthetic forward-compat 行
30resolveThinkingProfileモデル固有 /think オプションセット
31isBinaryThinkingバイナリ thinking on/off 互換性
32supportsXHighThinkingxhigh reasoning サポート互換性
33resolveDefaultThinkingLevelデフォルト /think ポリシー互換性
34isModernModelReflive/smoke モデルマッチング
35prepareRuntimeAuth推論前のトークン交換
36resolveUsageAuthカスタム使用量資格情報の解析
37fetchUsageSnapshotカスタム使用量エンドポイント
38createEmbeddingProviderメモリ/検索向けプロバイダー所有 embedding アダプター
39buildReplayPolicyカスタム transcript リプレイ/Compaction ポリシー
40sanitizeReplayHistory汎用クリーンアップ後のプロバイダー固有リプレイ書き換え
41validateReplayTurns組み込みランナー前の厳密な replay-turn 検証
42onModelSelected選択後コールバック(例: テレメトリ)
ランタイムフォールバック注記:
  • normalizeConfig はまず一致したプロバイダーを確認し、その後、実際に config を変更するものが見つかるまで他のフック対応プロバイダー Plugin を確認します。サポートされている Google ファミリー config エントリをどのプロバイダーフックも書き換えない場合でも、バンドルされた Google config 正規化は適用されます。
  • resolveConfigApiKey は公開されている場合、プロバイダーフックを使用します。バンドルされた amazon-bedrock パスにも、ここに組み込み AWS env-marker リゾルバーがありますが、Bedrock ランタイム auth 自体は引き続き AWS SDK のデフォルトチェーンを使用します。
  • resolveSystemPromptContribution により、プロバイダーはモデルファミリー向けにキャッシュ対応のシステムプロンプトガイダンスを注入できます。その挙動が 1 つのプロバイダー/モデルファミリーに属し、stable/dynamic キャッシュ分割を維持すべき場合は、before_prompt_build よりもこちらを優先してください。
詳細な説明と実例については、内部構造: プロバイダーランタイムフックを参照してください。
5

追加機能を追加する(任意)

ステップ 5: 追加機能を追加する

プロバイダープラグインは、テキスト推論に加えて、音声、リアルタイム文字起こし、リアルタイム 音声、メディア理解、画像生成、動画生成、Webフェッチ、 Web検索を登録できます。OpenClaw はこれを hybrid-capability プラグインとして分類します。これは企業プラグイン (ベンダーごとに1つのプラグイン)に推奨されるパターンです。 内部: Capability Ownershipを参照してください。既存の api.registerProvider(...) 呼び出しと並べて、各 capability を register(api) 内に登録します。必要なタブだけを選んでください。
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();
    }
  },
});
プロバイダーの HTTP 失敗には assertOkOrThrowProviderError(...) を使用してください。 そうすることで、プラグイン間で、上限付きのエラーボディ読み取り、JSON エラー解析、 リクエスト ID サフィックスを共有できます。
6

Test

ステップ 6: テスト

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

ClawHub への公開

プロバイダープラグインは、他の外部コードプラグインと同じ方法で公開します。
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
ここでは従来のスキル専用公開エイリアスを使用しないでください。プラグインパッケージは clawhub package publish を使用する必要があります。

ファイル構造

<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 は、組み込みプロバイダーに対してカタログがいつマージされるかを制御します。
順序タイミングユースケース
simple最初のパス単純な API キープロバイダー
profilesimple の後認証プロファイルで制御されるプロバイダー
pairedprofile の後複数の関連エントリを合成する
late最後のパス既存プロバイダーを上書きする(衝突時に優先)

次のステップ

関連