import { type JsonObject } from '@bufbuild/protobuf';
import { AgentSession as pb } from '@livekit/protocol';
import type { AudioFrame, Room } from '@livekit/rtc-node';
import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
import type { Context, Span } from '@opentelemetry/api';
import type { ReadableStream } from 'node:stream/web';
import type { z } from 'zod';
import type { BaseStreamingTurnDetector } from '../inference/eot/base.js';
import { type LLMModels, type STTModelString, type TTSModelString } from '../inference/index.js';
import type { OverlappingSpeechEvent } from '../inference/interruption/types.js';
import type { FunctionCall, FunctionCallOutput } from '../llm/chat_context.js';
import { AgentHandoffItem, ChatContext, ChatMessage, type Instructions } from '../llm/chat_context.js';
import type { LLM, RealtimeModel, RealtimeModelError, ToolChoice } from '../llm/index.js';
import type { LLMError } from '../llm/llm.js';
import { type ModelUsage, ModelUsageCollector } from '../metrics/model_usage.js';
import type { STT } from '../stt/index.js';
import type { STTError } from '../stt/stt.js';
import type { TTS, TTSError } from '../tts/tts.js';
import { type ResolvedSessionConnectOptions, type SessionConnectOptions } from '../types.js';
import { Task } from '../utils.js';
import type { VAD } from '../vad.js';
import type { Agent } from './agent.js';
import { AgentActivity } from './agent_activity.js';
import type { AMD, AMDPredictionEvent } from './amd.js';
import type { _TurnDetector } from './audio_recognition.js';
import { type AgentEvent, type AgentFalseInterruptionEvent, AgentSessionEventTypes, type AgentState, type AgentStateChangedEvent, type CloseEvent, type ConversationItemAddedEvent, type EotPredictionEvent, type ErrorEvent, type FunctionToolsExecutedEvent, type MetricsCollectedEvent, type SessionUsageUpdatedEvent, type ShutdownReason, type SpeechCreatedEvent, type UserInputTranscribedEvent, type UserState, type UserStateChangedEvent } from './events.js';
import { AgentInput, AgentOutput } from './io.js';
import { RecorderIO } from './recorder_io/index.js';
import { RoomIO, type RoomInputOptions, type RoomOutputOptions } from './room_io/index.js';
import type { UnknownUserData } from './run_context.js';
import type { SpeechHandle } from './speech_handle.js';
import { RunResult } from './testing/run_result.js';
import type { TextTransform } from './transcription/text_transforms.js';
import type { EndpointingOptions } from './turn_config/endpointing.js';
import type { InternalTurnHandlingOptions, TurnHandlingOptions } from './turn_config/turn_handling.js';
export interface AgentSessionUsage {
    /** List of usage summaries, one per model/provider combination. */
    modelUsage: Array<Partial<ModelUsage>>;
}
/**
 * Granular control over which recording features are active.
 *
 * All keys default to `true` when omitted, so `{ logs: false }` means "record
 * everything except logs". Pass to {@link AgentSession.start} as `record`:
 *
 * - `record: true` — all on (backward compatible)
 * - `record: false` — all off (backward compatible)
 * - `record: { audio: true, traces: false }` — granular
 */
export interface RecordingOptions {
    /** Record session audio. Defaults to `true`. */
    audio?: boolean;
    /** Export OpenTelemetry trace spans. Defaults to `true`. */
    traces?: boolean;
    /** Export OpenTelemetry logs. Defaults to `true`. */
    logs?: boolean;
    /** Upload the conversation transcript (chat history). Defaults to `true`. */
    transcript?: boolean;
}
/** @internal Recording options with every category resolved to a boolean. */
export type ResolvedRecordingOptions = Required<RecordingOptions>;
/**
 * Resolve a `record` argument into explicit per-category flags. A boolean turns
 * every category on or off; a partial object is merged onto all-on so omitted
 * keys default to `true`.
 *
 * @internal
 */
export declare function resolveRecordingOptions(record: boolean | RecordingOptions): ResolvedRecordingOptions;
export interface InternalSessionOptions<UserData> extends AgentSessionOptions<UserData> {
    turnHandling: InternalTurnHandlingOptions;
    useTtsAlignedTranscript: boolean;
    maxToolSteps: number;
    userAwayTimeout: number | null;
    ttsReadIdleTimeout: number;
    forwardAudioIdleTimeout: number;
    ttsTextTransforms: readonly TextTransform[] | null;
}
export declare const defaultAgentSessionOptions: {
    readonly maxToolSteps: 3;
    readonly userAwayTimeout: 15;
    readonly aecWarmupDuration: 3000;
    readonly ttsReadIdleTimeout: 10000;
    readonly forwardAudioIdleTimeout: 10000;
    readonly turnHandling: {};
    readonly useTtsAlignedTranscript: true;
    readonly ttsTextTransforms: readonly ["filter_markdown", "filter_emoji"];
};
/** @deprecated {@link VoiceOptions} has been flattened onto to {@link AgentSessionOptions} */
export type VoiceOptions = {
    maxToolSteps: number;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.preemptiveGeneration instead. */
    preemptiveGeneration?: boolean;
    userAwayTimeout?: number | null;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.interruption.mode instead. */
    allowInterruptions?: boolean;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.interruption.discardAudioIfUninterruptible instead. */
    discardAudioIfUninterruptible?: boolean;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.interruption.minDuration instead. */
    minInterruptionDuration?: number;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.interruption.minWords instead. */
    minInterruptionWords?: number;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.endpointing.minDelay instead. */
    minEndpointingDelay?: number;
    /** @deprecated Use {@link AgentSessionOptions.turnHandling}.endpointing.maxDelay instead. */
    maxEndpointingDelay?: number;
};
export type TurnDetectionMode = 'stt' | 'vad' | 'realtime_llm' | 'manual' | _TurnDetector | BaseStreamingTurnDetector;
export type AgentSessionCallbacks = {
    [AgentSessionEventTypes.UserInputTranscribed]: (ev: UserInputTranscribedEvent) => void;
    [AgentSessionEventTypes.AgentStateChanged]: (ev: AgentStateChangedEvent) => void;
    [AgentSessionEventTypes.UserStateChanged]: (ev: UserStateChangedEvent) => void;
    [AgentSessionEventTypes.ConversationItemAdded]: (ev: ConversationItemAddedEvent) => void;
    [AgentSessionEventTypes.FunctionToolsExecuted]: (ev: FunctionToolsExecutedEvent) => void;
    [AgentSessionEventTypes.MetricsCollected]: (ev: MetricsCollectedEvent) => void;
    [AgentSessionEventTypes.SessionUsageUpdated]: (ev: SessionUsageUpdatedEvent) => void;
    [AgentSessionEventTypes.DebugMessage]: (ev: pb.DebugMessage) => void;
    [AgentSessionEventTypes.SpeechCreated]: (ev: SpeechCreatedEvent) => void;
    [AgentSessionEventTypes.AgentFalseInterruption]: (ev: AgentFalseInterruptionEvent) => void;
    [AgentSessionEventTypes.Error]: (ev: ErrorEvent) => void;
    [AgentSessionEventTypes.Close]: (ev: CloseEvent) => void;
    [AgentSessionEventTypes.OverlappingSpeech]: (ev: OverlappingSpeechEvent) => void;
    [AgentSessionEventTypes.EotPrediction]: (ev: EotPredictionEvent) => void;
};
export type AgentSessionOptions<UserData = UnknownUserData> = {
    stt?: STT | STTModelString;
    /**
     * Voice Activity Detection. When omitted, `AgentSession` auto-provisions a
     * bundled `inference.VAD({ model: 'silero' })` and marks it as the default
     * (so sites that check whether the user supplied a VAD treat the bundled
     * one as absent). Pass `null` to opt out entirely.
     */
    vad?: VAD | null;
    llm?: LLM | RealtimeModel | LLMModels;
    tts?: TTS | TTSModelString;
    userData?: UserData;
    connOptions?: SessionConnectOptions;
    /** @deprecated use turnHandling.turnDetection instead */
    turnDetection?: TurnDetectionMode;
    /** @deprecated use top-level SessionOptions fields instead */
    voiceOptions?: Partial<VoiceOptions>;
    maxToolSteps?: number;
    /**
     * @deprecated Use `turnHandling.preemptiveGeneration` instead.
     * When set, migrated into `turnHandling.preemptiveGeneration.enabled`.
     */
    preemptiveGeneration?: boolean;
    /**
     * If set, set the user state as "away" after this amount of time after user and agent are
     * silent. Set to `null` to disable.
     * @defaultValue 15.0
     */
    userAwayTimeout?: number | null;
    /**
     * Duration in milliseconds for AEC (Acoustic Echo Cancellation) warmup, during which
     * interruptions from audio activity are suppressed. Set to `null` to disable.
     * @defaultValue 3000
     */
    aecWarmupDuration?: number | null;
    /**
     * Maximum time in milliseconds to wait for the next frame on the TTS audio stream
     * inside `performTTSInference`. Applies to every read, including the first.
     * If exceeded, the TTS stream is forcibly closed and a stall warning is logged.
     * @defaultValue 10000
     */
    ttsReadIdleTimeout?: number;
    /**
     * Maximum time in milliseconds to wait for the next frame while forwarding TTS
     * audio to the audio output inside `performAudioForwarding`. Applies to every read,
     * including the first. If exceeded, forwarding is forcibly closed and a stall
     * warning is logged.
     * @defaultValue 10000
     */
    forwardAudioIdleTimeout?: number;
    /**
     * Configuration for turn handling.
     */
    turnHandling?: Partial<TurnHandlingOptions>;
    useTtsAlignedTranscript?: boolean;
    /**
     * Transforms to apply to TTS input text. Built-in transforms are `filter_markdown`
     * and `filter_emoji`; pass `null` to disable text transforms.
     */
    ttsTextTransforms?: readonly TextTransform[] | null;
};
export type AgentSessionUpdateOptions = {
    /** Configuration updates for turn handling. */
    turnHandling?: {
        /**
         * Strategy for deciding when the user has finished speaking.
         *
         * - `undefined`: leave the current turn detection setting unchanged.
         * - `null`: clear the current turn detection setting and return to automatic selection.
         * - `TurnDetectionMode`: set the turn detection strategy to the provided value.
         */
        turnDetection?: TurnDetectionMode | null;
        /** Endpointing options to merge into the current session defaults. */
        endpointing?: Partial<EndpointingOptions>;
    };
    /**
     * @deprecated use turnHandling.turnDetection instead.
     *
     * - `undefined`: leave the current turn detection setting unchanged.
     * - `null`: clear the current turn detection setting and return to automatic selection.
     * - `TurnDetectionMode`: set the turn detection strategy to the provided value.
     */
    turnDetection?: TurnDetectionMode | null;
};
type ActivityTransitionOptions = {
    previousActivity?: 'close' | 'pause';
    newActivity?: 'start' | 'resume';
    blockedTasks?: Task<any>[];
    waitOnEnter?: boolean;
};
declare const AgentSession_base: new () => TypedEmitter<AgentSessionCallbacks>;
export declare class AgentSession<UserData = UnknownUserData> extends AgentSession_base {
    vad?: VAD;
    stt?: STT;
    llm?: LLM | RealtimeModel;
    tts?: TTS;
    turnDetection?: TurnDetectionMode;
    /** @deprecated use {@link sessionOptions } instead */
    readonly options: VoiceOptions;
    readonly sessionOptions: InternalSessionOptions<UserData>;
    private readonly activityLock;
    private agent?;
    private activity?;
    private nextActivity?;
    private updateActivityTask?;
    private started;
    private sessionHost?;
    private _chatCtx;
    private _userData;
    private _userState;
    private _agentState;
    private _input;
    private _output;
    private closing;
    private closingTask;
    private userAwayTimer;
    private _aecWarmupTimer;
    private _connOptions;
    private llmErrorCounts;
    private ttsErrorCounts;
    private sessionSpan?;
    private agentSpeakingSpan?;
    private _interruptionDetection?;
    /**
     * True iff this session auto-provisioned the bundled silero VAD because the
     * caller passed no `vad=`. Set once in the constructor; immutable from then
     * on. Read it via `AgentActivity.usingDefaultVad` from voice-pipeline code.
     *
     * @internal
     */
    _usingDefaultVad: boolean;
    /** @internal */
    _usageCollector: ModelUsageCollector;
    /** @internal */
    _roomIO?: RoomIO;
    /**
     * Currently active AMD instance, if one was constructed against this session.
     * Mirrors python `AgentSession._amd`. Useful for tests, telemetry, and
     * higher-level helpers that need to introspect classification state.
     */
    private _amd;
    /** @internal */
    _aecWarmupRemaining: number;
    /** @internal */
    _recorderIO?: RecorderIO;
    /** @internal */
    rootSpanContext?: Context;
    /** @internal */
    _recordedEvents: AgentEvent[];
    /** @internal Resolved per-category recording options for this session. */
    _recordingOptions: ResolvedRecordingOptions;
    /** @internal True when any recording category is enabled. */
    get _enableRecording(): boolean;
    /** @internal - Timestamp when the session started (milliseconds) */
    _startedAt?: number;
    /** @internal - Whether `start()` has been called and completed. */
    get _started(): boolean;
    /** @internal - Whether the session is closing/draining. */
    get _closing(): boolean;
    /** @internal - Current run state for testing */
    _globalRunState?: RunResult;
    /** @internal */
    _userSpeakingSpan?: Span;
    private logger;
    constructor(options?: AgentSessionOptions<UserData>);
    emit<K extends keyof AgentSessionCallbacks>(event: K, ...args: Parameters<AgentSessionCallbacks[K]>): boolean;
    get input(): AgentInput;
    get output(): AgentOutput;
    get userData(): UserData;
    get history(): ChatContext;
    /** Connection options for STT, LLM, and TTS. */
    get connOptions(): ResolvedSessionConnectOptions;
    get interruptionDetection(): "vad" | "adaptive" | undefined;
    /**
     * Returns usage summaries for this session, one per model/provider combination.
     */
    get usage(): AgentSessionUsage;
    get useTtsAlignedTranscript(): boolean;
    set userData(value: UserData);
    private _startImpl;
    start({ agent, room, inputOptions, outputOptions, record, }: {
        agent: Agent;
        room?: Room;
        inputOptions?: Partial<RoomInputOptions>;
        outputOptions?: Partial<RoomOutputOptions>;
        record?: boolean | RecordingOptions;
    }): Promise<void>;
    updateAgent(agent: Agent): void;
    commitUserTurn(): void;
    clearUserTurn(): void;
    say(text: string | ReadableStream<string>, options?: {
        audio?: ReadableStream<AudioFrame>;
        allowInterruptions?: boolean;
        addToChatCtx?: boolean;
    }): SpeechHandle;
    interrupt(options?: {
        force?: boolean;
    }): import("../utils.js").Future<void, Error>;
    /** @internal — emit a debug/trace payload to the debugger/recorder. */
    _emitDebugMessage(payload: JsonObject): void;
    /**
     * The currently bound `AMD` instance, or `null` if AMD is not in use.
     * Mirrors python `AgentSession.amd`.
     */
    get amd(): AMD | null;
    /** @internal — used by AMD to register/unregister itself with the session. */
    _setAmd(amd: AMD | null): void;
    /**
     * The currently running activity, or `undefined` when none is active. Mirrors
     * python `session._activity` — exposed so tightly-coupled internals (e.g. AMD)
     * can read activity state such as the endpointing delay.
     * @internal
     */
    get _activity(): AgentActivity | undefined;
    /**
     * @internal — forwarded to {@link SessionHost} so a connected
     * {@link RemoteSession} peer receives an `amd_prediction` event when AMD
     * settles. Mirrors python `AgentSession._session_host._on_amd_prediction`.
     */
    _onAmdPrediction(event: AMDPredictionEvent): void;
    /**
     * @internal — returns a tee'd branch of the active participant audio stream
     * for AMD's dedicated STT. Returns `undefined` when no `AgentActivity` is
     * running yet (the AMD STT pump retries until an activity is available).
     */
    _subscribeAudioStream(): ReadableStream<AudioFrame> | undefined;
    pauseReplyAuthorization(): void;
    resumeReplyAuthorization(): void;
    updateOptions(options: AgentSessionUpdateOptions): void;
    generateReply(options?: {
        userInput?: string | ChatMessage;
        chatCtx?: ChatContext;
        instructions?: string | Instructions;
        toolChoice?: ToolChoice;
        allowInterruptions?: boolean;
        /** The input modality used for generating the reply. Defaults to `"text"`. */
        inputModality?: 'audio' | 'text';
    }): SpeechHandle;
    /**
     * Run a test with user input and return a result for assertions.
     *
     * This method is primarily used for testing agent behavior without
     * requiring a real room connection.
     *
     * @example
     * ```typescript
     * const result = await session.run({ userInput: 'Hello' });
     * result.expect.nextEvent().isMessage({ role: 'assistant' });
     * result.expect.noMoreEvents();
     * ```
     *
     * @param options - Run options including user input and optional output type
     * @returns A RunResult that resolves when the agent finishes responding
     */
    run<T = unknown>({ userInput, inputModality, outputType, }: {
        userInput: string;
        inputModality?: 'audio' | 'text';
        outputType?: z.ZodType<T>;
    }): RunResult<T>;
    /** @internal */
    _updateActivity(agent: Agent, options?: ActivityTransitionOptions): Promise<void>;
    get chatCtx(): ChatContext;
    get agentState(): AgentState;
    get userState(): UserState;
    get currentAgent(): Agent;
    close(): Promise<void>;
    shutdown(options?: {
        drain?: boolean;
        reason?: ShutdownReason;
    }): void;
    /** @internal */
    _closeSoon({ reason, drain, error, }: {
        reason: ShutdownReason;
        drain?: boolean;
        error?: RealtimeModelError | STTError | TTSError | LLMError | null;
    }): void;
    /** @internal */
    _onError(error: RealtimeModelError | STTError | TTSError | LLMError): void;
    /** @internal */
    _conversationItemAdded(item: ChatMessage | AgentHandoffItem): void;
    /** @internal */
    _toolItemsAdded(items: (FunctionCall | FunctionCallOutput)[]): void;
    /** @internal */
    _updateAgentState(state: AgentState, options?: {
        startTime?: number;
        otelContext?: Context;
    }): void;
    /** @internal */
    _updateUserState(state: UserState, options?: {
        lastSpeakingTime?: number;
        otelContext?: Context;
    }): void;
    private onAudioInputChanged;
    private onAudioOutputChanged;
    private onTextOutputChanged;
    private _setUserAwayTimer;
    private _cancelUserAwayTimer;
    /** @internal */
    _onAecWarmupExpired(): void;
    private _onUserInputTranscribed;
    private closeImpl;
    private closeImplInner;
}
export {};
//# sourceMappingURL=agent_session.d.ts.map