Plugin SDK reference

Hilfsfunktionen für die Plugin-Laufzeit

Referenz für das Objekt api.runtime, das bei der Registrierung in jedes Plugin injiziert wird. Verwenden Sie diese Hilfsfunktionen, anstatt Host-Interna direkt zu importieren.

typescript
register(api) {  const runtime = api.runtime;}

api.runtime.version ist die aktuelle OpenClaw-Produktversion. Sie stammt aus der gemeinsamen Versionsauflösung, sodass Plugins denselben Wert sehen, den die CLI meldet.

Laden und Schreiben der Konfiguration

Bevorzugen Sie Konfigurationen, die bereits an den aktiven Aufrufpfad übergeben wurden, beispielsweise api.config während der Registrierung oder ein cfg-Argument in Kanal-/Provider-Callbacks. Dadurch wird ein einziger Prozess-Snapshot durch den Arbeitsablauf weitergereicht, anstatt die Konfiguration in häufig ausgeführten Pfaden erneut zu parsen.

Verwenden Sie api.runtime.config.current() nur, wenn ein langlebiger Handler den aktuellen Prozess-Snapshot benötigt und keine Konfiguration an diese Funktion übergeben wurde. Der zurückgegebene Wert ist schreibgeschützt; klonen Sie ihn oder verwenden Sie vor der Bearbeitung eine Mutationshilfsfunktion.

Tool-Fabriken erhalten ctx.runtimeConfig sowie ctx.getRuntimeConfig(). Verwenden Sie den Getter innerhalb des execute-Callbacks eines langlebigen Tools, wenn sich die Konfiguration nach Erstellung der Tool-Definition ändern kann.

Speichern Sie Änderungen mit api.runtime.config.mutateConfigFile(...) oder api.runtime.config.replaceConfigFile(...). Bei jedem Schreibvorgang muss ausdrücklich eine afterWrite-Richtlinie ausgewählt werden:

  • afterWrite: { mode: "auto" } überlässt die Entscheidung dem Planer für Gateway-Neuladungen.
  • afterWrite: { mode: "restart", reason: "..." } erzwingt einen sauberen Neustart, wenn der schreibende Code weiß, dass ein Neuladen im laufenden Betrieb unsicher ist.
  • afterWrite: { mode: "none", reason: "..." } unterdrückt ein automatisches Neuladen bzw. einen automatischen Neustart nur dann, wenn der Aufrufer für die Folgemaßnahme verantwortlich ist.

Die Mutationshilfsfunktionen geben afterWrite sowie eine typisierte followUp-Zusammenfassung zurück, damit Aufrufer protokollieren oder testen können, ob sie einen Neustart angefordert haben. Die Entscheidung, wann dieser Neustart tatsächlich erfolgt, liegt weiterhin beim Gateway.

Bevorzugen Sie bei direkten SDK-Importen die gezielten Konfigurations-Unterpfade gegenüber dem breiten Kompatibilitäts-Barrel openclaw/plugin-sdk/config-runtime: config-contracts für Typen, plugin-config-runtime für Prüfungen bereits geladener Konfigurationen und die Suche nach Plugin-Einstiegspunkten, runtime-config-snapshot für aktuelle Prozess-Snapshots und config-mutation für Schreibvorgänge. Tests gebündelter Plugins sollten diese gezielten Unterpfade direkt mocken, anstatt das breite Kompatibilitäts-Barrel zu mocken.

Der interne OpenClaw-Laufzeitcode folgt derselben Richtung: Laden Sie die Konfiguration einmal an der CLI-, Gateway- oder Prozessgrenze und reichen Sie diesen Wert anschließend weiter. Erfolgreiche Mutationsschreibvorgänge aktualisieren den Prozess-Laufzeit-Snapshot und erhöhen dessen interne Revision; langlebige Caches sollten den von der Laufzeit verwalteten Cache-Schlüssel verwenden, anstatt die Konfiguration lokal zu serialisieren. Für langlebige Laufzeitmodule gibt es einen Scanner ohne Fehlertoleranz für kontextlose loadConfig()-Aufrufe; verwenden Sie ein übergebenes cfg, ein context.getRuntimeConfig() der Anfrage oder getRuntimeConfig() an einer ausdrücklichen Prozessgrenze.

Ausführungspfade von Providern und Kanälen müssen den aktiven Laufzeit-Konfigurations-Snapshot verwenden, nicht einen Datei-Snapshot, der zum Zurücklesen oder Bearbeiten der Konfiguration zurückgegeben wird. Datei-Snapshots bewahren Quellwerte wie SecretRef-Markierungen für die Benutzeroberfläche und Schreibvorgänge; Provider-Callbacks benötigen die aufgelöste Laufzeitansicht. Wenn eine Hilfsfunktion entweder mit dem aktiven Quell-Snapshot oder dem aktiven Laufzeit-Snapshot aufgerufen werden kann, führen Sie ihn vor dem Lesen von Zugangsdaten durch selectApplicableRuntimeConfig().

Wiederverwendbare Laufzeit-Hilfsfunktionen

Verwenden Sie eingehende botLoopProtection-Fakten für eingehende Nachrichten, die von Bots verfasst wurden. Core wendet die gemeinsame speicherinterne Schutzfunktion mit gleitendem Zeitfenster vor Sitzungsaufzeichnung und Weiterleitung an, ohne die Richtlinie an einen einzelnen Kanal zu binden. Die Schutzfunktion verfolgt Schlüssel aus (scopeId, conversationId, participant pair), zählt beide Richtungen eines Paares gemeinsam, wendet nach Überschreiten des Fensterbudgets eine Abklingzeit an und entfernt inaktive Einträge bei Gelegenheit.

Kanal-Plugins, die dieses Verhalten für Betreiber verfügbar machen, sollten für Basisbudgets die gemeinsame Struktur channels.defaults.botLoopProtection bevorzugen und anschließend kanal-/providerspezifische Überschreibungen darüberlegen. Die gemeinsame Konfiguration verwendet Sekunden, da sie benutzerseitig sichtbar ist:

typescript
type ChannelBotLoopProtectionConfig = {  enabled?: boolean;  maxEventsPerWindow?: number;  windowSeconds?: number;  cooldownSeconds?: number;};

Übergeben Sie normalisierte Bot-Paar-Fakten zusammen mit dem aufgelösten Turn. Core löst Standardwerte, Einheitenumrechnung und die Semantik von enabled auf:

typescript
return {  channel: "example",  routeSessionKey,  storePath,  ctxPayload,  recordInboundSession,  runDispatch,  botLoopProtection: {    scopeId: "account-1",    conversationId: "channel-1",    senderId: "bot-a",    receiverId: "bot-b",    config: channelConfig.botLoopProtection,    defaultsConfig: runtimeConfig.channels?.defaults?.botLoopProtection,    defaultEnabled: allowBotsMode !== "off",  },};

Verwenden Sie openclaw/plugin-sdk/pair-loop-guard-runtime nur für benutzerdefinierte Ereignisschleifen zwischen zwei Parteien, die nicht über den gemeinsamen Runner für eingehende Antworten laufen.

Laufzeit-Namespaces

api.runtime.agent

Agentenidentität, Verzeichnisse und Sitzungsverwaltung.

typescript
// Arbeitsverzeichnis des Agenten auflösen (agentId ist erforderlich)const agentDir = api.runtime.agent.resolveAgentDir(cfg, agentId); // Agenten-Workspace auflösenconst workspaceDir = api.runtime.agent.resolveAgentWorkspaceDir(cfg, agentId); // Agentenidentität abrufenconst identity = api.runtime.agent.resolveAgentIdentity(cfg); // Standard-Denkstufe abrufenconst thinking = api.runtime.agent.resolveThinkingDefault({  cfg,  provider,  model,}); // Eine vom Benutzer angegebene Denkstufe anhand des aktiven Provider-Profils validierenconst policy = api.runtime.agent.resolveThinkingPolicy({ provider, model });const level = api.runtime.agent.normalizeThinkingLevel("extra high");if (level && policy.levels.some((entry) => entry.id === level)) {  // Stufe an einen eingebetteten Lauf übergeben} // Agenten-Zeitlimit abrufenconst timeoutMs = api.runtime.agent.resolveAgentTimeoutMs(cfg); // Sicherstellen, dass der Workspace vorhanden istawait api.runtime.agent.ensureAgentWorkspace(cfg); // Einen eingebetteten Agenten-Turn ausführenconst result = await api.runtime.agent.runEmbeddedAgent({  sessionId: "my-plugin:task-1",  runId: crypto.randomUUID(),  workspaceDir: api.runtime.agent.resolveAgentWorkspaceDir(cfg, agentId),  prompt: "Neueste Änderungen zusammenfassen",  timeoutMs: api.runtime.agent.resolveAgentTimeoutMs(cfg),});

runEmbeddedAgent(...) ist die neutrale Hilfsfunktion zum Starten eines normalen OpenClaw-Agenten-Turns aus Plugin-Code. Sie verwendet dieselbe Provider-/Modellauflösung und Auswahl des Agenten-Harnesses wie durch Kanäle ausgelöste Antworten.

runEmbeddedPiAgent(...) bleibt als veralteter Kompatibilitätsalias für bestehende Plugins erhalten. Neuer Code sollte runEmbeddedAgent(...) verwenden.

resolveThinkingPolicy(...) gibt die vom Provider/Modell unterstützten Denkstufen und optional einen Standardwert zurück. Provider-Plugins verwalten das modellspezifische Profil über ihre Denk-Hooks. Tool-Plugins sollten daher diese Laufzeit-Hilfsfunktion aufrufen, anstatt Provider-Listen zu importieren oder zu duplizieren.

normalizeThinkingLevel(...) wandelt Benutzereingaben wie on, x-high oder extra high in die kanonisch gespeicherte Stufe um, bevor sie anhand der aufgelösten Richtlinie geprüft werden.

Hilfsfunktionen für den Sitzungsspeicher befinden sich unter api.runtime.agent.session:

typescript
const entry = api.runtime.agent.session.getSessionEntry({ agentId, sessionKey });for (const { sessionKey, entry } of api.runtime.agent.session.listSessionEntries({ agentId })) {  // Sitzungszeilen durchlaufen, ohne von der veralteten sessions.json-Struktur abhängig zu sein.}await api.runtime.agent.session.patchSessionEntry({  agentId,  sessionKey,  update: (entry) => ({ thinkingLevel: "high" }),}); const created = await api.runtime.agent.session.createSessionEntry({  cfg,  key: "agent:main:my-plugin:task-1",  initialEntry: {    agentHarnessId: "my-harness",    modelSelectionLocked: true,    pluginExtensions: { "my-plugin": { phase: "initializing" } },  },  afterCreate: async () => ({    pluginExtensions: { "my-plugin": { phase: "ready" } },  }),}); const storePath = api.runtime.agent.session.resolveStorePath(cfg.session?.store, { agentId });await api.runtime.agent.session.runWithWorkAdmission(  { storePath, sessionKey },  async (signal) => {    // Sitzung erstellen oder aktualisieren und anschließend signal an den zugelassenen Agentenlauf übergeben.  },);

Bevorzugen Sie getSessionEntry(...), listSessionEntries(...), patchSessionEntry(...) oder upsertSessionEntry(...) für Sitzungsabläufe. Diese Hilfsfunktionen adressieren Sitzungen anhand der Agenten-/Sitzungsidentität, sodass Plugins nicht von der veralteten Speicherstruktur sessions.json abhängen. Verwenden Sie preserveActivity: true für reine Metadaten-Patches, die die Sitzungsaktivität nicht aktualisieren sollen, und replaceEntry: true nur dann, wenn der Callback einen vollständigen Eintrag zurückgibt und gelöschte Felder gelöscht bleiben müssen. Doctor- und Migrationspfade können fallbackEntry, skipMaintenance und requireWriteSuccess für eine einzelne atomare Reparatur des kanonischen Speichers kombinieren.

createSessionEntry(...) erstellt eine neue kanonische Sitzungszeile und ein Transkript. Die vertrauenswürdige Oberfläche initialEntry ist absichtlich eng gefasst: eine nicht leere agentHarnessId, optional modelSelectionLocked: true und optional pluginExtensions. Die injizierte Laufzeit akzeptiert nur Harness-IDs, die dem aufrufenden Plugin über registerAgentHarness(...) gehören; dies ist eine Eigentumsinvariante und keine Sandbox zwischen prozessinternen Plugins. Eine bereits vorhandene Zeile wird abgelehnt; label und spawnedCwd sind separate Erstellungsfelder und keine vertrauenswürdigen Eintrags-Patches.

Während afterCreate hält der Erstellungsprozess die Mutationssperre für den Sitzungslebenszyklus. Dadurch wartet neue Arbeit, bis die Plugin-eigene Initialisierung abgeschlossen ist, während bereits zuvor zugelassene Arbeit die Erstellung fehlschlagen lässt. Der Callback erhält einen Klon des erstellten Zustands. Wenn er einen Patch zurückgibt, darf dieser Patch ausschließlich pluginExtensions enthalten, und dessen Wert ist das vollständige endgültige Feld pluginExtensions. Ein Fehler im Callback oder bei der abschließenden Speicherung setzt die unveränderte neue Zeile und das Transkript zurück; der abgesicherte Rollback bewahrt eine Zeile, die nebenläufig geändert oder beansprucht wurde. recoverMatchingInitialEntry: true ist ausschließlich für die Wiederholung einer unterbrochenen Initialisierung vorgesehen, wenn die gespeicherten vertrauenswürdigen Felder exakt übereinstimmen. Für die Wiederherstellung muss afterCreate einen abschließenden Patch zurückgeben.

Verwenden Sie runWithWorkAdmission(...), wenn ein Plugin Arbeit an einer persistenten Sitzung startet. Der Callback lehnt archivierte oder nebenläufig ersetzte Sitzungen ab, koordiniert Archivierungs-, Zurücksetzungs- und Löschmutationen bis zum Abschluss und erhält ein AbortSignal, das an den Agentenlauf weitergeleitet werden muss. Ein Harness kann über sein experimentelles Registrierungsfeld delegatedExecutionPluginIds ausdrücklich vertrauenswürdige Ausführungsdelegierte benennen. Delegierte können nur eine exakt vorhandene, modellgesperrte Sitzung zulassen und ausführen; sämtliche Sitzungsmutationen bleiben auf den Eigentümer des Harnesses beschränkt. Siehe Agenten-Harness-Plugins.

Wartungs- und Reparatur-Plugins können deleteSessionEntry(...) für einen einzelnen eingegrenzten Sitzungseintrag, cleanupSessionLifecycleArtifacts(...) für Lebenszyklus-eigene temporäre Sitzungen und resolveSessionStoreBackupPaths(...) vor der Änderung eines Speichers verwenden. Diese Hilfsfunktionen sind eng begrenzte Reparatur-/Lebenszyklus-Schnittstellen und keine allgemeine API zum Löschen von Speichern.

resolveStorePath(...) und updateSessionStoreEntry(...) vervollständigen die Sitzungshilfen: resolveStorePath ermittelt den Pfad des Sitzungsspeichers für einen bestimmten Geltungsbereich, und updateSessionStoreEntry({ storePath, sessionKey, update }) aktualisiert einen Eintrag direkt anhand des Speicherpfads, wenn der Aufrufer ihn bereits kennt.

loadTranscriptEventsSync(...) ist für synchrone Doctor- und Reparaturpfade verfügbar, die die asynchrone Transkript-Laufzeit nicht verwenden können. Die Funktion gibt unverarbeitete SessionStoreTranscriptEvent-Datensätze zurück. Normaler Plugin-Laufzeitcode sollte openclaw/plugin-sdk/session-transcript-runtime bevorzugen.

formatSqliteSessionFileMarker(...), parseSqliteSessionFileMarker(...) und sqliteSessionFileMarkerMatchesSession(...) sind Übergangshilfen für Code, der noch ein Legacy-Feld namens sessionFile erhält. Eine analysierte SQLite-Markierung identifiziert ein aktives SQLite-Transkriptziel; sie ist kein Dateisystempfad. Neue APIs sollten eine typisierte Sitzungsidentität anstelle von Markierungszeichenfolgen übertragen.

Importieren Sie für das Lesen und Schreiben von Transkripten openclaw/plugin-sdk/session-transcript-runtime und verwenden Sie resolveSessionTranscriptIdentity(...), resolveSessionTranscriptTarget(...), readSessionTranscriptEvents(...), readVisibleSessionTranscriptMessageEntries(...), appendSessionTranscriptMessageByIdentity(...), publishSessionTranscriptUpdateByIdentity(...) oder withSessionTranscriptWriteLock(...) mit { agentId, sessionKey, sessionId }. Mit diesen APIs können Plugins ein Transkript identifizieren, unverarbeitete Ereignisse oder sichtbare, verzweigungssichere Nachrichteneinträge lesen, Nachrichten anhängen, Aktualisierungen veröffentlichen und zusammengehörige Vorgänge unter derselben Transkript-Schreibsperre ausführen, ohne von aktiven Transkriptdateipfaden abhängig zu sein. readVisibleSessionTranscriptMessageEntries(...) gibt geordnete Lesemetadaten zurück; das Feld seq ist kein fortsetzbarer Cursor.

Die Legacy-Hilfen für den gesamten Speicher und aktive Transkriptdateien werden nicht mehr aus dem Plugin-SDK exportiert. Verwenden Sie die eingegrenzten Eintragshilfen für Sitzungsmetadaten und die Hilfen zur Transkriptidentität für Vorgänge am aktiven Transkript. Archivierungs-/Support-Workflows, die Dateiartefakte benötigen, sollten ihre dedizierten Archivschnittstellen anstelle der APIs der aktiven Sitzungslaufzeit verwenden.

api.runtime.agent.defaults

Standardkonstanten für Modell und Provider:

typescript
const model = api.runtime.agent.defaults.model; // z. B. "gpt-5.6-sol"const provider = api.runtime.agent.defaults.provider; // z. B. "openai"
api.runtime.llm

Führen Sie eine vom Host verwaltete Textvervollständigung aus, ohne interne Provider-Komponenten zu importieren oder die Modell-/Authentifizierungs-/Basis-URL-Vorbereitung von OpenClaw zu duplizieren.

typescript
const result = await api.runtime.llm.complete({  messages: [{ role: "user", content: "Fassen Sie dieses Transkript zusammen." }],  purpose: "my-plugin.summary",  maxTokens: 512,  temperature: 0.2,});

Die Provider-Orchestrierung kann außerdem den konfigurierten Lebenszyklus des lokalen Dienstes übernehmen, bevor eine HTTP-Anfrage gesendet wird:

typescript
const lease = await api.runtime.llm.acquireLocalService(  {    providerId,    baseUrl,    headers,  },  signal,);try {  // Senden Sie die Provider-Anfrage und verarbeiten Sie sie vollständig.} finally {  await lease?.release();}

acquireLocalService(...) ist ein stabiler, generischer SDK-Vertrag für Provider-Dienste. Der Host ermittelt die Prozesskonfiguration aus models.providers.<providerId>.localService; Aufrufer können weder einen Befehl noch Argumente, eine Umgebung oder eine Lebenszyklusrichtlinie angeben. Prozesserzeugung, Bereitschaft, Diagnose und Richtlinie zum Beenden bei Inaktivität bleiben intern im Host.

Übergeben Sie die exakte konfigurierte Provider-ID und die aufgelöste Basis-URL der Anfrage. Ersetzen Sie Aliasse nicht durch eine Adapter-ID: Verschiedene Aliasse können auf verschiedene lokale GPU-Hosts verweisen. Der Host lehnt Endpunkte ab, die nicht mit der konfigurierten Provider-Basis-URL übereinstimmen, abgesehen von der von Ollama- und LM-Studio-Adaptern verwendeten /v1-Normalisierung. Der Host verwaltet die Serialisierung des Starts, Bereitschaftsprüfungen, Anfrage-Leases, Abbruchbehandlung und das Herunterfahren bei Inaktivität.

Die Hilfsfunktion verwendet denselben Vorbereitungspfad für einfache Vervollständigungen wie die integrierte Laufzeit von OpenClaw sowie den vom Host verwalteten Snapshot der Laufzeitkonfiguration. Kontext-Engines erhalten eine sitzungsgebundene llm.complete-Fähigkeit, sodass Modellaufrufe den Agenten der aktiven Sitzung verwenden und nicht stillschweigend auf den Standardagenten zurückfallen. Das Ergebnis enthält die Zuordnung zu Provider, Modell und Agent sowie normalisierte Angaben zur Token-, Cache- und geschätzten Kostennutzung, sofern verfügbar.

api.runtime.gateway

Rufen Sie eine andere Gateway-Methode innerhalb des Prozesses auf und bewahren Sie dabei die vertrauenswürdige Laufzeitidentität des aktuellen Plugins. Dies ist für gebündelte oder vertrauenswürdige offizielle Plugins vorgesehen, die Plugin-eigene Gateway-Fähigkeiten kombinieren, ohne eine Loopback-WebSocket-Verbindung zu öffnen.

typescript
if (await api.runtime.gateway.isAvailable()) {  const result = await api.runtime.gateway.request<{ callId: string }>(    "voicecall.start",    { to: "+15550001234", mode: "conversation" },    { timeoutMs: 60_000 },  );}

Anfragen verwenden den Geltungsbereich operator.write und gewähren keinen Administrator-Geltungsbereich. Aufrufe von beliebigen externen Plugins werden abgelehnt. Fehlgeschlagene Methoden lösen einen GatewayClientRequestError aus, wobei strukturierte details, Metadaten zu Wiederholungsversuchen und der Gateway-Fehlercode für Wiederherstellungsabläufe erhalten bleiben. Verwenden Sie isAvailable(), bevor Sie diesen Pfad in Tools auswählen, die auch in eigenständigen Agentenprozessen ausgeführt werden können.

api.runtime.subagent

Starten und verwalten Sie Subagent-Läufe im Hintergrund.

typescript
// Einen Subagent-Lauf startenconst { runId } = await api.runtime.subagent.run({  sessionKey: "agent:main:subagent:search-helper",  message: "Erweitern Sie diese Abfrage zu gezielten weiterführenden Suchen.",  provider: "openai", // optionale Überschreibung  model: "gpt-5.6-sol", // optionale Überschreibung  deliver: false,}); // Auf den Abschluss wartenconst result = await api.runtime.subagent.waitForRun({ runId, timeoutMs: 30000 }); // Sitzungsnachrichten lesenconst { messages } = await api.runtime.subagent.getSessionMessages({  sessionKey: "agent:main:subagent:search-helper",  limit: 10,}); // Eine Sitzung löschenawait api.runtime.subagent.deleteSession({  sessionKey: "agent:main:subagent:search-helper",});

deleteSession(...) kann Sitzungen löschen, die vom selben Plugin über api.runtime.subagent.run(...) erstellt wurden. Das Löschen beliebiger Benutzer- oder Operatorsitzungen erfordert weiterhin eine Gateway-Anfrage mit Administrator-Geltungsbereich.

api.runtime.nodes

Listen Sie verbundene Nodes auf und rufen Sie einen Node-Host-Befehl aus vom Gateway geladenem Plugin-Code oder aus Plugin-CLI-Befehlen auf. Verwenden Sie dies, wenn ein Plugin lokale Arbeit auf einem gekoppelten Gerät verwaltet, beispielsweise eine Browser- oder Audio-Bridge auf einem anderen Mac.

typescript
const { nodes } = await api.runtime.nodes.list({ connected: true }); const result = await api.runtime.nodes.invoke({  nodeId: "mac-studio",  command: "my-plugin.command",  params: { action: "start" },  timeoutMs: 30000,});

nodes.list(...) enthält die von jedem verbundenen Node angekündigten nodePluginTools-Deskriptoren, wenn dieser Node dem Agenten Plugin- oder MCP-gestützte Tools bereitstellt. Diese Deskriptoren stellen den aktuellen Verbindungsstatus dar: Das Gateway verwirft sie, wenn der Node die Verbindung trennt, und ein Node kann sie nach Änderungen am lokalen Plugin-/MCP-Bestand mit node.pluginTools.update ersetzen.

Innerhalb des Gateways wird diese Laufzeit prozessintern ausgeführt. In Plugin-CLI-Befehlen ruft sie das konfigurierte Gateway über RPC auf, sodass Befehle wie openclaw googlemeet recover-tab gekoppelte Nodes vom Terminal aus prüfen können. Node-Befehle durchlaufen weiterhin die normale Gateway-Node-Kopplung, Befehlsfreigabelisten, Richtlinien für Plugin-Node-Aufrufe und die Node-lokale Befehlsverarbeitung.

Plugins, die auf Nodes gehostete Agenten-Tools bereitstellen, können agentTool.defaultPlatforms für ungefährliche Befehle festlegen, die standardmäßig in die Freigabeliste aufgenommen werden sollen. Lassen Sie das Feld weg, wenn Operatoren die Befehle ausdrücklich mit gateway.nodes.allowCommands zulassen müssen. Gefährliche Node-Host-Befehle sollten mit api.registerNodeInvokePolicy(...) eine Richtlinie für Node-Aufrufe registrieren; die Richtlinie wird im Gateway nach den Prüfungen der Befehlsfreigabeliste und vor der Weiterleitung des Befehls an den Node ausgeführt, sodass direkte node.invoke-Aufrufe, auf Nodes gehostete Plugin-Tools und übergeordnete Plugin-Tools denselben Durchsetzungspfad verwenden.

api.runtime.tasks

Binden Sie den Zustand von Task Flow und Task Run an einen vorhandenen OpenClaw-Sitzungsschlüssel oder einen vertrauenswürdigen Tool-Kontext.

  • api.runtime.tasks.managedFlows unterstützt Änderungen: Task Flows erstellen, fortsetzen und abbrechen.
  • api.runtime.tasks.flows und api.runtime.tasks.runs sind schreibgeschützte DTO-Ansichten für Auflistungen und Statusabfragen; beide stellen bindSession(...) / fromToolContext(...) sowie get, list, findLatest und resolve bereit.
  • api.runtime.tasks.flow ist ein veralteter Alias für managedFlows.

Task Flow verfolgt den dauerhaften Zustand mehrstufiger Workflows. Es ist kein Scheduler: Verwenden Sie Cron oder api.session.workflow.scheduleSessionTurn(...) für zukünftige Aktivierungen und anschließend managedFlows aus dem geplanten Turn, wenn diese Arbeit Flow-Zustand, untergeordnete Aufgaben, Wartezustände oder einen Abbruch benötigt.

typescript
const taskFlow = api.runtime.tasks.managedFlows.fromToolContext(ctx); const created = taskFlow.createManaged({  controllerId: "my-plugin/review-batch",  goal: "Neue Pull Requests prüfen",}); const child = taskFlow.runTask({  flowId: created.flowId,  runtime: "acp",  childSessionKey: "agent:main:subagent:reviewer",  task: "PR #123 prüfen",  status: "running",  startedAt: Date.now(),}); const waiting = taskFlow.setWaiting({  flowId: created.flowId,  expectedRevision: created.revision,  currentStep: "await-human-reply",  waitJson: { kind: "reply", channel: "telegram" },});

Verwenden Sie bindSession({ sessionKey, requesterOrigin }), wenn Sie bereits einen vertrauenswürdigen OpenClaw-Sitzungsschlüssel aus Ihrer eigenen Bindungsschicht besitzen. Binden Sie nicht anhand unverarbeiteter Benutzereingaben.

api.runtime.tts

Sprachsynthese.

typescript
// Standard-TTSconst clip = await api.runtime.tts.textToSpeech({  text: "Hallo von OpenClaw",  cfg: api.config,}); // Für Telefonie optimiertes TTSconst telephonyClip = await api.runtime.tts.textToSpeechTelephony({  text: "Hallo von OpenClaw",  cfg: api.config,}); // Verfügbare Stimmen auflistenconst voices = await api.runtime.tts.listVoices({  provider: "elevenlabs",  cfg: api.config,});

Verwendet die zentrale messages.tts-Konfiguration und Provider-Auswahl. Gibt einen PCM-Audiopuffer und die Abtastrate zurück. textToSpeechStream ist ebenfalls für die Streaming-Synthese verfügbar.

api.runtime.mediaUnderstanding

Bild-, Audio- und Videoanalyse.

typescript
// Ein Bild beschreibenconst image = await api.runtime.mediaUnderstanding.describeImageFile({  filePath: "/tmp/inbound-photo.jpg",  cfg: api.config,  agentDir: "/tmp/agent",}); // Audio transkribierenconst { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({  filePath: "/tmp/inbound-audio.ogg",  cfg: api.config,  mime: "audio/ogg", // optional, falls MIME nicht abgeleitet werden kann}); // Ein Video beschreibenconst video = await api.runtime.mediaUnderstanding.describeVideoFile({  filePath: "/tmp/inbound-video.mp4",  cfg: api.config,}); // Allgemeine Dateianalyseconst result = await api.runtime.mediaUnderstanding.runFile({  filePath: "/tmp/inbound-file.pdf",  cfg: api.config,}); // Strukturierte Bildextraktion über einen bestimmten Provider/ein bestimmtes Modell.// Mindestens ein Bild einschließen; Texteingaben dienen als ergänzender Kontext.const evidence = 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: "Bevorzuge die gedruckte Gesamtsumme gegenüber handschriftlichen Notizen." },  ],  instructions: "Anbieter, Gesamtsumme und durchsuchbare Tags extrahieren.",  schemaName: "receipt.evidence",  jsonSchema: {    type: "object",    properties: {      vendor: { type: "string" },      total: { type: "number" },      tags: { type: "array", items: { type: "string" } },    },    required: ["vendor", "total"],  },  cfg: api.config,});

Gibt { text: undefined } zurück, wenn keine Ausgabe erzeugt wird (z. B. bei einer übersprungenen Eingabe).

describeImageFileWithModel(...) beschreibt ein bereits bekanntes Bild über einen bestimmten Provider/ein bestimmtes Modell und umgeht dabei die standardmäßige Auflösung des aktiven Modells, die describeImageFile(...) verwendet.

api.runtime.imageGeneration

Bilderzeugung.

typescript
const result = await api.runtime.imageGeneration.generate({  prompt: "Ein Roboter malt einen Sonnenuntergang",  cfg: api.config,}); const providers = api.runtime.imageGeneration.listProviders({ cfg: api.config });
api.runtime.videoGeneration

Videoerzeugung mit derselben Struktur wie die Bilderzeugung.

typescript
const result = await api.runtime.videoGeneration.generate({  prompt: "Eine Drohnenaufnahme, die bei Sonnenaufgang über eine Küste fliegt",  cfg: api.config,}); const providers = api.runtime.videoGeneration.listProviders({ cfg: api.config });
api.runtime.musicGeneration

Musikerzeugung mit derselben Struktur wie die Bilderzeugung.

typescript
const result = await api.runtime.musicGeneration.generate({  prompt: "Ein beschwingter Lo-Fi-Track für eine Programmiersitzung",  cfg: api.config,}); const providers = api.runtime.musicGeneration.listProviders({ cfg: api.config });
api.runtime.webSearch

Websuche.

typescript
const providers = api.runtime.webSearch.listProviders({ config: api.config }); const result = await api.runtime.webSearch.search({  config: api.config,  args: { query: "OpenClaw Plugin-SDK", count: 5 },});
api.runtime.media

Medien-Dienstprogramme auf niedriger Ebene.

typescript
const webMedia = await api.runtime.media.loadWebMedia(url);const mime = await api.runtime.media.detectMime(buffer);const kind = api.runtime.media.mediaKindFromMime("image/jpeg"); // "image"const isVoice = api.runtime.media.isVoiceCompatibleAudio(filePath);const metadata = await api.runtime.media.getImageMetadata(filePath);const resized = await api.runtime.media.resizeToJpeg(buffer, { maxWidth: 800 });const terminalQr = await api.runtime.media.renderQrTerminal("https://openclaw.ai");const pngQr = await api.runtime.media.renderQrPngBase64("https://openclaw.ai", {  scale: 6, // 1-12  marginModules: 4, // 0-16});const pngQrDataUrl = await api.runtime.media.renderQrPngDataUrl("https://openclaw.ai");const tmpRoot = resolvePreferredOpenClawTmpDir();const pngQrFile = await api.runtime.media.writeQrPngTempFile("https://openclaw.ai", {  tmpRoot,  dirPrefix: "my-plugin-qr-",  fileName: "qr.png",});
api.runtime.config

Aktueller Snapshot der Laufzeitkonfiguration und transaktionale Konfigurationsschreibvorgänge. Bevorzugen Sie die Konfiguration, die bereits an den aktiven Aufrufpfad übergeben wurde; verwenden Sie current() nur, wenn der Handler den Prozess-Snapshot direkt benötigt.

typescript
const cfg = api.runtime.config.current();await api.runtime.config.mutateConfigFile({  afterWrite: { mode: "auto" },  mutate(draft) {    draft.plugins ??= {};  },});

mutateConfigFile(...) und replaceConfigFile(...) geben einen followUp-Wert zurück, beispielsweise { mode: "restart", requiresRestart: true, reason }, der die Absicht des Schreibers festhält, ohne dem Gateway die Kontrolle über den Neustart zu entziehen.

api.runtime.system

Dienstprogramme auf Systemebene.

typescript
await api.runtime.system.enqueueSystemEvent(event);api.runtime.system.requestHeartbeat({  source: "other",  intent: "event",  reason: "plugin-event",});api.runtime.system.requestHeartbeatNow({ reason: "plugin-event" }); // Veralteter Kompatibilitätsalias.const heartbeatResult = await api.runtime.system.runHeartbeatOnce({  reason: "plugin-triggered-check",});const output = await api.runtime.system.runCommandWithTimeout(cmd, args, opts);const hint = api.runtime.system.formatNativeDependencyHint(pkg);

runHeartbeatOnce(...) führt sofort einen einzelnen Heartbeat-Zyklus aus und umgeht dabei den normalen Zusammenführungstimer. Übergeben Sie { heartbeat: { target: "last" } }, um die Zustellung an den zuletzt aktiven Kanal zu erzwingen, anstatt die standardmäßige Unterdrückung mit target: "none" zu verwenden.

runCommandWithTimeout(...) gibt erfasste Werte für stdout und stderr, optionale Kürzungszähler, code, signal, killed, termination und noOutputTimedOut zurück. Ergebnisse bei Zeitüberschreitung und bei Zeitüberschreitung ohne Ausgabe melden code: 124, wenn der Kindprozess keinen von null verschiedenen Exit-Code bereitstellt. Signalbedingte Beendigungen ohne Zeitüberschreitung können weiterhin code: null zurückgeben. Verwenden Sie daher termination und noOutputTimedOut, um die Gründe für die Zeitüberschreitung zu unterscheiden.

api.runtime.events

Ereignisabonnements.

typescript
api.runtime.events.onAgentEvent((event) => {  /* ... */});api.runtime.events.onSessionTranscriptUpdate((update) => {  /* ... */});
api.runtime.logging

Protokollierung.

typescript
const verbose = api.runtime.logging.shouldLogVerbose();const childLogger = api.runtime.logging.getChildLogger({ plugin: "my-plugin" }, { level: "debug" });
api.runtime.modelAuth

Auflösung der Modell- und Provider-Authentifizierung.

typescript
const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg }); // Für Anfragen einsatzbereite Authentifizierung, einschließlich Laufzeitaustausch mit Providern (z. B. OAuth-Aktualisierung)const runtimeAuth = await api.runtime.modelAuth.getRuntimeAuthForModel({ model, cfg }); const providerAuth = await api.runtime.modelAuth.resolveApiKeyForProvider({  provider: "openai",  cfg,});
api.runtime.state

Auflösung des Zustandsverzeichnisses und SQLite-gestützter schlüsselbasierter Speicher.

typescript
const stateDir = api.runtime.state.resolveStateDir(process.env);const store = api.runtime.state.openKeyedStore&lt;MyRecord&gt;({  namespace: "my-feature",  maxEntries: 200,  defaultTtlMs: 15 * 60_000,}); await store.register("key-1", { value: "hello" });const claimed = await store.registerIfAbsent("dedupe-key", { value: "first" });const value = await store.lookup("key-1");await store.consume("key-1");await store.clear();

Schlüsselbasierte Speicher überstehen Neustarts und werden anhand der an die Laufzeit gebundenen Plugin-ID isoliert. Verwenden Sie registerIfAbsent(...) für atomare Deduplizierungsansprüche: Die Methode gibt true zurück, wenn der Schlüssel fehlte oder abgelaufen war und registriert wurde, oder false, wenn bereits ein aktiver Wert vorhanden ist, ohne dessen Wert, Erstellungszeit oder TTL zu überschreiben. Grenzwerte: maxEntries pro Namensraum, 50,000 aktive Zeilen pro Plugin, JSON-Werte unter 64KB und optionaler TTL-Ablauf. Standardmäßig entfernt ein Schreibvorgang bei Erreichen eines der Zeilenlimits die ältesten aktiven Zeilen aus dem Namensraum, in den geschrieben wird; benachbarte Namensräume werden für diesen Schreibvorgang nicht bereinigt, und der Schreibvorgang schlägt weiterhin fehl, wenn der Namensraum nicht genügend Zeilen freigeben kann. Legen Sie overflowPolicy: "reject-new" für dauerhafte Eigentumsdatensätze fest, die niemals entfernt werden dürfen: Neue Schlüssel schlagen bei Erreichen eines der Limits fehl, während vorhandene Schlüssel weiterhin aktualisiert werden können.

openSyncKeyedStore&lt;T&gt;(...) gibt dieselbe Speicherstruktur mit synchronen Methoden zurück (register, registerIfAbsent, lookup, consume, clear geben alle Werte direkt statt Promises zurück), für Aufrufer, die nicht warten können.

openChannelIngressQueue&lt;TPayload&gt;(...) öffnet eine persistierte Eingangswarteschlange, deren Gültigkeitsbereich auf das aufrufende Plugin beschränkt ist, um eingehende Ereignisse zu puffern, die über Neustarts hinweg mindestens einmal verarbeitet werden müssen. Wenn die Wiederherstellung veralteter Ansprüche shouldRecover verwendet, geben Sie zusätzlich shouldRecoverCorrupt an, falls beschädigte beanspruchte Nutzdaten unter Quarantäne gestellt werden sollen: Die von den Nutzdaten unabhängige Anspruchsidentität ermöglicht dem Plugin, die Richtlinie für aktive Eigentümer und Verarbeitungsspuren beizubehalten, bevor die Warteschlange die Zeile mit einem Löschmarker versieht.

api.runtime.channel

Kanalspezifische Laufzeit-Hilfsfunktionen (verfügbar, wenn ein Kanal-Plugin geladen ist). Nach Aufgabenbereich gruppiert:

Gruppe Zweck
text Aufteilung (chunkText, chunkMarkdownText, resolveChunkMode), Erkennung von Steuerbefehlen, Konvertierung von Markdown-Tabellen.
reply Versand gepufferter Blockantworten, Umschlagformatierung, Auflösung der effektiven Konfiguration für Nachrichten/menschliche Verzögerung.
routing buildAgentSessionKey, resolveAgentRoute.
pairing buildPairingReply, Lesen der Zulassungsliste, Upserts von Kopplungsanfragen.
media Herunterladen/Speichern entfernter Medien (siehe unten).
activity Letzte Kanalaktivität aufzeichnen/lesen.
session Sitzungsmetadaten aus eingehenden Ereignissen, Aktualisierungen der letzten Route.
mentions Hilfsfunktionen für Erwähnungsrichtlinien (siehe unten).
reactions Handles für Bestätigungsreaktionen als Verarbeitungsindikatoren für laufende Vorgänge.
groups Gruppenrichtlinie und Auflösung der Erwähnungspflicht.
debounce Entprellung eingehender Nachrichten.
commands Befehlsautorisierung und Zugriffssteuerung für Textbefehle.
outbound Ausgehenden Adapter eines Kanals laden.
inbound Kontext für eingehende Ereignisse erstellen und den gemeinsamen Kernel für eingehende Ereignisse/Antworten ausführen.
threadBindings Leerlaufzeitlimit/maximales Alter für gebundene Sitzungsthreads anpassen.
runtimeContexts Prozesslokalen Kontext pro Kanal/Konto/Fähigkeit registrieren, lesen und überwachen.

api.runtime.channel.media ist die bevorzugte Oberfläche zum Herunterladen und Speichern von Kanalmedien:

typescript
const saved = await api.runtime.channel.media.saveRemoteMedia({  url,  subdir: "inbound",  maxBytes,  filePathHint: fileName,});

Verwenden Sie saveRemoteMedia(...), wenn eine entfernte URL zu einem OpenClaw-Medium werden soll. Verwenden Sie saveResponseMedia(...), wenn das Plugin bereits eine Response mit Plugin-eigener Authentifizierung, Weiterleitungs- oder Zulassungslistenbehandlung abgerufen hat. Verwenden Sie readRemoteMediaBuffer(...) nur, wenn das Plugin Rohbytes zur Prüfung, Transformation, Entschlüsselung oder zum erneuten Hochladen benötigt. fetchRemoteMedia(...) bleibt ein veralteter Kompatibilitätsalias für readRemoteMediaBuffer(...).

api.runtime.channel.mentions ist die gemeinsame Oberfläche für Richtlinien zu eingehenden Erwähnungen für gebündelte Kanal-Plugins, die Laufzeitinjektion verwenden:

typescript
const mentionMatch = api.runtime.channel.mentions.matchesMentionWithExplicit(text, {  mentionRegexes,  mentionPatterns,}); const decision = api.runtime.channel.mentions.resolveInboundMentionDecision({  facts: {    canDetectMention: true,    wasMentioned: mentionMatch.matched,    implicitMentionKinds: api.runtime.channel.mentions.implicitMentionKindWhen(      "reply_to_bot",      isReplyToBot,    ),  },  policy: {    isGroup,    requireMention,    allowTextCommands,    hasControlCommand,    commandAuthorized,  },});

Verfügbare Hilfsfunktionen für Erwähnungen:

  • buildMentionRegexes
  • matchesMentionPatterns
  • matchesMentionWithExplicit
  • implicitMentionKindWhen
  • resolveInboundMentionDecision

api.runtime.channel.mentions stellt die älteren Kompatibilitätshilfen resolveMentionGating* absichtlich nicht bereit. Bevorzugen Sie den normalisierten Pfad { facts, policy }.

Mehrere Felder unter reply, session und inbound enthalten feldspezifische @deprecated-Hinweise, die auf den aktuellen Kernel für Kanaldurchläufe oder die Adapter für ausgehende Kanalnachrichten verweisen; prüfen Sie das Inline-JSDoc der jeweiligen Hilfsfunktion, bevor Sie neuen Code darauf aufbauen.

Laufzeitreferenzen speichern

Verwenden Sie createPluginRuntimeStore, um die Laufzeitreferenz für die Verwendung außerhalb des register-Callbacks zu speichern:

  • Speicher erstellen

    typescript
    import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store"; const store = createPluginRuntimeStore&lt;PluginRuntime&gt;({  pluginId: "my-plugin",  errorMessage: "my-plugin runtime not initialized",});
  • Mit dem Einstiegspunkt verbinden

    typescript
    export default defineChannelPluginEntry({  id: "my-plugin",  name: "My Plugin",  description: "Example",  plugin: myPlugin,  setRuntime: store.setRuntime,});
  • Aus anderen Dateien darauf zugreifen

    typescript
    export function getRuntime() {  return store.getRuntime(); // löst einen Fehler aus, wenn nicht initialisiert} export function tryGetRuntime() {  return store.tryGetRuntime(); // gibt null zurück, wenn nicht initialisiert}
  • Weitere Felder der obersten Ebene von api

    Zusätzlich zu api.runtime stellt das API-Objekt Folgendes bereit:

    api.idstring

    Plugin-ID.

    api.namestring

    Anzeigename des Plugins.

    api.configOpenClawConfig

    Aktueller Konfigurations-Snapshot (sofern verfügbar, der aktive speicherinterne Laufzeit-Snapshot).

    OPENCLAW_DOCS_MARKER:paramOpen:IHBhdGg9ImFwaS5wbHVnaW5Db25maWciIHR5cGU9IlJlY29yZDxzdHJpbmcsIHVua25vd24 "> Plugin-spezifische Konfiguration aus plugins.entries.<id>.config.

    api.loggerPluginLogger

    Bereichsgebundener Logger (debug, info, warn, error).

    api.registrationModePluginRegistrationMode

    Aktueller Lademodus: "full" (Live-Aktivierung), "discovery" / "tool-discovery" (schreibgeschützte Fähigkeitsermittlung), "setup-only" (leichtgewichtiger Einrichtungseinstieg), "setup-runtime" (Einrichtungsablauf, der auch den Laufzeiteinstieg des Kanals benötigt) oder "cli-metadata" (Erfassung von CLI-Befehlsmetadaten).

    api.resolvePath(input)"(string)

    Verwandte Themen

    Was this useful?
    On this page

    On this page