how can I find out if a user hangs up in the agent...
# ask-ai
w
how can I find out if a user hangs up in the agent code?
t
Thanks for reaching out, Marius. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
You're asking how to detect when a user hangs up in the agent code. The most direct way is to listen for the AgentSession
close
event — it's emitted when the session ends (user disconnected, room deleted, or error). Example (Python-style):
Copy code
@session.on("close")
async def on_close(event):
    if event.error:
        logger.error(f"Session ended with error: {event.error}")
    else:
        <http://logger.info|logger.info>("User hung up or session ended gracefully")
You can also register a shutdown callback to run cleanup when the session is ending:
Copy code
async def on_shutdown():
    <http://logger.info|logger.info>("Agent session is shutting down (user may have hung up)")

ctx.add_shutdown_callback(on_shutdown)
If you need per-participant disconnection (in multi-participant rooms), monitor participant disconnection events on the Room object instead. Would you like a language-specific example (Node/Go/Python) or guidance for multi-participant handling? Sources: Events and error handling | LiveKit docs | How to detect and handle silence during calls
w
I am using DTMF to transfer users. In that case they also leave the room. I must find out when the caller hangs up, and I must seperate when a user hangs up, and when it is transferred using DTMF
t
Thanks — you're asking how to detect a real caller hang-up vs a DTMF-initiated transfer when the participant leaves the room. You can reliably distinguish them by combining SIP call status attributes with an explicit transfer state in your agent logic. What to do (concise): • Check
sip.callStatus
on the SIP participant: ◦
sip.callStatus == "hangup"
→ caller hung up. ◦ Other statuses like
active
,
automation
,
dialing
indicate call still active or in transfer flow. • Track when your agent initiates a DTMF transfer: ◦ Set a short-lived flag (e.g.,
is_transferring = True
) before sending DTMF, clear it after transfer completes or after a timeout. ◦ When a participant disconnects, if
is_transferring
is true treat it as a transfer; otherwise consult
sip.callStatus
. • Monitor events: ◦ Listen for
participant_disconnected
or the AgentSession
close
event to detect the leave. ◦ Also subscribe to
participant_attributes_changed
and watch
sip.callStatus
changes for confirmation. Example pattern (Python-style):
Copy code
self.is_transferring = False

async def transfer_with_dtmf(...):
    self.is_transferring = True
    await self.session.room.local_participant.publish_dtmf(digits)
    # optionally wait/validate transfer completion
    await asyncio.sleep(1)
    self.is_transferring = False

@room.on("participant_disconnected")
def on_participant_disconnected(participant):
    call_status = participant.attributes.get("sip.callStatus")
    if self.is_transferring:
        <http://logger.info|logger.info>("Participant left: treated as DTMF transfer")
    elif call_status == "hangup":
        <http://logger.info|logger.info>("Participant hung up")
    else:
        <http://logger.info|logger.info>(f"Participant left, status: {call_status}")
Would you like a Node or Go code example, or help deciding where to place the transfer flag in your current agent flow? Sources: SIP participant | LiveKit docs | SIP Lifecycle Management Agent | LiveKit docs | Handling DTMF | LiveKit docs