From 9b3db40b94e9d0717a532868a999cbdd9a742ccd Mon Sep 17 00:00:00 2001 From: goulustis Date: Fri, 6 Mar 2026 15:19:51 +0800 Subject: [PATCH] enable simple chat --- frontend/src/App.tsx | 212 ++++++++++++++++++++++++++++++---- frontend/src/api/frontApis.ts | 102 ++++++++++++++++ frontend/src/styles.css | 93 +++++++++++++++ 3 files changed, 384 insertions(+), 23 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e422c01..28998e6 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -16,6 +16,7 @@ import { listGraphConfigs, listPipelines, stopPipeline, + streamAgentChatResponse, updateMcpToolConfig, upsertGraphConfig, } from "./api/frontApis"; @@ -40,6 +41,12 @@ type EditableAgent = { llmName: string; }; +type AgentChatMessage = { + id: string; + role: "user" | "assistant"; + content: string; +}; + type ActiveTab = "agents" | "discussions" | "mcp"; type McpTransport = "streamable_http" | "sse" | "stdio"; type McpEntry = { @@ -401,6 +408,10 @@ function buildAgentChatUrlBase(): string { return `${baseUrl}/`; } +function createConversationId(): string { + return `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; +} + function toEditable( config: GraphConfigReadResponse, draft: boolean @@ -439,6 +450,11 @@ export default function App() { const [selectedConversationId, setSelectedConversationId] = useState(null); const [discussionMessages, setDiscussionMessages] = useState([]); const [discussionLoading, setDiscussionLoading] = useState(false); + const [chatPipelineId, setChatPipelineId] = useState(null); + const [chatConversationId, setChatConversationId] = useState(createConversationId); + const [chatInput, setChatInput] = useState(""); + const [chatMessages, setChatMessages] = useState([]); + const [chatSending, setChatSending] = useState(false); const [busy, setBusy] = useState(false); const configKeySet = useMemo( @@ -1037,6 +1053,88 @@ export default function App() { } } + function openAgentChat(pipelineId: string): void { + setChatPipelineId(pipelineId); + setChatConversationId(createConversationId()); + setChatMessages([]); + setChatInput(""); + setStatusMessage(""); + } + + function closeAgentChat(): void { + setChatPipelineId(null); + setChatMessages([]); + setChatInput(""); + } + + function startNewAgentChatConversation(): void { + setChatConversationId(createConversationId()); + setChatMessages([]); + setChatInput(""); + } + + async function sendAgentChatMessage(): Promise { + const pipelineId = (chatPipelineId || "").trim(); + const message = chatInput.trim(); + if (!pipelineId || !message || chatSending) { + return; + } + + const authKey = runtimeFastApiKey.trim() || "dev-key"; + const userMessage: AgentChatMessage = { + id: `user-${Date.now()}`, + role: "user", + content: message, + }; + const assistantMessageId = `assistant-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; + const assistantMessage: AgentChatMessage = { + id: assistantMessageId, + role: "assistant", + content: "", + }; + + setChatSending(true); + setChatInput(""); + setChatMessages((prev) => [...prev, userMessage, assistantMessage]); + setStatusMessage(""); + + try { + await streamAgentChatResponse({ + appId: pipelineId, + sessionId: chatConversationId, + apiKey: authKey, + message, + onText: (text) => { + setChatMessages((prev) => + prev.map((item) => + item.id === assistantMessageId + ? { + ...item, + content: text, + } + : item + ) + ); + }, + }); + } catch (error) { + const messageText = (error as Error).message || "Chat request failed."; + setStatusMessage(messageText); + setChatMessages((prev) => + prev.map((item) => + item.id === assistantMessageId + ? { + ...item, + content: `Error: ${messageText}`, + } + : item + ) + ); + } finally { + setChatSending(false); + } + } + const rows = [ ...draftAgents.map((d) => ({ id: d.id, @@ -1069,30 +1167,44 @@ export default function App() {
{rows.map((row) => ( - + {row.graphId} + + {!row.isDraft ? ( + + ) : null} +
))} {rows.length === 0 ?

No agents configured yet.

: null} @@ -1530,6 +1642,60 @@ export default function App() { )} + + {chatPipelineId ? ( +
+
+
+
+ Chat: {chatPipelineId} + conv_id: {chatConversationId} +
+
+ + +
+
+
+ {chatMessages.length === 0 ? ( +

Send a message to start this conversation.

+ ) : ( + chatMessages.map((message) => ( +
+ {message.role === "assistant" ? "Agent" : "You"} +

{message.content || (chatSending && message.role === "assistant" ? "..." : "")}

+
+ )) + )} +
+
+