import { type ElicitationRequest, type HumanReply } from '../elicitation.js';
import type { AgentStore, CostSource } from '../spi/agent-store.js';
import type { ApprovalRequirement } from '../spi/approval-policy.js';
import type { SinkWriter } from '../spi/token-stream-sink.js';
import type { AgentUiComponent } from '../stream-events.js';
import { type ToolPresentation } from '../tool-presentation.js';
import type { AgentRunInput, MessageUsage } from '../types.js';
import type { OpenCodeClient, OpenCodeEvent, OpenCodeForm, OpenCodeTokens } from './client.js';
/** How an OpenCode execution ended. */
export type TurnOutcome = {
    status: 'succeeded';
} | {
    status: 'failed';
    error: string;
} | {
    status: 'interrupted';
};
/**
 * Something the turn put to a person, with everything needed to hand the answer back to OpenCode
 * later — serializable, so a durable run journals it and replies from another process.
 */
export type PendingAsk = {
    kind: 'approval';
    /** The OpenCode permission request id — also the tool-call id the decision is signalled under. */
    id: string;
    action: string;
    approver: string;
    expiresAt?: string;
    /** The assistant message the call hangs on (absent for a request recovered after a restart). */
    messageId?: string;
} | {
    kind: 'form';
    id: string;
    form: OpenCodeForm;
    request: ElicitationRequest;
    messageId?: string;
};
/**
 * What a turn spent. `inputTokens` is the whole input side, cached input included (as the library's
 * `MessageUsage` counts it — OpenCode's own `tokens.input` leaves the cache out); `cacheReadTokens`,
 * `cacheWriteTokens` and `reasoningTokens` are subsets. `costUsd` sums every priced call; `steps`
 * counts the model steps.
 */
export interface OpenCodeUsage {
    inputTokens: number;
    outputTokens: number;
    cacheReadTokens: number;
    cacheWriteTokens: number;
    reasoningTokens: number;
    costUsd: number;
    steps: number;
}
export declare function emptyUsage(): OpenCodeUsage;
/** `a + b`; a missing side (a milestone journaled before usage travelled) counts as nothing. */
export declare function addUsage(a: OpenCodeUsage | undefined, b: Partial<OpenCodeUsage> | undefined): OpenCodeUsage;
/** The model a step ran on, as OpenCode names it (`session.step.started`). */
export interface StepModel {
    providerID: string;
    id: string;
}
/** What a model call cost, and where the figure came from. */
export interface StepCost {
    costUsd?: number;
    costSource?: CostSource;
}
/**
 * Where a turn stands: it needs a person, or it is over. `usage` is what the turn spent since its
 * previous milestone — journaled with the milestone, so a run resumed in another process still adds
 * up what every process saw.
 */
export type Milestone = {
    kind: 'ask';
    ask: PendingAsk;
    timeoutMs?: number;
    usage?: OpenCodeUsage;
} | {
    kind: 'finished';
    outcome: TurnOutcome;
    usage?: OpenCodeUsage;
};
export interface OpenCodeTurnArgs {
    runId: string;
    input: AgentRunInput;
    client: OpenCodeClient;
    sessionId: string;
    writer: SinkWriter;
    store: AgentStore;
    /** What an action needs before it runs (the agent's `ApprovalPolicy`). */
    approvalFor: (action: string) => Promise<ApprovalRequirement>;
    /**
     * The app tool a permission `action` names, with its presentation: its `confirm` templates (filled
     * from the call's arguments) word the approval card. `undefined` (or omitted) → an OpenCode
     * built-in, worded from its name.
     */
    approvalPresentation?: (action: string) => {
        name: string;
        presentation?: ToolPresentation;
    } | undefined;
    /** The model label usage is recorded under until OpenCode names the step's model. */
    modelLabel: string;
    /**
     * What a model call cost: OpenCode's reported figure, or the library's estimate. Omit → OpenCode's
     * figure as reported.
     */
    priceStep?: (step: {
        model: StepModel | undefined;
        usage: MessageUsage;
        reportedCostUsd: number | undefined;
    }) => Promise<StepCost>;
    /** What the run spent before this turn object existed (an earlier process, an earlier session). */
    carried?: OpenCodeUsage;
    /**
     * An action OpenCode was allowed to run — by a person, a remembered approval or the policy. The
     * engine's MCP endpoint runs an `action` tool only against one of these.
     */
    onGranted?: (action: string, permissionId: string) => void;
}
/**
 * One turn of an OpenCode session, as the library's stream and store see it. Fed the session's
 * events in order, it writes the protocol's frames and persists what the loop would have — the
 * assistant messages with their tool calls and results, the calls put to a person (so the
 * approve/answer routes find their run), usage per model step — and reports {@link Milestone}s: a
 * person was asked something, or the execution ended.
 *
 * The turn does not wait for people itself. Whoever drives it (`OpenCodeTurns`, under an in-memory
 * or a durable runner) takes the `ask` milestone, waits however it waits, and hands the answer back
 * with {@link decide} — which is what lets a durable run wait across a restart and reply from
 * another process, with a fresh turn object fed the journaled {@link PendingAsk}.
 */
export declare class OpenCodeTurn {
    private readonly a;
    /** Serializes the handling of events, so frames and rows land in the order OpenCode sent them. */
    private chain;
    private segment;
    private readonly tools;
    /** Results already persisted per message, so a late settlement adds to them rather than replacing. */
    private readonly messageResults;
    private readonly asked;
    /** Calls of {@link HIDDEN_TOOLS}, by id. */
    private readonly hidden;
    private readonly milestones;
    private waiting;
    /** What this turn object saw spent, and how much of it a milestone already reported. */
    private spent;
    private reported;
    private priced;
    private model;
    /** What the session had spent when this turn prompted it; what OpenCode reported since. */
    private baseline;
    private readonly seen;
    private compacted;
    private stepOpen;
    private sawText;
    private separator;
    private reasoningSince;
    private wroteMessage;
    private ended;
    private stepError;
    constructor(a: OpenCodeTurnArgs);
    /**
     * What the session had spent before this turn prompted it (`session.get`). When the execution
     * ends, what the session spent since that this turn's events did not report — the title OpenCode
     * generates, a compaction: OpenCode records those calls on the session without streaming them — is
     * recorded as a usage row of its own.
     */
    setBaseline(info: {
        cost?: number;
        tokens?: OpenCodeTokens;
    } | undefined): void;
    /** What the run spent so far: carried from before this turn object, plus what it saw. */
    totalUsage(): OpenCodeUsage;
    get sessionId(): string;
    get finished(): boolean;
    /** The run's totals so far (see {@link totalUsage}): tokens, cost, model steps. */
    totals(): {
        inputTokens: number;
        outputTokens: number;
        costUsd?: number;
        steps: number;
    };
    private isPriced;
    /** Feed one of the session's events. */
    handle(event: OpenCodeEvent): void;
    /** End the turn as failed without an event (the prompt was refused, the stream is gone). */
    fail(error: string): void;
    /**
     * A component a tool pushed (`ctx.emitUi`, through the engine's MCP endpoint): streamed as a `ui`
     * frame and persisted on the message being written, in the order it arrived. Pushing the same id
     * again replaces it.
     */
    pushUi(component: AgentUiComponent): Promise<void>;
    /** The next milestone: one already reached, or the next one to come. */
    next(): Promise<Milestone>;
    /** Whether a milestone is waiting to be taken. */
    hasMilestone(): boolean;
    /**
     * Requests OpenCode raised while nobody listened (this process started after them, or the event
     * stream dropped): its open permissions and forms, handled as if their events had just arrived.
     * One already recorded in the store is reported without being recorded or streamed again.
     */
    catchUp(): Promise<void>;
    /**
     * Hand a person's answer to what the turn asked, and let OpenCode go on. `tellOpenCode: false`
     * only settles the call (stream and store): the request died with a restarted server, and the
     * new session is told the answer in its prompt instead.
     */
    decide(ask: PendingAsk, reply: HumanReply, opts?: {
        tellOpenCode?: boolean;
    }): Promise<void>;
    private reach;
    private enqueue;
    private write;
    private event;
    private step;
    private endReasoning;
    private tool;
    private announce;
    private makeAvailable;
    private setInput;
    /** Code-mode calls made inside a tool (`metadata.toolCalls`), nested under it by `parentId`. */
    private innerCalls;
    private onEvent;
    private settleTool;
    private modelId;
    /** One model call's usage and cost, into the ledger and the run's total. */
    private spend;
    private stepEnded;
    /** The run's usage as its last message carries it: the whole run, cache tokens included. */
    private messageUsage;
    /**
     * Persist what the turn produced since the last flush as one assistant message — the message a
     * call put to a person hangs on, or the turn's last one. Returns its id.
     */
    private flush;
    /** A request recorded by an earlier process (a turn resumed after a restart). */
    private alreadyRecorded;
    /** The persisted assistant message carrying call `id`, so its result lands on the same message. */
    private messageOf;
    private onPermission;
    private decided;
    private onForm;
    private answered;
    private addResult;
    /** What the session spent since the baseline that no event of this turn reported. */
    private unreported;
    private end;
}
/**
 * OpenCode's token counts as the library's `MessageUsage`. OpenCode reports the uncached input in
 * `input` and the cache reads and writes beside it; the library counts the whole input side in
 * `inputTokens`, the cache counts being subsets of it.
 */
export declare function usageOf(tokens: any): MessageUsage;
//# sourceMappingURL=turn.d.ts.map