From 8058ae5bd2a7743285adac428bda4a90cf58cd87 Mon Sep 17 00:00:00 2001 From: Adrian Lyjak Date: Tue, 23 Sep 2025 14:26:57 -0400 Subject: [PATCH] handle errors better --- src/{{ project_name_snake }}/qa_workflows.py | 27 ++++++++++---------- test-proj/src/test_proj/qa_workflows.py | 27 ++++++++++---------- test-proj/ui/src/libs/useChatbot.ts | 19 ++++++++++++++ ui/src/libs/useChatbot.ts | 19 ++++++++++++++ 4 files changed, 66 insertions(+), 26 deletions(-) diff --git a/src/{{ project_name_snake }}/qa_workflows.py b/src/{{ project_name_snake }}/qa_workflows.py index ed05b8d..5d9281f 100644 --- a/src/{{ project_name_snake }}/qa_workflows.py +++ b/src/{{ project_name_snake }}/qa_workflows.py @@ -172,6 +172,12 @@ class QueryConversationHistoryEvent(HumanResponseEvent): pass +class ErrorEvent(Event): + """Event emitted when an error occurs""" + + error: str + + class ChatWorkflowState(BaseModel): index_name: str | None = None conversation_history: list[ConversationMessage] = Field(default_factory=list) @@ -219,7 +225,7 @@ class ChatWorkflow(Workflow): @step async def initialize_chat( self, ev: ChatEvent, ctx: Context[ChatWorkflowState] - ) -> InputRequiredEvent | StopEvent: + ) -> InputRequiredEvent | StopEvent | None: """Initialize the chat session and request first input""" try: logger.info(f"Initializing chat {ev.index_name}") @@ -236,17 +242,14 @@ class ChatWorkflow(Workflow): if ev.conversation_history: async with ctx.store.edit_state() as state: state.conversation_history.extend(ev.conversation_history) - # Request first user input - return InputRequiredEvent() except Exception as e: logger.error(f"Error initializing chat: {str(e)}", exc_info=True) - return StopEvent( - result={ - "success": False, - "error": f"Failed to initialize chat: {str(e)}", - } + ctx.write_event_to_stream( + ErrorEvent(error=f"Failed to initialize chat: {str(e)}") ) + return InputRequiredEvent() + @step async def get_conversation_history( @@ -260,7 +263,7 @@ class ChatWorkflow(Workflow): @step async def process_user_response( self, ev: HumanResponseEvent, ctx: Context[ChatWorkflowState] - ) -> InputRequiredEvent | HumanResponseEvent | StopEvent | None: + ) -> InputRequiredEvent | HumanResponseEvent | None: """Process user input and generate response""" try: logger.info(f"Processing user response {ev.response}") @@ -326,13 +329,11 @@ class ChatWorkflow(Workflow): assistant_response, ] ) - return InputRequiredEvent() except Exception as e: logger.error(f"Error processing query: {str(e)}", exc_info=True) - return StopEvent( - result={"success": False, "error": f"Error processing query: {str(e)}"} - ) + ctx.write_event_to_stream(ErrorEvent(error=str(e))) + return InputRequiredEvent() upload = DocumentUploadWorkflow(timeout=None) diff --git a/test-proj/src/test_proj/qa_workflows.py b/test-proj/src/test_proj/qa_workflows.py index ed05b8d..5d9281f 100644 --- a/test-proj/src/test_proj/qa_workflows.py +++ b/test-proj/src/test_proj/qa_workflows.py @@ -172,6 +172,12 @@ class QueryConversationHistoryEvent(HumanResponseEvent): pass +class ErrorEvent(Event): + """Event emitted when an error occurs""" + + error: str + + class ChatWorkflowState(BaseModel): index_name: str | None = None conversation_history: list[ConversationMessage] = Field(default_factory=list) @@ -219,7 +225,7 @@ class ChatWorkflow(Workflow): @step async def initialize_chat( self, ev: ChatEvent, ctx: Context[ChatWorkflowState] - ) -> InputRequiredEvent | StopEvent: + ) -> InputRequiredEvent | StopEvent | None: """Initialize the chat session and request first input""" try: logger.info(f"Initializing chat {ev.index_name}") @@ -236,17 +242,14 @@ class ChatWorkflow(Workflow): if ev.conversation_history: async with ctx.store.edit_state() as state: state.conversation_history.extend(ev.conversation_history) - # Request first user input - return InputRequiredEvent() except Exception as e: logger.error(f"Error initializing chat: {str(e)}", exc_info=True) - return StopEvent( - result={ - "success": False, - "error": f"Failed to initialize chat: {str(e)}", - } + ctx.write_event_to_stream( + ErrorEvent(error=f"Failed to initialize chat: {str(e)}") ) + return InputRequiredEvent() + @step async def get_conversation_history( @@ -260,7 +263,7 @@ class ChatWorkflow(Workflow): @step async def process_user_response( self, ev: HumanResponseEvent, ctx: Context[ChatWorkflowState] - ) -> InputRequiredEvent | HumanResponseEvent | StopEvent | None: + ) -> InputRequiredEvent | HumanResponseEvent | None: """Process user input and generate response""" try: logger.info(f"Processing user response {ev.response}") @@ -326,13 +329,11 @@ class ChatWorkflow(Workflow): assistant_response, ] ) - return InputRequiredEvent() except Exception as e: logger.error(f"Error processing query: {str(e)}", exc_info=True) - return StopEvent( - result={"success": False, "error": f"Error processing query: {str(e)}"} - ) + ctx.write_event_to_stream(ErrorEvent(error=str(e))) + return InputRequiredEvent() upload = DocumentUploadWorkflow(timeout=None) diff --git a/test-proj/ui/src/libs/useChatbot.ts b/test-proj/ui/src/libs/useChatbot.ts index 2fa88dc..7ca59d9 100644 --- a/test-proj/ui/src/libs/useChatbot.ts +++ b/test-proj/ui/src/libs/useChatbot.ts @@ -166,6 +166,9 @@ export function useChatbot({ interface AppendChatMessageData { message: ChatMessage; } +interface ErrorEventData { + error: string; +} interface ChatMessage { role: "user" | "assistant"; text: string; @@ -239,6 +242,22 @@ function toMessages(events: WorkflowEvent[]): Message[] { timestamp: new Date(content.message.timestamp), isPartial: false, }); + } else if (type.endsWith(".ErrorEvent")) { + if ( + lastMessage && + lastMessage.isPartial && + lastMessage.role === "assistant" + ) { + messages.pop(); + } + const content = ev.data as unknown as ErrorEventData; + messages.push({ + role: "assistant", + content: content.error, + timestamp: new Date(), + isPartial: false, + error: true, + }); } } return messages; diff --git a/ui/src/libs/useChatbot.ts b/ui/src/libs/useChatbot.ts index 2fa88dc..7ca59d9 100644 --- a/ui/src/libs/useChatbot.ts +++ b/ui/src/libs/useChatbot.ts @@ -166,6 +166,9 @@ export function useChatbot({ interface AppendChatMessageData { message: ChatMessage; } +interface ErrorEventData { + error: string; +} interface ChatMessage { role: "user" | "assistant"; text: string; @@ -239,6 +242,22 @@ function toMessages(events: WorkflowEvent[]): Message[] { timestamp: new Date(content.message.timestamp), isPartial: false, }); + } else if (type.endsWith(".ErrorEvent")) { + if ( + lastMessage && + lastMessage.isPartial && + lastMessage.role === "assistant" + ) { + messages.pop(); + } + const content = ev.data as unknown as ErrorEventData; + messages.push({ + role: "assistant", + content: content.error, + timestamp: new Date(), + isPartial: false, + error: true, + }); } } return messages;