/**
 * The runner contract — the data-driven replacement for a mode if/else.
 *
 * A {@link Runner} is one self-describing way to drive the agent: it knows the
 * single {@link Invocation} shape it {@link Runner.accepts | accepts} and how to
 * {@link Runner.run | run} a fully-prepared {@link BootContext} to an exit code.
 * Selection is a linear scan over a registry (see `registry.ts`) — the first
 * runner that accepts an invocation wins — so adding a new way to run the agent
 * is a matter of appending one entry, never editing a dispatch ladder.
 *
 * The interactive surface is kept behind the {@link InteractiveView} seam: the
 * REPL runner drives the agent through a `view` it never has to know the shape
 * of, so a richer terminal UI can be slotted in later by implementing the
 * interface — without this layer importing any UI toolkit.
 */
import type { Agent, RunEvent, RunSnapshot } from "../../runtime";
import type { Settings } from "../config";
import type { Invocation } from "../invocation/parse";
/**
 * The optional collaborators the boot module hands a runner.
 *
 * Re-declared here (rather than imported from `runtime`) so the runners layer
 * owns its own seam vocabulary. It mirrors the runtime's `AgentDeps` loosely:
 * the boot module is free to inject a scripted model, a store, or a ledger.
 */
export interface AgentDeps {
    /** A model entrypoint override; absent uses the gateway default. */
    readonly invokeModel?: unknown;
    /** A durable session store; absent disables persistence. */
    readonly store?: unknown;
    /** An event ledger to publish on; absent uses a fresh internal one. */
    readonly ledger?: unknown;
}
/**
 * The fully-resolved context a runner needs, assembled by the boot module.
 *
 * Boot does the up-front work — parse the invocation, load settings, resolve the
 * model id, probe the streams — and packages it here. A runner never re-derives
 * any of it; it only builds an agent (via {@link makeAgent}) and drives it over
 * the supplied streams.
 *
 * `view` is present only for the interactive runner; one-shot and wire runners
 * talk to {@link output}/{@link input} directly and ignore it.
 */
export interface BootContext {
    /** The parsed invocation this run was launched with. */
    readonly invocation: Invocation;
    /** The merged, normalized user settings. */
    readonly settings: Settings;
    /** The resolved model id every agent built here is bound to. */
    readonly modelId: string;
    /**
     * Factory for the run's {@link Agent}. The boot module pre-binds the model,
     * tools, and system prompt; a runner may pass optional {@link AgentDeps} to
     * override the model entrypoint, store, or ledger.
     */
    readonly makeAgent: (deps?: AgentDeps) => Agent;
    /** Where a runner writes its output (stdout in production). */
    readonly output: NodeJS.WritableStream;
    /** Where a runner reads its input (stdin in production). */
    readonly input: NodeJS.ReadableStream;
    /** The interactive seam, supplied only when an interactive runner will run. */
    readonly view?: InteractiveView;
}
/**
 * One self-describing way to drive the agent to an exit code.
 *
 * The registry holds many; {@link selectRunner} picks the first whose
 * {@link accepts} returns true for an invocation. `run` resolves the process
 * exit code (0 = success, non-zero = failure) — it must not call
 * `process.exit` itself, so the boot module stays in control of teardown.
 */
export interface Runner {
    /** A stable identifier, handy for logging and tests. */
    readonly id: string;
    /** Whether this runner handles the given invocation. */
    accepts(invocation: Invocation): boolean;
    /** Drive the prepared context to completion; resolves the exit code. */
    run(ctx: BootContext): Promise<number>;
}
/**
 * The seam a real interactive UI implements.
 *
 * The REPL runner owns the read-submit-render loop but knows nothing about *how*
 * a turn is presented: it pushes each {@link RunEvent} at {@link render}, asks
 * {@link prompt} for the next line of user input, and calls {@link close} once
 * on teardown. A minimal plain-text view ships in `repl.ts`; a richer terminal
 * UI can satisfy the same three methods later without touching this layer.
 */
export interface InteractiveView {
    /** Present one run event (a delta, a tool lifecycle marker, a settle…). */
    render(event: RunEvent): void;
    /**
     * Ask the user for their next line of input and resolve the typed line.
     *
     * End-of-input (the stream closed, or the user pressed Ctrl-D) is signalled by
     * *rejecting* with {@link EndOfInput} rather than resolving a sentinel, so an
     * empty line stays a legitimate, submittable value. The loop catches it and
     * leaves cleanly.
     */
    prompt(): Promise<string>;
    /** Release any resources (e.g. a readline interface). Called once. */
    close(): void;
}
/**
 * The rejection {@link InteractiveView.prompt} raises when input is exhausted.
 *
 * A typed marker (rather than a magic string return) keeps EOF distinguishable
 * from a blank line and lets the REPL loop end on `instanceof` rather than value
 * matching.
 */
export declare class EndOfInput extends Error {
    constructor();
}
/** Re-exported for convenience so runner modules import from one site. */
export type { Agent, RunEvent, RunSnapshot, Invocation, Settings };
