/**
 * minimal-loop — AgentLoop for multi-provider routing (Anthropic + Groq cascade).
 *
 * PUBLIC SURFACE — exactly 5 exports (1 class, 4 type re-exports). Any
 * additional helpers MUST remain unexported.
 */
import { type Tracer } from "@opentelemetry/api";
import { type AgentBudgetState } from "../budget/budget-state.js";
import type { ApprovalChannel } from "../hitl/approval-channel.js";
import type { CapabilityGate } from "../permissions/capability-gate.js";
import type { RenewalManager } from "../permissions/renewal-manager.js";
import type { InstructionInbox } from "../remote/inbox.js";
import type { SessionEventSink } from "../remote/sink.js";
import type { VetoChannel } from "../remote/veto.js";
import type { ProviderRouter } from "../router/provider-router.js";
export type { ToolRegistry } from "../tools/types.js";
import type { ToolRegistry } from "../tools/types.js";
interface AgentLoopConfig {
    agentId: string;
    agentVersion: string;
    systemPrompt: string;
    provider: ProviderRouter;
    tools: ToolRegistry;
    budget: AgentBudgetState;
    approvalChannel?: ApprovalChannel;
    tracker?: {
        recordStep: (d: {
            inputTokens: number;
            outputTokens: number;
            toolCalls?: number;
            costUsd: number;
        }) => Promise<void>;
    };
    /** Inject a tracer for tests. Defaults to the singleton OTel tracer. */
    tracer?: Tracer;
    /** HITL poll interval (ms). Default 500. */
    approvalPollIntervalMs?: number;
    /** HITL default timeout (ms). Default 60_000. */
    approvalTimeoutMs?: number;
    /**
     * Optional Biscuit capability gate. When provided, every tool call is
     * checked against the gate BEFORE dispatch. Denied calls produce a
     * `tool_denied` event and a structured tool-result error; the loop
     * continues with the next call (no panic).
     */
    capabilityGate?: CapabilityGate;
    /**
     * Hook fired when the capability gate denies a tool call. Receives the
     * call name and the deny reason. Best-effort — exceptions are swallowed.
     */
    onToolDenied?: (event: {
        toolName: string;
        reason: string;
        budgetUsed: number;
    }) => void;
    /**
     * Coarse cost-per-call (USD). Default 0 (loop doesn't know LLM unit
     * cost). Hosts that want budget enforcement set this to a per-call
     * estimate; it accumulates across the loop and is passed to the gate.
     */
    costPerToolCallUsd?: number;
    /**
     * Optional auto-renewal. When provided, the loop calls `maybeRenew()`
     * once per LLM iteration (before tool dispatch). The manager debounces
     * and only re-issues when ≥80% of the token lifetime has elapsed.
     */
    renewalManager?: RenewalManager;
    /**
     * Number of consecutive identical tool calls that triggers a loop abort.
     * Default 6. Set higher (e.g. 12) for autonomous research agents that
     * legitimately re-visit the same tools with the same args.
     */
    loopDetectionWindow?: number;
    /**
     * Steps without any tool call before a stall is declared.
     * Default 10. Set higher for agents that do long reasoning stretches.
     */
    stallThreshold?: number;
    /**
     * Optional embedding function for progress-based stall detection.
     * When provided, PromiseProgressTracker replaces the heuristic coherence check.
     * Signature: (text: string) => Promise<number[]>
     */
    embedFn?: (text: string) => Promise<number[]>;
    /**
     * Prior conversation history as proper messages (sprint-736+).
     *
     * When provided, the log is built as:
     *   [system] [initialMessages...] [user: userMessage]
     *
     * This replaces the legacy pattern of injecting history as a text suffix
     * in the system prompt. The model sees its own prior tool calls and results
     * as structured messages instead of having to parse a text summary.
     *
     * Messages with role "system" in this array are ignored — the system prompt
     * from `config.systemPrompt` is always used as the first message.
     */
    initialMessages?: Array<{
        role: string;
        content: string;
        toolName?: string;
    }>;
    /**
     * When true, disable ALL stop heuristics except budget_exhausted, complete,
     * user_cancelled, tool_denied, and error. Specifically:
     *   - WorldStateHashTracker collision → loop_definitive ; DISABLED
     *   - PromiseProgressTracker plateau → loop_definitive ; DISABLED
     *   - createCoherenceDetector loop/stall → incoherent ; DISABLED
     *
     * The read-result cache still applies (returns cached results to save tokens
     * and prevent the model from doing redundant work) but never aborts the loop.
     *
     * Use this in auto mode where the model is trusted to decide when to stop.
     * Matches Claude Code / Codex behavior: no heuristic safeguards.
     */
    disableLoopDetection?: boolean;
    /**
     * Wall-clock ceiling in milliseconds. 0 or undefined = unlimited.
     *
     * This is the SOTA antifragile backstop for autonomous runs: instead of an
     * arbitrary step cap (a "step" can be 100 or 50 000 tokens — unpredictable),
     * wall-clock time is semantic and predictable. When the elapsed time since
     * loop start exceeds this value, the loop stops with stopReason
     * "budget_exhausted" and loopDetail.reason "max_time".
     *
     * Recommended: interactive = unlimited (user watches), autonomous/daemon =
     * a real ceiling (e.g. 600_000 = 10 min).
     */
    maxWallClockMs?: number;
    /**
     * Cost ceiling in USD. 0 or undefined = unlimited.
     *
     * The twin of `maxWallClockMs`: a semantic, predictable budget bound for
     * autonomous runs. After each LLM round-trip the loop adds the step cost
     * (computed via `costFn`) to a running total; when it reaches `maxCostUsd`
     * the loop stops with stopReason "budget_exhausted" and
     * loopDetail.reason "max_cost".
     *
     * Requires `costFn` to be set — without a pricing function the loop cannot
     * compute cost and the ceiling is inert.
     */
    maxCostUsd?: number;
    /**
     * Pricing function: maps a step's token usage to a USD cost. Injected by
     * the caller (the SDK is pricing-table-agnostic on purpose). When set, the
     * loop accumulates cost per step and exposes the total in
     * `budgetFinal.tokensBudget` consumers / enables the `maxCostUsd` ceiling.
     */
    costFn?: (usage: {
        inputTokens: number;
        outputTokens: number;
    }) => number;
    /**
     * Remote-control event sink. When set, the loop emits `SessionEvent`s
     * (run.start, run.step, assistant.message, tool.call.*, run.finished) so a
     * remote client can observe the run live. Default: no events emitted.
     */
    eventSink?: SessionEventSink;
    /**
     * Remote-control instruction inbox. When set, the loop drains it at every
     * step boundary and injects queued instructions into the conversation as
     * `user` messages — mid-run steering (interrupt-and-redirect).
     */
    instructionInbox?: InstructionInbox;
    /**
     * Pre-tool-call veto bus (T6a). When set together with `vetoWindowMs > 0`
     * and an `eventSink`, the loop emits `tool.intent` before every tool call
     * and waits up to `vetoWindowMs` for a matching signal. A vetoed call is
     * SKIPPED and recorded as `[vetoed by <by>]` in the conversation log so
     * the LLM can adjust on its next step.
     */
    vetoChannel?: VetoChannel;
    /**
     * Milliseconds the loop waits on `vetoChannel` per tool call before
     * proceeding. Default: 0 (veto disabled). Keep low (e.g. 1500ms) for
     * interactive supervision, higher (e.g. 10s) for fully gated runs.
     */
    vetoWindowMs?: number;
}
interface AgentLoopRunResult {
    finalMessage: string;
    stopReason: "complete" | "budget_exhausted" | "incoherent" | "loop_definitive" | "tool_denied" | "user_cancelled" | "error";
    budgetFinal: AgentBudgetState;
    traceId: string;
    /** Populated when stopReason === "error" — the underlying exception message. */
    errorMessage?: string;
    /**
     * Populated when stopReason === "loop_definitive". Identifies which
     * tool+args+output state was observed twice and the earlier step index.
     */
    loopDetail?: {
        toolName: string;
        hash: string;
        firstStep: number;
        repeatStep: number;
        /**
         * Sub-reason for the stop. Distinguishes WHY a budget_exhausted /
         * loop_definitive fired so callers and the CLI banner can be precise.
         */
        reason?: "max_steps" | "max_time" | "max_cost" | "hash_collision" | "progress_plateau";
    };
    /** Cumulative LLM cost in USD across the run (0 when no costFn is set). */
    costUsd?: number;
}
declare class AgentLoopImpl {
    private readonly config;
    private readonly tracer;
    constructor(config: AgentLoopConfig);
    run(userMessage: string): Promise<AgentLoopRunResult>;
    private awaitApproval;
}
export { AgentLoopImpl as AgentLoop };
export type { AgentLoopRunResult, AgentLoopConfig };
//# sourceMappingURL=minimal-loop.d.ts.map