gorgeous-hydrogen-44699
02/13/2026, 1:39 PMtall-airline-16756
02/13/2026, 1:39 PMtall-airline-16756
02/13/2026, 1:39 PM@function_tool
async def detected_answering_machine(self, ctx: RunContext):
# Prevent user speech from interrupting this sequence
ctx.disallow_interruptions()
# Leave a message
await self.session.generate_reply(instructions="Leave a brief message that you'll call back later.")
# Optional: ensure audio finishes
await ctx.wait_for_playout()
# End the call for all participants
await ctx.api.room.delete_room(room_id)
Why this helps:
• ctx.disallow_interruptions() ensures the tool runs to completion even if the callee speaks, preventing mid-sequence cancellation that can truncate the call.
• Waiting for playout avoids cutting audio mid-sentence.
• Using the API to hang up (delete room or your telephony hangup) closes the call cleanly rather than leaving participants in a half-closed state.
If you'd like, tell me:
• Which SDK/language you’re using (so I can give exact code), and
• Whether you already call any wait-for-playout or hangup functions today.
I can provide a concrete code snippet for your environment and review where to place the disallow call in your current flow.
Sources: Tool definition and use | LiveKit Documentation | Agents telephony integration | LiveKit Documentation | Agent speech and audio | LiveKit Documentationgorgeous-hydrogen-44699
02/13/2026, 1:44 PMtall-airline-16756
02/13/2026, 1:44 PMctx.disallow_interruptions().
• Make sure any playout finishes before ending the call by awaiting a playout wait helper (for example ctx.wait_for_playout() if available).
• Hang up cleanly using your room/hangup API (avoid abruptly terminating the session without waiting for playout).
Example (adapted from your snippet — insert the correct room/hangup call for your environment):
async def detect_voice_mail(self, context: RunContext):
"""Call this immediately when you hear an automated voicemail greeting."""
# Ensure this sequence can't be interrupted by detected speech
context.disallow_interruptions()
# Mark voicemail detected for the agent logic
self.agent.voice_mail_detected = True
# Optional: if you play a message or generate a reply, do that here
# await self.session.generate_reply(instructions="Leave a brief message...")
# Wait for any playout to complete before hanging up
try:
await context.wait_for_playout()
except AttributeError:
# If wait_for_playout isn't available in your RunContext, you can use a short sleep
import asyncio
await asyncio.sleep(0.5)
# End the call cleanly (replace with your actual hangup/delete_room call)
await self.end_call_tool.end_call(context)
Notes on placement and behavior
• Call context.disallow_interruptions() immediately when you detect the voicemail greeting so downstream steps cannot be canceled by incoming speech.
• If your detection triggers while the callee is speaking, disallowing interruptions prevents that speech from canceling the voicemail flow and causing a mid-call cutoff.
• Waiting for playout (or a small sleep when playout waiting isn't available) prevents cutting off the final audio before the hangup.
• Ensure end_call_tool.end_call performs a clean hangup (for example, uses your API to delete the room or call so participants are disconnected gracefully).
Tool description suggestions Pick one that fits your UI tone; short and long options:
• Short (UI label): "Voicemail Detection"
• Short description: "Detects automated voicemail greetings and handles leaving a message without interrupting active calls."
• Longer description (for tool listing or docs):
"Automatically detects automated voicemail greetings (phrases like 'leave a message', 'after the tone', 'forwarded to voicemail') and runs a non-interruptible voicemail-handling sequence. The tool ensures audio playout completes and then ends the call cleanly so live calls are not cut off unexpectedly."
If you want a version tailored to a specific audience (developer, product, or end-user), tell me which and I’ll adapt it.
Next steps I can help with
• Provide a version of the code for a specific SDK or language if you tell me which one you’re using.
• Review your end_call_tool.end_call implementation to confirm it performs a graceful hangup.
• Add an example where the tool also plays a short message before hanging up.
Would you like the snippet converted to a specific SDK or to review your end_call implementation next?gorgeous-hydrogen-44699
02/13/2026, 1:49 PMtall-airline-16756
02/13/2026, 1:49 PMcontext.disallow_interruptions() (or equivalent) so voicemail handling no longer cuts off live calls.
Quick guidance you can consider right away
• Debounce detection: require two independent indicators (e.g., keyword + acoustic pattern) before triggering.
• Require multiple keyword matches or higher confidence thresholds instead of a single phrase.
• Add a short confirmation window (e.g., 500–1500 ms) to watch for human-like responses before executing voicemail flow.
• If you can, prefer metadata signals (carrier voicemail flags, SIP headers) to avoid audio-only false positives.
• Always call context.disallow_interruptions() at the start of the voicemail-handling sequence so when it does run it won't be interrupted.
Tell me which detection methods you use and whether you can accept a small confirm delay. I’ll provide tailored code changes and a suggested confidence/timeout policy.gorgeous-hydrogen-44699
02/13/2026, 1:51 PMtall-airline-16756
02/13/2026, 1:52 PMcontext.disallow_interruptions() so the sequence cannot be canceled by incoming speech.
2. If you play or generate any audio, wait for playout to finish—use await context.wait_for_playout() if available, or a short await asyncio.sleep(0.5) fallback—before hanging up.
3. Ensure your hangup path performs a clean disconnect (e.g., ctx.api.room.delete_room(room_id) or your existing end_call_tool.end_call) so participants aren’t left in a half-closed state.
Prompt + LLM-side guardrails (reduce false positives)
• Require multiple signals: change the LLM prompt to only trigger voicemail when it sees both a clear voicemail phrase (e.g., "leave a message", "after the tone", "forwarded to voicemail") AND at least one additional indicator (long continuous playback, absence of conversational reply, or a carrier/SIP voicemail flag).
• Raise confidence threshold: instruct the LLM to only call the tool when the predicted probability/confidence of "voicemail" is high (e.g., > 0.85), or when the same conclusion appears across N consecutive model inferences.
• Add a confirmation window: after the LLM predicts voicemail, wait 500–1500 ms to see if any human-like speech/response occurs. If human speech is detected in that window, cancel the voicemail flow.
• Require two independent detectors: have the LLM’s decision be validated by a secondary heuristic (e.g., keyword matcher or acoustic classifier) before triggering the tool.
• Be conservative on single-keyword matches: don’t trigger on a single low-information phrase such as "not available" unless paired with other evidence.
• Use explicit negative checks: instruct the LLM not to trigger if it detects conversational cues (questions, short answers, interruptions, or back-and-forth exchanges) in the recent audio.
Suggested prompt patterns
• Add a short checklist to the prompt: “Only call the voicemail tool if all of the following are true: 1) an automated greeting contains voicemail phrases, 2) audio shows long continuous playback or beep, 3) no human response occurs within 1 second, 4) confidence >= 0.85.”
• Ask the LLM to output a structured decision object: {decision: "voicemail" | "human", confidence: 0.0-1.0, reasons: [..]} so your orchestrator can apply deterministic thresholds before invoking the tool.
Concrete orchestration pattern
1. LLM processes audio and returns structured decision + confidence + reasons.
2. Orchestrator checks: if decision == "voicemail" AND confidence >= threshold AND at least one corroborating heuristic is true -> call voicemail tool.
3. If decision is borderline, buffer 500–1500 ms and re-evaluate with new audio before acting.
4. If voicemail tool is invoked, it starts with context.disallow_interruptions() and follows the playout/wait/hangup flow.
Tool description suggestions (final)
• Short label: "Voicemail Detection"
• Short description: "Detects automated voicemail greetings and safely handles leaving a message without interrupting active calls."
• Longer description: "Detects automated voicemail greetings (phrases like 'leave a message', 'after the tone', 'forwarded to voicemail') and runs a non-interruptible voicemail-handling flow that finishes audio playout and then ends the call cleanly. The tool is only triggered when multiple voicemail indicators are present to avoid false positives."
Next step — please paste:
1. The exact LLM prompt or trigger text you currently use to instruct the model to call the voicemail tool.
2. If possible, the structured output your LLM currently provides (if any), and whether it returns a numeric confidence score.
3. Whether you can accept a 500–1500 ms confirmation delay.
Once you share the prompt and answers, I’ll:
• Propose a revised prompt with guardrails.
• Show a small orchestrator snippet that applies the thresholds and confirmation window.
• Optionally convert the voicemail tool snippet to your exact runtime/SDK if you tell me which one you use.