import type { AudioFrame } from '@livekit/rtc-node';
import { EventEmitter } from 'node:events';
import type { ReadableStream } from 'node:stream/web';
import type { ChatContext } from '../llm/chat_context.js';
import type { ChatChunk } from '../llm/llm.js';
import type { ToolContext } from '../llm/tool_context.js';
import { MultiInputStream } from '../stream/multi_input_stream.js';
import type { SpeechEvent } from '../stt/stt.js';
import type { FlushSentinel } from '../types.js';
import type { ModelSettings } from './agent.js';
export type STTNode = (audio: ReadableStream<AudioFrame>, modelSettings: ModelSettings) => Promise<ReadableStream<SpeechEvent | string> | null>;
export type LLMNode = (chatCtx: ChatContext, toolCtx: ToolContext, modelSettings: ModelSettings) => Promise<ReadableStream<ChatChunk | string | FlushSentinel> | null>;
export type TTSNode = (text: ReadableStream<string>, modelSettings: ModelSettings) => Promise<ReadableStream<AudioFrame> | null>;
/**
 * Symbol used to identify TimedString objects.
 */
export declare const TIMED_STRING_SYMBOL: unique symbol;
/**
 * A string with optional start and end timestamps for word-level alignment.
 */
export interface TimedString {
    readonly [TIMED_STRING_SYMBOL]: true;
    text: string;
    startTime?: number;
    endTime?: number;
    confidence?: number;
    startTimeOffset?: number;
    speakerId?: string | null;
}
/**
 * Factory function to create a TimedString object.
 */
export declare function createTimedString(opts: {
    text: string;
    startTime?: number;
    endTime?: number;
    confidence?: number;
    startTimeOffset?: number;
    speakerId?: string | null;
}): TimedString;
/**
 * Type guard to check if a value is a TimedString.
 */
export declare function isTimedString(value: unknown): value is TimedString;
export interface AudioOutputCapabilities {
    /** Whether this output supports pause/resume functionality */
    pause: boolean;
}
export declare abstract class AudioInput {
    protected multiStream: MultiInputStream<AudioFrame>;
    get stream(): ReadableStream<AudioFrame>;
    close(): Promise<void>;
    onAttached(): void;
    onDetached(): void;
}
export declare abstract class AudioOutput extends EventEmitter {
    sampleRate?: number | undefined;
    protected readonly nextInChain?: AudioOutput | undefined;
    static readonly EVENT_PLAYBACK_STARTED = "playbackStarted";
    static readonly EVENT_PLAYBACK_FINISHED = "playbackFinished";
    private playbackFinishedFuture;
    private _capturing;
    private playbackFinishedCount;
    private playbackSegmentsCount;
    private lastPlaybackEvent;
    protected logger: import("pino").Logger;
    protected readonly capabilities: AudioOutputCapabilities;
    constructor(sampleRate?: number | undefined, nextInChain?: AudioOutput | undefined, capabilities?: AudioOutputCapabilities);
    /**
     * Whether this output and all outputs in the chain support pause/resume.
     */
    get canPause(): boolean;
    /**
     * Capture an audio frame for playback, frames can be pushed faster than real-time
     */
    captureFrame(_frame: AudioFrame): Promise<void>;
    /**
     * Wait for the past audio segments to finish playing out.
     *
     * @returns The event that was emitted when the audio finished playing out (only the last segment information)
     */
    waitForPlayout(): Promise<PlaybackFinishedEvent>;
    /**
     * Playback segments captured but not yet finished. Used by chained outputs to detect and
     * reconcile a segment-count drift against the next output in the chain.
     * @internal
     */
    get pendingPlayoutSegments(): number;
    /**
     * Called when playback actually starts (first frame is sent to output).
     * Developers building audio sinks should call this when the first frame is captured.
     */
    onPlaybackStarted(createdAt: number): void;
    /**
     * Developers building audio sinks must call this method when a playback/segment is finished.
     * Segments are segmented by calls to flush() or clearBuffer()
     */
    onPlaybackFinished(options: PlaybackFinishedEvent): void;
    flush(): void;
    /**
     * Clear the buffer, stopping playback immediately
     */
    abstract clearBuffer(): void;
    onAttached(): void;
    onDetached(): void;
    /**
     * Pause the audio playback
     */
    pause(): void;
    /**
     * Resume the audio playback
     */
    resume(): void;
}
export interface PlaybackFinishedEvent {
    /** How much of the audio was played back, in seconds */
    playbackPosition: number;
    /** True if playback was interrupted (clearBuffer() was called) */
    interrupted: boolean;
    /**
     * Transcript synced with playback; may be partial if the audio was interrupted.
     * When undefined, the transcript is not synchronized with the playback.
     */
    synchronizedTranscript?: string;
}
export interface PlaybackStartedEvent {
    /** The timestamp (Date.now()) when the playback started */
    createdAt: number;
}
export declare abstract class TextOutput {
    protected readonly nextInChain?: TextOutput | undefined;
    constructor(nextInChain?: TextOutput | undefined);
    abstract captureText(text: string | TimedString): Promise<void>;
    /**
     * Mark the current text segment as complete (e.g LLM generation is complete)
     */
    abstract flush(): void;
    onAttached(): void;
    onDetached(): void;
}
export declare class AgentInput {
    private readonly audioChanged;
    private _audioStream;
    private _audioEnabled;
    constructor(audioChanged: () => void);
    setAudioEnabled(enable: boolean): void;
    get audioEnabled(): boolean;
    get audio(): AudioInput | null;
    set audio(stream: AudioInput | null);
}
export declare class AgentOutput {
    private readonly audioChanged;
    private readonly transcriptionChanged;
    private _audioSink;
    private _transcriptionSink;
    private _audioEnabled;
    private _transcriptionEnabled;
    constructor(audioChanged: () => void, transcriptionChanged: () => void);
    setAudioEnabled(enabled: boolean): void;
    setTranscriptionEnabled(enabled: boolean): void;
    get audioEnabled(): boolean;
    get transcriptionEnabled(): boolean;
    get audio(): AudioOutput | null;
    set audio(sink: AudioOutput | null);
    get transcription(): TextOutput | null;
    set transcription(sink: TextOutput | null);
}
//# sourceMappingURL=io.d.ts.map