{"version":3,"sources":["../../src/stt/fallback_adapter.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { APIConnectionError, APIError } from '../_exceptions.js';\nimport { log } from '../log.js';\nimport type { STTMetrics } from '../metrics/base.js';\nimport { type APIConnectOptions, DEFAULT_API_CONNECT_OPTIONS } from '../types.js';\nimport { Task, cancelAndWait } from '../utils.js';\nimport type { VAD } from '../vad.js';\nimport type { ConversationItemAddedEvent } from '../voice/events.js';\nimport { StreamAdapter } from './stream_adapter.js';\nimport {\n  STT,\n  type STTCallbacks,\n  type STTError,\n  type SpeechEvent,\n  SpeechEventType,\n  SpeechStream,\n} from './stt.js';\n\n/**\n * Internal status tracking for each STT instance.\n * @internal\n */\ninterface STTStatus {\n  available: boolean;\n  recoveringRecognizeTask: Task<void> | null;\n  recoveringStreamTask: Task<void> | null;\n  waitingStreams: Set<FallbackSpeechStream>;\n  recoveryClosed: boolean;\n}\n\n/**\n * Options for creating a {@link FallbackAdapter}.\n */\nexport interface FallbackAdapterOptions {\n  /** List of STT instances to use for fallback (in priority order). At least one is required. */\n  sttInstances: STT[];\n  /**\n   * VAD used to auto-wrap non-streaming STTs with {@link StreamAdapter}. Required\n   * when any of the supplied STT instances does not support streaming.\n   */\n  vad?: VAD;\n  /** Per-attempt timeout in milliseconds. Defaults to 10000. */\n  attemptTimeoutMs?: number;\n  /** Number of internal retries per STT instance before moving to the next one. Defaults to 1. */\n  maxRetryPerSTT?: number;\n  /** Delay in milliseconds between internal retries. Defaults to 5000. */\n  retryIntervalMs?: number;\n}\n\n/**\n * Event emitted when an STT instance's availability changes.\n */\nexport interface AvailabilityChangedEvent {\n  /** The STT instance whose availability changed. */\n  stt: STT;\n  /** Whether the STT instance is now available. */\n  available: boolean;\n}\n\nconst DEFAULT_FALLBACK_API_CONNECT_OPTIONS: APIConnectOptions = {\n  maxRetry: 0,\n  timeoutMs: DEFAULT_API_CONNECT_OPTIONS.timeoutMs,\n  retryIntervalMs: DEFAULT_API_CONNECT_OPTIONS.retryIntervalMs,\n};\n\n/**\n * Agent Fallback Adapter for STT. Manages multiple STT instances with automatic\n * fallback when the primary provider fails.\n *\n * When the primary STT fails, the adapter switches to the next available\n * provider in the list for the active session. Failed providers are monitored\n * by one probe stream per provider. The probe receives its owner's live audio;\n * another waiting stream takes over if the owner closes. A non-empty\n * FINAL_TRANSCRIPT marks the provider available again.\n * If every provider is unavailable, normal streams retry them in priority order.\n *\n * Non-streaming STTs are automatically wrapped with {@link StreamAdapter}\n * provided a `vad` is passed in.\n *\n * @example\n * ```typescript\n * import { FallbackAdapter } from '@livekit/agents';\n * import { STT as DeepgramSTT } from '@livekit/agents-plugin-deepgram';\n * import { STT as AssemblyAISTT } from '@livekit/agents-plugin-assemblyai';\n *\n * const fallbackSTT = new FallbackAdapter({\n *   sttInstances: [\n *     new AssemblyAISTT(),  // Primary\n *     new DeepgramSTT(),    // Fallback\n *   ],\n * });\n * ```\n */\nexport class FallbackAdapter extends STT {\n  readonly sttInstances: STT[];\n  readonly attemptTimeoutMs: number;\n  readonly maxRetryPerSTT: number;\n  readonly retryIntervalMs: number;\n\n  private _status: STTStatus[] = [];\n  private _logger = log();\n  private _metricsForwarders = new Map<STT, (m: STTMetrics) => void>();\n  // Last child that produced output or returned a recognize result. Surfaced\n  // via the dynamic label/model/provider getters so OTel attributes like\n  // `gen_ai.request.model` on `user_turn` (refreshed on every STT event by\n  // {@link audio_recognition.refreshUserTurnSttAttributes}) reflect the\n  // actual provider used, not the wrapper. Not safe to share an adapter\n  // across concurrent sessions/streams — concurrent writers would corrupt\n  // attribution.\n  private _activeStt: STT | undefined;\n\n  label = 'stt.FallbackAdapter';\n\n  constructor(opts: FallbackAdapterOptions) {\n    if (!opts.sttInstances || opts.sttInstances.length < 1) {\n      throw new Error('at least one STT instance must be provided.');\n    }\n\n    const nonStreaming = opts.sttInstances.filter((s) => !s.capabilities.streaming);\n    if (nonStreaming.length > 0 && !opts.vad) {\n      const labels = nonStreaming.map((s) => s.label).join(', ');\n      throw new Error(\n        `STTs do not support streaming: ${labels}. ` +\n          'Provide a vad to enable stt.StreamAdapter automatically ' +\n          'or wrap them with stt.StreamAdapter before using this adapter.',\n      );\n    }\n\n    const wrapped = opts.sttInstances.map((s) =>\n      s.capabilities.streaming ? s : new StreamAdapter(s, opts.vad!),\n    );\n\n    // Pick the primary's granularity only if every instance supports aligned\n    // transcripts — otherwise consumers can't rely on a consistent format.\n    let alignedTranscript: 'word' | 'chunk' | false = false;\n    if (wrapped.every((s) => !!s.capabilities.alignedTranscript)) {\n      alignedTranscript = wrapped[0]!.capabilities.alignedTranscript ?? false;\n    }\n\n    super({\n      streaming: true,\n      interimResults: wrapped.every((s) => s.capabilities.interimResults),\n      diarization: wrapped.every((s) => !!s.capabilities.diarization),\n      alignedTranscript,\n      keyterms: wrapped.some((s) => !!s.capabilities.keyterms),\n      chatContext: wrapped.some((s) => !!s.capabilities.chatContext),\n    });\n\n    this.sttInstances = wrapped;\n    this.attemptTimeoutMs = opts.attemptTimeoutMs ?? 10_000;\n    this.maxRetryPerSTT = opts.maxRetryPerSTT ?? 1;\n    this.retryIntervalMs = opts.retryIntervalMs ?? 5_000;\n\n    this._status = this.sttInstances.map(() => ({\n      available: true,\n      recoveringRecognizeTask: null,\n      recoveringStreamTask: null,\n      waitingStreams: new Set<FallbackSpeechStream>(),\n      recoveryClosed: false,\n    }));\n\n    this.setupEventForwarding();\n  }\n\n  // Reflect the active child's model/provider so OTel `gen_ai.request.model`\n  // and `gen_ai.provider.name` on `user_turn` spans identify the provider\n  // that actually transcribed, not the static wrapper. `audio_recognition.\n  // refreshUserTurnSttAttributes` re-reads these on every STT event, so a\n  // mid-turn fallover surfaces the new child immediately.\n  override get model(): string {\n    return this._activeStt?.model ?? 'FallbackAdapter';\n  }\n\n  override get provider(): string {\n    return this._activeStt?.provider ?? 'livekit';\n  }\n\n  /**\n   * Record the child that most recently produced output. Called by\n   * `_recognize()` on a successful return and by the streaming path on\n   * every event yielded by the elected child.\n   * @internal\n   */\n  _setActiveStt(stt: STT): void {\n    this._activeStt = stt;\n  }\n\n  /**\n   * Returns the current status of all STT instances, including availability\n   * and background recovery state.\n   */\n  get status(): STTStatus[] {\n    return this._status;\n  }\n\n  override _updateSessionKeyterms(keyterms: string[]): void {\n    // forward to every underlying STT; unsupported ones warn-and-skip internally\n    for (const sttInstance of this.sttInstances) {\n      sttInstance._updateSessionKeyterms(keyterms);\n    }\n  }\n\n  override _pushConversationItem(ev: ConversationItemAddedEvent): void {\n    // forward to every underlying STT; unsupported ones warn-and-skip internally\n    for (const sttInstance of this.sttInstances) {\n      sttInstance._pushConversationItem(ev);\n    }\n  }\n\n  private setupEventForwarding(): void {\n    // We intentionally do NOT forward child 'error' events. The adapter's job\n    // is to mask transient child failures via fallback — surfacing them to\n    // consumers (e.g. AgentSession, which treats any unrecoverable stt_error\n    // as a reason to close the session) would defeat the point. Terminal\n    // errors still reach the session via the adapter's own run()/recognize()\n    // throwing APIConnectionError once every child has failed — the base\n    // SpeechStream.mainTask emits that on this STT instance naturally.\n    for (const s of this.sttInstances) {\n      const metricsForwarder = (metrics: STTMetrics) => this.emit('metrics_collected', metrics);\n      this._metricsForwarders.set(s, metricsForwarder);\n      s.on('metrics_collected', metricsForwarder);\n    }\n  }\n\n  emitAvailabilityChanged(stt: STT, available: boolean): void {\n    const event: AvailabilityChangedEvent = { stt, available };\n    (this as unknown as NodeJS.EventEmitter).emit('stt_availability_changed', event);\n  }\n\n  private tryRecoverRecognize(stt: STT, frame: Parameters<STT['recognize']>[0]): void {\n    const idx = this.sttInstances.indexOf(stt);\n    const status = this._status[idx];\n    if (!status || status.recoveryClosed) return;\n    if (status.recoveringRecognizeTask && !status.recoveringRecognizeTask.done) return;\n\n    const task = Task.from(async (controller) => {\n      try {\n        await stt.recognize(frame, controller.signal);\n        if (controller.signal.aborted || status.recoveryClosed) return;\n        status.available = true;\n        this._logger.info({ stt: stt.label }, 'STT recovered');\n        this.emitAvailabilityChanged(stt, true);\n      } catch (e) {\n        if (controller.signal.aborted || status.recoveryClosed) return;\n        if (e instanceof APIError) {\n          this._logger.warn(\n            { stt: stt.label, errorType: e instanceof Error ? e.constructor.name : typeof e },\n            'STT recovery failed',\n          );\n        } else {\n          this._logger.debug(\n            { stt: stt.label, errorType: e instanceof Error ? e.constructor.name : typeof e },\n            'STT recovery failed',\n          );\n        }\n      }\n    });\n    status.recoveringRecognizeTask = task;\n    task.addDoneCallback(() => {\n      if (status.recoveringRecognizeTask === task) status.recoveringRecognizeTask = null;\n    });\n  }\n\n  // Skip the base class's `metrics_collected` emit: the active child's own\n  // `recognize()` already emits metrics, and those are forwarded onto the\n  // adapter by `setupEventForwarding`. Without this override, consumers see\n  // each RECOGNITION_USAGE event twice and `audioDurationMs` is double-counted.\n  // Mirrors the streaming path's `monitorMetrics` override.\n  override async recognize(\n    frame: Parameters<STT['recognize']>[0],\n    abortSignal?: AbortSignal,\n  ): Promise<SpeechEvent> {\n    return this._recognize(frame, abortSignal);\n  }\n\n  protected async _recognize(\n    frame: Parameters<STT['recognize']>[0],\n    abortSignal?: AbortSignal,\n  ): Promise<SpeechEvent> {\n    const startTime = Date.now();\n    const allFailed = this._status.every((s) => !s.available);\n    if (allFailed) {\n      this._logger.error('all STTs are unavailable, retrying..');\n    }\n\n    for (let i = 0; i < this.sttInstances.length; i++) {\n      const stt = this.sttInstances[i]!;\n      const status = this._status[i]!;\n      if (status.available || allFailed) {\n        try {\n          const result = await stt.recognize(frame, abortSignal);\n          this._setActiveStt(stt);\n          return result;\n        } catch (e) {\n          this._logger.warn(\n            { stt: stt.label, errorType: e instanceof Error ? e.constructor.name : typeof e },\n            'STT failed, switching to next provider',\n          );\n          if (status.available) {\n            status.available = false;\n            this.emitAvailabilityChanged(stt, false);\n          }\n        }\n      }\n      this.tryRecoverRecognize(stt, frame);\n    }\n\n    const labels = this.sttInstances.map((s) => s.label).join(', ');\n    throw new APIConnectionError({\n      message: `all STTs failed (${labels}) after ${Date.now() - startTime}ms`,\n    });\n  }\n\n  stream(options?: { connOptions?: APIConnectOptions }): SpeechStream {\n    return new FallbackSpeechStream(\n      this,\n      options?.connOptions ?? DEFAULT_FALLBACK_API_CONNECT_OPTIONS,\n    );\n  }\n\n  override async close(): Promise<void> {\n    const tasks: Task<void>[] = [];\n    for (const status of this._status) {\n      status.recoveryClosed = true;\n      status.waitingStreams.clear();\n      if (status.recoveringRecognizeTask && !status.recoveringRecognizeTask.done) {\n        tasks.push(status.recoveringRecognizeTask);\n      }\n      if (status.recoveringStreamTask) tasks.push(status.recoveringStreamTask);\n    }\n    if (tasks.length > 0) {\n      await cancelAndWait(tasks, 1000);\n    }\n    for (const s of this.sttInstances) {\n      const m = this._metricsForwarders.get(s);\n      if (m) s.off('metrics_collected' as keyof STTCallbacks, m);\n    }\n    this._metricsForwarders.clear();\n  }\n}\n\nclass FallbackSpeechStream extends SpeechStream {\n  label = 'stt.FallbackSpeechStream';\n  private fallbackAdapter: FallbackAdapter;\n  private recoveringStreams = new Map<SpeechStream, Task<void>>();\n  private inputEnded = false;\n  private _logger = log();\n\n  constructor(adapter: FallbackAdapter, connOptions: APIConnectOptions) {\n    super(adapter, undefined, connOptions);\n    this.fallbackAdapter = adapter;\n  }\n\n  // Skip `metrics_collected` emission in the adapter stream — children's\n  // metrics are already forwarded to the adapter via `_metricsForwarders`.\n  // Without this override we double-count every RECOGNITION_USAGE event.\n  protected override async monitorMetrics(): Promise<void> {\n    for await (const event of this.queue) {\n      if (!this.output.closed) {\n        try {\n          this.output.put(event);\n        } catch {\n          /* queue closed during disconnect — expected */\n        }\n      }\n    }\n    if (!this.output.closed) this.output.close();\n  }\n\n  private tryRecoverStream(sttInstance: STT): boolean {\n    if (this.abortSignal.aborted) return false;\n    const idx = this.fallbackAdapter.sttInstances.indexOf(sttInstance);\n    const status = this.fallbackAdapter.status[idx];\n    if (!status || status.available || status.recoveryClosed) return false;\n    if (status.recoveringStreamTask && !status.recoveringStreamTask.done) {\n      status.waitingStreams.add(this);\n      return false;\n    }\n    status.waitingStreams.delete(this);\n\n    let probe: SpeechStream;\n    try {\n      probe = sttInstance.stream({\n        connOptions: {\n          maxRetry: 0,\n          timeoutMs: this.fallbackAdapter.attemptTimeoutMs,\n          retryIntervalMs: this.fallbackAdapter.retryIntervalMs,\n        },\n      });\n    } catch (error) {\n      this._logger.warn(\n        {\n          stt: sttInstance.label,\n          errorType: error instanceof Error ? error.constructor.name : typeof error,\n        },\n        'STT recovery failed',\n      );\n      return false;\n    }\n    const closeProbe = () => {\n      try {\n        probe.close();\n      } catch {\n        /* already closed */\n      }\n    };\n    if (this.abortSignal.aborted || status.recoveryClosed) {\n      closeProbe();\n      return false;\n    }\n\n    // Absorb provider error events; each probe records its own terminal outcome.\n    const errorSink: (e: STTError) => void = () => {};\n    sttInstance.on('error', errorSink);\n\n    const task = Task.from(async (controller) => {\n      controller.signal.addEventListener('abort', closeProbe, { once: true });\n      try {\n        let recovered = false;\n        for await (const ev of probe) {\n          if (controller.signal.aborted || this.abortSignal.aborted) break;\n          if (ev.type === SpeechEventType.FINAL_TRANSCRIPT) {\n            const text = ev.alternatives?.[0]?.text;\n            if (!text) continue;\n            recovered = true;\n            break;\n          }\n        }\n        if (\n          !recovered ||\n          controller.signal.aborted ||\n          this.abortSignal.aborted ||\n          status.recoveryClosed\n        )\n          return;\n        if (!status.available) {\n          status.available = true;\n          this._logger.info({ stt: sttInstance.label }, 'STT recovered');\n          this.fallbackAdapter.emitAvailabilityChanged(sttInstance, true);\n        }\n      } catch (e) {\n        if (controller.signal.aborted || this.abortSignal.aborted) return;\n        if (e instanceof APIError) {\n          this._logger.warn(\n            {\n              stt: sttInstance.label,\n              errorType: e instanceof Error ? e.constructor.name : typeof e,\n            },\n            'STT recovery failed',\n          );\n        } else {\n          this._logger.debug(\n            {\n              stt: sttInstance.label,\n              errorType: e instanceof Error ? e.constructor.name : typeof e,\n            },\n            'STT recovery failed',\n          );\n        }\n      } finally {\n        controller.signal.removeEventListener('abort', closeProbe);\n        sttInstance.off('error', errorSink);\n        closeProbe();\n      }\n    });\n    this.recoveringStreams.set(probe, task);\n    status.recoveringStreamTask = task;\n    task.addDoneCallback(() => {\n      this.recoveringStreams.delete(probe);\n      if (status.recoveringStreamTask !== task) return;\n      status.recoveringStreamTask = null;\n      if (status.available || status.recoveryClosed) {\n        status.waitingStreams.clear();\n        return;\n      }\n      for (const stream of status.waitingStreams) {\n        status.waitingStreams.delete(stream);\n        if (stream.tryRecoverStream(sttInstance)) break;\n      }\n    });\n    if (this.inputEnded) {\n      try {\n        probe.endInput();\n      } catch {\n        closeProbe();\n      }\n    }\n    return true;\n  }\n\n  protected async run(): Promise<void> {\n    if (this.abortSignal.aborted) return;\n    const startTime = Date.now();\n    const allFailed = this.fallbackAdapter.status.every((s) => !s.available);\n    if (allFailed) {\n      this._logger.error('all STTs are unavailable, retrying..');\n    }\n\n    // A single forwarder drains this.input and replicates each frame to the\n    // currently-elected main stream (mutable via `mainStream` ref) and every\n    // parallel probe stream. Fires once; closes main on input EOF.\n    // Box mutable refs so the async IIFE closure doesn't narrow the variable\n    // type to `never` based on its initial value. TS's control-flow analysis\n    // for closures can't always see that outer code reassigns the var.\n    const mainRef: { current: SpeechStream | null } = { current: null };\n    // Forwarder runs as a Task so we can cancel+await it on terminal failure.\n    const forwarderTask = Task.from(async (controller) => {\n      for await (const item of this.input) {\n        if (controller.signal.aborted || this.abortSignal.aborted) break;\n        for (const probe of this.recoveringStreams.keys()) {\n          try {\n            if (typeof item === 'symbol') probe.flush();\n            else probe.pushFrame(item);\n          } catch {\n            // probe closed — next tick will prune it via its own task\n          }\n        }\n        const current = mainRef.current;\n        if (current !== null) {\n          try {\n            if (typeof item === 'symbol') current.flush();\n            else current.pushFrame(item);\n          } catch (e) {\n            this._logger.debug(\n              { errorType: e instanceof Error ? e.constructor.name : typeof e },\n              'error forwarding input to main stream',\n            );\n          }\n        }\n      }\n      this.inputEnded = true;\n      for (const endTarget of [mainRef.current, ...this.recoveringStreams.keys()]) {\n        try {\n          endTarget?.endInput();\n        } catch {\n          /* already ended */\n        }\n      }\n    });\n\n    const closeStreams = () => {\n      for (const status of this.fallbackAdapter.status) status.waitingStreams.delete(this);\n      for (const task of this.recoveringStreams.values()) {\n        task.cancel();\n      }\n      for (const stream of [mainRef.current, ...this.recoveringStreams.keys()]) {\n        try {\n          stream?.close();\n        } catch {\n          // Continue closing the remaining streams if a provider throws.\n        }\n      }\n    };\n\n    this.abortSignal.addEventListener('abort', closeStreams, { once: true });\n    try {\n      for (let i = 0; i < this.fallbackAdapter.sttInstances.length; i++) {\n        if (this.abortSignal.aborted) return;\n        const sttInstance = this.fallbackAdapter.sttInstances[i]!;\n        const status = this.fallbackAdapter.status[i]!;\n        if (!status.available && !allFailed) {\n          this.tryRecoverStream(sttInstance);\n          continue;\n        }\n\n        // Absorb provider errors here; the child records its own terminal outcome.\n        const errListener = () => {};\n        sttInstance.on('error', errListener);\n\n        try {\n          const child = sttInstance.stream({\n            connOptions: {\n              maxRetry: this.fallbackAdapter.maxRetryPerSTT,\n              timeoutMs: this.fallbackAdapter.attemptTimeoutMs,\n              retryIntervalMs: this.fallbackAdapter.retryIntervalMs,\n            },\n          });\n          // Keep child timestamps anchored to the parent stream's current retry attempt.\n          child.startTimeOffset = this.startTimeOffset + (Date.now() - startTime) / 1000;\n          mainRef.current = child;\n          try {\n            if (this.abortSignal.aborted) return;\n            // If the forwarder has already drained and exited (input EOF), it\n            // will never call endInput() on this child. End it here so the\n            // child's `for await (input)` loop can terminate cleanly instead\n            // of hanging forever.\n            if (this.inputEnded) {\n              try {\n                child.endInput();\n              } catch {\n                /* already ended */\n              }\n            }\n\n            for await (const ev of child) {\n              // The parent can close while a child has a transcript in flight.\n              // Stop cleanly instead of treating the closed queue as a provider failure.\n              if (this.abortSignal.aborted || this.queue.closed) {\n                return;\n              }\n              this.fallbackAdapter._setActiveStt(sttInstance);\n              this.queue.put(ev);\n            }\n          } finally {\n            child.close();\n          }\n\n          if (this.abortSignal.aborted || (!child._failed && this.inputEnded)) {\n            return;\n          }\n          if (status.available) {\n            status.available = false;\n            this.fallbackAdapter.emitAvailabilityChanged(sttInstance, false);\n          }\n          this._logger.warn({ stt: sttInstance.label }, 'STT failed, switching to next provider');\n        } catch (e) {\n          if (this.abortSignal.aborted) return;\n          this._logger.warn(\n            {\n              stt: sttInstance.label,\n              errorType: e instanceof Error ? e.constructor.name : typeof e,\n            },\n            'STT failed, switching to next provider',\n          );\n          if (status.available) {\n            status.available = false;\n            this.fallbackAdapter.emitAvailabilityChanged(sttInstance, false);\n          }\n        } finally {\n          sttInstance.off('error', errListener);\n          mainRef.current = null;\n        }\n\n        this.tryRecoverStream(sttInstance);\n      }\n\n      if (this.abortSignal.aborted) return;\n      const labels = this.fallbackAdapter.sttInstances.map((s) => s.label).join(', ');\n      throw new APIConnectionError({\n        message: `all STTs failed (${labels}) after ${Date.now() - startTime}ms`,\n      });\n    } finally {\n      this.abortSignal.removeEventListener('abort', closeStreams);\n      if (!this.input.closed) this.input.close();\n      const tasks = [forwarderTask, ...this.recoveringStreams.values()];\n      closeStreams();\n      await cancelAndWait(tasks, 1000);\n    }\n  }\n}\n"],"mappings":"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","names":[]}