/**
 * GeminiLoopRunner (need-gem-002, increment 2) — the budget-gated, dark-by-default
 * service that makes the GeminiLoopDriver invocable.
 *
 * A multi-turn gemini loop can run for minutes (several turns × a turn each), so
 * it CANNOT block an HTTP request. `startRun` admits a run (enabled? under
 * concurrency cap? budget ok?), kicks off `driver.run()` in the background, and
 * returns a `runId` immediately; the result lands in a bounded in-memory registry
 * retrievable via `getRun`. Ships DARK (`enabled: false`); the `developmentAgent`
 * gate turns it on for dev agents only.
 *
 * Subscription auth is structural: the runner's spawn dep is the production
 * transport spawn (`buildGeminiChildEnv` strips every billing var), so no run can
 * introduce an API key.
 *
 * Spec: docs/specs/gemini-multi-turn-loop-driver.md
 */
import { type GeminiLoopSpawn, type GeminiLoopHandleCapture, type GeminiLoopBudgetGate, type GeminiLoopResult } from './GeminiLoopDriver.js';
export interface GeminiLoopDriverConfig {
    enabled: boolean;
    /** Model passed to every turn (explicit -m bypasses the router classifier). */
    model: string;
    /** Hard cap on turns per run. */
    maxTurns: number;
    /** Min ms between turns (anti-spin). */
    minTurnIntervalMs: number;
    /** Max concurrent runs. 1 keeps shared-cwd handle capture unambiguous. */
    maxConcurrent: number;
    /** Bounded registry size — oldest finished runs are evicted past this. */
    maxRetainedRuns: number;
    /** Sentinel the mentee emits when done. */
    doneSentinel?: string;
}
export type GeminiLoopRunStatus = 'running' | 'done' | 'error';
export interface GeminiLoopRunRecord {
    runId: string;
    status: GeminiLoopRunStatus;
    goalPrompt: string;
    model: string;
    maxTurns: number;
    startedAt: number;
    finishedAt?: number;
    result?: GeminiLoopResult;
    error?: string;
}
export interface GeminiLoopStartRequest {
    goalPrompt: string;
    model?: string;
    maxTurns?: number;
}
export type GeminiLoopStartOutcome = {
    ok: true;
    runId: string;
} | {
    ok: false;
    reason: 'disabled' | 'at-capacity' | 'budget' | 'invalid';
    detail?: string;
};
export interface GeminiLoopRunnerDeps {
    config: GeminiLoopDriverConfig;
    spawn: GeminiLoopSpawn;
    captureHandle: GeminiLoopHandleCapture;
    budgetGate: GeminiLoopBudgetGate;
    now?: () => number;
    genId?: () => string;
    log?: (msg: string) => void;
}
export declare class GeminiLoopRunner {
    private readonly config;
    private readonly spawn;
    private readonly captureHandle;
    private readonly budgetGate;
    private readonly now;
    private readonly genId;
    private readonly log;
    private readonly runs;
    private activeCount;
    constructor(deps: GeminiLoopRunnerDeps);
    isEnabled(): boolean;
    activeRuns(): number;
    /**
     * Admit + launch a run. Returns immediately with a runId; the loop runs in the
     * background. Admission order: feature enabled → under concurrency cap → valid
     * goal → budget gate open.
     */
    startRun(req: GeminiLoopStartRequest): GeminiLoopStartOutcome;
    getRun(runId: string): GeminiLoopRunRecord | null;
    listRuns(): GeminiLoopRunRecord[];
    private execute;
    /** Keep the registry bounded — drop the oldest FINISHED runs past the cap. */
    private evictOldFinished;
}
//# sourceMappingURL=GeminiLoopRunner.d.ts.map