gorgeous-hydrogen-44699
12/20/2025, 2:16 PMtall-airline-16756
12/20/2025, 2:16 PMtall-airline-16756
12/20/2025, 2:16 PMmove_participant. You’re seeing that error because move_participant is only available on LiveKit Cloud and is not supported on self‑hosted LiveKit Server. That’s why WarmTransferTask’s call to move_participant fails in your environment.
What you can do instead
• Use a same‑room warm transfer (co‑location): invite/add the human agent into the same room as the caller and AI agent, then hand off conversation state via metadata or client logic. This avoids move_participant entirely and works on all LiveKit deployments.
• Promote the agent’s role or update participant metadata to indicate the transfer state so clients know who should speak/listen.
• If you’re using SIP, create the SIP participant into the same room and preserve caller ID using sip_number in CreateSIPParticipantRequest.
If you want, I can:
• Provide a short code snippet to catch the Twirp error and perform the fallback (add agent to the room).
• Show an example flow for signaling transfer state with participant metadata or TrackPublication events.
Quick question to confirm next steps: are you running LiveKit Cloud or a self‑hosted LiveKit Server?
Sources: Managing participants | LiveKit docs | Preserving Caller ID During SIP Transfers in LiveKit Agentsgorgeous-hydrogen-44699
12/20/2025, 2:19 PMtall-airline-16756
12/20/2025, 2:19 PMmove_participant error and falls back to adding the human agent to the same room, plus a clear transfer flow.
Flow (fallback same-room warm transfer)
1. AI and caller are in Room A.
2. AI decides to escalate and notifies the caller: “I will add a human agent.”
3. AI attempts to call move_participant (if code tries it). If that fails (not supported), catch the error.
4. Fallback: create or invite the human agent into Room A (e.g., via SIP outbound call or creating a participant for the agent).
5. Wait for human agent to join; update participant metadata/roles to indicate transfer status.
6. Once human is connected, AI either mutes/stops its media or leaves the room (depending on desired UX).
7. Use metadata or TrackPublication events so clients switch focus to the human agent.
Minimal Python example (async) — catch TwirpError and fall back to SIP invite into the same room
from livekit import api # replace with your LiveKit API client import
from livekit import twirp_errors # placeholder for Twirp error types
import os
async def transfer_to_human(job_ctx, session):
room_name = job_ctx.room.name
# Optional: try move_participant if your environment might be LiveKit Cloud
try:
await job_ctx.api.move_participant(
api.MoveParticipantRequest(
room_name=room_name,
participant_identity=job_ctx.participant.identity,
target_room="support-room",
)
)
await session.generate_reply(instructions="Transferring you to a support room...")
return
except twirp_errors.TwirpError as e:
# move_participant not implemented on self-hosted servers
# fall back to same-room transfer
# (You can narrow by checking e.code or message if needed)
pass
# Fallback: create SIP participant (call human into same room)
try:
await job_ctx.api.sip.create_sip_participant(
api.CreateSIPParticipantRequest(
room_name=room_name,
sip_trunk_id=os.getenv("HUMAN_SIP_TRUNK_ID"),
sip_call_to=os.getenv("HUMAN_PHONE_NUMBER"),
participant_identity="human-support-agent",
wait_until_answered=True, # block until human answers (optional)
)
)
await session.generate_reply(instructions="A human agent is joining now.")
except Exception:
await session.generate_reply(
instructions="I couldn't connect a human agent right now. Please hold while I try again or transfer you another way."
)
Notes and suggestions
• Use participant metadata or a role field to signal to clients which participant is the human agent and when transfer is complete.
• For SIP, set sip_number or appropriate fields to preserve caller ID as needed.
• If you want the AI to gracefully exit after the human joins, have the AI stop publishing tracks or call a participant update/delete API.
If you’d like, I can:
• Provide a JavaScript/TypeScript equivalent snippet.
• Show example metadata payloads and client-side logic for switching UI to the human agent. Which would you prefer? Sources: Managing participants | LiveKit docs | Agents telephony integration | LiveKit docs | Outbound Calling Script | LiveKit docs