narrow-chef-71655
04/03/2026, 3:22 PM2026-04-03T13:49:14.870491124Z INFO:livekit:livekit::room:1506:livekit::room - disconnected from room with reason: RoomClosed
2026-04-03T13:49:14.871844042Z ERROR:livekit.agents:Error in _start_task
2026-04-03T13:49:14.871872948Z Traceback (most recent call last):
2026-04-03T13:49:14.871879421Z File "/usr/local/lib/python3.13/site-packages/livekit/agents/utils/log.py", line 17, in async_fn_logs
2026-04-03T13:49:14.871884102Z return await fn(*args, **kwargs)
2026-04-03T13:49:14.871888366Z ^^^^^^^^^^^^^^^^^^^^^^^^^
2026-04-03T13:49:14.871893097Z File "/usr/local/lib/python3.13/site-packages/livekit/agents/voice/avatar/_datastream_io.py", line 96, in _start_task
2026-04-03T13:49:14.871903502Z await utils.wait_for_participant(room=self._room, identity=self._destination_identity)
2026-04-03T13:49:14.871908196Z File "/usr/local/lib/python3.13/site-packages/livekit/agents/utils/participant.py", line 113, in wait_for_participant
2026-04-03T13:49:14.871910965Z return await fut
2026-04-03T13:49:14.871913489Z ^^^^^^^^^
2026-04-03T13:49:14.871916083Z RuntimeError: room disconnected while waiting for participant
2026-04-03T13:49:14.871918672Z Traceback (most recent call last):
2026-04-03T13:49:14.871921225Z File "/usr/local/lib/python3.13/site-packages/livekit/agents/utils/log.py", line 17, in async_fn_logs
2026-04-03T13:49:14.871923758Z return await fn(*args, **kwargs)
2026-04-03T13:49:14.871926270Z ^^^^^^^^^^^^^^^^^^^^^^^^^
2026-04-03T13:49:14.871928821Z File "/usr/local/lib/python3.13/site-packages/livekit/agents/voice/avatar/_datastream_io.py", line 96, in _start_task
2026-04-03T13:49:14.871931299Z await utils.wait_for_participant(room=self._room, identity=self._destination_identity)
2026-04-03T13:49:14.871933781Z File "/usr/local/lib/python3.13/site-packages/livekit/agents/utils/participant.py", line 113, in wait_for_participant
2026-04-03T13:49:14.871936243Z return await fut
2026-04-03T13:49:14.871938810Z ^^^^^^^^^
2026-04-03T13:49:14.871941408Z RuntimeError: room disconnected while waiting for participant
2026-04-03T13:49:14.873166242Z INFO:livekit.agents:process exitingtall-airline-16756
04/03/2026, 3:22 PMtall-airline-16756
04/03/2026, 3:23 PMRoomClosed. I'll walk through what this means, likely causes, and practical next steps to prevent or handle it.
What the error means
• Your agent called wait_for_participant(...) while connected to a LiveKit room and was blocking until a specific participant joined.
• The room connection ended (log shows reason: RoomClosed) before that participant arrived, so wait_for_participant raised RuntimeError: room disconnected while waiting for participant.
Likely causes
• The room was deleted or closed (for example via a DeleteRoom API call) before the participant joined.
• The room auto-closed because no participants connected and the room’s idle/departure timeout expired.
• The client you expected to join never connected or disconnected prematurely.
• The agent lost its connection (job context disconnected) while waiting; the agent framework does not automatically reconnect after a RoomClosed event.
What you can do right now
1. Confirm the room lifecycle events
◦ Check whether something (an API call or admin action) deleted or explicitly closed the room around the same timestamp.
◦ Check client-side logs for the participant you expected to join to see whether they attempted to connect and whether their connection succeeded or failed.
1. Add graceful error handling around wait_for_participant
◦ Catch the RuntimeError and:
▪︎ Log the event with room/identity/job IDs for correlation.
▪︎ Retry waiting a small number of times with a short backoff if the room is reconnectable in your flow.
▪︎ Or abort the agent task cleanly and mark the job as failed/safe-stop so it doesn’t hang.
1. Consider these mitigations depending on your workflow
◦ Ensure the participant joins promptly after the agent starts waiting — e.g., coordinate signaling so agent starts only after an initial client join attempt.
◦ If rooms auto-close due to idle time, increase the room idle/departure timeout (if applicable) so the room remains open long enough for the participant to join.
◦ If external services might delete rooms, add checks for room existence before starting wait logic and handle deletions explicitly.
Suggested code-level approach (conceptual)
1. Wrap wait_for_participant in try/except:
◦ On success: continue normal flow.
◦ On RuntimeError with room closed: either retry connect/ wait a configurable number of times OR exit gracefully and surface a clear error.
1. Optional: poll room state before waiting:
◦ If the room is already closed/marked for deletion, skip waiting and handle the condition immediately.
Information that would help me give a targeted fix
• Are your agents started automatically when a room is created, or do you start them after a participant connects?
• Do you have any logic that programmatically deletes rooms, or are you relying on an idle timeout?
• The job/room IDs and timestamps around 2026-04-03T134914 (if you can share) to correlate server-side events and confirm whether a DeleteRoom call or idle timeout occurred.
• A short snippet of how you call wait_for_participant (or agent start/connect flow) so I can suggest exact try/except and retry logic.
If you share one or two of those details I’ll give a concise example of robust error handling and retry logic tailored to your code.
Sources: Agent session | LiveKit Documentation | Understanding the STATE_MISMATCH Disconnect Reason | LiveKit | Job lifecycle | LiveKit Documentation | Handling asynchronous metadata updates in LiveKit | LiveKit, with interactive elementsnarrow-chef-71655
04/05/2026, 3:51 PMtall-airline-16756
04/05/2026, 3:51 PMthinking_sound (it plays during the agent’s "thinking" state, which includes tool calls).
• Built-in clips: BuiltinAudioClip.KEYBOARD_TYPING, KEYBOARD_TYPING2, and OFFICE_AMBIENCE.
• You can also play local files or stream raw audio frames.
Two ways to apply it
• Automatic during tool calls: configure BackgroundAudioPlayer(thinking_sound=[...]) and start it for the agent/session; the sound will play during tool execution.
• Manual for a specific tool: call background_audio.play("/path/to/typing.mp3") (and stop when done) from the tool’s logic for precise control.
Example (conceptual Python)
background_audio = BackgroundAudioPlayer(
thinking_sound=[
AudioConfig(BuiltinAudioClip.KEYBOARD_TYPING, volume=0.8),
],
)
await background_audio.start(room=ctx.room, agent_session=session)
# Or play on-demand inside a tool
await background_audio.play("/path/to/typing.mp3")
# ...run tool...
await background_audio.stop()
Questions to tailor this for you
• Do you want the sound only for one specific tool or for all tool calls?
• Are you using built-in clips or custom audio files?
• Do you need randomization/probabilities or varying volume?
Tell me those and I’ll provide the exact code snippet and placement for your agent/tool.
Sources: Background audio | LiveKit Documentation | Bring your LangChain Agents to LiveKit | LiveKit, with interactive elementsnarrow-chef-71655
04/05/2026, 3:52 PMtall-airline-16756
04/05/2026, 3:52 PMawait background_audio.play(...) with a built-in clip (BuiltinAudioClip.KEYBOARD_TYPING) or a file path.
3. Run the tool work.
4. Immediately call await background_audio.stop() when the tool finishes (or on error).
Concise example (conceptual Python)
# created once and passed into tool or accessible from context
background_audio = BackgroundAudioPlayer()
async def my_tool(ctx, ...):
await background_audio.play(BuiltinAudioClip.KEYBOARD_TYPING) # start typing sound
try:
# perform the tool's work (avoid calling LLM here if you don't want sound during LLM)
result = await do_tool_work(...)
finally:
await background_audio.stop() # ensure it always stops
return result
Notes
• Ensure the LLM call is outside the play/stop window (or pause/stop audio before LLM).
• You can use built-in clips, local files, or raw audio frames.
• Use try/finally to guarantee stopping on errors.
Do you want a full copy-paste-ready snippet for your agent framework (Python) including imports and initialization?
, with interactive elementsnarrow-chef-71655
04/05/2026, 4:14 PMtall-airline-16756
04/05/2026, 4:15 PMnarrow-chef-71655
04/06/2026, 7:44 AMtall-airline-16756
04/06/2026, 7:44 AMexecute (or equivalent) method, start the audio, run the tool work, then stop audio in a try/finally so LLM calls aren’t covered.
Example (concise)
background_audio = BackgroundAudioPlayer()
async def my_tool_execute(ctx, args):
await background_audio.play(BuiltinAudioClip.KEYBOARD_TYPING)
try:
result = await do_tool_work(args) # no LLM calls inside here if you don't want audio during LLM
finally:
await background_audio.stop()
return result
2) If you prefer a callback / central hook
• There isn’t a documented built-in tool_execution_started_cb event name guaranteed across versions, but you can detect tool calls by:
◦ Listening to conversation events such as function_call / function_call_output emitted by the AgentSession, or
◦ Observing agent state transitions (-> "thinking") which correspond to tool execution.
Conceptual example listening on session events:
def on_conversation_item(event):
if event.type == "function_call" and event.function_name == "my_tool":
await background_audio.play(BuiltinAudioClip.KEYBOARD_TYPING)
if event.type == "function_call_output" and event.function_name == "my_tool":
await background_audio.stop()
What I recommend
• Preferred: implement start/stop inside the tool’s execute so it’s precise and guaranteed to only wrap that tool.
• Alternate: subscribe to session conversation events if you need a centralized callback for multiple tools.
Tell me which SDK/version you’re using (Python agent version) and whether you want per-tool code or a global listener, and I’ll provide a copy-paste-ready snippet tailored to your setup.
Sources: Background audio | LiveKit Documentation | Agent session | LiveKit Documentation | Testing and evaluation | LiveKit Documentation | Turns overview | LiveKit Documentation, with interactive elementsnarrow-chef-71655
04/06/2026, 7:52 AMtall-airline-16756
04/06/2026, 7:53 AMfunction_call events in the session. Let’s troubleshoot and get it working.
Quick checklist (please confirm each):
• Which SDK and livekit-agents version are you using (Python or Node.js and the exact package version)?
• Are your event handlers registered before you start the session (handlers must be attached prior to session.start() / AgentSession run)?
• Are your tools defined as function tools (@function_tool in Python or llm.tool() in Node.js)? Only those generate function call items.
• Do you see any conversation events at all (e.g., conversation_item_added for regular messages)? If not, the session may not be started or events not wired correctly.
How to subscribe (Python)
• Register for conversation items (tool calls appear as items with type function_call):
@session.on("conversation_item_added")
async def on_conversation_item_added(event):
item = event.item
if getattr(item, "type", None) == "function_call" and item.name == "my_tool":
await background_audio.play(BuiltinAudioClip.KEYBOARD_TYPING)
if getattr(item, "type", None) == "function_call_output" and item.name == "my_tool":
await background_audio.stop()
Notes:
• Use "conversation_item_added" as the event name (not "function_call" directly).
• Ensure this decorator/handler is registered before session.start().
Alternate detection method
• Listen for agent state transitions (-> "thinking") as a fallback; tool execution maps to the thinking state:
@session.on("agent_state_changed")
async def on_state_changed(ev):
if ev.new_state == "thinking":
# start audio (but this is coarse-grained)
elif ev.new_state == "speaking":
# stop audio
If you still get no function_call items, provide:
• SDK and package version,
• A minimal snippet showing how you register handlers and start the session,
• One example tool definition (so I can confirm tool registration syntax).
Tell me those and I’ll give a copy-paste-ready listener + BackgroundAudioPlayer integration for your exact setup.
Sources: Agent session | LiveKit Documentation | Testing and evaluation | LiveKit Documentation | Function tool definition | LiveKit Documentation, with interactive elements