import type { AudioFrame } from '@livekit/rtc-node';
import { AsyncLocalStorage } from 'node:async_hooks';
import { ReadableStream } from 'node:stream/web';
import type { Logger } from 'pino';
import { type BaseStreamingTurnDetectorStream } from '../inference/eot/base.js';
import type { OverlappingSpeechEvent } from '../inference/interruption/types.js';
import { type ChatContext, ChatMessage, type Instructions } from '../llm/chat_context.js';
import { type GenerationCreatedEvent, type InputSpeechStartedEvent, type InputSpeechStoppedEvent, type InputTranscriptionCompleted, LLM, RealtimeModel, type RealtimeSession, type ToolChoice, type ToolContext } from '../llm/index.js';
import { STT, type SpeechEvent } from '../stt/stt.js';
import { TTS } from '../tts/tts.js';
import { Future, Task } from '../utils.js';
import { VAD, type VADEvent } from '../vad.js';
import { Agent } from './agent.js';
import { type AgentSession, type TurnDetectionMode } from './agent_session.js';
import { type EndOfTurnInfo, type PreemptiveGenerationInfo, type RecognitionHooks, type STTPipeline } from './audio_recognition.js';
import type { EotPredictionEvent, UserTurnExceededEvent, _AgentBackchannelOpportunityEvent } from './events.js';
import { type InputDetails, SpeechHandle } from './speech_handle.js';
import { type EndpointingOptions } from './turn_config/endpointing.js';
export declare const agentActivityStorage: AsyncLocalStorage<AgentActivity>;
export declare const onEnterStorage: AsyncLocalStorage<OnEnterData>;
interface OnEnterData {
    session: AgentSession;
    agent: Agent;
}
export interface ReusableResources {
    sttPipeline?: STTPipeline;
    sttInputStartedAt?: number;
    rtSession?: RealtimeSession;
    turnDetectorStream?: BaseStreamingTurnDetectorStream;
}
export declare class SchedulingPausedError extends Error {
    constructor();
}
export declare function isSchedulingPausedError(error: unknown): error is SchedulingPausedError;
export declare function cleanupReusableResources(resources: ReusableResources, logger: Logger): Promise<void>;
export declare class AgentActivity implements RecognitionHooks {
    agent: Agent;
    agentSession: AgentSession;
    private static readonly REPLY_TASK_CANCEL_TIMEOUT;
    private started;
    private audioRecognition?;
    private realtimeSession?;
    private realtimeSpans?;
    private turnDetectionMode?;
    private logger;
    private _schedulingPaused;
    private newTurnsBlocked;
    private _authorizationPaused;
    private _drainBlockedTasks;
    private _currentSpeech?;
    private speechQueue;
    private q_updated;
    private speechTasks;
    private _backgroundSpeeches;
    private pendingAutoToolReplyFut?;
    private lock;
    private audioStream;
    private audioStreamId?;
    private toolChoice;
    private _preemptiveGeneration?;
    private _preemptiveGenerationCount;
    private interruptionDetector?;
    private isInterruptionDetectionEnabled;
    private isInterruptionByAudioActivityEnabled;
    private isDefaultInterruptionByAudioActivityEnabled;
    /**
     * Validated turn detection for this activity. Equals `this.turnDetection`
     * except when an `BaseStreamingTurnDetector` instance fails the runtime preconditions
     * (no VAD, or RealtimeModel with server-side turn detection enabled), in
     * which case it is downgraded to `undefined` and a warning is logged.
     */
    private _resolvedTurnDetection;
    private pausedSpeech?;
    private falseInterruptionTimer?;
    private cancelSpeechPauseTask?;
    private userTurnExceededLocked;
    private userTurnExceededTask?;
    private readonly onRealtimeGenerationCreated;
    private readonly onRealtimeInputSpeechStarted;
    private readonly onRealtimeInputSpeechStopped;
    private readonly onRealtimeInputAudioTranscriptionCompleted;
    private readonly onModelError;
    private readonly onInterruptionOverlappingSpeech;
    private readonly onInterruptionMetricsCollected;
    private readonly onInterruptionError;
    /** @internal */
    _mainTask?: Task<void>;
    _onEnterTask?: Task<void>;
    _onExitTask?: Task<void>;
    _userTurnCompletedTask?: Task<void>;
    constructor(agent: Agent, agentSession: AgentSession);
    start(options?: {
        reuseResources?: ReusableResources;
    }): Promise<void>;
    resume(options?: {
        reuseResources?: ReusableResources;
    }): Promise<void>;
    private _startSession;
    _detachReusableResources(newActivity: AgentActivity): Promise<ReusableResources>;
    get currentSpeech(): SpeechHandle | undefined;
    get vad(): VAD | undefined;
    /**
     * True iff the effective VAD for this activity is the framework-auto-provisioned
     * default. False when the user passed `vad=` to either the agent or the
     * session, even if the value happens to be the same silero model.
     */
    get usingDefaultVad(): boolean;
    get stt(): STT | undefined;
    private getSttProvider;
    get llm(): LLM | RealtimeModel | undefined;
    get tts(): TTS | undefined;
    get tools(): ToolContext;
    get schedulingPaused(): boolean;
    /** @internal */
    blockNewTurns(): void;
    pauseReplyAuthorization(): void;
    resumeReplyAuthorization(): void;
    get realtimeLLMSession(): RealtimeSession | undefined;
    get allowInterruptions(): boolean;
    get useTtsAlignedTranscript(): boolean;
    get turnDetection(): TurnDetectionMode | undefined;
    get turnHandling(): Partial<import("./turn_config/turn_handling.js").TurnHandlingOptions>;
    /**
     * Endpointing options resolved for this activity. Sparse session overrides
     * and the agent's own endpointing keys are merged, then defaults are filled
     * in based on this activity's resolved turn detector — so a streaming
     * ("audio model") detector uses the tighter streaming defaults while a
     * non-streaming agent in the same session keeps the legacy defaults.
     */
    get endpointingOpts(): EndpointingOptions;
    get maxEndpointingDelay(): number;
    get toolCtx(): ToolContext;
    /** @internal */
    get inputStartedAt(): number | undefined;
    /**
     * @internal — used by AMD to obtain a private branch of the participant
     * audio stream that does not interfere with the pipeline VAD/STT.
     */
    subscribeAudioStream(): ReadableStream<AudioFrame> | undefined;
    updateChatCtx(chatCtx: ChatContext): Promise<void>;
    updateTools(tools: ToolContext): Promise<void>;
    updateOptions(options: {
        endpointing?: EndpointingOptions;
        toolChoice?: ToolChoice | null;
        turnDetection?: TurnDetectionMode | null;
    }): void;
    attachAudioInput(audioStream: ReadableStream<AudioFrame>): void;
    private shouldDiscardInputAudio;
    detachAudioInput(): void;
    commitUserTurn(options?: {
        audioDetached?: boolean;
        throwIfNotReady?: boolean;
    }): void;
    clearUserTurn(): void;
    say(text: string | ReadableStream<string>, options?: {
        audio?: ReadableStream<AudioFrame>;
        allowInterruptions?: boolean;
        addToChatCtx?: boolean;
    }): SpeechHandle;
    private onMetricsCollected;
    private onError;
    onInputSpeechStarted(_ev: InputSpeechStartedEvent): void;
    onInputSpeechStopped(ev: InputSpeechStoppedEvent): void;
    onInputAudioTranscriptionCompleted(ev: InputTranscriptionCompleted): void;
    onGenerationCreated(ev: GenerationCreatedEvent): void;
    onStartOfSpeech(ev: VADEvent): void;
    onEndOfSpeech(ev: VADEvent): void;
    onVADInferenceDone(ev: VADEvent): void;
    private interruptByAudioActivity;
    onInterruption(ev: OverlappingSpeechEvent): void;
    onInterimTranscript(ev: SpeechEvent, speaking: boolean | undefined): void;
    onFinalTranscript(ev: SpeechEvent, speaking: boolean | undefined): void;
    /** Forward audio EOT predictions up to the session so listeners (e.g.
     * remote-session forwarders) can observe them. */
    onEotPrediction(ev: EotPredictionEvent): void;
    onAgentBackchannelOpportunity(_ev: _AgentBackchannelOpportunityEvent): void;
    onPreemptiveGeneration(info: PreemptiveGenerationInfo): void;
    onUserTurnExceeded(ev: UserTurnExceededEvent): void;
    private runUserTurnExceededTask;
    private cancelPreemptiveGeneration;
    private _interruptBackgroundSpeeches;
    private createSpeechTask;
    onEndOfTurn(info: EndOfTurnInfo): Promise<boolean>;
    retrieveChatCtx(): ChatContext;
    private waitForInactive;
    private waitForOrAbort;
    private mainTask;
    private getDrainPendingSpeechTasks;
    private wakeupMainTask;
    generateReply(options: {
        userMessage?: ChatMessage;
        chatCtx?: ChatContext;
        instructions?: string | Instructions;
        toolChoice?: ToolChoice | null;
        allowInterruptions?: boolean;
        scheduleSpeech?: boolean;
        inputDetails?: InputDetails;
    }): SpeechHandle;
    interrupt(options?: {
        force?: boolean;
    }): Future<void>;
    private onPipelineReplyDone;
    /**
     * Commit a user turn whose reply is being skipped: append the transcript to the
     * agent chat context (when non-empty) without triggering reply generation.
     * Mirrors the python `_on_user_turn_completed` `skip_reply` branch.
     */
    private commitSkippedUserTurn;
    private userTurnCompleted;
    private ttsTask;
    private _pipelineReplyTaskImpl;
    private pipelineReplyTask;
    private realtimeGenerationTask;
    private _realtimeGenerationTaskImpl;
    private summarizeToolExecutionOutput;
    private realtimeReplyTask;
    private scheduleSpeech;
    private _pauseSchedulingTask;
    private _resumeSchedulingTask;
    pause(options?: {
        blockedTasks?: Task<any>[];
        newActivity?: AgentActivity;
    }): Promise<ReusableResources | undefined>;
    drain(options?: {
        newActivity?: AgentActivity;
    }): Promise<ReusableResources | undefined>;
    private _drainImpl;
    close(): Promise<void>;
    private _resolveTurnDetection;
    private resolveInterruptionDetector;
    private updatePausedSpeech;
    private pauseEnabled;
    private startFalseInterruptionTimer;
    private cancelSpeechPause;
    /**
     * Disable VAD-based interruption either immediately or after the backchannel boundary
     * cooldown expires. While the cooldown is active the VAD path stays enabled, allowing the
     * user to correct themselves at the very start of agent speech.
     */
    private disableVadInterruptionSoon;
    private restoreInterruptionByAudioActivity;
    private fallbackToVadInterruption;
    private _closeSessionResources;
}
export {};
//# sourceMappingURL=agent_activity.d.ts.map