rapid-painting-51133
12/17/2025, 6:43 PMtall-airline-16756
12/17/2025, 6:43 PMtall-airline-16756
12/17/2025, 6:44 PMkind for AGENT.
JavaScript:
room.on('participantDisconnected', (participant) => {
if (participant.kind === 'AGENT') {
console.log('Agent disconnected:', participant.identity);
// handle agent disconnect
}
});
Python:
@room.on("participant_disconnected")
def on_participant_disconnected(participant):
if participant.kind == proto.ParticipantInfo.Kind.AGENT:
print(f"Agent disconnected: {participant.identity}")
# handle agent disconnect
Go:
room.OnParticipantDisconnected(func(p *livekit.RemoteParticipant) {
if p.Kind() == livekit.ParticipantInfo_AGENT {
log.Printf("Agent disconnected: %s", p.Identity())
// handle agent disconnect
}
})
If you want, I can show how to also listen for agent_state_changed or handle reconnect vs. graceful leave—which would you prefer?
Sources: Rooms, participants, and tracks | LiveKit docs | Events and error handling | LiveKit docsrapid-painting-51133
12/17/2025, 6:45 PMtall-airline-16756
12/17/2025, 6:45 PMdef on_participant_disconnected(participant: RemoteParticipant):
if participant.kind != proto.ParticipantInfo.Kind.AGENT:
return
<http://LOGGER.info|LOGGER.info>("Agent %s disconnected, deleting room", participant.identity)
asyncio.create_task(delete_room(self.ctx))
1. Make delete_room resilient to errors and idempotent:
async def delete_room(ctx: agents.JobContext) -> None:
try:
await ctx.api.room.delete_room(DeleteRoomRequest(room=ctx.job.room.name))
<http://LOGGER.info|LOGGER.info>("Room %s deleted", ctx.job.room.name)
except Exception as e:
LOGGER.exception("Failed deleting room %s: %s", ctx.job.room.name, e)
1. Consider race conditions / multiple disconnect events:
• If multiple participants could trigger deletion, detect if the room already deleted or check a guard flag on the job/context before creating the task.
Would you like a version that handles reconnect vs. leave (graceful vs. network dropout) or a guard example to prevent duplicate delete attempts?rapid-painting-51133
12/17/2025, 6:54 PMtall-airline-16756
12/17/2025, 6:54 PMparticipant_disconnected hook fires for any participant who leaves the room — that includes LiveKit agents and remote SIP participants.
Differentiate them by checking participant.kind (agent participants have kind AGENT). If you need more granularity about an agent's local state (e.g., agent-side detected disconnect vs. network blip), you can also listen for agent_state_changed on the agent side.
Would you like a short code snippet that ignores non-agent disconnects and debounces duplicate delete attempts?rapid-painting-51133
12/17/2025, 6:55 PMtall-airline-16756
12/17/2025, 6:55 PMagent_state_changed hook is — it’s an AgentSession event that notifies you when an agent's internal state changes (e.g., initializing, listening, thinking, speaking).
What it provides:
• Emitted by the AgentSession as an AgentStateChangedEvent.
• Contains old_state and new_state.
• new_state is mirrored in the participant attribute lk.agent.state for frontend use.
Why use it:
• Update UI (listening/processing/speaking indicators).
• Coordinate audio playback or logging.
• Trigger backend logic when the agent begins/stops speaking or starts thinking.
Examples:
Python:
from livekit.agents import AgentStateChangedEvent
@session.on("agent_state_changed")
def on_agent_state_changed(event: AgentStateChangedEvent):
print(f"Agent state changed from {event.old_state} to {event.new_state}")
if event.new_state == "speaking":
# handle start speaking
Node/TS:
session.on(voice.AgentSessionEventTypes.AgentStateChanged, (event) => {
console.log(`Agent state changed from ${event.oldState} to ${event.newState}`);
if (event.newState === 'speaking') {
// handle start speaking
}
});
Notes for disconnect detection:
• agent_state_changed tracks runtime behavior, not full session end.
• To detect full disconnects, also listen for AgentSession close and room participant_disconnected (check participant.kind === 'AGENT'). Sources: Events and error handling | LiveKit docs | Web and mobile frontends | LiveKit docsrapid-painting-51133
12/17/2025, 7:00 PMtall-airline-16756
12/17/2025, 7:01 PMadd_shutdown_callback — it runs when the agent session is shutting down. Triggers include:
• The session is ended explicitly via session.shutdown() or ctx.shutdown().
• The room closes because the last non-agent participant leaves.
• The agent server receives a termination signal (SIGTERM/SIGINT/SIGQUIT) and finishes draining active sessions.
Register the callback with `ctx.add_shutdown_callback(fn)`; it will run during the session's post-shutdown cleanup (useful for saving state, logging, or releasing resources).
Sources: Distributed Setup | LiveKit docs | Agent server | LiveKit docs | Job lifecycle | LiveKit docs | Observability data hooks | LiveKit docs