Plugins

Допоміжні засоби середовища виконання Plugin

Довідник для об’єкта api.runtime, який впроваджується в кожен плагін під час реєстрації. Використовуйте ці допоміжні функції замість прямого імпорту внутрішніх компонентів хоста.

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

Завантаження та запис конфігурації

Надавайте перевагу конфігурації, яку вже передано в активний шлях виклику, наприклад api.config під час реєстрації або аргумент cfg у зворотних викликах каналів чи провайдерів. Це дає змогу передавати один знімок процесу через роботу замість повторного розбору конфігурації на гарячих шляхах.

Використовуйте api.runtime.config.current() лише тоді, коли довготривалому обробнику потрібен поточний знімок процесу, а конфігурацію не було передано в цю функцію. Повернене значення доступне лише для читання; перед редагуванням клонуйте його або використайте допоміжну функцію мутації.

Фабрики інструментів отримують ctx.runtimeConfig разом із ctx.getRuntimeConfig(). Використовуйте геттер усередині зворотного виклику execute довготривалого інструмента, коли конфігурація може змінитися після створення визначення інструмента.

Зберігайте зміни за допомогою api.runtime.config.mutateConfigFile(...) або api.runtime.config.replaceConfigFile(...). Кожен запис має вибрати явну політику afterWrite:

  • afterWrite: { mode: "auto" } дозволяє планувальнику перезавантаження Gateway ухвалити рішення.
  • afterWrite: { mode: "restart", reason: "..." } примусово виконує чистий перезапуск, коли автор запису знає, що гаряче перезавантаження небезпечне.
  • afterWrite: { mode: "none", reason: "..." } пригнічує автоматичне перезавантаження чи перезапуск лише тоді, коли викликач володіє подальшою дією.

Допоміжні функції мутації повертають afterWrite разом із типізованим підсумком followUp, щоб викликачі могли журналювати або тестувати, чи запросили вони перезапуск. Gateway і надалі визначає, коли цей перезапуск фактично відбудеться.

api.runtime.config.loadConfig() і api.runtime.config.writeConfigFile(...) є застарілими допоміжними функціями сумісності в межах runtime-config-load-write. Вони попереджають один раз під час виконання й залишаються доступними для старих зовнішніх плагінів протягом міграційного вікна. Вбудовані плагіни не повинні їх використовувати; захисні перевірки межі конфігурації завершуються помилкою, якщо код плагіна викликає їх або імпортує ці допоміжні функції з підшляхів SDK плагінів.

Для прямих імпортів SDK використовуйте цільові підшляхи конфігурації замість широкого сумісного бареля openclaw/plugin-sdk/config-runtime: config-types для типів, plugin-config-runtime для перевірок уже завантаженої конфігурації та пошуку точки входу плагіна, runtime-config-snapshot для поточних знімків процесу, а config-mutation для записів. Тести вбудованих плагінів мають напряму мокати ці цільові підшляхи замість мокання широкого сумісного бареля.

Внутрішній код середовища виконання OpenClaw має той самий напрям: завантажити конфігурацію один раз на межі CLI, Gateway або процесу, а потім передавати це значення далі. Успішні записи мутацій оновлюють знімок середовища виконання процесу та збільшують його внутрішню ревізію; довготривалі кеші мають використовувати ключ кешу, яким володіє середовище виконання, замість локальної серіалізації конфігурації. Довготривалі модулі середовища виконання мають сканер із нульовою толерантністю до неявних викликів loadConfig(); використовуйте переданий cfg, запит context.getRuntimeConfig() або getRuntimeConfig() на явній межі процесу.

Шляхи виконання провайдерів і каналів мають використовувати активний знімок конфігурації середовища виконання, а не файловий знімок, повернений для зворотного читання чи редагування конфігурації. Файлові знімки зберігають вихідні значення, як-от маркери SecretRef, для UI та записів; зворотним викликам провайдера потрібне розв’язане подання середовища виконання. Коли допоміжну функцію можна викликати або з активним вихідним знімком, або з активним знімком середовища виконання, перед читанням облікових даних маршрутизуйте через selectApplicableRuntimeConfig().

Простори імен середовища виконання

api.runtime.agent

Ідентичність агента, каталоги та керування сеансами.

// 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(...) — нейтральна допоміжна функція для запуску звичайного ходу агента OpenClaw з коду плагіна. Вона використовує те саме розв’язання провайдера/моделі та вибір агентного каркаса, що й відповіді, ініційовані каналом.

runEmbeddedPiAgent(...) залишається псевдонімом для сумісності.

resolveThinkingPolicy(...) повертає підтримувані рівні мислення провайдера/моделі та необов’язкове значення за замовчуванням. Плагіни провайдерів володіють профілем, специфічним для моделі, через свої хуки мислення, тому плагіни інструментів мають викликати цю допоміжну функцію середовища виконання замість імпорту або дублювання списків провайдерів.

normalizeThinkingLevel(...) перетворює текст користувача, як-от on, x-high або extra high, на канонічний збережений рівень перед перевіркою його відносно розв’язаної політики.

Допоміжні функції сховища сеансів розташовані в 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);

Надавайте перевагу updateSessionStore(...) або updateSessionStoreEntry(...) для записів під час виконання. Вони маршрутизуються через автор сховища сеансів, яким володіє Gateway, зберігають паралельні оновлення та повторно використовують гарячий кеш. saveSessionStore(...) залишається доступним для сумісності й офлайн-перезаписів у стилі обслуговування.

api.runtime.agent.defaults

Константи моделі та провайдера за замовчуванням:

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

Запуск і керування фоновими виконаннями субагентів.

// 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(...) може видаляти сеанси, створені тим самим плагіном через api.runtime.subagent.run(...). Видалення довільних сеансів користувача або оператора все ще потребує запиту Gateway з адміністративною областю дії.

api.runtime.nodes

Перелічує підключені вузли та викликає команду, розміщену на вузлі, з коду плагіна, завантаженого Gateway, або з CLI-команд плагіна. Використовуйте це, коли плагін володіє локальною роботою на спареному пристрої, наприклад мостом браузера чи аудіо на іншому 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,
});

Усередині Gateway це середовище виконання працює в процесі. У CLI-командах плагіна воно викликає налаштований Gateway через RPC, тому команди на кшталт openclaw googlemeet recover-tab можуть переглядати спарені вузли з термінала. Команди вузлів усе ще проходять через звичайне спарення вузлів Gateway, списки дозволених команд, політики виклику вузлів плагіна та локальну обробку команд вузла.

Плагіни, які надають небезпечні команди хоста вузла, мають зареєструвати політику виклику вузла за допомогою api.registerNodeInvokePolicy(...). Політика виконується в Gateway після перевірок списку дозволених команд і перед пересиланням команди на вузол, тому прямі виклики node.invoke і високорівневі інструменти плагіна мають спільний шлях застосування правил.

api.runtime.tasks.managedFlows

Прив’язує середовище виконання Task Flow до наявного ключа сеансу OpenClaw або надійного контексту інструмента, а потім створює й керує Task Flows без передавання власника в кожному виклику.

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

Використовуйте bindSession({ sessionKey, requesterOrigin }), коли вже маєте надійний ключ сеансу OpenClaw з вашого власного шару прив’язки. Не прив’язуйтеся з сирого введення користувача.

api.runtime.tts

Синтез мовлення з тексту.

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

Використовує основну конфігурацію messages.tts і вибір провайдера. Повертає PCM-аудіобуфер + частоту дискретизації.

api.runtime.mediaUnderstanding

Аналіз зображень, аудіо та відео.

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

Повертає { text: undefined }, коли вихідні дані не створено (наприклад, пропущене введення).

api.runtime.imageGeneration

Генерація зображень.

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

Вебпошук.

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

Низькорівневі утиліти для медіа.

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

Поточний знімок runtime-конфігурації та транзакційні записи конфігурації. Надавайте перевагу конфігурації, яку вже було передано в активний шлях виклику; використовуйте current() лише тоді, коли обробнику потрібен безпосередньо знімок процесу.

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

mutateConfigFile(...) і replaceConfigFile(...) повертають значення followUp, наприклад { mode: "restart", requiresRestart: true, reason }, яке фіксує намір записувача, не забираючи керування перезапуском у gateway.

api.runtime.system

Утиліти системного рівня.

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

Підписки на події.

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

Журналювання.

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

Розв’язання автентифікації моделі та провайдера.

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

Визначення каталогу стану та сховище ключів на основі 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();

Сховища ключів переживають перезапуски та ізольовані за прив’язаним до runtime ідентифікатором Plugin. Використовуйте registerIfAbsent(...) для атомарних заявок дедуплікації: він повертає true, коли ключ був відсутній або прострочений і зареєстрований, або false, коли активне значення вже існує без перезапису його значення, часу створення чи TTL. Обмеження: maxEntries на простір імен, 1 000 активних рядків на Plugin, JSON-значення до 64 КБ та необов’язкове завершення терміну дії TTL.

api.runtime.tools

Фабрики інструментів пам’яті та CLI.

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

Допоміжні runtime-засоби, специфічні для каналу (доступні, коли завантажено channel plugin).

api.runtime.channel.mentions — це спільна поверхня політики вхідних згадок для вбудованих channel plugins, які використовують 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,
  },
});

Доступні допоміжні засоби для згадок:

  • buildMentionRegexes
  • matchesMentionPatterns
  • matchesMentionWithExplicit
  • implicitMentionKindWhen
  • resolveInboundMentionDecision

api.runtime.channel.mentions навмисно не надає старіші допоміжні засоби сумісності resolveMentionGating*. Надавайте перевагу нормалізованому шляху { facts, policy }.

Зберігання runtime-посилань

Використовуйте createPluginRuntimeStore, щоб зберегти runtime-посилання для використання поза callback register:

  • Створіть сховище

    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",
    });
    
  • Під’єднайте до точки входу

    export default defineChannelPluginEntry({
      id: "my-plugin",
      name: "My Plugin",
      description: "Example",
      plugin: myPlugin,
      setRuntime: store.setRuntime,
    });
    
  • Отримуйте доступ з інших файлів

    export function getRuntime() {
      return store.getRuntime(); // throws if not initialized
    }
    
    export function tryGetRuntime() {
      return store.tryGetRuntime(); // returns null if not initialized
    }
    
  • Інші поля api верхнього рівня

    Окрім api.runtime, об’єкт API також надає:

    api.idstring

    Ідентифікатор Plugin.

    api.namestring

    Відображуване ім’я Plugin.

    api.configOpenClawConfig

    Поточний знімок конфігурації (активний runtime-знімок у пам’яті, коли доступний).

    OPENCLAW_DOCS_MARKER:paramOpen:IHBhdGg9ImFwaS5wbHVnaW5Db25maWciIHR5cGU9IlJlY29yZDxzdHJpbmcsIHVua25vd24 "> Конфігурація, специфічна для Plugin, з plugins.entries.<id>.config.

    api.loggerPluginLogger

    Обмежений за областю логер (debug, info, warn, error).

    api.registrationModePluginRegistrationMode

    Поточний режим завантаження; "setup-runtime" — це легковагове вікно запуску/налаштування перед повним входом.

    api.resolvePath(input)"(string)

    Пов’язане