Building plugins
Sağlayıcı Plugin'leri oluşturma
OpenClaw'a bir model sağlayıcısı (LLM) eklemek için bir sağlayıcı Plugin'i oluşturun: model kataloğu, API anahtarıyla kimlik doğrulama ve dinamik model çözümleme.
Adım adım anlatım
Paket ve manifest
1. Adım: Paket ve 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" }}}{"id": "acme-ai","name": "Acme AI","description": "Acme AI model provider","providers": ["acme-ai"],"modelSupport": { "modelPrefixes": ["acme-"]},"setup": { "providers": [ { "id": "acme-ai", "envVars": ["ACME_AI_API_KEY"] } ]},"providerAuthAliases": { "acme-ai-coding": "acme-ai"},"providerAuthChoices": [ { "provider": "acme-ai", "method": "api-key", "choiceId": "acme-ai-api-key", "choiceLabel": "Acme AI API key", "groupId": "acme-ai", "groupLabel": "Acme AI", "cliFlag": "--acme-ai-api-key", "cliOption": "--acme-ai-api-key <key>", "cliDescription": "Acme AI API key" }],"configSchema": { "type": "object", "additionalProperties": false}}setup.providers[].envVars, OpenClaw'ın Plugin çalışma zamanınızı
yüklemeden kimlik bilgilerini algılamasını sağlar. Bir sağlayıcı varyantının
başka bir sağlayıcı kimliğinin kimlik doğrulamasını yeniden kullanması
gerektiğinde providerAuthAliases ekleyin. modelSupport isteğe bağlıdır
ve çalışma zamanı kancaları bulunmadan önce OpenClaw'ın sağlayıcı
Plugin'inizi acme-large gibi kısa model kimliklerinden otomatik olarak
yüklemesini sağlar. package.json içindeki openclaw.compat ve
openclaw.build, ClawHub'da yayımlama için gereklidir
(openclaw.compat.pluginApi ve openclaw.build.openclawVersion gerekli iki
alandır; minGatewayVersion belirtilmediğinde
openclaw.install.minHostVersion değerine geri döner).
Sağlayıcıyı kaydetme
Minimal bir metin sağlayıcısı için id, label, auth ve catalog
gerekir. catalog, sağlayıcının sahip olduğu çalışma zamanı/yapılandırma
kancasıdır; canlı sağlayıcı API'lerini çağırabilir ve models.providers
girdileri döndürür.
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, liste/yardım/seçici kullanıcı arayüzü için
text, voice, image_generation, video_generation ve
music_generation satırlarını kapsayan daha yeni kontrol düzlemi katalog
yüzeyidir. Sağlayıcı uç noktası çağrılarını ve yanıt eşlemesini Plugin'de
tutun; paylaşılan satır biçiminin, kaynak etiketlerinin ve yardım
oluşturmanın sahibi OpenClaw'dır.
Bu, çalışan bir sağlayıcıdır. Kullanıcılar artık
openclaw onboard --acme-ai-api-key <key> komutunu çalıştırabilir ve model
olarak acme-ai/acme-large seçebilir.
Canlı model keşfi
Sağlayıcınız /models tarzı bir API sunuyorsa sağlayıcıya özgü uç noktayı
ve satır yansıtmayı Plugin'inizde tutun ve paylaşılan getirme yaşam döngüsü
için openclaw/plugin-sdk/provider-catalog-live-runtime kullanın. Yardımcı,
sağlayıcı politikasını OpenClaw çekirdeğine koymadan korumalı HTTP
getirmeleri, sağlayıcı kimlik doğrulama üst bilgileri, yapılandırılmış HTTP
hataları, TTL önbelleğe alma ve statik geri dönüş davranışı sağlar.
Canlı API yalnızca sağlayıcının sahip olduğu statik katalog satırlarından
hangilerinin şu anda kullanılabilir olduğunu bildiriyorsa
buildLiveModelProviderConfig kullanın:
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";import { buildLiveModelProviderConfig, type LiveModelCatalogFetchGuard,} from "openclaw/plugin-sdk/provider-catalog-live-runtime"; const STATIC_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, },] as const; async function buildAcmeLiveProvider(params: { apiKey: string; discoveryApiKey?: string; fetchGuard?: LiveModelCatalogFetchGuard;}) { return await buildLiveModelProviderConfig({ providerId: "acme-ai", endpoint: "https://api.acme-ai.com/v1/models", providerConfig: { baseUrl: "https://api.acme-ai.com/v1", api: "openai-completions", }, models: STATIC_MODELS, apiKey: params.apiKey, discoveryApiKey: params.discoveryApiKey, fetchGuard: params.fetchGuard, ttlMs: 60_000, auditContext: "acme-ai-model-discovery", });} export default definePluginEntry({ id: "acme-ai", name: "Acme AI", register(api) { api.registerProvider({ id: "acme-ai", label: "Acme AI", catalog: { order: "simple", run: async (ctx) => { const auth = ctx.resolveProviderAuth("acme-ai"); const apiKey = auth.apiKey ?? ctx.resolveProviderApiKey("acme-ai").apiKey; if (!apiKey) return null; return { provider: await buildAcmeLiveProvider({ apiKey, discoveryApiKey: auth.discoveryApiKey, }), }; }, }, staticCatalog: { order: "simple", run: async () => ({ provider: { baseUrl: "https://api.acme-ai.com/v1", api: "openai-completions", models: [...STATIC_MODELS], }, }), }, }); },});Sağlayıcı API'si daha zengin meta veriler döndürüyor ve Plugin'in satırları
OpenClaw model tanımlarına kendisinin yansıtması gerekiyorsa
getCachedLiveProviderModelRows kullanın:
import { getCachedLiveProviderModelRows, LiveModelCatalogHttpError,} from "openclaw/plugin-sdk/provider-catalog-live-runtime"; async function discoverAcmeModels(apiKey: string) { try { const rows = await getCachedLiveProviderModelRows({ providerId: "acme-ai", endpoint: "https://api.acme-ai.com/v1/models", apiKey, ttlMs: 60_000, auditContext: "acme-ai-model-discovery", }); return rows .map((row) => projectAcmeModel(row)) .filter((model) => model !== null); } catch (error) { if (error instanceof LiveModelCatalogHttpError) { return STATIC_MODELS; } throw error; }}run, kimlik doğrulama denetimli kalmalı ve kullanılabilir kimlik bilgisi
bulunmadığında null döndürmelidir. Kurulum, belgeler, testler ve seçici
yüzeylerin canlı ağ erişimine bağlı olmaması için çevrimdışı bir
staticRun veya statik geri dönüş bulundurun. Model listesinin güncellik
gereksinimine uygun bir TTL kullanın, istek sırasında dosya sistemi
yoklamasından kaçının ve yalnızca üst kaynak yanıtı OpenAI uyumlu
{ data: [{ id, object }] } biçiminde değilse sağlayıcıya özgü bir
readRows / readModelId iletin.
Üst kaynak sağlayıcı OpenClaw'dan farklı kontrol belirteçleri kullanıyorsa akış yolunu değiştirmek yerine küçük, çift yönlü bir metin dönüşümü ekleyin:
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, aktarımdan önce son sistem istemini ve metin mesajı içeriğini
yeniden yazar. output, OpenClaw kendi kontrol işaretçilerini ayrıştırmadan
veya kanal teslimatı yapılmadan önce asistan metin deltalarını ve son metni
yeniden yazar.
Yalnızca API anahtarıyla kimlik doğrulanan tek bir metin sağlayıcısını ve
katalog destekli tek bir çalışma zamanını kaydeden paketlenmiş sağlayıcılar
için daha dar kapsamlı defineSingleProviderPluginEntry(...) yardımcısını
tercih edin:
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry"; export default defineSingleProviderPluginEntry({ id: "acme-ai", name: "Acme AI", description: "Acme AI model sağlayıcısı", provider: { label: "Acme AI", docsPath: "/providers/acme-ai", auth: [ { methodId: "api-key", label: "Acme AI API anahtarı", hint: "Acme AI kontrol panelinizden alınan API anahtarı", optionKey: "acmeAiApiKey", flagName: "--acme-ai-api-key", envVar: "ACME_AI_API_KEY", promptMessage: "Acme AI API anahtarınızı girin", 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 gerçek sağlayıcı kimlik doğrulamasını çözümleyebildiğinde
kullanılan canlı katalog yoludur. Sağlayıcıya özgü keşif işlemleri gerçekleştirebilir.
buildStaticProvider öğesini yalnızca kimlik doğrulama yapılandırılmadan önce
güvenle gösterilebilen çevrimdışı satırlar için kullanın; kimlik bilgileri
gerektirmemeli veya ağ istekleri yapmamalıdır. OpenClaw'ın models list --all
görünümü şu anda statik katalogları yalnızca paketlenmiş sağlayıcı Plugin'leri için;
boş bir yapılandırma, boş ortam ve hiçbir aracı/çalışma alanı yolu olmadan yürütür.
Kimlik doğrulama akışınızın ilk katılım sırasında models.providers.* öğesini,
takma adları ve aracının varsayılan modelini de yamaması gerekiyorsa
openclaw/plugin-sdk/provider-onboard içindeki ön ayar yardımcılarını kullanın.
En dar kapsamlı yardımcılar createDefaultModelPresetAppliers(...),
createDefaultModelsPresetAppliers(...) ve
createModelCatalogPresetAppliers(...) öğeleridir.
Bir sağlayıcının yerel uç noktası normal openai-completions aktarımında
akışlı kullanım bloklarını destekliyorsa sağlayıcı kimliği denetimlerini sabit
kodlamak yerine openclaw/plugin-sdk/provider-catalog-shared içindeki paylaşılan
katalog yardımcılarını tercih edin. supportsNativeStreamingUsageCompat(...) ve
applyProviderNativeStreamingUsageCompat(...), desteği uç nokta yetenek
eşlemesinden algılar; böylece yerel Moonshot/DashScope tarzı uç noktalar, bir
Plugin özel bir sağlayıcı kimliği kullandığında bile özelliği etkinleştirebilir.
Yukarıdaki canlı keşif örnekleri /models tarzı sağlayıcı API'lerini kapsar.
Bu keşfi kullanılabilir kimlik doğrulamasıyla sınırlandırılmış biçimde
catalog.run içinde tutun ve çevrimdışı katalog oluşturma için staticRun
öğesinin ağ kullanmamasını sağlayın.
Dinamik model çözümleme ekleyin
Sağlayıcınız isteğe bağlı model kimliklerini kabul ediyorsa (bir proxy veya
yönlendirici gibi), resolveDynamicModel ekleyin:
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, }),});Çözümleme bir ağ çağrısı gerektiriyorsa eşzamansız ön hazırlık için
prepareDynamicModel kullanın; tamamlandıktan sonra resolveDynamicModel
yeniden çalışır.
Çalışma zamanı kancaları ekleyin (gerektiğinde)
Çoğu sağlayıcı yalnızca catalog + resolveDynamicModel gerektirir.
Sağlayıcınız ihtiyaç duydukça kancaları kademeli olarak ekleyin.
Paylaşılan yardımcı oluşturucular artık en yaygın yeniden oynatma/araç uyumluluğu ailelerini kapsadığından Plugin'lerin genellikle her kancayı tek tek elle bağlaması gerekmez:
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,});Günümüzde kullanılabilen yeniden oynatma aileleri:
| Aile | Bağladığı işlevler | Paketlenmiş örnekler |
|---|---|---|
openai-compatible |
Araç çağrısı kimliği temizliği, önce yardımcı sıralamasına yönelik düzeltmeler ve aktarımın gerektirdiği yerlerde genel Gemini dönüşü doğrulaması dâhil, OpenAI uyumlu aktarımlar için paylaşılan OpenAI tarzı yeniden oynatma ilkesi | moonshot, ollama, xai, zai |
anthropic-by-model |
modelId tarafından seçilen Claude uyumlu yeniden oynatma ilkesi; böylece Anthropic ileti aktarımları, yalnızca çözümlenen model gerçekten bir Claude kimliğiyse Claude'a özgü düşünme bloğu temizliğini alır |
amazon-bedrock |
native-anthropic-by-model |
anthropic-by-model ile aynı modele göre Claude ilkesi; buna ek olarak, üreticiye özgü kimlikleri koruması gereken aktarımlar için araç çağrısı kimliği temizliği ve yerel Anthropic araç kullanımı kimliği koruması |
anthropic-vertex, clawrouter |
google-gemini |
Yerel Gemini yeniden oynatma ilkesi ve başlangıç yeniden oynatma temizliği. Paylaşılan aile, metin çıktılı Gemini CLI'da etiketli akıl yürütmeyi korur; doğrudan google sağlayıcısı ise Gemini API düşünme içeriği yerel düşünce parçaları olarak geldiği için resolveReasoningOutputMode öğesini native olarak geçersiz kılar. |
google, google-gemini-cli |
passthrough-gemini |
OpenAI uyumlu proxy aktarımları üzerinden çalışan Gemini modelleri için Gemini düşünce imzası temizliği; yerel Gemini yeniden oynatma doğrulamasını veya başlangıç yeniden yazımlarını etkinleştirmez | openrouter, kilocode, opencode, opencode-go |
hybrid-anthropic-openai |
Anthropic ileti ve OpenAI uyumlu model yüzeylerini tek bir Plugin'de birleştiren sağlayıcılar için karma ilke; isteğe bağlı, yalnızca Claude'a özgü düşünme bloğu kaldırma işlemi Anthropic tarafıyla sınırlı kalır | minimax |
Günümüzde kullanılabilen akış aileleri:
| Aile | Bağladığı işlevler | Paketlenmiş örnekler |
|---|---|---|
google-thinking |
Paylaşılan akış yolunda Gemini düşünme yükü normalleştirmesi | google, google-gemini-cli |
kilocode-thinking |
Paylaşılan proxy akış yolunda Kilo akıl yürütme sarmalayıcısı; kilo/auto ve desteklenmeyen proxy akıl yürütme kimlikleri eklenen düşünme işlemini atlar |
kilocode |
moonshot-thinking |
Yapılandırma ve /think düzeyinden Moonshot ikili yerel düşünme yükü eşlemesi |
moonshot |
minimax-fast-mode |
Paylaşılan akış yolunda MiniMax hızlı mod modelini yeniden yazma | minimax, minimax-portal |
openai-responses-defaults |
Paylaşılan yerel OpenAI/Codex Responses sarmalayıcıları: ilişkilendirme üst bilgileri, /fast/serviceTier, metin ayrıntı düzeyi, yerel Codex web araması, akıl yürütme uyumluluğu yükü şekillendirme ve Responses bağlam yönetimi |
openai |
openrouter-thinking |
Proxy rotaları için OpenRouter akıl yürütme sarmalayıcısı; desteklenmeyen model/auto atlamaları merkezi olarak işlenir |
openrouter |
tool-stream-default-on |
Açıkça devre dışı bırakılmadığı sürece araç akışı isteyen Z.AI gibi sağlayıcılar için varsayılan olarak etkin tool_stream sarmalayıcısı |
zai |
Aile oluşturucuları destekleyen SDK bağlantı noktaları
Her aile oluşturucu, aynı paketten dışa aktarılan daha alt düzey genel yardımcılardan oluşturulur. Bir sağlayıcının yaygın kalıbın dışına çıkması gerektiğinde bunları kullanabilirsiniz:
openclaw/plugin-sdk/provider-model-shared-ProviderReplayFamily,buildProviderReplayFamilyHooks(...)ve ham yeniden oynatma oluşturucuları (buildOpenAICompatibleReplayPolicy,buildAnthropicReplayPolicyForModel,buildGoogleGeminiReplayPolicy,buildHybridAnthropicOrOpenAIReplayPolicy). Ayrıca Gemini yeniden oynatma yardımcılarını (sanitizeGoogleGeminiReplayHistory,resolveTaggedReasoningOutputMode) ve uç nokta/model yardımcılarını (resolveProviderEndpoint,normalizeProviderId,normalizeGooglePreviewModelId) dışa aktarır.openclaw/plugin-sdk/provider-stream-ProviderStreamFamily,buildProviderStreamFamilyHooks(...),composeProviderStreamWrappers(...); ayrıca paylaşılan OpenAI/Codex sarmalayıcıları (createOpenAIAttributionHeadersWrapper,createOpenAIFastModeWrapper,createOpenAIServiceTierWrapper,createOpenAIResponsesContextManagementWrapper,createCodexNativeWebSearchWrapper), DeepSeek V4 OpenAI uyumlu sarmalayıcısı (createDeepSeekV4OpenAICompatibleThinkingWrapper), Anthropic Messages düşünme ön doldurma temizliği (createAnthropicThinkingPrefillPayloadWrapper), düz metin araç çağrısı uyumluluğu (createPlainTextToolCallCompatWrapper) ve paylaşılan proxy/sağlayıcı sarmalayıcıları (createOpenRouterWrapper,createToolStreamWrapper,createMinimaxFastModeWrapper).openclaw/plugin-sdk/provider-stream-shared-createOpenAICompatibleCompletionsThinkingOffWrapper,createPayloadPatchStreamWrapper,createPlainTextToolCallCompatWrapper,normalizeOpenAICompatibleReasoningPayload(...)vesetQwenChatTemplateThinking(...)dâhil, yoğun kullanılan sağlayıcı yolları için hafif yük ve olay sarmalayıcıları.openclaw/plugin-sdk/provider-tools-ProviderToolCompatFamily,buildProviderToolCompatFamilyHooks("deepseek" | "gemini" | "openai")ve temel sağlayıcı şeması yardımcıları.
Gemini ailesindeki sağlayıcılar için akıl yürütme çıktı modunu aktarımla
uyumlu tutun. Doğrudan Google Gemini API sağlayıcıları, OpenClaw'ın
<think> / <final> istem yönergeleri eklemeden yerel düşünce parçalarını
kullanabilmesi için native akıl yürütme çıktısını kullanmalıdır. Son bir
JSON/metin yanıtını ayrıştıran yalnızca metin kullanan Gemini CLI tarzı arka
uçlar, paylaşılan google-gemini etiketli sözleşmesini koruyabilir.
Bazı akış yardımcıları bilinçli olarak sağlayıcıya özel kalır.
@openclaw/anthropic-provider; wrapAnthropicProviderStream,
resolveAnthropicBetas, resolveAnthropicFastMode,
resolveAnthropicServiceTier ve daha alt düzey Anthropic sarmalayıcı
oluşturucularını kendi genel api.ts / contract-api.ts bağlantı noktasında
tutar; çünkü bunlar Claude OAuth beta işleme ve context1m sınırlamasını
kodlar. xAI Plugin'i de benzer şekilde yerel xAI Responses şekillendirmesini
kendi wrapStreamFn öğesinde tutar (/fast takma adları, varsayılan
tool_stream, desteklenmeyen katı araç temizliği, xAI'ye özgü akıl yürütme
yükü kaldırma).
Aynı paket kökü kalıbı ayrıca @openclaw/openai-provider (sağlayıcı
oluşturucuları, varsayılan model yardımcıları, gerçek zamanlı sağlayıcı
oluşturucuları) ve @openclaw/openrouter-provider (sağlayıcı oluşturucusu
ile ilk katılım/yapılandırma yardımcıları) için de kullanılır.
Belirteç değişimi
Her çıkarım çağrısından önce belirteç değişimi gerektiren sağlayıcılar için:
prepareRuntimeAuth: async (ctx) => { const exchanged = await exchangeToken(ctx.apiKey); return { apiKey: exchanged.token, baseUrl: exchanged.baseUrl, expiresAt: exchanged.expiresAt, };},Özel üst bilgiler
Özel istek üst bilgileri veya gövde değişiklikleri gerektiren sağlayıcılar için:
// wrapStreamFn returns a StreamFn derived from ctx.streamFnwrapStreamFn: (ctx) => { if (!ctx.streamFn) return undefined; const inner = ctx.streamFn; return async (params) => { params.headers = { ...params.headers, "X-Acme-Version": "2", }; return inner(params); };},Yerel aktarım kimliği
Genel HTTP veya WebSocket aktarımlarında yerel istek/oturum üst bilgileri ya da meta veriler gerektiren sağlayıcılar için:
resolveTransportTurnState: (ctx) => ({ headers: { "x-request-id": ctx.turnId, }, metadata: { session_id: ctx.sessionId ?? "", turn_id: ctx.turnId, },}),resolveWebSocketSessionPolicy: (ctx) => ({ headers: { "x-session-id": ctx.sessionId ?? "", }, degradeCooldownMs: 60_000,}),Kullanım ve faturalandırma
Kullanım/faturalandırma verilerini sunan sağlayıcılar için:
resolveUsageAuth: async (ctx) => { const auth = await ctx.resolveOAuthToken(); return auth ? { token: auth.token } : null;},fetchUsageSnapshot: async (ctx) => { return await fetchAcmeUsage(ctx.token, ctx.timeoutMs);},resolveUsageAuth üç olası sonuç verir. Sağlayıcının bir
kullanım/faturalandırma kimlik bilgisi olduğunda
{ token, accountId?, subscriptionType?, rateLimitTier? } döndürün
(isteğe bağlı alanlar, çözümlenen profildeki gizli olmayan plan meta
verilerini fetchUsageSnapshot içine taşır). Yalnızca sağlayıcı kullanım
kimlik doğrulamasını kesin olarak işlediyse ancak kullanılabilir bir
kullanım belirteci yoksa ve OpenClaw genel API anahtarı/OAuth geri dönüşünü
atlamalıysa { handled: true } döndürün. Sağlayıcı isteği işlemediyse ve
OpenClaw genel geri dönüşle devam etmeliyse null veya undefined
döndürün.
Sağlayıcı kimliğini contracts.usageProviders içinde bildirin. Bu manifest
sözleşmesi ve her iki kanca da mevcut olduğunda OpenClaw, ilgisiz
sağlayıcı Plugin'lerini yüklemeden sağlayıcıyı otomatik olarak kullanım
verisi toplamaya dahil eder. Çekirdek izin listesinin güncellenmesi
gerekmez.
fetchUsageSnapshot, sağlayıcıdan bağımsız ortak biçimi döndürür:
plan: sağlayıcının bildirdiği abonelik veya anahtar etiketiwindows: kullanılan yüzdeler olarak sıfırlanabilir kota pencereleribilling: türü belirtilmişbalance,spendveyabudgetgirdileri;unit, bir ISO para birimi ya dacreditsgibi bir sağlayıcı birimi olabilirsummary: bu yapılandırılmış alanlara sığmayan, sağlayıcıya özgü kısa bağlam
Para birimi anlamlarını tam olarak koruyun. Üst kaynak sözleşmesi öyle
olduğunu belirtmediği sürece bir sağlayıcı kredisi USD değildir. Yalnızca
fetchUsageSnapshot uygulayan bir Plugin, açık/sentetik çağıranlar için
kullanılabilir olmaya devam eder ancak OpenClaw kullanım kimlik bilgisini
çözümleyemediği için otomatik olarak keşfedilmez.
Yaygın sağlayıcı kancaları
OpenClaw, model/sağlayıcı Plugin'leri için kancaları yaklaşık olarak bu
sırayla çağırır. Çoğu sağlayıcı yalnızca 2-3 tanesini kullanır. Bu,
ProviderPlugin sözleşmesinin tamamı değildir; eksiksiz ve güncel kanca
listesi ile geri dönüş notları için İç Yapı: Sağlayıcı Çalışma Zamanı
Kancaları bölümüne
bakın. OpenClaw'ın artık çağırmadığı, yalnızca uyumluluk amaçlı
ProviderPlugin.capabilities ve suppressBuiltInModel gibi sağlayıcı
alanları burada listelenmemiştir.
| Kanca | Ne zaman kullanılmalı |
|---|---|
catalog |
Model kataloğu veya temel URL varsayılanları |
applyConfigDefaults |
Yapılandırma somutlaştırılırken sağlayıcının sahip olduğu genel varsayılanlar |
normalizeModelId |
Aramadan önce eski/önizleme model kimliği takma adlarını temizleme |
normalizeTransport |
Genel model birleştirmesinden önce sağlayıcı ailesine ait api / baseUrl temizliği |
normalizeConfig |
models.providers.<id> yapılandırmasını normalleştirme |
applyNativeStreamingUsageCompat |
Yapılandırma sağlayıcıları için yerel akış kullanımı uyumluluk yeniden yazımları |
resolveConfigApiKey |
Sağlayıcının sahip olduğu ortam işaretçisi kimlik doğrulama çözümlemesi |
resolveSyntheticAuth |
Yerel/kendi sunucusunda barındırılan veya yapılandırma destekli sentetik kimlik doğrulama |
resolveExternalAuthProfiles |
CLI/uygulama tarafından yönetilen kimlik bilgileri için sağlayıcının sahip olduğu harici kimlik doğrulama profillerini katmanlama |
shouldDeferSyntheticProfileAuth |
Sentetik kayıtlı profil yer tutucularını ortam/yapılandırma kimlik doğrulamasının arkasına alma |
resolveDynamicModel |
İsteğe bağlı üst kaynak model kimliklerini kabul etme |
prepareDynamicModel |
Çözümlemeden önce eşzamansız meta veri getirme |
normalizeResolvedModel |
Çalıştırıcıdan önce aktarım yeniden yazımları |
normalizeToolSchemas |
Kayıttan önce sağlayıcının sahip olduğu araç şeması temizliği |
inspectToolSchemas |
Sağlayıcının sahip olduğu araç şeması tanılamaları |
resolveReasoningOutputMode |
Etiketli ve yerel akıl yürütme çıktısı sözleşmesi |
prepareExtraParams |
Varsayılan istek parametreleri |
createStreamFn |
Tamamen özel StreamFn aktarımı |
wrapStreamFn |
Normal akış yolundaki özel üstbilgi/gövde sarmalayıcıları |
resolveTransportTurnState |
Her tur için yerel üstbilgiler/meta veriler |
resolveWebSocketSessionPolicy |
Yerel WS oturum üstbilgileri/bekleme süresi |
formatApiKey |
Özel çalışma zamanı belirteci biçimi |
refreshOAuth |
Özel OAuth yenilemesi |
buildAuthDoctorHint |
Kimlik doğrulama onarım rehberliği |
matchesContextOverflowError |
Sağlayıcının sahip olduğu taşma algılama |
classifyFailoverReason |
Sağlayıcının sahip olduğu hız sınırı/aşırı yük sınıflandırması |
isCacheTtlEligible |
İstem önbelleği TTL geçiş denetimi |
buildMissingAuthMessage |
Özel eksik kimlik doğrulama ipucu |
augmentModelCatalog |
Sentetik ileriye dönük uyumluluk satırları (kullanımdan kaldırıldı; registerModelCatalogProvider tercih edin) |
resolveThinkingProfile |
Modele özgü /think seçenek kümesi |
isBinaryThinking |
İkili düşünme açık/kapalı uyumluluğu (kullanımdan kaldırıldı; resolveThinkingProfile tercih edin) |
supportsXHighThinking |
xhigh akıl yürütme desteği uyumluluğu (kullanımdan kaldırıldı; resolveThinkingProfile tercih edin) |
resolveDefaultThinkingLevel |
Varsayılan /think politikası uyumluluğu (kullanımdan kaldırıldı; resolveThinkingProfile tercih edin) |
isModernModelRef |
Canlı/duman testi modeli eşleştirme |
prepareRuntimeAuth |
Çıkarımdan önce belirteç değişimi |
resolveUsageAuth |
Özel kullanım kimlik bilgisi ayrıştırma |
fetchUsageSnapshot |
Özel kullanım uç noktası |
createEmbeddingProvider |
Bellek/arama için sağlayıcının sahip olduğu gömme bağdaştırıcısı |
buildReplayPolicy |
Özel döküm yeniden oynatma/Compaction politikası |
sanitizeReplayHistory |
Genel temizlikten sonra sağlayıcıya özgü yeniden oynatma yazımları |
validateReplayTurns |
Gömülü çalıştırıcıdan önce katı yeniden oynatma turu doğrulaması |
onModelSelected |
Seçim sonrası geri çağırma (ör. telemetri) |
Çalışma zamanı geri dönüş notları:
normalizeConfig, her sağlayıcı kimliği için bir sahip Plugin'i çözümler (önce paketlenmiş sağlayıcılar, ardından eşleşen çalışma zamanı Plugin'i) ve yalnızca bu kancayı çağırır; diğer sağlayıcılar arasında tarama yapılmaz.google/google-vertex/google-antigravityyapılandırma girdilerini normalleştiren, Google'ın kendinormalizeConfigkancasıdır; bu ayrı bir çekirdek geri dönüşü değildir.resolveConfigApiKey, sunulduğunda sağlayıcı kancasını kullanır. Amazon Bedrock, AWS ortam işaretçisi çözümlemesini kendi sağlayıcı Plugin'inde tutar; çalışma zamanı kimlik doğrulamasının kendisi,auth: "aws-sdk"ile yapılandırıldığında AWS SDK varsayılan zincirini kullanmaya devam eder.resolveThinkingProfile(ctx)seçiliprovider,modelId, isteğe bağlı birleştirilmişreasoningkatalog ipucunu ve isteğe bağlı birleştirilmiş modelcompatbilgilerini alır.compatdeğerini yalnızca sağlayıcının düşünme kullanıcı arayüzünü/profilini seçmek için kullanın.resolveSystemPromptContribution, bir sağlayıcının bir model ailesi için önbellek duyarlı sistem istemi rehberliği eklemesine olanak tanır. Davranış tek bir sağlayıcı/model ailesine ait olduğunda ve kararlı/dinamik önbellek ayrımını koruması gerektiğinde eski, Plugin genelindekibefore_prompt_buildkancası yerine bunu tercih edin.
Ek yetenekler ekleyin (isteğe bağlı)
Adım 5: Ek yetenekler ekleyin
Bir sağlayıcı Plugin'i; metin çıkarımının yanı sıra gömmeler, konuşma, gerçek zamanlı transkripsiyon, gerçek zamanlı ses, medya anlama, görüntü oluşturma, video oluşturma, web'den getirme ve web aramayı kaydedebilir. OpenClaw bunu bir hibrit yetenek Plugin'i olarak sınıflandırır; şirket Plugin'leri için önerilen kalıp budur (satıcı başına bir Plugin). Bkz. İç Yapı: Yetenek Sahipliği.
Her yeteneği, mevcut api.registerProvider(...) çağrınızın yanında
register(api) içinde kaydedin. Yalnızca ihtiyaç duyduğunuz sekmeleri seçin:
Konuşma (TTS)
import { assertOkOrThrowProviderError, postJsonRequest,} from "openclaw/plugin-sdk/provider-http"; api.registerSpeechProvider({ id: "acme-ai", label: "Acme Speech", defaultTimeoutMs: 120_000, 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(); } },});Sağlayıcı HTTP hataları için assertOkOrThrowProviderError(...) kullanın;
böylece Plugin'ler sınırlı hata gövdesi okumalarını, JSON hata
ayrıştırmasını ve istek kimliği son eklerini paylaşır.
Gerçek zamanlı transkripsiyon
createRealtimeTranscriptionWebSocketSession(...) kullanmayı tercih edin;
paylaşılan yardımcı, proxy yakalamayı, yeniden bağlanma geri çekilmesini,
kapanış temizlemesini, hazır el sıkışmalarını, ses kuyruğa almayı ve
kapanış olayı tanılamalarını yönetir. Plugin'iniz yalnızca üst kaynak
olaylarını eşler.
api.registerRealtimeTranscriptionProvider({ id: "acme-ai", label: "Acme Realtime Transcription", isConfigured: () => true, createSession: (req) => { const apiKey = String(req.providerConfig.apiKey ?? ""); return createRealtimeTranscriptionWebSocketSession({ providerId: "acme-ai", callbacks: req, url: "wss://api.example.com/v1/realtime-transcription", headers: { Authorization: `Bearer ${apiKey}` }, onMessage: (event, transport) => { if (event.type === "session.created") { transport.sendJson({ type: "session.update" }); transport.markReady(); return; } if (event.type === "transcript.final") { req.onTranscript?.(event.text); } }, sendAudio: (audio, transport) => { transport.sendJson({ type: "audio.append", audio: audio.toString("base64"), }); }, onClose: (transport) => { transport.sendJson({ type: "audio.end" }); }, }); },});Çok parçalı sesi POST ile gönderen toplu STT sağlayıcıları,
openclaw/plugin-sdk/provider-http içindeki
buildAudioTranscriptionFormData(...) yardımcısını kullanmalıdır. Yardımcı,
uyumlu transkripsiyon API'leri için M4A tarzı bir dosya adına ihtiyaç
duyan AAC yüklemeleri dahil olmak üzere yükleme dosya adlarını normalleştirir.
Gerçek zamanlı ses
api.registerRealtimeVoiceProvider({ id: "acme-ai", label: "Acme Realtime Voice", capabilities: { transports: ["gateway-relay"], inputAudioFormats: [{ encoding: "pcm16", sampleRateHz: 24000, channels: 1 }], outputAudioFormats: [{ encoding: "pcm16", sampleRateHz: 24000, channels: 1 }], supportsBargeIn: true, handlesInputAudioBargeIn: true, supportsToolCalls: true, }, isConfigured: ({ providerConfig }) => Boolean(providerConfig.apiKey), createBridge: (req) => ({ // Set this only if the provider accepts multiple tool responses for // one call, for example an immediate "working" response followed by // the final result. supportsToolResultContinuation: false, connect: async () => {}, sendAudio: () => {}, setMediaTimestamp: () => {}, handleBargeIn: () => {}, submitToolResult: () => {}, acknowledgeMark: () => {}, close: () => {}, isConnected: () => true, }),});talk.catalog öğesinin tarayıcı ve yerel Talk istemcilerine geçerli
modları, aktarımları, ses biçimlerini ve özellik bayraklarını sunabilmesi
için capabilities bildirin. Bir aktarım, bir kişinin asistanın ses
oynatımını kestiğini algılayabiliyorsa ve sağlayıcı etkin ses yanıtını
kısaltmayı veya temizlemeyi destekliyorsa handleBargeIn uygulayın.
submitToolResult, eşzamanlı gönderim için void veya sağlayıcı
köprüsünün sunabileceği eşzamansız bir tamamlanma sınırı için
Promise<void> döndürebilir. Gateway aktarma oturumları, nihai sonucu
onaylamadan veya bağlantılı çalıştırmayı temizlemeden önce bu sözü
bekler; gönderim başarısız olduğunda sözü reddedin.
Sağlayıcı options.suppressResponse seçeneğine uyamıyorsa
supportsToolResultSuppression: false ayarlayın. OpenClaw böylece
dahili zorunlu danışma ve iptal sonuçlarında bastırmadan kaçınır ve
sessizce yanıt başlatmak yerine doğrudan bastırılmış sonuç isteklerini
reddeder. createRealtimeVoiceBridgeSession tüketicileri de benzer
şekilde onToolCall içinden bir söz döndürebilir; eşzamanlı fırlatmalar
ve reddetmeler oturumun onError geri çağrısına yönlendirilir.
handlesInputAudioBargeIn seçeneğini yalnızca sağlayıcı VAD'si,
onClearAudio("barge-in") çağrısıyla bir kesintiyi doğruladığında
ayarlayın. Bayrağı belirtmeyen sağlayıcılar OpenClaw'ın yerel giriş sesi
yedek algılamasını kullanır.
Medya anlama
api.registerMediaUnderstandingProvider({ id: "acme-ai", capabilities: ["image", "audio"], describeImage: async (req) => ({ text: "A photo of..." }), transcribeAudio: async (req) => ({ text: "Transcript..." }),});Kimlik bilgilerini kasıtlı olarak gerektirmeyen yerel veya kendi
barındırılan medya sağlayıcıları resolveAuth sunabilir ve
kind: "none" döndürebilir. OpenClaw, açıkça katılım sağlamayan
sağlayıcılar için normal kimlik doğrulama geçidini korumaya devam eder.
Mevcut sağlayıcılar req.apiKey okumayı sürdürebilir; yeni sağlayıcılar
req.auth seçeneğini tercih etmelidir.
api.registerMediaUnderstandingProvider({ id: "local-audio", capabilities: ["audio"], resolveAuth: () => ({ kind: "none", source: "local-audio plugin no-auth", }), transcribeAudio: async (req) => ({ text: "Transcript..." }),});Gömmeler
api.registerEmbeddingProvider({ id: "acme-ai", defaultModel: "acme-embed", transport: "remote", authProviderId: "acme-ai", create: async ({ model }) => ({ provider: { id: "acme-ai", model, dimensions: 1536, embed: async (input) => { const text = typeof input === "string" ? input : input.text; return fetchAcmeEmbedding(text); }, embedBatch: async (inputs) => Promise.all( inputs.map((input) => fetchAcmeEmbedding(typeof input === "string" ? input : input.text), ), ), }, }),});Aynı kimliği contracts.embeddingProviders içinde bildirin. Bu,
bellek araması dahil olmak üzere yeniden kullanılabilir vektör üretimi
için genel gömme sözleşmesidir. registerMemoryEmbeddingProvider(...),
mevcut belleğe özgü bağdaştırıcılar için kullanım dışı bırakılmış
uyumluluktur.
Görüntü ve video üretimi
Görüntü ve video yetenekleri mod duyarlı bir yapı kullanır. Görüntü
sağlayıcıları gerekli generate ve edit yetenek bloklarını; video
sağlayıcıları ise generate, imageToVideo ve videoToVideo
bloklarını bildirir. maxInputImages / maxInputVideos /
maxDurationSeconds gibi düz toplu alanlar, dönüştürme modu desteğini
veya devre dışı modları açık biçimde duyurmak için yeterli değildir.
Müzik üretimi de aynı generate / edit kalıbını izler.
api.registerImageGenerationProvider({ id: "acme-ai", label: "Acme Images", capabilities: { generate: { maxCount: 4, supportsSize: true }, edit: { enabled: false }, }, generateImage: async (req) => ({ images: [] }),}); api.registerVideoGenerationProvider({ id: "acme-ai", label: "Acme Video", defaultTimeoutMs: 600_000, models: ["acme-video", "acme-image-video"], capabilities: { generate: { maxVideos: 1, maxDurationSeconds: 10, supportsResolution: true }, imageToVideo: { enabled: true, maxVideos: 1, maxInputImages: 1, maxInputImagesByModel: { "acme/reference-to-video": 9 }, maxDurationSeconds: 5, }, videoToVideo: { enabled: false }, }, catalogByModel: { "acme-image-video": { modes: ["imageToVideo"], capabilities: { imageToVideo: { enabled: true, maxVideos: 1, maxInputImages: 1, resolutions: ["480P", "720P", "1080P"], supportsResolution: true, }, videoToVideo: { enabled: false }, }, }, }, generateVideo: async (req) => ({ videos: [] }),});capabilities her iki sağlayıcı türünde de zorunludur; edit ve video
dönüştürme blokları (imageToVideo, videoToVideo) her zaman açık bir
enabled bayrağı gerektirir.
Listelenen bir modelin statik modları veya yetenekleri sağlayıcı
varsayılanlarından farklıysa catalogByModel kullanın. Bu meta veriler,
sağlayıcı kodunu çağırmadan video_generate action=list ve model
kataloglarının doğru kalmasını sağlar. İstek zamanındaki yetenek arama
ve uygulama işlemleri yine resolveModelCapabilities ve
generateVideo içinde yer alır; mümkün olduğunda her iki yol için de
aynı yetenek sabitini yeniden kullanın.
Web getirme ve arama
api.registerWebFetchProvider({ id: "acme-ai-fetch", label: "Acme Fetch", hint: "Fetch pages through Acme's rendering backend.", envVars: ["ACME_FETCH_API_KEY"], placeholder: "acme-...", signupUrl: "https://acme.example.com/fetch", credentialPath: "plugins.entries.acme.config.webFetch.apiKey", getCredentialValue: (fetchConfig) => fetchConfig?.acme?.apiKey, setCredentialValue: (fetchConfigTarget, value) => { const acme = (fetchConfigTarget.acme ??= {}); acme.apiKey = value; }, createTool: () => ({ description: "Fetch a page through Acme Fetch.", parameters: {}, execute: async (args) => ({ content: [] }), }),}); api.registerWebSearchProvider({ id: "acme-ai-search", label: "Acme Search", hint: "Search the web through Acme's search backend.", envVars: ["ACME_SEARCH_API_KEY"], placeholder: "acme-...", signupUrl: "https://acme.example.com/search", credentialPath: "plugins.entries.acme.config.webSearch.apiKey", getCredentialValue: (searchConfig) => searchConfig?.acme?.apiKey, setCredentialValue: (searchConfigTarget, value) => { const acme = (searchConfigTarget.acme ??= {}); acme.apiKey = value; }, createTool: () => ({ description: "Search the web through Acme Search.", parameters: {}, execute: async (args) => ({ content: [] }), }),});Her iki sağlayıcı türü de aynı kimlik bilgisi bağlantı yapısını
paylaşır: hint, envVars, placeholder, signupUrl,
credentialPath, getCredentialValue, setCredentialValue ve
createTool alanlarının tümü zorunludur.
Test
Adım 6: Test
import { describe, it, expect } from "vitest";// Export your provider config object from index.ts or a dedicated fileimport { 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'da yayımlama
Sağlayıcı plugin'leri diğer tüm harici kod plugin'leriyle aynı şekilde yayımlanır:
clawhub package publish your-org/your-plugin --dry-runclawhub package publish your-org/your-pluginclawhub skill publish <path>, bir plugin paketi değil, bir skill klasörü
yayımlamak için kullanılan farklı bir komuttur; burada kullanmayın.
Dosya yapısı
<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)Katalog sırası referansı
catalog.order, kataloğunuzun yerleşik sağlayıcılara göre ne zaman
birleştirileceğini denetler:
| Sıra | Zaman | Kullanım alanı |
|---|---|---|
simple |
İlk geçiş | Yalnızca API anahtarı kullanan sağlayıcılar |
profile |
simple sonrası | Kimlik doğrulama profillerine bağlı sağlayıcılar |
paired |
profile sonrası | Birbiriyle ilişkili birden fazla girdiyi sentezleme |
late |
Son geçiş | Mevcut sağlayıcıları geçersiz kılma (çakışmada kazanır) |
Sonraki adımlar
- Kanal Pluginleri - Plugininiz ayrıca bir kanal sağlıyorsa
- SDK Çalışma Zamanı -
api.runtimeyardımcıları (TTS, arama, alt ajan) - SDK'ya Genel Bakış - alt yol içe aktarımlarının tam başvuru kaynağı
- Plugin İç Yapısı - kanca ayrıntıları ve paketlenmiş örnekler