Plugin maintainer reference
Interna der Plugin-Architektur
Für das öffentliche Fähigkeitsmodell, die Plugin-Strukturen und die Verträge zu Eigentümerschaft und Ausführung siehe Plugin-Architektur. Diese Seite behandelt die internen Mechanismen: Ladepipeline, Registry, Runtime-Hooks, Gateway-HTTP- Routen, Importpfade und Schematabellen.
Ladepipeline
Beim Start führt OpenClaw ungefähr Folgendes aus:
- potenzielle Plugin-Stammverzeichnisse ermitteln
- 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 bestimmen
- aktivierte native Module laden: Erstellte gebündelte Module verwenden einen nativen Loader; lokaler TypeScript-Quellcode von Drittanbietern verwendet als Notlösung den Jiti-Fallback
- native
register(api)-Hooks aufrufen und Registrierungen in der Plugin-Registry sammeln - die Registry für Befehle und Runtime-Oberflächen bereitstellen
Sicherheitsprüfungen werden vor der Runtime-Ausführung durchgeführt. Die Ermittlung blockiert einen Kandidaten, wenn:
- sein aufgelöster Einstiegspunkt außerhalb des Plugin-Stammverzeichnisses liegt
- sein Pfad (oder dessen Stammverzeichnis) für alle Benutzer beschreibbar ist
- bei nicht gebündelten Plugins die Eigentümerschaft des Pfads nicht mit der aktuellen UID (oder root) übereinstimmt
Bei für alle Benutzer beschreibbaren gebündelten Verzeichnissen wird zunächst direkt ein
chmod-Reparaturversuch durchgeführt (npm-/globale Installationen können Paketverzeichnisse mit
0777 ausliefern), bevor die Prüfung erneut erfolgt; für gebündelte Ursprünge werden
Eigentümerschaftsprüfungen vollständig übersprungen.
Blockierte Kandidaten enthalten in der ausgegebenen Diagnose weiterhin ihre Plugin-ID, sofern diese bekannt ist (einschließlich IDs, die aus einem Manifest innerhalb eines ansonsten abgelehnten Verzeichnisses aufgelöst wurden). So erkennt eine Konfiguration, die auf diese ID verweist, ein blockiertes Plugin zusammen mit einer Warnung zur Pfadsicherheit statt eines nicht zugehörigen Fehlers „unbekanntes Plugin“.
Manifest-zentriertes Verhalten
Das Manifest ist die maßgebliche Informationsquelle der Steuerungsebene. OpenClaw verwendet es, um:
- das Plugin zu identifizieren
- deklarierte Kanäle, Skills, Konfigurationsschemata oder Bundle-Fähigkeiten zu ermitteln
plugins.entries.<id>.configzu validieren- Beschriftungen und Platzhalter der Control UI zu ergänzen
- Installations- und Katalogmetadaten anzuzeigen
- kostengünstige Aktivierungs- und Einrichtungsdeskriptoren beizubehalten, ohne die Plugin-Runtime zu laden
Bei nativen Plugins bildet das Runtime-Modul den Teil der Datenebene. Es registriert das tatsächliche Verhalten, beispielsweise Hooks, Werkzeuge, Befehle oder Provider-Abläufe.
Optionale Manifest-Blöcke activation und setup verbleiben auf der Steuerungsebene.
Sie sind reine Metadatendeskriptoren für die Aktivierungsplanung und Einrichtungsermittlung;
sie ersetzen weder die Runtime-Registrierung noch register(...) oder setupEntry.
Aktive Aktivierungsverbraucher verwenden Hinweise zu Befehlen, Kanälen und Providern aus dem Manifest, um
das Laden von Plugins vor einer umfassenderen Materialisierung der Registry einzugrenzen:
- Beim Laden der CLI wird auf Plugins eingegrenzt, denen der angeforderte primäre Befehl gehört
- Die Kanaleinrichtung bzw. Plugin-Auflösung wird auf Plugins eingegrenzt, denen die angeforderte Kanal-ID gehört
- Die explizite Provider-Einrichtung bzw. Runtime-Auflösung wird auf Plugins eingegrenzt, denen die angeforderte Provider-ID gehört
- Die Gateway-Startplanung verwendet
activation.onStartupfür explizite Start- Importe; Plugins ohne Startmetadaten werden nur über spezifischere Aktivierungsauslöser geladen
Der Aktivierungsplaner stellt sowohl eine reine ID-API für bestehende Aufrufer als auch eine
Plan-API für Diagnosen bereit. Planeinträge geben an, warum ein Plugin ausgewählt wurde,
und unterscheiden explizite activation.*-Hinweise vom Fallback über die Manifest-Eigentümerschaft:
Grund (aus activation.*-Hinweisen) |
Grund (aus Manifest-Eigentümerschaft) |
|---|---|
activation-agent-harness-hint |
— |
activation-capability-hint |
— |
activation-channel-hint |
manifest-channel-owner (channels) |
activation-command-hint |
manifest-command-alias (commandAliases) |
activation-provider-hint |
manifest-provider-owner (providers), manifest-setup-provider-owner (setup.providers) |
activation-route-hint |
— |
| — (der Hook-Auslöser hat keine Hinweisvariante) | manifest-hook-owner (hooks), manifest-tool-contract (contracts.tools) |
Diese Trennung der Gründe bildet die Kompatibilitätsgrenze: Bestehende Plugin-Metadaten funktionieren weiterhin, während neuer Code allgemeine Hinweise oder Fallback-Verhalten erkennen kann, ohne die Semantik des Runtime-Ladens zu ändern.
Runtime-Vorabladevorgänge zur Anfragezeit, die den allgemeinen Geltungsbereich all anfordern, leiten weiterhin
eine explizite effektive Menge von Plugin-IDs aus der Konfiguration, der Startplanung, konfigurierten
Kanälen, Slots und Regeln zur automatischen Aktivierung ab
(resolveEffectivePluginIds in src/plugins/effective-plugin-ids.ts). Wenn diese
abgeleitete Menge leer ist, belässt OpenClaw den Geltungsbereich leer, statt ihn auf
jedes ermittelbare Plugin auszuweiten.
Die Einrichtungsermittlung bevorzugt Deskriptor-eigene IDs wie setup.providers und
setup.cliBackends, um potenzielle Plugins einzugrenzen, bevor auf
setup-api für Plugins zurückgegriffen wird, die weiterhin Runtime-Hooks zur Einrichtungszeit benötigen. Listen zur
Provider-Einrichtung verwenden Manifest-providerAuthChoices, aus Deskriptoren abgeleitete Einrichtungsoptionen
und Installationskatalog-Metadaten, ohne die Provider-Runtime zu laden. Ein explizites
setup.requiresRuntime: false ist eine reine Deskriptor-Abgrenzung; ein ausgelassenes
requiresRuntime behält aus Kompatibilitätsgründen den bisherigen Setup-API-Fallback bei. Wenn
mehr als ein ermitteltes Plugin denselben normalisierten Einrichtungs-Provider oder
dieselbe CLI-Backend-ID beansprucht, lehnt die Einrichtungssuche den mehrdeutigen Eigentümer ab, statt sich auf
die Ermittlungsreihenfolge zu verlassen. Wenn die Einrichtungs-Runtime ausgeführt wird, melden Registry-Diagnosen
Abweichungen zwischen setup.providers / setup.cliBackends und den tatsächlich von der Setup-API
registrierten Providern oder CLI-Backends, ohne ältere Plugins zu blockieren.
Grenze des Plugin-Caches
OpenClaw speichert weder Ergebnisse der Plugin-Ermittlung noch direkte Daten der Manifest-Registry hinter zeitbasierten Gültigkeitsfenstern zwischen. Installationen, Manifeständerungen und Änderungen an Ladepfaden müssen beim nächsten expliziten Lesen der Metadaten oder Neuaufbau eines Snapshots sichtbar werden. Der Manifestdatei-Parser verwendet einen begrenzten Dateisignatur-Cache, dessen Schlüssel aus dem geöffneten Manifestpfad sowie Gerät/Inode, Größe und mtime/ctime besteht; dieser Cache vermeidet lediglich das erneute Parsen unveränderter Bytes und darf keine Antworten zu Ermittlung, Registry, Eigentümern oder Richtlinien zwischenspeichern.
Der sichere schnelle Metadatenpfad basiert auf expliziter Objekteigentümerschaft, nicht auf einem verborgenen Cache.
Häufig durchlaufene Pfade beim Gateway-Start sollten die aktuelle PluginMetadataSnapshot, die
abgeleitete PluginLookUpTable oder eine explizite Manifest-Registry durch die Aufrufkette
weiterreichen. Konfigurationsvalidierung, automatische Aktivierung beim Start, Plugin-Bootstrap und Provider-
Auswahl können diese Objekte wiederverwenden, solange sie die aktuelle Konfiguration und
das aktuelle Plugin-Inventar repräsentieren. Die Einrichtungssuche rekonstruiert Manifest-Metadaten weiterhin bei Bedarf,
sofern der jeweilige Einrichtungspfad keine explizite Manifest-Registry erhält; dies sollte ein
Fallback für selten durchlaufene Pfade bleiben, statt verborgene Such-Caches hinzuzufügen. Wenn sich die
Eingabe ändert, muss der Snapshot neu erstellt und ersetzt werden, statt ihn zu verändern oder
historische Kopien aufzubewahren. Ansichten der aktiven Plugin-Registry und Hilfsfunktionen für den Bootstrap
gebündelter Kanäle sollten aus der aktuellen Registry bzw. dem aktuellen Stammverzeichnis neu berechnet werden.
Kurzlebige Maps innerhalb eines einzelnen Aufrufs sind zur Deduplizierung von Arbeit oder zum Schutz vor Wiedereintritt zulässig;
sie dürfen nicht zu Prozessmetadaten-Caches werden.
Beim Laden von Plugins ist das Runtime-Laden die persistente Cache-Ebene. Sie darf Loader-Zustände wiederverwenden, wenn Code oder installierte Artefakte tatsächlich geladen werden, beispielsweise:
PluginLoaderCacheStateund kompatible aktive Runtime-Registries- Jiti-/Modul-Caches und Loader-Caches für öffentliche Oberflächen, die verhindern, dass dieselbe Runtime-Oberfläche wiederholt importiert wird
- Dateisystem-Caches für installierte Plugin-Artefakte
- kurzlebige aufrufbezogene Maps zur Pfadnormalisierung oder Auflösung von Duplikaten
Diese Caches sind Implementierungsdetails der Datenebene. Sie dürfen keine Fragen der Steuerungsebene wie „Welchem Plugin gehört dieser Provider?“ beantworten, es sei denn, der Aufrufer hat ausdrücklich das Laden der Runtime angefordert.
Fügen Sie keine persistenten oder zeitbasierten Caches hinzu für:
- Ermittlungsergebnisse
- direkte Manifest-Registries
- aus dem Index installierter Plugins rekonstruierte Manifest-Registries
- Suche nach Provider-Eigentümern, Modellunterdrückung, Provider-Richtlinien oder Metadaten öffentlicher Artefakte
- jede andere aus dem Manifest abgeleitete Antwort, bei der ein geändertes Manifest, ein geänderter Installationsindex oder Ladepfad beim nächsten Lesen der Metadaten sichtbar sein sollte
Aufrufer, die Manifest-Metadaten aus dem persistent gespeicherten Index installierter Plugins neu erstellen, rekonstruieren diese Registry bei Bedarf. Der Installationsindex ist ein dauerhafter Zustand der Quellebene; er ist kein verborgener prozessinterner Metadaten-Cache.
Registry-Modell
Geladene Plugins verändern nicht direkt beliebige globale Variablen des Kerns. Sie registrieren sich in einer
zentralen Plugin-Registry (PluginRegistry in src/plugins/registry-types.ts),
die Plugin-Datensätze (Identität, Quelle, Ursprung, Status, Diagnosen)
sowie Arrays für jede Fähigkeit verwaltet: Werkzeuge, ältere und typisierte Hooks,
Kanäle, Provider, Gateway-RPC-Handler, HTTP-Routen, CLI-Registrierungsfunktionen,
Hintergrunddienste, Plugin-eigene Befehle und Dutzende weitere typisierte Provider-
Familien (Sprache, Embeddings, Bild-/Video-/Musikgenerierung, Web-
Abruf/-Suche, Agent-Harnesse, Sitzungsaktionen und so weiter).
Kernfunktionen lesen anschließend aus dieser Registry, statt direkt mit Plugin- Modulen zu kommunizieren. Dadurch bleibt der Ladevorgang unidirektional:
- Plugin-Modul -> Registry-Registrierung
- Kern-Runtime -> Registry-Nutzung
Diese Trennung ist für die Wartbarkeit wichtig. Dadurch benötigen die meisten Kernoberflächen nur einen Integrationspunkt: „Registry lesen“ statt „jedes Plugin-Modul gesondert behandeln“.
Callbacks für Konversationsbindungen
Plugins, die eine Konversation binden, können reagieren, wenn eine Genehmigung entschieden wurde.
Verwenden Sie api.onConversationBindingResolved(...), um einen Callback zu erhalten, nachdem eine Bindungs-
anfrage genehmigt oder abgelehnt wurde:
export default { id: "my-plugin", register(api) { api.onConversationBindingResolved(async (event) => { if (event.status === "approved") { // Für dieses Plugin und diese Konversation besteht nun eine Bindung. console.log(event.binding?.conversationId); return; } // Die Anfrage wurde abgelehnt; lokalen ausstehenden Zustand löschen. console.log(event.request.conversation.conversationId); }); },};Felder der Callback-Nutzlast:
status:"approved"oder"denied"decision:"allow-once","allow-always"oder"deny"binding: die aufgelöste Bindung für genehmigte Anfragenrequest: die ursprüngliche Anfragezusammenfassung, der Hinweis zum Trennen, die Absender-ID und die Konversationsmetadaten
Dieser Callback dient ausschließlich der Benachrichtigung. Er ändert nicht, wer eine Konversation binden darf, und wird ausgeführt, nachdem die Genehmigungsverarbeitung im Kern abgeschlossen ist.
Provider-Runtime-Hooks
Provider-Plugins bestehen aus drei Ebenen:
- Manifest-Metadaten für kostengünstige Abfragen vor der Runtime:
setup.providers[].envVars,providerAuthAliases,providerAuthChoicesundchannelConfigs. - Hooks zur Konfigurationszeit:
catalogsowieapplyConfigDefaults. - Runtime-Hooks: mehr als 40 optionale Hooks für Authentifizierung, Modellauflösung, Stream-Wrapper, Denkstufen, Wiederholungsrichtlinien und Nutzungsendpunkte. Siehe Hook-Reihenfolge und Nutzung.
OpenClaw ist weiterhin für die generische Agent-Schleife, das Failover, die Transkriptverarbeitung und die Tool-Richtlinie zuständig. Diese Hooks bilden die Erweiterungsschnittstelle für providerspezifisches Verhalten, ohne dass dafür ein vollständig benutzerdefinierter Inferenztransport erforderlich ist.
Verwenden Sie Manifest setup.providers[].envVars, wenn der Provider umgebungsvariablenbasierte
Anmeldedaten besitzt, die generische Authentifizierungs-, Status- und Modellauswahlpfade erkennen sollen, ohne
die Plugin-Laufzeit zu laden. Verwenden Sie Manifest providerAuthAliases,
wenn eine Provider-ID die Umgebungsvariablen, Authentifizierungsprofile,
konfigurationsbasierte Authentifizierung und die API-Schlüssel-Auswahl beim Onboarding einer anderen Provider-ID wiederverwenden soll. Verwenden Sie Manifest
providerAuthChoices, wenn CLI-Oberflächen für Onboarding und Authentifizierungsauswahl die
Auswahl-ID des Providers, Gruppenbezeichnungen und eine einfache Authentifizierungsanbindung über ein einzelnes Flag kennen sollen, ohne
die Provider-Laufzeit zu laden. Behalten Sie Provider-Laufzeit-
envVars für Hinweise für Betreiber bei, etwa Onboarding-Bezeichnungen oder Variablen
zur Einrichtung von OAuth-Client-ID und -Client-Secret.
Beschreiben Sie die umgebungsvariablengesteuerte Kanaleinrichtung und Authentifizierung über die zugehörigen
channelConfigs.<id>.schema und Einrichtungsdeskriptoren.
Reihenfolge und Verwendung der Hooks
Für Modell-/Provider-Plugins ruft OpenClaw Hooks ungefähr in dieser Reihenfolge auf.
Die Spalte „Verwendungszweck“ dient als schnelle Entscheidungshilfe.
Reine Kompatibilitätsfelder für Provider, die OpenClaw nicht mehr aufruft, wie
ProviderPlugin.capabilities und suppressBuiltInModel, sind hier absichtlich nicht
aufgeführt.
| Hook | Funktion | Verwendung |
|---|---|---|
catalog |
Provider-Konfiguration während der Generierung von models.json in models.providers veröffentlichen |
Der Provider besitzt einen Katalog oder Standardwerte für die Basis-URL |
applyConfigDefaults |
Globale, Provider-eigene Standardwerte bei der Materialisierung der Konfiguration anwenden | Standardwerte hängen vom Authentifizierungsmodus, von Umgebungsvariablen oder von der Semantik der Provider-Modellfamilie ab |
| (integrierte Modellsuche) | OpenClaw versucht zuerst den normalen Registry-/Katalogpfad | (kein Plugin-Hook) |
normalizeModelId |
Aliasse älterer oder Vorschau-Modell-IDs vor der Suche normalisieren | Der Provider bereinigt Aliasse vor der kanonischen Modellauflösung |
normalizeTransport |
api / baseUrl der Provider-Familie vor der generischen Modellzusammenstellung normalisieren |
Der Provider bereinigt den Transport für benutzerdefinierte Provider-IDs derselben Transportfamilie |
normalizeConfig |
models.providers.<id> vor der Laufzeit-/Provider-Auflösung normalisieren |
Der Provider benötigt eine Konfigurationsbereinigung, die beim Plugin liegen sollte; gebündelte Hilfsfunktionen der Google-Familie sichern außerdem unterstützte Google-Konfigurationseinträge ab |
applyNativeStreamingUsageCompat |
Native Kompatibilitätsumschreibungen für die Streaming-Nutzung auf konfigurierte Provider anwenden | Der Provider benötigt Endpunkt-gesteuerte Korrekturen nativer Metadaten zur Streaming-Nutzung |
resolveConfigApiKey |
Authentifizierung über Umgebungsmarker für konfigurierte Provider vor dem Laden der Laufzeitauthentifizierung auflösen | Provider stellen eigene Hooks zur Auflösung von API-Schlüsseln über Umgebungsmarker bereit |
resolveSyntheticAuth |
Lokale, selbst gehostete oder konfigurationsgestützte Authentifizierung ohne Speicherung im Klartext verfügbar machen | Der Provider kann mit einem synthetischen/lokalen Anmeldedatenmarker arbeiten |
resolveExternalAuthProfiles |
Provider-eigene externe Authentifizierungsprofile überlagern; der Standardwert von persistence ist runtime-only für CLI-/App-eigene Anmeldedaten |
Der Provider verwendet externe Anmeldedaten erneut, ohne kopierte Aktualisierungstoken zu speichern; contracts.externalAuthProviders im Manifest deklarieren |
shouldDeferSyntheticProfileAuth |
Gespeicherte synthetische Profilplatzhalter hinter umgebungs-/konfigurationsgestützter Authentifizierung niedriger priorisieren | Der Provider speichert synthetische Platzhalterprofile, die bei der Priorisierung nicht gewinnen sollen |
resolveDynamicModel |
Synchrone Ausweichlösung für Provider-eigene Modell-IDs, die noch nicht in der lokalen Registry enthalten sind | Der Provider akzeptiert beliebige vorgelagerte Modell-IDs |
prepareDynamicModel |
Asynchrones Aufwärmen, danach wird resolveDynamicModel erneut ausgeführt |
Der Provider benötigt Netzwerkmetadaten, bevor unbekannte IDs aufgelöst werden |
normalizeResolvedModel |
Abschließende Umschreibung, bevor der eingebettete Runner das aufgelöste Modell verwendet | Der Provider benötigt Transportumschreibungen, verwendet aber weiterhin einen Core-Transport |
normalizeToolSchemas |
Werkzeugschemas normalisieren, bevor der eingebettete Runner sie verarbeitet | Der Provider benötigt eine Schemabereinigung für die Transportfamilie |
inspectToolSchemas |
Provider-eigene Schemadiagnosen nach der Normalisierung verfügbar machen | Der Provider möchte Warnungen zu Schlüsselwörtern ausgeben, ohne den Core um Provider-spezifische Regeln zu erweitern |
resolveReasoningOutputMode |
Nativen oder markierten Vertrag für Reasoning-Ausgaben auswählen | Der Provider benötigt markierte Reasoning-/Endausgaben anstelle nativer Felder |
prepareExtraParams |
Anfrageparameter vor generischen Wrappern für Stream-Optionen normalisieren | Der Provider benötigt Standard-Anfrageparameter oder eine Provider-spezifische Parameterbereinigung |
createStreamFn |
Den normalen Stream-Pfad vollständig durch einen benutzerdefinierten Transport ersetzen | Der Provider benötigt ein benutzerdefiniertes Wire-Protokoll und nicht nur einen Wrapper |
wrapStreamFn |
Stream-Wrapper, nachdem generische Wrapper angewendet wurden | Der Provider benötigt Kompatibilitäts-Wrapper für Anfrage-Header, -Body oder -Modell, jedoch keinen benutzerdefinierten Transport |
resolveTransportTurnState |
Native Transport-Header oder Metadaten pro Durchlauf anhängen | Der Provider möchte, dass generische Transporte eine Provider-native Durchlaufidentität senden |
resolveWebSocketSessionPolicy |
Native WebSocket-Header oder eine Richtlinie für die Sitzungsabkühlzeit anhängen | Der Provider möchte Sitzungs-Header oder die Ausweichrichtlinie generischer WS-Transporte anpassen |
formatApiKey |
Formatierer für Authentifizierungsprofile: Das gespeicherte Profil wird zur Laufzeitzeichenfolge apiKey |
Der Provider speichert zusätzliche Authentifizierungsmetadaten und benötigt eine benutzerdefinierte Form des Laufzeittokens |
refreshOAuth |
OAuth-Aktualisierung für benutzerdefinierte Aktualisierungsendpunkte oder Richtlinien bei Aktualisierungsfehlern überschreiben | Der Provider passt nicht zu den gemeinsamen OpenClaw-Aktualisierungsmechanismen |
buildAuthDoctorHint |
Reparaturhinweis anhängen, wenn die OAuth-Aktualisierung fehlschlägt | Der Provider benötigt nach einem Aktualisierungsfehler Provider-eigene Hinweise zur Reparatur der Authentifizierung |
matchesContextOverflowError |
Provider-eigener Matcher für Kontextfensterüberläufe | Der Provider erzeugt rohe Überlauffehler, die generische Heuristiken nicht erkennen würden |
classifyFailoverReason |
Provider-eigene Klassifizierung von Failover-Gründen | Der Provider kann rohe API-/Transportfehler unter anderem auf Ratenbegrenzung oder Überlastung abbilden |
isCacheTtlEligible |
Prompt-Cache-Richtlinie für Proxy-/Backhaul-Provider | Der Provider benötigt Proxy-spezifische Einschränkungen für die Cache-TTL |
buildMissingAuthMessage |
Ersatz für die generische Wiederherstellungsmeldung bei fehlender Authentifizierung | Der Provider benötigt einen Provider-spezifischen Wiederherstellungshinweis bei fehlender Authentifizierung |
augmentModelCatalog |
Synthetische/abschließende Katalogzeilen nach der Erkennung anhängen (veraltet, siehe unten) | Der Provider benötigt synthetische Zeilen für Vorwärtskompatibilität in models list und Auswahlfeldern |
resolveThinkingProfile |
Modellspezifische Stufenmenge, Anzeigebezeichnungen und Standardwert für /think |
Der Provider stellt für ausgewählte Modelle eine benutzerdefinierte Denkstufenfolge oder binäre Bezeichnung bereit |
isBinaryThinking |
Kompatibilitäts-Hook zum Ein-/Ausschalten von Reasoning | Der Provider unterstützt nur binäres Ein-/Ausschalten des Denkens |
supportsXHighThinking |
Kompatibilitäts-Hook für die Reasoning-Unterstützung von xhigh |
Der Provider möchte xhigh nur für eine Teilmenge der Modelle verwenden |
resolveDefaultThinkingLevel |
Kompatibilitäts-Hook für die standardmäßige Stufe /think |
Der Provider legt die Standardrichtlinie für /think einer Modellfamilie fest |
isModernModelRef |
Matcher für moderne Modelle für Live-Profilfilter und Smoke-Auswahl | Der Provider legt den Abgleich bevorzugter Modelle für Live-/Smoke-Prüfungen fest |
prepareRuntimeAuth |
Konfigurierte Anmeldedaten unmittelbar vor der Inferenz gegen das tatsächliche Laufzeittoken bzw. den tatsächlichen Laufzeitschlüssel austauschen | Der Provider benötigt einen Tokenaustausch oder kurzlebige Anfrageanmeldedaten |
resolveUsageAuth |
Nutzungs-/Abrechnungsanmeldedaten für /usage und zugehörige Statusoberflächen auflösen |
Der Provider benötigt eine benutzerdefinierte Analyse von Nutzungs-/Kontingenttokens oder andere Anmeldedaten für die Nutzung |
fetchUsageSnapshot |
Provider-spezifische Nutzungs-/Kontingentmomentaufnahmen abrufen und normalisieren, nachdem die Authentifizierung aufgelöst wurde | Der Provider benötigt einen Provider-spezifischen Nutzungsendpunkt oder Nutzdatenparser |
createEmbeddingProvider |
Einen Provider-eigenen Embedding-Adapter für Speicher/Suche erstellen | Das Verhalten von Speicher-Embeddings gehört in das Provider-Plugin |
buildReplayPolicy |
Eine Replay-Richtlinie zurückgeben, die die Transkriptverarbeitung für den Provider steuert | Der Provider benötigt eine benutzerdefinierte Transkriptrichtlinie (zum Beispiel zum Entfernen von Thinking-Blöcken) |
sanitizeReplayHistory |
Den Replay-Verlauf nach der generischen Transkriptbereinigung neu schreiben | Der Provider benötigt Provider-spezifische Replay-Umschreibungen, die über gemeinsam genutzte Compaction-Hilfsfunktionen hinausgehen |
validateReplayTurns |
Abschließende Validierung oder Umformung des Replay-Turns vor dem eingebetteten Runner | Der Provider-Transport benötigt nach der generischen Bereinigung eine strengere Turn-Validierung |
onModelSelected |
Provider-eigene Nebeneffekte nach der Auswahl 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 durchlaufen dann weitere Hook-fähige Provider-Plugins,
bis eines tatsächlich die Modell-ID oder den Transport/die Konfiguration ändert. Dadurch
funktionieren Alias-/Kompatibilitäts-Provider-Shims weiterhin, ohne dass der Aufrufer wissen
muss, welches gebündelte Plugin für die Umschreibung zuständig ist. Wenn kein Provider-Hook
einen unterstützten Konfigurationseintrag der Google-Familie umschreibt, führt der gebündelte
Google-Konfigurationsnormalisierer diese Kompatibilitätsbereinigung weiterhin durch.
Wenn der Provider ein vollständig benutzerdefiniertes Wire-Protokoll oder einen benutzerdefinierten Request-Executor benötigt, handelt es sich um eine andere Erweiterungsklasse. Diese Hooks sind für Provider-Verhalten vorgesehen, das weiterhin in der normalen Inferenzschleife von OpenClaw ausgeführt wird.
resolveUsageAuth entscheidet, ob OpenClaw fetchUsageSnapshot aufrufen oder
für Nutzungs-/Statusoberflächen auf die generische Auflösung von Anmeldedaten
zurückgreifen soll. Geben Sie { token, accountId?, subscriptionType?, rateLimitTier? } zurück, wenn der Provider
über Nutzungsanmeldedaten verfügt (die optionalen Tarifmetadaten werden an
fetchUsageSnapshot weitergegeben), geben Sie
{ handled: true } zurück, wenn die Provider-eigene Nutzungsauthentifizierung die Anfrage
verarbeitet hat und den generischen API-Schlüssel-/OAuth-Fallback unterdrücken
muss, und geben Sie null oder undefined zurück,
wenn der Provider die Nutzungsauthentifizierung nicht verarbeitet hat.
Deklarieren Sie Organisations- oder Abrechnungsanmeldedaten im Manifest
providerUsageAuthEnvVars. Dadurch können generische Erkennungs- und
Secret-Bereinigungsoberflächen sie erkennen, ohne sie zu Kandidaten für die
Inferenzauthentifizierung zu machen.
Provider-Beispiel
api.registerProvider({ id: "example-proxy", label: "Beispiel-Proxy", auth: [], catalog: { order: "simple", run: async (ctx) => { const apiKey = ctx.resolveProviderApiKey("example-proxy").apiKey; if (!apiKey) { return null; } return { provider: { baseUrl: "https://proxy.example.com/v1", apiKey, api: "openai-completions", models: [{ id: "auto", name: "Automatisch" }], }, }; }, }, resolveDynamicModel: (ctx) => ({ id: ctx.modelId, name: ctx.modelId, provider: "example-proxy", api: "openai-completions", baseUrl: "https://proxy.example.com/v1", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128000, maxTokens: 8192, }), prepareRuntimeAuth: async (ctx) => { const exchanged = await exchangeToken(ctx.apiKey); return { apiKey: exchanged.token, baseUrl: exchanged.baseUrl, expiresAt: exchanged.expiresAt, }; }, resolveUsageAuth: async (ctx) => { const auth = await ctx.resolveOAuthToken(); return auth ? { token: auth.token } : null; }, fetchUsageSnapshot: async (ctx) => { return await fetchExampleProxyUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn); },});Integrierte Beispiele
Gebündelte Provider-Plugins kombinieren die obigen Hooks entsprechend den Anforderungen
des jeweiligen Anbieters an Katalog, Authentifizierung, Denkprozess, Replay und Nutzung.
Der maßgebliche Hook-Satz befindet sich bei jedem Plugin unter
extensions/; diese Seite veranschaulicht die Strukturen, anstatt die Liste
zu spiegeln.
Provider mit durchgereichtem Katalog
OpenRouter, Kilocode, Z.AI und xAI registrieren catalog sowie
resolveDynamicModel / prepareDynamicModel, damit sie vorgelagerte
Modell-IDs vor dem statischen Katalog von OpenClaw bereitstellen können.
Provider mit OAuth- und Nutzungsendpunkten
GitHub Copilot, Gemini CLI, ChatGPT Codex, MiniMax, Xiaomi und z.ai kombinieren
prepareRuntimeAuth oder formatApiKey mit resolveUsageAuth +
fetchUsageSnapshot, um den Token-Austausch und die Integration von
/usage zu übernehmen.
Familien für Replay- und Transkriptbereinigung
Gemeinsam benannte Familien (google-gemini, passthrough-gemini,
anthropic-by-model, hybrid-anthropic-openai) ermöglichen Providern, sich über
buildReplayPolicy für Transkriptrichtlinien zu entscheiden, statt die
Bereinigung in jedem Plugin erneut zu implementieren.
Provider nur mit Katalog
byteplus, cloudflare-ai-gateway, huggingface, kimi-coding, nvidia,
qianfan, synthetic, together, venice, vercel-ai-gateway und
volcengine registrieren lediglich catalog und verwenden die gemeinsame Inferenzschleife.
Anthropic-spezifische Stream-Helfer
Beta-Header, /fast / serviceTier und context1m befinden sich
innerhalb der öffentlichen api.ts- / contract-api.ts-Schnittstelle
des Anthropic-Plugins (wrapAnthropicProviderStream, resolveAnthropicBetas,
resolveAnthropicFastMode, resolveAnthropicServiceTier) statt im
generischen SDK.
Runtime-Helfer
Plugins können über api.runtime auf ausgewählte Core-Helfer zugreifen. Für TTS:
const clip = await api.runtime.tts.textToSpeech({ text: "Hallo von OpenClaw", cfg: api.config,}); const result = await api.runtime.tts.textToSpeechTelephony({ text: "Hallo von OpenClaw", cfg: api.config,}); const voices = await api.runtime.tts.listVoices({ provider: "elevenlabs", cfg: api.config,});Hinweise:
textToSpeechgibt die normale Core-TTS-Ausgabenutzlast für Datei-/Sprachnachrichtenoberflächen zurück.- Verwendet die Core-Konfiguration
ttsund die Provider-Auswahl. - Gibt einen PCM-Audiopuffer und die Abtastrate zurück. Plugins müssen für Provider neu abtasten/codieren.
listVoicesist je Provider optional. Verwenden Sie dies für anbietereigene Sprachauswahlen oder Einrichtungsabläufe.- Core übergibt eine aufgelöste Anfragefrist an die Provider-Hooks
listVoices; Provider-spezifische Zeitüberschreitungseinstellungen können sie überschreiben. - Stimmlisten können umfangreichere Metadaten wie Gebietsschema, Geschlecht und Persönlichkeitstags für Provider-spezifische Auswahlen enthalten.
- OpenAI und ElevenLabs unterstützen derzeit Telefonie. Microsoft nicht.
Plugins können über api.registerSpeechProvider(...) auch Sprachanbieter registrieren.
api.registerSpeechProvider({ id: "acme-speech", label: "Acme Speech", isConfigured: ({ config }) => Boolean(config.messages?.tts), synthesize: async (req) => { return { audioBuffer: Buffer.from([]), outputFormat: "mp3", fileExtension: ".mp3", voiceCompatible: false, }; },});Hinweise:
- Belassen Sie TTS-Richtlinien, Fallback und Antwortzustellung im Core.
- Verwenden Sie Sprachanbieter für anbietereigenes Syntheseverhalten.
- Die Legacy-Eingabe
edgevon Microsoft wird auf die Provider-IDmicrosoftnormalisiert. - Das bevorzugte Zuständigkeitsmodell ist unternehmensorientiert: Ein einziges Anbieter-Plugin kann Text-, Sprach-, Bild- und zukünftige Medien-Provider verwalten, wenn OpenClaw diese Fähigkeitsverträge hinzufügt.
Für das Verstehen von Bildern, Audio und Videos registrieren Plugins einen typisierten Provider für Medienverständnis anstelle einer generischen Schlüssel/Wert-Sammlung:
api.registerMediaUnderstandingProvider({ id: "google", capabilities: ["image", "audio", "video"], describeImage: async (req) => ({ text: "..." }), transcribeAudio: async (req) => ({ text: "..." }), describeVideo: async (req) => ({ text: "..." }),});Hinweise:
- Belassen Sie Orchestrierung, Fallback, Konfiguration und Kanalverdrahtung im Core.
- Belassen Sie anbieterspezifisches Verhalten im Provider-Plugin.
- Additive Erweiterungen sollten typisiert bleiben: neue optionale Methoden, neue optionale Ergebnisfelder, neue optionale Fähigkeiten.
- Die Videogenerierung folgt bereits demselben Muster:
- Core verwaltet den Fähigkeitsvertrag und den Runtime-Helfer.
- Anbieter-Plugins registrieren
api.registerVideoGenerationProvider(...). - Funktions-/Kanal-Plugins verwenden
api.runtime.videoGeneration.*.
Für Runtime-Helfer zum Medienverständnis können Plugins Folgendes aufrufen:
const image = await api.runtime.mediaUnderstanding.describeImageFile({ filePath: "/tmp/inbound-photo.jpg", cfg: api.config, agentDir: "/tmp/agent",}); const video = await api.runtime.mediaUnderstanding.describeVideoFile({ filePath: "/tmp/inbound-video.mp4", cfg: api.config,}); const extraction = await api.runtime.mediaUnderstanding.extractStructuredWithModel({ provider: "codex", model: "gpt-5.6-sol", input: [ { type: "image", buffer: receiptImageBuffer, fileName: "receipt.png", mime: "image/png", }, { type: "text", text: "Verwenden Sie die gedruckten Felder als maßgebliche Quelle." }, ], instructions: "Geben Sie Entitäten und durchsuchbare Tags zurück.", schemaName: "example.evidence", jsonSchema: { type: "object", properties: { entities: { type: "array", items: { type: "string" } }, tags: { type: "array", items: { type: "string" } }, }, }, cfg: api.config,});Für die Audiotranskription können Plugins entweder die Runtime für Medienverständnis oder den älteren STT-Alias verwenden:
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ filePath: "/tmp/inbound-audio.ogg", cfg: api.config, // Optional, wenn MIME nicht zuverlässig abgeleitet werden kann: mime: "audio/ogg",});Hinweise:
api.runtime.mediaUnderstanding.*ist die bevorzugte gemeinsame Oberfläche für das Verstehen von Bildern, Audio und Videos.extractStructuredWithModel(...)ist die Plugin-seitige Schnittstelle für begrenzte, Provider-eigene bildorientierte Extraktion. Fügen Sie mindestens eine Bildeingabe ein; Texteingaben sind ergänzender Kontext. Produkt-Plugins verwalten ihre Routen und Schemas, während OpenClaw die Provider-/Runtime-Grenze verwaltet.- Verwendet die Core-Audiokonfiguration für Medienverständnis (
tools.media.audio) und die Provider-Fallback-Reihenfolge. - Gibt
{ text: undefined }zurück, wenn keine Transkriptionsausgabe erzeugt wird (beispielsweise bei übersprungener/nicht unterstützter Eingabe).
Plugins können über api.runtime.subagent auch Subagent-Läufe im Hintergrund starten:
const result = await api.runtime.subagent.run({ sessionKey: "agent:main:subagent:search-helper", message: "Erweitern Sie diese Suchanfrage zu gezielten Folgesuchen.", toolsAlsoAllow: ["my_plugin_progress"], provider: "openai", model: "gpt-4.1-mini", deliver: false,});Hinweise:
providerundmodelsind optionale Überschreibungen je Lauf, keine dauerhaften Sitzungsänderungen.toolsAlsoAllowakzeptiert exakte, eindeutig zugeordnete Tool-Namen, die vom aufrufenden Plugin registriert wurden. Core-Namen und mehrdeutige Namen werden abgelehnt. Dies ergänzt das normale Profil, aber Betreiber-Zulassungs- und Sperrlisten bleiben maßgeblich.- OpenClaw berücksichtigt diese Überschreibungsfelder nur für vertrauenswürdige Aufrufer.
- Für Plugin-eigene Fallback-Läufe müssen Betreiber dies mit
plugins.entries.<id>.subagent.allowModelOverride: trueaktivieren. - Verwenden Sie
plugins.entries.<id>.subagent.allowedModels, um vertrauenswürdige Plugins auf bestimmte kanonischeprovider/model-Ziele zu beschränken, oder"*", um ausdrücklich jedes Ziel zuzulassen. - Subagent-Läufe nicht vertrauenswürdiger Plugins funktionieren weiterhin, aber Überschreibungsanfragen werden abgelehnt, anstatt stillschweigend auf den Fallback zurückzugreifen.
- Von Plugins erstellte Subagent-Sitzungen werden mit der ID des erstellenden Plugins gekennzeichnet. Der Fallback
api.runtime.subagent.deleteSession(...)darf nur diese eigenen Sitzungen löschen; das Löschen beliebiger Sitzungen erfordert weiterhin eine Gateway-Anfrage mit Administratorberechtigung.
Für die Websuche können Plugins den gemeinsamen Runtime-Helfer verwenden, anstatt auf die Verdrahtung des Agent-Tools zuzugreifen:
const providers = api.runtime.webSearch.listProviders({ config: api.config,}); const result = await api.runtime.webSearch.search({ config: api.config, args: { query: "Runtime-Helfer für OpenClaw-Plugins", count: 5, },});Plugins können über api.registerWebSearchProvider(...) auch Websuch-Provider registrieren.
Hinweise:
- Belassen Sie Provider-Auswahl, Auflösung von Anmeldedaten und gemeinsame Anfrage-Semantik im Core.
- Verwenden Sie Websuch-Provider für anbieterspezifische Suchtransporte.
api.runtime.webSearch.*ist die bevorzugte gemeinsame Oberfläche für Funktions-/Kanal-Plugins, die Suchverhalten benötigen, ohne vom Wrapper des Agent-Tools abhängig zu sein.
api.runtime.imageGeneration
const result = await api.runtime.imageGeneration.generate({ config: api.config, args: { prompt: "Ein freundliches Hummer-Maskottchen", size: "1024x1024" },}); const providers = api.runtime.imageGeneration.listProviders({ config: api.config,});generate(...): Generiert ein Bild mithilfe der konfigurierten Provider-Kette für die Bilderzeugung.listProviders(...): Listet verfügbare Provider für die Bilderzeugung und deren Fähigkeiten auf.
Gateway-HTTP-Routen
Plugins können mit api.registerHttpRoute(...) HTTP-Endpunkte bereitstellen.
api.registerHttpRoute({ path: "/acme/webhook", auth: "plugin", match: "exact", handler: async (_req, res) => { res.statusCode = 200; res.end("ok"); return true; },});Routenfelder:
path: Routenpfad unter dem Gateway-HTTP-Server.auth: Erforderlich,"gateway"oder"plugin". Verwenden Sie"gateway", um die normale Gateway-Authentifizierung zu verlangen, oder"plugin"für eine vom Plugin verwaltete Authentifizierung/Webhook-Verifizierung.match: Optional."exact"(Standard) oder"prefix".handleUpgrade: Optionaler Handler für WebSocket-Upgrade-Anfragen auf derselben Route.replaceExisting: Optional. Ermöglicht demselben Plugin, seine eigene vorhandene Routenregistrierung zu ersetzen.handler: Gibttruezurück, wenn die Route die Anfrage verarbeitet hat.
Hinweise:
api.registerHttpHandler(...)wurde entfernt und verursacht einen Fehler beim Laden des Plugins. Verwenden Sie stattdessenapi.registerHttpRoute(...).- Plugin-Routen müssen
authexplizit deklarieren. - Exakte Konflikte bei
path + matchwerden abgelehnt, sofern nichtreplaceExisting: truegilt, und ein Plugin kann die Route eines anderen Plugins nicht ersetzen. - Sich überschneidende Routen mit unterschiedlichen
auth-Stufen werden abgelehnt. Verwenden Sieexact- undprefix-Fallthrough-Ketten nur auf derselben Authentifizierungsstufe. auth: "plugin"-Routen erhalten nicht automatisch Operator-Laufzeitbereiche. Sie sind für vom Plugin verwaltete Webhooks bzw. Signaturverifizierung vorgesehen, nicht für privilegierte Aufrufe von Gateway-Hilfsfunktionen.auth: "gateway"-Routen werden innerhalb eines Gateway-Anfragelaufzeitbereichs ausgeführt. Die Standardoberfläche (gatewayRuntimeScopeSurface: "write-default") ist bewusst restriktiv:- Die Bearer-Authentifizierung mit gemeinsamem Geheimnis (
gateway.auth.mode = "token"/"password") sowie jede Authentifizierungsmethode ohne vertrauenswürdigen Proxy erhalten einen einzigenoperator.write-Bereich, selbst wenn der Aufruferx-openclaw-scopessendet. trusted-proxy-Aufrufer ohne explizitenx-openclaw-scopes-Header behalten ebenfalls die alte, ausschließlich aufoperator.writebeschränkte Oberfläche.trusted-proxy-Aufrufer, diex-openclaw-scopessenden, erhalten stattdessen die deklarierten Bereiche.- Eine Route kann
gatewayRuntimeScopeSurface: "trusted-operator"aktivieren, umx-openclaw-scopesbei identitätstragenden Authentifizierungsmodi stets zu berücksichtigen (wenn der Header fehlt, wird auf den vollständigen Standardsatz der CLI-Bereiche zurückgegriffen).
- Die Bearer-Authentifizierung mit gemeinsamem Geheimnis (
- Externe Control-UI-Tabs in einer Sandbox, die auf
auth: "gateway"-Routen basieren, verwenden eine kurzlebige, signierte Cookie-Berechtigung, die ausschließlich durch einen authentifizierten Bootstrap ausgestellt wird; Tabs mit Plugin-Authentifizierung behalten ihren direkten iframe-Pfad. Vor dem Einbinden führt das übergeordnete Element innerhalb derselben opaken Sandbox einen routeneigenen Test aus und verweigert den Zugriff, wenn die Datenschutzrichtlinie des Browsers das Cookie blockiert. Die Berechtigung ist an das besitzende Plugin, die übereinstimmende Routenwurzel und die aktuelle Authentifizierungsgeneration gebunden. Ihr pro Prozess zufällig gewählter Cookie-Name verhindert, dass vertrauenswürdige Gateways auf demselben Host einander überschreiben; Cookies isolieren jedoch niemals TCP-Ports. Der Gateway-Hostname bildet daher eine einzelne Anmeldedatengrenze: Stellen Sie unter diesem Hostnamen keine gegenseitig nicht vertrauenswürdigen Dienste bereit, auch nicht auf anderen Ports. Die Routenweiterleitung lehnt die Wiederverwendung für eine verschachtelte Route ab, die einem anderen Plugin gehört. Da Sandbox-Nachfahren für Cookie-Zwecke websiteübergreifend sind, akzeptiert die Berechtigung nurGETundHEADmitoperator.read; Änderungen und WebSocket-Upgrades verbleiben auf explizit über das Gateway authentifizierten Oberflächen. Das Cookie kann absichtlich nicht CHIPS verwenden: Aktuelle Browser beziehen ein Bit für websiteübergreifende Vorfahren in den Partitionierungsschlüssel ein, sodass verschachtelte opake Sandbox-Frames den Zugriff auf Ressourcen derselben Route verlieren würden. Das Cookie erfordert einen sicheren Kontext und die Browserberechtigung für websiteübergreifende Cookies. Daher sind externe Tabs mit Gateway-Authentifizierung auf LAN-Ursprüngen mit einfachem HTTP oder bei vollständiger Blockierung von Drittanbieter-Cookies nicht verfügbar. Verwenden Sie HTTPS/Tailscale Serve oder einen vom Browser als vertrauenswürdig eingestuften Loopback mit einer kompatiblen Cookie-Richtlinie. - Die Berechtigung verhindert die Offenlegung des Gateway-Bearer-Tokens und die versehentliche Wiederverwendung von Routen oder Bereichen; sie schafft keine Sicherheitsgrenze zwischen nativen Plugins. Nativer Plugin-Code und die von ihm bereitgestellten UI-Inhalte bleiben Teil derselben vertrauenswürdigen prozessinternen Plugin-Grenze.
- Praktische Regel: Gehen Sie nicht davon aus, dass eine Plugin-Route mit Gateway-Authentifizierung implizit eine Administratoroberfläche ist. Wenn Ihre Route ausschließlich Administratoren vorbehaltenes Verhalten benötigt, aktivieren Sie die
trusted-operator-Bereichsoberfläche, verlangen Sie einen identitätstragenden Authentifizierungsmodus und dokumentieren Sie den expliziten Vertrag für denx-openclaw-scopes-Header. - Nach Routenabgleich und Authentifizierung nehmen gewöhnliche Handler an der Zulassung für Gateway-Stammaufgaben teil. Ein vorbereitetes oder neu startendes Gateway gibt
503zurück, bevor der Handler aufgerufen wird. Die eng begrenzte Ausnahme ist eine durch das Manifest berechtigteauth: "gateway"-Route, die zusätzlich die routenspezifischetrusted-operator-Oberfläche aktiviert. Sie bleibt erreichbar, damit die Weiterleitung der Aussetzungssteuerung nicht blockiert wird, während gewöhnliche benachbarte Routen desselben Plugins hinter der Zulassungsgrenze verbleiben. Die Eigentümerschaft für WebSocket-handleUpgradeverwendet dieselbe atomare Zulassungsgrenze. Sobald der Handler einen Socket akzeptiert, liegt dessen weitere Lebensdauer in der Verantwortung des Plugins und wird von dieser Grenze nicht verfolgt.
Importpfade des Plugin SDK
Verwenden Sie beim Erstellen neuer Plugins schmale SDK-Unterpfade anstelle des monolithischen
openclaw/plugin-sdk-Stamm-Barrels. Kernunterpfade:
| Unterpfad | Zweck |
|---|---|
openclaw/plugin-sdk/plugin-entry |
Primitive für die Plugin-Registrierung |
openclaw/plugin-sdk/channel-core |
Hilfsfunktionen für Kanaleinstieg und -Build |
openclaw/plugin-sdk/core |
Generische gemeinsame Hilfsfunktionen und übergreifender Vertrag |
Kanal-Plugins wählen aus einer Familie schmaler Schnittstellen – channel-setup,
setup-runtime, setup-tools, channel-pairing,
channel-contract, channel-feedback, channel-inbound, channel-outbound,
command-auth, secret-input, webhook-ingress,
channel-targets und channel-actions. Das Genehmigungsverhalten sollte in
einem einzigen approvalCapability-Vertrag zusammengeführt werden, statt nicht zusammengehörige
Plugin-Felder zu vermischen. Siehe Kanal-Plugins.
Laufzeit- und Konfigurationshilfen befinden sich unter entsprechenden fokussierten *-runtime-Unterpfaden
(approval-runtime, agent-runtime, lazy-runtime, directory-runtime,
text-runtime, runtime-store, system-event-runtime, heartbeat-runtime,
channel-activity-runtime usw.). Bevorzugen Sie config-contracts,
plugin-config-runtime, runtime-config-snapshot und config-mutation
anstelle des breiten config-runtime-Kompatibilitäts-Barrels.
Repo-interne Einstiegspunkte (je Stammverzeichnis eines gebündelten Plugin-Pakets):
index.js– Einstiegspunkt des gebündelten Pluginsapi.js– Barrel für Hilfsfunktionen und Typenruntime-api.js– ausschließlich für die Laufzeit bestimmtes Barrelsetup-entry.js– Einstiegspunkt des Einrichtungs-Plugins
Externe Plugins sollten ausschließlich openclaw/plugin-sdk/*-Unterpfade importieren. Importieren Sie
niemals src/* aus dem Paket eines anderen Plugins in den Kern oder ein anderes Plugin.
Über Fassaden geladene Einstiegspunkte bevorzugen den aktiven Schnappschuss der Laufzeitkonfiguration,
wenn einer vorhanden ist, und greifen andernfalls auf die auf dem Datenträger aufgelöste Konfigurationsdatei zurück.
Fähigkeitsspezifische Unterpfade wie image-generation, media-understanding
und speech sind vorhanden, weil gebündelte Plugins sie derzeit verwenden. Sie sind nicht
automatisch langfristig unveränderliche externe Verträge – prüfen Sie die entsprechende SDK-
Referenzseite, wenn Sie sich auf sie verlassen.
Schemas des Nachrichtenwerkzeugs
Plugins sollten für kanalspezifische describeMessageTool(...)-Schema-
Beiträge für Primitive zuständig sein, die keine Nachrichten sind, etwa Reaktionen, Lesebestätigungen und Umfragen.
Für die gemeinsame Sendedarstellung sollte der generische MessagePresentation-Vertrag
anstelle von Provider-nativen Schaltflächen-, Komponenten-, Block- oder Kartenfeldern verwendet werden.
Unter Nachrichtendarstellung finden Sie den Vertrag,
die Fallback-Regeln, die Provider-Zuordnung und die Checkliste für Plugin-Autoren.
Sendefähige Plugins deklarieren über Nachrichtenfähigkeiten, was sie darstellen können:
presentationfür semantische Darstellungsblöcke (text,context,divider,chart,table,buttons,select)delivery-pinfür Anfragen zur angehefteten Zustellung
Der Kern entscheidet, ob die Darstellung nativ gerendert oder auf Text reduziert wird. Stellen Sie keine Provider-nativen UI-Ausweichmöglichkeiten über das generische Nachrichtenwerkzeug bereit. Veraltete SDK-Hilfsfunktionen für ältere native Schemas werden für vorhandene Drittanbieter-Plugins weiterhin exportiert, neue Plugins sollten sie jedoch nicht verwenden.
Auflösung von Kanalzielen
Kanal-Plugins sollten für kanalspezifische Zielsemantiken zuständig sein. Halten Sie den gemeinsamen ausgehenden Host generisch und verwenden Sie die Messaging-Adapter-Oberfläche für Provider-Regeln:
messaging.inferTargetChatType({ to })entscheidet vor der Verzeichnissuche, ob ein normalisiertes Ziel alsdirect,groupoderchannelbehandelt werden soll.messaging.targetResolver.looksLikeId(raw, normalized)teilt dem Kern mit, ob eine Eingabe unter Umgehung der Verzeichnissuche direkt mit einer ID-ähnlichen Auflösung verarbeitet werden soll.messaging.targetResolver.reservedLiteralsführt alleinstehende Wörter auf, die für diesen Provider Kanal- oder Sitzungsreferenzen darstellen. Bei der Auflösung werden konfigurierte Verzeichniseinträge berücksichtigt, bevor reservierte Literale abgelehnt werden; bei einem Fehlschlag der Verzeichnissuche wird der Zugriff anschließend verweigert.messaging.targetResolver.resolveTarget(...)ist der Plugin-Fallback, wenn der Kern nach der Normalisierung oder nach einem Fehlschlag der Verzeichnissuche eine abschließende Provider-eigene Auflösung benötigt.messaging.resolveOutboundSessionRoute(...)ist nach der Auflösung eines Ziels für die Provider-spezifische Konstruktion der Sitzungsroute zuständig.
Empfohlene Aufteilung:
- Verwenden Sie
inferTargetChatTypefür Kategorieentscheidungen, die vor der Suche nach Peers/Gruppen erfolgen sollen. - Verwenden Sie
looksLikeIdfür Prüfungen nach dem Muster „Dies als explizite/native Ziel-ID behandeln“. - Verwenden Sie
resolveTargetfür den Provider-spezifischen Normalisierungs-Fallback, nicht für eine umfassende Verzeichnissuche. - Belassen Sie Provider-native IDs wie Chat-IDs, Thread-IDs, JIDs, Handles und Raum-
IDs in
target-Werten oder Provider-spezifischen Parametern, nicht in generischen SDK- Feldern.
Konfigurationsgestützte Verzeichnisse
Plugins, die Verzeichniseinträge aus der Konfiguration ableiten, sollten diese Logik im
Plugin belassen und die gemeinsamen Hilfsfunktionen aus
openclaw/plugin-sdk/directory-runtime wiederverwenden.
Verwenden Sie dies, wenn ein Kanal konfigurationsgestützte Peers/Gruppen benötigt, beispielsweise:
- durch Zulassungslisten gesteuerte Direktnachrichten-Peers
- konfigurierte Kanal-/Gruppenzuordnungen
- kontobezogene statische Verzeichnis-Fallbacks
Die gemeinsamen Hilfsfunktionen in directory-runtime verarbeiten ausschließlich generische Operationen:
- Abfragefilterung
- Anwendung von Begrenzungen
- Hilfsfunktionen für Deduplizierung/Normalisierung
- Erstellung von
ChannelDirectoryEntry[]
Kanalspezifische Kontoprüfung und ID-Normalisierung sollten in der Plugin-Implementierung verbleiben.
Provider-Kataloge
Provider-Plugins können mit registerProvider({ catalog: { run(...) { ... } } })
Modellkataloge für Inferenz definieren.
catalog.run(...) gibt dieselbe Struktur zurück, die OpenClaw in
models.providers schreibt:
{ provider }für einen Provider-Eintrag{ providers }für mehrere Provider-Einträge
Verwenden Sie catalog, wenn das Plugin providerspezifische Modell-IDs, Standardwerte
für die Basis-URL oder authentifizierungsabhängige Modellmetadaten verwaltet.
catalog.order steuert, wann der Katalog eines Plugins relativ zu den integrierten
impliziten Providern von OpenClaw zusammengeführt wird:
simple: einfache Provider mit API-Schlüssel oder umgebungsvariablengesteuerte Providerprofile: Provider, die angezeigt werden, wenn Authentifizierungsprofile vorhanden sindpaired: Provider, die mehrere zusammengehörige Provider-Einträge erzeugenlate: letzter Durchlauf nach anderen impliziten Providern
Bei Schlüsselkollisionen haben spätere Provider Vorrang, sodass Plugins einen integrierten Provider-Eintrag mit derselben Provider-ID absichtlich überschreiben können.
Plugins können über api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog }) auch schreibgeschützte Modellzeilen
veröffentlichen. Dies ist der vorgesehene Weg für Listen-, Hilfe- und Auswahloberflächen und unterstützt
Zeilen vom Typ text, voice, image_generation, video_generation und music_generation.
Provider-Plugins verwalten weiterhin Live-Endpunktaufrufe, den Token-Austausch und
die Zuordnung von Anbieterantworten; der Core verwaltet die gemeinsame Zeilenstruktur, Quellenbezeichnungen und
die Formatierung der Hilfe für Medienwerkzeuge. Registrierungen von Providern zur Mediengenerierung erzeugen
automatisch statische Katalogzeilen aus defaultModel, models und
capabilities.
Kompatibilität:
discoveryfunktioniert weiterhin als veralteter Alias, gibt jedoch eine Veraltungswarnung aus- wenn sowohl
catalogals auchdiscoveryregistriert sind, verwendet OpenClawcatalogund gibt eine Warnung aus augmentModelCatalogist veraltet; gebündelte Provider sollten ergänzende Zeilen überregisterModelCatalogProviderveröffentlichen
Schreibgeschützte Kanalprüfung
Wenn Ihr Plugin einen Kanal registriert, implementieren Sie vorzugsweise
plugin.config.inspectAccount(cfg, accountId) zusammen mit resolveAccount(...).
Warum:
resolveAccount(...)ist der Laufzeitpfad. Er darf davon ausgehen, dass Anmeldedaten vollständig materialisiert sind, und kann sofort fehlschlagen, wenn erforderliche Geheimnisse fehlen.- Schreibgeschützte Befehlspfade wie
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolvesowie Reparaturabläufe für Doctor und Konfiguration sollten keine Laufzeitanmeldedaten materialisieren müssen, nur um die Konfiguration zu beschreiben.
Empfohlenes Verhalten von inspectAccount(...):
- Geben Sie nur einen beschreibenden Kontostatus zurück.
- Behalten Sie
enabledundconfiguredbei. - Fügen Sie gegebenenfalls Felder für Quelle und Status der Anmeldedaten hinzu, beispielsweise:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Sie müssen keine Rohwerte von Tokens zurückgeben, nur um die schreibgeschützte
Verfügbarkeit zu melden. Die Rückgabe von
tokenStatus: "available"(und des zugehörigen Quellenfelds) genügt für statusähnliche Befehle. - Verwenden Sie
configured_unavailable, wenn Anmeldedaten über SecretRef konfiguriert, im aktuellen Befehlspfad jedoch nicht verfügbar sind.
Dadurch können schreibgeschützte Befehle „konfiguriert, aber in diesem Befehlspfad nicht verfügbar“ melden, statt abzustürzen oder das Konto fälschlicherweise als nicht konfiguriert auszuweisen.
Paket-Packs
Ein Plugin-Verzeichnis kann eine package.json mit openclaw.extensions enthalten:
{ "name": "my-pack", "openclaw": { "extensions": ["./src/safety.ts", "./src/tools.ts"], "setupEntry": "./src/setup-entry.ts" }}Jeder Eintrag wird zu einem Plugin. Wenn das Pack mehrere Erweiterungen auflistet, wird die Plugin-ID
zu <manifestOrPackageName>/<fileBase> (die Manifest-ID hat Vorrang, sofern
vorhanden; andernfalls der Name package.json ohne Gültigkeitsbereich).
Wenn Ihr Plugin npm-Abhängigkeiten importiert, installieren Sie diese in diesem Verzeichnis, damit
node_modules verfügbar ist (npm install / pnpm install).
Sicherheitsvorkehrung: Jeder openclaw.extensions-Eintrag muss nach der Auflösung
symbolischer Links innerhalb des Plugin-Verzeichnisses verbleiben. Einträge, die das Paketverzeichnis verlassen,
werden abgelehnt.
Sicherheitshinweis: openclaw plugins install installiert Plugin-Abhängigkeiten mit einer
projektlokalen npm install --omit=dev --ignore-scripts (keine Lebenszyklusskripte,
keine Entwicklungsabhängigkeiten zur Laufzeit) und ignoriert dabei geerbte globale npm-Installationseinstellungen.
Halten Sie die Abhängigkeitsbäume von Plugins „reines JS/TS“ und vermeiden Sie Pakete, die
postinstall-Builds erfordern.
Optional: openclaw.setupEntry kann auf ein schlankes, ausschließlich für die Einrichtung vorgesehenes Modul verweisen.
Wenn OpenClaw Einrichtungsoberflächen für ein deaktiviertes Kanal-Plugin benötigt oder
wenn ein Kanal-Plugin aktiviert, aber noch nicht konfiguriert ist, lädt es setupEntry
anstelle des vollständigen Plugin-Eintrags. Dadurch bleiben Start und Einrichtung schlanker,
wenn Ihr Haupt-Plugin-Eintrag außerdem Werkzeuge, Hooks oder anderen ausschließlich zur Laufzeit benötigten
Code einbindet.
Optional: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen
kann ein Kanal-Plugin während der Startphase vor dem Lauschen des Gateways für denselben
setupEntry-Pfad aktivieren, auch wenn der Kanal bereits konfiguriert ist.
Verwenden Sie dies nur, wenn setupEntry die Startoberfläche vollständig abdeckt, die vorhanden sein muss,
bevor das Gateway mit dem Lauschen beginnt. In der Praxis bedeutet dies, dass der Einrichtungseintrag
jede kanaleigene Fähigkeit registrieren muss, von der der Start abhängt, beispielsweise:
- die Kanalregistrierung selbst
- alle HTTP-Routen, die verfügbar sein müssen, bevor das Gateway mit dem Lauschen beginnt
- alle Gateway-Methoden, Werkzeuge oder Dienste, die im selben Zeitfenster vorhanden sein müssen
Wenn Ihr vollständiger Eintrag weiterhin eine erforderliche Startfähigkeit verwaltet, aktivieren Sie dieses Flag nicht. Behalten Sie für das Plugin das Standardverhalten bei und lassen Sie OpenClaw während des Starts den vollständigen Eintrag laden.
Gebündelte Kanäle können außerdem ausschließlich für die Einrichtung vorgesehene Hilfsfunktionen für Vertragsoberflächen veröffentlichen, die der Core abfragen kann, bevor die vollständige Kanallaufzeit geladen wird. Die aktuelle Einrichtungsoberfläche für die Hochstufung ist:
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
Der Core verwendet diese Oberfläche, wenn er eine veraltete Einkonto-Kanalkonfiguration
in channels.<id>.accounts.* überführen muss, ohne den vollständigen Plugin-Eintrag zu laden.
Matrix ist das aktuelle gebündelte Beispiel: Wenn benannte Konten bereits vorhanden sind, verschiebt es
nur Authentifizierungs-/Bootstrap-Schlüssel in ein benanntes hochgestuftes Konto und kann einen
konfigurierten, nicht kanonischen Schlüssel für das Standardkonto beibehalten, statt immer
accounts.default zu erstellen.
Diese Einrichtungs-Patch-Adapter halten die Erkennung gebündelter Vertragsoberflächen verzögert. Die Importzeit bleibt kurz; die Hochstufungsoberfläche wird erst bei der ersten Verwendung geladen, statt den Start gebündelter Kanäle beim Modulimport erneut auszuführen.
Wenn diese Startoberflächen Gateway-RPC-Methoden enthalten, behalten Sie dafür ein
Plugin-spezifisches Präfix bei. Die Core-Admin-Namensräume (config.*,
exec.approvals.*, wizard.*, update.*) bleiben reserviert und werden stets
zu operator.admin aufgelöst, selbst wenn ein Plugin einen engeren Gültigkeitsbereich anfordert.
Beispiel:
{ "name": "@scope/my-channel", "openclaw": { "extensions": ["./index.ts"], "setupEntry": "./setup-entry.ts", "startup": { "deferConfiguredChannelFullLoadUntilAfterListen": true } }}Kanalkatalog-Metadaten
Kanal-Plugins können Einrichtungs-/Erkennungsmetadaten über openclaw.channel und
Installationshinweise über openclaw.install bereitstellen. Dadurch bleibt der Core-Katalog datenfrei.
Beispiel:
{ "name": "@openclaw/nextcloud-talk", "openclaw": { "extensions": ["./index.ts"], "channel": { "id": "nextcloud-talk", "label": "Nextcloud Talk", "selectionLabel": "Nextcloud Talk (selbst gehostet)", "docsPath": "/channels/nextcloud-talk", "docsLabel": "nextcloud-talk", "blurb": "Selbst gehosteter Chat über Nextcloud-Talk-Webhook-Bots.", "order": 65, "aliases": ["nc-talk", "nc"] }, "install": { "npmSpec": "@openclaw/nextcloud-talk", "localPath": "<bundled-plugin-local-path>", "defaultChoice": "npm" } }}Nützliche openclaw.channel-Felder über das Minimalbeispiel hinaus:
detailLabel: sekundäre Bezeichnung für umfangreichere Katalog-/StatusoberflächendocsLabel: Linktext für den Dokumentationslink überschreibenpreferOver: Plugin-/Kanal-IDs mit niedrigerer Priorität, die dieser Katalogeintrag übertreffen sollselectionDocsPrefix,selectionDocsOmitLabel,selectionExtras: Textsteuerung für AuswahloberflächenmarkdownCapable: kennzeichnet den Kanal für Entscheidungen zur ausgehenden Formatierung als Markdown-fähigexposure.configured: blendet den Kanal auf Oberflächen zur Auflistung konfigurierter Kanäle aus, wenn auffalsegesetztexposure.setup: blendet den Kanal in interaktiven Auswahlmenüs für Einrichtung/Konfiguration aus, wenn auffalsegesetztexposure.docs: kennzeichnet den Kanal für Dokumentationsnavigationsoberflächen als intern/privatquickstartAllowFrom: nimmt den Kanal in den standardmäßigen SchnellstartablaufallowFromaufforceAccountBinding: erfordert eine explizite Kontobindung, auch wenn nur ein Konto vorhanden istpreferSessionLookupForAnnounceTarget: bevorzugt bei der Auflösung von Ankündigungszielen die Sitzungssuche
OpenClaw kann außerdem externe Kanalkataloge zusammenführen (beispielsweise einen Export einer MPM-Registry). Legen Sie eine JSON-Datei an einem der folgenden Orte ab:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
Oder lassen Sie OPENCLAW_PLUGIN_CATALOG_PATHS (oder OPENCLAW_MPM_CATALOG_PATHS) auf
eine oder mehrere JSON-Dateien verweisen (durch Kommas/Semikolons/PATH getrennt). Jede Datei sollte
{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] } enthalten. Der Parser akzeptiert außerdem "packages" oder "plugins" als veraltete Aliase für den Schlüssel "entries".
Generierte Kanalkatalogeinträge und Katalogeinträge für Provider-Installationen stellen
normalisierte Fakten zur Installationsquelle neben dem rohen openclaw.install-Block bereit. Die
normalisierten Fakten geben an, ob es sich bei der npm-Spezifikation um eine exakte Version oder einen flexiblen
Selektor handelt, ob erwartete Integritätsmetadaten vorhanden sind und ob außerdem ein lokaler
Quellpfad verfügbar ist. Wenn die Katalog-/Paketidentität bekannt ist, warnen die
normalisierten Fakten, falls der analysierte npm-Paketname von dieser Identität abweicht.
Sie warnen außerdem, wenn defaultChoice ungültig ist oder auf eine nicht
verfügbare Quelle verweist, sowie wenn npm-Integritätsmetadaten ohne eine gültige npm-Quelle
vorhanden sind. Verbraucher sollten installSource als additives optionales Feld behandeln, damit
manuell erstellte Einträge und Katalog-Shims es nicht erzeugen müssen.
Dadurch können Onboarding und Diagnosen den Status der Quellenebene erklären, ohne
die Plugin-Laufzeit zu importieren.
Offizielle externe npm-Einträge sollten eine exakte npmSpec zusammen mit
expectedIntegrity bevorzugen. Reine Paketnamen und Dist-Tags funktionieren aus
Kompatibilitätsgründen weiterhin, zeigen jedoch Warnungen der Quellenebene an, sodass der Katalog schrittweise
zu angehefteten, integritätsgeprüften Installationen übergehen kann, ohne vorhandene Plugins zu beeinträchtigen.
Wenn das Onboarding aus einem lokalen Katalogpfad installiert, zeichnet es einen verwalteten
Plugin-Indexeintrag mit source: "path" und nach Möglichkeit einem arbeitsbereichsrelativen
sourcePath auf. Der absolute operative Ladepfad verbleibt in
plugins.load.paths; der Installationsdatensatz vermeidet es, lokale Arbeitsstationspfade
in langlebige Konfigurationen zu duplizieren. Dadurch bleiben lokale Entwicklungsinstallationen für
Diagnosen der Quellenebene sichtbar, ohne eine zweite Offenlegungsoberfläche für rohe Dateisystempfade
hinzuzufügen. Die persistierte SQLite-Tabelle installed_plugin_index ist die maßgebliche Quelle
für Installationen und kann aktualisiert werden, ohne Plugin-Laufzeitmodule zu laden.
Ihre installRecords-Zuordnung ist dauerhaft, selbst wenn ein Plugin-Manifest fehlt oder
ungültig ist; ihre plugins-Nutzlast ist eine wiederherstellbare Manifestansicht.
Kontext-Engine-Plugins
Kontext-Engine-Plugins verwalten die Orchestrierung des Sitzungskontexts für Aufnahme, Zusammenstellung
und Compaction. Registrieren Sie diese aus Ihrem Plugin mit
api.registerContextEngine(id, factory) und wählen Sie anschließend die aktive Engine mit
plugins.slots.contextEngine aus.
Verwenden Sie dies, wenn Ihr Plugin die standardmäßige Kontext-Pipeline ersetzen oder erweitern muss, statt lediglich Speichersuche oder Hooks hinzuzufügen.
export default function (api) { api.registerContextEngine("lossless-claw", (ctx) => ({ info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true }, async ingest() { return { ingested: true }; }, async assemble({ messages, sessionKey, availableTools, citationsMode }) { return { messages, estimatedTokens: 0, systemPromptAddition: buildMemorySystemPromptAddition({ availableTools: availableTools ?? new Set(), citationsMode, agentSessionKey: sessionKey, }), }; }, async compact() { return { ok: true, compacted: false }; }, }));}Die Factory ctx stellt optionale Werte für config, agentDir und workspaceDir
zur Initialisierung bei der Konstruktion bereit.
Der Host schließt die registrierte asynchrone Vorbereitung des Memory-Prompts ab, bevor er
assemble() einer nicht veralteten Engine aufruft. buildMemorySystemPromptAddition(...) bleibt
synchron und liest diesen unveränderlichen Snapshot des Laufs, während assemble() aktiv ist.
Reichen Sie den bereitgestellten Tool- und Zitierkontext unverändert durch, damit der Snapshot
keine Laufgrenzen überschreiten kann.
assemble() kann contextProjection zurückgeben, wenn das aktive Harness über einen
persistenten Backend-Thread verfügt. Lassen Sie es bei einer veralteten Projektion pro Turn weg. Geben Sie
{ mode: "thread_bootstrap", epoch } zurück, wenn der zusammengesetzte Kontext
einmal in einen Backend-Thread eingefügt und wiederverwendet werden soll, bis sich die Epoche ändert. Ändern Sie
die Epoche, nachdem sich der semantische Kontext der Engine geändert hat, beispielsweise nach einem
von der Engine verwalteten Compaction-Durchlauf. Hosts können Metadaten von Tool-Aufrufen, die Eingabeform
und redigierte Tool-Ergebnisse in einer Thread-Bootstrap-Projektion beibehalten, sodass neue
Backend-Threads die Tool-Kontinuität wahren, ohne rohe, geheimnishaltige
Payloads zu kopieren.
Wenn Ihre Engine den Compaction-Algorithmus nicht verwaltet, lassen Sie compact()
implementiert und delegieren Sie ihn ausdrücklich:
buildMemorySystemPromptAddition, delegateCompactionToRuntime,} from "openclaw/plugin-sdk/core"; export default function (api) { api.registerContextEngine("my-memory-engine", (ctx) => ({ info: { id: "my-memory-engine", name: "My Memory Engine", ownsCompaction: false, }, async ingest() { return { ingested: true }; }, async assemble({ messages, sessionKey, availableTools, citationsMode }) { return { messages, estimatedTokens: 0, systemPromptAddition: buildMemorySystemPromptAddition({ availableTools: availableTools ?? new Set(), citationsMode, agentSessionKey: sessionKey, }), }; }, async compact(params) { return await delegateCompactionToRuntime(params); }, }));}Eine neue Fähigkeit hinzufügen
Wenn ein Plugin ein Verhalten benötigt, das nicht zur aktuellen API passt, umgehen Sie das Plugin-System nicht durch einen privaten direkten Zugriff. Fügen Sie die fehlende Fähigkeit hinzu.
Empfohlene Reihenfolge:
- Definieren Sie den Core-Vertrag. Legen Sie fest, welches gemeinsame Verhalten der Core verwalten soll: Richtlinien, Fallback, Zusammenführung der Konfiguration, Lebenszyklus, kanalbezogene Semantik und Form der Runtime-Hilfsfunktion.
- Fügen Sie typisierte Oberflächen für Plugin-Registrierung und Runtime hinzu. Erweitern Sie
OpenClawPluginApiund/oderapi.runtimeum die kleinstmögliche sinnvolle typisierte Fähigkeitsoberfläche. - Binden Sie Core sowie Kanal- und Funktionskonsumenten an. Kanäle und Funktions-Plugins sollten die neue Fähigkeit über den Core nutzen, statt eine Implementierung eines Providers direkt zu importieren.
- Registrieren Sie Provider-Implementierungen. Provider-Plugins registrieren anschließend ihre Backends für die Fähigkeit.
- Fügen Sie Vertragsabdeckung hinzu. Fügen Sie Tests hinzu, damit die Zuständigkeit und die Registrierungsform dauerhaft explizit bleiben.
So bleibt OpenClaw meinungsstark, ohne die Weltsicht eines einzelnen Providers fest zu codieren. Eine konkrete Datei-Checkliste und ein ausgearbeitetes Beispiel finden Sie im Kochbuch für Fähigkeiten.
Checkliste für Fähigkeiten
Wenn Sie eine neue Fähigkeit hinzufügen, sollte die Implementierung in der Regel die folgenden Oberflächen gemeinsam berücksichtigen:
- Core-Vertragstypen in
src/<capability>/types.ts - Core-Runner bzw. Runtime-Hilfsfunktion in
src/<capability>/runtime.ts - Registrierungsoberfläche der Plugin-API in
src/plugins/types.ts - Verdrahtung der Plugin-Registry in
src/plugins/registry.ts - Bereitstellung in der Plugin-Runtime in
src/plugins/runtime/*, wenn Funktions- oder Kanal-Plugins sie nutzen müssen - Erfassungs- und Testhilfen in
src/test-utils/plugin-registration.ts - Zusicherungen zu Zuständigkeit und Vertrag in
src/plugins/contracts/registry.ts - Dokumentation für Betreiber und Plugins in
docs/
Wenn eine dieser Oberflächen fehlt, ist dies in der Regel ein Zeichen dafür, dass die Fähigkeit noch nicht vollständig integriert ist.
Vorlage für Fähigkeiten
Minimales Muster:
// core contractexport type VideoGenerationProviderPlugin = { id: string; label: string; generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;}; // plugin APIapi.registerVideoGenerationProvider({ id: "openai", label: "OpenAI", async generateVideo(req) { return await generateOpenAiVideo(req); },}); // shared runtime helper for feature/channel pluginsconst clip = await api.runtime.videoGeneration.generate({ prompt: "Show the robot walking through the lab.", cfg,});Muster für Vertragstests (src/plugins/contracts/registry.ts stellt Abfragen zur Zuständigkeit
wie providerContractPluginIds bereit; Tests stellen sicher, dass die
contracts.videoGenerationProviders-Liste eines Plugins seinen tatsächlichen Registrierungen entspricht):
expect(pluginManifest.contracts?.videoGenerationProviders).toEqual(["openai"]);Dadurch bleibt die Regel einfach:
- Der Core verwaltet den Fähigkeitsvertrag und die Orchestrierung
- Provider-Plugins verwalten die Provider-Implementierungen
- Funktions- und Kanal-Plugins nutzen Runtime-Hilfsfunktionen
- Vertragstests halten die Zuständigkeit explizit fest
Verwandte Themen
- Plugin-Architektur — öffentliches Fähigkeitsmodell und Formen
- Unterpfade des Plugin SDK
- Einrichtung des Plugin SDK
- Plugins erstellen