Plugins

Funkcje pomocnicze środowiska wykonawczego Plugin

Dokumentacja referencyjna obiektu api.runtime wstrzykiwanego do każdego Plugin podczas rejestracji. Używaj tych pomocników zamiast bezpośrednio importować wewnętrzne elementy hosta.

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

Wczytywanie i zapisywanie konfiguracji

Preferuj konfigurację, która została już przekazana do aktywnej ścieżki wywołania, na przykład api.config podczas rejestracji albo argument cfg w wywołaniach zwrotnych kanału/dostawcy. Dzięki temu jedna migawka procesu przepływa przez pracę zamiast ponownego parsowania konfiguracji na gorących ścieżkach.

Używaj api.runtime.config.current() tylko wtedy, gdy długotrwały handler potrzebuje bieżącej migawki procesu, a do tej funkcji nie przekazano żadnej konfiguracji. Zwracana wartość jest tylko do odczytu; przed edycją sklonuj ją albo użyj pomocnika mutacji.

Fabryki narzędzi otrzymują ctx.runtimeConfig oraz ctx.getRuntimeConfig(). Używaj gettera wewnątrz wywołania zwrotnego execute długotrwałego narzędzia, gdy konfiguracja może się zmienić po utworzeniu definicji narzędzia.

Utrwalaj zmiany za pomocą api.runtime.config.mutateConfigFile(...) albo api.runtime.config.replaceConfigFile(...). Każdy zapis musi wybrać jawną politykę afterWrite:

  • afterWrite: { mode: "auto" } pozwala mechanizmowi przeładowania Gateway podjąć decyzję.
  • afterWrite: { mode: "restart", reason: "..." } wymusza czysty restart, gdy zapisujący wie, że przeładowanie na gorąco jest niebezpieczne.
  • afterWrite: { mode: "none", reason: "..." } blokuje automatyczne przeładowanie/restart tylko wtedy, gdy wywołujący odpowiada za dalsze działania.

Pomocniki mutacji zwracają afterWrite oraz typowane podsumowanie followUp, aby wywołujący mogli logować albo testować, czy zażądali restartu. Gateway nadal odpowiada za to, kiedy ten restart faktycznie nastąpi.

api.runtime.config.loadConfig() oraz api.runtime.config.writeConfigFile(...) są przestarzałymi pomocnikami zgodności pod runtime-config-load-write. Ostrzegają raz w czasie działania i pozostają dostępne dla starych zewnętrznych Plugin w oknie migracji. Dołączone Plugin nie mogą ich używać; strażnicy granicy konfiguracji zawodzą, jeśli kod Plugin je wywoła albo zaimportuje tych pomocników ze ścieżek podrzędnych SDK Plugin.

W przypadku bezpośrednich importów SDK używaj wyspecjalizowanych ścieżek podrzędnych konfiguracji zamiast szerokiego beczkowego modułu zgodności openclaw/plugin-sdk/config-runtime: config-types dla typów, plugin-config-runtime dla asercji już wczytanej konfiguracji i wyszukiwania wpisu Plugin, runtime-config-snapshot dla bieżących migawek procesu oraz config-mutation dla zapisów. Testy dołączonych Plugin powinny mockować te wyspecjalizowane ścieżki podrzędne bezpośrednio zamiast mockować szeroki beczkowy moduł zgodności.

Wewnętrzny kod runtime OpenClaw podąża w tym samym kierunku: wczytaj konfigurację raz na granicy CLI, Gateway albo procesu, a następnie przekazuj tę wartość dalej. Udane zapisy mutacji odświeżają migawkę runtime procesu i zwiększają jej wewnętrzną rewizję; długotrwałe cache powinny opierać klucze na kluczu cache należącym do runtime zamiast lokalnie serializować konfigurację. Długotrwałe moduły runtime mają skaner o zerowej tolerancji dla otaczających wywołań loadConfig(); użyj przekazanego cfg, żądania context.getRuntimeConfig() albo getRuntimeConfig() na jawnej granicy procesu.

Ścieżki wykonywania dostawców i kanałów muszą używać aktywnej migawki konfiguracji runtime, a nie migawki pliku zwróconej do odczytu zwrotnego lub edycji konfiguracji. Migawki plików zachowują wartości źródłowe, takie jak znaczniki SecretRef, dla UI i zapisów; wywołania zwrotne dostawców potrzebują rozwiązanego widoku runtime. Gdy pomocnik może zostać wywołany zarówno z aktywną migawką źródłową, jak i aktywną migawką runtime, przed odczytem poświadczeń przeprowadź przepływ przez selectApplicableRuntimeConfig().

Przestrzenie nazw runtime

api.runtime.agent

Tożsamość agenta, katalogi i zarządzanie sesjami.

// 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(...) to neutralny pomocnik do uruchamiania normalnej tury agenta OpenClaw z kodu Plugin. Używa tego samego rozwiązywania dostawcy/modelu i wyboru uprzęży agenta co odpowiedzi wyzwalane przez kanał.

runEmbeddedPiAgent(...) pozostaje aliasem zgodności.

resolveThinkingPolicy(...) zwraca obsługiwane poziomy myślenia dostawcy/modelu oraz opcjonalną wartość domyślną. Plugin dostawców odpowiadają za profil specyficzny dla modelu przez swoje hooki myślenia, więc Plugin narzędziowe powinny wywoływać tego pomocnika runtime zamiast importować albo duplikować listy dostawców.

normalizeThinkingLevel(...) konwertuje tekst użytkownika, taki jak on, x-high albo extra high, na kanoniczny przechowywany poziom przed sprawdzeniem go względem rozwiązanej polityki.

Pomocniki magazynu sesji znajdują się pod 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);

Preferuj updateSessionStore(...) albo updateSessionStoreEntry(...) dla zapisów runtime. Przechodzą one przez należący do Gateway mechanizm zapisu magazynu sesji, zachowują współbieżne aktualizacje i ponownie wykorzystują gorący cache. saveSessionStore(...) pozostaje dostępne dla zgodności i przepisań w stylu konserwacji offline.

api.runtime.agent.defaults

Domyślne stałe modelu i dostawcy:

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

Uruchamianie i zarządzanie działaniami subagentów w tle.

// 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(...) może usuwać sesje utworzone przez ten sam Plugin za pomocą api.runtime.subagent.run(...). Usuwanie dowolnych sesji użytkownika lub operatora nadal wymaga żądania Gateway o zakresie administracyjnym.

api.runtime.nodes

Wyświetlanie połączonych węzłów i wywoływanie polecenia hostowanego przez węzeł z kodu Plugin wczytanego przez Gateway albo z poleceń CLI Plugin. Użyj tego, gdy Plugin odpowiada za pracę lokalną na sparowanym urządzeniu, na przykład most przeglądarki albo audio na innym Macu.

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,
});

Wewnątrz Gateway ten runtime działa w procesie. W poleceniach CLI Plugin wywołuje skonfigurowany Gateway przez RPC, więc polecenia takie jak openclaw googlemeet recover-tab mogą sprawdzać sparowane węzły z terminala. Polecenia węzłów nadal przechodzą przez zwykłe parowanie węzłów Gateway, listy dozwolonych poleceń, polityki wywołań węzłów Plugin oraz lokalną obsługę poleceń węzła.

Plugin, które ujawniają niebezpieczne polecenia hostowane przez węzeł, powinny zarejestrować politykę wywołań węzła za pomocą api.registerNodeInvokePolicy(...). Polityka działa w Gateway po sprawdzeniach listy dozwolonych poleceń i przed przekazaniem polecenia do węzła, więc bezpośrednie wywołania node.invoke i narzędzia Plugin wyższego poziomu współdzielą tę samą ścieżkę egzekwowania.

api.runtime.tasks.managedFlows

Powiąż runtime Task Flow z istniejącym kluczem sesji OpenClaw albo zaufanym kontekstem narzędzia, a następnie twórz i zarządzaj Task Flows bez przekazywania właściciela przy każdym wywołaniu.

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" },
});

Użyj bindSession({ sessionKey, requesterOrigin }), gdy masz już zaufany klucz sesji OpenClaw z własnej warstwy wiązania. Nie wiąż z surowego wejścia użytkownika.

api.runtime.tts

Synteza tekstu na mowę.

// 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,
});

Używa podstawowej konfiguracji messages.tts i wyboru dostawcy. Zwraca bufor audio PCM + częstotliwość próbkowania.

api.runtime.mediaUnderstanding

Analiza obrazów, audio i wideo.

// 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,
});

Zwraca { text: undefined }, gdy nie zostanie wygenerowane żadne wyjście (np. pominięte dane wejściowe).

api.runtime.imageGeneration

Generowanie obrazów.

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

Wyszukiwanie w sieci.

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

Niskopoziomowe narzędzia multimedialne.

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

Bieżąca migawka konfiguracji środowiska runtime i transakcyjne zapisy konfiguracji. Preferuj konfigurację, która została już przekazana do aktywnej ścieżki wywołania; używaj current() tylko wtedy, gdy handler potrzebuje bezpośrednio migawki procesu.

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

mutateConfigFile(...) i replaceConfigFile(...) zwracają wartość followUp, na przykład { mode: "restart", requiresRestart: true, reason }, która rejestruje intencję zapisującego bez odbierania kontroli nad ponownym uruchomieniem Gateway.

api.runtime.system

Narzędzia na poziomie systemu.

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

Subskrypcje zdarzeń.

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

Logowanie.

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

Rozwiązywanie uwierzytelniania modeli i dostawców.

const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg });
const providerAuth = await api.runtime.modelAuth.resolveApiKeyForProvider({
  provider: "openai",
  cfg,
});
api.runtime.state

Rozwiązywanie katalogu stanu i magazyn kluczowany oparty na 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();

Magazyny kluczowane przetrwają ponowne uruchomienia i są izolowane przez identyfikator pluginu powiązany ze środowiskiem runtime. Użyj registerIfAbsent(...) do atomowych roszczeń deduplikacyjnych: zwraca true, gdy klucza brakowało albo wygasł i został zarejestrowany, albo false, gdy aktywna wartość już istnieje bez nadpisywania jej wartości, czasu utworzenia ani TTL. Limity: maxEntries na przestrzeń nazw, 1000 aktywnych wierszy na plugin, wartości JSON poniżej 64 KB oraz opcjonalne wygasanie TTL.

api.runtime.tools

Fabryki narzędzi pamięci i CLI.

const getTool = api.runtime.tools.createMemoryGetTool(/* ... */);
const searchTool = api.runtime.tools.createMemorySearchTool(/* ... */);
api.runtime.tools.registerMemoryCli(/* ... */);
api.runtime.channel

Pomocnicze funkcje runtime specyficzne dla kanału (dostępne, gdy załadowany jest plugin kanału).

api.runtime.channel.mentions to współdzielona powierzchnia zasad wzmianek przychodzących dla wbudowanych pluginów kanałów używających wstrzykiwania 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,
  },
});

Dostępne funkcje pomocnicze wzmianek:

  • buildMentionRegexes
  • matchesMentionPatterns
  • matchesMentionWithExplicit
  • implicitMentionKindWhen
  • resolveInboundMentionDecision

api.runtime.channel.mentions celowo nie udostępnia starszych funkcji pomocniczych zgodności resolveMentionGating*. Preferuj znormalizowaną ścieżkę { facts, policy }.

Przechowywanie referencji runtime

Użyj createPluginRuntimeStore, aby przechować referencję runtime do użycia poza callbackiem register:

  • Create the 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",
    });
    
  • Wire into the entry point

    export default defineChannelPluginEntry({
      id: "my-plugin",
      name: "My Plugin",
      description: "Example",
      plugin: myPlugin,
      setRuntime: store.setRuntime,
    });
    
  • Access from other files

    export function getRuntime() {
      return store.getRuntime(); // throws if not initialized
    }
    
    export function tryGetRuntime() {
      return store.tryGetRuntime(); // returns null if not initialized
    }
    
  • Inne pola najwyższego poziomu api

    Poza api.runtime obiekt API udostępnia także:

    api.idstring

    Identyfikator pluginu.

    api.namestring

    Nazwa wyświetlana pluginu.

    api.configOpenClawConfig

    Bieżąca migawka konfiguracji (aktywna migawka runtime w pamięci, gdy jest dostępna).

    OPENCLAW_DOCS_MARKER:paramOpen:IHBhdGg9ImFwaS5wbHVnaW5Db25maWciIHR5cGU9IlJlY29yZDxzdHJpbmcsIHVua25vd24 "> Konfiguracja specyficzna dla pluginu z plugins.entries.<id>.config.

    api.loggerPluginLogger

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

    api.registrationModePluginRegistrationMode

    Bieżący tryb ładowania; "setup-runtime" to lekki okres uruchamiania/konfiguracji przed pełnym punktem wejścia.

    api.resolvePath(input)(string) =,������� Q�<

    Powiązane