/** * JsonLineDriver — shared base for harnesses that speak a JSON-line stdout * protocol with a `kind`/`type` discriminator field. * * Codex, OpenCode, Hermes, Ollama, Gemini, and Memoire-native all fit this * shape. By the time we have 3 of them ported (Codex, Claude Code, * OpenCode), the duplication is obvious — this base class lifts it out so * the next 4 drivers are 50–100 LOC each instead of 250+. * * Subclasses provide: * - PROTOCOL_DISCRIMINATOR: "kind" | "type" (which field carries the event tag) * - PROTOCOL_TAGS: a mapping from this harness's event tags to canonical * ProviderRuntimeEvent emitter calls * * This keeps the per-harness code focused on protocol-specific quirks * (auth, transport startup, model identifiers, env shape) and pushes the * boilerplate into one place. * * Codex and Claude Code do NOT extend this base — they were authored * before the abstraction. They can be migrated later without changing * any behavior, since this base preserves the exact emission shape they * use today. */ import { Effect } from "effect"; import { type HarnessError } from "../contracts/errors.js"; import { BaseHarnessDriver, type HarnessTurnRequest } from "./base.js"; export interface LineTransport { write(line: string): Promise; close(reason?: string): Promise; kill(signal?: NodeJS.Signals): Promise; onLine(cb: (line: string, stream: "stdout" | "stderr") => void): () => void; onExit(cb: (code: number | null, signal: NodeJS.Signals | null) => void): () => void; } export interface JsonLineSpawnContext { model: string; env: NodeJS.ProcessEnv; cwd: string; } export interface JsonLineDriverOptions extends Record { model?: string; cwd?: string; env?: NodeJS.ProcessEnv; spawnTransport: (ctx: JsonLineSpawnContext) => Promise; } export interface JsonLineProtocolBinding { /** Which field on the parsed object carries the event tag. */ discriminatorField: "kind" | "type"; /** Default model identifier when options.model isn't set. */ defaultModel: string; /** Friendly subprocess name for diagnostics ("ollama", "gemini", etc.). */ processName: string; /** Map of harness-specific event tags to canonical emitter calls. */ emit(self: AbstractJsonLineDriver, tag: string, raw: Record): "handled" | "unknown"; } export declare abstract class AbstractJsonLineDriver extends BaseHarnessDriver { protected transport: LineTransport | null; private offLine; private offExit; protected abstract binding(): JsonLineProtocolBinding; private opts; start(): Effect.Effect; sendTurn(req: HarnessTurnRequest): Effect.Effect; interrupt(reason?: string): Effect.Effect; shutdown(): Effect.Effect; private handleLine; private handleExit; } /** * Default emitter helpers for the shared "Codex-style" protocol used by * Codex, OpenCode, Hermes, Ollama, Gemini, and Memoire-native. * * Each helper handles one event tag and returns "handled". Drivers that * need extra tags wrap this and add their own cases first. */ export declare const codexShapedEmit: { assistant_delta(self: AbstractJsonLineDriver, raw: Record): void; assistant_message(self: AbstractJsonLineDriver, raw: Record): void; tool_started(self: AbstractJsonLineDriver, raw: Record): void; tool_output(self: AbstractJsonLineDriver, raw: Record): void; tool_completed(self: AbstractJsonLineDriver, raw: Record): void; turn_completed(self: AbstractJsonLineDriver, raw: Record): void; usage(self: AbstractJsonLineDriver, raw: Record): void; }; /** Default emitter that handles the standard Codex-shaped tags. */ export declare function defaultCodexShapedEmit(self: AbstractJsonLineDriver, tag: string, raw: Record): "handled" | "unknown";