From be49a54856a0f6180715efaec6b45eacf5c07bfa Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Tue, 13 Jan 2026 17:32:20 -0500 Subject: [PATCH] Fast-exit in the fix for parallel function calling with Gemini 3, if we can determine up-front that there's no work to do --- .../adapters/services/gemini_adapter.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pipecat/adapters/services/gemini_adapter.py b/src/pipecat/adapters/services/gemini_adapter.py index cb6f6d8de..2de3742c8 100644 --- a/src/pipecat/adapters/services/gemini_adapter.py +++ b/src/pipecat/adapters/services/gemini_adapter.py @@ -256,7 +256,7 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): self._apply_thought_signatures_to_messages(thought_signature_dicts, messages) # When thinking is enabled, merge parallel tool calls into single messages - messages = self._merge_parallel_tool_calls_for_thinking(messages) + messages = self._merge_parallel_tool_calls_for_thinking(thought_signature_dicts, messages) # Check if we only have function-related messages (no regular text) has_regular_messages = any( @@ -436,7 +436,9 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): tool_call_id_to_name_mapping=tool_call_id_to_name_mapping, ) - def _merge_parallel_tool_calls_for_thinking(self, messages: List[Content]) -> List[Content]: + def _merge_parallel_tool_calls_for_thinking( + self, thought_signature_dicts: List[dict], messages: List[Content] + ) -> List[Content]: """Merge parallel tool calls into single Content objects when thinking is enabled. Gemini expects parallel tool calls (multiple function calls made @@ -460,6 +462,8 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): messages appear in between. Args: + thought_signature_dicts: A list of thought signature dicts, used + to determine if the work of merging is necessary. messages: List of Content messages to process. Returns: @@ -469,6 +473,16 @@ class GeminiLLMAdapter(BaseLLMAdapter[GeminiLLMInvocationParams]): if not messages: return messages + # Fast-exit if no function-call-related thought signatures + # This is a shortcut for determining both: + # - whether thinking is enabled, and + # - whether there are function calls in the messages + has_function_call_signatures = any( + ts.get("bookmark", {}).get("function_call") for ts in thought_signature_dicts + ) + if not has_function_call_signatures: + return messages + def is_tool_call_message(msg: Content) -> bool: """Check if message contains only function_call parts.""" return (