diff --git a/packages/react-headless/src/store/createChatStore.ts b/packages/react-headless/src/store/createChatStore.ts index 55c6d4c88..6811f0f6f 100644 --- a/packages/react-headless/src/store/createChatStore.ts +++ b/packages/react-headless/src/store/createChatStore.ts @@ -245,6 +245,8 @@ export const createChatStore = (config: StoreConfig) => { throw new Error(`Request failed: ${response.status} ${response.statusText}`); } + const messageCountBefore = get().messages.length; + await processStreamedMessage({ response, createMessage: (msg) => set((s) => ({ messages: [...s.messages, msg] })), @@ -255,9 +257,15 @@ export const createChatStore = (config: StoreConfig) => { deleteMessage: (id) => set((s) => ({ messages: s.messages.filter((m) => m.id !== id) })), adapter: streamProtocol, }); + + if (get().messages.length === messageCountBefore) { + throw new Error("Failed to get a response. Please check your connection and try again."); + } } catch (e) { if (!abortController.signal.aborted) { - set({ threadError: e instanceof Error ? e : new Error(String(e)) }); + const error = e instanceof Error ? e : new Error(String(e)); + console.error("[OpenUI] processMessage failed:", error); + set({ threadError: error }); } } finally { set({ _abortController: null, isRunning: false }); diff --git a/packages/react-headless/src/stream/processStreamedMessage.ts b/packages/react-headless/src/stream/processStreamedMessage.ts index fb8002f69..5c59da1d5 100644 --- a/packages/react-headless/src/stream/processStreamedMessage.ts +++ b/packages/react-headless/src/stream/processStreamedMessage.ts @@ -91,9 +91,10 @@ export const processStreamedMessage = async ({ } break; - case EventType.RUN_ERROR: - console.error("Stream error:", (event as any).error); - break; + case EventType.RUN_ERROR: { + const msg = (event as any).message || (event as any).error || "Stream error"; + throw new Error(typeof msg === "string" ? msg : JSON.stringify(msg)); + } } if (isFirst) { diff --git a/packages/react-ui/src/components/Shell/Thread.tsx b/packages/react-ui/src/components/Shell/Thread.tsx index 68af847da..86aaf21d8 100644 --- a/packages/react-ui/src/components/Shell/Thread.tsx +++ b/packages/react-ui/src/components/Shell/Thread.tsx @@ -4,6 +4,7 @@ import clsx from "clsx"; import React, { memo, useEffect, useRef } from "react"; import { useLayoutContext } from "../../context/LayoutContext"; import { ScrollVariant, useScrollToBottom } from "../../hooks/useScrollToBottom"; +import { Callout } from "../Callout"; import { MarkDownRenderer } from "../MarkDownRenderer"; import { MessageLoading as MessageLoadingComponent } from "../MessageLoading"; import type { AssistantMessageComponent, UserMessageComponent } from "../OpenUIChat/types"; @@ -320,6 +321,21 @@ export const MessageLoading = () => { ); }; +export const ThreadError = () => { + const threadError = useThread((s) => s.threadError); + if (!threadError) return null; + + return ( +