Hello everyone! Anyone else having trouble with wa...
# agents
e
Hello everyone! Anyone else having trouble with wait_if_not_interrupted, wait_for_playout and/or speech_handle.interrupted not working? We dispatch outbound calls and because of that we needed a tool that leaves a voice mail message. My problem is that sometimes the automated message from the user interrupts the agent, preventing the agent to speak the message, but the tool just keeps going ending the call without ever leaving a message. I am following this for reference. GPT 4.1, cartesia for tts and deepgram for stt
r
e
Hi @refined-appointment-81829! That's what I followed for my implementation. This is what I have right now:
Copy code
message_spoken = False
        while not message_spoken:
            voicemail_task = asyncio.ensure_future(handle_voicemail())
            await context.speech_handle.wait_if_not_interrupted([voicemail_task])
            current_speech = context.session.current_speech
            if context.speech_handle.interrupted:
                voicemail_task.cancel()
                logger.debug(f"VOICEMAIL: Message interrupted {self._conversation_id}")
                self._leaving_voicemail = False 
                return
            
            if current_speech:
                await context.wait_for_playout()
                <http://logger.info|logger.info>(
                    f"📞 END_CALL: Speech playout completed for conversation {self._conversation_id}"
                )

            if context.speech_handle.interrupted:
                logger.debug(
                    f"VOICEMAIL: Interrupted after playout for conversation {self._conversation_id}"
                )
                voicemail_task.cancel()
                self._leaving_voicemail = False
                return
            message_spoken = True
            logger.debug(f"VOICEMAIL: Hanging up conversation {self._conversation_id}")
            now = datetime.now(timezone.utc)
            await log_event(
                message="Call ended after leaving voicemail",
                conversation_id=self._conversation_id,
                message_metadata=json.dumps(
                    {"livekit": {"voice": True, "reason": "voicemail"}}
                ),
                raw_content="Voicemail detected, message left, call ended",
                message_type="voice_call_ended",
                function_name="detected_answering_machine",
                delivered_at=now,
                trigger_call_summary=True,
            )
            await hangup_call(comms_api_client, egress_id=self._egress_id, immediate=True)
            self._leaving_voicemail = False
r
We used to have some voice mail examples but I am struggling to find them at the moment
e
I know there is a bunch of unecessery stuff in there but I'm getting desperate here
That handle_voicemail function is just a generate_reply and a log
r
This is an example that @clever-pharmacist-81891 uses in his project:
Copy code
import asyncio
from re import L
from livekit.agents import get_job_context
from livekit import api
from lk.types.userdata import RunContext_T
from logging import getLogger

logger = getLogger(__name__)

async def detected_answering_machine(context: RunContext_T) -> str:
    """Handle detected voicemail system by leaving a message and ending the call.
    
    This should be called AFTER hearing the voicemail greeting.
    """
    try:
        <http://logger.info|logger.info>("Detected answering machine, leaving voicemail message")
        # Leave voicemail message
        await context.session.generate_reply(
            instructions="Leave a brief, professional voicemail message. Include your name, the purpose of your call, and ask them to call back. Be concise and speak clearly. Example: 'Hi, this is [your name]. I'm calling regarding [goal]. Please call back when convenient. Thank you.'",
            allow_interruptions=False
        )
        await asyncio.sleep(2)  # Add a natural gap to the end of the voicemail message
        
        # Automatically end the call after leaving voicemail
        from .end_call import end_call
        await end_call(
            context=context,
            summary="Reached voicemail, left message",
            mission_completed=False,
            mission_result="Left voicemail message requesting callback"
        )
        
        return "Voicemail message left and call ended successfully."
    except Exception as e:
        logger.error('Error handling voicemail', exc_info=True)
        return f"Error handling voicemail: {str(e)}"
e
Thanks! That's close to what I had initially. What motivated all of the mess above was that sometimes the agent would trigger the tool while the automated message is still playing, either because of problems with turn detection or because some people have very long gaps in their messages. This would cause the agent to start speaking before the beep and, in the end, parts of or the whole message wouldn't be saved. What I was trying to do is to allow the agent to be interrupted but always go back and say the message from the start after it gets interrupted Have you ever faced something similar @clever-pharmacist-81891
c
I haven't been as concerned about it with my personal outbound agents, but there are plenty of solutions. For example, with Twilio, you can subscribe to their webhooks, and they'll notify you when to trigger the
generate_replay
function. https://www.twilio.com/docs/voice/answering-machine-detection