--- title: "Plugin Runtime Helpers" sidebarTitle: "Runtime Helpers" summary: "api.runtime -- the injected runtime helpers available to plugins" read_when: - You need to call core helpers from a plugin (TTS, STT, image gen, web search, subagent) - You want to understand what api.runtime exposes - You are accessing config, agent, or media helpers from plugin code --- # Plugin Runtime Helpers Reference for the `api.runtime` object injected into every plugin during registration. Use these helpers instead of importing host internals directly. **Looking for a walkthrough?** See [Channel Plugins](/plugins/sdk-channel-plugins) or [Provider Plugins](/plugins/sdk-provider-plugins) for step-by-step guides that show these helpers in context. ```typescript register(api) { const runtime = api.runtime; } ``` ## Runtime namespaces ### `api.runtime.agent` Agent identity, directories, and session management. ```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); // Get agent timeout const timeoutMs = api.runtime.agent.resolveAgentTimeoutMs(cfg); // Ensure workspace exists await api.runtime.agent.ensureAgentWorkspace(cfg); // Run an embedded Pi agent (requires sessionFile + workspaceDir at minimum) const agentDir = api.runtime.agent.resolveAgentDir(cfg); const result = await api.runtime.agent.runEmbeddedPiAgent({ sessionId: "my-plugin:task-1", sessionFile: path.join(agentDir, "sessions", "my-plugin-task-1.jsonl"), workspaceDir: api.runtime.agent.resolveAgentWorkspaceDir(cfg), prompt: "Summarize the latest changes", }); ``` **Session store helpers** are under `api.runtime.agent.session`: ```typescript const storePath = api.runtime.agent.session.resolveStorePath(cfg); const store = api.runtime.agent.session.loadSessionStore(cfg); await api.runtime.agent.session.saveSessionStore(cfg, store); const filePath = api.runtime.agent.session.resolveSessionFilePath(cfg, sessionId); ``` ### `api.runtime.agent.defaults` Default model and provider constants: ```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" ``` ### `api.runtime.subagent` Launch and manage background subagent runs. ```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", }); ``` Model overrides (`provider`/`model`) require operator opt-in via `plugins.entries..subagent.allowModelOverride: true` in config. Untrusted plugins can still run subagents, but override requests are rejected. ### `api.runtime.tts` Text-to-speech synthesis. ```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, }); ``` Uses core `messages.tts` configuration and provider selection. Returns PCM audio buffer + sample rate. ### `api.runtime.mediaUnderstanding` Image, audio, and video analysis. ```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, }); ``` Returns `{ text: undefined }` when no output is produced (e.g. skipped input). `api.runtime.stt.transcribeAudioFile(...)` remains as a compatibility alias for `api.runtime.mediaUnderstanding.transcribeAudioFile(...)`. ### `api.runtime.imageGeneration` Image generation. ```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 }); ``` ### `api.runtime.webSearch` Web search. ```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 }, }); ``` ### `api.runtime.media` Low-level media utilities. ```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 }); ``` ### `api.runtime.config` Config load and write. ```typescript const cfg = await api.runtime.config.loadConfig(); await api.runtime.config.writeConfigFile(cfg); ``` ### `api.runtime.system` System-level utilities. ```typescript await api.runtime.system.enqueueSystemEvent(event); api.runtime.system.requestHeartbeatNow(); const output = await api.runtime.system.runCommandWithTimeout(cmd, args, opts); const hint = api.runtime.system.formatNativeDependencyHint(pkg); ``` ### `api.runtime.events` Event subscriptions. ```typescript api.runtime.events.onAgentEvent((event) => { /* ... */ }); api.runtime.events.onSessionTranscriptUpdate((update) => { /* ... */ }); ``` ### `api.runtime.logging` Logging. ```typescript const verbose = api.runtime.logging.shouldLogVerbose(); const childLogger = api.runtime.logging.getChildLogger({ plugin: "my-plugin" }, { level: "debug" }); ``` ### `api.runtime.modelAuth` Model and provider auth resolution. ```typescript const auth = await api.runtime.modelAuth.getApiKeyForModel({ model, cfg }); const providerAuth = await api.runtime.modelAuth.resolveApiKeyForProvider({ provider: "openai", cfg, }); ``` ### `api.runtime.state` State directory resolution. ```typescript const stateDir = api.runtime.state.resolveStateDir(); ``` ### `api.runtime.tools` Memory tool factories and CLI. ```typescript const getTool = api.runtime.tools.createMemoryGetTool(/* ... */); const searchTool = api.runtime.tools.createMemorySearchTool(/* ... */); api.runtime.tools.registerMemoryCli(/* ... */); ``` ### `api.runtime.channel` Channel-specific runtime helpers (available when a channel plugin is loaded). ## Storing runtime references Use `createPluginRuntimeStore` to store the runtime reference for use outside the `register` callback: ```typescript import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store"; const store = createPluginRuntimeStore("my-plugin runtime not initialized"); // In your entry point export default defineChannelPluginEntry({ id: "my-plugin", name: "My Plugin", description: "Example", plugin: myPlugin, setRuntime: store.setRuntime, }); // In other files export function getRuntime() { return store.getRuntime(); // throws if not initialized } export function tryGetRuntime() { return store.tryGetRuntime(); // returns null if not initialized } ``` ## Other top-level `api` fields Beyond `api.runtime`, the API object also provides: | Field | Type | Description | | ------------------------ | ------------------------- | --------------------------------------------------------- | | `api.id` | `string` | Plugin id | | `api.name` | `string` | Plugin display name | | `api.config` | `OpenClawConfig` | Current config snapshot | | `api.pluginConfig` | `Record` | Plugin-specific config from `plugins.entries..config` | | `api.logger` | `PluginLogger` | Scoped logger (`debug`, `info`, `warn`, `error`) | | `api.registrationMode` | `PluginRegistrationMode` | `"full"`, `"setup-only"`, or `"setup-runtime"` | | `api.resolvePath(input)` | `(string) => string` | Resolve a path relative to the plugin root | ## Related - [SDK Overview](/plugins/sdk-overview) -- subpath reference - [SDK Entry Points](/plugins/sdk-entrypoints) -- `definePluginEntry` options - [Plugin Internals](/plugins/architecture) -- capability model and registry