most-evening-18072
02/28/2026, 6:30 PMtall-airline-16756
02/28/2026, 6:31 PMtall-airline-16756
02/28/2026, 6:31 PMsession.userdata).
• Update that store in real time by emitting participant/room attribute changes and listening for attribute-change events inside the agent.
Why this pattern works
• Job metadata gives the agent the full initial context when the job starts.
• session.userdata acts as the runtime, mutable source of truth accessible to the agent and any tools or downstream agents.
• Listening to participant/room attribute changes ensures updates made after dispatch are delivered to the running session and reflected in session.userdata.
Practical implementation outline
1. Provide initial context when dispatching the agent
◦ Put structured JSON into the dispatch metadata (string field) with fields like user_id, name, enabled_integrations.
◦ In the agent entrypoint, parse ctx.job.metadata to populate initial session state.
1. Initialize a typed session state
◦ Create a small data class or dict for session.userdata with fields like user_id and enabled_integrations.
◦ Assign the parsed initial values so all agent logic uses session.userdata instead of ctx.job.metadata directly.
1. Make integration changes visible at runtime
◦ When the application changes the user’s integrations, update the participant or room attributes (e.g., set an enabled_integrations attribute).
◦ Use a compact representation (comma-separated list or JSON string) suitable for attributes.
1. React to attribute change events inside the agent
◦ Register an event handler for participant_attributes_changed (or the relevant room event).
◦ In that handler, parse the changed attribute and update ctx.session.userdata.enabled_integrations so all agent code sees the latest value.
1. Persist and share across handoffs
◦ session.userdata persists across agent handoffs in multi-agent flows, so the updated state stays available if you move the conversation to another agent.
Minimal code sketch (conceptual)
# parse initial metadata
metadata = json.loads(ctx.job.metadata)
session.userdata = SessionState(
user_id=metadata["user_id"],
enabled_integrations=metadata.get("enabled_integrations", [])
)
# listen for attribute changes
@ctx.room.on("participant_attributes_changed")
def on_attrs_changed(changed_attrs, participant):
if "enabled_integrations" in changed_attrs:
new_list = json.loads(changed_attrs["enabled_integrations"])
ctx.session.userdata.enabled_integrations = new_list
Notes and best practices
• Keep metadata small: use concise JSON for the job metadata because it’s a string field.
• Use structured values in attributes (JSON string) if you need multiple fields; parse them in the agent.
• Only send what the agent needs to reduce parsing and event noise.
• If many rapid changes occur, consider debouncing updates or sending only the delta to avoid overwhelming the agent logic.
If you want, I can:
• Show a complete example using the exact SDK you’re using (Python, TypeScript, etc.).
• Help design the structure for metadata and session.userdata tailored to your integrations list.
• Suggest a format for participant attributes (CSV vs JSON) based on your expected change frequency.
Which SDK are you using and would you like a full code example for it?
Sources: Job lifecycle | LiveKit Documentation | Agents and handoffs | LiveKit Documentation | Agent dispatch | LiveKit Documentation | Handling asynchronous metadata updates in LiveKit | LiveKit | Building multi-agent architectures with LiveKit agents | LiveKit