/**
 * Reusable fake STT for exercising the STT pipeline in tests without talking
 * to a real provider. Ported from the Python harness at
 * `livekit-agents/tests/fake_stt.py` so JS tests can achieve the same
 * coverage shape (scripted failures, mid-test behaviour flips, timed interim
 * + final transcript emission).
 */
import type { AudioFrame } from '@livekit/rtc-node';
import type { APIConnectOptions } from '../../types.js';
import { AsyncIterableQueue, type AudioBuffer } from '../../utils.js';
import { STT, type STTCapabilities, type SpeechEvent, SpeechStream } from '../stt.js';
/**
 * Describes a scheduled speech turn. `startTime`/`endTime`/`sttDelay` are in
 * milliseconds and keyed to the moment the first audio frame is pushed into
 * the stream — not wall-clock. `sttDelay` is the provider's transcription
 * lag; the stream emits an interim result halfway through and a final result
 * at `endTime + sttDelay`.
 *
 * Python uses seconds here — multiply Python fixtures by 1000 when porting.
 */
export interface FakeUserSpeech {
    startTime: number;
    endTime: number;
    transcript: string;
    sttDelay: number;
    final?: boolean;
}
/** Scale every timing field by `factor` — useful for speeding up tests. */
export declare function speedUpFakeUserSpeech(speech: FakeUserSpeech, factor: number): FakeUserSpeech;
/** Marker posted to {@link FakeSTT.recognizeCh} each time `recognize()` runs. */
export declare class RecognizeSentinel {
}
export interface FakeSTTOptions {
    label?: string;
    fakeException?: Error | null;
    fakeTranscript?: string | null;
    fakeTimeoutMs?: number | null;
    fakeUserSpeeches?: FakeUserSpeech[] | null;
    fakeRequireAudio?: boolean;
    capabilities?: Partial<STTCapabilities>;
}
type UpdateOptions = Partial<Pick<FakeSTTOptions, 'fakeException' | 'fakeTranscript' | 'fakeTimeoutMs'>>;
/**
 * Configurable stand-in for a real {@link STT}. Knobs mirror Python's
 * `FakeSTT`: inject exceptions, scripted transcripts, connection timeouts,
 * or a full sequence of {@link FakeUserSpeech} turns.
 *
 * Observability: every call to `recognize()` posts to {@link recognizeCh}
 * and every call to `stream()` posts the new stream to {@link streamCh}, so
 * tests can assert on attempt counts directly instead of inferring them.
 *
 * @example
 * ```ts
 * const primary = new FakeSTT({ fakeException: new APIConnectionError('down') });
 * const fallback = new FakeSTT({ fakeTranscript: 'hello world' });
 * const adapter = new FallbackAdapter({ sttInstances: [primary, fallback] });
 * const ev = await adapter.recognize(frame);
 * assert(ev.alternatives[0].text === 'hello world');
 * assert((await primary.recognizeCh.next()).value instanceof RecognizeSentinel);
 * ```
 */
export declare class FakeSTT extends STT {
    label: string;
    private _fakeException;
    private _fakeTranscript;
    private _fakeTimeoutMs;
    private _fakeUserSpeeches;
    private _fakeRequireAudio;
    private _recognizeCh;
    private _streamCh;
    private _fakeUserSpeechesDone;
    private _resolveFakeUserSpeechesDone;
    constructor(opts?: FakeSTTOptions);
    /** Replace one or more fake knobs mid-test (e.g. flip from error to success). */
    updateOptions(opts: UpdateOptions): void;
    /** Channel: one sentinel per `recognize()` invocation. */
    get recognizeCh(): AsyncIterableQueue<RecognizeSentinel>;
    /** Channel: one stream instance per `stream()` invocation. */
    get streamCh(): AsyncIterableQueue<FakeRecognizeStream>;
    get fakeUserSpeeches(): FakeUserSpeech[] | null;
    /** Resolves once the scheduled `fake_user_speeches` have all been emitted. */
    get fakeUserSpeechesDone(): Promise<void>;
    /** @internal Read-only state snapshot for the stream to consult. */
    get _state(): Readonly<{
        fakeException: Error | null;
        fakeTranscript: string | null;
        fakeTimeoutMs: number | null;
        fakeUserSpeeches: FakeUserSpeech[] | null;
        fakeRequireAudio: boolean;
    }>;
    /** @internal Called from the stream once it has finished the scheduled speeches. */
    _markFakeUserSpeechesDone(): void;
    protected _recognize(_frame: AudioBuffer): Promise<SpeechEvent>;
    recognize(frame: AudioBuffer, abortSignal?: AbortSignal): Promise<SpeechEvent>;
    stream(options?: {
        connOptions?: APIConnectOptions;
    }): FakeRecognizeStream;
}
/**
 * Stream returned by {@link FakeSTT.stream}. Exposes an `attempt` counter and
 * `sendFakeTranscript()` so tests can inject interim/final events at will.
 */
export declare class FakeRecognizeStream extends SpeechStream {
    label: string;
    private _attempt;
    private _fakeStt;
    constructor(stt: FakeSTT, connOptions?: APIConnectOptions);
    get attempt(): number;
    /** Push a synthetic INTERIM or FINAL event onto the output queue. */
    sendFakeTranscript(transcript: string, isFinal?: boolean): void;
    protected run(): Promise<void>;
    private fakeUserSpeechTask;
}
/** Convenience: a zero-length audio frame suitable for `recognize()` calls. */
export declare function emptyAudioFrame(): AudioBuffer;
export type { AudioFrame };
//# sourceMappingURL=fake_stt.d.ts.map