numerous-vegetable-16012
08/07/2025, 10:41 AMtall-airline-16756
08/07/2025, 10:41 AMtall-airline-16756
08/07/2025, 10:42 AMagent_name
and dispatch rules.
2. Verify Dispatch Method: Confirm whether you're using automatic or explicit dispatch. For explicit dispatch, ensure the agent is correctly assigned via the API or token generation.
3. Review SIP Dispatch Rules: Ensure SIP dispatch rules are correctly routing calls to the intended agent.
4. Check Agent Lifecycle: Verify the agent is registered and available to accept calls.
5. Update LiveKit Version: Ensure you're using the latest version of LiveKit to avoid known issues.
6. Review Logs: Check logs for errors or warnings related to agent assignment.
7. Verify Permissions: Ensure the agent has the necessary permissions and SIP-related grants to join the room.
8. Test with Simple Configuration: Create a room and assign an agent using a basic setup to isolate the issue.
These steps should help identify and resolve the issue. Let me know if you need further assistance with any specific step.
Sources: LiveKit Agents | Agent dispatch | LiveKit Docs | Web and mobile frontends | LiveKit Docs | Dispatching agents | LiveKit Docs | Accepting inbound calls | LiveKit Docsnumerous-vegetable-16012
08/07/2025, 10:44 AMtall-airline-16756
08/07/2025, 10:44 AMJobContext
.
3. Room Configuration: You can set up a participant’s access token to dispatch agents as soon as they connect, including any metadata for the agent.
4. Room Creation: Don’t worry if the room doesn’t exist yet—LiveKit will create it automatically during dispatch.
Since you’re working with metadata, just make sure the agent is explicitly dispatched to the room. If you want, I’m here to help with more details or examples whenever you need them!
Sources: Dispatching agents | LiveKit Docs | packages/livekit-server-sdk/src/AgentDispatchClient.ts | Agent dispatch | LiveKit Docsnumerous-vegetable-16012
08/07/2025, 10:46 AMtall-airline-16756
08/07/2025, 10:46 AMimport json
async def entrypoint(ctx: JobContext):
# First, let's parse the job metadata
metadata = json.loads(ctx.job.metadata)
# Then, we grab some key details
user_id = metadata.get("user_id")
user_name = metadata.get("user_name")
phone_number = metadata.get("phone_number")
# Now, we use that info to set up the agent
session = AgentSession()
agent = YourAgent(
instructions=f"Hello {user_name}!",
context={"user_id": user_id}
)
# Finally, connect the agent to the room
await ctx.connect()
Here’s a quick rundown:
• We start by parsing the metadata from ctx.job.metadata
.
• Then, we pull out important bits like user_id
and user_name
to help guide the agent’s behavior.
• And lastly, the agent connects to the room with ctx.connect()
.
If you want me to walk you through any part of this or need some more examples, just let me know—I’m happy to help!numerous-vegetable-16012
08/07/2025, 10:48 AMtall-airline-16756
08/07/2025, 10:48 AM{
"name": "My SIP Dispatch Rule",
"rule": {
"dispatchRuleIndividual": {
"roomPrefix": "sip-call-"
}
},
"room_config": {
"agents": [
{
"agentName": "sip-agent",
"metadata": "{\"source\": \"sip\", \"call_id\": \"12345\"}"
}
]
}
}
2. Set Custom Metadata: Use the metadata
field to add user and tenant details. This helps with processing the calls smoothly.
3. Apply the Dispatch Rule: Just run this command with the LiveKit CLI to apply your rule to a SIP trunk:
lk sip dispatch create dispatch-rule.json
4. Handle Metadata in Agents: In your agent’s entrypoint, you can grab the metadata like this:
async def entrypoint(ctx: JobContext):
<http://logger.info|logger.info>(f"Job metadata: {ctx.job.metadata}")
<http://logger.info|logger.info>(f"Source: {ctx.job.metadata.get('source')}")
# Process call based on metadata
And that’s it! This setup makes sure your agents get assigned to SIP-created rooms with all the metadata they need. If you have any questions or want me to walk you through any part, just let me know—I’m here to help!numerous-vegetable-16012
08/07/2025, 10:50 AMtall-airline-16756
08/07/2025, 10:50 AMagent_id
and caller_number
.
2. Error Handling: Nice job with the error handling around missing or invalid agent_id
. This kind of attention really helps with debugging and keeps things running smoothly.
3. Service Initialization: Using create_services()
and load_agent_config()
is a smart move for keeping your code modular. Just make sure these functions handle exceptions nicely and log useful error messages.
4. Usage Limits: Including a check for usage limits with check_usage_limits()
is a solid addition. It might be helpful to log some detailed info if the limit is exceeded to make troubleshooting easier.
5. Agent Session: Creating an InboundAgent
and kicking off the session with session.start()
looks great. Just confirm that get_room_input_options()
is returning the right setup for your specific needs.
6. Logging: Your logging coverage is thorough. Just a heads-up to avoid logging sensitive info like agent_id
or caller_number
in plaintext to keep things secure.
7. Graceful Cleanup: The finally
block doing cleanup with LiveKit is a nice touch. You might also want to explicitly disconnect the agent or free up resources if that fits your workflow.
All in all, you’ve built a solid implementation here. If you want me to dive deeper or provide some specific code examples, just let me know—I’m happy to help!
Sources: telephony/sip_lifecycle.py | README.md | ivr-nagivator/flask_livekit/extension.py | agent.py | README.mdnumerous-vegetable-16012
08/07/2025, 10:51 AMtall-airline-16756
08/07/2025, 10:52 AM{
"dispatch_rule": {
"rule": {
"dispatchRuleIndividual": {
"roomPrefix": "sip-call-"
}
},
"roomConfig": {
"agents": [
{
"agentName": "my-agent",
"metadata": "{\"custom\":\"data\"}"
}
]
}
}
}
2. Apply the Dispatch Rule: Use the LiveKit CLI to apply your rule to the SIP trunk like this:
lk sip dispatch create dispatch-rule.json
3. Explicit Agent Dispatch: Make sure your agent is registered with an agent_name
so you can dispatch them explicitly. For example:
opts = WorkerOptions(agent_name="test-agent")
4. Dispatch via API: You can also use the API to send your agent to the room directly:
dispatch = await lkapi.agent_dispatch.create_dispatch(
api.CreateAgentDispatchRequest(
agent_name="test-agent",
room="sip-call-room",
metadata="{\"user_id\":\"12345\"}"
)
)
5. Handle Metadata: If you want to pass custom info to your agent, just add it in the metadata
field—it’ll be included in the job metadata.
Following these steps will make sure your agent joins the SIP-created room smoothly. If you have any questions or want me to walk you through anything, just let me know—I’m here to help!
Sources: Agent dispatch | LiveKit Docs | packages/livekit-server-sdk/src/AgentDispatchClient.tsnumerous-vegetable-16012
08/07/2025, 10:54 AM{
"dispatch_rule": {
"rule": {
"dispatchRuleIndividual": {
"roomPrefix": "sip-call-"
}
},
"roomConfig": {
"agents": [{
"agentName": "my-agent",
"metadata": "{\"custom\":\"data\"}"
}]
}
}
}
tall-airline-16756
08/07/2025, 10:55 AMagent.py
for your dispatch rule that you might find helpful:
# agent.py
import asyncio
from livekit import api
room_name = "sip-call-room"
agent_name = "my-agent"
async def create_explicit_dispatch():
lkapi = api.LiveKitAPI()
# This function creates an explicit dispatch so your agent can join a specific room
dispatch = await lkapi.agent_dispatch.create_dispatch(
api.CreateAgentDispatchRequest(
agent_name=agent_name,
room=room_name,
metadata="{\"custom\":\"data\"}"
)
)
print("Created dispatch:", dispatch)
# Let's also list all dispatches in the room to keep track
dispatches = await lkapi.agent_dispatch.list_dispatch(room_name=room_name)
print(f"There are {len(dispatches)} dispatches in {room_name}")
await lkapi.aclose()
async def create_token_with_agent_dispatch() -> str:
# Here we create an access token that includes the agent configuration
token = (
api.AccessToken()
.with_identity("my_participant")
.with_grants(api.VideoGrants(room_join=True, room=room_name))
.with_room_config(
api.RoomConfiguration(
agents=[api.RoomAgentDispatch(agent_name=agent_name, metadata="{\"custom\":\"data\"}")],
),
)
.to_jwt()
)
return token
async def main():
token = await create_token_with_agent_dispatch()
print("Created participant token:", token)
print("Creating explicit dispatch")
await create_explicit_dispatch()
asyncio.run(main())
Here are a few key points to keep in mind:
• Explicit Dispatch: The create_explicit_dispatch
function helps your agent join the room using the LiveKit API.
• Token Configuration: The create_token_with_agent_dispatch
function generates a token that includes the agent’s settings and metadata.
• Room Configuration: The token contains RoomConfiguration
with RoomAgentDispatch
to specify the agent and its metadata.
Just swap out room_name
and agent_name
with your own values. If you have any questions or want me to walk you through anything else, just let me know—I’m here to help!numerous-vegetable-16012
08/07/2025, 10:58 AM*Explicit Dispatch:* Once agents are specified, automatic dispatch takes a backseat. You'll need to assign the agent to a room yourself, either through the API or when generating the token.
more specifically this one ``*Explicit Dispatch:* Once agents are specified, automatic dispatch takes a backseat.`
it is not for Worker option even in dispatch ruletall-airline-16756
08/07/2025, 10:58 AMnumerous-vegetable-16012
08/07/2025, 11:14 AMtall-airline-16756
08/07/2025, 11:15 AMnumerous-vegetable-16012
08/07/2025, 11:17 AMtall-airline-16756
08/07/2025, 11:17 AMentrypoint
function to make sure the agent joins the room created by the dispatch rule with the same agent name and metadata:
async def entrypoint(ctx: JobContext):
"""
Inbound call entrypoint that handles incoming SIP calls.
Args:
ctx: Job context containing call metadata
"""
<http://logger.info|logger.info>(f"Connecting to room {ctx.room.name}")
await ctx.connect()
try:
# Parse call metadata
metadata = {}
if ctx.job.metadata:
metadata = json.loads(ctx.job.metadata)
agent_id_raw = metadata.get("agent_id")
caller_number = metadata.get("phone_number") or metadata.get("caller_number")
if not agent_id_raw:
logger.error("No agent_id provided in metadata")
raise ValueError("Missing required agent_id in call metadata")
# Convert agent_id to integer if it's a string
try:
agent_id = int(agent_id_raw)
except (ValueError, TypeError):
logger.error(f"Invalid agent_id format: {agent_id_raw}")
raise ValueError(f"Invalid agent_id format: {agent_id_raw}")
# Create services
knowledge_service, usage_service, agent_service, user_service = (
await create_services()
)
# Load agent configuration
agent_config = await load_agent_config(agent_service, agent_id)
user_id = agent_config["user_id"]
# Check usage limits
if not await check_usage_limits(usage_service, user_service, user_id):
logger.warning(f"Usage limit exceeded for user {user_id}")
raise ValueError(f"Daily usage limit exceeded for user {user_id}")
# Make sure the agent joins the room created by the dispatch rule
if ctx.room.name.startswith("sip-call-") and agent_config["agent_name"] == ctx.job.metadata.get("agent_name"):
<http://logger.info|logger.info>(f"Agent {agent_config['agent_name']} is joining the room {ctx.room.name}")
# Create the inbound agent
agent = InboundAgent(
agent_config=agent_config,
caller_number=caller_number,
knowledge_service=knowledge_service,
usage_service=usage_service,
agent_service=agent_service,
user_service=user_service,
)
# Create agent session
session = create_agent_session()
# Start call tracking
await agent.start_call_tracking()
# Start the session
await session.start(
agent=agent,
room=ctx.room,
room_input_options=get_room_input_options(),
)
<http://logger.info|logger.info>(f"Inbound agent session started for room {ctx.room.name}")
except Exception as e:
logger.error(f"Inbound call failed: {e}")
# Let the exception propagate - LiveKit will handle cleanup
Here are the key updates:
• We added a check to make sure the agent joins the right room by verifying the room name starts with sip-call-
and that the agent name in the metadata matches.
• Included some logging so you can see when the agent is joining the correct room.
If you want me to tweak anything else or have questions, just let me know—I’m happy to help!numerous-vegetable-16012
08/07/2025, 11:21 AMtall-airline-16756
08/07/2025, 11:21 AMcall-
.
• Agent: The agent voice-ai-universal-agent
will be the one dispatched to these rooms.
• Metadata: The agent will get the following metadata:
{
"agent_id": 60,
"agent_external_id": "some id",
"agent_type": "inbound"
}
• Trunk: This rule is linked to the SIP trunk ID testtrunck id
.
Just make sure your entrypoint function looks out for the room prefix call-
and matches the agent name voice-ai-universal-agent
in the metadata so it can join the room properly. If you have any questions or want to chat more about this, I’m here to help!numerous-vegetable-16012
08/07/2025, 11:21 AMtall-airline-16756
08/07/2025, 11:22 AMcall-
by looking at the ctx.room.name
property in your entrypoint function. Here’s a quick example:
if ctx.room.name.startswith("call-"):
<http://logger.info|logger.info>(f"Room {ctx.room.name} matches the dispatch rule prefix.")
This way, your agent will only handle rooms created by the dispatch rule with that prefix. If anything’s unclear or you want to dive deeper, just give me a shout—I’m happy to help!numerous-vegetable-16012
08/07/2025, 11:23 AMtall-airline-16756
08/07/2025, 11:23 AMtrunk_id_1
with metadata {"agent_id": 1}
, and another for trunk_id_2
with metadata {"agent_id": 2}
. The system will then check the rules and apply the best match based on trunk ID and setup.
If you want, I’m happy to help you get those multiple dispatch rules up and running!
Sources: SIP overview | LiveKit Docs | SIP overview | LiveKit Docs | SIP APIs | LiveKit Docs | livekit/livekit_sip.pb.gonumerous-vegetable-16012
08/07/2025, 11:23 AMnumerous-vegetable-16012
08/07/2025, 11:24 AMtall-airline-16756
08/07/2025, 11:25 AMnumerous-vegetable-16012
08/07/2025, 11:26 AMtall-airline-16756
08/07/2025, 11:27 AMctx.job.metadata
) to spot the trunk, dispatch rule, or any other important details. For example:
metadata = json.loads(ctx.job.metadata)
trunk_id = metadata.get("trunk_id")
dispatch_rule_id = metadata.get("dispatch_rule_id")
# Use these values to customize agent behavior
3. Dynamic Configuration: Use that metadata to load configurations on the fly, like call scripts, routing logic, or service integrations, depending on the trunk or dispatch rule.
4. Unified Agent: Register one single agent (like common-agent
) across all dispatch rules. This agent will handle every call and adjust how it behaves based on the metadata it receives.
This setup lets one agent handle calls smoothly and flexibly across multiple trunks and dispatch rules. If you’d like, I’m here to help you get this up and running!numerous-vegetable-16012
08/07/2025, 11:28 AMtall-airline-16756
08/07/2025, 11:28 AMimport json
async def entrypoint(ctx: JobContext):
"""
Common agent entrypoint to handle calls based on metadata.
Args:
ctx: Job context containing call metadata
"""
<http://logger.info|logger.info>(f"Connecting to room {ctx.room.name}")
await ctx.connect()
try:
# Parse metadata from the job context
metadata = json.loads(ctx.job.metadata) if ctx.job.metadata else {}
# Extract relevant metadata fields
trunk_id = metadata.get("trunk_id")
dispatch_rule_id = metadata.get("dispatch_rule_id")
caller_number = metadata.get("phone_number")
if not trunk_id or not dispatch_rule_id:
logger.error("Missing trunk_id or dispatch_rule_id in metadata")
raise ValueError("Required metadata fields are missing")
# Log metadata for debugging
<http://logger.info|logger.info>(f"Handling call from trunk: {trunk_id}, dispatch rule: {dispatch_rule_id}")
# Dynamically load configurations or behavior based on metadata
if dispatch_rule_id == "rule_1":
<http://logger.info|logger.info>("Applying behavior for dispatch rule 1")
# Add specific logic for rule 1
elif dispatch_rule_id == "rule_2":
<http://logger.info|logger.info>("Applying behavior for dispatch rule 2")
# Add specific logic for rule 2
else:
<http://logger.info|logger.info>("Applying default behavior")
# Create the agent and session
agent = CommonAgent(caller_number=caller_number, metadata=metadata)
session = create_agent_session()
# Start the session
await session.start(
agent=agent,
room=ctx.room,
room_input_options=get_room_input_options(),
)
<http://logger.info|logger.info>(f"Agent session started for room {ctx.room.name}")
except Exception as e:
logger.error(f"Call handling failed: {e}")
# Let the exception propagate for cleanup
Key Features:
• Metadata Parsing: It gently pulls out trunk_id
, dispatch_rule_id
, and other handy details from the job metadata.
• Dynamic Behavior: The agent adapts its approach depending on the dispatch rule or trunk ID—pretty neat, right?
• Unified Agent: We use one friendly agent instance (CommonAgent
) to handle all calls, keeping things simple and smooth.
If you’d like me to tweak this or need some more examples, just let me know—I’m here to help!numerous-vegetable-16012
08/07/2025, 11:31 AMtall-airline-16756
08/07/2025, 11:31 AMvoice-ai-universal-agent
, which matches your dispatch rule perfectly. Just double-check that all dispatch rules pointing to this name are set up correctly.
2. Metadata Handling: Your determine_agent_type
and enhanced_request_handler
functions do a great job parsing metadata to pick the right agent type and validate job requests. This really helps keep things flexible.
3. Entrypoint Routing: The agent_entrypoint
function smartly routes calls to either the inbound or outbound agent based on metadata. It’s a neat, modular way to keep things organized and scalable.
4. Prewarming: The prewarm_agent_process
function loads up resources like the voice pipeline and database connections ahead of time, which helps cut down on startup delays. Just make sure these preloaded parts are used often enough to make the extra prep worthwhile.
5. Load Management: I really like how the calculate_worker_load
function keeps track of worker load dynamically. It’s a smart move to balance resources and keep performance running smoothly.
If you’d like a hand with any specific parts or want some more examples, just give me a shout—I’m here to help!numerous-vegetable-16012
08/07/2025, 11:32 AMtall-airline-16756
08/07/2025, 11:33 AMsip.callStatus
in the participant’s metadata—it should say "active" once the call is connected.
2. Dispatch Rules: Make sure the SIP dispatch rule is pointing to the right agent in room_config.agents
. Double-check that the agent name matches exactly what’s registered with LiveKit.
3. Agent Availability: Confirm the agent is properly registered and running. The agent needs to be active to receive any dispatch requests.
4. Logs: Take a peek at the SIP service logs for any errors during call setup or agent dispatch. Watch out for issues like incorrect metadata or dispatch failures.
5. Room Existence: Verify that the room actually gets created when the SIP call connects. The agent can only join a room that exists.
6. Token Configuration: If you’re using token-based dispatch, make sure the token includes the right RoomAgentDispatch
configuration.
If you want, I’m here to help dig into specific logs or configurations to get this sorted out!
Sources: Dispatching agents | LiveKit Docs | pkg/sip/room.go | Web and mobile frontends | LiveKit Docs | protobufs/livekit_sip.proto | test/agent_test.gonumerous-vegetable-16012
08/07/2025, 11:33 AMtall-airline-16756
08/07/2025, 11:33 AMsetLogLevel
function to turn on detailed logging:
import { setLogLevel, LogLevel } from 'livekit-client';
setLogLevel(LogLevel.debug);
2. Environment Variable: You can set LIVEKIT_EVALS_VERBOSE=1
to see more verbose output:
LIVEKIT_EVALS_VERBOSE=1 pytest -s -o log_cli=true <your-test-file>
3. Run in Dev Mode: Start the agent in development mode—it’s super helpful for debugging:
python agent.py dev
4. Console Mode: Running the agent in console mode lets you debug locally:
python agent.py console
These tips should help you grab detailed logs and figure out what’s going on. If you hit any snags or want a hand, just let me know—I’m here to help!
Sources: Testing and evaluation | LiveKit Docs | Voice AI quickstart | LiveKit Docs | hooks/useDebug.ts | avatars/hedra/education_avatar/education-frontend/hooks/useDebug.tsnumerous-vegetable-16012
08/07/2025, 11:39 AMtall-airline-16756
08/07/2025, 11:39 AMimport asyncio
from livekit import api
room_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="my_job_metadata"
)
)
print("Dispatch created:", dispatch)
dispatches = await lkapi.agent_dispatch.list_dispatch(room_name=room_name)
print(f"Found {len(dispatches)} dispatches in {room_name}")
asyncio.run(create_explicit_dispatch())
2. Using the Node.js SDK:
`const { AgentDispatchClient } = require('livekit-server-sdk');
const roomName = 'my-room';
const agentName = 'test-agent';
const client = new AgentDispatchClient('LIVEKIT_URL', 'API_KEY', 'API_SECRET');
const dispatch = await client.createDispatch(roomName, agentName, {
metadata: '{"mydata": "myvalue"}',
});
console.log('Dispatch created:', dispatch);
const dispatches = await client.listDispatch(roomName);
console.log(Found ${dispatches.length} dispatches in ${roomName}
);`
3. Using the LiveKit CLI:
lk dispatch create --room test-room --agent-name test-agent
These are great ways to explicitly dispatch an agent to a room for testing. If you have any questions or want a hand with anything else, just let me know—I’m here to help!
Sources: packages/livekit-server-sdk/src/AgentDispatchClient.ts | Dispatching agents | LiveKit Docs | Agent dispatch | LiveKit Docsnumerous-vegetable-16012
08/07/2025, 11:43 AMtall-airline-16756
08/07/2025, 11:44 AMagent_id
is missing from the metadata. This makes sense given how your current setup works—it checks for agent_id
before accepting any job.
To fix this, just make sure the dispatch rule or token you're using to create the job includes the agent_id
in the metadata. Here’s a quick example:
{
"agents": [
{
"agentName": "voice-ai-universal-agent",
"metadata": "{\"agent_id\": 60, \"agent_external_id\": \"some id\", \"agent_type\": \"inbound\"}"
}
]
}
If you want, I’m here to help you update the dispatch rule or token configuration—just let me know!numerous-vegetable-16012
08/07/2025, 11:47 AMtall-airline-16756
08/07/2025, 11:47 AMimport asyncio
from livekit import api
async def create_explicit_dispatch():
lkapi = api.LiveKitAPI()
# Dispatch an agent to a specific room with metadata
dispatch = await lkapi.agent_dispatch.create_dispatch(
api.CreateAgentDispatchRequest(
agent_name="test-agent",
room="test-room",
metadata="{\"key\": \"value\"}"
)
)
print("Dispatch created:", dispatch)
# List all dispatches in the room
dispatches = await lkapi.agent_dispatch.list_dispatch(room_name="test-room")
print(f"Found {len(dispatches)} dispatches in test-room")
asyncio.run(create_explicit_dispatch())
Node.js SDK:
const { AgentDispatchClient } = require('livekit-server-sdk');
async function createExplicitDispatch() {
const client = new AgentDispatchClient('LIVEKIT_URL', 'API_KEY', 'API_SECRET');
// Dispatch an agent to a specific room with metadata
const dispatch = await client.createDispatch('test-room', 'test-agent', {
metadata: '{"key": "value"}'
});
console.log('Dispatch created:', dispatch);
// List all dispatches in the room
const dispatches = await client.listDispatch('test-room');
console.log(`Found ${dispatches.length} dispatches in test-room`);
}
createExplicitDispatch();
LiveKit CLI:
# Create a dispatch using the CLI
lk dispatch create --room test-room --agent-name test-agent --metadata '{"key": "value"}'
# List all dispatches in a room
lk dispatch list --room test-room
These examples show you how to explicitly dispatch agents to a room with metadata using Python, Node.js, and the LiveKit CLI. If you have any questions or want to dive deeper, just let me know—I'm here to help!numerous-vegetable-16012
08/07/2025, 11:47 AMtall-airline-16756
08/07/2025, 11:48 AMimport asyncio
from livekit import api
async def create_explicit_dispatch():
lkapi = api.LiveKitAPI()
# Dispatch an agent to a specific room with metadata
dispatch = await lkapi.agent_dispatch.create_dispatch(
api.CreateAgentDispatchRequest(
agent_name="voice-ai-universal-agent",
room="sip-call-room",
metadata="{\"agent_id\": 60, \"agent_type\": \"inbound\"}"
)
)
print("Dispatch created:", dispatch)
# List all dispatches in the room
dispatches = await lkapi.agent_dispatch.list_dispatch(room_name="sip-call-room")
print(f"Found {len(dispatches)} dispatches in sip-call-room")
asyncio.run(create_explicit_dispatch())
Where to Place This Code:
• Feel free to add this code in your agent’s initialization or a special script just for testing out dispatch functionality.
• When you’re ready for production, you can tuck it into your SIP call handling workflow—like right when a SIP call comes in and a room gets created.
What to Listen For:
• Keep an ear out for SIP call events, such as when a call connects or a room is created. You can use the JobContext
or JobRequest
in your agent’s entrypoint to manage these events.
• Check ctx.room.name
and ctx.job.metadata
to decide if it’s the right time to dispatch the agent.
If you want a hand integrating this into your workflow, just let me know—I’m happy to help!numerous-vegetable-16012
08/07/2025, 11:49 AMtall-airline-16756
08/07/2025, 11:49 AMJobRequest
or JobContext
to spot when a room pops up. For example:
async def enhanced_request_handler(ctx: JobRequest):
if ctx.job.room.name.startswith("sip-call-"):
<http://logger.info|logger.info>(f"Room created: {ctx.job.room.name}")
await dispatch_agent(ctx.job.room.name)
2. Dispatch the Agent: Then, you can explicitly assign the agent to that room with this code:
async def dispatch_agent(room_name):
lkapi = api.LiveKitAPI()
dispatch = await lkapi.agent_dispatch.create_dispatch(
api.CreateAgentDispatchRequest(
agent_name="voice-ai-universal-agent",
room=room_name,
metadata="{\"agent_id\": 60, \"agent_type\": \"inbound\"}"
)
)
<http://logger.info|logger.info>(f"Agent dispatched to room: {room_name}")
3. Integrate with SIP Workflow: Make sure your SIP dispatch rule creates rooms with a clear prefix like sip-call-
. This way, your handler can easily spot and manage them.
This setup will automatically dispatch an agent whenever a SIP call creates a room. If you have any questions or want to chat more about it, just let me know—I’m here to help!numerous-vegetable-16012
08/07/2025, 11:51 AMtall-airline-16756
08/07/2025, 11:51 AMJobContext
. You can easily access it in the agent’s entrypoint function using ctx.job.metadata
. Here’s a quick example:
async def entrypoint(ctx: JobContext):
# Parse metadata from the job context
metadata = json.loads(ctx.job.metadata) if ctx.job.metadata else {}
# Access dispatch rule metadata
tenant_id = metadata.get("tenant_id")
agent_id = metadata.get("agent_id")
<http://logger.info|logger.info>(f"Dispatch rule metadata: Tenant ID: {tenant_id}, Agent ID: {agent_id}")
This metadata is super important for multi-tenant systems because it helps you identify the tenant and tailor the agent’s behavior just right.
Make sure the dispatch rule includes the necessary metadata when you create it. For example:
{
"agents": [
{
"agentName": "voice-ai-universal-agent",
"metadata": "{\"tenant_id\": \"12345\", \"agent_id\": 60}"
}
]
}
If anything’s unclear or you want to dive deeper, just let me know—I’m here to help!numerous-vegetable-16012
08/07/2025, 11:52 AMtall-airline-16756
08/07/2025, 11:52 AMJobContext
, so you can easily access metadata and handle the job.
If anything’s unclear or you want to chat more about it, just let me know—I’m here to help!numerous-vegetable-16012
08/07/2025, 11:53 AMtall-airline-16756
08/07/2025, 11:53 AMnumerous-vegetable-16012
08/07/2025, 11:55 AMtall-airline-16756
08/07/2025, 11:55 AMmetadata
field in the CreateAgentDispatchRequest
. The agent will then receive this metadata in the JobContext
.
2. SIP Participant Metadata: Metadata set in the SIP trunk (like with participant_metadata
or participant_attributes
) gets attached to the SIP participant. However, this metadata won’t automatically reach the agent unless you include it explicitly in the dispatch.
So, to make sure your agent gets the metadata they need, it’s best to use explicit dispatch with the metadata field. If you want me to walk you through it or share some examples, just let me know—I’m here to help!
Sources: Agent dispatch | LiveKit Docs | livekit/livekit_sip.pb.gonumerous-vegetable-16012
08/07/2025, 11:55 AMnumerous-vegetable-16012
08/07/2025, 11:56 AMtall-airline-16756
08/07/2025, 11:57 AMnumerous-vegetable-16012
08/07/2025, 11:58 AMtall-airline-16756
08/07/2025, 11:59 AMdispatchRuleIndividual
type with a roomPrefix
of call-643aaa88-
.
• trunkIds: These are the trunk IDs (ST_Axxxxx
) that this rule applies to.
• name: A friendly name for the rule (Agent dispatch rule
).
Everything fits perfectly with LiveKit’s SIP Dispatch Rule requirements. If you have any questions or need a hand with anything else, just let me know—I’m here to help!