From ab3e6ae3c8f89ab1966eeb4b79da08a512ab0cad Mon Sep 17 00:00:00 2001 From: Richard Palethorpe Date: Tue, 1 Apr 2025 08:43:12 +0100 Subject: [PATCH] fix(ui): Fix SSE in chat --- webui/app.go | 5 ++-- webui/react-ui/src/hooks/useChat.js | 39 +++++++++++++++++------------ webui/react-ui/src/hooks/useSSE.js | 6 ++--- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/webui/app.go b/webui/app.go index 1509b87..a8a1f8a 100644 --- a/webui/app.go +++ b/webui/app.go @@ -6,6 +6,7 @@ import ( "fmt" "net/http" "os" + "path/filepath" "strings" "time" @@ -215,7 +216,7 @@ func (a *App) ImportAgent(pool *state.AgentPool) func(c *fiber.Ctx) error { os.MkdirAll("./uploads", os.ModePerm) // Safely save the file to prevent path traversal - destination := fmt.Sprintf("./uploads/%s", file.Filename) + destination := filepath.Join("./uploads", file.Filename) if err := c.SaveFile(file, destination); err != nil { // Handle error return err @@ -385,7 +386,7 @@ func (a *App) ChatAPI(pool *state.AgentPool) func(c *fiber.Ctx) error { xlog.Error("Error marshaling error message", "error", err) } else { manager.Send( - sse.NewMessage(string(errorData)).WithEvent("error")) + sse.NewMessage(string(errorData)).WithEvent("json_error")) } } else { // Send agent response diff --git a/webui/react-ui/src/hooks/useChat.js b/webui/react-ui/src/hooks/useChat.js index 759097b..03aa113 100644 --- a/webui/react-ui/src/hooks/useChat.js +++ b/webui/react-ui/src/hooks/useChat.js @@ -109,22 +109,22 @@ export function useChat(agentName) { setSending(true); setError(null); - // Add user message to the local state immediately for better UX - const messageId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - - const userMessage = { - id: messageId, - sender: 'user', - content, - timestamp: new Date().toISOString(), - }; - - setMessages(prev => [...prev, userMessage]); - - // Track this message content to avoid duplication from SSE - localMessageContents.current.add(content); - try { + // Add user message to the local state immediately for better UX + const messageId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + + const userMessage = { + id: messageId, + sender: 'user', + content, + timestamp: new Date().toISOString(), + }; + + setMessages(prev => [...prev, userMessage]); + + // Track this message content to avoid duplication from SSE + localMessageContents.current.add(content); + // Use the JSON-based API endpoint await chatApi.sendMessage(agentName, content); return true; @@ -133,8 +133,15 @@ export function useChat(agentName) { console.error('Error sending message:', err); setSending(false); return false; + } finally { + // Ensure sending state is reset after a timeout in case SSE doesn't update + setTimeout(() => { + if (sending) { + setSending(false); + } + }, 5000); // 5 second timeout } - }, [agentName]); + }, [agentName, sending]); // Clear chat history const clearChat = useCallback(() => { diff --git a/webui/react-ui/src/hooks/useSSE.js b/webui/react-ui/src/hooks/useSSE.js index 262b885..76409cc 100644 --- a/webui/react-ui/src/hooks/useSSE.js +++ b/webui/react-ui/src/hooks/useSSE.js @@ -63,8 +63,8 @@ export function useSSE(agentName) { } }); - // Handle 'status' event - eventSource.addEventListener('status', (event) => { + // Handle 'json_status' event + eventSource.addEventListener('json_status', (event) => { try { const data = JSON.parse(event.data); const timestamp = data.timestamp || new Date().toISOString(); @@ -81,7 +81,7 @@ export function useSSE(agentName) { }); // Handle 'error' event - eventSource.addEventListener('error', (event) => { + eventSource.addEventListener('json_error', (event) => { try { const data = JSON.parse(event.data); const timestamp = data.timestamp || new Date().toISOString();