From 53ce57b7fac4d0b3246a305d106199787f7f1bdf Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Mon, 27 Apr 2026 16:41:38 -0400 Subject: [PATCH] fix: tighten _process_completed_function_calls in AWS Nova Sonic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three small changes that resolve pyright errors and sharpen the logic: - Guard `self._context` with the codebase's "should never happen" early-return pattern, so we don't blindly call `.get_messages()` on None. - Skip `LLMSpecificMessage` items in the iteration. They're opaque provider-specific payloads with no `.get()`, and the surrounding logic only applies to standard tool-result messages. - Match `role == "tool"` explicitly. The previous truthy-only check was working by accident — the `tool_call_id` filter further down was effectively narrowing to tool messages, but the intent is clearer when stated upfront. --- src/pipecat/services/aws/nova_sonic/llm.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pipecat/services/aws/nova_sonic/llm.py b/src/pipecat/services/aws/nova_sonic/llm.py index d3396cef2..ddf430f00 100644 --- a/src/pipecat/services/aws/nova_sonic/llm.py +++ b/src/pipecat/services/aws/nova_sonic/llm.py @@ -49,7 +49,7 @@ from pipecat.frames.frames import ( UserStartedSpeakingFrame, UserStoppedSpeakingFrame, ) -from pipecat.processors.aggregators.llm_context import LLMContext +from pipecat.processors.aggregators.llm_context import LLMContext, LLMSpecificMessage from pipecat.processors.frame_processor import FrameDirection from pipecat.services.aws.nova_sonic.session_continuation import ( SessionContinuationHelper, @@ -612,9 +612,18 @@ class AWSNovaSonicLLMService(LLMService): await self._disconnect() async def _process_completed_function_calls(self, send_new_results: bool): + if not self._context: # should never happen + return # Check for set of completed function calls in the context for message in self._context.get_messages(): - if message.get("role") and message.get("content") not in ["IN_PROGRESS", "CANCELLED"]: + # LLMSpecificMessages are opaque provider-specific payloads, not + # standard tool-result messages — skip them. + if isinstance(message, LLMSpecificMessage): + continue + if message.get("role") == "tool" and message.get("content") not in [ + "IN_PROGRESS", + "CANCELLED", + ]: tool_call_id = message.get("tool_call_id") if tool_call_id and tool_call_id not in self._completed_tool_calls: # Found a newly-completed function call - send the result to the service