/**
 * High-level Agent wrapper around the streaming loop. It keeps the mutable run
 * state, exposes the public prompt/steer/follow-up surface, and forwards work to
 * the loop functions directly. There is no transport indirection here: by
 * default the model is reached through streamSimple.
 */
import { type ImageContent, type Message, type Model, type ThinkingBudgets } from "../ml/index.js";
import type { AgentEvent, AgentMessage, AgentState, AgentTool, CanUseToolFn, StreamFn, ThinkingLevel } from "./types.js";
type QueueMode = "all" | "one-at-a-time";
export interface AgentOptions {
    initialState?: Partial<AgentState>;
    /**
     * Hook that maps the agent's AgentMessage[] onto the provider-facing
     * Message[] right before every model call. When omitted, the built-in
     * reducer keeps only user/assistant/toolResult messages and converts
     * attachments.
     */
    convertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
    /**
     * Runs ahead of convertToLlm and may rewrite the message list — handy for
     * trimming long histories or splicing in extra context.
     */
    transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
    /**
     * How queued steering messages are released: "all" flushes the whole queue
     * in one go, "one-at-a-time" releases a single message per turn.
     */
    steeringMode?: QueueMode;
    /**
     * How queued follow-up messages are released: "all" flushes the whole queue
     * in one go, "one-at-a-time" releases a single message per turn.
     */
    followUpMode?: QueueMode;
    /**
     * Swap in an alternative streaming implementation — e.g. a remote proxy
     * backend. Falls back to streamSimple when not provided.
     */
    streamFn?: StreamFn;
    /**
     * Stable identifier passed through to providers that key their server-side
     * caches on a session, so repeated turns can reuse prior context.
     */
    sessionId?: string;
    /**
     * Supplies a fresh API key per call. Useful when credentials rotate or
     * expire, such as short-lived OAuth access tokens.
     */
    getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
    /**
     * Hard permission gate consulted before each tool runs. A host supplies it to
     * enforce an allow/ask/deny policy; the loop awaits it on the validated args
     * and either proceeds (optionally with substituted input) or short-circuits
     * to an isError result. Omit it to allow every tool — today's behavior.
     */
    canUseTool?: CanUseToolFn;
    /**
     * Per-level token allowances for thinking; only meaningful for providers
     * whose reasoning effort is expressed as a token budget.
     */
    thinkingBudgets?: ThinkingBudgets;
}
export declare class Agent {
    private _state;
    private readonly eventBus;
    private readonly stateManager;
    private readonly queuePolicy;
    private abortController?;
    private convertToLlm;
    private transformContext?;
    streamFn: StreamFn;
    private _sessionId?;
    getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
    canUseTool?: CanUseToolFn;
    private runningPrompt?;
    private resolveRunningPrompt?;
    private _thinkingBudgets?;
    constructor(opts?: AgentOptions);
    /**
     * The session identifier currently forwarded to providers for caching.
     */
    get sessionId(): string | undefined;
    /**
     * Update the provider-caching session identifier. Set a new value whenever
     * the conversation changes identity — a brand-new session, a branch, or a
     * resumed run.
     */
    set sessionId(value: string | undefined);
    /**
     * The thinking-level token budgets currently in effect, if any.
     */
    get thinkingBudgets(): ThinkingBudgets | undefined;
    /**
     * Override the thinking-level token budgets for providers that meter
     * reasoning by token count.
     */
    set thinkingBudgets(value: ThinkingBudgets | undefined);
    get state(): AgentState;
    subscribe(fn: (e: AgentEvent) => void): () => void;
    setSystemPrompt(v: string): void;
    setModel(m: Model<any>): void;
    setThinkingLevel(l: ThinkingLevel): void;
    setSteeringMode(mode: QueueMode): void;
    getSteeringMode(): QueueMode;
    setFollowUpMode(mode: QueueMode): void;
    getFollowUpMode(): QueueMode;
    setTools(t: AgentTool<any>[]): void;
    replaceMessages(ms: AgentMessage[]): void;
    appendMessage(m: AgentMessage): void;
    /**
     * Enqueue a steering message to redirect the agent while it is running. It
     * lands once the in-flight tool finishes and causes any still-pending tool
     * calls in that turn to be skipped.
     */
    steer(m: AgentMessage): void;
    /**
     * Enqueue a follow-up message that is held back until the agent has gone
     * idle — i.e. there are no outstanding tool calls and no steering left to
     * process.
     */
    followUp(m: AgentMessage): void;
    clearSteeringQueue(): void;
    clearFollowUpQueue(): void;
    clearAllQueues(): void;
    clearMessages(): void;
    abort(): void;
    waitForIdle(): Promise<void>;
    reset(): void;
    /** Submit a new prompt, given either raw text or one or more AgentMessages. */
    prompt(message: AgentMessage | AgentMessage[]): Promise<void>;
    prompt(input: string, images?: ImageContent[]): Promise<void>;
    /** Resume the existing conversation, e.g. to retry after a context overflow. */
    continue(): Promise<void>;
    /**
     * Core driver for a run. Passing a messages array opens a new turn seeded
     * with them; passing nothing resumes the conversation already in state.
     */
    private _runLoop;
    private emit;
}
export {};
