witty-kangaroo-6889
07/23/2025, 10:49 AMtall-airline-16756
07/23/2025, 10:49 AMtall-airline-16756
07/23/2025, 10:52 AMctx.shutdown() is explicitly called in your code
• When the room gets disconnected
• When the worker receives a shutdown signal from the LiveKit server
During shutdown, all registered shutdown callbacks are executed concurrently after the room is disconnected. These callbacks are typically used for cleanup tasks, such as saving user state or writing transcripts.
Shutdown callbacks should complete quickly. By default, the framework waits 60 seconds before forcefully terminating the agent process, but this timeout can be adjusted using the shutdown_process_timeout parameter in WorkerOptions.
You can register a shutdown callback using ctx.add_shutdown_callback in your agent code.
Shutdown callbacks can also receive the shutdown reason as a parameter if needed.
Sources: Inside a session | LiveKit Docs | tests/test_ipc.pywitty-kangaroo-6889
07/23/2025, 11:13 AMtall-airline-16756
07/23/2025, 11:14 AMasync def entrypoint(ctx: JobContext):
# Perform some work here
...
# Shutdown the agent with a reason
ctx.shutdown(reason="Session ended")
Want a more robust example that covers error handling too? Check this out:
async def entrypoint(ctx: JobContext):
<http://logger.info|logger.info>(f"connecting to room {ctx.room.name}")
await ctx.connect()
try:
# Perform some agent work here
await some_agent_task()
ctx.shutdown(reason="Task completed successfully")
except Exception as e:
logger.error(f"Error during agent execution: {e}")
ctx.shutdown(reason="Agent encountered an error")
So, what's the deal with ctx.shutdown()? It's basically your agent's way of saying "I'm done here!" It disconnects you from the room and can trigger any shutdown hooks you've set up. Pro tip: including a reason helps with logging and makes debugging way easier. 😊
Sources: Job lifecycle | LiveKit Docs | agent.pywitty-kangaroo-6889
07/23/2025, 11:18 AMtall-airline-16756
07/23/2025, 11:20 AMentrypoint function. I've got a few friendly tips to make this super clear:
• Custom status tracking: Think of this like a progress bar for your agent. You can create a way to track what steps have been completed, so you always know exactly where things stand.
• AgentTask completion: If your agent is using AgentTask, you've got a handy complete() method that's perfect for marking when you're done. It's like giving your agent a gold star when it finishes its work!
Here's a quick example of how you might track your progress:
def is_task_complete(self):
# This is where you'll decide if your agent has hit its goal
return self.progress == 100
In your entrypoint function, after doing all the hard work, you'll want to check if you're done and then wrap things up:
async def entrypoint(ctx: JobContext):
...
if agent.is_task_complete():
ctx.shutdown(reason="Task completed")
Remember, every agent is unique, so you'll want to tailor this approach to fit exactly what your specific agent needs. You've got this!
Sources: flows/multi_stage_flow.py | livekit-agents/livekit/agents/ipc/job_proc_lazy_main.py | Job lifecycle | LiveKit Docswitty-kangaroo-6889
07/23/2025, 11:26 AMtall-airline-16756
07/23/2025, 11:27 AMAgentSession.start or context.connect – it happens earlier in the process. Think of it like setting up a virtual meeting space before everyone joins.
Here's the typical flow that might help make this clearer:
1. An end-user first connects to LiveKit, which creates the room
2. The agent worker gets assigned to this existing room
3. You'll use await ctx.connect() to connect the agent to the room
4. Then await session.start(room=ctx.room) starts the agent's session in that room
Just to be crystal clear: neither of those methods is responsible for creating the room itself. Hope this helps explain things!
Sources: Agents Overview | LiveKit Docs | complex-agents/ivr-agent/agent.py | livekit-agents/livekit/agents/voice/agent_session.py | An open source stack for real-time multimodal AI