Skip to main content

Routing

OpenRTC resolves the active agent for each incoming session through a priority chain. The chain runs before ctx.connect(), so it must work entirely from pre-connect metadata.

Priority chain

Strategies run in order. The first one that returns a match wins.
PrioritySourceHow it works
1ctx.job.metadata["agent"]Agent name from the job assignment metadata (set by your dispatch caller).
2ctx.job.metadata["demo"]Legacy fallback key, same format.
3ctx.job.room.metadata["agent"]Room metadata from the job’s room assignment (read before connect; authoritative).
4ctx.job.room.metadata["demo"]Legacy fallback key, same format.
5Room name prefixRoom name begins with <agent-name>-, e.g. support-call-123 routes to support.
6First registered agentDefault fallback: the agent registered first with pool.add().
Strategies 3 and 4 read ctx.job.room.metadata, not ctx.room.metadata. The rtc.Room (ctx.room) is empty until ctx.connect() is called. The job assignment carries the authoritative room metadata from LiveKit’s dispatch system before the room connects.

Metadata format

Pass metadata as a JSON object with an "agent" key:
{"agent": "support"}
OpenRTC accepts:
  • A JSON string: '{"agent": "support"}' (common from LiveKit CreateRoom)
  • A Python dict: {"agent": "support"} (common from test fixtures)
The "demo" key is an alias for "agent" with lower priority. You can use it for showcase scenarios where the primary "agent" key is absent. Non-JSON strings, blank strings, and JSON scalars (e.g. "42") are ignored — the strategy defers to the next one. An absent metadata field is also a no-op (no error).

Routing a session via job metadata

When dispatching a job with the LiveKit SDK, set job.metadata:
from livekit import api

await lk_api.agent_dispatch.create_dispatch(
    api.CreateAgentDispatchRequest(
        agent_name="my-worker",
        room="my-room",
        metadata='{"agent": "dental"}',
    )
)
OpenRTC reads ctx.job.metadata first (priority 1), which resolves before the room connects.

Routing a session via room metadata

Set the room’s metadata when creating it:
await lk_api.room.create_room(
    api.CreateRoomRequest(
        name="dental-room-42",
        metadata='{"agent": "dental"}',
    )
)
OpenRTC reads ctx.job.room.metadata (priority 3) — the LiveKit dispatch system copies the room metadata onto the job assignment, so routing works pre-connect.

Routing via room name prefix

If neither job nor room metadata contains an "agent" key, OpenRTC checks whether the room name starts with a registered agent name followed by -:
dental-call-1234    →  dental
restaurant-room-42  →  restaurant
general-chat        →  (no match, falls through to default)
This is convenient for low-config deployments where the room naming convention is enough to route.

Default fallback

If no strategy matches, OpenRTC routes to the first registered agent (the first call to pool.add()). This means a single-agent pool always resolves, and a multi-agent pool has a sensible default for sessions that carry no routing signal.

Error behavior

ConditionBehavior
Metadata specifies an agent name that is not registeredRaises ValueError("Unknown agent '...' requested via ...") — no silent fallback
Pool has no registered agentsRaises RuntimeError("No agents are registered in the pool.")
Valid agent resolvedLogs Resolved agent '<name>' via <source>. at INFO level
The deliberate error-on-unknown keeps routing failures loud. A typo in a metadata value surfaces immediately rather than silently falling through to the wrong agent.

Checking routing in the CLI

openrtc list --agents-dir ./agents
This prints each registered agent and its configured providers. Registration order determines default fallback order.