pipecat version
1.0.0 (from pypi)
Python version
3.14.4
Operating System
macOS (Apple Silicon)
Issue description
A RuntimeWarning fires — and more importantly the Gemini Live session stalls for ~10 seconds — when a function call dispatched by GeminiLiveLLMService is cancelled by an interruption broadcast originating from TranscriptionUserTurnStartStrategy.
This is distinct from #3588:
#3588's fix (a finally: cancel_task(timeout_task) block) targets the inner timeout handler; it does not address this outer-coroutine leak on interruption cancellation.
The warning is a symptom. The substantive problem is that Gemini Live never receives the function-call result, and its session sits idle producing zero completion tokens for ~10 seconds until the next user utterance triggers a server-side VAD interruption and unsticks it. For an agent that performs many tool calls in a conversation, this is a meaningful UX regression, not cosmetic.
Reproduction steps
- Use
examples/realtime/realtime-gemini-live-function-calling.py with GeminiLiveLLMService (not Vertex), Daily transport in direct mode (-t daily -d).
- Speak a question that fires a registered function (e.g. "What's the weather in Tokyo?"). The very first turn of a fresh session reliably triggers the race; later turns hit it occasionally.
- Observe:
_handle_msg_input_transcription logs the user text
_on_user_turn_started fires broadcast_interruption
_run_function_call starts
_cancel_function_call fires within ~1 ms
RuntimeWarning: coroutine 'LLMService._run_function_call' was never awaited is emitted
- The next 10+ seconds show
TTFB: 10.421s, prompt tokens: 0, completion tokens: 0 — Gemini produces nothing because it's still waiting for the cancelled tool result
- Only the next user utterance's Gemini-VAD interruption signal unblocks the session
Expected behavior
The function call should either:
- Not be cancelled by a same-turn interruption broadcast (the tool was requested by the current turn; interrupting the current turn shouldn't kill it), or
- If cancellation is required, its outer coroutine should be awaited/cancelled cleanly and Gemini should be notified so it doesn't stall waiting for an undelivered result.
No RuntimeWarning in either case.
Actual behavior
RuntimeWarning: coroutine 'LLMService._run_function_call' was never awaited
- Session stalls for ~10 seconds (0 completion tokens,
TTFB: 10.421s)
- Stalled state only clears when the next user utterance triggers a fresh VAD interruption
Logs (trimmed to the critical window)
18:15:28.682 [Transcription:user] [Oh, what's the weather in Tokyo?]
18:15:28.683 _on_user_turn_started (TranscriptionUserTurnStartStrategy#0)
18:15:28.683 broadcast_interruption
18:15:28.687 _on_user_turn_stopped (TurnAnalyzerUserTurnStopStrategy#0)
18:15:28.689 Cancelling function call [get_current_weather:fc_13054767619604724024]...
18:15:28.690 Function call [get_current_weather:...] has been cancelled
/path/to/python3.14/asyncio/events.py:94: RuntimeWarning:
coroutine 'LLMService._run_function_call' was never awaited
18:15:28.696 FunctionCallsStartedFrame: ['get_current_weather:...']
18:15:28.697 FunctionCallCancelFrame: [get_current_weather:...]
18:15:39.110 Gemini VAD: interrupted signal received
18:15:39.111 broadcast_interruption (GeminiLiveLLMService#0)
18:15:39.111 TTFB: 10.421s
18:15:39.112 prompt tokens: 0, completion tokens: 0
18:15:41.925 [Transcription:user] [Recommend a restaurant in Paris.]
Potential direction (not a fix, just a hypothesis)
LLMUserAggregator broadcasts interruption on _on_user_turn_started without regard for whether the current turn's LLM response is emitting a tool call. An interruption that cancels a just-fired tool call from the same turn is arguably wrong — the tool was requested by this turn, not a stale prior one.
Options worth considering:
- Suppress interruption-driven cancellation for function calls emitted within the same turn window as the interruption.
- Still cancel, but send a synthetic error result back to Gemini so it doesn't stall waiting.
- Ensure the outer
_run_function_call coroutine is properly awaited on the cancellation path so the warning at minimum goes away.
pipecat version
1.0.0 (from pypi)
Python version
3.14.4
Operating System
macOS (Apple Silicon)
Issue description
A
RuntimeWarningfires — and more importantly the Gemini Live session stalls for ~10 seconds — when a function call dispatched byGeminiLiveLLMServiceis cancelled by an interruption broadcast originating fromTranscriptionUserTurnStartStrategy.This is distinct from #3588:
RuntimeWarning: coroutine 'LLMService._run_function_call.<locals>.timeout_handler' was never awaitedwhen function call triggers pipeline end #3588 reports_run_function_call.<locals>.timeout_handlerbeing unawaited; this report is the outer_run_function_callcoroutine itself being unawaited.RuntimeWarning: coroutine 'LLMService._run_function_call.<locals>.timeout_handler' was never awaitedwhen function call triggers pipeline end #3588 is triggered by a function handler pushingEndTaskFrame/EndFrame. This one is triggered by the normal turn-interruption race: when input transcription arrives andLLMUserAggregatorbroadcasts an interruption frame within the same millisecond the model emits a tool call.#3588's fix (a
finally: cancel_task(timeout_task)block) targets the inner timeout handler; it does not address this outer-coroutine leak on interruption cancellation.The warning is a symptom. The substantive problem is that Gemini Live never receives the function-call result, and its session sits idle producing zero completion tokens for ~10 seconds until the next user utterance triggers a server-side VAD interruption and unsticks it. For an agent that performs many tool calls in a conversation, this is a meaningful UX regression, not cosmetic.
Reproduction steps
examples/realtime/realtime-gemini-live-function-calling.pywithGeminiLiveLLMService(not Vertex), Daily transport in direct mode (-t daily -d)._handle_msg_input_transcriptionlogs the user text_on_user_turn_startedfiresbroadcast_interruption_run_function_callstarts_cancel_function_callfires within ~1 msRuntimeWarning: coroutine 'LLMService._run_function_call' was never awaitedis emittedTTFB: 10.421s, prompt tokens: 0, completion tokens: 0— Gemini produces nothing because it's still waiting for the cancelled tool resultExpected behavior
The function call should either:
No
RuntimeWarningin either case.Actual behavior
RuntimeWarning: coroutine 'LLMService._run_function_call' was never awaitedTTFB: 10.421s)Logs (trimmed to the critical window)
Potential direction (not a fix, just a hypothesis)
LLMUserAggregatorbroadcasts interruption on_on_user_turn_startedwithout regard for whether the current turn's LLM response is emitting a tool call. An interruption that cancels a just-fired tool call from the same turn is arguably wrong — the tool was requested by this turn, not a stale prior one.Options worth considering:
_run_function_callcoroutine is properly awaited on the cancellation path so the warning at minimum goes away.