import { Model, ModelRequest, ModelResponse, ModelRetryAdvice, ModelRetryAdviceRequest } from '../model';
import type { AssistantMessageItem, FunctionCallItem, StreamEvent } from '../types/protocol';
/**
 * A complete normalized response or an output-only shorthand.
 *
 * Output-only responses count as one model request and receive a deterministic
 * response ID. Automatic streaming also assigns a deterministic response ID
 * when a complete response omits one because the normalized terminal stream
 * event requires an ID.
 */
export type ScriptedModelResponse = ModelResponse | ModelResponse['output'];
export type RecordedModelCall = Readonly<{
    /** The zero-based position of this model call in `calls`. */
    index: number;
    /** Whether the runner requested a streamed response. */
    streamed: boolean;
    /**
     * A frozen request snapshot with detached mutable input collections and
     * model settings. Runtime object identities such as the abort signal remain
     * unchanged.
     */
    request: Readonly<ModelRequest>;
}>;
export type ScriptedModelRetryAdvice = ModelRetryAdvice | ((request: ModelRetryAdviceRequest) => ModelRetryAdvice | undefined | Promise<ModelRetryAdvice | undefined>);
type ScriptedModelResponseStep = {
    type: 'response';
    response: ScriptedModelResponse;
};
type ScriptedModelErrorStep = {
    type: 'error';
    error: unknown;
    retryAdvice?: ScriptedModelRetryAdvice;
};
type ScriptedModelResponderStep = {
    type: 'responder';
    respond: (call: RecordedModelCall) => ScriptedModelResponse | Promise<ScriptedModelResponse>;
};
export type ScriptedModelStream = Iterable<StreamEvent> | AsyncIterable<StreamEvent>;
type ScriptedModelStreamStep = {
    type: 'stream';
    events: ScriptedModelStream;
};
type ScriptedModelStreamResponderStep = {
    type: 'stream_responder';
    respond: (call: RecordedModelCall) => ScriptedModelStream | Promise<ScriptedModelStream>;
};
type ScriptedModelStep = ScriptedModelResponseStep | ScriptedModelErrorStep | ScriptedModelResponderStep | ScriptedModelStreamStep | ScriptedModelStreamResponderStep;
export type ScriptedModelInput = ScriptedModelStep | ScriptedModelResponse;
export type AssistantMessageOptions = {
    id?: string;
    phase?: AssistantMessageItem['phase'];
    providerData?: Record<string, unknown>;
};
export type FunctionCallOptions = {
    callId: string;
    id?: string;
    namespace?: string;
    providerData?: Record<string, unknown>;
};
export type InvalidScriptedModelStepReason = 'invalid_input' | 'unknown_step_type' | 'missing_response' | 'invalid_response' | 'missing_error' | 'missing_responder' | 'invalid_stream' | 'incompatible_call';
export declare class UnexpectedModelCallError extends Error {
    /** The zero-based position of the call in `ScriptedModel.calls`. */
    readonly callIndex: number;
    readonly streamed: boolean;
    constructor(call: RecordedModelCall);
}
export declare class UnconsumedModelStepsError extends Error {
    readonly remainingSteps: number;
    constructor(remainingSteps: number);
}
export declare class InvalidScriptedModelStepError extends Error {
    readonly reason: InvalidScriptedModelStepReason;
    /** The zero-based position of an invalid constructor or `enqueue()` input. */
    readonly inputIndex?: number;
    /** The zero-based position of a call in `ScriptedModel.calls`. */
    readonly callIndex?: number;
    readonly stepType?: string;
    constructor(options: {
        reason: InvalidScriptedModelStepReason;
        message: string;
        inputIndex?: number;
        callIndex?: number;
        stepType?: string;
    });
}
export declare class ScriptedModelRequestAbortedError extends Error {
    /** The zero-based position of a call in `ScriptedModel.calls`. */
    readonly callIndex?: number;
    constructor(callIndex?: number);
}
/** Creates a scripted normalized model response step. */
export declare function modelResponse(response: ScriptedModelResponse): ScriptedModelResponseStep;
/** Creates a scripted model failure step. */
export declare function modelError(error: unknown, retryAdvice?: ScriptedModelRetryAdvice): ScriptedModelErrorStep;
/** Creates a response step that derives its output from the recorded call. */
export declare function modelResponder(respond: ScriptedModelResponderStep['respond']): ScriptedModelResponderStep;
/** Creates a raw normalized stream step. */
export declare function modelStream(events: ScriptedModelStreamStep['events']): ScriptedModelStreamStep;
/** Creates a raw normalized stream derived from the recorded call. */
export declare function modelStreamResponder(respond: ScriptedModelStreamResponderStep['respond']): ScriptedModelStreamResponderStep;
/** Creates a normalized assistant text message. */
export declare function assistantMessage(text: string, options?: AssistantMessageOptions): AssistantMessageItem;
/** Creates a normalized function call item. */
export declare function functionCall(name: string, args: string | Record<string, unknown>, options: FunctionCallOptions): FunctionCallItem;
/**
 * A deterministic model test double that consumes one scripted step per call.
 */
export declare class ScriptedModel implements Model {
    #private;
    constructor(inputs?: Iterable<ScriptedModelInput>);
    /** All calls recorded by this model in invocation order. */
    get calls(): readonly RecordedModelCall[];
    /** The first recorded call, if one has occurred. */
    get firstCall(): RecordedModelCall | undefined;
    /** The most recent recorded call, if one has occurred. */
    get lastCall(): RecordedModelCall | undefined;
    /** The number of scripted steps that have not been consumed. */
    get remainingSteps(): number;
    /** Adds steps to the end of the script. */
    enqueue(...inputs: ScriptedModelInput[]): void;
    /** Throws when the script still contains unconsumed steps. */
    assertComplete(): void;
    getResponse(request: ModelRequest): Promise<ModelResponse>;
    getStreamedResponse(request: ModelRequest): AsyncIterable<StreamEvent>;
    getRetryAdvice(request: ModelRetryAdviceRequest): Promise<ModelRetryAdvice | undefined>;
}
export {};
