diff --git a/frontend/src/context/ws-client-provider.tsx b/frontend/src/context/ws-client-provider.tsx index 38f390476f..22e8b64be8 100644 --- a/frontend/src/context/ws-client-provider.tsx +++ b/frontend/src/context/ws-client-provider.tsx @@ -142,6 +142,7 @@ export function WsClientProvider({ const { addEvent, clearEvents } = useEventStore(); const queryClient = useQueryClient(); const sioRef = React.useRef(null); + const pendingEventsRef = React.useRef[]>([]); const [webSocketStatus, setWebSocketStatus] = React.useState("DISCONNECTED"); const lastEventRef = React.useRef | null>(null); @@ -151,17 +152,37 @@ export function WsClientProvider({ const { data: conversation, refetch: refetchConversation } = useActiveConversation(); - function send(event: Record) { - if (!sioRef.current) { - EventLogger.error("WebSocket is not connected."); + function flushPendingEvents(socket: Socket | null = sioRef.current) { + if (!socket || pendingEventsRef.current.length === 0) { return; } - sioRef.current.emit("oh_user_action", event); + + pendingEventsRef.current.forEach((queuedEvent) => { + socket.emit("oh_user_action", queuedEvent); + }); + pendingEventsRef.current = []; + } + + function send(event: Record) { + const socket = sioRef.current; + + if (!socket) { + EventLogger.error("WebSocket is not connected, queuing message..."); + pendingEventsRef.current.push(event); + return; + } + + if (pendingEventsRef.current.length > 0) { + flushPendingEvents(socket); + } + + socket.emit("oh_user_action", event); } function handleConnect() { setWebSocketStatus("CONNECTED"); removeErrorMessage(); + flushPendingEvents(); } function handleMessage(event: Record) { @@ -292,6 +313,7 @@ export function WsClientProvider({ clearEvents(); setWebSocketStatus("CONNECTING"); + pendingEventsRef.current = []; }, [conversationId]); React.useEffect(() => { @@ -301,6 +323,12 @@ export function WsClientProvider({ // Clear error messages when conversation is intentionally stopped if (conversation && conversation.status === "STOPPED") { + const existingSocket = sioRef.current; + if (existingSocket) { + existingSocket.disconnect(); + } + sioRef.current = null; + pendingEventsRef.current = []; removeErrorMessage(); setWebSocketStatus("DISCONNECTED"); return () => undefined; // conversation intentionally stopped @@ -320,6 +348,10 @@ export function WsClientProvider({ !conversation.runtime_status || conversation.runtime_status === "STATUS$STOPPED" ) { + if (sioRef.current) { + sioRef.current.disconnect(); + } + sioRef.current = null; return () => undefined; // conversation not ready for WebSocket connection } @@ -368,6 +400,7 @@ export function WsClientProvider({ sio.on("disconnect", handleDisconnect); sioRef.current = sio; + flushPendingEvents(sio); return () => { sio.off("connect", handleConnect);