Plugin-Interna
Dies ist die tiefgehende Architektur-Referenz. Praktische Anleitungen findest du hier:
- Plugins installieren und verwenden — Benutzerhandbuch
- Erste Schritte — erstes Plugin-Tutorial
- Channel-Plugins — einen Messaging-Kanal erstellen
- Provider-Plugins — einen Modell-Provider erstellen
- SDK-Überblick — Import-Map und Registrierungs-API
Öffentliches Fähigkeitsmodell
Fähigkeiten sind das öffentliche Modell für native Plugins innerhalb von OpenClaw. Jedes native OpenClaw-Plugin registriert sich für einen oder mehrere Fähigkeitstypen:| Fähigkeit | Registrierungsverfahren | Beispiel-Plugins |
|---|---|---|
| Textinferenz | api.registerProvider(...) | openai, anthropic |
| CLI-Inferenz-Backend | api.registerCliBackend(...) | openai, anthropic |
| Speech | api.registerSpeechProvider(...) | elevenlabs, microsoft |
| Echtzeit-Transkription | api.registerRealtimeTranscriptionProvider(...) | openai |
| Echtzeit-Stimme | api.registerRealtimeVoiceProvider(...) | openai |
| Medienverständnis | api.registerMediaUnderstandingProvider(...) | openai, google |
| Bildgenerierung | api.registerImageGenerationProvider(...) | openai, google, fal, minimax |
| Videogenerierung | api.registerVideoGenerationProvider(...) | qwen |
| Web-Abruf | api.registerWebFetchProvider(...) | firecrawl |
| Websuche | api.registerWebSearchProvider(...) | google |
| Channel / Messaging | api.registerChannel(...) | msteams, matrix |
Haltung zur externen Kompatibilität
Das Fähigkeitsmodell ist im Core verankert und wird heute von gebündelten/nativen Plugins verwendet, aber für die Kompatibilität externer Plugins brauchen wir weiterhin eine höhere Hürde als „es wird exportiert, also ist es eingefroren“. Aktuelle Leitlinien:- bestehende externe Plugins: Hook-basierte Integrationen funktionsfähig halten; das gilt als Kompatibilitäts-Basis
- neue gebündelte/native Plugins: explizite Fähigkeitsregistrierung gegenüber vendor-spezifischen Direkteingriffen oder neuen reinen Hook-Designs bevorzugen
- externe Plugins, die Fähigkeitsregistrierung übernehmen: erlaubt, aber fähigkeitsspezifische Helper-Oberflächen als weiterentwickelbar behandeln, sofern die Dokumentation einen Vertrag nicht ausdrücklich als stabil markiert
- APIs zur Fähigkeitsregistrierung sind die beabsichtigte Richtung
- alte Hooks bleiben während des Übergangs der sicherste Pfad ohne Inkompatibilitäten für externe Plugins
- exportierte Helper-Subpaths sind nicht alle gleichwertig; bevorzuge den schmalen dokumentierten Vertrag, nicht zufällig exportierte Helper
Plugin-Formen
OpenClaw klassifiziert jedes geladene Plugin anhand seines tatsächlichen Registrierungsverhaltens in eine Form, nicht nur anhand statischer Metadaten:- plain-capability — registriert genau einen Fähigkeitstyp (zum Beispiel ein reines Provider-Plugin wie
mistral) - hybrid-capability — registriert mehrere Fähigkeitstypen (zum Beispiel besitzt
openaiTextinferenz, Speech, Medienverständnis und Bildgenerierung) - hook-only — registriert nur Hooks (typisiert oder benutzerdefiniert), keine Fähigkeiten, Tools, Befehle oder Dienste
- non-capability — registriert Tools, Befehle, Dienste oder Routen, aber keine Fähigkeiten
openclaw plugins inspect <id>, um die Form und Aufschlüsselung der Fähigkeiten eines Plugins zu sehen. Details findest du in der CLI-Referenz.
Alte Hooks
Der Hookbefore_agent_start bleibt als Kompatibilitätspfad für reine Hook-Plugins unterstützt. Alte reale Plugins sind weiterhin davon abhängig.
Richtung:
- funktionsfähig halten
- als alt dokumentieren
- für Arbeit an Modell-/Provider-Überschreibungen
before_model_resolvebevorzugen - für Prompt-Mutationen
before_prompt_buildbevorzugen - erst entfernen, wenn die reale Nutzung sinkt und Fixture-Abdeckung die Sicherheit der Migration belegt
Kompatibilitätssignale
Wenn duopenclaw doctor oder openclaw plugins inspect <id> ausführst, kannst du eines dieser Labels sehen:
| Signal | Bedeutung |
|---|---|
| config valid | Konfiguration wird korrekt geparst und Plugins werden aufgelöst |
| compatibility advisory | Plugin verwendet ein unterstütztes, aber älteres Muster (z. B. hook-only) |
| legacy warning | Plugin verwendet before_agent_start, das veraltet ist |
| hard error | Konfiguration ist ungültig oder Plugin konnte nicht geladen werden |
hook-only noch before_agent_start führen heute zum Ausfall deines Plugins — hook-only ist nur ein Hinweis, und before_agent_start löst nur eine Warnung aus. Diese Signale erscheinen auch in openclaw status --all und openclaw plugins doctor.
Architekturüberblick
Das Plugin-System von OpenClaw hat vier Ebenen:- Manifest + Discovery
OpenClaw findet Kandidaten-Plugins aus konfigurierten Pfaden, Workspace-Wurzeln, globalen Erweiterungswurzeln und gebündelten Erweiterungen. Discovery liest zuerst native
openclaw.plugin.json-Manifeste sowie unterstützte Bundle-Manifeste. - Aktivierung + Validierung Der Core entscheidet, ob ein entdecktes Plugin aktiviert, deaktiviert, blockiert oder für einen exklusiven Slot wie Memory ausgewählt wird.
- Laufzeitladen Native OpenClaw-Plugins werden im selben Prozess über jiti geladen und registrieren Fähigkeiten in einer zentralen Registry. Kompatible Bundles werden in Registry-Einträge normalisiert, ohne Laufzeitcode zu importieren.
- Nutzung der Oberflächen Der Rest von OpenClaw liest die Registry, um Tools, Channels, Provider-Setup, Hooks, HTTP-Routen, CLI-Befehle und Dienste bereitzustellen.
- Parse-Zeit-Metadaten stammen aus
registerCli(..., { descriptors: [...] }) - das eigentliche Plugin-CLI-Modul kann lazy bleiben und sich beim ersten Aufruf registrieren
- Discovery und Konfigurationsvalidierung sollten auf Basis von Manifest-/Schema-Metadaten funktionieren, ohne Plugin-Code auszuführen
- natives Laufzeitverhalten kommt aus dem Pfad
register(api)des Plugin-Moduls
Channel-Plugins und das gemeinsame Message-Tool
Channel-Plugins müssen für normale Chat-Aktionen kein separates Send/Edit/React-Tool registrieren. OpenClaw behält ein gemeinsamesmessage-Tool im Core, und Channel-Plugins besitzen die channelspezifische Discovery und Ausführung dahinter.
Die aktuelle Grenze ist:
- der Core besitzt den gemeinsamen
message-Tool-Host, Prompt-Verdrahtung, Session-/Thread-Buchführung und Ausführungs-Dispatch - Channel-Plugins besitzen scoped Action-Discovery, Capability-Discovery und etwaige channelspezifische Schema-Fragmente
- Channel-Plugins besitzen die providerspezifische Grammatik für Session-Konversationen, also zum Beispiel wie Konversations-IDs Thread-IDs codieren oder von übergeordneten Konversationen erben
- Channel-Plugins führen die endgültige Aktion über ihren Action-Adapter aus
ChannelMessageActionAdapter.describeMessageTool(...). Dieser einheitliche Discovery-Aufruf erlaubt es einem Plugin, seine sichtbaren Aktionen, Fähigkeiten und Schema-Beiträge gemeinsam zurückzugeben, sodass diese Teile nicht auseinanderlaufen.
Der Core übergibt den Laufzeit-Scope in diesen Discovery-Schritt. Wichtige Felder sind unter anderem:
accountIdcurrentChannelIdcurrentThreadTscurrentMessageIdsessionKeysessionIdagentId- vertrauenswürdige eingehende
requesterSenderId
message-Tool zu hart zu codieren.
Deshalb bleiben Änderungen am Embedded-Runner-Routing Plugin-Arbeit: Der Runner ist dafür verantwortlich, die aktuelle Chat-/Session-Identität an die Plugin-Discovery-Grenze weiterzugeben, damit das gemeinsame message-Tool für den aktuellen Zug die richtige plugin-eigene Oberfläche bereitstellt.
Für channel-eigene Ausführungs-Helper sollten gebündelte Plugins die Ausführungs-Laufzeit in ihren eigenen Erweiterungsmodulen behalten. Der Core besitzt nicht länger die Message-Action-Laufzeiten für Discord, Slack, Telegram oder WhatsApp unter src/agents/tools. Wir veröffentlichen keine separaten plugin-sdk/*-action-runtime-Subpaths, und gebündelte Plugins sollten ihren eigenen lokalen Laufzeitcode direkt aus ihren erweiterungseigenen Modulen importieren.
Dieselbe Grenze gilt allgemein für provider-benannte SDK-Übergänge: Der Core sollte keine channelspezifischen Convenience-Barrels für Slack, Discord, Signal, WhatsApp oder ähnliche Erweiterungen importieren. Wenn der Core ein Verhalten benötigt, sollte er entweder das plugin-eigene api.ts / runtime-api.ts-Barrel des gebündelten Plugins verwenden oder den Bedarf in eine schmale generische Fähigkeit im gemeinsamen SDK überführen.
Speziell für Umfragen gibt es zwei Ausführungspfade:
outbound.sendPollist die gemeinsame Basis für Channels, die zum gemeinsamen Umfragemodell passenactions.handleAction("poll")ist der bevorzugte Pfad für channelspezifische Umfragesemantik oder zusätzliche Umfrageparameter
Modell der Fähigkeitszuständigkeit
OpenClaw behandelt ein natives Plugin als Zuständigkeitsgrenze für ein Unternehmen oder ein Feature, nicht als Sammelsurium unverbundener Integrationen. Das bedeutet:- ein Unternehmens-Plugin sollte in der Regel alle OpenClaw-bezogenen Oberflächen dieses Unternehmens besitzen
- ein Feature-Plugin sollte in der Regel die vollständige von ihm eingeführte Feature-Oberfläche besitzen
- Channels sollten gemeinsame Core-Fähigkeiten verwenden, statt Provider-Verhalten ad hoc neu zu implementieren
- das gebündelte Plugin
openaibesitzt das OpenAI-Modell-Provider-Verhalten und das OpenAI-Verhalten für Speech + Echtzeit-Stimme + Medienverständnis + Bildgenerierung - das gebündelte Plugin
elevenlabsbesitzt das ElevenLabs-Speech-Verhalten - das gebündelte Plugin
microsoftbesitzt das Microsoft-Speech-Verhalten - das gebündelte Plugin
googlebesitzt das Google-Modell-Provider-Verhalten sowie Google-Medienverständnis + Bildgenerierung + Websuche - das gebündelte Plugin
firecrawlbesitzt das Firecrawl-Web-Abruf-Verhalten - die gebündelten Plugins
minimax,mistral,moonshotundzaibesitzen ihre Backends für Medienverständnis - das gebündelte Plugin
qwenbesitzt das Qwen-Text-Provider-Verhalten sowie Medienverständnis und Videogenerierung - das Plugin
voice-callist ein Feature-Plugin: Es besitzt Call-Transport, Tools, CLI, Routen und Twilio-Media-Stream-Bridging, verwendet aber gemeinsame Fähigkeiten für Speech sowie Echtzeit-Transkription und Echtzeit-Stimme, statt Vendor-Plugins direkt zu importieren
- OpenAI lebt in einem Plugin, auch wenn es Textmodelle, Speech, Bilder und künftig Video umfasst
- ein anderer Vendor kann dasselbe für seinen eigenen Bereich tun
- Channels ist es egal, welches Vendor-Plugin den Provider besitzt; sie verwenden den gemeinsamen vom Core bereitgestellten Fähigkeitsvertrag
- Plugin = Zuständigkeitsgrenze
- Fähigkeit = Core-Vertrag, den mehrere Plugins implementieren oder verwenden können
- die fehlende Fähigkeit im Core definieren
- sie typisiert über die Plugin-API/Laufzeit bereitstellen
- Channels/Features gegen diese Fähigkeit verdrahten
- Vendor-Plugins Implementierungen registrieren lassen
Fähigkeits-Schichtung
Verwende dieses mentale Modell, wenn du entscheidest, wo Code hingehört:- Core-Fähigkeitsschicht: gemeinsame Orchestrierung, Richtlinien, Fallback, Regeln zum Konfigurationszusammenführen, Zustellungssemantik und typisierte Verträge
- Vendor-Plugin-Schicht: vendor-spezifische APIs, Auth, Modellkataloge, Sprachsynthese, Bildgenerierung, künftige Video-Backends, Usage-Endpunkte
- Channel-/Feature-Plugin-Schicht: Integration von Slack/Discord/voice-call/usw., die Core-Fähigkeiten verwendet und an einer Oberfläche bereitstellt
- der Core besitzt Richtlinien für TTS zur Antwortzeit, Fallback-Reihenfolge, Präferenzen und Channel-Zustellung
openai,elevenlabsundmicrosoftbesitzen die Synthese-Implementierungenvoice-callverwendet den Telephony-TTS-Laufzeit-Helper
Beispiel für ein Unternehmens-Plugin mit mehreren Fähigkeiten
Ein Unternehmens-Plugin sollte sich von außen kohärent anfühlen. Wenn OpenClaw gemeinsame Verträge für Modelle, Speech, Echtzeit-Transkription, Echtzeit-Stimme, Medienverständnis, Bildgenerierung, Videogenerierung, Web-Abruf und Websuche hat, kann ein Vendor alle seine Oberflächen an einer Stelle besitzen:- ein Plugin besitzt die Vendor-Oberfläche
- der Core besitzt weiterhin die Fähigkeitsverträge
- Channels und Feature-Plugins verwenden
api.runtime.*-Helper, nicht Vendor-Code - Vertragstests können überprüfen, dass das Plugin die Fähigkeiten registriert hat, für die es vorgibt zuständig zu sein
Fähigkeitsbeispiel: Videoverständnis
OpenClaw behandelt Bild-/Audio-/Videoverständnis bereits als eine gemeinsame Fähigkeit. Dasselbe Zuständigkeitsmodell gilt auch dort:- der Core definiert den Vertrag für Medienverständnis
- Vendor-Plugins registrieren je nach Anwendbarkeit
describeImage,transcribeAudiounddescribeVideo - Channels und Feature-Plugins verwenden das gemeinsame Core-Verhalten, statt direkt Vendor-Code anzubinden
api.registerVideoGenerationProvider(...).
Du brauchst eine konkrete Einführungs-Checkliste? Siehe Capability Cookbook.
Verträge und Durchsetzung
Die Plugin-API-Oberfläche ist bewusst typisiert und inOpenClawPluginApi zentralisiert. Dieser Vertrag definiert die unterstützten Registrierungspunkte und die Laufzeit-Helper, auf die sich ein Plugin verlassen darf.
Warum das wichtig ist:
- Plugin-Autoren erhalten einen stabilen internen Standard
- der Core kann doppelte Zuständigkeiten zurückweisen, z. B. wenn zwei Plugins dieselbe Provider-ID registrieren
- beim Start können umsetzbare Diagnosen für fehlerhafte Registrierungen angezeigt werden
- Vertragstests können Zuständigkeiten gebündelter Plugins durchsetzen und stilles Abdriften verhindern
- Durchsetzung bei der Laufzeit-Registrierung Die Plugin-Registry validiert Registrierungen beim Laden der Plugins. Beispiele: doppelte Provider-IDs, doppelte Speech-Provider-IDs und fehlerhafte Registrierungen erzeugen Plugin-Diagnosen statt undefiniertem Verhalten.
- Vertragstests Gebündelte Plugins werden während Testläufen in Vertrags-Registries erfasst, sodass OpenClaw Zuständigkeiten explizit prüfen kann. Heute wird das für Modell-Provider, Speech-Provider, Websuch-Provider und die Zuständigkeit gebündelter Registrierungen verwendet.
Was in einen Vertrag gehört
Gute Plugin-Verträge sind:- typisiert
- klein
- fähigkeitsspezifisch
- vom Core besessen
- von mehreren Plugins wiederverwendbar
- von Channels/Features ohne Vendor-Wissen verwendbar
- vendorspezifische Richtlinien, die im Core versteckt sind
- einmalige Plugin-Notausgänge, die die Registry umgehen
- Channel-Code, der direkt in eine Vendor-Implementierung greift
- ad hoc-Laufzeitobjekte, die nicht Teil von
OpenClawPluginApioderapi.runtimesind
Ausführungsmodell
Native OpenClaw-Plugins laufen im selben Prozess wie das Gateway. Sie sind nicht sandboxed. Ein geladenes natives Plugin hat dieselbe vertrauensbezogene Prozessgrenze wie Core-Code. Folgen:- ein natives Plugin kann Tools, Netzwerk-Handler, Hooks und Dienste registrieren
- ein Fehler in einem nativen Plugin kann das Gateway zum Absturz bringen oder destabilisieren
- ein bösartiges natives Plugin entspricht beliebiger Codeausführung innerhalb des OpenClaw-Prozesses
@openclaw/<id> oder ein genehmigtes typisiertes Suffix wie -provider, -plugin, -speech, -sandbox oder -media-understanding, wenn das Paket bewusst eine engere Plugin-Rolle bereitstellt.
Wichtiger Vertrauenshinweis:
plugins.allowvertraut Plugin-IDs, nicht der Herkunft des Quellcodes.- Ein Workspace-Plugin mit derselben ID wie ein gebündeltes Plugin überschattet absichtlich die gebündelte Kopie, wenn dieses Workspace-Plugin aktiviert bzw. auf der Allowlist steht.
- Das ist normal und nützlich für lokale Entwicklung, Patch-Tests und Hotfixes.
Exportgrenze
OpenClaw exportiert Fähigkeiten, nicht Komfort-Implementierungen. Die Fähigkeitsregistrierung soll öffentlich bleiben. Nicht-vertragliche Helper-Exporte sollten reduziert werden:- Helper-Subpaths, die spezifisch für gebündelte Plugins sind
- Laufzeit-Plumbing-Subpaths, die nicht als öffentliche API gedacht sind
- vendorspezifische Convenience-Helper
- Setup-/Onboarding-Helper, die Implementierungsdetails sind
plugin-sdk/feishu, plugin-sdk/feishu-setup, plugin-sdk/zalo, plugin-sdk/zalo-setup und mehrere plugin-sdk/matrix*-Übergänge. Behandle diese als reservierte, implementierungsbezogene Exporte und nicht als empfohlenes SDK-Muster für neue Drittanbieter-Plugins.
Ladepipeline
Beim Start führt OpenClaw ungefähr Folgendes aus:- Kandidaten-Plugin-Wurzeln entdecken
- native oder kompatible Bundle-Manifeste und Paketmetadaten lesen
- unsichere Kandidaten ablehnen
- Plugin-Konfiguration normalisieren (
plugins.enabled,allow,deny,entries,slots,load.paths) - Aktivierung für jeden Kandidaten festlegen
- aktivierte native Module über jiti laden
- native Hooks
register(api)(oderactivate(api)— ein alter Alias) aufrufen und Registrierungen in der Plugin-Registry sammeln - die Registry an Befehls-/Laufzeit-Oberflächen bereitstellen
activate ist ein alter Alias für register — der Loader löst auf, welches vorhanden ist (def.register ?? def.activate), und ruft es an derselben Stelle auf. Alle gebündelten Plugins verwenden register; bevorzuge register für neue Plugins.Manifest-First-Verhalten
Das Manifest ist die Quelle der Wahrheit für die Control Plane. OpenClaw nutzt es, um:- das Plugin zu identifizieren
- deklarierte Channels/Skills/Konfigurationsschema oder Bundle-Fähigkeiten zu entdecken
plugins.entries.<id>.configzu validieren- Labels/Platzhalter in der Control UI zu ergänzen
- Installations-/Katalog-Metadaten anzuzeigen
Was der Loader cached
OpenClaw hält kurze prozessinterne Caches für:- Discovery-Ergebnisse
- Daten der Manifest-Registry
- geladene Plugin-Registries
- Setze
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1oderOPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1, um diese Caches zu deaktivieren. - Passe die Cache-Fenster mit
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MSundOPENCLAW_PLUGIN_MANIFEST_CACHE_MSan.
Registry-Modell
Geladene Plugins verändern nicht direkt beliebige globale Core-Zustände. Sie registrieren sich in einer zentralen Plugin-Registry. Die Registry verfolgt:- Plugin-Einträge (Identität, Quelle, Ursprung, Status, Diagnosen)
- Tools
- alte Hooks und typisierte Hooks
- Channels
- Provider
- Gateway-RPC-Handler
- HTTP-Routen
- CLI-Registrar-Funktionen
- Hintergrunddienste
- plugin-eigene Befehle
- Plugin-Modul -> Registrierung in der Registry
- Core-Laufzeit -> Nutzung der Registry
Callbacks für Konversations-Bindung
Plugins, die eine Konversation binden, können reagieren, wenn eine Genehmigung aufgelöst wurde. Verwendeapi.onConversationBindingResolved(...), um einen Callback zu erhalten, nachdem ein Bindungsantrag genehmigt oder abgelehnt wurde:
status:"approved"oder"denied"decision:"allow-once","allow-always"oder"deny"binding: die aufgelöste Bindung für genehmigte Anfragenrequest: die ursprüngliche Anfragezusammenfassung, Detach-Hinweis, Sender-ID und Konversationsmetadaten
Provider-Laufzeit-Hooks
Provider-Plugins haben jetzt zwei Ebenen:- Manifest-Metadaten:
providerAuthEnvVarsfür kostengünstige Env-Auth-Ermittlung vor dem Laufzeitladen sowieproviderAuthChoicesfür kostengünstige Labels für Onboarding/Auth-Auswahl und CLI-Flag-Metadaten vor dem Laufzeitladen - Hooks zur Konfigurationszeit:
catalog/ altesdiscoverysowieapplyConfigDefaults - Laufzeit-Hooks:
normalizeModelId,normalizeTransport,normalizeConfig,applyNativeStreamingUsageCompat,resolveConfigApiKey,resolveSyntheticAuth,shouldDeferSyntheticProfileAuth,resolveDynamicModel,prepareDynamicModel,normalizeResolvedModel,contributeResolvedModelCompat,capabilities,normalizeToolSchemas,inspectToolSchemas,resolveReasoningOutputMode,prepareExtraParams,createStreamFn,wrapStreamFn,resolveTransportTurnState,resolveWebSocketSessionPolicy,formatApiKey,refreshOAuth,buildAuthDoctorHint,matchesContextOverflowError,classifyFailoverReason,isCacheTtlEligible,buildMissingAuthMessage,suppressBuiltInModel,augmentModelCatalog,isBinaryThinking,supportsXHighThinking,resolveDefaultThinkingLevel,isModernModelRef,prepareRuntimeAuth,resolveUsageAuth,fetchUsageSnapshot,createEmbeddingProvider,buildReplayPolicy,sanitizeReplayHistory,validateReplayTurns,onModelSelected
providerAuthEnvVars, wenn der Provider env-basierte Zugangsdaten hat, die generische Auth-/Status-/Modellpicker-Pfade sehen sollen, ohne die Plugin-Laufzeit zu laden. Verwende das Manifest-Feld providerAuthChoices, wenn Onboarding-/Auth-Choice-CLI-Oberflächen die Choice-ID, Gruppenlabels und einfache One-Flag-Auth-Verdrahtung des Providers kennen sollen, ohne die Provider-Laufzeit zu laden. Behalte Provider-Laufzeit-envVars für operatororientierte Hinweise wie Onboarding-Labels oder Setup-Variablen für OAuth-Client-ID/Client-Secret.
Hook-Reihenfolge und Verwendung
Für Modell-/Provider-Plugins ruft OpenClaw Hooks ungefähr in dieser Reihenfolge auf. Die Spalte „Wann verwenden“ ist die schnelle Entscheidungshilfe.| # | Hook | Was er tut | Wann verwenden |
|---|---|---|---|
| 1 | catalog | Provider-Konfiguration während der Generierung von models.json in models.providers veröffentlichen | Der Provider besitzt einen Katalog oder Standardwerte für Base-URLs |
| 2 | applyConfigDefaults | globale providerspezifische Konfigurationsstandardwerte während der Materialisierung anwenden | Standardwerte hängen von Auth-Modus, Env oder Semantik der Provider-Modellfamilie ab |
| — | (integrierte Modellsuche) | OpenClaw versucht zuerst den normalen Registry-/Katalogpfad | (kein Plugin-Hook) |
| 3 | normalizeModelId | alte oder Preview-Aliasse für Modell-IDs vor der Suche normalisieren | Der Provider besitzt Alias-Bereinigung vor der kanonischen Modellauflösung |
| 4 | normalizeTransport | providerspezifische api / baseUrl vor der generischen Modellerstellung normalisieren | Der Provider besitzt Transport-Bereinigung für benutzerdefinierte Provider-IDs in derselben Transportfamilie |
| 5 | normalizeConfig | models.providers.<id> vor Laufzeit-/Provider-Auflösung normalisieren | Der Provider benötigt Konfigurationsbereinigung, die beim Plugin liegen sollte; gebündelte Google-Familien-Helper stützen außerdem unterstützte Google-Konfigurationseinträge ab |
| 6 | applyNativeStreamingUsageCompat | native Streaming-Usage-Kompatibilitäts-Umschreibungen auf Konfigurations-Provider anwenden | Der Provider braucht endpointgesteuerte Korrekturen für native Streaming-Usage-Metadaten |
| 7 | resolveConfigApiKey | Env-Marker-Auth für Konfigurations-Provider vor dem Laden der Laufzeit-Auth auflösen | Der Provider besitzt providerspezifische Auflösung von Env-Marker-API-Keys; amazon-bedrock hat hier außerdem einen integrierten AWS-Env-Marker-Resolver |
| 8 | resolveSyntheticAuth | lokale/self-hosted oder konfigurationsbasierte Auth anzeigen, ohne Klartext zu persistieren | Der Provider kann mit einem synthetischen/lokalen Credential-Marker arbeiten |
| 9 | shouldDeferSyntheticProfileAuth | gespeicherte synthetische Profil-Platzhalter hinter Env-/konfigurationsgestützter Auth zurückstufen | Der Provider speichert synthetische Platzhalterprofile, die keinen Vorrang haben sollten |
| 10 | resolveDynamicModel | synchroner Fallback für provider-eigene Modell-IDs, die noch nicht in der lokalen Registry sind | Der Provider akzeptiert beliebige Upstream-Modell-IDs |
| 11 | prepareDynamicModel | asynchrones Warm-up, danach läuft resolveDynamicModel erneut | Der Provider benötigt Netzwerk-Metadaten, bevor unbekannte IDs aufgelöst werden können |
| 12 | normalizeResolvedModel | endgültige Umschreibung, bevor der Embedded Runner das aufgelöste Modell verwendet | Der Provider benötigt Transport-Umschreibungen, verwendet aber weiterhin einen Core-Transport |
| 13 | contributeResolvedModelCompat | Kompatibilitäts-Flags für Vendor-Modelle hinter einem anderen kompatiblen Transport beitragen | Der Provider erkennt seine eigenen Modelle auf Proxy-Transporten, ohne den Provider zu übernehmen |
| 14 | capabilities | providerspezifische Metadaten für Transkripte/Tooling, die von gemeinsamer Core-Logik genutzt werden | Der Provider benötigt Transkript-/Providerfamilien-Sonderfälle |
| 15 | normalizeToolSchemas | Tool-Schemata normalisieren, bevor der Embedded Runner sie sieht | Der Provider benötigt Bereinigung von Schemata für eine Transportfamilie |
| 16 | inspectToolSchemas | providerspezifische Schema-Diagnosen nach der Normalisierung bereitstellen | Der Provider will Keyword-Warnungen anzeigen, ohne dem Core providerspezifische Regeln beizubringen |
| 17 | resolveReasoningOutputMode | nativen oder getaggten Vertrag für den Reasoning-Output auswählen | Der Provider benötigt getaggten Reasoning-/Final-Output statt nativer Felder |
| 18 | prepareExtraParams | Request-Param-Normalisierung vor generischen Stream-Option-Wrappern | Der Provider benötigt Standard-Request-Parameter oder providerspezifische Param-Bereinigung |
| 19 | createStreamFn | den normalen Stream-Pfad vollständig durch einen benutzerdefinierten Transport ersetzen | Der Provider benötigt ein benutzerdefiniertes Wire-Protokoll, nicht nur einen Wrapper |
| 20 | wrapStreamFn | Stream-Wrapper, nachdem generische Wrapper angewendet wurden | Der Provider benötigt Wrapper für Request-Header/Body/Modell-Kompatibilität ohne benutzerdefinierten Transport |
| 21 | resolveTransportTurnState | native Turn-spezifische Transport-Header oder Metadaten anhängen | Der Provider will, dass generische Transporte provider-native Turn-Identität senden |
| 22 | resolveWebSocketSessionPolicy | native WebSocket-Header oder Session-Cool-down-Richtlinien anhängen | Der Provider will, dass generische WS-Transporte Session-Header oder Fallback-Richtlinien abstimmen |
| 23 | formatApiKey | Formatter für Auth-Profile: gespeichertes Profil wird zur Laufzeit-apiKey-Zeichenkette | Der Provider speichert zusätzliche Auth-Metadaten und benötigt eine benutzerdefinierte Laufzeit-Tokenform |
| 24 | refreshOAuth | OAuth-Refresh-Override für benutzerdefinierte Refresh-Endpunkte oder Refresh-Fehler-Richtlinien | Der Provider passt nicht zu den gemeinsamen pi-ai-Refresh-Mechanismen |
| 25 | buildAuthDoctorHint | Reparaturhinweis anhängen, wenn OAuth-Refresh fehlschlägt | Der Provider benötigt providerspezifische Hinweise zur Auth-Reparatur nach einem fehlgeschlagenen Refresh |
| 26 | matchesContextOverflowError | providerspezifische Erkennung für Context-Window-Überlauf | Der Provider hat rohe Overflow-Fehler, die generische Heuristiken übersehen würden |
| 27 | classifyFailoverReason | providerspezifische Klassifizierung des Failover-Grunds | Der Provider kann rohe API-/Transport-Fehler auf Rate-Limit/Überlast/usw. abbilden |
| 28 | isCacheTtlEligible | Prompt-Cache-Richtlinie für Proxy-/Backhaul-Provider | Der Provider braucht proxiespezifisches Cache-TTL-Gating |
| 29 | buildMissingAuthMessage | Ersatz für die generische Recovery-Meldung bei fehlender Auth | Der Provider benötigt einen providerspezifischen Recovery-Hinweis bei fehlender Auth |
| 30 | suppressBuiltInModel | Unterdrückung veralteter Upstream-Modelle plus optionaler benutzerseitiger Fehlerhinweis | Der Provider muss veraltete Upstream-Zeilen ausblenden oder durch einen Vendor-Hinweis ersetzen |
| 31 | augmentModelCatalog | synthetische/endgültige Katalogzeilen nach der Discovery anhängen | Der Provider benötigt synthetische Vorwärtskompatibilitäts-Zeilen in models list und Pickern |
| 32 | isBinaryThinking | Reasoning-Umschalter Ein/Aus für Provider mit binärem Thinking | Der Provider bietet nur binäres Thinking Ein/Aus an |
| 33 | supportsXHighThinking | Unterstützung für xhigh-Reasoning bei ausgewählten Modellen | Der Provider möchte xhigh nur bei einer Teilmenge von Modellen |
| 34 | resolveDefaultThinkingLevel | Standard-/think-Stufe für eine bestimmte Modellfamilie | Der Provider besitzt die Standard-/think-Richtlinie für eine Modellfamilie |
| 35 | isModernModelRef | Matcher für moderne Modelle für Live-Profilfilter und Smoke-Auswahl | Der Provider besitzt die Zuordnung bevorzugter Modelle für Live-/Smoke-Tests |
| 36 | prepareRuntimeAuth | eine konfigurierte Credential unmittelbar vor der Inferenz in das eigentliche Laufzeit-Token/den Schlüssel umwandeln | Der Provider benötigt einen Token-Austausch oder kurzlebige Request-Credentials |
| 37 | resolveUsageAuth | Credentials für Usage/Abrechnung für /usage und verwandte Status-Oberflächen auflösen | Der Provider benötigt benutzerdefiniertes Parsing von Usage-/Quota-Tokens oder andere Usage-Credentials |
| 38 | fetchUsageSnapshot | providerspezifische Usage-/Quota-Snapshots abrufen und normalisieren, nachdem Auth aufgelöst ist | Der Provider benötigt einen providerspezifischen Usage-Endpunkt oder Payload-Parser |
| 39 | createEmbeddingProvider | einen provider-eigenen Embedding-Adapter für Memory/Suche erstellen | Verhalten für Memory-Embeddings gehört zum Provider-Plugin |
| 40 | buildReplayPolicy | eine Replay-Richtlinie zurückgeben, die die Transkriptbehandlung für den Provider steuert | Der Provider benötigt eine benutzerdefinierte Transkript-Richtlinie (z. B. Entfernen von Thinking-Blöcken) |
| 41 | sanitizeReplayHistory | Replay-Historie nach generischer Transkript-Bereinigung umschreiben | Der Provider benötigt providerspezifische Replay-Umschreibungen jenseits gemeinsamer Kompaktierungs-Helper |
| 42 | validateReplayTurns | abschließende Replay-Turn-Validierung oder Umformung vor dem Embedded Runner | Der Provider-Transport benötigt strengere Turn-Validierung nach generischer Bereinigung |
| 43 | onModelSelected | providerspezifische Nebeneffekte nach der Modellauswahl ausführen | Der Provider benötigt Telemetrie oder provider-eigenen Zustand, wenn ein Modell aktiv wird |
normalizeModelId, normalizeTransport und normalizeConfig prüfen zuerst das passende Provider-Plugin und fallen dann auf andere Hook-fähige Provider-Plugins zurück, bis tatsächlich eines die Modell-ID oder den Transport/die Konfiguration ändert. Dadurch bleiben Alias-/Kompatibilitäts-Shims für Provider funktionsfähig, ohne dass der Aufrufer wissen muss, welches gebündelte Plugin für die Umschreibung zuständig ist. Wenn kein Provider-Hook einen unterstützten Google-Familien-Konfigurationseintrag umschreibt, greift weiterhin der gebündelte Google-Konfigurations-Normalizer für diese Kompatibilitäts-Bereinigung.
Wenn der Provider ein vollständig benutzerdefiniertes Wire-Protokoll oder einen benutzerdefinierten Request-Executor benötigt, ist das eine andere Klasse von Erweiterung. Diese Hooks sind für Provider-Verhalten gedacht, das weiterhin auf der normalen Inferenzschleife von OpenClaw läuft.
Provider-Beispiel
Integrierte Beispiele
- Anthropic verwendet
resolveDynamicModel,capabilities,buildAuthDoctorHint,resolveUsageAuth,fetchUsageSnapshot,isCacheTtlEligible,resolveDefaultThinkingLevel,applyConfigDefaults,isModernModelRefundwrapStreamFn, weil es Vorwärtskompatibilität für Claude 4.6, Hinweise für die Provider-Familie, Anleitung zur Auth-Reparatur, Integration des Usage-Endpunkts, Prompt-Cache-Berechtigung, auth-bewusste Konfigurationsstandardwerte, Claude- Standard-/adaptive Thinking-Richtlinien und Anthropic-spezifische Stream-Formung für Beta-Header,/fast/serviceTierundcontext1mbesitzt. - Die Claude-spezifischen Stream-Helper von Anthropic bleiben vorerst im eigenen
öffentlichen Übergang
api.ts/contract-api.tsdes gebündelten Plugins. Diese Paketoberfläche exportiertwrapAnthropicProviderStream,resolveAnthropicBetas,resolveAnthropicFastMode,resolveAnthropicServiceTierund die Low-Level- Wrapper-Builder für Anthropic, statt das generische SDK um die Beta-Header-Regeln eines einzigen Providers zu verbreitern. - OpenAI verwendet
resolveDynamicModel,normalizeResolvedModelundcapabilitiessowiebuildMissingAuthMessage,suppressBuiltInModel,augmentModelCatalog,supportsXHighThinkingundisModernModelRef, weil es Vorwärtskompatibilität für GPT-5.4, die direkte OpenAI- Normalisierungopenai-completions->openai-responses, auth-Hinweise mit Codex-Bezug, Spark-Unterdrückung, synthetische OpenAI-Listenzeilen und die Richtlinien für GPT-5-Thinking / Live-Modelle besitzt; die Stream-Familieopenai-responses-defaultsbesitzt die gemeinsamen nativen OpenAI-Responses-Wrapper für Attributions-Header,/fast/serviceTier, Text-Verbosity, native Codex-Websuche, Formung von Reasoning-Kompatibilitäts-Payloads und Responses-Context-Management. - OpenRouter verwendet
catalogsowieresolveDynamicModelundprepareDynamicModel, weil der Provider pass-through ist und neue Modell-IDs anzeigen kann, bevor der statische Katalog von OpenClaw aktualisiert wurde; es verwendet auchcapabilities,wrapStreamFnundisCacheTtlEligible, um providerspezifische Request-Header, Routing-Metadaten, Reasoning-Patches und Prompt-Cache-Richtlinien aus dem Core herauszuhalten. Seine Replay-Richtlinie stammt aus der Familiepassthrough-gemini, während die Stream-Familieopenrouter-thinkingProxy-Reasoning-Injektion und das Überspringen nicht unterstützter Modelle / vonautobesitzt. - GitHub Copilot verwendet
catalog,auth,resolveDynamicModelundcapabilitiessowieprepareRuntimeAuthundfetchUsageSnapshot, weil es providerspezifischen Device-Login, Fallback-Verhalten bei Modellen, Claude-Transkript-Sonderfälle, einen Austausch GitHub-Token -> Copilot-Token und einen provider-eigenen Usage-Endpunkt benötigt. - OpenAI Codex verwendet
catalog,resolveDynamicModel,normalizeResolvedModel,refreshOAuthundaugmentModelCatalogsowieprepareExtraParams,resolveUsageAuthundfetchUsageSnapshot, weil es weiterhin auf den OpenAI-Transporten des Core läuft, aber seine Transport-/Base-URL-Normalisierung, OAuth-Refresh-Fallback-Richtlinie, Standardwahl des Transports, synthetische Codex-Katalogzeilen und die Integration des ChatGPT-Usage-Endpunkts besitzt; es teilt sich dieselbe Stream-Familieopenai-responses-defaultsmit direktem OpenAI. - Google AI Studio und Gemini CLI OAuth verwenden
resolveDynamicModel,buildReplayPolicy,sanitizeReplayHistory,resolveReasoningOutputMode,wrapStreamFnundisModernModelRef, weil die Replay-Familiegoogle-geminiVorwärtskompatibilitäts-Fallback für Gemini 3.1, native Gemini-Replay-Validierung, Bootstrap-Replay-Bereinigung, getaggten Reasoning-Output-Modus und modernes Modell-Matching besitzt, während die Stream-Familiegoogle-thinkingdie Normalisierung der Gemini-Thinking-Payload besitzt; Gemini CLI OAuth verwendet außerdemformatApiKey,resolveUsageAuthundfetchUsageSnapshotfür Token-Formatierung, Token-Parsing und Verdrahtung des Quota-Endpunkts. - Anthropic Vertex verwendet
buildReplayPolicyüber die Replay-Familieanthropic-by-model, damit Claude-spezifische Replay-Bereinigung auf Claude-IDs begrenzt bleibt statt auf jedenanthropic-messages-Transport. - Amazon Bedrock verwendet
buildReplayPolicy,matchesContextOverflowError,classifyFailoverReasonundresolveDefaultThinkingLevel, weil es Bedrock-spezifische Klassifizierung von Drosselungs-/Not-ready-/Context-Overflow-Fehlern für Anthropic-on-Bedrock-Datenverkehr besitzt; seine Replay-Richtlinie teilt weiterhin denselben nur für Claude geltenden Schutzanthropic-by-model. - OpenRouter, Kilocode, Opencode und Opencode Go verwenden
buildReplayPolicyüber die Replay-Familiepassthrough-gemini, weil sie Gemini- Modelle über OpenAI-kompatible Transporte proxien und daher Thought-Signature-Bereinigung für Gemini benötigen, aber keine native Gemini-Replay-Validierung oder Bootstrap-Umschreibungen. - MiniMax verwendet
buildReplayPolicyüber die Replay-Familiehybrid-anthropic-openai, weil ein Provider sowohl Anthropic-Message- als auch OpenAI-kompatible Semantik besitzt; so bleibt das Entfernen von Thinking-Blöcken nur für Claude auf der Anthropic-Seite erhalten, während der Reasoning- Output-Modus wieder auf nativ überschrieben wird, und die Stream-Familieminimax-fast-modebesitzt Fast-Mode-Modell-Umschreibungen auf dem gemeinsamen Stream-Pfad. - Moonshot verwendet
catalogpluswrapStreamFn, weil es weiterhin den gemeinsamen OpenAI-Transport verwendet, aber providerspezifische Normalisierung der Thinking-Payload benötigt; die Stream-Familiemoonshot-thinkingbildet Konfiguration plus/think-Status auf ihre native Payload für binäres Thinking ab. - Kilocode verwendet
catalog,capabilities,wrapStreamFnundisCacheTtlEligible, weil es providerspezifische Request-Header, Normalisierung der Reasoning-Payload, Gemini-Transkript-Hinweise und Anthropic- Cache-TTL-Gating benötigt; die Stream-Familiekilocode-thinkinghält die Kilo-Thinking-Injektion auf dem gemeinsamen Proxy-Stream-Pfad, währendkilo/autound andere Proxy-Modell-IDs übersprungen werden, die keine expliziten Reasoning-Payloads unterstützen. - Z.AI verwendet
resolveDynamicModel,prepareExtraParams,wrapStreamFn,isCacheTtlEligible,isBinaryThinking,isModernModelRef,resolveUsageAuthundfetchUsageSnapshot, weil es GLM-5-Fallback, Standardwerte fürtool_stream, binäre Thinking-UX, Matching moderner Modelle und sowohl Usage-Auth als auch Quota-Abruf besitzt; die Stream-Familietool-stream-default-onhält den standardmäßig aktiventool_stream-Wrapper aus handgeschriebenem Glue pro Provider heraus. - xAI verwendet
normalizeResolvedModel,normalizeTransport,contributeResolvedModelCompat,prepareExtraParams,wrapStreamFn,resolveSyntheticAuth,resolveDynamicModelundisModernModelRef, weil es die Normalisierung auf nativen xAI-Responses-Transport, Umschreibungen von Grok-Fast-Mode- Aliasen, Standard-tool_stream, Bereinigung von strict-tool / Reasoning-Payload, Wiederverwendung von Fallback-Auth für plugin-eigene Tools, Vorwärtskompatibilitäts- Auflösung von Grok-Modellen und providerspezifische Kompatibilitäts-Patches wie xAI-Tool-Schema- Profil, nicht unterstützte Schema-Keywords, nativesweb_searchund Dekodierung von Tool-Call-Argumenten mit HTML-Entities besitzt. - Mistral, OpenCode Zen und OpenCode Go verwenden nur
capabilities, um Transkript-/Tooling-Sonderfälle aus dem Core herauszuhalten. - Katalog-only-Provider unter den gebündelten Plugins wie
byteplus,cloudflare-ai-gateway,huggingface,kimi-coding,nvidia,qianfan,synthetic,together,venice,vercel-ai-gatewayundvolcengineverwenden nurcatalog. - Qwen verwendet
catalogfür seinen Text-Provider sowie gemeinsame Registrierungen für Medienverständnis und Videogenerierung für seine multimodalen Oberflächen. - MiniMax und Xiaomi verwenden
catalogplus Usage-Hooks, weil ihr/usage- Verhalten dem Plugin gehört, obwohl die Inferenz weiterhin über die gemeinsamen Transporte läuft.
Laufzeit-Helper
Plugins können überapi.runtime auf ausgewählte Core-Helper zugreifen. Für TTS:
textToSpeechgibt die normale Core-TTS-Ausgabe-Payload für Datei-/Sprachnachrichten-Oberflächen zurück.- Verwendet die Core-Konfiguration
messages.ttsund die Providerauswahl. - Gibt PCM-Audiopuffer + Sampling-Rate zurück. Plugins müssen für Provider resamplen/kodieren.
listVoicesist je nach Provider optional. Verwende es für vendor-eigene Voice-Picker oder Setup-Flows.- Stimmenlisten können umfangreichere Metadaten wie Locale, Geschlecht und Personality-Tags für providerbewusste Picker enthalten.
- OpenAI und ElevenLabs unterstützen heute Telephony. Microsoft nicht.
api.registerSpeechProvider(...) registrieren.
- Behalte TTS-Richtlinien, Fallback und Antwortzustellung im Core.
- Verwende Speech-Provider für vendor-eigenes Syntheseverhalten.
- Alte Microsoft-Eingaben vom Typ
edgewerden auf die Provider-IDmicrosoftnormalisiert. - Das bevorzugte Zuständigkeitsmodell ist unternehmensorientiert: Ein Vendor-Plugin kann Text-, Speech-, Bild- und künftige Medien-Provider besitzen, wenn OpenClaw diese Fähigkeitsverträge hinzufügt.
- Behalte Orchestrierung, Fallback, Konfiguration und Channel-Verdrahtung im Core.
- Behalte Vendor-Verhalten im Provider-Plugin.
- Additive Erweiterung sollte typisiert bleiben: neue optionale Methoden, neue optionale Ergebnisfelder, neue optionale Fähigkeiten.
- Videogenerierung folgt bereits demselben Muster:
- der Core besitzt den Fähigkeitsvertrag und den Laufzeit-Helper
- Vendor-Plugins registrieren
api.registerVideoGenerationProvider(...) - Feature-/Channel-Plugins verwenden
api.runtime.videoGeneration.*
api.runtime.mediaUnderstanding.*ist die bevorzugte gemeinsame Oberfläche für Bild-/Audio-/Videoverständnis.- Verwendet die Core-Audiokonfiguration für Medienverständnis (
tools.media.audio) und die Fallback-Reihenfolge der Provider. - Gibt
{ text: undefined }zurück, wenn keine Transkriptionsausgabe erzeugt wird (zum Beispiel bei übersprungenen/nicht unterstützten Eingaben). api.runtime.stt.transcribeAudioFile(...)bleibt als Kompatibilitäts-Alias bestehen.
api.runtime.subagent starten:
providerundmodelsind optionale Überschreibungen pro Lauf, keine dauerhaften Sitzungsänderungen.- OpenClaw berücksichtigt diese Überschreibungsfelder nur für vertrauenswürdige Aufrufer.
- Für plugin-eigene Fallback-Läufe müssen Operatoren dies mit
plugins.entries.<id>.subagent.allowModelOverride: trueaktiv erlauben. - Verwende
plugins.entries.<id>.subagent.allowedModels, um vertrauenswürdige Plugins auf bestimmte kanonische Zieleprovider/modelzu beschränken, oder"*", um jedes Ziel ausdrücklich zu erlauben. - Läufe von Subagents untrusted Plugins funktionieren weiterhin, aber Überschreibungsanfragen werden abgelehnt, statt stillschweigend auf einen Fallback auszuweichen.
api.registerWebSearchProvider(...) registrieren.
Hinweise:
- Behalte Providerauswahl, Credential-Auflösung und gemeinsame Request-Semantik im Core.
- Verwende Websuch-Provider für vendor-spezifische Suchtransporte.
api.runtime.webSearch.*ist die bevorzugte gemeinsame Oberfläche für Feature-/Channel-Plugins, die Suchverhalten benötigen, ohne von dem Agent-Tool-Wrapper abzuhängen.
api.runtime.imageGeneration
generate(...): ein Bild mit der konfigurierten Kette von Bildgenerierungs-Providern erzeugen.listProviders(...): verfügbare Bildgenerierungs-Provider und ihre Fähigkeiten auflisten.
Gateway-HTTP-Routen
Plugins können mitapi.registerHttpRoute(...) HTTP-Endpunkte bereitstellen.
path: Routenpfad unter dem Gateway-HTTP-Server.auth: erforderlich. Verwende"gateway", um normale Gateway-Auth zu verlangen, oder"plugin"für Plugin-verwaltete Auth/Webhook-Verifizierung.match: optional."exact"(Standard) oder"prefix".replaceExisting: optional. Erlaubt demselben Plugin, seine eigene vorhandene Routenregistrierung zu ersetzen.handler:truezurückgeben, wenn die Route die Anfrage verarbeitet hat.
api.registerHttpHandler(...)wurde entfernt und verursacht einen Fehler beim Laden des Plugins. Verwende stattdessenapi.registerHttpRoute(...).- Plugin-Routen müssen
authexplizit deklarieren. - Konflikte bei identischem
path + matchwerden abgelehnt, außerreplaceExisting: trueist gesetzt, und ein Plugin kann keine Route eines anderen Plugins ersetzen. - Überlappende Routen mit unterschiedlichen
auth-Stufen werden abgelehnt. Halteexact-/prefix-Fallthrough-Ketten nur auf derselbenauth-Stufe. - Routen mit
auth: "plugin"erhalten nicht automatisch Runtime-Scopes für Operatoren. Sie sind für Plugin-verwaltete Webhooks/Signaturprüfung gedacht, nicht für privilegierte Gateway-Helper-Aufrufe. - Routen mit
auth: "gateway"laufen innerhalb eines Gateway-Request-Runtime-Scopes, aber dieser Scope ist bewusst konservativ:- Bearer-Auth mit gemeinsamem Secret (
gateway.auth.mode = "token"/"password") hält Runtime-Scopes für Plugin-Routen aufoperator.writefest, auch wenn der Aufruferx-openclaw-scopessendet - vertrauenswürdige HTTP-Modi mit Identität (zum Beispiel
trusted-proxyodergateway.auth.mode = "none"auf einem privaten Ingress) beachtenx-openclaw-scopesnur, wenn der Header ausdrücklich vorhanden ist - fehlt
x-openclaw-scopesbei solchen Plugin-Routen-Anfragen mit Identität, fällt der Runtime-Scope aufoperator.writezurück
- Bearer-Auth mit gemeinsamem Secret (
- Praktische Regel: Gehe nicht davon aus, dass eine per Gateway authentifizierte Plugin-Route implizit eine Admin-Oberfläche ist. Wenn deine Route admin-only-Verhalten benötigt, verlange einen Auth-Modus mit Identität und dokumentiere den expliziten Header-Vertrag für
x-openclaw-scopes.
Importpfade des Plugin SDK
Verwende SDK-Subpaths statt des monolithischen Importsopenclaw/plugin-sdk, wenn
du Plugins entwickelst:
openclaw/plugin-sdk/plugin-entryfür Primitiven zur Plugin-Registrierung.openclaw/plugin-sdk/corefür den generischen gemeinsamen Vertrag auf Plugin-Seite.openclaw/plugin-sdk/config-schemafür den Zod-Schema-Export des Root-openclaw.json(OpenClawSchema).- Stabile Channel-Primitiven wie
openclaw/plugin-sdk/channel-setup,openclaw/plugin-sdk/setup-runtime,openclaw/plugin-sdk/setup-adapter-runtime,openclaw/plugin-sdk/setup-tools,openclaw/plugin-sdk/channel-pairing,openclaw/plugin-sdk/channel-contract,openclaw/plugin-sdk/channel-feedback,openclaw/plugin-sdk/channel-inbound,openclaw/plugin-sdk/channel-lifecycle,openclaw/plugin-sdk/channel-reply-pipeline,openclaw/plugin-sdk/command-auth,openclaw/plugin-sdk/secret-inputundopenclaw/plugin-sdk/webhook-ingressfür gemeinsame Verdrahtung von Setup/Auth/Antwort/Webhooks.channel-inboundist das gemeinsame Zuhause für Debounce, Mention-Matching, Envelope-Formatierung und Kontext-Helper für eingehende Envelopes.channel-setupist der schmale Setup-Übergang für optionale Installationen.setup-runtimeist die runtime-sichere Setup-Oberfläche, die vonsetupEntry/ verzögertem Start verwendet wird, einschließlich import-sicherer Setup-Patch-Adapter.setup-adapter-runtimeist der env-bewusste Übergang für Account-Setup-Adapter.setup-toolsist der kleine Übergang für CLI-/Archiv-/Docs-Helper (formatCliCommand,detectBinary,extractArchive,resolveBrewExecutable,formatDocsLink,CONFIG_DIR). - Domain-Subpaths wie
openclaw/plugin-sdk/channel-config-helpers,openclaw/plugin-sdk/allow-from,openclaw/plugin-sdk/channel-config-schema,openclaw/plugin-sdk/telegram-command-config,openclaw/plugin-sdk/channel-policy,openclaw/plugin-sdk/approval-runtime,openclaw/plugin-sdk/config-runtime,openclaw/plugin-sdk/infra-runtime,openclaw/plugin-sdk/agent-runtime,openclaw/plugin-sdk/lazy-runtime,openclaw/plugin-sdk/reply-history,openclaw/plugin-sdk/routing,openclaw/plugin-sdk/status-helpers,openclaw/plugin-sdk/text-runtime,openclaw/plugin-sdk/runtime-storeundopenclaw/plugin-sdk/directory-runtimefür gemeinsame Laufzeit-/Konfigurations-Helper.telegram-command-configist der schmale öffentliche Übergang für die Normalisierung/Validierung benutzerdefinierter Telegram-Befehle und bleibt verfügbar, auch wenn die gebündelte Telegram-Vertragsoberfläche vorübergehend nicht verfügbar ist.text-runtimeist der gemeinsame Übergang für Text/Markdown/Logging, einschließlich des Entfernens von für Assistenten sichtbarem Text, Helpern zum Rendern/Chunking von Markdown, Helpern zur Redigierung, Helpern für Directive-Tags und Hilfsfunktionen für sicheren Text. - Approval-spezifische Channel-Übergänge sollten einen einzigen Vertrag
approvalCapabilityauf dem Plugin bevorzugen. Der Core liest dann Auth, Zustellung, Rendering und natives Routing für Approvals über diese eine Fähigkeit, statt Approval-Verhalten in nicht zusammengehörige Plugin-Felder zu mischen. openclaw/plugin-sdk/channel-runtimeist veraltet und bleibt nur als Kompatibilitäts-Shim für ältere Plugins bestehen. Neuer Code sollte stattdessen die schmaleren generischen Primitiven importieren, und Repo-Code sollte keine neuen Importe dieses Shims hinzufügen.- Interne Bestandteile gebündelter Erweiterungen bleiben privat. Externe Plugins sollten nur
openclaw/plugin-sdk/*-Subpaths verwenden. OpenClaw-Core-/Test-Code darf die öffentlichen Repo-Einstiegspunkte unter einer Plugin-Paketwurzel wieindex.js,api.js,runtime-api.js,setup-entry.jsund eng gefasste Dateien wielogin-qr-api.jsverwenden. Importiere niemalssrc/*eines Plugin-Pakets aus dem Core oder aus einer anderen Erweiterung. - Aufteilung der Repo-Einstiegspunkte:
<plugin-package-root>/api.jsist das Barrel für Helper/Typen,<plugin-package-root>/runtime-api.jsist das reine Runtime-Barrel,<plugin-package-root>/index.jsist der Einstieg des gebündelten Plugins und<plugin-package-root>/setup-entry.jsist der Einstieg des Setup-Plugins. - Aktuelle Beispiele für gebündelte Provider:
- Anthropic verwendet
api.js/contract-api.jsfür Claude-Stream-Helper wiewrapAnthropicProviderStream, Helper für Beta-Header und Parsing vonservice_tier. - OpenAI verwendet
api.jsfür Provider-Builder, Default-Modell-Helper und Realtime-Provider-Builder. - OpenRouter verwendet
api.jsfür seinen Provider-Builder sowie Onboarding-/Konfigurations- Helper, währendregister.runtime.jsweiterhin generischeplugin-sdk/provider-stream-Helper für repo-lokale Nutzung re-exportieren kann.
- Anthropic verwendet
- Öffentlich zugängliche Einstiegspunkte, die über eine Fassade geladen werden, bevorzugen den aktiven Runtime-Konfigurations-Snapshot, falls vorhanden, und greifen andernfalls auf die auf der Platte aufgelöste Konfigurationsdatei zurück, wenn OpenClaw noch keinen Runtime-Snapshot bereitstellt.
- Generische gemeinsame Primitiven bleiben der bevorzugte öffentliche SDK-Vertrag. Eine kleine
reservierte Kompatibilitätsmenge von gebündelten channel-markierten Helper-Übergängen existiert weiterhin.
Behandle diese als Übergänge für gebündelte Wartung/Kompatibilität, nicht als neue Importziele für Drittanbieter; neue kanalübergreifende Verträge sollten weiterhin auf
generischen
plugin-sdk/*-Subpaths oder den plugin-lokalen Barrelsapi.js/runtime-api.jslanden.
- Vermeide für neuen Code das Root-Barrel
openclaw/plugin-sdk. - Bevorzuge zuerst die schmalen stabilen Primitiven. Die neueren Setup-/Pairing-/Reply-/
Feedback-/Contract-/Inbound-/Threading-/Command-/Secret-input-/Webhook-/Infra-/
Allowlist-/Status-/Message-Tool-Subpaths sind der beabsichtigte Vertrag für neue
gebündelte und externe Plugin-Arbeit.
Target-Parsing/-Matching gehört auf
openclaw/plugin-sdk/channel-targets. Gates für Message-Actions und Helper für Reaktions-Message-IDs gehören aufopenclaw/plugin-sdk/channel-actions. - Erweiterungsspezifische Helper-Barrels gebündelter Erweiterungen sind standardmäßig nicht stabil. Wenn ein
Helper nur für eine gebündelte Erweiterung benötigt wird, halte ihn hinter dem
lokalen Übergang
api.jsoderruntime-api.jsdieser Erweiterung, statt ihn nachopenclaw/plugin-sdk/<extension>zu befördern. - Neue gemeinsame Helper-Übergänge sollten generisch sein, nicht channel-markiert. Gemeinsames Target-
Parsing gehört auf
openclaw/plugin-sdk/channel-targets; channelspezifische Interna bleiben hinter dem lokalen Übergangapi.jsoderruntime-api.jsdes zuständigen Plugins. - Fähigkeitsspezifische Subpaths wie
image-generation,media-understandingundspeechexistieren, weil gebündelte/native Plugins sie heute verwenden. Ihre Existenz bedeutet für sich genommen nicht, dass jeder exportierte Helper ein langfristig eingefrorener externer Vertrag ist.
Message-Tool-Schemata
Plugins sollten channelspezifische Schema-Beiträge fürdescribeMessageTool(...)
besitzen. Halte providerspezifische Felder im Plugin, nicht im gemeinsamen Core.
Für gemeinsame portable Schema-Fragmente verwende die generischen Helper, die über
openclaw/plugin-sdk/channel-actions exportiert werden:
createMessageToolButtonsSchema()für Payloads im Stil von Button-RasterncreateMessageToolCardSchema()für strukturierte Card-Payloads
Auflösung von Channel-Zielen
Channel-Plugins sollten channelspezifische Zielsemantik besitzen. Halte den gemeinsamen Outbound-Host generisch und verwende die Messaging-Adapter-Oberfläche für Provider-Regeln:messaging.inferTargetChatType({ to })entscheidet, ob ein normalisiertes Ziel vor der Verzeichnisabfrage alsdirect,groupoderchannelbehandelt werden soll.messaging.targetResolver.looksLikeId(raw, normalized)teilt dem Core mit, ob eine Eingabe direkt in eine id-ähnliche Auflösung übergehen soll statt in eine Verzeichnissuche.messaging.targetResolver.resolveTarget(...)ist der Plugin-Fallback, wenn der Core nach der Normalisierung oder nach einem Verzeichnis-Fehlschlag eine endgültige provider-eigene Auflösung benötigt.messaging.resolveOutboundSessionRoute(...)besitzt die providerspezifische Konstruktion der Session-Route, sobald ein Ziel aufgelöst ist.
- Verwende
inferTargetChatTypefür Kategorieentscheidungen, die vor dem Durchsuchen von Peers/Gruppen getroffen werden sollten. - Verwende
looksLikeIdfür Prüfungen der Art „dies als explizite/native Ziel-ID behandeln“. - Verwende
resolveTargetals providerspezifischen Normalisierungs-Fallback, nicht für eine breite Verzeichnissuche. - Halte provider-native IDs wie Chat-IDs, Thread-IDs, JIDs, Handles und Raum-IDs in
target-Werten oder providerspezifischen Parametern, nicht in generischen SDK-Feldern.
Verzeichnisse auf Konfigurationsbasis
Plugins, die Verzeichniseinträge aus der Konfiguration ableiten, sollten diese Logik im Plugin behalten und die gemeinsamen Helper ausopenclaw/plugin-sdk/directory-runtime wiederverwenden.
Verwende dies, wenn ein Channel konfigurationsgestützte Peers/Gruppen benötigt, etwa:
- von der Allowlist gesteuerte DM-Peers
- konfigurierte Channel-/Gruppen-Zuordnungen
- kontobezogene statische Verzeichnis-Fallbacks
directory-runtime behandeln nur generische Operationen:
- Query-Filterung
- Anwendung von Limits
- Helper für Deduplizierung/Normalisierung
- Erstellen von
ChannelDirectoryEntry[]
Provider-Kataloge
Provider-Plugins können Modellkataloge für Inferenz mitregisterProvider({ catalog: { run(...) { ... } } }) definieren.
catalog.run(...) gibt dieselbe Form zurück, die OpenClaw in
models.providers schreibt:
{ provider }für einen einzelnen Provider-Eintrag{ providers }für mehrere Provider-Einträge
catalog, wenn das Plugin providerspezifische Modell-IDs, Standardwerte für Base-URLs oder auth-gesteuerte Modellmetadaten besitzt.
catalog.order steuert, wann der Katalog eines Plugins relativ zu den
integrierten impliziten Providern von OpenClaw zusammengeführt wird:
simple: einfache Provider mit API-Key oder env-gesteuertprofile: Provider, die erscheinen, wenn Auth-Profile existierenpaired: Provider, die mehrere zusammengehörige Provider-Einträge synthetisierenlate: letzter Durchgang, nach anderen impliziten Providern
discoveryfunktioniert weiterhin als alter Alias- wenn sowohl
catalogals auchdiscoveryregistriert sind, verwendet OpenClawcatalog
Schreibgeschützte Channel-Inspektion
Wenn dein Plugin einen Channel registriert, solltest duplugin.config.inspectAccount(cfg, accountId) zusammen mit resolveAccount(...) implementieren.
Warum:
resolveAccount(...)ist der Laufzeitpfad. Es darf annehmen, dass Zugangsdaten vollständig materialisiert sind, und schnell fehlschlagen, wenn erforderliche Secrets fehlen.- Schreibgeschützte Befehlspfade wie
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolvesowie Doctor-/Konfigurations- Reparaturflüsse sollten keine Laufzeit-Zugangsdaten materialisieren müssen, nur um die Konfiguration zu beschreiben.
inspectAccount(...):
- Nur beschreibenden Kontostatus zurückgeben.
enabledundconfiguredbeibehalten.- Relevante Felder für Quelle/Status von Zugangsdaten aufnehmen, z. B.:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Du musst keine rohen Token-Werte zurückgeben, nur um schreibgeschützte
Verfügbarkeit zu melden.
tokenStatus: "available"zurückzugeben (und das passende Quellfeld) reicht für statusartige Befehle aus. - Verwende
configured_unavailable, wenn eine Credential über SecretRef konfiguriert ist, aber im aktuellen Befehlspfad nicht verfügbar.
Paket-Packs
Ein Plugin-Verzeichnis kann einpackage.json mit openclaw.extensions enthalten:
name/<fileBase>.
Wenn dein Plugin npm-Abhängigkeiten importiert, installiere sie in diesem Verzeichnis, damit
node_modules verfügbar ist (npm install / pnpm install).
Sicherheitsleitplanke: Jeder Eintrag in openclaw.extensions muss nach der Auflösung von Symlinks innerhalb des Plugin-Verzeichnisses bleiben. Einträge, die das Paketverzeichnis verlassen, werden abgelehnt.
Sicherheitshinweis: openclaw plugins install installiert Plugin-Abhängigkeiten mit
npm install --omit=dev --ignore-scripts (keine Lifecycle-Skripte, keine Dev-Abhängigkeiten zur Laufzeit). Halte Abhängigkeitsbäume von Plugins „reines JS/TS“ und vermeide Pakete, die postinstall-Builds benötigen.
Optional: openclaw.setupEntry kann auf ein leichtgewichtiges Modul nur für Setup zeigen.
Wenn OpenClaw Setup-Oberflächen für ein deaktiviertes Channel-Plugin benötigt oder
wenn ein Channel-Plugin aktiviert, aber noch unkonfiguriert ist, lädt es setupEntry
statt des vollständigen Plugin-Einstiegs. Das hält Start und Setup schlanker,
wenn dein Haupteinstieg auch Tools, Hooks oder anderen reinen Laufzeit-Code verdrahtet.
Optional: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen
kann ein Channel-Plugin in denselben setupEntry-Pfad während der
Pre-Listen-Startphase des Gateways optieren, auch wenn der Channel bereits konfiguriert ist.
Verwende das nur, wenn setupEntry die Oberfläche beim Start vollständig abdeckt, die
vor dem Lauschen des Gateways vorhanden sein muss. In der Praxis bedeutet das, dass der
Setup-Einstieg jede vom Channel besessene Fähigkeit registrieren muss, von der der Start abhängt, wie zum Beispiel:
- die Channel-Registrierung selbst
- alle HTTP-Routen, die verfügbar sein müssen, bevor das Gateway zu lauschen beginnt
- alle Gateway-Methoden, Tools oder Dienste, die in diesem selben Zeitfenster vorhanden sein müssen
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
channels.<id>.accounts.* hochstufen muss, ohne den vollständigen Plugin-Einstieg zu laden.
Matrix ist das aktuelle gebündelte Beispiel: Es verschiebt nur Auth-/Bootstrap-Schlüssel in ein
benanntes hochgestuftes Konto, wenn benannte Konten bereits existieren, und es kann einen
konfigurierten nicht-kanonischen Default-Account-Schlüssel beibehalten, statt immer
accounts.default zu erstellen.
Diese Setup-Patch-Adapter halten die Discovery der Vertragsoberfläche gebündelter Channels lazy. Die Importzeit bleibt gering; die Promotion-Oberfläche wird nur beim ersten Gebrauch geladen, statt beim Modulimport erneut in den Start gebündelter Channels einzusteigen.
Wenn diese Start-Oberflächen Gateway-RPC-Methoden enthalten, halte sie auf einem
plugin-spezifischen Präfix. Core-Admin-Namespaces (config.*,
exec.approvals.*, wizard.*, update.*) bleiben reserviert und werden immer
zu operator.admin aufgelöst, auch wenn ein Plugin einen engeren Scope anfordert.
Beispiel:
Channel-Katalog-Metadaten
Channel-Plugins können Setup-/Discovery-Metadaten überopenclaw.channel und
Installationshinweise über openclaw.install bekannt geben. Dadurch bleiben die Core-Katalogdaten frei von Inhalten.
Beispiel:
openclaw.channel über das Minimalbeispiel hinaus:
detailLabel: sekundäres Label für umfangreichere Katalog-/Status-OberflächendocsLabel: Linktext für den Docs-Link überschreibenpreferOver: Plugin-/Channel-IDs mit niedrigerer Priorität, die dieser Katalogeintrag übertreffen sollselectionDocsPrefix,selectionDocsOmitLabel,selectionExtras: Steuerung des Texts auf AuswahloberflächenmarkdownCapable: markiert den Channel für Entscheidungen zur Outbound-Formatierung als markdownfähigshowConfigured: blendet den Channel in Oberflächen zur Auflistung konfigurierter Channels aus, wenn auffalsegesetztquickstartAllowFrom: optiert den Channel in den Standard-Quickstart-FlowallowFromeinforceAccountBinding: explizite Kontobindung verlangen, auch wenn nur ein Konto existiertpreferSessionLookupForAnnounceTarget: Session-Lookup bevorzugen, wenn Ziele für Ankündigungen aufgelöst werden
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
OPENCLAW_PLUGIN_CATALOG_PATHS (oder OPENCLAW_MPM_CATALOG_PATHS) auf
eine oder mehrere JSON-Dateien (durch Komma/Semikolon/PATH getrennt). Jede Datei sollte
{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] } enthalten. Der Parser akzeptiert außerdem "packages" oder "plugins" als alte Aliasse für den Schlüssel "entries".
Context-Engine-Plugins
Context-Engine-Plugins besitzen die Orchestrierung des Session-Kontexts für Ingest, Zusammenstellung und Kompaktierung. Registriere sie in deinem Plugin mitapi.registerContextEngine(id, factory) und wähle dann die aktive Engine über
plugins.slots.contextEngine aus.
Verwende dies, wenn dein Plugin die Standard-Context-Pipeline ersetzen oder erweitern muss,
anstatt nur Memory-Suche oder Hooks hinzuzufügen.
compact() trotzdem und delegiere ihn explizit:
Eine neue Fähigkeit hinzufügen
Wenn ein Plugin Verhalten benötigt, das nicht in die aktuelle API passt, umgehe das Plugin-System nicht mit einem privaten Direkteingriff. Füge die fehlende Fähigkeit hinzu. Empfohlene Reihenfolge:- den Core-Vertrag definieren Entscheide, welches gemeinsame Verhalten dem Core gehören sollte: Richtlinien, Fallback, Konfigurations-Zusammenführung, Lebenszyklus, channelseitige Semantik und Form des Laufzeit-Helpers.
- typisierte Oberflächen für Plugin-Registrierung/Laufzeit hinzufügen
Erweitere
OpenClawPluginApiund/oderapi.runtimeum die kleinste nützliche typisierte Fähigkeitsoberfläche. - Core- und Channel-/Feature-Consumers verdrahten Channels und Feature-Plugins sollten die neue Fähigkeit über den Core verwenden, nicht durch direkten Import einer Vendor-Implementierung.
- Vendor-Implementierungen registrieren Vendor-Plugins registrieren dann ihre Backends für die Fähigkeit.
- Vertragsabdeckung hinzufügen Füge Tests hinzu, damit Zuständigkeit und Form der Registrierung im Laufe der Zeit explizit bleiben.
Fähigkeits-Checkliste
Wenn du eine neue Fähigkeit hinzufügst, sollte die Implementierung diese Oberflächen in der Regel gemeinsam berühren:- Core-Vertragstypen in
src/<capability>/types.ts - Core-Runner/Laufzeit-Helper in
src/<capability>/runtime.ts - Oberfläche zur Plugin-API-Registrierung in
src/plugins/types.ts - Verdrahtung der Plugin-Registry in
src/plugins/registry.ts - Bereitstellung der Plugin-Laufzeit in
src/plugins/runtime/*, wenn Feature-/Channel- Plugins sie verwenden müssen - Capture-/Test-Helper in
src/test-utils/plugin-registration.ts - Assertions zu Zuständigkeit/Verträgen in
src/plugins/contracts/registry.ts - Dokumentation für Operatoren/Plugins in
docs/
Fähigkeitsvorlage
Minimales Muster:- der Core besitzt den Fähigkeitsvertrag + die Orchestrierung
- Vendor-Plugins besitzen Vendor-Implementierungen
- Feature-/Channel-Plugins verwenden Laufzeit-Helper
- Vertragstests halten Zuständigkeit explizit