tall-ability-14645
04/10/2026, 6:54 PMtall-airline-16756
04/10/2026, 6:55 PMtall-airline-16756
04/10/2026, 6:55 PMWarmTransferTask and a brief explanation of how it works.
Example (Python, Beta):
from livekit.agents import Agent, function_tool, RunContext
from livekit.agents.beta.workflows import WarmTransferTask
SUPERVISOR_PHONE = "+15551234567"
SIP_TRUNK_ID = "your-sip-trunk-id"
class SupportAgent(Agent):
@function_tool()
async def escalate_to_human(self, context: RunContext):
await self.session.say(
"I'm connecting you with a specialist now. I'll share our conversation so you won't need to repeat anything.",
allow_interruptions=False,
)
await context.wait_for_playout()
result = await WarmTransferTask(
sip_call_to=SUPERVISOR_PHONE,
sip_trunk_id=SIP_TRUNK_ID,
chat_ctx=self.chat_ctx,
)
# WarmTransferResult contains the human agent identity
return result
What this does (brief):
• Plays a message, then waits for playout to finish.
• Places caller on hold (default hold music) and creates a private consultation room.
• Dials the supervisor via SIP using sip_call_to and sip_trunk_id.
• Passes chat_ctx so the human receives conversation context.
• Moves the supervisor into the caller's room and disconnects the agents, returning a WarmTransferResult with human_agent_identity.
If you want, I can:
• Show how to pass custom hold_audio or extra_instructions.
• Convert this to another language or integrate with your SIP setup — which would you prefer? Sources: WarmTransferTask | LiveKit Documentation | The Handoff Pattern for Voice Agents That Replaces IVR Menus | LiveKit, with interactive elementstall-ability-14645
04/10/2026, 7:10 PMtall-airline-16756
04/10/2026, 7:10 PMhold_audio (BuiltinAudioClip.HOLD_MUSIC) or a custom audio file/stream?
• Which SDK/version of LiveKit Agents are you running?
• Does the issue reproduce with the stock warm-transfer example (no custom audio logic)?
• Are there any custom room/participant hooks or middleware that might keep audio playing after transfer?
Immediate suggestions you can try now:
1. If you use custom hold_audio, swap to the default BuiltinAudioClip.HOLD_MUSIC and retest to see if the MoH stops when connected.
2. Ensure your custom audio is finite (not an infinite loop/stream) and that playback is closed when WarmTransferTask completes.
3. Test with the latest LiveKit Agents release — media lifecycle fixes are included in recent updates.
4. Reproduce using the official warm-transfer example; if it stops there but not in your app, check for middleware or extra audio sources injecting MoH.
If you share which of the checklist items apply (especially whether you’re using custom hold audio and your Agents SDK version), I’ll give the next targeted steps.
Sources: WarmTransferTask | LiveKit Documentation | The Handoff Pattern for Voice Agents That Replaces IVR Menus | LiveKit | Background audio | LiveKit Documentation, with interactive elementstall-ability-14645
04/10/2026, 7:11 PMhold_audio argument at all. Agents version is 1.5.0tall-airline-16756
04/10/2026, 7:12 PMhold_audio and are on Agents v1.5.0.
Try these targeted steps:
1. Explicitly disable default MoH by calling WarmTransferTask with `hold_audio=None`:
result = await WarmTransferTask(
sip_call_to=SUPERVISOR_PHONE,
sip_trunk_id=SIP_TRUNK_ID,
chat_ctx=self.chat_ctx,
hold_audio=None,
)
1. After the transfer completes, ensure agent sessions are closing so no audio sources remain:
◦ Listen for the agent session close event or confirm WarmTransferResult returned before assuming cleanup.
1. If disabling MoH fixes it, you can implement manual hold playback that you stop explicitly when the supervisor is joined.
2. If MoH still persists with hold_audio=None, please tell me:
◦ A short call flow log (timestamps of hold start, SIP answered, transfer completion) or
◦ Whether you see any lingering published audio tracks for the agent or hold source in the room.
I’ll use that info to provide next troubleshooting steps.
Sources: WarmTransferTask | LiveKit Documentation | Agent session | LiveKit Documentation, with interactive elementstall-ability-14645
04/10/2026, 7:16 PMtall-airline-16756
04/10/2026, 7:16 PMfrom livekit.agents import Agent, function_tool, RunContext
from livekit.agents.beta.workflows import WarmTransferTask
from livekit.audio import BuiltinAudioClip # adjust import to your SDK layout
SUPERVISOR_PHONE = "+15551234567"
SIP_TRUNK_ID = "your-sip-trunk-id"
class SupportAgent(Agent):
@function_tool()
async def escalate_to_human(self, context: RunContext):
# 1) Start manual hold playback to the caller
# publish_hold returns a handle/track id in many SDKs; adjust to your API
hold_handle = await self.session.publish_audio(BuiltinAudioClip.HOLD_MUSIC)
# 2) Tell caller you're placing them on hold, wait for playout to finish
await self.session.say(
"I'm connecting you with a specialist now. Please hold for a moment.",
allow_interruptions=False,
)
await context.wait_for_playout()
# 3) Start the warm transfer but disable built-in MoH
result = await WarmTransferTask(
sip_call_to=SUPERVISOR_PHONE,
sip_trunk_id=SIP_TRUNK_ID,
chat_ctx=self.chat_ctx,
hold_audio=None, # we handle hold manually
)
# 4) Stop manual hold when supervisor is connected.
# WarmTransferResult indicates transfer completion; stop hold after result
await self.session.unpublish_audio(hold_handle)
# 5) Inform caller that the human is now connected
# Use session.say (non-interrupting) or a brief TTS
await self.session.say(
"You are now connected to a specialist. They will help you from here.",
allow_interruptions=True,
)
return result
Key notes and alternatives:
• Publish/unpublish API: Replace `publish_audio`/`unpublish_audio` and hold_handle with the exact methods your Agents SDK exposes for publishing and removing an audio source or track. The pattern is: publish an audio source/track for hold, keep its handle, then remove that handle when transfer completes.
• Stop timing: Stop/unpublish the hold immediately after WarmTransferTask returns a successful WarmTransferResult (that indicates the supervisor was joined), or listen for any explicit event that indicates the human was moved into the caller’s room.
• Informing the caller: Use session.say (TTS) right after stopping hold audio. Keep the message short and allow interruptions if the human may speak right away (allow_interruptions=True).
• If you need seamless handoff (no overlapping audio): unpublish hold audio first, then session.say immediately before/handover so the caller hears the single confirmation message and the human joins without overlap.
If you tell me the exact publish/unpublish method names your Agents SDK exposes, I’ll convert the placeholders into the precise calls for your version.
, with interactive elements