cuddly-vr-85751
03/22/2026, 12:30 PMtall-airline-16756
03/22/2026, 12:31 PMtall-airline-16756
03/22/2026, 12:31 PMcuddly-vr-85751
03/22/2026, 12:31 PMtall-airline-16756
03/22/2026, 12:31 PMtransfer_context["sip_trunk_id"]? You already check this in code, but confirm it’s set and valid.
• Does your SIP provider allow caller-ID passthrough for the sip_number you send? If the trunk rejects the sip_number, the SIP leg may fail even though the agent’s phone rings.
1. Observe SIP participant events and logs
• Can you share logs or events for the SIP participant created by ctx.api.sip.create_sip_participant? Look for sip.callStatus changes (dialing → ringing → active → hangup). If it goes to hangup right after active, that indicates the SIP leg dropped quickly.
• Any exception trace from the try/except around create_sip_participant? Your code wraps it and raises ToolError; include the original exception text if available.
1. Confirm wait-until-answered behavior
• You use wait_until_answered=True. Does the human agent actually press accept on their phone and stay on the line (not auto-reject)? Some phones/softclients auto-answer or immediately send a transfer response—confirm the agent’s endpoint behavior.
• If possible, test with wait_until_answered=False to see if behavior differs (this can reveal whether waiting is causing a race).
1. Verify agent session lifecycle
• After the SIP participant answers, you call agent_ref.session.say(...) and then agent_ref.session.shutdown(). Confirm that agent_ref.session.shutdown() is not triggered prematurely (for example, if the session thinks the agent handoff was already completed). Do you see any session shutdown events right after the introduction phrases?
• Try temporarily removing or delaying session.shutdown() to observe whether the agent connection remains.
1. Caller audio / hold-state
• Is the caller put on hold or hearing hold audio while you dial the agent? If the caller I/O is disabled or muted, agent may think caller disconnected. Confirm the caller remains connected to the room during the warm transfer steps.
1. Destination format and stripping
• You strip prefixes with .removeprefix("tel:").removeprefix("sip:"). Confirm dest is a valid e164 or SIP URI after stripping. Print/log dest before calling create_sip_participant to verify.
1. Quick tests you can run now
• Enable more verbose logging around the SIP create call (print the request and the resulting participant ID/status).
• Try calling a test number you control and watch SIP traces on the provider side to see if INVITE/200/ACK occur and if the provider sends a BYE.
• Temporarily replace the SIP dial with a non-SIP participant (if supported) to isolate whether the issue is SIP-specific or your session tooling.
If you can, please paste:
• Any exception text or stack trace from the ToolError when the transfer fails.
• Recent SIP participant events showing sip.callStatus.
• The values for sip_trunk_id, dest (masked if sensitive), and whether caller_id was set or left None.
What I can help with next
• Interpret SIP participant events and the exception trace you share.
• Suggest small code changes (examples) to add logging or to adjust when shutdown() runs.
• If the trunk is rejecting caller ID, suggest alternatives (use trunk-verified caller or notify human agent and then use SIP REFER transfer).
Send the logs/events and answers to the checks above and I’ll walk you through the next debugging steps.
Sources: WarmTransferTask | LiveKit Documentation | Preserving Caller ID During SIP Transfers in LiveKit Agents | Agents telephony integration | LiveKit Documentation | Company directory phone assistant | LiveKit Documentation | Job lifecycle | LiveKit Documentation, with interactive elementscuddly-vr-85751
03/22/2026, 12:34 PMtall-airline-16756
03/22/2026, 12:34 PMtransfer_context["sip_trunk_id"] is set and points to the outbound trunk used for this transfer.
• Does your SIP provider allow the trunk to present the agent’s number as sip_number? Some providers block unverified caller IDs and will fail the outbound call even though it rings briefly. If you’re not sure, try a test where sip_number is left blank or set to a verified number.
2) SIP participant events / status
• Please share the SIP participant events or logs around the transfer attempt (especially sip.callStatus values). Look for the sequence: dialing → ringing → active → hangup. If you see hangup immediately after active, the agent leg is likely dropping.
• If you have an exception stack trace from the try/except that raises ToolError("Failed to reach human agent: ..."), paste it here.
3) Verify dest and caller_id values used at runtime
• Log the dest (after removeprefix) and caller_id immediately before calling create_sip_participant. Confirm dest is a valid e164 number (e.g., +1619...) or SIP URI and not empty.
• From your config, transfer_to is "tel:+1619...", so dest should be correct, but please confirm the actual runtime string.
4) Confirm agent endpoint behavior
• Does the human agent actually accept the call and stay connected? Some endpoints auto-answer and then immediately close or send a transfer response that your flow treats as completion.
• Try calling a phone you control to reproduce and watch if you can stay on the line.
5) session.shutdown() timing
• You call agent_ref.session.shutdown() after announcing "Connecting the caller to you now." If the session believes the transfer already completed (or if there’s a race), shutdown may run too early.
• As a quick test, comment out or delay session.shutdown() (e.g., sleep 10–15s) to see if the caller actually connects and the agent remains on the line.
6) Additional quick tests
• Temporarily set wait_until_answered=False to see whether behavior changes (this can reveal if waiting is causing a timing issue).
• Try using the LiveKit WarmTransferTask (if available in your stack) which handles hold music, separate human agent room, and connectors — it implements a proven handoff flow and can help isolate whether the problem is your orchestration or SIP leg behavior.
What to paste here for fast diagnosis
• Any exception text from the raised ToolError.
• SIP participant event timeline showing sip.callStatus.
• The runtime values (or logs) for sip_trunk_id, dest, and caller_id (mask sensitive digits if needed).
If you prefer, I can suggest small code changes to add logging and to change the shutdown flow so we can observe where the handoff drops. Which logs can you share now?
, with interactive elements