microscopic-dinner-57620
02/13/2026, 9:33 AM@function_tool
@log_exceptions(logger=logger)
async def provide_club_information(
self,
rephrased_user_query: str,
context: RunContext,
):
"""Retrieve club-related information or policies based on the user's intent.
"""
logger.debug(
f"User Query Rephrased by provide_club_information tool: {rephrased_user_query}"
)
await context.wait_for_playout()
because I am getting error like this
RuntimeError: cannot call SpeechHandle.wait_for_playout() from inside the function tool provide_club_information 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.tall-airline-16756
02/13/2026, 9:34 AMtall-airline-16756
02/13/2026, 9:34 AMawait context.wait_for_playout() from inside your provide_club_information function tool and getting this runtime error about a circular wait. You're right to question it — here's what is happening and how to fix it.
What causes the RuntimeError
• context.wait_for_playout() pauses until the agent's current speech finishes playing to the user.
• The function tool provide_club_information is part of the agent's response generation. The agent waits for the tool to finish before it considers the response (and its speech) complete.
• Calling wait_for_playout() from within the same tool makes the tool wait for the speech to finish, while the speech system is waiting for the tool to finish — a circular dependency that raises the RuntimeError.
What you can do instead
• Do not call context.wait_for_playout() from inside the tool that participates in generating the speech. That creates the circular wait.
• Move the wait_for_playout() call outside the function tool, into the higher-level flow that invoked the tool (the agent/runner) so speech can complete first and then you can await playout.
• If you need to coordinate actions relative to speech completion, use a callback or an external task that runs after the agent's response finishes, rather than blocking inside the tool.
• If you only need to ensure audio is fully sent or finalized (not necessarily that speech finished playing to the user), consider other synchronization points your system exposes (for example, state/events provided by the agent runner) rather than wait_for_playout() inside the tool.
If you'd like, tell me:
• Where you currently call provide_club_information from (agent/runner code), and
• What exact behavior you want after speech finishes (e.g., start another tool, log analytics, send follow-up message).
With that I can suggest a concrete refactor or show an example pattern to await playout outside the tool.
Sources: Agent speech and audio | LiveKit Documentationmicroscopic-dinner-57620
02/13/2026, 11:58 AMtall-airline-16756
02/13/2026, 11:58 AMend_call tool is typically invoked after the agent has finished generating the response and the speech playback has either finished or is in a state where waiting for playout does not depend on the tool completing. In other words, end_call runs outside (or after) the active speech’s critical path, so awaiting ctx.wait_for_playout() there does not create a circular dependency.
Why it fails in provide_club_information
• provide_club_information is being executed as part of the agent’s response generation. The agent will wait for that tool to return before it finalizes the response and completes the speech lifecycle.
• Calling await context.wait_for_playout() inside that same tool makes the tool wait for speech to finish, while the speech system is waiting for the tool to finish. That is a circular wait — the speech handle cannot complete because the agent hasn't finished (the tool is still running), and the tool cannot finish because it’s waiting for speech to complete. That deadlock is what raises the RuntimeError.
Key difference summary
• end_call: runs after/outside the active speech path → waiting for playout is safe.
• provide_club_information: runs inside the active speech path → waiting for playout causes circular wait and is disallowed.
What to do instead
• Move await context.wait_for_playout() out of provide_club_information into the caller/agent flow that invokes the tool, or into a tool that runs after the response/speech completes (like end_call).
• If you need follow-up work when playback finishes, attach that work to a post-playout handler or schedule it as a separate async task that is triggered after the agent’s response completes.
• If you share what behavior you want after playback (e.g., log analytics, start another tool, send a follow-up message), I can suggest a concrete pattern or code example that avoids the circular wait.
If you want, paste the call site where provide_club_information is invoked or describe the exact sequence you expect after speech finishes, and I’ll propose a refactor you can use.