/** * OpenClaw Runtime Adapter — drives the local `openclaw` CLI as a subprocess. * * Each call to `promptWithFallback` invokes * `openclaw --no-color agent --local --json --session-id --message ` * (and `--model`, `--thinking`, `--timeout`, `--agent` if configured), * parses the JSON document on stdout, and forwards visible/reasoning text * via the session callbacks. * * Session continuity: the UUID minted on session create is reused on every * subsequent prompt as `--session-id`, so openclaw resumes the same agent * conversation server-side. */ import type { AgentRuntime, AgentRuntimeOptions, AgentSessionResult, CliConfig, GatewaySession, } from "./types.js"; import { createCliSession, describeCliModel, promptCli, resolveCliConfig, } from "./pi-module.js"; export class OpenClawRuntimeAdapter implements AgentRuntime { readonly id = "openclaw"; readonly name = "OpenClaw Runtime"; private readonly config: CliConfig; constructor(settings?: Partial | Record) { this.config = resolveCliConfig(settings as Record | undefined); } async createSession(options: AgentRuntimeOptions): Promise { const session = createCliSession({ systemPrompt: options.systemPrompt, agentId: this.config.agentId, callbacks: { onText: options.onText, onThinking: options.onThinking, onToolStart: options.onToolStart, onToolEnd: options.onToolEnd, }, }); return { session, sessionFile: undefined }; } async promptWithFallback( session: GatewaySession, prompt: string, options?: unknown, ): Promise { const overrideCallbacks = (options ?? undefined) as | Parameters[3] | undefined; await promptCli(session, prompt, this.config, overrideCallbacks); } describeModel(session: GatewaySession): string { return describeCliModel(session); } async dispose(_session: GatewaySession): Promise { // No persistent resources — each prompt spawns a fresh subprocess. } }