From 53922819ed3d47d19ab0710f1b089516c150c212 Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Fri, 8 May 2026 15:47:06 -0400 Subject: [PATCH] refactor: explicit kind=='final' check in async-tool routing (Gemini Live) Mirrors the same change applied to AWSNovaSonicLLMService and OpenAIRealtimeLLMService in #4441 / GrokRealtimeLLMService in #4447: replaces the implicit "final happens last" pattern in _process_completed_function_calls with an explicit `if async_payload.kind == "final":` block, plus a trailing defensive `continue` so async-tool messages with an unrecognized kind don't fall through to the regular tool-result handling block. --- .../services/google/gemini_live/llm.py | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/pipecat/services/google/gemini_live/llm.py b/src/pipecat/services/google/gemini_live/llm.py index 86fcc9b97..8330f9137 100644 --- a/src/pipecat/services/google/gemini_live/llm.py +++ b/src/pipecat/services/google/gemini_live/llm.py @@ -926,15 +926,22 @@ class GeminiLiveLLMService(LLMService[GeminiLLMAdapter]): error_msg="Gemini Live does not support streamed async tool results.", ) continue - # kind == "final": deliver via the formal tool-response channel - # — same path as a synchronous tool result, just delayed. - tool_name = self._tool_call_id_to_name.get( - async_payload.tool_call_id, "tool_call_result" - ) - response_dict = GeminiLLMAdapter.to_function_response_dict(async_payload.result) - if send_new_results: - await self._tool_result(async_payload.tool_call_id, tool_name, response_dict) - self._completed_tool_calls.add(async_payload.tool_call_id) + if async_payload.kind == "final": + # Deliver via the formal tool-response channel — same + # path as a synchronous tool result, just delayed. + tool_name = self._tool_call_id_to_name.get( + async_payload.tool_call_id, "tool_call_result" + ) + response_dict = GeminiLLMAdapter.to_function_response_dict(async_payload.result) + if send_new_results: + await self._tool_result( + async_payload.tool_call_id, tool_name, response_dict + ) + self._completed_tool_calls.add(async_payload.tool_call_id) + continue + # Defensive: any async-tool message must not fall through + # to the regular tool-result block below, even if it + # carries a kind we don't recognize. continue # Look for newly-completed "regular" (as opposed to async-tool) results