Skip to content

FallbackAdapter throws "no audio received" on tool-only LLM turns (empty token stream) #1454

@ubinatus

Description

@ubinatus

Symptom

FallbackSynthesizeStream throws APIConnectionError("TTS stream completed but no audio was received") and triggers markUnAvailable + cascade to the next provider on turns where the LLM emits zero spoken text — e.g., a turn that only contains a tool/function call.

In production this manifests as recurring spurious failover storms (and skewed provider availability metrics) on agents that use tool calls.

Root cause

In agents/src/tts/fallback_adapter.ts, forwardBufferToTTS may consume the LLM stream and forward only sentinel tokens (FLUSH_SENTINEL, END_OF_STREAM) without ever calling stream.pushText(...). The provider correctly returns no audio because nothing was sent to synthesize. The adapter then hits if (!sawRawAudio) and throws, which:

  • marks the first provider unavailable,
  • retries through the rest of the fallback chain,
  • ultimately raises all TTS instances failed,
  • so a benign tool-only turn looks like a multi-provider outage.

Repro

Run an agent with a FallbackAdapter([ttsA, ttsB]) and any LLM/flow that produces a turn whose content is a tool call with no text field. The first synth attempt throws "no audio received"; the second does the same; the run errors with "all TTS instances failed".

Proposed fix

Track whether any text token was actually pushed inside forwardBufferToTTS. In the !sawRawAudio branch, if zero text tokens were ever forwarded, treat it as a clean no-op turn:

  • emit SynthesizeStream.END_OF_STREAM downstream,
  • await the input LLM stream read,
  • return without throwing.

Keep the existing behavior (throw + failover) for the real failure case (text was sent, no audio came back).

Affected version

@livekit/agents@1.4.0 (and earlier 1.3.x — same code path).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions