import type { AgentEvent, AgentExecuteParams, AgentRuntime } from "./types.js"; /** * Abstract base class encapsulating shared subprocess machinery for CLI-based agent runtimes. * * Concrete runtimes (Claude, Gemini, Codex, OpenCode) extend this and implement only * the CLI-specific parts: argument construction, event extraction, and environment setup. */ export declare abstract class CLIRuntimeBase implements AgentRuntime { /** CLI command name (e.g., "claude", "gemini", "codex", "opencode"). */ protected readonly command: string; /** Subprocess timeout in milliseconds (default: 5 minutes). */ protected readonly timeoutMs: number; /** Threshold above which prompts are delivered via stdin instead of CLI argument. */ private static readonly STDIN_PROMPT_THRESHOLD; /** * In-flight subprocess counts per CLI backend. Shared across all instances * of a given runtime so the gauge reflects total concurrency, not per-instance. */ private static readonly inflightCounts; constructor( /** CLI command name (e.g., "claude", "gemini", "codex", "opencode"). */ command: string, /** Subprocess timeout in milliseconds (default: 5 minutes). */ timeoutMs?: number); /** * Whether to sample subprocess RSS during in-flight execution. * Default `false`. Multi-process backends (Gemini/Codex/OpenCode) override * to `true`. Claude's per-session 1-process-per-turn model has different * topology, so RSS sampling is not applied there. */ protected get shouldSampleRss(): boolean; /** RSS sampling interval in milliseconds (default 5s). */ protected get rssSampleIntervalMs(): number; /** * Emit a single structured metric line via the debug logger. * * Format: `[agent-runtime] metric= backend= value= [extra=...]` * * Intentionally line-oriented and grep-aggregatable so no metrics backend * is required at the call site. See `src/middleware/README.md` for the * full metric vocabulary. */ protected emitMetric(name: string, value: number, extras?: Record): void; /** * Run an MCP-config manager's `setup()` with timing instrumentation. * Emits the `mcp_config_setup_ms` metric on completion (success or failure). */ protected timedMcpSetup(manager: { setup(): Promise; } | null): Promise; /** * Run an MCP-config manager's `teardown()` with timing instrumentation. * Emits the `mcp_config_teardown_ms` metric on completion (always — teardown * is invoked from `finally` blocks even on the failure path). */ protected timedMcpTeardown(manager: { teardown(): Promise; } | null): Promise; /** * Sample resident set size of a child process via `ps -o rss= -p `. * Returns RSS in megabytes, or `undefined` if sampling failed (e.g., the * child has already exited or `ps` is unavailable on the host). */ protected sampleRssMb(pid: number): Promise; /** Construct CLI-specific command-line arguments. */ protected abstract buildArgs(params: AgentExecuteParams): string[]; /** Parse a single NDJSON line into an AgentEvent (or null to skip). */ protected abstract extractEvent(line: string): AgentEvent | null; /** Construct provider-specific environment variables. */ protected abstract buildEnv(params: AgentExecuteParams): Record; /** * Compose the full prompt from structured parts (system + extra context + user). * Runtimes that support separate system prompt delivery (e.g. Claude) should * override or bypass this and handle the parts individually. */ protected composePrompt(params: AgentExecuteParams): string; /** * Construct a custom stdin payload for the subprocess. * When this returns a string, it is written to stdin instead of * the default large-prompt fallback. Subclasses may override. */ protected buildStdinPayload(_params: AgentExecuteParams): string | undefined; /** Whether this CLI accepts prompts via stdin. Subclasses may override. */ protected get supportsStdinPrompt(): boolean; /** * Which subprocess stream carries NDJSON output. * Defaults to `"stdout"`. Override to `"stderr"` for CLIs (like Claude) * that emit structured output on stderr. */ protected get ndjsonStream(): "stdout" | "stderr"; execute(params: AgentExecuteParams): AsyncIterable; }