> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openrtc.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Routing

> How OpenRTC resolves which Agent handles each incoming session, with priority rules, metadata formats, and error behavior.

# 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.

| Priority | Source                           | How it works                                                                        |
| -------- | -------------------------------- | ----------------------------------------------------------------------------------- |
| 1        | `ctx.job.metadata["agent"]`      | Agent name from the job assignment metadata (set by your dispatch caller).          |
| 2        | `ctx.job.metadata["demo"]`       | Legacy fallback key, same format.                                                   |
| 3        | `ctx.job.room.metadata["agent"]` | Room metadata from the job's room assignment (read before connect; authoritative).  |
| 4        | `ctx.job.room.metadata["demo"]`  | Legacy fallback key, same format.                                                   |
| 5        | Room name prefix                 | Room name begins with `<agent-name>-`, e.g. `support-call-123` routes to `support`. |
| 6        | First registered agent           | Default fallback: the agent registered first with `pool.add()`.                     |

<Note>
  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.
</Note>

## Metadata format

Pass metadata as a JSON object with an `"agent"` key:

```json theme={null}
{"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`:

```python theme={null}
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:

```python theme={null}
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 `-`:

```text theme={null}
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

| Condition                                               | Behavior                                                                          |
| ------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Metadata specifies an agent name that is not registered | Raises `ValueError("Unknown agent '...' requested via ...")` — no silent fallback |
| Pool has no registered agents                           | Raises `RuntimeError("No agents are registered in the pool.")`                    |
| Valid agent resolved                                    | Logs `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

```bash theme={null}
openrtc list --agents-dir ./agents
```

This prints each registered agent and its configured providers. Registration order determines default fallback order.
