docs/docs/uk/plugins/sdk-runtime.md
2026-05-04 08:54:05 +00:00

31 KiB
Raw Blame History

read_when sidebarTitle summary title x-i18n
Потрібно викликати допоміжні функції ядра з Plugin (TTS, STT, генерація зображень, вебпошук, субагент, вузли)
Ви хочете зрозуміти, що надає api.runtime
Ви звертаєтеся до допоміжних функцій конфігурації, агента або медіа з коду Plugin
Runtime helpers api.runtime -- впроваджені допоміжні засоби середовища виконання, доступні для plugins Допоміжні засоби середовища виконання Plugin
generated_at model provider source_hash source_path workflow
2026-05-04T08:52:43Z gpt-5.5 openai c968f30052ecba4359bdaa9b1c640c1220268933ce01ccef06bcade225b50b7d plugins/sdk-runtime.md 16

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

Покроковий посібник, який показує використання цих допоміжних засобів у контексті plugin каналів. Покроковий посібник, який показує використання цих допоміжних засобів у контексті plugin провайдерів.
register(api) {
  const runtime = api.runtime;
}

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

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

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

Фабрики інструментів отримують ctx.runtimeConfig і ctx.getRuntimeConfig(). Використовуйте getter усередині зворотного виклику 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. Вони один раз попереджають під час виконання й залишаються доступними для старих зовнішніх plugin протягом вікна міграції. Вбудовані plugin не мають їх використовувати; захисні перевірки межі конфігурації завершуються помилкою, якщо код plugin викликає їх або імпортує ці допоміжні засоби з підшляхів SDK plugin.

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

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

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

Простори імен runtime

Ідентичність агента, каталоги та керування сеансами.
```typescript
// 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 з коду plugin. Він використовує те саме розв’язання провайдера/моделі та вибір agent-harness, що й відповіді, ініційовані каналом.

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

`resolveThinkingPolicy(...)` повертає підтримувані рівні мислення провайдера/моделі та необов’язкове значення за замовчуванням. Plugin провайдерів володіють специфічним для моделі профілем через свої hooks мислення, тому plugin інструментів мають викликати цей runtime-допоміжний засіб замість імпортування або дублювання списків провайдерів.

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

**Допоміжні засоби сховища сеансів** розміщені в `api.runtime.agent.session`:

```typescript
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);
```

Для runtime-записів надавайте перевагу `updateSessionStore(...)` або `updateSessionStoreEntry(...)`. Вони проходять через writer сховища сеансів, яким володіє Gateway, зберігають паралельні оновлення та повторно використовують гарячий кеш. `saveSessionStore(...)` залишається доступним для сумісності та автономних переписувань у стилі обслуговування.
Константи моделі та провайдера за замовчуванням:
```typescript
const model = api.runtime.agent.defaults.model; // e.g. "anthropic/claude-sonnet-4-6"
const provider = api.runtime.agent.defaults.provider; // e.g. "anthropic"
```
Запуск і керування фоновими виконаннями субагентів.
```typescript
// 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",
});
```

<Warning>
Перевизначення моделі (`provider`/`model`) потребують явної згоди оператора через `plugins.entries.<id>.subagent.allowModelOverride: true` у конфігурації. Недовірені plugin все ще можуть запускати субагентів, але запити перевизначення відхиляються.
</Warning>

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

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

Plugin, які відкривають небезпечні команди хоста вузла, мають зареєструвати політику node-invoke через `api.registerNodeInvokePolicy(...)`. Політика виконується в Gateway після перевірок allowlist команд і до пересилання команди на вузол, тому прямі виклики `node.invoke` і високорівневі інструменти plugin використовують той самий шлях примусового застосування.
Прив’язує runtime Task Flow до наявного ключа сеансу OpenClaw або довіреного контексту інструмента, а потім створює й керує Task Flows без передавання власника під час кожного виклику.
```typescript
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 зі свого власного шару прив’язки. Не виконуйте прив’язку з необробленого користувацького введення.
Синтез мовлення з тексту.
```typescript
// 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 + частоту дискретизації.
Аналіз зображень, аудіо та відео.
```typescript
// 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 }`, коли вихідні дані не створено (наприклад, вхід пропущено).

<Info>
`api.runtime.stt.transcribeAudioFile(...)` залишається сумісним псевдонімом для `api.runtime.mediaUnderstanding.transcribeAudioFile(...)`.
</Info>
Генерація зображень.
```typescript
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 });
```
Вебпошук.
```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 },
});
```
Низькорівневі медіаутиліти.
```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",
});
```
Поточний знімок конфігурації середовища виконання та транзакційні записи конфігурації. Надавайте перевагу конфігурації, яку вже було передано в активний шлях виклику; використовуйте `current()` лише тоді, коли обробнику потрібен безпосередньо знімок процесу.
```typescript
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.
Утиліти системного рівня.
```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" }); // Deprecated compatibility alias.
const output = await api.runtime.system.runCommandWithTimeout(cmd, args, opts);
const hint = api.runtime.system.formatNativeDependencyHint(pkg);
```
Підписки на події.
```typescript
api.runtime.events.onAgentEvent((event) => {
  /* ... */
});
api.runtime.events.onSessionTranscriptUpdate((update) => {
  /* ... */
});
```
Журналювання.
```typescript
const verbose = api.runtime.logging.shouldLogVerbose();
const childLogger = api.runtime.logging.getChildLogger({ plugin: "my-plugin" }, { level: "debug" });
```
Розв’язання автентифікації моделей і провайдерів.
```typescript
const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg });
const providerAuth = await api.runtime.modelAuth.resolveApiKeyForProvider({
  provider: "openai",
  cfg,
});
```
Розв’язання каталогу стану та сховище ключів на базі SQLite.
```typescript
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();
```

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

<Warning>
У цьому релізі лише вбудовані плагіни.
</Warning>
Фабрики інструментів пам’яті та CLI.
```typescript
const getTool = api.runtime.tools.createMemoryGetTool(/* ... */);
const searchTool = api.runtime.tools.createMemorySearchTool(/* ... */);
api.runtime.tools.registerMemoryCli(/* ... */);
```
Допоміжні засоби середовища виконання, специфічні для каналів (доступні, коли завантажено плагін каналу).
`api.runtime.channel.mentions` — це спільна поверхня політики вхідних згадок для вбудованих плагінів каналів, які використовують ін’єкцію середовища виконання:

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

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

- `buildMentionRegexes`
- `matchesMentionPatterns`
- `matchesMentionWithExplicit`
- `implicitMentionKindWhen`
- `resolveInboundMentionDecision`

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

Зберігання посилань на середовище виконання

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

```typescript 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",
});
```
```typescript export default defineChannelPluginEntry({ id: "my-plugin", name: "My Plugin", description: "Example", plugin: myPlugin, setRuntime: store.setRuntime, }); ``` ```typescript export function getRuntime() { return store.getRuntime(); // throws if not initialized }
export function tryGetRuntime() {
  return store.tryGetRuntime(); // returns null if not initialized
}
```
Надавайте перевагу `pluginId` для ідентичності runtime-store. Нижчорівнева форма `key` призначена для нечастих випадків, коли одному Plugin навмисно потрібно більше ніж один слот середовища виконання.

Інші поля api верхнього рівня

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

Ідентифікатор Plugin. Відображувана назва Plugin. Поточний знімок конфігурації (активний знімок середовища виконання в пам’яті, коли доступний). Конфігурація, специфічна для Plugin, з `plugins.entries..config`. Журналювач з обмеженою областю (`debug`, `info`, `warn`, `error`). Поточний режим завантаження; `"setup-runtime"` — це легке вікно запуску/налаштування перед повним входом. Розв’язати шлях відносно кореня Plugin.

Пов’язане