future-glass-56154
09/16/2025, 6:02 PMtall-airline-16756
09/16/2025, 6:02 PMtall-airline-16756
09/16/2025, 6:02 PMUserData is actually the best way to go. It helps keep your agents stateless while still holding onto session-specific context, which is fantastic for making your system scalable and reusable.
You can use UserData in both function tools and pipeline nodes:
• For function tools, you can access UserData through the RunContext parameter. This makes it easy to manage and update session-specific data as your tool runs.
• Within pipeline nodes, UserData is available via self.session.userdata, so you can maintain consistent state throughout your agent's workflow.
To get started with UserData, just define it as a dataclass and pass an instance to the AgentSession constructor. This way, your agent will smoothly handle state across all its operations. If you have any questions while setting this up, feel free to ask—I’m here to help!
Sources: Building Multi-Agent Architectures with LiveKit Agents | Workflows | LiveKit Docs | complex-agents/nova-sonic/form_agent.py | examples/voice_agents/restaurant_agent.py | Building an Automated IVR Menu Caller | LiveKit Docsfuture-glass-56154
09/16/2025, 6:08 PM<http://logger.info|logger.info>(f"Userdata in main: {_ctx_.proc.userdata}")
This doesn't appear to have anything after I set _self_.session.userdata.test = "testing" on the on_enter function in my agent class.tall-airline-16756
09/16/2025, 6:09 PMuserdata by initializing it as you create the AgentSession. For instance, you can define a dataclass for userdata, set it up with some initial values, and then pass it along to the AgentSession constructor. This way, the session and all its parts stay in sync with the same state.
The challenge you’re seeing happens because the on_enter function runs asynchronously after the session has started, while your entrypoint function finishes running beforehand. So, any changes made to userdata inside on_enter won’t show up in the entrypoint function since it’s already done executing.
To work around this, try to make sure that important updates to userdata happen right within the entrypoint function, or access the updated state later on in components that run after on_enter, like tools or downstream agents. I hope this helps clarify things! Feel free to ask if you'd like me to walk through it with you step-by-step.
Sources: Building an Automated IVR Menu Caller | LiveKit Docs | Workflows | LiveKit Docs | complex-agents/nova-sonic/form_agent.py | examples/voice_agents/restaurant_agent.py | Workflows | LiveKit Docsfuture-glass-56154
09/16/2025, 6:10 PM<http://logger.info|logger.info>(f"Userdata in main: {_ctx_.proc.userdata}")
To clarify this is running in the shutdown callbacktall-airline-16756
09/16/2025, 6:11 PMuserdata in the shutdown callback, a helpful approach is to make sure the callback can reach the session or userdata by capturing it within the closure when you register the callback. Here’s a simple example to guide you:
async def entrypoint(ctx: JobContext):
@dataclass
class MySessionInfo:
test: str = "default"
userdata = MySessionInfo()
session = AgentSession[MySessionInfo](userdata=userdata)
async def cleanup_hook():
<http://logger.info|logger.info>(f"Userdata in shutdown: {userdata.test}")
ctx.add_shutdown_callback(cleanup_hook)
await session.start(...)
In your situation, if userdata is being set in on_enter, it’s important to make sure the session stays alive until the shutdown callback runs. If the session ends before the callback gets a chance to execute, userdata won’t be available. I hope this helps clarify things for you!
Sources: examples/voice_agents/basic_agent.py | Inside a session | LiveKit Docs | Job lifecycle | LiveKit Docs | Building an Automated IVR Menu Caller | LiveKit Docs | Inside a session | LiveKit Docs