From e4f1d5145327a477170d3a6089921f33fc97fcb4 Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:39:32 +0800 Subject: [PATCH] feat(store,ui): handle Hub error messages and display error banner - Handle `action: "error"` messages in connection-store (e.g. UNAUTHORIZED) - Widen lastError type to `{code, message}` to support all error codes - Display dismissible error banner in Chat with role="alert" and aria-live - Add accessible close button with focus-visible ring Co-Authored-By: Claude Opus 4.5 --- packages/store/src/connection-store.ts | 12 +++++++++--- packages/ui/src/components/chat.tsx | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/store/src/connection-store.ts b/packages/store/src/connection-store.ts index b2951b38..fd5c09e0 100644 --- a/packages/store/src/connection-store.ts +++ b/packages/store/src/connection-store.ts @@ -20,7 +20,6 @@ import { GatewayClient, StreamAction, type ConnectionState, - type SendErrorResponse, type StreamPayload, type AgentEvent, type GetAgentMessagesResult, @@ -35,7 +34,7 @@ interface ConnectionStoreState { hubId: string | null agentId: string | null connectionState: ConnectionState - lastError: SendErrorResponse | null + lastError: { code: string; message: string } | null } interface ConnectionStoreActions { @@ -146,13 +145,20 @@ function createClient( return } + // Handle error messages from Hub (e.g. UNAUTHORIZED) + if (msg.action === "error") { + const payload = msg.payload as { code: string; message: string } + set({ lastError: { code: payload.code, message: payload.message } }) + return + } + // Handle direct (non-streaming) messages const payload = msg.payload as { agentId?: string; content?: string } if (payload?.agentId && payload?.content) { useMessagesStore.getState().addAssistantMessage(payload.content, payload.agentId) } }) - .onSendError((error) => set({ lastError: error })) + .onSendError((error) => set({ lastError: { code: error.code, message: error.error } })) } /** Fetch message history from Hub via RPC after connection is established */ diff --git a/packages/ui/src/components/chat.tsx b/packages/ui/src/components/chat.tsx index fa3d7773..60f7519a 100644 --- a/packages/ui/src/components/chat.tsx +++ b/packages/ui/src/components/chat.tsx @@ -16,6 +16,7 @@ export function Chat() { const agentId = useConnectionStore((s) => s.agentId) const gwState = useConnectionStore((s) => s.connectionState) const hubId = useConnectionStore((s) => s.hubId) + const lastError = useConnectionStore((s) => s.lastError) const messages = useMessagesStore((s) => s.messages) const streamingIds = useMessagesStore((s) => s.streamingIds) @@ -65,6 +66,23 @@ export function Chat() { )} + {/* Error banner */} + {lastError && ( +
+
+ {lastError.message} ({lastError.code}) + +
+
+ )} + {/* Footer */}