I am trying to setup a goodbye function. The agent...
# ask-ai
m
I am trying to setup a goodbye function. The agent sucessfully calls the function/tool call but hangs up halfway through the goodbye message
t
Thanks for reaching out, Matt. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
To address the issue of the goodbye function hanging up halfway through the message, here are some steps you can take: 1. Ensure Message Completion Before Hangup: Use
allow_interruptions=False
when generating the goodbye message to prevent interruptions. Await the message generation to ensure it completes before proceeding. For example:
Copy code
@function_tool
async def story_finished(self, context: RunContext[StoryData]):
    self.session.interrupt()
    await self.session.generate_reply(
        instructions=f"say goodbye to {context.userdata.name}", 
        allow_interruptions=False
    )
    job_ctx = get_job_context()
    await job_ctx.api.room.delete_room(api.DeleteRoomRequest(room=job_ctx.room.name))
1. Wait for Current Speech to Complete: If there is ongoing speech, wait for it to finish before proceeding with the hangup. For example:
Copy code
@function_tool
async def end_call(self, ctx: RunContext):
    current_speech = ctx.session.current_speech
    if current_speech:
        await current_speech.wait_for_playout()
    await hangup_call()
1. Proper Session Drainage: Use
session.drain()
before closing to ensure all pending audio is processed. For example:
Copy code
@function_tool
async def end_session(self):
    await self.session.drain()
    await self.session.aclose()
1. Avoid Premature Task Creation: Do not create the close task immediately after generating the reply. Instead, await the reply first. For example:
Copy code
@function_tool
async def goodbye(self):
    await self.session.generate_reply(instructions="instructions:say goodbye to the user")
    self._close_session_task = asyncio.create_task(self.session.aclose())
By following these steps, you can ensure the goodbye message is fully delivered before the session ends. Sources: Community & Support | livekit/livekit_composite | DeepWiki | examples/voice_agents/session_close_callback.py | Agents telephony integration | LiveKit Docs | basics/exit_message.py | Community & Support | livekit/livekit_composite | DeepWiki
m
Failed to end call: cannot call
SpeechHandle.wait_for_playout()
from inside the function tool
end_call
that owns this SpeechHandle. This creates a circular wait: the speech handle is waiting for the function tool to complete, while the function tool is simultaneously waiting for the speech handle.
t
Hey there! I totally get the frustration with this tricky error. Let me break down what's happening in a way that'll help you solve this smoothly. When you call
SpeechHandle.wait_for_playout()
inside the same function that owns the speech handle, you're accidentally creating a circular dependency - kind of like getting tangled up in your own code. 😅 The good news? There's a super simple fix! Just switch to using
RunContext.wait_for_playout()
, which lets you wait for the assistant's response without causing any technical headaches. Think of it like taking a quick pause to make sure everything's in sync. Here's how you can update your code to work perfectly:
Copy code
async def my_function_tool(ctx: RunContext) -> str:
    # Wait for the assistant's spoken response prior to running this tool
    await ctx.wait_for_playout()  # ✅ Correct approach

    # Your tool logic here
    return "Tool completed"
By using
RunContext.wait_for_playout()
, you'll ensure your function tool runs smoothly, without any pesky circular wait issues. Hope this helps make your coding journey a bit easier! 🌟 Sources: livekit-agents/livekit/agents/voice/background_audio.py