From cdad3bbc3f5ce7831f217a8eb882e2989f04a153 Mon Sep 17 00:00:00 2001 From: Efros Ionelu Date: Thu, 28 Aug 2025 10:10:58 +0300 Subject: [PATCH 1/3] workflow agents --- src/components/AgentIndicator/index.jsx | 19 +++ .../ChatWindow/ChatContainer/index.jsx | 101 ++++++++++++- src/components/ChatWindow/index.jsx | 2 + src/utils/agent.js | 135 ++++++++++++++++++ src/utils/chat/index.js | 44 +++++- src/utils/request.js | 8 ++ 6 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 src/components/AgentIndicator/index.jsx create mode 100644 src/utils/agent.js create mode 100644 src/utils/request.js diff --git a/src/components/AgentIndicator/index.jsx b/src/components/AgentIndicator/index.jsx new file mode 100644 index 0000000..68b6003 --- /dev/null +++ b/src/components/AgentIndicator/index.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import { useIsAgentSessionActive } from "@/utils/agent"; + +export default function AgentIndicator() { + const isAgentActive = useIsAgentSessionActive(); + + if (!isAgentActive) return null; + + return ( +
+
+
+ + Agent session active + +
+
+ ); +} \ No newline at end of file diff --git a/src/components/ChatWindow/ChatContainer/index.jsx b/src/components/ChatWindow/ChatContainer/index.jsx index b74ac15..fc89574 100644 --- a/src/components/ChatWindow/ChatContainer/index.jsx +++ b/src/components/ChatWindow/ChatContainer/index.jsx @@ -1,8 +1,14 @@ import React, { useState, useEffect } from "react"; import ChatHistory from "./ChatHistory"; import PromptInput from "./PromptInput"; -import handleChat from "@/utils/chat"; +import handleChat, { ABORT_STREAM_EVENT } from "@/utils/chat"; import ChatService from "@/models/chatService"; +import handleSocketResponse, { + websocketURI, + AGENT_SESSION_END, + AGENT_SESSION_START, +} from "@/utils/agent"; +import { v4 } from "uuid"; export const SEND_TEXT_EVENT = "anythingllm-embed-send-prompt"; export default function ChatContainer({ @@ -13,6 +19,8 @@ export default function ChatContainer({ const [message, setMessage] = useState(""); const [loadingResponse, setLoadingResponse] = useState(false); const [chatHistory, setChatHistory] = useState(knownHistory); + const [socketId, setSocketId] = useState(null); + const [websocket, setWebsocket] = useState(null); // Resync history if the ref to known history changes // eg: cleared. @@ -93,6 +101,18 @@ export default function ChatContainer({ const remHistory = chatHistory.length > 0 ? chatHistory.slice(0, -1) : []; var _chatHistory = [...remHistory]; + // Override hook for new messages to now go to agents until the connection closes + if (!!websocket) { + if (!promptMessage || !promptMessage?.userMessage) return false; + websocket.send( + JSON.stringify({ + type: "awaitingFeedback", + feedback: promptMessage?.userMessage, + }) + ); + return; + } + if (!promptMessage || !promptMessage?.userMessage) { setLoadingResponse(false); return false; @@ -108,14 +128,15 @@ export default function ChatContainer({ setLoadingResponse, setChatHistory, remHistory, - _chatHistory + _chatHistory, + setSocketId ) ); return; } loadingResponse === true && fetchReply(); - }, [loadingResponse, chatHistory]); + }, [loadingResponse, chatHistory, websocket]); const handleAutofillEvent = (event) => { if (!event.detail.command) return; @@ -129,6 +150,80 @@ export default function ChatContainer({ }; }, []); + // Websocket connection management for agent sessions + useEffect(() => { + function handleWSS() { + try { + if (!socketId || !!websocket) return; + const socket = new WebSocket( + `${websocketURI(settings)}/api/agent-invocation/${socketId}` + ); + + window.addEventListener(ABORT_STREAM_EVENT, () => { + window.dispatchEvent(new CustomEvent(AGENT_SESSION_END)); + if (websocket) websocket.close(); + }); + + socket.addEventListener("message", (event) => { + setLoadingResponse(true); + try { + handleSocketResponse(event, setChatHistory); + } catch (e) { + console.error("Failed to parse agent data:", e); + window.dispatchEvent(new CustomEvent(AGENT_SESSION_END)); + socket.close(); + } + setLoadingResponse(false); + }); + + socket.addEventListener("close", (_event) => { + window.dispatchEvent(new CustomEvent(AGENT_SESSION_END)); + setChatHistory((prev) => [ + ...prev.filter((msg) => !!msg.content), + { + uuid: v4(), + type: "statusResponse", + content: "Agent session complete.", + role: "assistant", + sources: [], + closed: true, + error: null, + animate: false, + pending: false, + sentAt: Math.floor(Date.now() / 1000), + }, + ]); + setLoadingResponse(false); + setWebsocket(null); + setSocketId(null); + }); + + setWebsocket(socket); + window.dispatchEvent(new CustomEvent(AGENT_SESSION_START)); + } catch (e) { + setChatHistory((prev) => [ + ...prev.filter((msg) => !!msg.content), + { + uuid: v4(), + type: "abort", + content: e.message, + role: "assistant", + sources: [], + closed: true, + error: e.message, + animate: false, + pending: false, + sentAt: Math.floor(Date.now() / 1000), + }, + ]); + setLoadingResponse(false); + setWebsocket(null); + setSocketId(null); + } + } + handleWSS(); + }, [socketId]); + return (
diff --git a/src/components/ChatWindow/index.jsx b/src/components/ChatWindow/index.jsx index 3628d1b..edff7ef 100644 --- a/src/components/ChatWindow/index.jsx +++ b/src/components/ChatWindow/index.jsx @@ -5,6 +5,7 @@ import ChatContainer from "./ChatContainer"; import Sponsor from "../Sponsor"; import { ChatHistoryLoading } from "./ChatContainer/ChatHistory"; import ResetChat from "../ResetChat"; +import AgentIndicator from "../AgentIndicator"; export default function ChatWindow({ closeChat, settings, sessionId }) { const { chatHistory, setChatHistory, loading } = useChatHistory( @@ -44,6 +45,7 @@ export default function ChatWindow({ closeChat, settings, sessionId }) { setChatHistory={setChatHistory} /> )} +
{ + return [ + ...prev.filter((msg) => !!msg.content), + { + uuid: v4(), + content: data.content, + role: "assistant", + sources: [], + closed: true, + error: null, + animate: false, + pending: false, + sentAt: Math.floor(Date.now() / 1000), + }, + ]; + }); + } + + if (!handledEvents.includes(data.type) || !data.content) return; + + if (data.type === "fileDownload") { + // File download functionality for embed + const blob = new Blob([atob(data.content.b64Content)], { type: 'application/octet-stream' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = data.content.filename ?? 'unknown.txt'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + return; + } + + if (data.type === "rechartVisualize") { + return setChatHistory((prev) => { + return [ + ...prev.filter((msg) => !!msg.content), + { + type: "rechartVisualize", + uuid: v4(), + content: data.content, + role: "assistant", + sources: [], + closed: true, + error: null, + animate: false, + pending: false, + sentAt: Math.floor(Date.now() / 1000), + }, + ]; + }); + } + + if (data.type === "wssFailure") { + return setChatHistory((prev) => { + return [ + ...prev.filter((msg) => !!msg.content), + { + uuid: v4(), + content: data.content, + role: "assistant", + sources: [], + closed: true, + error: data.content, + animate: false, + pending: false, + sentAt: Math.floor(Date.now() / 1000), + }, + ]; + }); + } + + return setChatHistory((prev) => { + return [ + ...prev.filter((msg) => !!msg.content), + { + uuid: v4(), + type: data.type, + content: data.content, + role: "assistant", + sources: [], + closed: true, + error: null, + animate: data?.animate || false, + pending: false, + sentAt: Math.floor(Date.now() / 1000), + }, + ]; + }); +} + +export function useIsAgentSessionActive() { + const [activeSession, setActiveSession] = useState(false); + useEffect(() => { + function listenForAgentSession() { + if (!window) return; + window.addEventListener(AGENT_SESSION_START, () => + setActiveSession(true) + ); + window.addEventListener(AGENT_SESSION_END, () => setActiveSession(false)); + } + listenForAgentSession(); + }, []); + + return activeSession; +} \ No newline at end of file diff --git a/src/utils/chat/index.js b/src/utils/chat/index.js index 62d25cb..6883977 100644 --- a/src/utils/chat/index.js +++ b/src/utils/chat/index.js @@ -1,10 +1,13 @@ +export const ABORT_STREAM_EVENT = "abort-chat-stream"; + // For handling of synchronous chats that are not utilizing streaming or chat requests. export default function handleChat( chatResult, setLoadingResponse, setChatHistory, remHistory, - _chatHistory + _chatHistory, + setSocketId = null ) { const { uuid, @@ -14,12 +17,18 @@ export default function handleChat( error, close, errorMsg = null, + websocketUUID = null, } = chatResult; // Preserve the sentAt from the last message in the chat history const lastMessage = _chatHistory[_chatHistory.length - 1]; const sentAt = lastMessage?.sentAt; + console.log("--------"); + console.log("--------"); + console.log("--------"); + console.log(chatResult); + if (type === "abort") { setLoadingResponse(false); setChatHistory([ @@ -109,6 +118,39 @@ export default function handleChat( }); } setChatHistory([..._chatHistory]); + } else if (type === "agentInitWebsocketConnection" && setSocketId) { + setSocketId(websocketUUID); + } else if (type === "statusResponse") { + setLoadingResponse(false); + setChatHistory([ + ...remHistory, + { + uuid, + type: "statusResponse", + content: textResponse, + role: "assistant", + sources, + closed: true, + error, + errorMsg, + animate: false, + pending: false, + sentAt, + }, + ]); + _chatHistory.push({ + uuid, + type: "statusResponse", + content: textResponse, + role: "assistant", + sources, + closed: true, + error, + errorMsg, + animate: false, + pending: false, + sentAt, + }); } } diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..b4c48ec --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,8 @@ +export function safeJsonParse(jsonString, defaultValue) { + try { + return JSON.parse(jsonString); + } catch (error) { + console.error("Failed to parse JSON:", error); + return defaultValue; + } +} \ No newline at end of file From 6a6577b8019c3106465729ae2961b6b1415c8340 Mon Sep 17 00:00:00 2001 From: Efros Ionelu Date: Thu, 28 Aug 2025 11:45:00 +0300 Subject: [PATCH 2/3] workflow agents --- src/components/AgentIndicator/index.jsx | 19 ----------- .../ChatWindow/ChatContainer/index.jsx | 15 -------- src/components/ChatWindow/Header/index.jsx | 9 +++-- src/components/ChatWindow/index.jsx | 2 -- src/hooks/useScriptAttributes.js | 1 + src/utils/agent.js | 2 +- src/utils/chat/index.js | 34 ------------------- 7 files changed, 9 insertions(+), 73 deletions(-) delete mode 100644 src/components/AgentIndicator/index.jsx diff --git a/src/components/AgentIndicator/index.jsx b/src/components/AgentIndicator/index.jsx deleted file mode 100644 index 68b6003..0000000 --- a/src/components/AgentIndicator/index.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from "react"; -import { useIsAgentSessionActive } from "@/utils/agent"; - -export default function AgentIndicator() { - const isAgentActive = useIsAgentSessionActive(); - - if (!isAgentActive) return null; - - return ( -
-
-
- - Agent session active - -
-
- ); -} \ No newline at end of file diff --git a/src/components/ChatWindow/ChatContainer/index.jsx b/src/components/ChatWindow/ChatContainer/index.jsx index fc89574..3fb3862 100644 --- a/src/components/ChatWindow/ChatContainer/index.jsx +++ b/src/components/ChatWindow/ChatContainer/index.jsx @@ -178,21 +178,6 @@ export default function ChatContainer({ socket.addEventListener("close", (_event) => { window.dispatchEvent(new CustomEvent(AGENT_SESSION_END)); - setChatHistory((prev) => [ - ...prev.filter((msg) => !!msg.content), - { - uuid: v4(), - type: "statusResponse", - content: "Agent session complete.", - role: "assistant", - sources: [], - closed: true, - error: null, - animate: false, - pending: false, - sentAt: Math.floor(Date.now() / 1000), - }, - ]); setLoadingResponse(false); setWebsocket(null); setSocketId(null); diff --git a/src/components/ChatWindow/Header/index.jsx b/src/components/ChatWindow/Header/index.jsx index 2cc00fe..35c3eb3 100644 --- a/src/components/ChatWindow/Header/index.jsx +++ b/src/components/ChatWindow/Header/index.jsx @@ -49,9 +49,14 @@ export default function ChatWindowHeader({ className="allm-flex allm-items-center allm-relative allm-rounded-t-2xl" id="anything-llm-header" > -
+
{iconUrl diff --git a/src/components/ChatWindow/index.jsx b/src/components/ChatWindow/index.jsx index edff7ef..3628d1b 100644 --- a/src/components/ChatWindow/index.jsx +++ b/src/components/ChatWindow/index.jsx @@ -5,7 +5,6 @@ import ChatContainer from "./ChatContainer"; import Sponsor from "../Sponsor"; import { ChatHistoryLoading } from "./ChatContainer/ChatHistory"; import ResetChat from "../ResetChat"; -import AgentIndicator from "../AgentIndicator"; export default function ChatWindow({ closeChat, settings, sessionId }) { const { chatHistory, setChatHistory, loading } = useChatHistory( @@ -45,7 +44,6 @@ export default function ChatWindow({ closeChat, settings, sessionId }) { setChatHistory={setChatHistory} /> )} -
Date: Thu, 28 Aug 2025 11:45:53 +0300 Subject: [PATCH 3/3] workflow agents --- src/components/ChatWindow/Header/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ChatWindow/Header/index.jsx b/src/components/ChatWindow/Header/index.jsx index 35c3eb3..b23b745 100644 --- a/src/components/ChatWindow/Header/index.jsx +++ b/src/components/ChatWindow/Header/index.jsx @@ -56,7 +56,7 @@ export default function ChatWindowHeader({ }} > {iconUrl