import type { Context } from '@opentelemetry/api';
import type { ChatItem } from '../llm/index.js';
import type { Task } from '../utils.js';
/** Symbol used to identify SpeechHandle instances */
declare const SPEECH_HANDLE_SYMBOL: unique symbol;
/**
 * How long a cooperatively cancelled task may take to unwind after its abort signal fires.
 *
 * Has no python counterpart: there a cancelled task takes `CancelledError` at its next await point,
 * so `utils.aio.cancel_and_wait` needs no ceiling at all. Nothing here can cancel a pending
 * promise, so tasks are aborted cooperatively and waited on with this bound instead.
 *
 * All it bounds is how long an *aborted task body* takes to reach its own return — not how long
 * the work it started takes. The pipeline's tasks are stream pumps that re-check `signal.aborted`
 * each iteration, and `performToolExecutions` never awaits a user tool promise on this path: it
 * races the abort signal (`_waitForToolExecutionResult`), while `ToolExecutor` abandons a cancelled
 * tool outright and only *logs* if `execute()` is still running after `DRAIN_TOOL_TIMEOUT_MS`.
 * Non-cancellable tools are awaited to completion by `ToolExecutor.drain()` with no ceiling at all,
 * and the shutdown drain is a separate unbounded await that runs *after* this budget — so tool
 * cleanup is governed by the executor's own design, never by this value.
 *
 * Measured `performToolExecutions` settle latency after `abort()`: 0.04–0.33 ms across a tool that
 * observes its abort signal, a 4s tool that ignores it, a non-cancellable 4s tool, three concurrent
 * tools, and a tool body that never settles at all. The one shape that exceeds 2s is a task parked
 * on a tool-call stream that is never closed — it never settles, so no finite ceiling rescues it.
 *
 * 2s is therefore ample, and small enough that the two budgets an interrupted reply spends in
 * sequence (its task group, then its tool-execution task) still fit inside
 * {@link INTERRUPTION_TIMEOUT}; at 5s they would not.
 */
export declare const REPLY_TASK_CANCEL_TIMEOUT = 2000;
/**
 * Type guard to check if a value is a SpeechHandle.
 */
export declare function isSpeechHandle(value: unknown): value is SpeechHandle;
/**
 * Type returned by `await` on a {@link SpeechHandle}.
 *
 * Structurally identical to SpeechHandle at runtime — this alias only exists
 * to hide the `then` key from the static view. Without it, TypeScript's
 * `Awaited<T>` unwrap recurses through `SpeechHandle`'s own `.then` callback
 * parameter forever, emitting TS1062 ("Type is referenced directly or
 * indirectly in the fulfillment callback of its own 'then' method").
 * Omitting `then` terminates the unwrap because the pattern
 * `object & { then(...) }` no longer matches. In practice, calling `.then`
 * on an already-awaited handle has no meaningful use.
 *
 * @public
 */
export type ResolvedSpeechHandle = Omit<SpeechHandle, 'then'>;
/**
 * Thrown by {@link SpeechHandle.waitForPlayout} when called from inside the
 * function tool that owns this SpeechHandle. Awaiting the handle that owns the
 * currently-running tool creates a real circular wait — the handle's playout
 * cannot finish until the tool returns, but the tool is blocked waiting for
 * the playout.
 *
 * @public
 */
export declare class SpeechHandleCircularWaitError extends Error {
    constructor(functionCallName: string);
}
/**
 * Describes how the user provided input that triggered the current turn.
 * Used by modality-aware Instructions to pick the correct variant.
 *
 * @public
 */
export interface InputDetails {
    modality: 'audio' | 'text';
}
/** Default {@link InputDetails} used when no explicit value is provided. */
export declare const DEFAULT_INPUT_DETAILS: InputDetails;
/**
 * Controls and observes one agent speech turn.
 *
 * @public
 */
export declare class SpeechHandle {
    private _id;
    private _allowInterruptions;
    /** @internal */
    _stepIndex: number;
    private _inputDetails;
    readonly parent?: SpeechHandle | undefined;
    /** Priority for messages that should be played after all other messages in the queue */
    static SPEECH_PRIORITY_LOW: number;
    /** Every speech generates by the VoiceAgent defaults to this priority. */
    static SPEECH_PRIORITY_NORMAL: number;
    /** Priority for important messages that should be played before others. */
    static SPEECH_PRIORITY_HIGH: number;
    private interruptFut;
    private authorizedEvent;
    private scheduledFut;
    private doneFut;
    private generations;
    private _chatItems;
    private _error;
    private interruptionHolds;
    private interruptionHoldsRestore;
    /** @internal */
    _tasks: Task<void>[];
    /** @internal */
    _numSteps: number;
    /** @internal - OpenTelemetry context for the agent turn span */
    _agentTurnContext?: Context;
    /** @internal - used by AgentTask/RunResult final output plumbing */
    _maybeRunFinalOutput?: unknown;
    private itemAddedCallbacks;
    private doneCallbacks;
    private interruptTimeout?;
    private logger;
    /** @internal Symbol marker for type identification */
    readonly [SPEECH_HANDLE_SYMBOL] = true;
    constructor(_id: string, _allowInterruptions: boolean, 
    /** @internal */
    _stepIndex: number, _inputDetails?: InputDetails, parent?: SpeechHandle | undefined);
    static create(options?: {
        allowInterruptions?: boolean;
        stepIndex?: number;
        inputDetails?: InputDetails;
        parent?: SpeechHandle;
    }): SpeechHandle;
    get inputDetails(): InputDetails;
    get interrupted(): boolean;
    get numSteps(): number;
    get id(): string;
    get scheduled(): boolean;
    get allowInterruptions(): boolean;
    /**
     * Allow or disallow interruptions on this SpeechHandle.
     *
     * When set to false, the SpeechHandle will no longer accept any incoming
     * interruption requests until re-enabled. If the handle is already
     * interrupted, clearing interruptions is not allowed.
     *
     * @param value - true to allow interruptions, false to disallow
     * @throws Error If attempting to disable interruptions when already interrupted
     */
    set allowInterruptions(value: boolean);
    /** @internal */
    _holdInterruptions(): void;
    /** @internal */
    _releaseInterruptions(): void;
    done(): boolean;
    /**
     * Returns the error that caused this SpeechHandle to complete, if any.
     *
     * @throws Error if the SpeechHandle is not done yet.
     */
    exception(): unknown;
    get chatItems(): ChatItem[];
    /**
     * Interrupt the current speech generation.
     *
     * @throws Error If this speech handle is still running and does not allow interruptions.
     *
     * @returns The same speech handle that was interrupted.
     */
    interrupt(force?: boolean): SpeechHandle;
    /**
     * Waits for the entire assistant turn to complete playback.
     *
     * This method waits until the assistant has fully finished speaking,
     * including any finalization steps beyond initial response generation.
     * This is appropriate to call when you want to ensure the speech output
     * has entirely played out, including any tool calls and response follow-ups.
     *
     * @throws {@link SpeechHandleCircularWaitError} if called on the SpeechHandle
     * that owns the currently-running function tool — that would be a real
     * circular wait (the tool is blocked waiting for this handle, and the handle
     * cannot finish until the tool returns). Awaiting a *different* handle
     * scheduled from inside a tool (e.g.
     * `session.generateReply().waitForPlayout()`) is safe, because the main
     * speech-queue loop frees the owning handle's generation slot via
     * `_markGenerationDone()` before awaiting tool execution.
     */
    waitForPlayout(): Promise<void>;
    /**
     * Makes the SpeechHandle awaitable: `await handle` resolves to the handle
     * itself once its playout has finished.
     *
     * Implementation note: naively returning `this` from `onFulfilled` would
     * trigger infinite Promise assimilation recursion (the returned thenable
     * gets unwrapped, calling `.then()` again, forever). We side-step this by
     * shadowing `.then` with `undefined` on the instance for the duration of
     * the synchronous `Resolve(this)` call. The spec-level IsCallable check
     * reads `undefined`, fulfills the outer promise with `this` as a plain
     * value, and we restore the prototype method immediately after.
     */
    then<R1 = ResolvedSpeechHandle, R2 = never>(onFulfilled?: ((value: ResolvedSpeechHandle) => R1 | PromiseLike<R1>) | null, onRejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | null): Promise<R1 | R2>;
    waitIfNotInterrupted(aw: Promise<unknown>[]): Promise<void>;
    addDoneCallback(callback: (sh: SpeechHandle) => void): void;
    removeDoneCallback(callback: (sh: SpeechHandle) => void): void;
    /** @internal */
    _cancel(): SpeechHandle;
    /**
     * Arm the watchdog that force-cancels an interrupted speech that refuses to finish.
     *
     * Interrupting only resolves `interruptFut`; it is up to the owning reply task to notice and
     * unwind. A task parked on something the interruption itself cannot settle — most of the
     * pipeline reply's post-interrupt waits race the reply's abort signal, and nothing on the
     * ordinary interrupt path ever fires it — would otherwise never reach
     * `_markGenerationDone()`. The speech scheduling loop waits on that generation, so a single
     * stuck reply silently mutes the session for the rest of its life (#2065). Cancelling the
     * owned tasks aborts exactly the signal those waits are watching; `_markDone` then releases
     * the scheduler even if a task ignores its signal.
     *
     * Ported from python's `SpeechHandle._cancel`.
     */
    private startInterruptTimeout;
    private clearInterruptTimeout;
    /** @internal */
    get _hasGenerations(): boolean;
    /** @internal */
    _authorizeGeneration(): void;
    /** @internal */
    _clearAuthorization(): void;
    /** @internal */
    _waitForAuthorization(): Promise<void>;
    /** @internal */
    _waitForGeneration(stepIdx?: number): Promise<void>;
    /** @internal */
    _waitForScheduled(): Promise<void>;
    /** @internal */
    _markGenerationDone(): void;
    /** @internal */
    _markDone(error?: unknown): void;
    /** @internal */
    _markScheduled(): void;
    /** @internal */
    _addItemAddedCallback(callback: (item: ChatItem) => void): void;
    /** @internal */
    _removeItemAddedCallback(callback: (item: ChatItem) => void): void;
    /** @internal */
    _itemAdded(items: ChatItem[]): void;
}
export {};
//# sourceMappingURL=speech_handle.d.ts.map