When calling `session.say()` inside `tts_node()`, ...
# ask-ai
b
When calling
session.say()
inside
tts_node()
, what guarantees exist about suppression of further yields? Is there an integrated mechanism to prevent
tts_node()
from continuing and yielding after a
session.say()
call?
t
Thanks for reaching out, Patrick. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — you're asking whether calling
session.say()
inside
tts_node()
automatically suppresses further yields or stops the node from continuing. Short answer: It does not. There is no built‑in guarantee that
session.say()
will halt the current
tts_node()
execution or prevent further yields. What this means and what you can do: •
session.say()
schedules speech (returns a
SpeechHandle
) via the agent's speech queue, but scheduling is independent of the
tts_node()
control flow. • If you want
tts_node()
to stop yielding after calling
session.say()
, implement that yourself: ◦ Return early from
tts_node()
immediately after
session.say()
. ◦ Or set and check a control flag (e.g.,
should_stop
) before each yield and exit when set. ◦ If you need to cancel in‑flight speech, use the interruption/cancel mechanisms provided by the speech system. If you want, tell me which behavior you want (e.g., immediate stop, finish current chunk then stop, or cancel scheduled speech) and I’ll suggest a specific code pattern. Sources: Pipeline nodes and hooks | LiveKit docs | Agent speech and audio | LiveKit docs
b
When
session.say()
is invoked inside the same agent turn, how does LiveKit’s internal TTS pipeline reconcile generator yields vs explicit TTS calls? Is there a recommended pattern to avoid double speech?
t
You're asking how LiveKit reconciles
tts_node()
generator yields with
session.say()
invoked in the same agent turn, and how to avoid double/overlapping speech. Short answer: LiveKit does not automatically reconcile them. If
session.say()
is called while
tts_node()
is yielding, both can produce audio unless you coordinate them. Recommended patterns to avoid double speech • Use one mechanism per turn: ◦ Prefer
tts_node()
for LLM-driven replies. ◦ Use
session.say()
only for injected/short phrases (greetings, interrupts). • Return or stop the generator after calling `session.say()`: ◦ Call
return
from
tts_node()
or set a control flag checked before yielding further frames. • Interrupt/cancel current speech before calling `session.say()`: ◦ Call
session.interrupt()
or interrupt the active
SpeechHandle
, then
await
cancellation if needed, then call
session.say()
. • Chain via separate turns when injecting speech: ◦ Interrupt →
session.say()
→ start a new
generate_reply()
if follow-up LLM output is needed. • Use pre-synthesized audio to bypass TTS: ◦ Call
session.say(audio=...)
with prepared frames so
tts_node()
is not involved. If you tell me which behavior you want (immediate stop, finish current chunk then stop, or cancel queued speech), I’ll provide a concise code pattern you can plug into your
tts_node()
implementation. Sources: Agent speech and audio | LiveKit docs | Pipeline nodes and hooks | LiveKit docs | Interrupt User | LiveKit docs | Turns overview | LiveKit docs | Text and transcriptions | LiveKit docs