{"version":3,"sources":["../../src/voice/audio_recognition.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Mutex } from '@livekit/mutex';\nimport type { AudioFrame, ParticipantKind } from '@livekit/rtc-node';\nimport { ThrowsPromise } from '@livekit/throws-transformer/throws';\nimport {\n  type Context,\n  ROOT_CONTEXT,\n  type Span,\n  context as otelContext,\n  trace,\n} from '@opentelemetry/api';\nimport type { ReadableStream, WritableStreamDefaultWriter } from 'node:stream/web';\nimport { TransformStream } from 'node:stream/web';\nimport { isAPIError } from '../_exceptions.js';\nimport {\n  BaseStreamingTurnDetector,\n  BaseStreamingTurnDetectorStream,\n  MIN_SILENCE_DURATION_MS,\n  type TurnDetectionEvent,\n} from '../inference/eot/base.js';\nimport { apiConnectDefaults, intervalForRetry } from '../inference/interruption/defaults.js';\nimport { InterruptionDetectionError } from '../inference/interruption/errors.js';\nimport type { AdaptiveInterruptionDetector } from '../inference/interruption/interruption_detector.js';\nimport { InterruptionStreamSentinel } from '../inference/interruption/interruption_stream.js';\nimport {\n  type InterruptionSentinel,\n  type OverlapSpeechEnded,\n  type OverlapSpeechStarted,\n  type OverlappingSpeechEvent,\n} from '../inference/interruption/types.js';\nimport type { LanguageCode } from '../language.js';\nimport { ChatContext } from '../llm/chat_context.js';\nimport { log } from '../log.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { IdentityTransform } from '../stream/identity_transform.js';\nimport { mergeReadableStreams } from '../stream/merge_readable_streams.js';\nimport { type StreamChannel, createStreamChannel } from '../stream/stream_channel.js';\nimport { type SpeechEvent, SpeechEventType } from '../stt/stt.js';\nimport { traceTypes, tracer } from '../telemetry/index.js';\nimport { splitWords } from '../tokenize/basic/word.js';\nimport type { Future } from '../utils.js';\nimport { Task, cancelAndWait, delay, readStream, waitForAbort } from '../utils.js';\nimport { type VAD, type VADEvent, VADEventType, type VADStream } from '../vad.js';\nimport type { TurnDetectionMode } from './agent_session.js';\nimport {\n  type EotPredictionEvent,\n  type UserTurnExceededEvent,\n  type _AgentBackchannelOpportunityEvent,\n  _createAgentBackchannelOpportunityEvent,\n  createEotPredictionEvent,\n  createUserTurnExceededEvent,\n} from './events.js';\nimport type { STTNode } from './io.js';\nimport { toSnakeCaseDeep } from './report.js';\nimport {\n  type BaseEndpointing,\n  createEndpointing,\n  defaultEndpointingOptions,\n} from './turn_config/endpointing.js';\nimport type { UserTurnLimitOptions } from './turn_config/user_turn_limit.js';\nimport {\n  createSilenceFrame,\n  createSilenceFrameLike,\n  setParticipantSpanAttributes,\n} from './utils.js';\n\n// Maximum number of chat items included in the `lk.pii.chat_ctx` attribute of the\n// `eou_detection` span (mirrors Python's `_EOU_MAX_HISTORY_TURNS`).\nconst EOU_MAX_HISTORY_TURNS = 6;\nconst MIN_LANGUAGE_DETECTION_LENGTH = 5;\nconst NON_SPECIFIC_LANGUAGE_CODES = new Set(['auto', 'multi']);\n\nexport interface EndOfTurnInfo {\n  /** The new transcript text from the user's speech. */\n  newTranscript: string;\n  /** Confidence score of the transcript (0-1). */\n  transcriptConfidence: number;\n  /** Delay from speech stop to final transcription in milliseconds. */\n  transcriptionDelay: number | undefined;\n  /** Delay from speech stop to end of utterance detection in milliseconds. */\n  endOfUtteranceDelay: number | undefined;\n  /** Timestamp when user started speaking (milliseconds since epoch). */\n  startedSpeakingAt: number | undefined;\n  /** Timestamp when user stopped speaking (milliseconds since epoch). */\n  stoppedSpeakingAt: number | undefined;\n  /**\n   * When `true`, the agent activity commits the user turn to chat context but\n   * skips generating the normal auto-reply. Mirrors python `_EndOfTurnInfo.skip_reply`.\n   * Set, for example, when AMD has taken over the turn with a machine verdict and the\n   * caller drives its own `generateReply` (e.g. leaving a voicemail).\n   */\n  skipReply?: boolean;\n  /** The turn's speech overlapped agent speech and was classified a backchannel. */\n  backchannelOverAgent?: boolean;\n}\n\ntype EndOfTurnMetrics = {\n  startedSpeakingAt: number | undefined;\n  stoppedSpeakingAt: number | undefined;\n  transcriptionDelay: number | undefined;\n  endOfUtteranceDelay: number | undefined;\n};\n\nexport function _computeEndOfTurnMetrics({\n  speechStartTime,\n  lastSpeakingTime,\n  lastFinalTranscriptTime,\n  now,\n}: {\n  speechStartTime: number | undefined;\n  lastSpeakingTime: number | undefined;\n  lastFinalTranscriptTime: number;\n  now: number;\n}): EndOfTurnMetrics {\n  if (\n    lastFinalTranscriptTime === 0 ||\n    lastSpeakingTime === undefined ||\n    speechStartTime === undefined ||\n    lastSpeakingTime < speechStartTime\n  ) {\n    return {\n      startedSpeakingAt: undefined,\n      stoppedSpeakingAt: undefined,\n      transcriptionDelay: undefined,\n      endOfUtteranceDelay: undefined,\n    };\n  }\n\n  return {\n    startedSpeakingAt: speechStartTime,\n    stoppedSpeakingAt: lastSpeakingTime,\n    transcriptionDelay: Math.max(lastFinalTranscriptTime - lastSpeakingTime, 0),\n    endOfUtteranceDelay: Math.max(now - lastSpeakingTime, 0),\n  };\n}\n\nexport interface PreemptiveGenerationInfo {\n  newTranscript: string;\n  transcriptConfidence: number;\n  /** Timestamp when user started speaking (milliseconds since epoch), if known. */\n  startedSpeakingAt: number | undefined;\n}\n\nexport interface RecognitionHooks {\n  onInterruption: (ev: OverlappingSpeechEvent) => void;\n  onBackchannelConfirmed: () => void;\n  onStartOfSpeech: (ev: VADEvent) => void;\n  onVADInferenceDone: (ev: VADEvent) => void;\n  onEndOfSpeech: (ev?: VADEvent) => void;\n  onInterimTranscript: (ev: SpeechEvent, speaking: boolean | undefined) => void;\n  onFinalTranscript: (ev: SpeechEvent, speaking: boolean | undefined) => void;\n  onTranscriptionTimeout: (speechDuration: number, turnStart: number) => void;\n  onEndOfTurn: (info: EndOfTurnInfo) => Promise<boolean>;\n  onEotPrediction: (ev: EotPredictionEvent) => void;\n  onAgentBackchannelOpportunity: (ev: _AgentBackchannelOpportunityEvent) => void;\n  onPreemptiveGeneration: (info: PreemptiveGenerationInfo) => void;\n  onUserTurnExceeded: (ev: UserTurnExceededEvent) => void;\n\n  retrieveChatCtx: () => ChatContext;\n}\n\ninterface UserTurnTracker {\n  words: number;\n  transcript: string;\n  startedAt?: number;\n}\n\nexport class STTPipeline {\n  static readonly PUMP_TASK_CANCEL_TIMEOUT = 5000;\n\n  private sttNode: STTNode;\n  private _audioChannel: StreamChannel<AudioFrame> = createStreamChannel();\n  private _eventChannel: StreamChannel<SpeechEvent> = createStreamChannel();\n  private _pumpTask: Task<void>;\n  /** Wall-clock anchor for this stream, used with STT-relative timestamps. */\n  inputStartedAt?: number;\n\n  constructor(sttNode: STTNode) {\n    this.sttNode = sttNode;\n    this._pumpTask = Task.from(({ signal }) => this.sttPump(signal));\n    this._pumpTask.addDoneCallback(() => {\n      this._eventChannel.close().catch((error) => {\n        log().error(error, 'Error closing STT event channel');\n      });\n    });\n  }\n\n  get audioChannel() {\n    return this._audioChannel;\n  }\n\n  get eventChannel() {\n    return this._eventChannel;\n  }\n\n  private async sttPump(signal: AbortSignal): Promise<void> {\n    const node = await this.sttNode(this._audioChannel.stream(), {});\n    if (node === null) return;\n\n    try {\n      for await (const value of readStream(node, signal)) {\n        if (typeof value === 'string') {\n          throw new Error(`STT node must yield SpeechEvent, got: ${typeof value}`);\n        }\n        await this._eventChannel.write(value);\n      }\n    } finally {\n      await node.cancel().catch(() => {});\n    }\n  }\n\n  async close(): Promise<void> {\n    await cancelAndWait([this._pumpTask], STTPipeline.PUMP_TASK_CANCEL_TIMEOUT);\n  }\n}\n\nexport interface _TurnDetector {\n  /** The model name used by this turn detector. */\n  readonly model: string;\n  /** The provider name for this turn detector. */\n  readonly provider: string;\n  unlikelyThreshold: (language?: LanguageCode) => Promise<number | undefined>;\n  supportsLanguage: (language?: LanguageCode) => Promise<boolean>;\n  /**\n   * Text-based detectors own their inference timeout behavior internally.\n   */\n  predictEndOfTurn(chatCtx: ChatContext, timeoutMs?: number): Promise<number>;\n}\n\nexport interface AudioRecognitionOptions {\n  /** Hooks for recognition events. */\n  recognitionHooks: RecognitionHooks;\n  /** Speech-to-text node. */\n  stt?: STTNode;\n  /** Voice activity detection. */\n  vad?: VAD;\n  /** Turn detector for end-of-turn prediction. Accepts text-based detectors\n   * via `_TurnDetector` (e.g. plugins/livekit) or audio-based detectors via\n   * `TurnDetector` (e.g. `inference.TurnDetector`). */\n  turnDetector?: _TurnDetector | BaseStreamingTurnDetector;\n  /** Turn detection mode. */\n  turnDetectionMode?: TurnDetectionMode;\n  interruptionDetection?: AdaptiveInterruptionDetector;\n  /**\n   * Backchannel boundary for adaptive interruption suppression, expressed in milliseconds.\n   *\n   * A single number applies to both the start and end of agent speech; a `[start, end]` tuple\n   * configures them separately. `null` (or `undefined`) disables.\n   */\n  backchannelBoundary?: number | [number, number] | null;\n  /** Endpointing delay strategy. */\n  endpointing?: BaseEndpointing;\n  /** User turn limit configuration. */\n  userTurnLimit?: UserTurnLimitOptions;\n  /** @deprecated Use endpointing instead. */\n  minEndpointingDelay?: number;\n  /** @deprecated Use endpointing instead. */\n  maxEndpointingDelay?: number;\n  /** Root span context for tracing. */\n  rootSpanContext?: Context;\n  /** STT model name for tracing */\n  sttModel?: string;\n  /** STT provider name for tracing */\n  sttProvider?: string;\n  /** Getter for linked participant for span attribution */\n  getLinkedParticipant?: () => ParticipantLike | undefined;\n  /** Predicate used to substitute silence for STT while still forwarding real audio elsewhere. */\n  shouldDiscardAudioForStt?: (frame: AudioFrame) => boolean;\n  /** User transcription timeout in milliseconds. `null` or `undefined` disables it. */\n  transcriptionTimeout?: number | null;\n}\n\n/**\n * Minimal participant shape for span attribution.\n * Compatible with both `LocalParticipant` and `RemoteParticipant` from `@livekit/rtc-node`.\n */\nexport interface ParticipantLike {\n  sid: string | undefined;\n  identity: string;\n  kind: ParticipantKind;\n}\n\n// TODO add ability to update stt/vad/interruption-detection\nexport class AudioRecognition {\n  private hooks: RecognitionHooks;\n  private stt?: STTNode;\n  private sttPipeline?: STTPipeline;\n  private vad?: VAD;\n  private turnDetector?: _TurnDetector | BaseStreamingTurnDetector;\n  private turnDetectorStream?: BaseStreamingTurnDetectorStream;\n  /**\n   * Future for the in-flight audio-EOT inference request. Recognition owns the\n   * request lifecycle: it starts a request on the VAD silence tick, holds the\n   * future here, awaits it (with the model prediction timeout) in the eou bounce, and\n   * clears it on turn boundaries / superseding speech.\n   */\n  private turnDetectorPredictionFut?: Future<TurnDetectionEvent>;\n  /**\n   * True between a turn flush (commit / clearUserTurn) and the next VAD\n   * start-of-speech. While set, a late stt final won't start a fresh request;\n   * the eou bounce short-circuits via `onMissingEotPrediction`.\n   */\n  private turnDetectorFlushed = false;\n  /** Warn once per recognition when the eou bounce runs after a flush. */\n  private turnDetectorLatePredictionWarned = false;\n  /**\n   * The last `TurnDetectionEvent` we forwarded via `onEotPrediction`, kept\n   * by reference to dedupe: both EOU triggers in a turn read the same\n   * resolved prediction future, but the event should fire once per request.\n   */\n  private lastEmittedEotPrediction?: TurnDetectionEvent;\n  private warnedTurnDetectorPushFailure = false;\n  private turnDetectionMode?: TurnDetectionMode;\n  private endpointing: BaseEndpointing;\n  private userTurnLimit?: UserTurnLimitOptions;\n  private lastLanguage?: LanguageCode;\n  private rootSpanContext?: Context;\n  private sttModel?: string;\n  private sttProvider?: string;\n  private getLinkedParticipant?: () => ParticipantLike | undefined;\n\n  private deferredInputStream: DeferredReadableStream<AudioFrame>;\n  private logger = log();\n  private lastFinalTranscriptTime = 0;\n  private audioTranscript = '';\n  private audioInterimTranscript = '';\n  private audioPreflightTranscript = '';\n  private finalTranscriptConfidence: number[] = [];\n  private lastSpeakingTime: number | undefined;\n  private speechStartTime: number | undefined;\n  private userTurnStart: number | undefined;\n  private userTurnCommitted = false;\n  private speaking = false;\n  private activeUserSpeakingSpan?: Span;\n  private vadSpeechStarted = false;\n  private transcriptionTimeout?: number;\n  private transcriptionTimeoutTimer?: ReturnType<typeof setTimeout>;\n  private turnSpeechDuration = 0;\n  private turnTranscriptReceived = false;\n  private sampleRate?: number;\n\n  private userTurnSpan?: Span;\n  private userTurnTracker: UserTurnTracker = { words: 0, transcript: '' };\n  // Provider-known STT ids for the current user turn. Written to the\n  // `user_turn` span when it ends so we can correlate traces with the\n  // provider's logs for debugging.\n  private sttRequestIds: string[] = [];\n\n  private vadInputStream: ReadableStream<AudioFrame>;\n  private sttInputStream: ReadableStream<AudioFrame>;\n  /**\n   * Active subscriber writers fed from {@link subscribersBroadcast}. Each\n   * {@link subscribeAudioStream} call appends one entry; entries are dropped\n   * (and their stream closed) on {@link close}.\n   *\n   * The broadcast pattern replaces an earlier `tee()`-based approach where\n   * the second branch grew without bound for sessions that never called\n   * `subscribeAudioStream()` (every voice session that doesn't use AMD).\n   * With this design no extra buffering happens until at least one\n   * subscriber is registered.\n   */\n  private subscriberWriters: WritableStreamDefaultWriter<AudioFrame>[] = [];\n  private silenceAudioTransform = new IdentityTransform<AudioFrame>();\n  private silenceAudioWriter: WritableStreamDefaultWriter<AudioFrame>;\n  private sttOwnershipTransferred = false;\n  private readonly sttLifecycleLock = new Mutex();\n  private readonly vadLifecycleLock = new Mutex();\n\n  // all cancellable tasks\n  private bounceEOUTask?: Task<void>;\n  private commitUserTurnTask?: Task<void>;\n  private sttForwardTask?: Task<void>;\n  private vadTask?: Task<void>;\n  private vadStream?: VADStream;\n  private sttConsumerTask?: Task<void>;\n  private interruptionTask?: Task<void>;\n\n  // interruption detection\n  private interruptionDetection?: AdaptiveInterruptionDetector;\n  private ignoreUserTranscriptUntil?: number;\n  private transcriptBuffer: SpeechEvent[];\n  private isInterruptionEnabled: boolean;\n  private isAgentSpeaking: boolean;\n  private agentSpeechStartedAt?: number;\n  private interruptionDetected?: boolean;\n  private overlapInCurrentTurn = false;\n  private turnBackchannelOverAgent = false;\n  // An overlap is open right now, awaiting a verdict; several can occur within one turn.\n  private overlapOpen = false;\n  private interruptionStreamChannel?: StreamChannel<InterruptionSentinel | AudioFrame>;\n  private interruptionSentinelWrite: Promise<void> = Promise.resolve();\n  private closed = false;\n  private readonly closeWakeController = new AbortController();\n\n  // backchannel boundary for adaptive interruption suppression\n  private backchannelBoundary?: [number, number];\n  private backchannelBoundaryTimer?: ReturnType<typeof setTimeout>;\n  /** Callback invoked when the backchannel boundary timer expires naturally. */\n  backchannelBoundaryCallback?: () => void;\n\n  constructor(opts: AudioRecognitionOptions) {\n    this.hooks = opts.recognitionHooks;\n    this.stt = opts.stt;\n    this.vad = opts.vad;\n    this.turnDetector = opts.turnDetector;\n    this.checkVadSilenceRequirement();\n    // The FSM stream is opened on `start()` so callers can hand off the\n    // previous activity's stream (cloud↔local fallback state, in-flight\n    // inference) instead of forcing a cold restart.\n    this.turnDetectionMode = opts.turnDetectionMode;\n    this.userTurnLimit = opts.userTurnLimit;\n    this.endpointing =\n      opts.endpointing ??\n      createEndpointing({\n        ...defaultEndpointingOptions,\n        minDelay: opts.minEndpointingDelay ?? defaultEndpointingOptions.minDelay,\n        maxDelay: opts.maxEndpointingDelay ?? defaultEndpointingOptions.maxDelay,\n      });\n    this.lastLanguage = undefined;\n    this.rootSpanContext = opts.rootSpanContext;\n    this.sttModel = opts.sttModel;\n    this.sttProvider = opts.sttProvider;\n    this.getLinkedParticipant = opts.getLinkedParticipant;\n    this.transcriptionTimeout = opts.transcriptionTimeout ?? undefined;\n\n    this.deferredInputStream = new DeferredReadableStream<AudioFrame>();\n    this.interruptionDetection = opts.interruptionDetection;\n    this.transcriptBuffer = [];\n    this.isInterruptionEnabled = !!(opts.interruptionDetection && opts.vad);\n    this.isAgentSpeaking = false;\n    this.interruptionDetected = undefined;\n\n    const rawBoundary = opts.backchannelBoundary;\n    if (rawBoundary === undefined || rawBoundary === null) {\n      this.backchannelBoundary = undefined;\n    } else if (typeof rawBoundary === 'number') {\n      if (rawBoundary < 0) {\n        throw new Error('backchannelBoundary must be a non-negative number');\n      }\n      this.backchannelBoundary = [rawBoundary, rawBoundary];\n    } else {\n      const [start, end] = rawBoundary;\n      if (rawBoundary.length !== 2 || start < 0 || end < 0) {\n        throw new Error('backchannelBoundary must be a tuple of two non-negative numbers');\n      }\n      this.backchannelBoundary = [start, end];\n    }\n\n    // Pipe the deferred input stream through a broadcast transform. The\n    // transform is a no-op identity until something calls `subscribeAudioStream()`\n    // — at which point each frame is forwarded to the registered subscriber\n    // writers in addition to flowing downstream to VAD/STT. This avoids the\n    // unbounded queue growth of a pre-emptive `tee()` for sessions that\n    // never subscribe (i.e. anything not using AMD).\n    const broadcast = new TransformStream<AudioFrame, AudioFrame>(\n      {\n        transform: (chunk, controller) => {\n          controller.enqueue(chunk);\n          // Fan the same frame into the audio EOT detector stream when\n          // one is attached. The FSM accepts arbitrary-rate input and\n          // resamples internally. `pushAudio` is a no-op when the stream's\n          // internal channel is closed; any actual throw indicates a bug\n          // (e.g. resampler init failure, sample-rate mismatch). Log once\n          // when we hit that path so a regression doesn't silently drop\n          // every audio frame.\n          if (this.turnDetectorStream !== undefined) {\n            try {\n              this.turnDetectorStream.pushAudio(chunk);\n            } catch (err) {\n              if (!this.warnedTurnDetectorPushFailure) {\n                this.warnedTurnDetectorPushFailure = true;\n                this.logger.warn(\n                  { err: err instanceof Error ? err.message : String(err) },\n                  'audio EOT stream pushAudio failed; dropping frames for this turn',\n                );\n              }\n            }\n          }\n          if (this.subscriberWriters.length === 0) return;\n          for (const writer of this.subscriberWriters) {\n            writer.write(chunk).catch(() => {\n              // Subscriber stream closed or backpressure exceeded; drop.\n            });\n          }\n        },\n      },\n      { highWaterMark: Number.MAX_SAFE_INTEGER },\n      { highWaterMark: Number.MAX_SAFE_INTEGER },\n    );\n    const primaryInputStream = this.deferredInputStream.stream.pipeThrough(broadcast);\n\n    const replaceSttInputWithSilence = (stream: ReadableStream<AudioFrame>) => {\n      if (!opts.shouldDiscardAudioForStt) {\n        return stream;\n      }\n\n      return stream.pipeThrough(\n        new TransformStream<AudioFrame, AudioFrame>({\n          transform: (frame, controller) => {\n            controller.enqueue(\n              opts.shouldDiscardAudioForStt!(frame) ? createSilenceFrameLike(frame) : frame,\n            );\n          },\n        }),\n      );\n    };\n\n    if (opts.interruptionDetection) {\n      const [vadInputStream, teedInput] = primaryInputStream.tee();\n      const [inputStream, sttInputStream] = teedInput.tee();\n      this.vadInputStream = vadInputStream;\n      this.sttInputStream = mergeReadableStreams(\n        replaceSttInputWithSilence(sttInputStream),\n        this.silenceAudioTransform.readable,\n      );\n      this.interruptionStreamChannel = createStreamChannel();\n      this.interruptionStreamChannel.addStreamInput(inputStream);\n    } else {\n      const [vadInputStream, sttInputStream] = primaryInputStream.tee();\n      this.vadInputStream = vadInputStream;\n      this.sttInputStream = mergeReadableStreams(\n        replaceSttInputWithSilence(sttInputStream),\n        this.silenceAudioTransform.readable,\n      );\n    }\n    this.silenceAudioWriter = this.silenceAudioTransform.writable.getWriter();\n  }\n\n  /**\n   * Current transcript of the user's speech, including interim transcript if available.\n   */\n  get currentTranscript(): string {\n    if (this.audioInterimTranscript) {\n      return `${this.audioTranscript} ${this.audioInterimTranscript}`.trim();\n    }\n    return this.audioTranscript;\n  }\n\n  /** @internal */\n  get inputStartedAt() {\n    return this.sttPipeline?.inputStartedAt;\n  }\n\n  /** @internal */\n  get endOfTurnTask(): Task<void> | undefined {\n    return this.bounceEOUTask;\n  }\n\n  /** @internal */\n  get endpointingOverlapping(): boolean {\n    return this.endpointing.overlapping;\n  }\n\n  /** @internal */\n  get isClosed(): boolean {\n    return this.closed;\n  }\n\n  /** @internal */\n  updateOptions(options: {\n    endpointing?: BaseEndpointing;\n    turnDetection?: TurnDetectionMode | null;\n  }): void {\n    if (options.endpointing !== undefined) {\n      this.endpointing = options.endpointing;\n    }\n    if (options.turnDetection !== undefined) {\n      this.turnDetectionMode = options.turnDetection ?? undefined;\n    }\n  }\n\n  /**\n   * Swap the active turn detector at runtime. When an `BaseStreamingTurnDetector`\n   * is provided, opens a per-turn FSM stream after retiring the prior one.\n   *\n   * When `stream` is provided it is adopted as-is (handoff reuse) instead of\n   * opening a fresh stream on `detector`; the live transport stream — and its\n   * per-session cloud→local fallback state — survives the handoff.\n   */\n  updateTurnDetector(\n    detector: _TurnDetector | BaseStreamingTurnDetector | undefined,\n    options?: { stream?: BaseStreamingTurnDetectorStream },\n  ): void {\n    // Validate against the incoming detector before swapping in so the error\n    // — when raised — names the configuration that failed.\n    this.checkVadSilenceRequirement(detector);\n    this.turnDetector = detector;\n\n    const reuseStream = options?.stream;\n    // Retire the prior stream before creating the new one. `detach()` frees\n    // the detector's single-stream slot synchronously (so `stream()` below\n    // won't throw if the same detector is reused), while the network teardown\n    // runs in the background.\n    const oldStream = this.turnDetectorStream;\n    if (oldStream !== undefined && oldStream !== reuseStream) {\n      oldStream.detach();\n      void oldStream.aclose().catch(() => undefined);\n    }\n    const newStream =\n      reuseStream !== undefined\n        ? reuseStream\n        : detector instanceof BaseStreamingTurnDetector\n          ? detector.stream()\n          : undefined;\n    // A different stream means a fresh request lifecycle: drop any held\n    // prediction future and re-arm so the adopting recognition starts its own\n    // request on the next VAD event.\n    if (this.turnDetectorStream !== newStream) {\n      this.turnDetectorPredictionFut = undefined;\n      this.turnDetectorFlushed = false;\n    }\n    this.turnDetectorStream = newStream;\n  }\n\n  /**\n   * Detach the turn detector stream for handoff to another AudioRecognition.\n   *\n   * Returns the live stream (transport run loop intact) without closing it.\n   * The caller passes it to the new AudioRecognition via\n   * `start({ turnDetectorStream })`. The stream stays attached to its\n   * detector, retaining the detector's single-stream slot, so the new\n   * AudioRecognition must adopt it rather than open a second stream.\n   */\n  detachTurnDetector(): BaseStreamingTurnDetectorStream | undefined {\n    const stream = this.turnDetectorStream;\n    this.turnDetectorStream = undefined;\n    // The adopting recognition starts a fresh request on its next VAD event,\n    // superseding any request that survived the handoff.\n    this.turnDetectorPredictionFut = undefined;\n    return stream;\n  }\n\n  /**\n   * The audio EOT detector needs a wider silence window than typical VAD\n   * defaults. Rather than mutate the VAD's knob, require the caller to\n   * configure it: raise if the bound VAD exposes `minSilenceDuration` and it\n   * is below the floor. VADs that don't expose the knob are left untouched.\n   */\n  checkVadSilenceRequirement(\n    detector: _TurnDetector | BaseStreamingTurnDetector | undefined = this.turnDetector,\n    vad: VAD | undefined = this.vad,\n  ): void {\n    if (!(detector instanceof BaseStreamingTurnDetector) || vad === undefined) {\n      return;\n    }\n    const current = vad.minSilenceDuration;\n    if (current === null) {\n      return;\n    }\n    const required = MIN_SILENCE_DURATION_MS + 50;\n    if (current < required) {\n      throw new Error(\n        `vad minSilenceDuration=${current}ms is too low for the TurnDetector. ` +\n          `Raise the VAD's minSilenceDuration to at least ${required}ms.`,\n      );\n    }\n  }\n\n  private updateLastLanguage(language: LanguageCode | undefined, transcript: string): void {\n    if (!language || NON_SPECIFIC_LANGUAGE_CODES.has(language)) {\n      return;\n    }\n\n    if (!this.lastLanguage || transcript.length > MIN_LANGUAGE_DETECTION_LENGTH) {\n      this.lastLanguage = language;\n    }\n  }\n\n  async updateStt(\n    stt: STTNode | undefined,\n    options: { model?: string; provider?: string; resetContext?: boolean } = {},\n  ): Promise<void> {\n    const unlock = await this.sttLifecycleLock.lock();\n    try {\n      this.stt = stt;\n      if (Object.hasOwn(options, 'model')) {\n        this.sttModel = options.model;\n      }\n      if (Object.hasOwn(options, 'provider')) {\n        this.sttProvider = options.provider;\n      }\n      if (options.resetContext) {\n        this.lastLanguage = undefined;\n        this.sttRequestIds = [];\n        this.transcriptBuffer = [];\n        this.ignoreUserTranscriptUntil = undefined;\n      }\n\n      await this.stopSttTasks();\n      await this.sttPipeline?.close();\n      this.sttPipeline = undefined;\n      this.sttOwnershipTransferred = false;\n\n      if (!this.closed && this.stt !== undefined) {\n        this.startSttTasks();\n      }\n    } finally {\n      unlock();\n    }\n  }\n\n  async updateVad(vad: VAD | undefined): Promise<void> {\n    this.checkVadSilenceRequirement(undefined, vad);\n    const unlock = await this.vadLifecycleLock.lock();\n    try {\n      this.vad = vad;\n      this.isInterruptionEnabled = !!(this.interruptionDetection && this.vad);\n\n      await this.vadTask?.cancelAndWait();\n      this.vadTask = undefined;\n      this.vadStream = undefined;\n\n      if (!this.closed && this.vad !== undefined) {\n        this.startVadTask(this.vad);\n      }\n    } finally {\n      unlock();\n    }\n  }\n\n  async start(options?: {\n    sttPipeline?: STTPipeline;\n    turnDetectorStream?: BaseStreamingTurnDetectorStream;\n  }) {\n    this.startSttTasks(options?.sttPipeline);\n\n    if (this.vad !== undefined) {\n      this.startVadTask(this.vad);\n    }\n\n    this.interruptionTask = Task.from(({ signal }) =>\n      this.createInterruptionTask(this.interruptionDetection, signal),\n    );\n    this.interruptionTask.result.catch((err) => {\n      this.logger.error(`Error running interruption task: ${err}`);\n    });\n\n    // Open (or adopt) the audio EOT detector stream now that the activity is\n    // running. We only call `updateTurnDetector` for BaseStreamingTurnDetector /\n    // undefined detectors — plugin-based `_TurnDetector` instances are\n    // text-only and don't carry a stream.\n    if (this.turnDetector instanceof BaseStreamingTurnDetector || this.turnDetector === undefined) {\n      this.updateTurnDetector(this.turnDetector, { stream: options?.turnDetectorStream });\n    }\n  }\n\n  async disableInterruptionDetection(): Promise<void> {\n    this.isInterruptionEnabled = false;\n    this.interruptionDetection = undefined;\n    this.overlapOpen = false;\n    await this.interruptionTask?.cancelAndWait();\n    this.interruptionTask = undefined;\n    await this.interruptionStreamChannel?.close();\n    this.interruptionStreamChannel = undefined;\n    this.cancelBackchannelBoundary();\n    await this.flushHeldTranscripts(0, true);\n  }\n\n  /**\n   * Whether the backchannel boundary timer is currently running.\n   */\n  get backchannelBoundaryActive(): boolean {\n    return this.backchannelBoundaryTimer !== undefined;\n  }\n\n  /**\n   * Fires when the backchannel boundary timer expires naturally. Drops the timer handle and\n   * invokes the registered callback exactly once.\n   */\n  private onBackchannelBoundaryDone(): void {\n    this.backchannelBoundaryTimer = undefined;\n    const cb = this.backchannelBoundaryCallback;\n    this.backchannelBoundaryCallback = undefined;\n    cb?.();\n  }\n\n  /**\n   * Cancel any pending backchannel boundary timer and clear the registered callback.\n   */\n  cancelBackchannelBoundary(): void {\n    if (this.backchannelBoundaryTimer !== undefined) {\n      clearTimeout(this.backchannelBoundaryTimer);\n      this.backchannelBoundaryTimer = undefined;\n    }\n    this.backchannelBoundaryCallback = undefined;\n  }\n\n  /**\n   * Mark the start of active agent speech.\n   *\n   * This lifecycle follows audible playout, not the generation. Resuming paused playout starts\n   * a new active-speech interval.\n   */\n  async onStartOfAgentSpeech(startedAt: number) {\n    this.isAgentSpeaking = true;\n    this.agentSpeechStartedAt = startedAt;\n    this.endpointing.onStartOfAgentSpeech(startedAt);\n    this.userTurnTracker = { words: 0, transcript: '' };\n\n    if (this.backchannelBoundary && this.backchannelBoundary[0] > 0) {\n      this.cancelBackchannelBoundary();\n      const startCooldown = this.backchannelBoundary[0];\n      this.backchannelBoundaryTimer = setTimeout(\n        () => this.onBackchannelBoundaryDone(),\n        startCooldown,\n      );\n    }\n\n    const sentinels: InterruptionSentinel[] = [InterruptionStreamSentinel.agentSpeechStarted()];\n\n    if (this.speaking) {\n      const overlapStarted = this.startOverlapInference(0, startedAt, this.activeUserSpeakingSpan);\n      if (overlapStarted) {\n        sentinels.push(overlapStarted);\n      }\n    }\n    await this.trySendInterruptionSentinel(sentinels);\n  }\n\n  /**\n   * Mark the end of active agent speech.\n   *\n   * This can occur while the generation remains active, such as when playout is paused.\n   */\n  async onEndOfAgentSpeech(ignoreUserTranscriptUntil: number) {\n    this.cancelBackchannelBoundary();\n\n    const now = Date.now();\n    const wasAgentSpeaking = this.isAgentSpeaking;\n    if (wasAgentSpeaking) {\n      this.endpointing.onEndOfAgentSpeech(now);\n    }\n\n    if (!this.isInterruptionEnabled) {\n      this.isAgentSpeaking = false;\n      return;\n    }\n\n    let endCooldown = 0;\n    if (wasAgentSpeaking) {\n      endCooldown = this.backchannelBoundary ? this.backchannelBoundary[1] : 0;\n      const ignoreUntil = this.ignoreUserTranscriptUntil\n        ? Math.min(ignoreUserTranscriptUntil, this.ignoreUserTranscriptUntil)\n        : ignoreUserTranscriptUntil;\n      this.logger.trace({ ignoreUntil, endCooldown }, 'flushing held transcripts');\n      // Subtracting `endCooldown` widens the release window so transcripts that ended just\n      // before the agent finished speaking (premature corrections) are surfaced.\n      this.ignoreUserTranscriptUntil = ignoreUntil - endCooldown;\n    }\n    // Python's detector channel writes are synchronous. Clear before awaiting the equivalent JS\n    // writes so STT events arriving while boundaries are sent are not buffered as active speech.\n    this.isAgentSpeaking = false;\n    const sentinels: InterruptionSentinel[] = [];\n    if (wasAgentSpeaking) {\n      // Close any unresolved overlap before resetting the detector.\n      const overlapEnded = this.closeOverlap(now, undefined, true);\n      if (overlapEnded) {\n        sentinels.push(overlapEnded);\n      }\n    }\n\n    sentinels.push(InterruptionStreamSentinel.agentSpeechEnded());\n    const inputOpen = await this.trySendInterruptionSentinel(sentinels);\n    if (!inputOpen) {\n      this.overlapOpen = false;\n      return;\n    }\n\n    if (wasAgentSpeaking) {\n      await this.flushHeldTranscripts(endCooldown);\n    }\n  }\n\n  /** Start interruption inference when agent is speaking and overlap speech starts. */\n  async onStartOfOverlapSpeech(speechDuration: number, startedAt: number, userSpeakingSpan?: Span) {\n    this.activeUserSpeakingSpan = userSpeakingSpan;\n    if (this.isAgentSpeaking) {\n      if (!this.endpointing.overlapping) {\n        this.endpointing.onStartOfSpeech(startedAt, true);\n      }\n      const overlapStarted = this.startOverlapInference(\n        speechDuration,\n        startedAt,\n        userSpeakingSpan,\n      );\n      if (overlapStarted) {\n        await this.trySendInterruptionSentinel(overlapStarted);\n      }\n    }\n  }\n\n  private startOverlapInference(\n    speechDuration: number,\n    startedAt: number,\n    userSpeakingSpan?: Span,\n  ): OverlapSpeechStarted | undefined {\n    if (!this.isInterruptionEnabled || !this.isAgentSpeaking || this.overlapOpen) {\n      return undefined;\n    }\n    this.interruptionDetected = undefined;\n    this.turnBackchannelOverAgent = false;\n    this.overlapInCurrentTurn = true;\n    this.overlapOpen = true;\n    return InterruptionStreamSentinel.overlapSpeechStarted(\n      speechDuration,\n      startedAt,\n      userSpeakingSpan,\n    );\n  }\n\n  /** End interruption inference when overlap speech ends. */\n  async onEndOfOverlapSpeech(endedAt: number, userSpeakingSpan?: Span, agentEnded = false) {\n    if (!agentEnded) {\n      this.activeUserSpeakingSpan = undefined;\n    }\n    const overlapEnded = this.closeOverlap(endedAt, userSpeakingSpan, agentEnded);\n    if (overlapEnded) {\n      return this.trySendInterruptionSentinel(overlapEnded);\n    }\n  }\n\n  private closeOverlap(\n    endedAt: number,\n    userSpeakingSpan?: Span,\n    agentEnded = false,\n  ): OverlapSpeechEnded | undefined {\n    // The overlap ends once, on the first of a verdict, the user stopping, the agent stopping,\n    // or teardown, so a call can arrive with it already closed.\n    if (!this.isInterruptionEnabled || !this.overlapOpen) {\n      return undefined;\n    }\n    this.overlapOpen = false;\n    if (\n      this.overlapInCurrentTurn &&\n      this.interruptionDetected !== true &&\n      userSpeakingSpan &&\n      userSpeakingSpan.isRecording()\n    ) {\n      userSpeakingSpan.setAttribute(traceTypes.ATTR_IS_INTERRUPTION, 'false');\n    }\n\n    return InterruptionStreamSentinel.overlapSpeechEnded(endedAt, agentEnded);\n  }\n\n  /**\n   * Flush held transcripts. When `force` is true, all buffered events are emitted during\n   * interruption-detector teardown because ignore-window gating can no longer be trusted.\n   * Otherwise, only transcripts whose end time is after `ignoreUserTranscriptUntil - cooldown`\n   * are emitted. Events without timestamps are treated as the next valid event.\n   */\n  private async flushHeldTranscripts(cooldown: number = 0, force = false) {\n    if (this.transcriptBuffer.length === 0) {\n      this.resetInterruptionDetection();\n      return;\n    }\n\n    if (force) {\n      const eventsToEmit = [...this.transcriptBuffer];\n      this.resetInterruptionDetection();\n      for (const event of eventsToEmit) {\n        await this.onSTTEvent(event);\n      }\n      return;\n    }\n\n    if (\n      !this.isInterruptionEnabled ||\n      this.ignoreUserTranscriptUntil === undefined ||\n      this.inputStartedAt === undefined\n    ) {\n      this.resetInterruptionDetection();\n      return;\n    }\n\n    let emitFromIndex: number | null = null;\n    let shouldFlush = false;\n\n    for (let i = 0; i < this.transcriptBuffer.length; i++) {\n      const ev = this.transcriptBuffer[i];\n      if (!ev || !ev.alternatives || ev.alternatives.length === 0) {\n        emitFromIndex = Math.min(emitFromIndex ?? i, i);\n        continue;\n      }\n      const firstAlternative = ev.alternatives[0];\n      if (\n        firstAlternative.startTime === firstAlternative.endTime &&\n        firstAlternative.startTime === 0\n      ) {\n        this.resetInterruptionDetection();\n        return;\n      }\n\n      if (this.#alternativeEndsWithinIgnoreWindow(firstAlternative)) {\n        emitFromIndex = null;\n      } else {\n        emitFromIndex = Math.min(emitFromIndex ?? i, i);\n        shouldFlush = true;\n        break;\n      }\n    }\n\n    const eventsToEmit =\n      emitFromIndex !== null && shouldFlush ? this.transcriptBuffer.slice(emitFromIndex) : [];\n\n    // Snapshot the ignore-until before resetting so the added-delay diagnostic below mirrors\n    // the value the holding decision was made against.\n    const prevIgnoreUserTranscriptUntil = this.ignoreUserTranscriptUntil;\n    const prevInputStartedAt = this.inputStartedAt;\n    this.resetInterruptionDetection();\n\n    for (const event of eventsToEmit) {\n      let addedDelay = 0;\n      const firstAlternative = event.alternatives?.[0];\n      if (\n        firstAlternative &&\n        firstAlternative.endTime > 0 &&\n        prevIgnoreUserTranscriptUntil !== undefined &&\n        prevInputStartedAt !== undefined\n      ) {\n        addedDelay = Math.max(\n          0,\n          firstAlternative.endTime * 1000 +\n            prevInputStartedAt -\n            prevIgnoreUserTranscriptUntil +\n            cooldown,\n        );\n      }\n      this.logger.trace(\n        { event: event.type, cooldown, addedDelay },\n        're-emitting held user transcript',\n      );\n      await this.onSTTEvent(event);\n    }\n  }\n\n  private resetInterruptionDetection(): void {\n    this.transcriptBuffer = [];\n    this.ignoreUserTranscriptUntil = undefined;\n    // Keep the anchor while a newer agent-speech cycle is active, so a stale flush\n    // can't clear an anchor that cycle has already set.\n    if (!this.isAgentSpeaking) {\n      this.agentSpeechStartedAt = undefined;\n    }\n  }\n\n  private withinIgnoreWindow(eventTime: number): boolean {\n    if (this.ignoreUserTranscriptUntil === undefined) {\n      return false;\n    }\n\n    const lower = this.agentSpeechStartedAt ?? 0;\n    const upper = Math.min(Date.now(), this.ignoreUserTranscriptUntil);\n    return lower < eventTime && eventTime < upper;\n  }\n\n  #alternativeEndsWithinIgnoreWindow(\n    alternative: NonNullable<SpeechEvent['alternatives']>[number],\n  ) {\n    return (\n      alternative.endTime > 0 &&\n      this.inputStartedAt !== undefined &&\n      this.withinIgnoreWindow(alternative.endTime * 1000 + this.inputStartedAt)\n    );\n  }\n\n  private shouldHoldSttEvent(ev: SpeechEvent): boolean {\n    if (!this.isInterruptionEnabled) {\n      return false;\n    }\n    if (this.isAgentSpeaking) {\n      return true;\n    }\n\n    // reset when the user starts speaking after the agent speech\n    if (ev.type === SpeechEventType.START_OF_SPEECH) {\n      this.resetInterruptionDetection();\n      return false;\n    }\n\n    if (this.ignoreUserTranscriptUntil === undefined) {\n      return false;\n    }\n    // sentinel events are always held until we have something concrete to release them\n    if (!ev.alternatives || ev.alternatives.length === 0) {\n      return true;\n    }\n\n    const alternative = ev.alternatives[0];\n\n    if (\n      alternative.startTime !== alternative.endTime &&\n      this.inputStartedAt !== undefined &&\n      alternative.startTime > 0 &&\n      this.withinIgnoreWindow(alternative.startTime * 1000 + this.inputStartedAt)\n    ) {\n      return true;\n    }\n    return false;\n  }\n\n  private async trySendInterruptionSentinel(\n    frame: AudioFrame | InterruptionSentinel | InterruptionSentinel[],\n  ): Promise<boolean> {\n    const frames = Array.isArray(frame) ? frame : [frame];\n    let sent = false;\n    const write = async () => {\n      if (\n        this.isInterruptionEnabled &&\n        this.interruptionStreamChannel &&\n        !this.interruptionStreamChannel.closed\n      ) {\n        try {\n          for (const item of frames) {\n            await this.interruptionStreamChannel.write(item);\n          }\n          sent = true;\n        } catch (e: unknown) {\n          this.logger.warn(\n            `could not forward interruption sentinel: ${e instanceof Error ? e.message : String(e)}`,\n          );\n        }\n      }\n    };\n    this.interruptionSentinelWrite = this.interruptionSentinelWrite.then(write, write);\n    await this.interruptionSentinelWrite;\n    return sent;\n  }\n\n  private ensureUserTurnSpan(startTime?: number): Span {\n    if (this.userTurnSpan && this.userTurnSpan.isRecording()) {\n      return this.userTurnSpan;\n    }\n\n    startTime ??= Date.now();\n    if (this.userTurnStart === undefined) {\n      this.userTurnStart = startTime;\n    }\n\n    this.userTurnSpan = tracer.startSpan({\n      name: 'user_turn',\n      context: this.rootSpanContext,\n      startTime,\n    });\n\n    const participant = this.getLinkedParticipant?.();\n    if (participant) {\n      setParticipantSpanAttributes(this.userTurnSpan, participant);\n    }\n\n    if (this.sttModel) {\n      this.userTurnSpan.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, this.sttModel);\n    }\n    if (this.sttProvider) {\n      this.userTurnSpan.setAttribute(traceTypes.ATTR_GEN_AI_PROVIDER_NAME, this.sttProvider);\n    }\n\n    return this.userTurnSpan;\n  }\n\n  private userTurnContext(span: Span): Context {\n    const base = this.rootSpanContext ?? ROOT_CONTEXT;\n    return trace.setSpan(base, span);\n  }\n\n  private async onSTTEvent(ev: SpeechEvent) {\n    // Collect provider-known STT ids for this user turn. The actual attribute is\n    // written once when the user_turn span ends (see _endUserTurnSpan), to avoid\n    // ordering issues with span creation.\n    if (ev.requestId && !this.sttRequestIds.includes(ev.requestId)) {\n      this.sttRequestIds.push(ev.requestId);\n    }\n\n    if (\n      this.turnDetectionMode === 'manual' &&\n      this.userTurnCommitted &&\n      (this.bounceEOUTask === undefined ||\n        this.bounceEOUTask.done ||\n        ev.type == SpeechEventType.INTERIM_TRANSCRIPT)\n    ) {\n      // ignore stt event if user turn already committed and EOU task is done\n      // or it's an interim transcript\n      this.logger.debug(\n        {\n          userTurnCommitted: this.userTurnCommitted,\n          eouTaskDone: this.bounceEOUTask?.done,\n          evType: ev.type,\n          turnDetectionMode: this.turnDetectionMode,\n        },\n        'ignoring stt event',\n      );\n      return;\n    }\n\n    // Interim and preflight transcripts may never be followed by a final transcript.\n    if (ev.type === SpeechEventType.FINAL_TRANSCRIPT && ev.alternatives?.[0]?.text) {\n      this.markTurnTranscribed();\n    }\n\n    // handle interruption detection\n    // - hold the event until the ignore_user_transcript_until expires\n    // - release only relevant events\n    // - allow RECOGNITION_USAGE to pass through immediately\n\n    if (ev.type !== SpeechEventType.RECOGNITION_USAGE && this.isInterruptionEnabled) {\n      if (this.shouldHoldSttEvent(ev)) {\n        this.logger.trace(\n          { event: ev.type, ignoreUserTranscriptUntil: this.ignoreUserTranscriptUntil },\n          'holding STT event until ignore_user_transcript_until expires',\n        );\n        this.transcriptBuffer.push(ev);\n        return;\n      } else if (this.transcriptBuffer.length > 0) {\n        const endCooldown = this.backchannelBoundary ? this.backchannelBoundary[1] : 0;\n        await this.flushHeldTranscripts(endCooldown);\n        // no return here to allow the new event to be processed normally\n      }\n    }\n\n    const firstAlternative = ev.alternatives?.[0];\n    const inputStartedAt = this.inputStartedAt;\n    const hasSTTEndTime =\n      firstAlternative !== undefined &&\n      firstAlternative.endTime > 0 &&\n      inputStartedAt !== undefined;\n    const hasAbsoluteSpeechEndTime = ev.speechEndTime !== undefined;\n    // clamp to now: a reused STT stream's clock can be far ahead of this\n    // activity's input epoch (e.g. after a handoff), and a future\n    // lastSpeakingTime would stall the EOU bounce task for that long\n    // (1.4.5 silence regression from #1603; see audio_recognition_eou.test.ts)\n    const sttLastSpeakingTime =\n      ev.speechEndTime !== undefined\n        ? Math.min(ev.speechEndTime, Date.now())\n        : hasSTTEndTime\n          ? Math.min(firstAlternative.endTime * 1000 + inputStartedAt, Date.now())\n          : Date.now();\n    // Prefer STT timing when no VAD anchor exists. In STT turn detection, a real\n    // timestamp or an explicit end-of-speech event owns the turn boundary too.\n    const useSTTSpeakingTime =\n      this.vad === undefined ||\n      this.lastSpeakingTime === undefined ||\n      (this.turnDetectionMode === 'stt' &&\n        (hasAbsoluteSpeechEndTime || hasSTTEndTime || ev.type === SpeechEventType.END_OF_SPEECH));\n\n    switch (ev.type) {\n      case SpeechEventType.FINAL_TRANSCRIPT:\n        const transcript = ev.alternatives?.[0]?.text ?? '';\n        const confidence = ev.alternatives?.[0]?.confidence ?? 0;\n        const language = ev.alternatives?.[0]?.language;\n        this.updateLastLanguage(language, transcript);\n\n        if (!transcript) {\n          // stt final transcript received but no transcript\n          return;\n        }\n\n        this.hooks.onFinalTranscript(\n          ev,\n          this.vad !== undefined || this.turnDetectionMode === 'stt' ? this.speaking : undefined,\n        );\n\n        this.logger.debug(\n          {\n            'lk.pii.user_transcript': transcript,\n            language: this.lastLanguage,\n          },\n          'received user transcript',\n        );\n\n        this.lastFinalTranscriptTime = Date.now();\n        this.audioTranscript += ` ${transcript}`;\n        this.audioTranscript = this.audioTranscript.trimStart();\n        this.finalTranscriptConfidence.push(confidence);\n        const transcriptChanged = this.audioTranscript !== this.audioPreflightTranscript;\n        this.audioInterimTranscript = '';\n        this.audioPreflightTranscript = '';\n\n        if (useSTTSpeakingTime) {\n          this.lastSpeakingTime = sttLastSpeakingTime;\n        }\n\n        this.checkUserTurnLimit(transcript);\n\n        if (this.vadBaseTurnDetection || this.userTurnCommitted) {\n          if (transcriptChanged) {\n            this.logger.debug(\n              { 'lk.pii.transcript': this.audioTranscript },\n              'triggering preemptive generation (FINAL_TRANSCRIPT)',\n            );\n            this.hooks.onPreemptiveGeneration({\n              newTranscript: this.audioTranscript,\n              transcriptConfidence:\n                this.finalTranscriptConfidence.length > 0\n                  ? this.finalTranscriptConfidence.reduce((a, b) => a + b, 0) /\n                    this.finalTranscriptConfidence.length\n                  : 0,\n              startedSpeakingAt: this.speechStartTime,\n            });\n          }\n\n          if (!this.speaking) {\n            const chatCtx = this.hooks.retrieveChatCtx();\n            this.logger.debug('running EOU detection on stt FINAL_TRANSCRIPT');\n            this.runEOUDetection(chatCtx, 'stt');\n          }\n        }\n        break;\n      case SpeechEventType.PREFLIGHT_TRANSCRIPT:\n        this.hooks.onInterimTranscript(\n          ev,\n          this.vad !== undefined || this.turnDetectionMode === 'stt' ? this.speaking : undefined,\n        );\n        const preflightTranscript = ev.alternatives?.[0]?.text ?? '';\n        const preflightConfidence = ev.alternatives?.[0]?.confidence ?? 0;\n        const preflightLanguage = ev.alternatives?.[0]?.language;\n\n        this.updateLastLanguage(preflightLanguage, preflightTranscript);\n\n        if (!preflightTranscript) {\n          return;\n        }\n\n        this.logger.debug(\n          {\n            'lk.pii.user_transcript': preflightTranscript,\n            language: this.lastLanguage,\n          },\n          'received user preflight transcript',\n        );\n\n        // still need to increment it as it's used for turn detection,\n        this.lastFinalTranscriptTime = Date.now();\n        // preflight transcript includes all pre-committed transcripts (including final transcript from the previous STT run)\n        this.audioPreflightTranscript =\n          `${this.audioTranscript} ${preflightTranscript}`.trimStart();\n        this.audioInterimTranscript = preflightTranscript;\n\n        if (useSTTSpeakingTime) {\n          this.lastSpeakingTime = sttLastSpeakingTime;\n        }\n\n        if (this.turnDetectionMode !== 'manual' || this.userTurnCommitted) {\n          const confidenceVals = [...this.finalTranscriptConfidence, preflightConfidence];\n          this.logger.debug(\n            {\n              'lk.pii.transcript':\n                this.audioPreflightTranscript.length > 100\n                  ? this.audioPreflightTranscript.slice(0, 100) + '...'\n                  : this.audioPreflightTranscript,\n            },\n            'triggering preemptive generation (PREFLIGHT_TRANSCRIPT)',\n          );\n          this.hooks.onPreemptiveGeneration({\n            newTranscript: this.audioPreflightTranscript,\n            transcriptConfidence:\n              confidenceVals.length > 0\n                ? confidenceVals.reduce((a, b) => a + b, 0) / confidenceVals.length\n                : 0,\n            startedSpeakingAt: this.speechStartTime,\n          });\n        }\n        break;\n      case SpeechEventType.INTERIM_TRANSCRIPT:\n        this.logger.debug(\n          { 'lk.pii.transcript': ev.alternatives?.[0]?.text },\n          'interim transcript',\n        );\n        this.hooks.onInterimTranscript(\n          ev,\n          this.vad !== undefined || this.turnDetectionMode === 'stt' ? this.speaking : undefined,\n        );\n        this.audioInterimTranscript = ev.alternatives?.[0]?.text ?? '';\n        break;\n      case SpeechEventType.START_OF_SPEECH:\n        if (this.turnDetectionMode !== 'stt') break;\n        {\n          const speechStartTime = Date.now();\n          const span = this.ensureUserTurnSpan(speechStartTime);\n          const ctx = this.userTurnContext(span);\n          this.endpointing.onStartOfSpeech(speechStartTime, this.isAgentSpeaking);\n          this.interruptionDetected = undefined;\n          this.turnBackchannelOverAgent = false;\n          this.overlapInCurrentTurn = this.isAgentSpeaking;\n          otelContext.with(ctx, () => {\n            this.hooks.onStartOfSpeech({\n              type: VADEventType.START_OF_SPEECH,\n              samplesIndex: 0,\n              timestamp: Date.now(),\n              speechDuration: 0,\n              silenceDuration: 0,\n              frames: [],\n              probability: 0,\n              inferenceDuration: 0,\n              speaking: true,\n              rawAccumulatedSilence: 0,\n              rawAccumulatedSpeech: 0,\n            });\n          });\n        }\n        this.speaking = true;\n        this.lastSpeakingTime = sttLastSpeakingTime;\n        this.bounceEOUTask?.cancel();\n        break;\n      case SpeechEventType.END_OF_SPEECH:\n        if (this.turnDetectionMode !== 'stt') break;\n        {\n          const speechEndTime = Date.now();\n          const span = this.ensureUserTurnSpan();\n          const ctx = this.userTurnContext(span);\n          if (this.speaking) {\n            this.endpointing.onEndOfSpeech(speechEndTime, this.interruptionDetected);\n          }\n          otelContext.with(ctx, () => {\n            this.hooks.onEndOfSpeech({\n              type: VADEventType.END_OF_SPEECH,\n              samplesIndex: 0,\n              timestamp: Date.now(),\n              speechDuration: 0,\n              silenceDuration: 0,\n              frames: [],\n              probability: 0,\n              inferenceDuration: 0,\n              speaking: false,\n              rawAccumulatedSilence: 0,\n              rawAccumulatedSpeech: 0,\n            });\n          });\n        }\n        // STT EOT changes user state from speaking to listening without updating VAD internal states.\n        // VAD EOS will also skip updating user state from listening (STT enforced) to listening (VAD detected)\n        // and user state won't be updated until a new VAD SOS is received.\n        // Reset VAD so that incorrect end of turn from STT can be corrected by VAD interruption.\n        // If user is still speaking (an immediate VAD SOS will interrupt the agent).\n        if (this.vad !== undefined && this.vadSpeechStarted) {\n          if (this.vadStream) {\n            this.vadStream.flush();\n          } else {\n            this.resetVad();\n          }\n\n          this.logger.warn(\n            {\n              vadSpeechStartTime: this.speechStartTime,\n              flushed: this.vadStream !== undefined,\n            },\n            'stt end of speech received while vad is still in a speech segment, flushing vad',\n          );\n        }\n        this.speaking = false;\n        this.userTurnCommitted = true;\n        if (ev.speechEndTime !== undefined) {\n          // Clamp provider clock skew so endpointing sleep cannot be extended\n          // by an anchor that lies in the future.\n          this.lastSpeakingTime = Math.min(ev.speechEndTime, Date.now());\n        } else if (useSTTSpeakingTime) {\n          this.lastSpeakingTime = sttLastSpeakingTime;\n        }\n\n        if (!this.speaking) {\n          const chatCtx = this.hooks.retrieveChatCtx();\n          this.logger.debug('running EOU detection on stt END_OF_SPEECH');\n          this.runEOUDetection(chatCtx, 'stt');\n        }\n    }\n  }\n\n  private onOverlapSpeechEvent(ev: OverlappingSpeechEvent) {\n    // Every verdict is terminal for its overlap, including one the cooldown then ignores.\n    this.overlapOpen = false;\n\n    if (this.backchannelBoundaryActive && !ev.isInterruption) {\n      this.logger.trace(\n        'ignoring backchannel event during backchannel boundary cooldown, falling back to vad',\n      );\n      return;\n    }\n\n    this.interruptionDetected = ev.isInterruption;\n\n    if (this.overlapInCurrentTurn && !ev.agentEnded) {\n      this.turnBackchannelOverAgent = !ev.isInterruption;\n      if (!ev.isInterruption && !this.speaking) {\n        this.hooks.onBackchannelConfirmed();\n      }\n    }\n\n    if (ev.isInterruption) {\n      this.hooks.onInterruption(ev);\n    }\n  }\n\n  private onMissingEotPrediction(): void {\n    if (this.turnDetectorFlushed) {\n      if (!this.turnDetectorLatePredictionWarned) {\n        this.turnDetectorLatePredictionWarned = true;\n        this.logger.warn(\n          'transcript arrives after turn has been committed. consider raising `minDelay` in the ' +\n            'endpointing options to accommodate a slow stt. subsequent ' +\n            'occurrences will log at debug level.',\n        );\n      } else {\n        this.logger.debug('stt transcript arrived after a turn flush, skipping eot prediction');\n      }\n    } else {\n      this.logger.debug('no eot inference request in flight, skipping eot prediction');\n    }\n  }\n\n  private runEOUDetection(chatCtx: ChatContext, trigger: 'vad' | 'stt' | 'manual' = 'vad') {\n    this.logger.debug(\n      {\n        stt: this.stt,\n        'lk.pii.audio_transcript': this.audioTranscript,\n        turnDetectionMode: this.turnDetectionMode,\n      },\n      'running EOU detection',\n    );\n\n    if (this.stt && !this.audioTranscript && this.turnDetectionMode !== 'manual') {\n      // stt enabled but no transcript yet\n      this.logger.debug('skipping EOU detection');\n      return;\n    }\n\n    chatCtx = chatCtx.copy();\n    if (this.audioTranscript) {\n      chatCtx.addMessage({ role: 'user', content: this.audioTranscript });\n    }\n\n    // Pick the right detector:\n    //  - manual mode: no detector (turn boundary decided externally)\n    //  - audio EOT detector: prefer the per-turn stream (it caches the\n    //    prediction for the current inference window so the bounce task\n    //    can short-circuit on cache)\n    //  - text-based detector: only run when we have a transcript to score\n    const hasAudioDetector = this.turnDetector instanceof BaseStreamingTurnDetector;\n    const useDetector =\n      this.turnDetectionMode !== 'manual' && (this.audioTranscript || hasAudioDetector);\n    // The unified type only covers the predict surface; the audio\n    // detector's per-turn stream stands in for the parent when one is\n    // attached so the cached prediction is available.\n    let turnDetector: _TurnDetector | BaseStreamingTurnDetectorStream | undefined;\n    if (!useDetector) {\n      turnDetector = undefined;\n    } else if (hasAudioDetector) {\n      turnDetector = this.turnDetectorStream;\n    } else {\n      // text-based detector — `this.turnDetector` cannot be the audio\n      // base class here, because `hasAudioDetector` already screened it.\n      turnDetector = this.turnDetector as _TurnDetector | undefined;\n    }\n\n    const bounceEOUTask =\n      (\n        lastSpeakingTime: number | undefined,\n        lastFinalTranscriptTime: number,\n        speechStartTime: number | undefined,\n      ) =>\n      async (controller: AbortController) => {\n        let endpointingDelay = this.endpointing.minDelay;\n\n        const userTurnSpan = this.ensureUserTurnSpan();\n        const userTurnCtx = this.userTurnContext(userTurnSpan);\n\n        if (turnDetector) {\n          if (!(await turnDetector.supportsLanguage(this.lastLanguage))) {\n            // Unsupported language: produce no span and emit no prediction event.\n            this.logger.debug(`Turn detector does not support language ${this.lastLanguage}`);\n          } else {\n            await tracer.startActiveSpan(\n              async (span) => {\n                this.logger.debug('Running turn detector model');\n\n                // undefined => the prediction never resolved (e.g. timed out\n                // or inference threw); gates the span attributes and the emit\n                // below.\n                let endOfTurnProbability: number | undefined;\n                let unlikelyThreshold: number | undefined;\n                let backchannelThreshold: number | undefined;\n                // True when the held future was already resolved when this\n                // bounce started — i.e. the prediction was served from the\n                // request the silence tick warmed, not awaited fresh.\n                let fromCache = false;\n                // The resolved prediction event for this turn, shared by\n                // reference across both EOU triggers (vad + stt final) so the\n                // emit can dedupe.\n                let predictionEvent: TurnDetectionEvent | undefined;\n\n                if (turnDetector instanceof BaseStreamingTurnDetectorStream) {\n                  const fut = this.turnDetectorPredictionFut;\n                  if (fut === undefined) {\n                    if (trigger === 'stt') {\n                      this.onMissingEotPrediction();\n                    }\n                  } else {\n                    fromCache = fut.done;\n                    // Await the held future against the model prediction timeout.\n                    const predictionTimeout = turnDetector.predictionTimeout;\n                    let timeoutId: ReturnType<typeof setTimeout> | undefined;\n                    const winner = await Promise.race([\n                      fut.await.then((ev) => ({ kind: 'value', ev }) as const),\n                      new Promise<{ kind: 'timeout' }>((resolve) => {\n                        timeoutId = setTimeout(\n                          () => resolve({ kind: 'timeout' }),\n                          predictionTimeout,\n                        );\n                      }),\n                    ]);\n                    if (timeoutId !== undefined) clearTimeout(timeoutId);\n\n                    // A newer trigger calls `bounceEOUTask?.cancel()`. A JS abort\n                    // does NOT interrupt the await above, so bail here before\n                    // touching shared state so the superseded bounce doesn't\n                    // clobber a freshly-armed future or double-emit.\n                    if (controller.signal.aborted) return;\n\n                    if (winner.kind === 'value') {\n                      predictionEvent = winner.ev;\n                      endOfTurnProbability = predictionEvent.endOfTurnProbability;\n                      unlikelyThreshold = await turnDetector.unlikelyThreshold(this.lastLanguage);\n                      backchannelThreshold = await turnDetector.backchannelThreshold(\n                        this.lastLanguage,\n                      );\n                    } else {\n                      this.logger.warn(\n                        { timeoutMs: predictionTimeout },\n                        'eot prediction timed out, committing without a prediction',\n                      );\n                      turnDetector.cancelInference({ timedOut: true });\n                      this.turnDetectorPredictionFut = undefined;\n                    }\n                  }\n                } else {\n                  try {\n                    endOfTurnProbability = await turnDetector.predictEndOfTurn(chatCtx);\n                    unlikelyThreshold = await turnDetector.unlikelyThreshold(this.lastLanguage);\n                  } catch (error) {\n                    this.logger.error(error, 'Error predicting end of turn');\n                  }\n                  // See the streaming-branch note: bail if a newer trigger\n                  // superseded this bounce while it awaited.\n                  if (controller.signal.aborted) return;\n                }\n\n                if (\n                  endOfTurnProbability !== undefined &&\n                  unlikelyThreshold !== undefined &&\n                  endOfTurnProbability < unlikelyThreshold\n                ) {\n                  endpointingDelay = this.endpointing.maxDelay;\n                }\n\n                this.logger.debug(\n                  {\n                    endOfTurnProbability,\n                    unlikelyThreshold,\n                    endpointingDelay,\n                    language: this.lastLanguage,\n                    trigger,\n                    fromCache,\n                  },\n                  'eot prediction',\n                );\n\n                const prediction = predictionEvent;\n\n                span.setAttribute(\n                  traceTypes.ATTR_CHAT_CTX,\n                  // snake_case wire shape, matching Python's EOU span: trim to the last\n                  // few items and drop function calls, instructions, empty messages,\n                  // handoffs, and config updates, so the span doesn't re-emit the whole\n                  // conversation on every EOU inference.\n                  JSON.stringify(\n                    toSnakeCaseDeep(\n                      new ChatContext(chatCtx.items.slice(-EOU_MAX_HISTORY_TURNS))\n                        .copy({\n                          excludeFunctionCall: true,\n                          excludeInstructions: true,\n                          excludeEmptyMessage: true,\n                          excludeHandoff: true,\n                          excludeConfigUpdate: true,\n                        })\n                        .toJSON({ excludeTimestamp: false }),\n                    ),\n                  ),\n                );\n                if (endOfTurnProbability !== undefined) {\n                  span.setAttribute(traceTypes.ATTR_EOU_PROBABILITY, endOfTurnProbability);\n                }\n                if (unlikelyThreshold !== undefined) {\n                  span.setAttribute(traceTypes.ATTR_EOU_UNLIKELY_THRESHOLD, unlikelyThreshold);\n                }\n                span.setAttribute(traceTypes.ATTR_EOU_DELAY, endpointingDelay);\n                span.setAttribute(traceTypes.ATTR_EOU_LANGUAGE, this.lastLanguage ?? '');\n                span.setAttribute(traceTypes.ATTR_EOU_FROM_CACHE, fromCache);\n                span.setAttribute(traceTypes.ATTR_EOU_SOURCE, trigger);\n\n                // Emit once the prediction resolved (a timeout / failed\n                // inference emits nothing). Both EOU triggers in a turn (vad +\n                // stt final) read the same resolved `TurnDetectionEvent`; dedupe\n                // by reference so the event fires once per request. The abort\n                // guard above drops a superseded bounce; this reference check\n                // catches the race where the first bounce completes (and emits)\n                // just before the second trigger fires. Text detectors have no\n                // shared event (`prediction === undefined`), so they always emit.\n                if (\n                  endOfTurnProbability !== undefined &&\n                  unlikelyThreshold !== undefined &&\n                  (prediction === undefined || prediction !== this.lastEmittedEotPrediction)\n                ) {\n                  this.lastEmittedEotPrediction = prediction;\n                  const inferenceDurationMs = prediction?.inferenceDuration ?? 0;\n                  const delayMs =\n                    lastSpeakingTime !== undefined ? Date.now() - lastSpeakingTime : 0;\n                  this.hooks.onEotPrediction(\n                    createEotPredictionEvent({\n                      probability: endOfTurnProbability,\n                      threshold: unlikelyThreshold,\n                      inferenceDurationMs,\n                      delayMs,\n                    }),\n                  );\n\n                  // Surface the backchannel opportunity whenever it clears its\n                  // threshold, regardless of end-of-turn; AgentActivity decides\n                  // whether to acknowledge mid-turn or let it lead the reply.\n                  // Shares the eot-emit dedupe so it fires once per request.\n                  const backchannelProbability = prediction?.backchannelProbability;\n                  if (\n                    backchannelProbability !== undefined &&\n                    backchannelThreshold !== undefined &&\n                    backchannelProbability >= backchannelThreshold\n                  ) {\n                    this.hooks.onAgentBackchannelOpportunity(\n                      _createAgentBackchannelOpportunityEvent({\n                        probability: backchannelProbability,\n                        threshold: backchannelThreshold,\n                        endOfTurnProbability,\n                        endOfTurnThreshold: unlikelyThreshold,\n                        language: this.lastLanguage,\n                      }),\n                    );\n                  }\n                }\n\n                if (prediction?.detectionDelay !== undefined) {\n                  span.setAttribute(traceTypes.ATTR_EOU_DETECTION_DELAY, prediction.detectionDelay);\n                }\n              },\n              {\n                name: 'eou_detection',\n                context: userTurnCtx,\n              },\n            );\n          }\n        }\n\n        let extraSleep = endpointingDelay;\n        if (lastSpeakingTime !== undefined) {\n          extraSleep += lastSpeakingTime - Date.now();\n        }\n\n        if (extraSleep > 0) {\n          // add delay to see if there's a potential upcoming EOU task that cancels this one\n          try {\n            await delay(Math.max(extraSleep, 0), {\n              signal: AbortSignal.any([controller.signal, this.closeWakeController.signal]),\n            });\n          } catch (error) {\n            if (!this.closeWakeController.signal.aborted) {\n              throw error;\n            }\n          }\n        }\n\n        if (controller.signal.aborted) {\n          return;\n        }\n\n        // Re-check the creation-time transcript guard at fire time. The commit path\n        // (`onEndOfTurn`) awaits, so another bounce can be created in the window between\n        // an earlier bounce reading the transcript and resetting it — that newer bounce\n        // passes the guard at creation, then wakes up here after the transcript was\n        // already committed and cleared. Without this check it commits a duplicate,\n        // empty user turn (with stale metrics) and triggers a spurious reply. Python\n        // avoids this via preemptive task cancellation and a synchronous commit.\n        if (this.stt && !this.audioTranscript && this.turnDetectionMode !== 'manual') {\n          this.logger.debug('skipping EOU commit, transcript was already committed');\n          return;\n        }\n\n        this.logger.debug({ 'lk.pii.transcript': this.audioTranscript }, 'end of user turn');\n\n        const confidenceAvg =\n          this.finalTranscriptConfidence.length > 0\n            ? this.finalTranscriptConfidence.reduce((a, b) => a + b, 0) /\n              this.finalTranscriptConfidence.length\n            : 0;\n\n        // sometimes, we can't calculate the metrics because VAD was unreliable or\n        // the speaking anchor is stale/out-of-order. in this case, we just ignore the\n        // calculation, it's better than providing likely wrong values\n        const metrics = _computeEndOfTurnMetrics({\n          speechStartTime,\n          lastSpeakingTime,\n          lastFinalTranscriptTime,\n          now: Date.now(),\n        });\n\n        const committed = await this.hooks.onEndOfTurn({\n          newTranscript: this.audioTranscript,\n          transcriptConfidence: confidenceAvg,\n          transcriptionDelay: metrics.transcriptionDelay,\n          endOfUtteranceDelay: metrics.endOfUtteranceDelay,\n          startedSpeakingAt: metrics.startedSpeakingAt,\n          stoppedSpeakingAt: metrics.stoppedSpeakingAt,\n          backchannelOverAgent: this.turnBackchannelOverAgent,\n        });\n\n        if (committed) {\n          this._endUserTurnSpan({\n            transcript: this.audioTranscript,\n            confidence: confidenceAvg,\n            transcriptionDelay: metrics.transcriptionDelay ?? 0,\n            endOfUtteranceDelay: metrics.endOfUtteranceDelay ?? 0,\n          });\n\n          // clear the transcript if the user turn was committed\n          this.audioTranscript = '';\n          this.finalTranscriptConfidence = [];\n          this.lastFinalTranscriptTime = 0;\n          // Concurrent user speech might have changed it; only reset if there is no new speech.\n          if (this.lastSpeakingTime === lastSpeakingTime) {\n            this.speechStartTime = undefined;\n            this.vadSpeechStarted = false;\n            this.lastSpeakingTime = undefined;\n          }\n\n          // Flush the in-flight request and write the turn-boundary sentinel to\n          // the transport so the next turn's predict starts fresh — the normal\n          // EOU-commit path, mirroring clearUserTurn()'s flush on interrupt.\n          if (this.turnDetectorStream !== undefined) {\n            this.turnDetectorStream.flush('turn committed');\n            this.turnDetectorPredictionFut = undefined;\n            this.turnDetectorFlushed = true;\n          }\n          this.resetTranscriptionTimeout();\n        }\n\n        this.turnBackchannelOverAgent = false;\n        this.overlapInCurrentTurn = false;\n        this.userTurnCommitted = false;\n      };\n\n    // cancel any existing EOU task\n    this.bounceEOUTask?.cancel();\n    // copy the values before awaiting (the values can change)\n    const lastSpeakingTime = this.lastSpeakingTime;\n    const lastFinalTranscriptTime = this.lastFinalTranscriptTime;\n    const speechStartTime = this.userTurnStart;\n\n    this.bounceEOUTask = Task.from(\n      bounceEOUTask(lastSpeakingTime, lastFinalTranscriptTime, speechStartTime),\n    );\n\n    this.bounceEOUTask.result\n      .then(() => {\n        this.logger.debug('EOU detection task completed');\n      })\n      .catch((err: unknown) => {\n        if (err instanceof Error && err.name === 'AbortError') {\n          // ignore aborted errors\n          return;\n        }\n        if (this.closed) return;\n        this.logger.error(err, 'Error in EOU detection task:');\n      });\n  }\n\n  async waitForEndOfTurnTask(): Promise<void> {\n    if (!this.bounceEOUTask || this.bounceEOUTask.done) {\n      return;\n    }\n\n    try {\n      await this.bounceEOUTask.result;\n    } catch (error) {\n      if (error instanceof Error && error.name === 'AbortError') {\n        return;\n      }\n      throw error;\n    }\n  }\n\n  private checkUserTurnLimit(transcript: string): void {\n    const maxWords = this.userTurnLimit?.maxWords ?? null;\n    const maxDuration = this.userTurnLimit?.maxDuration ?? null;\n\n    if (maxWords === null && maxDuration === null) {\n      return;\n    }\n\n    const now = Date.now();\n    this.userTurnTracker.startedAt ??= this.speechStartTime ?? now;\n    this.userTurnTracker.words += splitWords(transcript, true).length;\n    this.userTurnTracker.transcript = `${this.userTurnTracker.transcript} ${transcript}`.trim();\n\n    const duration = now - this.userTurnTracker.startedAt;\n    const timeExceeded = maxDuration !== null && duration >= maxDuration;\n    const wordsExceeded = maxWords !== null && this.userTurnTracker.words >= maxWords;\n\n    if (!timeExceeded && !wordsExceeded) {\n      return;\n    }\n\n    this.hooks.onUserTurnExceeded(\n      createUserTurnExceededEvent({\n        transcript: this.currentTranscript,\n        accumulatedTranscript: this.userTurnTracker.transcript,\n        accumulatedWordCount: this.userTurnTracker.words,\n        duration,\n      }),\n    );\n  }\n\n  private startSttTasks(reusePipeline?: STTPipeline) {\n    if (!this.stt) return;\n\n    this.sttPipeline = reusePipeline ?? new STTPipeline(this.stt);\n\n    this.transcriptBuffer = [];\n    this.ignoreUserTranscriptUntil = undefined;\n    this.sttOwnershipTransferred = false;\n\n    const pipeline = this.sttPipeline;\n\n    this.sttForwardTask = Task.from(({ signal }) => this.forwardInputAudioToStt(pipeline, signal));\n    this.sttForwardTask.result.catch((err) => {\n      this.logger.error(`Error forwarding audio to STT pipeline: ${err}`);\n    });\n\n    this.sttConsumerTask = Task.from(({ signal }) => this.consumeSttEvents(pipeline, signal));\n    this.sttConsumerTask.result.catch((err) => {\n      this.logger.error(`Error running STT task: ${err}`);\n    });\n  }\n\n  private async stopSttTasks() {\n    await this.sttConsumerTask?.cancelAndWait();\n    this.sttConsumerTask = undefined;\n    await this.sttForwardTask?.cancelAndWait();\n    this.sttForwardTask = undefined;\n  }\n\n  async detachSttPipeline(): Promise<STTPipeline | undefined> {\n    const unlock = await this.sttLifecycleLock.lock();\n    try {\n      const pipeline = this.sttPipeline;\n      const consumerTask = this.sttConsumerTask;\n      try {\n        await consumerTask?.cancelAndWait();\n      } finally {\n        if (this.sttConsumerTask === consumerTask) {\n          this.sttConsumerTask = undefined;\n        }\n      }\n\n      this.sttPipeline = undefined;\n      this.sttOwnershipTransferred = pipeline !== undefined;\n\n      return pipeline;\n    } finally {\n      unlock();\n    }\n  }\n\n  private async forwardInputAudioToStt(pipeline: STTPipeline, signal: AbortSignal) {\n    for await (const frame of readStream(this.sttInputStream, signal)) {\n      const frameDurationMs = (frame.samplesPerChannel / frame.sampleRate) * 1000;\n      pipeline.inputStartedAt ??= Date.now() - frameDurationMs;\n      await pipeline.audioChannel.write(frame);\n    }\n  }\n\n  private async consumeSttEvents(pipeline: STTPipeline, signal: AbortSignal) {\n    for await (const ev of readStream(pipeline.eventChannel.stream(), signal)) {\n      await this.onSTTEvent(ev);\n    }\n  }\n\n  private async createVadTask(vad: VAD | undefined, signal: AbortSignal) {\n    if (!vad) return;\n\n    const vadStream = vad.stream();\n    this.vadStream = vadStream;\n    vadStream.updateInputStream(this.vadInputStream);\n\n    const abortHandler = () => {\n      vadStream.detachInputStream();\n      vadStream.close();\n      signal.removeEventListener('abort', abortHandler);\n    };\n    signal.addEventListener('abort', abortHandler);\n\n    try {\n      for await (const ev of vadStream) {\n        if (signal.aborted) break;\n\n        switch (ev.type) {\n          case VADEventType.START_OF_SPEECH:\n            this.logger.debug('VAD task: START_OF_SPEECH');\n            {\n              const startTime = Date.now() - ev.speechDuration - ev.inferenceDuration;\n              if (!this.vadSpeechStarted) {\n                this.speechStartTime = startTime;\n                this.vadSpeechStarted = true;\n              }\n              const span = this.ensureUserTurnSpan(startTime);\n              const ctx = this.userTurnContext(span);\n              this.endpointing.onStartOfSpeech(startTime, this.isAgentSpeaking);\n              this.interruptionDetected = undefined;\n              this.turnBackchannelOverAgent = false;\n              this.overlapInCurrentTurn = this.isAgentSpeaking;\n              otelContext.with(ctx, () => this.hooks.onStartOfSpeech(ev));\n            }\n            this.speaking = true;\n            this.cancelTranscriptionTimeout();\n\n            // Audio EOT: tear down any in-flight inference for the now-stale\n            // prior window and re-arm so the next silence tick starts fresh.\n            this.turnDetectorStream?.cancelInference();\n            this.turnDetectorPredictionFut = undefined;\n            this.turnDetectorFlushed = false;\n\n            // Capture sample rate from the first VAD event if not already set\n            if (ev.frames.length > 0 && ev.frames[0]) {\n              this.sampleRate = ev.frames[0].sampleRate;\n            }\n\n            this.bounceEOUTask?.cancel();\n            break;\n          case VADEventType.INFERENCE_DONE:\n            this.hooks.onVADInferenceDone(ev);\n            // for metrics, get the \"earliest\" signal of speech as possible\n            if (ev.rawAccumulatedSpeech > 0.0) {\n              this.lastSpeakingTime = Date.now();\n\n              if (this.speechStartTime === undefined) {\n                // Backdate speechStartTime to the actual start of accumulated speech.\n                // ev.rawAccumulatedSpeech is in ms (VADEvent durations are all ms in TS).\n                this.speechStartTime = Date.now() - ev.rawAccumulatedSpeech;\n              }\n              // A short intra-segment pause can resolve a request before VAD\n              // emits END_OF_SPEECH. When speech resumes (without a new SOS),\n              // drop that request so the next pause gets a fresh window.\n              if (this.speaking && this.turnDetectorPredictionFut !== undefined) {\n                this.turnDetectorStream?.cancelInference();\n                this.turnDetectorPredictionFut = undefined;\n              }\n            }\n\n            // Audio EOT: start an inference request once we've seen enough\n            // trailing silence (`MIN_SILENCE_DURATION_MS`), but only when no\n            // request is already in flight. The silence tick\n            // is the sole request trigger — and it warms even while the agent\n            // is speaking so an overlapping/interrupting turn still gets a\n            // window.\n            if (\n              ev.rawAccumulatedSilence >= MIN_SILENCE_DURATION_MS &&\n              this.speaking &&\n              this.turnDetectorStream !== undefined &&\n              this.turnDetectorPredictionFut === undefined\n            ) {\n              this.turnDetectorPredictionFut = this.turnDetectorStream.predict();\n            }\n            break;\n          case VADEventType.END_OF_SPEECH:\n            this.logger.debug('VAD task: END_OF_SPEECH');\n            const vadSpeechStarted = this.vadSpeechStarted;\n            {\n              const endTime = Date.now() - ev.silenceDuration - ev.inferenceDuration;\n              const span = this.ensureUserTurnSpan();\n              const ctx = this.userTurnContext(span);\n              if (this.speaking) {\n                this.endpointing.onEndOfSpeech(endTime, this.interruptionDetected);\n              }\n              otelContext.with(ctx, () => this.hooks.onEndOfSpeech(ev));\n            }\n\n            // when VAD fires END_OF_SPEECH, it already waited for the silence_duration\n            this.vadSpeechStarted = false;\n            this.speaking = false;\n            this.lastSpeakingTime = Date.now() - ev.silenceDuration - ev.inferenceDuration;\n\n            // A committed turn clears vadSpeechStarted before its late VAD EOS arrives.\n            if (this.sttPipeline !== undefined && vadSpeechStarted) {\n              this.armTranscriptionTimeout(\n                ev.speechDuration,\n                ev.silenceDuration + ev.inferenceDuration,\n              );\n            }\n\n            // Audio EOT: the silence tick owns request-starting, not\n            // END_OF_SPEECH. EOS consumes the already-armed future (if any)\n            // and runs the eou bounce.\n\n            if (\n              this.vadBaseTurnDetection ||\n              (this.turnDetectionMode === 'stt' && this.userTurnCommitted)\n            ) {\n              const chatCtx = this.hooks.retrieveChatCtx();\n              this.runEOUDetection(chatCtx, 'vad');\n            }\n            break;\n        }\n      }\n    } catch (e) {\n      this.logger.error(e, 'Error in VAD task');\n    } finally {\n      this.logger.debug('VAD task closed');\n      if (this.vadStream === vadStream) {\n        this.vadStream = undefined;\n      }\n\n      if (this.speaking) {\n        const span = this.ensureUserTurnSpan();\n        const ctx = this.userTurnContext(span);\n        otelContext.with(ctx, () => this.hooks.onEndOfSpeech(undefined));\n        this.speaking = false;\n        this.vadSpeechStarted = false;\n      }\n    }\n  }\n\n  private async createInterruptionTask(\n    interruptionDetection: AdaptiveInterruptionDetector | undefined,\n    signal: AbortSignal,\n  ) {\n    if (!interruptionDetection || !this.interruptionStreamChannel) return;\n\n    let numRetries = 0;\n    const maxRetries = apiConnectDefaults.maxRetries;\n\n    while (!signal.aborted) {\n      const stream = interruptionDetection.createStream();\n      const eventReader = stream.stream().getReader();\n\n      const cleanup = async () => {\n        try {\n          signal.removeEventListener('abort', onAbort);\n          eventReader.releaseLock();\n          await stream.close();\n        } catch (e) {\n          this.logger.debug('createInterruptionTask: error during cleanup:', e);\n        }\n      };\n\n      const onAbort = () => {\n        void cleanup();\n      };\n      signal.addEventListener('abort', onAbort, { once: true });\n\n      let forwardTask: Promise<void> | undefined;\n\n      try {\n        // Unlike Python where _agent_speech_started lives on `self` and survives retries,\n        // JS creates a fresh InterruptionStreamBase per retry with agentSpeechStarted = false.\n        // Re-inject the sentinel so the new stream knows the agent is mid-speech.\n        if (numRetries > 0 && this.isAgentSpeaking) {\n          await stream.pushFrame(InterruptionStreamSentinel.agentSpeechStarted());\n        }\n\n        forwardTask = (async () => {\n          const inputReader = this.interruptionStreamChannel!.stream().getReader();\n          const abortPromise = waitForAbort(signal);\n\n          try {\n            while (!signal.aborted) {\n              const res = await ThrowsPromise.race([inputReader.read(), abortPromise]);\n              if (!res) break;\n\n              const { value, done } = res;\n              if (done) break;\n\n              await stream.pushFrame(value);\n            }\n          } finally {\n            inputReader.releaseLock();\n          }\n        })();\n\n        const abortPromise = waitForAbort(signal);\n\n        while (!signal.aborted) {\n          const res = await ThrowsPromise.race([eventReader.read(), abortPromise]);\n          if (!res) break;\n          const { done, value: ev } = res;\n          if (done) break;\n          // A healthy stream delivering events recovers the failover budget, so a later transient\n          // failure isn't charged against earlier ones.\n          numRetries = 0;\n          this.onOverlapSpeechEvent(ev);\n        }\n        break;\n      } catch (e) {\n        if (signal.aborted) break;\n\n        if (isAPIError(e)) {\n          if (maxRetries === 0 || !e.retryable) {\n            interruptionDetection.emitError(\n              new InterruptionDetectionError(\n                e.message,\n                Date.now(),\n                interruptionDetection.label,\n                false,\n              ),\n            );\n            break;\n          } else if (numRetries >= maxRetries) {\n            interruptionDetection.emitError(\n              new InterruptionDetectionError(\n                `failed to detect interruption after ${numRetries} attempts`,\n                Date.now(),\n                interruptionDetection.label,\n                false,\n              ),\n            );\n            break;\n          } else {\n            const retryInterval = intervalForRetry(numRetries);\n            interruptionDetection.emitError(\n              new InterruptionDetectionError(\n                e.message,\n                Date.now(),\n                interruptionDetection.label,\n                true,\n              ),\n            );\n            this.logger.warn(\n              { model: interruptionDetection.label, attempt: numRetries },\n              `failed to detect interruption, retrying in ${retryInterval}ms`,\n            );\n            numRetries++;\n            await delay(retryInterval, { signal });\n          }\n        } else {\n          const msg = e instanceof Error ? e.message : String(e);\n          interruptionDetection.emitError(\n            new InterruptionDetectionError(msg, Date.now(), interruptionDetection.label, false),\n          );\n          this.logger.error(e, 'Error in interruption task');\n          break;\n        }\n      } finally {\n        await cleanup();\n        await forwardTask?.catch((e) => {\n          this.logger.debug({ err: e }, 'interruption task exited with error');\n        });\n      }\n    }\n    this.logger.debug('Interruption task closed');\n  }\n\n  setInputAudioStream(audioStream: ReadableStream<AudioFrame>) {\n    this.deferredInputStream.setSource(audioStream);\n  }\n\n  detachInputAudioStream() {\n    this.deferredInputStream.detachSource();\n  }\n\n  /**\n   * Returns an independent ReadableStream of input audio frames. Each call\n   * returns a fresh branch fed by the broadcast transform inserted into the\n   * deferred input pipeline — frames written after the subscription point\n   * will be delivered, but earlier frames are not replayed.\n   *\n   * Used by AMD when its private STT needs the same participant audio that\n   * the pipeline is processing without consuming it (see python AMD\n   * detector pushing audio into `_AMDClassifier.push_audio`).\n   */\n  subscribeAudioStream(): ReadableStream<AudioFrame> {\n    const transform = new IdentityTransform<AudioFrame>();\n    const writer = transform.writable.getWriter();\n    this.subscriberWriters.push(writer);\n    // Auto-prune the entry once the subscriber's readable side is cancelled\n    // or its writer otherwise errors. Without this, a subscriber that hands\n    // back its stream (e.g. AMD's STT pump after `aclose()`) leaves a writer\n    // in `subscriberWriters` that the broadcast transform keeps writing into\n    // — frames pile up in the IdentityTransform queue until\n    // `AudioRecognition.close()` runs, leaking ~16-32 KB/s.\n    writer.closed\n      .catch(() => {\n        // closed/errored — fall through to the prune below\n      })\n      .finally(() => {\n        const idx = this.subscriberWriters.indexOf(writer);\n        if (idx >= 0) this.subscriberWriters.splice(idx, 1);\n      });\n    return transform.readable;\n  }\n\n  clearUserTurn() {\n    this.audioTranscript = '';\n    this.audioInterimTranscript = '';\n    this.audioPreflightTranscript = '';\n    this.finalTranscriptConfidence = [];\n    this.lastFinalTranscriptTime = 0;\n    this.speechStartTime = undefined;\n    this.userTurnStart = undefined;\n    this.lastSpeakingTime = undefined;\n    this.vadSpeechStarted = false;\n    this.speaking = false;\n    this.userTurnCommitted = false;\n    this.userTurnTracker = { words: 0, transcript: '' };\n    this.resetTranscriptionTimeout();\n    // New turn → allow the next window's prediction to emit.\n    this.lastEmittedEotPrediction = undefined;\n\n    // Any in-flight request on the audio stream belongs to the turn we\n    // just cleared — flush it so the next predict starts fresh.\n    if (this.turnDetectorStream !== undefined) {\n      this.turnDetectorStream.flush('clear_user_turn');\n      this.turnDetectorPredictionFut = undefined;\n      this.turnDetectorFlushed = true;\n    }\n\n    this._endUserTurnSpan();\n\n    const restartStt = async () => {\n      const unlock = await this.sttLifecycleLock.lock();\n      try {\n        if (!this.stt || this.sttOwnershipTransferred) {\n          return;\n        }\n\n        await this.stopSttTasks();\n        await this.sttPipeline?.close();\n        this.sttPipeline = undefined;\n\n        if (this.sttOwnershipTransferred) {\n          return;\n        }\n\n        this.startSttTasks();\n      } finally {\n        unlock();\n      }\n    };\n\n    void restartStt().catch((err) => {\n      this.logger.error(`Error resetting STT task: ${err}`);\n    });\n  }\n\n  /**\n   * Reset the VAD by restarting its task. This is needed when STT sends a premature\n   * end-of-turn signal while the user is still speaking, so VAD can detect new speech\n   * and trigger interruptions correctly.\n   */\n  private resetVad() {\n    void this.resetVadTask().catch((err) => {\n      this.logger.error(`Error resetting VAD task: ${err}`);\n    });\n  }\n\n  private async resetVadTask(): Promise<void> {\n    const unlock = await this.vadLifecycleLock.lock();\n    try {\n      if (!this.vad || this.closed) return;\n      await this.vadTask?.cancelAndWait();\n      if (!this.closed && this.vad !== undefined) {\n        this.startVadTask(this.vad);\n      }\n    } finally {\n      unlock();\n    }\n  }\n\n  private startVadTask(vad: VAD): void {\n    this.vadTask = Task.from(({ signal }) => this.createVadTask(vad, signal));\n    this.vadTask.result.catch((err) => {\n      this.logger.error(`Error running VAD task: ${err}`);\n    });\n  }\n\n  commitUserTurn(audioDetached: boolean) {\n    const commitUserTurnTask =\n      (delayDuration: number = 500) =>\n      async (controller: AbortController) => {\n        if (Date.now() - this.lastFinalTranscriptTime > delayDuration) {\n          // flush the stt by pushing silence\n          if (audioDetached && this.sampleRate !== undefined) {\n            const silenceFrame = createSilenceFrame(delayDuration, this.sampleRate);\n            this.silenceAudioWriter.write(silenceFrame);\n          }\n\n          // wait for the final transcript to be available\n          await delay(delayDuration, { signal: controller.signal });\n        }\n\n        if (this.audioInterimTranscript) {\n          // append interim transcript in case the final transcript is not ready\n          this.audioTranscript = `${this.audioTranscript} ${this.audioInterimTranscript}`.trim();\n        }\n        this.audioInterimTranscript = '';\n\n        const chatCtx = this.hooks.retrieveChatCtx();\n        this.logger.debug('running EOU detection on commitUserTurn');\n        this.runEOUDetection(chatCtx, 'manual');\n        this.userTurnCommitted = true;\n      };\n\n    // cancel any existing commit user turn task\n    this.commitUserTurnTask?.cancel();\n    this.commitUserTurnTask = Task.from(commitUserTurnTask());\n\n    this.commitUserTurnTask.result\n      .then(() => {\n        this.logger.debug('User turn committed');\n      })\n      .catch((err: unknown) => {\n        if (err instanceof Error && err.name === 'AbortError') {\n          this.logger.debug('User turn commit task cancelled');\n          return;\n        }\n        if (this.closed) return;\n        this.logger.error(err, 'Error in user turn commit task:');\n      });\n  }\n\n  async close() {\n    this.closed = true;\n    this.closeWakeController.abort();\n    this.overlapOpen = false;\n    this.detachInputAudioStream();\n    this.silenceAudioWriter.releaseLock();\n    // WARNING: These tasks are intentionally allowed to finish so the final user turn is not\n    // lost. Cleanup can therefore continue past the worker's session-close timeout.\n    if (this.commitUserTurnTask) {\n      try {\n        await this.commitUserTurnTask.result;\n      } catch (error) {\n        if (!(error instanceof Error && error.name === 'AbortError')) {\n          this.logger.warn(\n            { errorType: error instanceof Error ? error.constructor.name : typeof error },\n            'error while committing the final user turn on close',\n          );\n        }\n      }\n    }\n    await this.stopSttTasks();\n\n    if (this.sttPipeline) {\n      await this.sttPipeline.close();\n      this.sttPipeline = undefined;\n    }\n\n    // Close any outstanding broadcast subscribers so their consumers see EOF\n    // and don't keep the IdentityTransform queues pinned in memory.\n    for (const writer of this.subscriberWriters) {\n      try {\n        await writer.close();\n      } catch {\n        // already closed / aborted\n      }\n    }\n    this.subscriberWriters = [];\n\n    await this.vadTask?.cancelAndWait();\n    if (this.bounceEOUTask) {\n      try {\n        await this.bounceEOUTask.result;\n      } catch (error) {\n        if (!(error instanceof Error && error.name === 'AbortError')) {\n          this.logger.warn(\n            { errorType: error instanceof Error ? error.constructor.name : typeof error },\n            'error while completing the final user turn on close',\n          );\n        }\n      }\n    }\n    await this.interruptionTask?.cancelAndWait();\n\n    if (this.turnDetectorStream !== undefined) {\n      const stream = this.turnDetectorStream;\n      this.turnDetectorStream = undefined;\n      await stream.aclose().catch(() => undefined);\n    }\n\n    await this.interruptionStreamChannel?.close();\n    this.cancelBackchannelBoundary();\n    // Cancel last, after the VAD consumer is torn down: a buffered\n    // END_OF_SPEECH processed earlier in close() can otherwise re-arm the timer.\n    this.cancelTranscriptionTimeout();\n\n    // A speech segment may never produce a transcript or committed turn. End\n    // its span after all recognition tasks stop so it is still exported.\n    this._endUserTurnSpan();\n  }\n\n  private cancelTranscriptionTimeout(): void {\n    if (this.transcriptionTimeoutTimer !== undefined) {\n      clearTimeout(this.transcriptionTimeoutTimer);\n      this.transcriptionTimeoutTimer = undefined;\n    }\n  }\n\n  private resetTranscriptionTimeout(): void {\n    this.cancelTranscriptionTimeout();\n    this.turnSpeechDuration = 0;\n    this.turnTranscriptReceived = false;\n  }\n\n  private markTurnTranscribed(): void {\n    this.turnTranscriptReceived = true;\n    this.cancelTranscriptionTimeout();\n  }\n\n  private armTranscriptionTimeout(speechDuration: number, elapsedDelay: number): void {\n    if (this.closed) {\n      return;\n    }\n\n    if (this.transcriptionTimeout === undefined || this.turnTranscriptReceived) {\n      return;\n    }\n\n    this.turnSpeechDuration += speechDuration;\n    this.cancelTranscriptionTimeout();\n    const remainingTimeout = Math.max(0, this.transcriptionTimeout - elapsedDelay);\n    this.transcriptionTimeoutTimer = setTimeout(\n      () => this.onTranscriptionTimeout(),\n      remainingTimeout,\n    );\n  }\n\n  private onTranscriptionTimeout(): void {\n    this.transcriptionTimeoutTimer = undefined;\n    if (this.userTurnStart === undefined || this.turnTranscriptReceived) {\n      return;\n    }\n    this.hooks.onTranscriptionTimeout(this.turnSpeechDuration, this.userTurnStart);\n  }\n\n  private _endUserTurnSpan(info?: {\n    transcript: string;\n    confidence: number;\n    transcriptionDelay: number;\n    endOfUtteranceDelay: number;\n  }): void {\n    if (this.userTurnSpan && info) {\n      this.userTurnSpan.setAttributes({\n        [traceTypes.ATTR_USER_TRANSCRIPT]: info.transcript,\n        [traceTypes.ATTR_TRANSCRIPT_CONFIDENCE]: info.confidence,\n        [traceTypes.ATTR_TRANSCRIPTION_DELAY]: info.transcriptionDelay,\n        [traceTypes.ATTR_END_OF_TURN_DELAY]: info.endOfUtteranceDelay,\n      });\n      if (this.sttRequestIds.length) {\n        this.userTurnSpan.setAttribute(traceTypes.ATTR_PROVIDER_REQUEST_IDS, this.sttRequestIds);\n      }\n    }\n    if (this.userTurnSpan?.isRecording()) {\n      this.userTurnSpan.end();\n    }\n    this.userTurnSpan = undefined;\n    this.userTurnStart = undefined;\n    this.sttRequestIds = [];\n  }\n\n  private get vadBaseTurnDetection() {\n    if (typeof this.turnDetectionMode === 'object') {\n      return false;\n    }\n\n    if (this.turnDetectionMode === undefined || this.turnDetectionMode === 'vad') {\n      return true;\n    }\n\n    return false;\n  }\n}\n"],"mappings":"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","names":["import_utils","eventsToEmit","otelContext","lastSpeakingTime","lastFinalTranscriptTime","speechStartTime","abortPromise"]}