From 21f5cfe21ad943007ad65730e316ada8d9b587d7 Mon Sep 17 00:00:00 2001 From: Mark Backman Date: Tue, 21 Apr 2026 16:47:12 -0400 Subject: [PATCH] Fix type errors in utils and add to pyright checked set --- pyrightconfig.json | 4 ++-- .../context/llm_context_summarization.py | 22 +++++++++++++------ src/pipecat/utils/frame_queue.py | 2 +- src/pipecat/utils/string.py | 2 +- .../utils/text/base_text_aggregator.py | 2 +- .../utils/text/pattern_pair_aggregator.py | 2 +- .../utils/tracing/service_attributes.py | 4 ++-- 7 files changed, 23 insertions(+), 15 deletions(-) diff --git a/pyrightconfig.json b/pyrightconfig.json index 822ccbf22..31bac33c8 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -13,7 +13,8 @@ "src/pipecat/runner", "src/pipecat/tests", "src/pipecat/transcriptions", - "src/pipecat/turns" + "src/pipecat/turns", + "src/pipecat/utils" ], "exclude": ["**/*_pb2.py", "**/__pycache__"], "ignore": [ @@ -23,7 +24,6 @@ "src/pipecat/serializers", "src/pipecat/services", "src/pipecat/transports", - "src/pipecat/utils", "tests" ], "reportMissingImports": false diff --git a/src/pipecat/utils/context/llm_context_summarization.py b/src/pipecat/utils/context/llm_context_summarization.py index 85a7e6e19..59de6f4fa 100644 --- a/src/pipecat/utils/context/llm_context_summarization.py +++ b/src/pipecat/utils/context/llm_context_summarization.py @@ -20,7 +20,11 @@ if TYPE_CHECKING: from loguru import logger -from pipecat.processors.aggregators.llm_context import LLMContext, LLMSpecificMessage +from pipecat.processors.aggregators.llm_context import ( + LLMContext, + LLMContextMessage, + LLMSpecificMessage, +) # Fallback timeout (seconds) used when summarization_timeout is None. DEFAULT_SUMMARIZATION_TIMEOUT = 120.0 @@ -269,7 +273,7 @@ class LLMMessagesToSummarize: last_summarized_index: Index of the last message being summarized """ - messages: list[dict] + messages: list[LLMContextMessage] last_summarized_index: int @@ -415,7 +419,7 @@ class LLMContextSummarizationUtil: @staticmethod def _get_earliest_function_call_not_resolved_in_range( - messages: list[dict], start_idx: int, summary_end: int + messages: list[LLMContextMessage], start_idx: int, summary_end: int ) -> int: """Find the earliest message index with incomplete function calls. @@ -470,9 +474,10 @@ class LLMContextSummarizationUtil: if role == "tool": tool_call_id = msg.get("tool_call_id") if tool_call_id and tool_call_id in pending_tool_calls: - if not LLMContextSummarizationUtil._is_tool_message_pending( - msg.get("content", "") - ): + content = msg.get("content", "") + if not isinstance(content, str): + content = "" + if not LLMContextSummarizationUtil._is_tool_message_pending(content): pending_tool_calls.pop(tool_call_id) # Check for async tool completion — a developer message with @@ -480,7 +485,10 @@ class LLMContextSummarizationUtil: # async result has arrived and the call is now resolved. if role == "developer": try: - parsed = json.loads(msg.get("content", "")) + content = msg.get("content", "") + if not isinstance(content, str): + continue + parsed = json.loads(content) if ( isinstance(parsed, dict) and parsed.get("type") == "async_tool" diff --git a/src/pipecat/utils/frame_queue.py b/src/pipecat/utils/frame_queue.py index 1b787362d..14347681a 100644 --- a/src/pipecat/utils/frame_queue.py +++ b/src/pipecat/utils/frame_queue.py @@ -58,7 +58,7 @@ class FrameQueue(asyncio.Queue): Returns: True if at least one enqueued frame is an instance of ``frame_type``. """ - for item in self._queue: + for item in self._queue: # pyright: ignore[reportAttributeAccessIssue] if isinstance(self._frame_getter(item), frame_type): return True return False diff --git a/src/pipecat/utils/string.py b/src/pipecat/utils/string.py index 55b1c2d53..c464e189f 100644 --- a/src/pipecat/utils/string.py +++ b/src/pipecat/utils/string.py @@ -234,7 +234,7 @@ class TextPartForConcatenation: includes_inter_part_spaces: bool def __str__(self): - return f"{self.name}(text: [{self.text}], includes_inter_part_spaces: {self.includes_inter_part_spaces})" + return f"{type(self).__name__}(text: [{self.text}], includes_inter_part_spaces: {self.includes_inter_part_spaces})" def concatenate_aggregated_text(text_parts: list[TextPartForConcatenation]) -> str: diff --git a/src/pipecat/utils/text/base_text_aggregator.py b/src/pipecat/utils/text/base_text_aggregator.py index 99ca145b6..b1b933c81 100644 --- a/src/pipecat/utils/text/base_text_aggregator.py +++ b/src/pipecat/utils/text/base_text_aggregator.py @@ -125,7 +125,7 @@ class BaseTextAggregator(ABC): """ pass # Make this a generator to satisfy type checker - yield # pragma: no cover + yield # pyright: ignore[reportReturnType] # pragma: no cover @abstractmethod async def flush(self) -> Aggregation | None: diff --git a/src/pipecat/utils/text/pattern_pair_aggregator.py b/src/pipecat/utils/text/pattern_pair_aggregator.py index 975413c78..67e044152 100644 --- a/src/pipecat/utils/text/pattern_pair_aggregator.py +++ b/src/pipecat/utils/text/pattern_pair_aggregator.py @@ -273,7 +273,7 @@ class PatternPairAggregator(SimpleTextAggregator): # Which is why we base the return on the first found. if start_count > end_count: start_index = text.find(start) - return [start_index, pattern_info] + return (start_index, pattern_info) return None diff --git a/src/pipecat/utils/tracing/service_attributes.py b/src/pipecat/utils/tracing/service_attributes.py index d9b86a9a4..a8b33e225 100644 --- a/src/pipecat/utils/tracing/service_attributes.py +++ b/src/pipecat/utils/tracing/service_attributes.py @@ -440,7 +440,7 @@ def add_openai_realtime_span_attributes( if isinstance(tool, dict) and "name" in tool: tool_names.append(tool["name"]) elif hasattr(tool, "name"): - tool_names.append(tool.name) + tool_names.append(getattr(tool, "name")) elif isinstance(tool, dict) and "function" in tool and "name" in tool["function"]: tool_names.append(tool["function"]["name"]) @@ -455,7 +455,7 @@ def add_openai_realtime_span_attributes( if function_calls: call = function_calls[0] if hasattr(call, "name"): - span.set_attribute("function_calls.first_name", call.name) + span.set_attribute("function_calls.first_name", getattr(call, "name")) elif isinstance(call, dict) and "name" in call: span.set_attribute("function_calls.first_name", call["name"])