The Speech Lifecycle and State Machine
How Flux TTS models a conversation as turns — Idle, Generating, Finalizing, Closing — and which events fire at each boundary.
Flux TTS reframes synthesis from a text-to-audio pipe into a turn-based conversation. You own turn boundaries (Flush) and content; the server handles streaming and lifecycle reporting. This page explains the state machine that connects your Client Messages to the Server Messages you receive.
Early Access. This describes the EA lifecycle, where a turn ends with Flush. Barge-in (Interrupt, which cancels a turn mid-generation and reports what was heard) is planned for GA.
Vocabulary
Getting the unit right is the key to reasoning about the protocol:
- Chunk — the text payload of one
Speakmessage. Size is up to you: a single LLM token or a full paragraph. Chunk boundaries do not drive synthesis. - Turn — one complete agent response, bounded by
Flush. The turn is the customer-facing reporting unit:SpeechStartedfires once at the start, andSpeechMetadatafires once at the end. speech_id— the server-assigned identifier for a turn (dg_sp_<12 hex>). Informational; a new one is minted at the start of each turn.
The server holds one active turn at a time. If you Flush and then send more Speak before the active turn finishes, the new turn is pending — pending turns queue behind the active one (there’s no limit) and become active in order.
You stream chunks; the server groups them into a turn; the wire reports per turn.
States
Voice consistency carries across turns. The model keeps conversational state across the turns it generates, so prosody stays consistent from turn to turn — with no API surface to manage. See Cross-Turn Context.
Key rules
- The first
Speak(fromIdle) starts a turn. The server assigns aspeech_idand emitsSpeechStarted.speech_idis turn-scoped — it represents one agent turn. - Subsequent
Speakmessages append to the active turn. The server streams that turn’s audio as text arrives — you don’t have toFlushto start hearing audio. SpeechStartedandSpeechMetadatabookmark a turn’s audio. Every audio frame for a turn arrives between them, andSpeechMetadatais the server’s signal that no more audio is coming for that turn.- Manual
Flushfinalizes the active turn: the server finishes its remaining audio, emitsFlushedwhen the buffer has actually been flushed, thenSpeechMetadata. - One active turn at a time. A
Speaksent after youFlush(but before that turn’sSpeechMetadata) starts a pending turn; it becomes active once the current turn’sSpeechMetadatais sent, and gets its ownSpeechStarted. SessionMetadatais sent once before close, with cumulative totals.
Edge cases
A turn, end to end
A single agent turn that completes normally — the agent says “Sure, I can help you cancel your subscription,” streamed as LLM tokens and ended with a manual Flush. The exchange is shown as alternating client and server steps.
1. The client streams tokens. The first Speak starts the turn.
2. The server opens the turn and streams audio.
3. The client ends the turn.
4. The server finishes the audio and reports the turn. All of the turn’s audio has arrived between SpeechStarted and this SpeechMetadata.
The next Speak begins a new turn with a new speech_id.
Related resources
- Client Messages — the messages that drive these transitions
- Server Messages — full reference for each event above
- Build a Flux TTS Voice Agent — the state machine in a real agent loop
- Cross-Turn Context — what persists across turns