From ad0f0a1294d0a98a05a17477109bf7e96d4360dc Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Fri, 8 May 2026 15:43:37 -0400 Subject: [PATCH] refactor: explicit kind=='final' check in async-tool routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the implicit "final happens last" pattern in _process_completed_function_calls with an explicit `if async_payload.kind == "final":` block in both AWSNovaSonicLLMService and OpenAIRealtimeLLMService. Adds a trailing defensive `continue` so async-tool messages with an unrecognized kind don't fall through to the regular tool-result handling block — clearer at the call site, and safer against future additions to AsyncToolMessageKind. --- src/pipecat/services/aws/nova_sonic/llm.py | 17 ++++++++++++----- src/pipecat/services/openai/realtime/llm.py | 19 +++++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/pipecat/services/aws/nova_sonic/llm.py b/src/pipecat/services/aws/nova_sonic/llm.py index f77d6aee5..4aeb5c848 100644 --- a/src/pipecat/services/aws/nova_sonic/llm.py +++ b/src/pipecat/services/aws/nova_sonic/llm.py @@ -645,11 +645,18 @@ class AWSNovaSonicLLMService(LLMService[AWSNovaSonicLLMAdapter]): error_msg="Nova Sonic does not support streamed async tool results.", ) continue - # kind == "final": deliver via the formal toolResult channel - # — same path as a synchronous tool result, just delayed. - if send_new_results: - await self._send_tool_result(async_payload.tool_call_id, async_payload.result) - self._completed_tool_calls.add(async_payload.tool_call_id) + if async_payload.kind == "final": + # Deliver via the formal toolResult channel — same path + # as a synchronous tool result, just delayed. + if send_new_results: + await self._send_tool_result( + async_payload.tool_call_id, async_payload.result + ) + 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 diff --git a/src/pipecat/services/openai/realtime/llm.py b/src/pipecat/services/openai/realtime/llm.py index d105a8a39..28b987437 100644 --- a/src/pipecat/services/openai/realtime/llm.py +++ b/src/pipecat/services/openai/realtime/llm.py @@ -1068,12 +1068,19 @@ class OpenAIRealtimeLLMService(LLMService[OpenAIRealtimeLLMAdapter]): error_msg="OpenAI Realtime does not support streamed async tool results.", ) continue - # kind == "final": deliver via the formal tool-result channel - # — same path as a synchronous tool result, just delayed. - if send_new_results: - sent_new_result = True - await self._send_tool_result(async_payload.tool_call_id, async_payload.result) - self._completed_tool_calls.add(async_payload.tool_call_id) + if async_payload.kind == "final": + # Deliver via the formal tool-result channel — same path + # as a synchronous tool result, just delayed. + if send_new_results: + sent_new_result = True + await self._send_tool_result( + async_payload.tool_call_id, async_payload.result + ) + 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