Plugins
Fungsi bantu waktu proses Plugin
Referensi untuk objek api.runtime yang disuntikkan ke setiap plugin selama registrasi. Gunakan helper ini alih-alih mengimpor internal host secara langsung.
Panduan langkah demi langkah yang menggunakan helper ini dalam konteks untuk plugin saluran.
Panduan langkah demi langkah yang menggunakan helper ini dalam konteks untuk plugin penyedia.
register(api) {
const runtime = api.runtime;
}
Pemuatan dan penulisan config
Utamakan config yang sudah diteruskan ke jalur panggilan aktif, misalnya api.config selama registrasi atau argumen cfg pada callback saluran/penyedia. Ini menjaga satu snapshot proses mengalir melalui pekerjaan, alih-alih mem-parse ulang config pada hot path.
Gunakan api.runtime.config.current() hanya ketika handler berumur panjang membutuhkan snapshot proses saat ini dan tidak ada config yang diteruskan ke fungsi tersebut. Nilai yang dikembalikan bersifat readonly; klon atau gunakan helper mutasi sebelum mengedit.
Factory tool menerima ctx.runtimeConfig serta ctx.getRuntimeConfig(). Gunakan getter di dalam callback execute milik tool berumur panjang ketika config dapat berubah setelah definisi tool dibuat.
Persist perubahan dengan api.runtime.config.mutateConfigFile(...) atau api.runtime.config.replaceConfigFile(...). Setiap penulisan harus memilih kebijakan afterWrite yang eksplisit:
afterWrite: { mode: "auto" }membiarkan Gateway memutuskan pemuatan ulang planner.afterWrite: { mode: "restart", reason: "..." }memaksa restart bersih ketika penulis mengetahui hot reload tidak aman.afterWrite: { mode: "none", reason: "..." }menekan reload/restart otomatis hanya ketika pemanggil memiliki tindak lanjutnya.
Helper mutasi mengembalikan afterWrite plus ringkasan followUp bertipe sehingga pemanggil dapat mencatat log atau menguji apakah mereka meminta restart. Gateway tetap memiliki kendali kapan restart tersebut benar-benar terjadi.
api.runtime.config.loadConfig() dan api.runtime.config.writeConfigFile(...) adalah helper kompatibilitas yang sudah deprecated di bawah runtime-config-load-write. Keduanya memperingatkan sekali saat runtime, dan tetap tersedia untuk plugin eksternal lama selama jendela migrasi. Plugin bawaan tidak boleh menggunakannya; guard batas config akan gagal jika kode plugin memanggilnya atau mengimpor helper tersebut dari subpath SDK plugin.
Untuk impor SDK langsung, gunakan subpath config yang terfokus alih-alih barrel kompatibilitas luas
openclaw/plugin-sdk/config-runtime: config-types untuk
tipe, plugin-config-runtime untuk assertion config yang sudah dimuat dan lookup entry plugin,
runtime-config-snapshot untuk snapshot proses saat ini, dan
config-mutation untuk penulisan. Test plugin bawaan harus me-mock subpath terfokus ini secara langsung, bukan me-mock barrel kompatibilitas luas.
Kode runtime internal OpenClaw memiliki arah yang sama: muat config sekali di batas CLI, Gateway, atau proses, lalu teruskan nilai itu. Penulisan mutasi yang berhasil menyegarkan snapshot runtime proses dan memajukan revisi internalnya; cache berumur panjang harus memakai cache key milik runtime, alih-alih menserialisasi config secara lokal. Modul runtime berumur panjang memiliki scanner tanpa toleransi untuk panggilan loadConfig() ambient; gunakan cfg yang diteruskan, context.getRuntimeConfig() dari request, atau getRuntimeConfig() pada batas proses yang eksplisit.
Jalur eksekusi penyedia dan saluran harus menggunakan snapshot config runtime aktif, bukan snapshot file yang dikembalikan untuk readback atau pengeditan config. Snapshot file mempertahankan nilai sumber seperti marker SecretRef untuk UI dan penulisan; callback penyedia membutuhkan tampilan runtime yang sudah di-resolve. Ketika helper dapat dipanggil dengan snapshot sumber aktif atau snapshot runtime aktif, route melalui selectApplicableRuntimeConfig() sebelum membaca kredensial.
Namespace runtime
api.runtime.agent
Identitas agen, direktori, dan manajemen sesi.
// 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(...) adalah helper netral untuk memulai turn agen OpenClaw normal dari kode plugin. Helper ini menggunakan resolusi penyedia/model dan pemilihan agent-harness yang sama seperti balasan yang dipicu saluran.
runEmbeddedPiAgent(...) tetap menjadi alias kompatibilitas.
resolveThinkingPolicy(...) mengembalikan level thinking yang didukung penyedia/model dan default opsional. Plugin penyedia memiliki profil khusus model melalui hook thinking mereka, jadi plugin tool harus memanggil helper runtime ini alih-alih mengimpor atau menduplikasi daftar penyedia.
normalizeThinkingLevel(...) mengonversi teks pengguna seperti on, x-high, atau extra high ke level tersimpan kanonis sebelum memeriksanya terhadap policy yang di-resolve.
Helper penyimpanan sesi berada di bawah 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);
Utamakan updateSessionStore(...) atau updateSessionStoreEntry(...) untuk penulisan runtime. Keduanya route melalui penulis session-store milik Gateway, mempertahankan pembaruan serentak, dan menggunakan kembali hot cache. saveSessionStore(...) tetap tersedia untuk kompatibilitas dan penulisan ulang bergaya pemeliharaan offline.
api.runtime.agent.defaults
Konstanta model dan penyedia default:
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
Luncurkan dan kelola run subagent latar belakang.
// 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(...) dapat menghapus sesi yang dibuat oleh plugin yang sama melalui api.runtime.subagent.run(...). Menghapus sesi pengguna atau operator sembarang tetap memerlukan request Gateway dengan cakupan admin.
api.runtime.nodes
Cantumkan node yang terhubung dan panggil perintah yang di-host node dari kode plugin yang dimuat Gateway atau dari perintah CLI plugin. Gunakan ini ketika plugin memiliki pekerjaan lokal pada perangkat berpasangan, misalnya browser atau bridge audio di Mac lain.
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,
});
Di dalam Gateway, runtime ini berjalan in-process. Dalam perintah CLI plugin, runtime ini memanggil Gateway yang dikonfigurasi melalui RPC, sehingga perintah seperti openclaw googlemeet recover-tab dapat memeriksa node berpasangan dari terminal. Perintah node tetap melalui pairing node Gateway normal, allowlist perintah, kebijakan node-invoke plugin, dan penanganan perintah lokal node.
Plugin yang mengekspos perintah berbahaya yang di-host node harus mendaftarkan kebijakan node-invoke dengan api.registerNodeInvokePolicy(...). Kebijakan berjalan di Gateway setelah pemeriksaan allowlist perintah dan sebelum perintah diteruskan ke node, sehingga panggilan node.invoke langsung dan tool plugin level lebih tinggi berbagi jalur enforcement yang sama.
api.runtime.tasks.managedFlows
Ikat runtime Task Flow ke kunci sesi OpenClaw yang ada atau konteks tool tepercaya, lalu buat dan kelola Task Flow tanpa meneruskan owner pada setiap panggilan.
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" },
});
Gunakan bindSession({ sessionKey, requesterOrigin }) ketika Anda sudah memiliki kunci sesi OpenClaw tepercaya dari layer binding Anda sendiri. Jangan melakukan bind dari input pengguna mentah.
api.runtime.tts
Sintesis teks-ke-ucapan.
// 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,
});
Menggunakan konfigurasi inti messages.tts dan pemilihan penyedia. Mengembalikan buffer audio PCM + sample rate.
api.runtime.mediaUnderstanding
Analisis gambar, audio, dan 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,
});
Mengembalikan { text: undefined } ketika tidak ada keluaran yang dihasilkan (misalnya input dilewati).
api.runtime.imageGeneration
Pembuatan gambar.
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
Pencarian 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
Utilitas media tingkat rendah.
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 konfigurasi runtime saat ini dan penulisan konfigurasi transaksional. Utamakan
konfigurasi yang sudah diteruskan ke jalur panggilan aktif; gunakan
current() hanya ketika handler memerlukan snapshot proses secara langsung.
const cfg = api.runtime.config.current();
await api.runtime.config.mutateConfigFile({
afterWrite: { mode: "auto" },
mutate(draft) {
draft.plugins ??= {};
},
});
mutateConfigFile(...) dan replaceConfigFile(...) mengembalikan nilai
followUp, misalnya { mode: "restart", requiresRestart: true, reason },
yang mencatat maksud penulis tanpa mengambil alih kendali restart dari
Gateway.
api.runtime.system
Utilitas tingkat sistem.
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
Langganan peristiwa.
api.runtime.events.onAgentEvent((event) => {
/* ... */
});
api.runtime.events.onSessionTranscriptUpdate((update) => {
/* ... */
});
api.runtime.logging
Pencatatan log.
const verbose = api.runtime.logging.shouldLogVerbose();
const childLogger = api.runtime.logging.getChildLogger({ plugin: "my-plugin" }, { level: "debug" });
api.runtime.modelAuth
Resolusi autentikasi model dan penyedia.
const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg });
const providerAuth = await api.runtime.modelAuth.resolveApiKeyForProvider({
provider: "openai",
cfg,
});
api.runtime.state
Resolusi direktori status dan penyimpanan keyed berbasis 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();
Penyimpanan berkunci tetap bertahan setelah restart dan diisolasi oleh id plugin yang terikat runtime. Gunakan registerIfAbsent(...) untuk klaim deduplikasi atomik: fungsi ini mengembalikan true ketika kunci tidak ada atau sudah kedaluwarsa lalu didaftarkan, atau false ketika nilai live sudah ada tanpa menimpa nilainya, waktu pembuatannya, atau TTL. Batas: maxEntries per namespace, 1.000 baris live per plugin, nilai JSON di bawah 64KB, dan kedaluwarsa TTL opsional.
api.runtime.tools
Factory alat memori dan CLI.
const getTool = api.runtime.tools.createMemoryGetTool(/* ... */);
const searchTool = api.runtime.tools.createMemorySearchTool(/* ... */);
api.runtime.tools.registerMemoryCli(/* ... */);
api.runtime.channel
Helper runtime khusus channel (tersedia ketika plugin channel dimuat).
api.runtime.channel.mentions adalah permukaan kebijakan mention masuk bersama untuk plugin channel bawaan yang menggunakan injeksi 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 mention yang tersedia:
buildMentionRegexesmatchesMentionPatternsmatchesMentionWithExplicitimplicitMentionKindWhenresolveInboundMentionDecision
api.runtime.channel.mentions sengaja tidak mengekspos helper kompatibilitas resolveMentionGating* yang lebih lama. Utamakan jalur { facts, policy } yang sudah dinormalisasi.
Menyimpan referensi runtime
Gunakan createPluginRuntimeStore untuk menyimpan referensi runtime agar dapat digunakan di luar callback register:
Buat penyimpanan
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",
});
Hubungkan ke titik masuk
export default defineChannelPluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Example",
plugin: myPlugin,
setRuntime: store.setRuntime,
});
Akses dari file lain
export function getRuntime() {
return store.getRuntime(); // throws if not initialized
}
export function tryGetRuntime() {
return store.tryGetRuntime(); // returns null if not initialized
}
Field api tingkat atas lainnya
Selain api.runtime, objek API juga menyediakan:
api.idstringId plugin.
api.namestringNama tampilan plugin.
api.configOpenClawConfigSnapshot config saat ini (snapshot runtime dalam memori yang aktif saat tersedia).
OPENCLAW_DOCS_MARKER:paramOpen:IHBhdGg9ImFwaS5wbHVnaW5Db25maWciIHR5cGU9IlJlY29yZDxzdHJpbmcsIHVua25vd24
">
Config khusus plugin dari plugins.entries.<id>.config.
api.loggerPluginLoggerLogger dengan cakupan (debug, info, warn, error).
api.registrationModePluginRegistrationModeMode muat saat ini; "setup-runtime" adalah jendela startup/setup ringan sebelum entri penuh.
api.resolvePath(input)"(string)Terkait
- Internal plugin — model kapabilitas dan registry
- Titik masuk SDK — opsi
definePluginEntry - Ikhtisar SDK — referensi subpath