Dispatching agents
Dispatch is the process of assigning an agent to a room. LiveKit server manages this process as part of the Server lifecycle. LiveKit optimizes dispatch for high concurrency and low latency, typically supporting hundreds of thousands of new connections per second with a max dispatch time under 150 ms.
Explicit dispatch is the recommended approach for most applications. It gives you control over when agents join rooms and lets you pass job-specific metadata to each agent session.
Explicit agent dispatch
Explicit dispatch gives you full control over when and how agents join rooms.
To use explicit dispatch, set the agent_name field:
In Python, set the agent name in the @server.rtc_session decorator:
@server.rtc_session(agent_name="test-agent")async def my_agent(ctx: JobContext):# Agent entrypoint code...
const opts = new ServerOptions({//...agentName: "test-agent",});
Setting agent_name disables automatic dispatch. Agents are only assigned to rooms when explicitly dispatched.
Automatic agent dispatch
Automatic dispatch is not recommended for most applications. It dispatches an agent to every new room, regardless of whether one is needed, and doesn't support passing metadata to the agent session. Use explicit dispatch instead.
When agent_name is not set, an agent is automatically dispatched to each new room. This can be useful for simple prototypes where every room requires the same agent.
Dispatch via API
You can explicitly dispatch an agent to a room using the AgentDispatchService API.
import asynciofrom livekit import apiroom_name = "my-room"agent_name = "test-agent"async def create_explicit_dispatch():lkapi = api.LiveKitAPI()dispatch = await lkapi.agent_dispatch.create_dispatch(api.CreateAgentDispatchRequest(agent_name=agent_name, room=room_name, metadata='{"user_id": "12345"}'))print("created dispatch", dispatch)dispatches = await lkapi.agent_dispatch.list_dispatch(room_name=room_name)print(f"there are {len(dispatches)} dispatches in {room_name}")await lkapi.aclose()asyncio.run(create_explicit_dispatch())
import { AgentDispatchClient } from 'livekit-server-sdk';const roomName = 'my-room';const agentName = 'test-agent';async function createExplicitDispatch() {const agentDispatchClient = new AgentDispatchClient(process.env.LIVEKIT_URL, process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET);// create a dispatch request for an agent named "test-agent" to join "my-room"const dispatch = await agentDispatchClient.createDispatch(roomName, agentName, {metadata: '{"user_id": "12345"}',});console.log('created dispatch', dispatch);const dispatches = await agentDispatchClient.listDispatch(roomName);console.log(`there are ${dispatches.length} dispatches in ${roomName}`);}
lk dispatch create \--agent-name test-agent \--room my-room \--metadata '{"user_id": "12345"}'
require "livekit"room_name = "my-room"agent_name = "test-agent"client = LiveKit::AgentDispatchServiceClient.new(ENV["LIVEKIT_URL"],api_key: ENV["LIVEKIT_API_KEY"],api_secret: ENV["LIVEKIT_API_SECRET"],)dispatch = client.create_dispatch(room_name,agent_name,metadata: '{"user_id": "12345"}',)if dispatch.dataputs "successfully dispatched agent #{dispatch.data.agent_name} to #{dispatch.data.room}"elseputs "created dispatch (error): #{dispatch}"end
func createAgentDispatch() {req := &livekit.CreateAgentDispatchRequest{Room: "my-room",AgentName: "test-agent",Metadata: "{\"user_id\": \"12345\"}",}dispatch, err := dispatchClient.CreateDispatch(context.Background(), req)if err != nil {panic(err)}fmt.Printf("Dispatch created: %v\n", dispatch)}
import io.livekit.server.AgentDispatchServiceClientval roomName = "my-room"val agentName = "test-agent"fun createExplicitDispatch() {val client = AgentDispatchServiceClient.createClient(System.getenv("LIVEKIT_URL")!!.replace("wss", "https"),System.getenv("LIVEKIT_API_KEY")!!,System.getenv("LIVEKIT_API_SECRET")!!,)try {val response = client.createDispatch(room = roomName,agentName = agentName,metadata = """{"user_id": "12345"}""",).execute().body()if (response != null) {println("successfully dispatched agent ${response.agentName} to ${response.room}")} else {println("created dispatch (error): ${response}")}} catch (e: Exception) {println("error creating dispatch: ${e.message}")}}
The room, my-room, is automatically created during dispatch if it doesn't already exist, and the agent server assigns test-agent to it.
Job metadata
Explicit dispatch allows you to pass metadata to the agent, available in the JobContext. This is useful for including details such as the user's ID, name, or phone number.
The metadata field is a string. LiveKit recommends using JSON to pass structured data.
The examples in the previous section demonstrate how to pass job metadata during dispatch.
For information on consuming job metadata in an agent, see the following guide:
Job metadata
Learn how to consume job metadata in an agent.
Dispatch from inbound SIP calls
Agents can be explicitly dispatched for inbound SIP calls. SIP dispatch rules can define one or more agents using the room_config.agents field.
LiveKit recommends explicit agent dispatch for SIP inbound calls rather than automatic agent dispatch as it allows multiple agents within a single project.
Dispatch via access token
You can include one or more agent dispatch entries in a participant's access token. When the first participant connects and creates the room, LiveKit dispatches the specified agents.
Agent dispatch from the token only occurs when the room is first created. If the room already exists, the token's dispatch configuration is ignored. Use a unique room name per session or dispatch via API for more control.
The following example creates a token that dispatches the test-agent agent to the my-room room:
from livekit.api import (AccessToken,RoomAgentDispatch,RoomConfiguration,VideoGrants,)room_name = "my-room"agent_name = "test-agent"def create_token_with_agent_dispatch() -> str:token = (AccessToken().with_identity("my_participant").with_grants(VideoGrants(room_join=True, room=room_name)).with_room_config(RoomConfiguration(agents=[RoomAgentDispatch(agent_name="test-agent", metadata='{"user_id": "12345"}')],),).to_jwt())return token
import { RoomAgentDispatch, RoomConfiguration } from '@livekit/protocol';import { AccessToken } from 'livekit-server-sdk';const roomName = 'my-room';const agentName = 'test-agent';async function createTokenWithAgentDispatch(): Promise<string> {const at = new AccessToken();at.identity = 'my-participant';at.addGrant({ roomJoin: true, room: roomName });at.roomConfig = new RoomConfiguration({agents: [new RoomAgentDispatch({agentName: agentName,metadata: '{"user_id": "12345"}',}),],});return await at.toJwt();}
The following example assumes the environment variables LIVEKIT_API_KEY and LIVEKIT_API_SECRET are set:
lk token create \--identity "my-participant" \--room "my-room" \--agent "test-agent" \--join
require "livekit"roomName = "my-room"agentName = "test-agent"def create_token_with_agent_dispatch(roomName:, agentName:)token = LiveKit::AccessToken.new(api_key: ENV["LIVEKIT_API_KEY"],api_secret: ENV["LIVEKIT_API_SECRET"],identity: "my-participant",)token.video_grant = LiveKit::VideoGrant.new(roomJoin: true, room: roomName)token.room_config = LiveKit::Proto::RoomConfiguration.new(agents: [LiveKit::Proto::RoomAgentDispatch.new(agent_name: agentName,metadata: '{"user_id": "12345"}',),],)token.to_jwtend
func createTokenWithAgentDispatch() (string, error) {at := auth.NewAccessToken(os.Getenv("LIVEKIT_API_KEY"),os.Getenv("LIVEKIT_API_SECRET"),).SetIdentity("my-participant").SetName("Participant Name").SetVideoGrant(&auth.VideoGrant{Room: "my-room",RoomJoin: true,}).SetRoomConfig(&livekit.RoomConfiguration{Agents: []*livekit.RoomAgentDispatch{{AgentName: "test-agent",Metadata: "{\"user_id\": \"12345\"}",},},})return at.ToJWT()}
import io.livekit.server.AccessTokenimport io.livekit.server.RoomJoinimport io.livekit.server.RoomNameimport livekit.LivekitAgentDispatchimport livekit.LivekitRoom.RoomConfigurationval roomName = "my-room"val agentName = "test-agent"fun createTokenWithAgentDispatch(): String {val token = AccessToken(System.getenv("LIVEKIT_API_KEY")!!,System.getenv("LIVEKIT_API_SECRET")!!,)token.identity = "my-participant"token.addGrants(RoomJoin(true), RoomName(roomName))token.roomConfiguration = RoomConfiguration.newBuilder().addAgents(LivekitAgentDispatch.RoomAgentDispatch.newBuilder().setAgentName(agentName).setMetadata("""{"user_id": "12345"}""").build(),).build()return token.toJwt()}