aloof-scooter-47164
12/31/2025, 9:00 PM// Configure room without automatic agent dispatch
token.roomConfig = new RoomConfiguration({
name: roomName,
emptyTimeout: ROOM_EMPTY_TIMEOUT_SEC,
departureTimeout: ROOM_DEPARTURE_TIMEOUT_SEC,
maxParticipants: 4,
minPlayoutDelay: ROOM_MIN_PLAYOUT_DELAY_MS,
maxPlayoutDelay: ROOM_MAX_PLAYOUT_DELAY_MS,
metadata: JSON.stringify({
deviceId,
userId,
}),
// No agents array - agents will be dispatched on-demand
});tall-airline-16756
12/31/2025, 9:00 PMtall-airline-16756
12/31/2025, 9:00 PMagents array in roomConfig and agents dispatched on-demand, there’s no built‑in 10‑agent limit — agents can be dispatched explicitly (AgentDispatchService, CLI, or agent participant tokens) and agent participants are distinct from regular participants.
To confirm for your environment, please tell me:
1. Which product/version are you using (self‑hosted LiveKit, managed LiveKit, or a third‑party service/SDK)?
2. How are you dispatching agents in practice (AgentDispatchService/CLI, agent tokens, or automatic config)?
3. Are agents joining as ParticipantKind.AGENT in your code?
4. Any errors or logs you see when dispatch stops (e.g., after ~10 agents)?
With those details I’ll verify whether anything in your setup could be enforcing a limit and suggest next steps.
Sources: Agent dispatch | LiveKit docs | livekit/livekit_composite | DeepWikialoof-scooter-47164
12/31/2025, 9:02 PMtall-airline-16756
12/31/2025, 9:02 PMmaxParticipants controls.
Short answer
• Preventing multiple agents is not automatic — enforce it in your dispatch logic.
• maxParticipants limits human/standard participants, not agents.
How to enforce a single agent per room (options)
• Explicit dispatch with server-side guard (recommended): before calling AgentDispatchService (or issuing an agent token), check room state in your backend (e.g., via room participant list or your own room record). Only dispatch if no participant with ParticipantKind.AGENT is present.
• Dispatch via token at room creation: include a single RoomAgentDispatch in the room config embedded in the participant’s token so one agent is requested at join. Also ensure your server blocks any later dispatch calls for that room.
• Single agent registration: register only one worker with a given agent_name. That prevents multiple distinct agents with the same name from being concurrently assigned, but you still must prevent additional dispatch calls.
Practical checks to implement
• Query the room participants (or maintain a backend flag) to detect any AGENT participant before dispatching.
• On agent connect, mark the room as “agent-occupied”; clear it on agent disconnect/timeout.
• Return a clear error when dispatch is attempted while the room is occupied, so callers know why the dispatch failed.
About maxParticipants
• maxParticipants caps standard (human/external/SIP) participants in the room. It does not apply to AGENT participants. Use application-level logic (above) to limit agents.
If you want, tell me how you currently dispatch agents (API/CLI/token) and whether agents register with `agent_name`; I’ll give a short code snippet or sequence for the exact place to check/guard in your flow.
Sources: Agent dispatch | LiveKit docs | Agents Framework | livekit/livekit_composite | DeepWikialoof-scooter-47164
12/31/2025, 10:01 PMtall-airline-16756
12/31/2025, 10:02 PMagent_name and room. LiveKit will handle creating the room if needed and will avoid duplicate agent runs for the same dispatch. No pre-checks required.
• Token-based single dispatch: embed a single RoomAgentDispatch in the participant token at room creation to request one agent at join. This prevents duplicates during the join flow.
• Lightweight server-side guard (optional): maintain a small atomic flag or record (e.g., Redis SETNX or a DB transaction) per room that you set when dispatching and clear on agent disconnect. This prevents redundant dispatch calls for logging/metrics or to reduce API calls, but is not required for correctness.
When to use the guard
• Use it if you care about minimizing repeated API calls, consistent logging of who dispatched, or avoiding transient race attempts in your callers. Otherwise rely on direct dispatch idempotency.
If you want, tell me which dispatch method you use (API, CLI, or token) and I’ll give a 3–5 line snippet showing the exact call or a small Redis pattern for the optional guard.
Sources: Agent dispatch | LiveKit docsaloof-scooter-47164
12/31/2025, 10:02 PMtall-airline-16756
12/31/2025, 10:03 PMagent_name or different dispatch metadata are treated as distinct and can start separate agents.
• Worker registration: multiple agent workers registered under different names or without a single authoritative agent_name can result in more than one worker running for a room.
• External/manual dispatch: someone or some process may be issuing additional dispatch calls (CLI, scheduled jobs, or retries).
• Token + API overlap: a token-based dispatch at join plus a subsequent API dispatch can lead to two agents if both succeed.
Foolproof patterns to enforce single-agent-per-room 1) Idempotent dispatch with a single authoritative agent_name
• Always dispatch with the same agent_name. The dispatch system will treat repeated requests with identical agent_name+room as the same logical dispatch.
• Avoid issuing dispatches using different names/metadata for the same agent role.
2) Server-side atomic guard (recommended for production)
• Before calling create_dispatch, perform an atomic check-and-set on a fast store (Redis SETNX or DB row with transaction): set key room:{roomName}:agent = agent_name with short TTL. If SETNX fails, abort dispatch.
• On agent connect, clear or extend the key; on agent disconnect, clear it. This prevents concurrent callers from issuing multiple dispatches.
3) Verify and dedupe after dispatch (safety net)
• After create_dispatch returns, confirm the active dispatch record or check room participants for an AGENT. If multiple agents are present, programmatically stop extra dispatches (AgentDispatchService.delete) for duplicates.
4) Use token-based single dispatch for join flows (when applicable)
• Embed one RoomAgentDispatch in the room token so only one agent is requested at creation. Don’t also call create_dispatch for the same room concurrently.
Minimal implementation suggestion (Redis SETNX pattern)
• SETNX room{room}agent <agent_name> EX 300 => success => call create_dispatch
• If SETNX fails => another dispatch is in-flight/active => do not dispatch
• On agent connected or on heartbeat, extend TTL; on disconnect, DEL the key.
What I need from you to give an exact snippet
• Which dispatch method are you using now? (AgentDispatchService API, CLI, or token-based)
• Are you using agent_name consistently?
• Do you have a fast store available (Redis) or do you prefer a DB transaction?
Tell me those and I’ll give a 3–6 line code snippet for your stack (Redis or DB) or the exact API call pattern to prevent duplicates.aloof-scooter-47164
12/31/2025, 10:06 PMtall-airline-16756
12/31/2025, 10:06 PMagent_name. That helps.
Short answer: add a cheap atomic guard around your dispatch call (Redis SETNX or a DB transactional flag) so concurrent callers can't create duplicate dispatches. Even with a single agent_name, race conditions or retries can still start multiple agents unless you serialize attempts.
Recommended pattern (Redis SETNX — 3 steps)
1. Attempt to acquire lock:
◦ SETNX room:{roomName}:agent <agent_name> EX 300
◦ If SETNX fails -> another dispatch in-flight/active → abort.
1. Call AgentDispatchService.create_dispatch(...).
2. On agent connect, extend TTL or replace the key; on agent disconnect or stop, DEL the key.
Minimal pseudo-JS (node-style):
const key = `room:${roomName}:agent`;
const got = await redis.setnx(key, agentName);
if (!got) throw new Error('agent already dispatching');
await redis.expire(key, 300);
await agentDispatch.createDispatch({ agent_name: agentName, room: roomName });
// on agent connected: redis.expire(key, 3600)
// on disconnect: redis.del(key)
Notes and extras
• Keep TTL short enough to recover from crashed dispatches but long enough to avoid races.
• After create_dispatch, you can verify room participants and delete extras if you see duplicates as a safety net.
• If you can’t use Redis, same idea with a DB row + transactional INSERT/unique constraint.
If you want, I can give a 4–6 line example for your language (Python, Go, or JavaScript) or a recommended TTL value based on your agent startup time. Which language do you use?aloof-scooter-47164
12/31/2025, 10:12 PMtall-airline-16756
12/31/2025, 10:12 PMconst dispatches = await lkApi.agentDispatch.listDispatch({ room: roomName });
if (dispatches.length === 0) {
// safe to create_dispatch
}
• Python-like
dispatches = await lkapi.agent_dispatch.list_dispatch(room=room_name)
if len(dispatches) == 0:
# safe to create_dispatch
Combining with your atomic guard (recommended)
• Acquire your Redis SETNX lock first.
• Call list_dispatch(room) as a final check (optional) then call create_dispatch.
• After create_dispatch returns, call list_dispatch/get_dispatch to confirm and clear/set your room key appropriately.
If you want, tell me which SDK/language you prefer and I’ll give a 4–6 line concrete snippet for that stack.
Sources: Agent dispatch | LiveKit docsaloof-scooter-47164
12/31/2025, 10:13 PMtall-airline-16756
12/31/2025, 10:13 PM