Plugins
Helper di esecuzione dei Plugin
Riferimento per l'oggetto api.runtime iniettato in ogni plugin durante la registrazione. Usa questi helper invece di importare direttamente gli elementi interni dell'host.
Guida passo passo che usa questi helper nel contesto dei channel plugin.
Guida passo passo che usa questi helper nel contesto dei provider plugin.
register(api) {
const runtime = api.runtime;
}
Caricamento e scritture della configurazione
Preferisci la configurazione che è già stata passata nel percorso di chiamata attivo, per esempio api.config durante la registrazione o un argomento cfg nei callback di canale/provider. Questo mantiene uno snapshot di processo che fluisce attraverso il lavoro invece di rianalizzare la configurazione nei percorsi caldi.
Usa api.runtime.config.current() solo quando un handler a lunga durata ha bisogno dello snapshot di processo corrente e a quella funzione non è stata passata alcuna configurazione. Il valore restituito è di sola lettura; clonalo o usa un helper di mutazione prima di modificarlo.
Le factory degli strumenti ricevono ctx.runtimeConfig più ctx.getRuntimeConfig(). Usa il getter dentro il callback execute di uno strumento a lunga durata quando la configurazione può cambiare dopo la creazione della definizione dello strumento.
Persisti le modifiche con api.runtime.config.mutateConfigFile(...) o api.runtime.config.replaceConfigFile(...). Ogni scrittura deve scegliere una policy afterWrite esplicita:
afterWrite: { mode: "auto" }lascia decidere al reload planner del Gateway.afterWrite: { mode: "restart", reason: "..." }forza un riavvio pulito quando chi scrive sa che l'hot reload non è sicuro.afterWrite: { mode: "none", reason: "..." }sopprime il reload/riavvio automatico solo quando il chiamante possiede il follow-up.
Gli helper di mutazione restituiscono afterWrite più un riepilogo followUp tipizzato, così i chiamanti possono registrare nei log o testare se hanno richiesto un riavvio. Il Gateway resta comunque responsabile di quando quel riavvio avviene effettivamente.
api.runtime.config.loadConfig() e api.runtime.config.writeConfigFile(...) sono helper di compatibilità deprecati sotto runtime-config-load-write. Emettono un avviso una volta a runtime e restano disponibili per i vecchi plugin esterni durante la finestra di migrazione. I plugin inclusi non devono usarli; le guardie del confine di configurazione falliscono se il codice del plugin li chiama o importa quegli helper dai sottopercorsi dell'SDK dei plugin.
Per le importazioni dirette dell'SDK, usa i sottopercorsi di configurazione mirati invece del barrel di compatibilità ampio
openclaw/plugin-sdk/config-runtime: config-types per i
tipi, plugin-config-runtime per le asserzioni sulla configurazione già caricata e la ricerca delle entry dei plugin, runtime-config-snapshot per gli snapshot di processo correnti, e
config-mutation per le scritture. I test dei plugin inclusi dovrebbero mockare direttamente questi
sottopercorsi mirati invece di mockare il barrel di compatibilità ampio.
Il codice runtime interno di OpenClaw segue la stessa direzione: caricare la configurazione una volta al confine della CLI, del Gateway o del processo, poi passare quel valore. Le scritture di mutazione riuscite aggiornano lo snapshot runtime del processo e avanzano la sua revisione interna; le cache a lunga durata dovrebbero basarsi sulla chiave cache posseduta dal runtime invece di serializzare localmente la configurazione. I moduli runtime a lunga durata hanno uno scanner a tolleranza zero per chiamate ambientali a loadConfig(); usa un cfg passato, un context.getRuntimeConfig() della richiesta o getRuntimeConfig() a un confine di processo esplicito.
I percorsi di esecuzione di provider e canali devono usare lo snapshot della configurazione runtime attiva, non uno snapshot di file restituito per la rilettura o la modifica della configurazione. Gli snapshot di file preservano valori sorgente come i marker SecretRef per UI e scritture; i callback dei provider hanno bisogno della vista runtime risolta. Quando un helper può essere chiamato con lo snapshot sorgente attivo o con lo snapshot runtime attivo, passa attraverso selectApplicableRuntimeConfig() prima di leggere le credenziali.
Namespace runtime
api.runtime.agent
Identità dell'agente, directory e gestione delle sessioni.
// Resolve the agent's working directory
const agentDir = api.runtime.agent.resolveAgentDir(cfg);
// Resolve agent workspace
const workspaceDir = api.runtime.agent.resolveAgentWorkspaceDir(cfg);
// Get agent identity
const identity = api.runtime.agent.resolveAgentIdentity(cfg);
// Get default thinking level
const thinking = api.runtime.agent.resolveThinkingDefault({
cfg,
provider,
model,
});
// Validate a user-provided thinking level against the active provider profile
const policy = api.runtime.agent.resolveThinkingPolicy({ provider, model });
const level = api.runtime.agent.normalizeThinkingLevel("extra high");
if (level && policy.levels.some((entry) => entry.id === level)) {
// pass level to an embedded run
}
// Get agent timeout
const timeoutMs = api.runtime.agent.resolveAgentTimeoutMs(cfg);
// Ensure workspace exists
await api.runtime.agent.ensureAgentWorkspace(cfg);
// Run an embedded agent turn
const agentDir = api.runtime.agent.resolveAgentDir(cfg);
const result = await api.runtime.agent.runEmbeddedAgent({
sessionId: "my-plugin:task-1",
runId: crypto.randomUUID(),
sessionFile: path.join(agentDir, "sessions", "my-plugin-task-1.jsonl"),
workspaceDir: api.runtime.agent.resolveAgentWorkspaceDir(cfg),
prompt: "Summarize the latest changes",
timeoutMs: api.runtime.agent.resolveAgentTimeoutMs(cfg),
});
runEmbeddedAgent(...) è l'helper neutro per avviare un normale turno di agente OpenClaw dal codice del plugin. Usa la stessa risoluzione provider/modello e la stessa selezione dell'harness agente delle risposte attivate dai canali.
runEmbeddedPiAgent(...) resta come alias di compatibilità.
resolveThinkingPolicy(...) restituisce i livelli di ragionamento supportati dal provider/modello e il default opzionale. I provider plugin possiedono il profilo specifico del modello tramite i loro hook di ragionamento, quindi i plugin di strumenti dovrebbero chiamare questo helper runtime invece di importare o duplicare elenchi di provider.
normalizeThinkingLevel(...) converte testo dell'utente come on, x-high o extra high nel livello memorizzato canonico prima di controllarlo rispetto alla policy risolta.
Gli helper dello store delle sessioni sono sotto api.runtime.agent.session:
const storePath = api.runtime.agent.session.resolveStorePath(cfg);
const store = api.runtime.agent.session.loadSessionStore(storePath);
await api.runtime.agent.session.updateSessionStore(storePath, (nextStore) => {
// Patch one entry without replacing the whole file from stale state.
nextStore[sessionKey] = { ...nextStore[sessionKey], thinkingLevel: "high" };
});
const filePath = api.runtime.agent.session.resolveSessionFilePath(cfg, sessionId);
Preferisci updateSessionStore(...) o updateSessionStoreEntry(...) per le scritture runtime. Passano attraverso lo writer dello store delle sessioni posseduto dal Gateway, preservano gli aggiornamenti concorrenti e riutilizzano la cache calda. saveSessionStore(...) resta disponibile per compatibilità e riscritture in stile manutenzione offline.
api.runtime.agent.defaults
Modello e costanti provider predefiniti:
const model = api.runtime.agent.defaults.model; // e.g. "anthropic/claude-sonnet-4-6"
const provider = api.runtime.agent.defaults.provider; // e.g. "anthropic"
api.runtime.subagent
Avvia e gestisci esecuzioni di subagent in background.
// Start a subagent run
const { runId } = await api.runtime.subagent.run({
sessionKey: "agent:main:subagent:search-helper",
message: "Expand this query into focused follow-up searches.",
provider: "openai", // optional override
model: "gpt-4.1-mini", // optional override
deliver: false,
});
// Wait for completion
const result = await api.runtime.subagent.waitForRun({ runId, timeoutMs: 30000 });
// Read session messages
const { messages } = await api.runtime.subagent.getSessionMessages({
sessionKey: "agent:main:subagent:search-helper",
limit: 10,
});
// Delete a session
await api.runtime.subagent.deleteSession({
sessionKey: "agent:main:subagent:search-helper",
});
deleteSession(...) può eliminare sessioni create dallo stesso plugin tramite api.runtime.subagent.run(...). L'eliminazione di sessioni arbitrarie dell'utente o dell'operatore richiede comunque una richiesta Gateway con ambito admin.
api.runtime.nodes
Elenca i nodi connessi e invoca un comando ospitato su nodo dal codice del plugin caricato dal Gateway o dai comandi CLI del plugin. Usalo quando un plugin possiede lavoro locale su un dispositivo abbinato, per esempio un bridge browser o audio su un altro Mac.
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,
});
Dentro il Gateway questo runtime è in-process. Nei comandi CLI del plugin chiama il Gateway configurato tramite RPC, quindi comandi come openclaw googlemeet recover-tab possono ispezionare i nodi abbinati dal terminale. I comandi Node passano comunque attraverso il normale abbinamento dei nodi del Gateway, le allowlist dei comandi, le policy node-invoke dei plugin e la gestione dei comandi locale al nodo.
I plugin che espongono comandi per host nodo pericolosi dovrebbero registrare una policy node-invoke con api.registerNodeInvokePolicy(...). La policy viene eseguita nel Gateway dopo i controlli della allowlist dei comandi e prima che il comando venga inoltrato al nodo, quindi le chiamate dirette node.invoke e gli strumenti plugin di livello superiore condividono lo stesso percorso di enforcement.
api.runtime.tasks.managedFlows
Associa un runtime Task Flow a una chiave di sessione OpenClaw esistente o a un contesto strumento attendibile, poi crea e gestisci Task Flows senza passare un owner a ogni chiamata.
const taskFlow = api.runtime.tasks.managedFlows.fromToolContext(ctx);
const created = taskFlow.createManaged({
controllerId: "my-plugin/review-batch",
goal: "Review new pull requests",
});
const child = taskFlow.runTask({
flowId: created.flowId,
runtime: "acp",
childSessionKey: "agent:main:subagent:reviewer",
task: "Review PR #123",
status: "running",
startedAt: Date.now(),
});
const waiting = taskFlow.setWaiting({
flowId: created.flowId,
expectedRevision: created.revision,
currentStep: "await-human-reply",
waitJson: { kind: "reply", channel: "telegram" },
});
Usa bindSession({ sessionKey, requesterOrigin }) quando hai già una chiave di sessione OpenClaw attendibile dal tuo livello di binding. Non eseguire il binding da input utente grezzo.
api.runtime.tts
Sintesi text-to-speech.
// Standard TTS
const clip = await api.runtime.tts.textToSpeech({
text: "Hello from OpenClaw",
cfg: api.config,
});
// Telephony-optimized TTS
const telephonyClip = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
// List available voices
const voices = await api.runtime.tts.listVoices({
provider: "elevenlabs",
cfg: api.config,
});
Usa la configurazione core messages.tts e la selezione del provider. Restituisce buffer audio PCM + frequenza di campionamento.
api.runtime.mediaUnderstanding
Analisi di immagini, audio e video.
// Describe an image
const image = await api.runtime.mediaUnderstanding.describeImageFile({
filePath: "/tmp/inbound-photo.jpg",
cfg: api.config,
agentDir: "/tmp/agent",
});
// Transcribe audio
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
mime: "audio/ogg", // optional, for when MIME cannot be inferred
});
// Describe a video
const video = await api.runtime.mediaUnderstanding.describeVideoFile({
filePath: "/tmp/inbound-video.mp4",
cfg: api.config,
});
// Generic file analysis
const result = await api.runtime.mediaUnderstanding.runFile({
filePath: "/tmp/inbound-file.pdf",
cfg: api.config,
});
Restituisce { text: undefined } quando non viene prodotto alcun output (ad es. input ignorato).
api.runtime.imageGeneration
Generazione di immagini.
const result = await api.runtime.imageGeneration.generate({
prompt: "A robot painting a sunset",
cfg: api.config,
});
const providers = api.runtime.imageGeneration.listProviders({ cfg: api.config });
api.runtime.webSearch
Ricerca web.
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
Utilità multimediali di basso livello.
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
Snapshot della configurazione runtime corrente e scritture transazionali della configurazione. Preferisci
la configurazione già passata nel percorso di chiamata attivo; usa
current() solo quando il gestore deve accedere direttamente allo snapshot del processo.
const cfg = api.runtime.config.current();
await api.runtime.config.mutateConfigFile({
afterWrite: { mode: "auto" },
mutate(draft) {
draft.plugins ??= {};
},
});
mutateConfigFile(...) e replaceConfigFile(...) restituiscono un valore followUp,
per esempio { mode: "restart", requiresRestart: true, reason },
che registra l'intento dello scrittore senza togliere al
gateway il controllo del riavvio.
api.runtime.system
Utilità a livello di sistema.
await api.runtime.system.enqueueSystemEvent(event);
api.runtime.system.requestHeartbeat({
source: "other",
intent: "event",
reason: "plugin-event",
});
api.runtime.system.requestHeartbeatNow({ reason: "plugin-event" }); // Deprecated compatibility alias.
const output = await api.runtime.system.runCommandWithTimeout(cmd, args, opts);
const hint = api.runtime.system.formatNativeDependencyHint(pkg);
api.runtime.events
Sottoscrizioni agli eventi.
api.runtime.events.onAgentEvent((event) => {
/* ... */
});
api.runtime.events.onSessionTranscriptUpdate((update) => {
/* ... */
});
api.runtime.logging
Logging.
const verbose = api.runtime.logging.shouldLogVerbose();
const childLogger = api.runtime.logging.getChildLogger({ plugin: "my-plugin" }, { level: "debug" });
api.runtime.modelAuth
Risoluzione dell'autenticazione per modelli e provider.
const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg });
const providerAuth = await api.runtime.modelAuth.resolveApiKeyForProvider({
provider: "openai",
cfg,
});
api.runtime.state
Risoluzione della directory di stato e archiviazione con chiavi basata su SQLite.
const stateDir = api.runtime.state.resolveStateDir(process.env);
const store = api.runtime.state.openKeyedStore<MyRecord>({
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();
Gli store con chiavi sopravvivono ai riavvii e sono isolati dall'id del Plugin vincolato al runtime. Usa registerIfAbsent(...) per rivendicazioni atomiche di deduplicazione: restituisce true quando la chiave era assente o scaduta ed è stata registrata, oppure false quando esiste già un valore valido senza sovrascriverne valore, ora di creazione o TTL. Limiti: maxEntries per namespace, 1.000 righe attive per Plugin, valori JSON sotto 64 KB e scadenza TTL opzionale.
api.runtime.tools
Factory degli strumenti di memoria e CLI.
const getTool = api.runtime.tools.createMemoryGetTool(/* ... */);
const searchTool = api.runtime.tools.createMemorySearchTool(/* ... */);
api.runtime.tools.registerMemoryCli(/* ... */);
api.runtime.channel
Helper runtime specifici del canale (disponibili quando viene caricato un Plugin di canale).
api.runtime.channel.mentions è la superficie condivisa per la policy delle menzioni in ingresso per i Plugin di canale inclusi che usano l'iniezione runtime:
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,
},
});
Helper per le menzioni disponibili:
buildMentionRegexesmatchesMentionPatternsmatchesMentionWithExplicitimplicitMentionKindWhenresolveInboundMentionDecision
api.runtime.channel.mentions intenzionalmente non espone i vecchi helper di compatibilità resolveMentionGating*. Preferisci il percorso normalizzato { facts, policy }.
Archiviazione dei riferimenti runtime
Usa createPluginRuntimeStore per archiviare il riferimento runtime da usare al di fuori del callback register:
Crea lo store
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
const store = createPluginRuntimeStore<PluginRuntime>({
pluginId: "my-plugin",
errorMessage: "my-plugin runtime not initialized",
});
Collega al punto di ingresso
export default defineChannelPluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Example",
plugin: myPlugin,
setRuntime: store.setRuntime,
});
Accedi da altri file
export function getRuntime() {
return store.getRuntime(); // throws if not initialized
}
export function tryGetRuntime() {
return store.tryGetRuntime(); // returns null if not initialized
}
Altri campi api di primo livello
Oltre a api.runtime, l'oggetto API fornisce anche:
api.idstringId del Plugin.
api.namestringNome visualizzato del Plugin.
api.configOpenClawConfigSnapshot della configurazione corrente (snapshot runtime attivo in memoria, quando disponibile).
OPENCLAW_DOCS_MARKER:paramOpen:IHBhdGg9ImFwaS5wbHVnaW5Db25maWciIHR5cGU9IlJlY29yZDxzdHJpbmcsIHVua25vd24
">
Configurazione specifica del Plugin da plugins.entries.<id>.config.
api.loggerPluginLoggerLogger con ambito (debug, info, warn, error).
api.registrationModePluginRegistrationModeModalità di caricamento corrente; "setup-runtime" è la finestra leggera di avvio/configurazione prima della voce completa.
api.resolvePath(input)"(string)Correlati
- Interni dei Plugin — modello delle capability e registro
- Punti di ingresso SDK — opzioni di
definePluginEntry - Panoramica SDK — riferimento dei subpath