diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5c30b0e..024bd10f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 removed in a future version. Use the `/start` endpoint in its place. In the meantime, both endpoints work and deliver equivalent functionality. +- Added `processor` field to `ErrorFrame` to indicate `FrameProcessor` that generated the error. + ## [0.0.77] - 2025-07-31 ### Added diff --git a/src/pipecat/frames/frames.py b/src/pipecat/frames/frames.py index 94e799aa6..94a60787d 100644 --- a/src/pipecat/frames/frames.py +++ b/src/pipecat/frames/frames.py @@ -664,10 +664,12 @@ class ErrorFrame(SystemFrame): Parameters: error: Description of the error that occurred. fatal: Whether the error is fatal and requires bot shutdown. + source: The frame processor that generated the error. """ error: str fatal: bool = False + processor: Optional["FrameProcessor"] = None def __str__(self): return f"{self.name}(error: {self.error}, fatal: {self.fatal})" diff --git a/src/pipecat/processors/frame_processor.py b/src/pipecat/processors/frame_processor.py index a049fabdb..e6611a161 100644 --- a/src/pipecat/processors/frame_processor.py +++ b/src/pipecat/processors/frame_processor.py @@ -494,6 +494,8 @@ class FrameProcessor(BaseObject): Args: error: The error frame to push. """ + if not error.processor: + error.processor = self await self.push_frame(error, FrameDirection.UPSTREAM) async def push_frame(self, frame: Frame, direction: FrameDirection = FrameDirection.DOWNSTREAM): diff --git a/src/pipecat/services/anthropic/llm.py b/src/pipecat/services/anthropic/llm.py index d7c703ebb..15c4cebee 100644 --- a/src/pipecat/services/anthropic/llm.py +++ b/src/pipecat/services/anthropic/llm.py @@ -26,6 +26,7 @@ from pydantic import BaseModel, Field from pipecat.adapters.services.anthropic_adapter import AnthropicLLMAdapter from pipecat.frames.frames import ( + ErrorFrame, Frame, FunctionCallCancelFrame, FunctionCallInProgressFrame, @@ -346,6 +347,7 @@ class AnthropicLLMService(LLMService): await self._call_event_handler("on_completion_timeout") except Exception as e: logger.exception(f"{self} exception: {e}") + await self.push_error(ErrorFrame(f"{e}")) finally: await self.stop_processing_metrics() await self.push_frame(LLMFullResponseEndFrame()) diff --git a/src/pipecat/services/deepgram/stt.py b/src/pipecat/services/deepgram/stt.py index 56658cad5..8381135d9 100644 --- a/src/pipecat/services/deepgram/stt.py +++ b/src/pipecat/services/deepgram/stt.py @@ -13,6 +13,7 @@ from loguru import logger from pipecat.frames.frames import ( CancelFrame, EndFrame, + ErrorFrame, Frame, InterimTranscriptionFrame, StartFrame, @@ -246,6 +247,7 @@ class DeepgramSTTService(STTService): async def _on_error(self, *args, **kwargs): error: ErrorResponse = kwargs["error"] logger.warning(f"{self} connection error, will retry: {error}") + await self.push_error(ErrorFrame(f"{error}")) await self.stop_all_metrics() # NOTE(aleix): we don't disconnect (i.e. call finish on the connection) # because this triggers more errors internally in the Deepgram SDK. So,