31 KiB
| read_when | sidebarTitle | summary | title | x-i18n | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Runtime helpers | api.runtime -- впроваджені допоміжні засоби середовища виконання, доступні для plugins | Допоміжні засоби середовища виконання Plugin |
|
Довідник для об’єкта api.runtime, який впроваджується в кожен 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:
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 — модель можливостей і реєстр
- Точки входу SDK — параметри
definePluginEntry - Огляд SDK — довідник підшляхів