/** * AgentRunner — provider-agnostic execution surface for Org Runtime v2. * * Why this exists: session.ts used to import `query`, `tool`, and * `createSdkMcpServer` directly from `@anthropic-ai/claude-agent-sdk`, which * hard-coupled the entire org runtime to Claude. This interface lets session.ts * describe WHAT to run (an agent with a set of org tools, a system prompt, and * a mailbox prompt stream) without knowing WHICH SDK executes it. * * Behavior preservation (the invariant the Claude path must not break): * ClaudeAgentRunner is a faithful, line-for-line extraction of the previous * inline logic in session.ts's runOneSession — same options object, same * message normalization, same queryFn injection seam that test-loop.ts relies * on. The default runner is ClaudeAgentRunner, so an org that doesn't ask for * opencode executes through exactly the same code path it always did. */ import { query } from '@anthropic-ai/claude-agent-sdk'; import type { z } from 'zod'; /** A platform-agnostic org tool definition. `schema` is a zod object because * both the Claude SDK's `tool()` and opencode's `tool()` consume zod. */ export interface OrgToolDef { name: string; description: string; /** zod shape object (e.g. { query: z.string() }), NOT a z.object() instance. * Both the Claude SDK's tool() and opencode's tool() consume a shape. */ schema: Record>; handler: (args: Record) => Promise<{ text: string; }>; } /** Arguments every runner needs to execute one agent session. */ export interface AgentRunArgs { tools: OrgToolDef[]; /** The mailbox prompt stream (or any async iterable of prompt messages). */ prompt: AsyncIterable; systemPrompt: string; model?: string; cwd: string; env: Record; maxTurns: number; resume?: string; canUseTool?: (toolName: string, input: Record) => Promise; /** Provider-specific escape hatch. ClaudeAgentRunner merges this into the * SDK options verbatim (e.g. the `_orgTest` seam used by test-loop.ts). * Other runners ignore it. */ extras?: Record; } /** Normalized message every runner yields. Carries `session_id` on whatever * message the underlying SDK attaches it to, so session.ts can track it for * resume — matching the previous `if (m.session_id) sessionId = m.session_id` * behaviour that read it off ANY message kind. * * `tool_use` is a lightweight liveness/progress signal: session.ts never * renders it as chat or usage — it only feeds the StateDetector (which maps * it to the 'tool-call' state) and refreshes last-activity. Subprocess * runners (kimicode) emit it for native tool activity so long turns show * ongoing progress instead of looking silent. */ export interface AgentMessage { type: 'assistant' | 'result' | 'tool_use'; session_id?: string; text?: string; subtype?: string; is_error?: boolean; input_tokens?: number; output_tokens?: number; cost_usd?: number; } export interface AgentRunner { run(args: AgentRunArgs): AsyncIterable; } /** * Default runner — wraps the Claude Agent SDK. This is the previous inline * logic of runOneSession, extracted verbatim: * - convert OrgToolDef[] → SDK tool() calls → createSdkMcpServer * - call queryFn({ prompt, options }) (queryFn injectable for tests) * - normalize the raw stream into AgentMessage */ export declare class ClaudeAgentRunner implements AgentRunner { private queryFn; constructor(queryFn?: typeof query); run(args: AgentRunArgs): AsyncIterable; } /** Shared default instance (stateless — safe to reuse). */ export declare const defaultClaudeRunner: ClaudeAgentRunner; //# sourceMappingURL=agent-runner.d.ts.map