diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 805cf41..9e61658 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -46,7 +46,7 @@ type EditableAgent = { type AgentChatMessage = { id: string; - role: "user" | "assistant"; + role: "user" | "assistant" | "tool"; content: string; }; @@ -452,6 +452,28 @@ function createConversationId(): string { return `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; } +function mapConversationMessageToAgentChatMessage( + message: ConversationMessageItem +): AgentChatMessage | null { + const type = (message.message_type || "").toLowerCase(); + let role: AgentChatMessage["role"] | null = null; + if (type === "human" || type === "user") { + role = "user"; + } else if (type === "ai" || type === "assistant") { + role = "assistant"; + } else if (type === "tool") { + role = "tool"; + } + if (!role) { + return null; + } + return { + id: `${message.sequence_number}-${message.created_at}-${role}`, + role, + content: message.content || "", + }; +} + function normalizeDeepAgentActBackend(value: unknown): DeepAgentActBackend { if (value === "local_shell" || value === "localshell") { return "local_shell"; @@ -1227,6 +1249,7 @@ export default function App() { async function sendAgentChatMessage(): Promise { const pipelineId = (chatPipelineId || "").trim(); + const conversationId = chatConversationId; const message = chatInput.trim(); if (!pipelineId || !message || chatSending) { return; @@ -1256,7 +1279,7 @@ export default function App() { try { await streamAgentChatResponse({ appId: pipelineId, - sessionId: chatConversationId, + sessionId: conversationId, apiKey: authKey, message, signal: controller.signal, @@ -1273,6 +1296,34 @@ export default function App() { ); }, }); + // Some runtimes namespace thread ids as ":" when persisting. + // Try both IDs and fail soft so a successful streamed reply never turns into a UI error. + const candidateConversationIds = [ + conversationId, + `${pipelineId}:${conversationId}`, + ]; + let reloaded = false; + for (const candidateId of candidateConversationIds) { + try { + const storedMessages = await getPipelineConversationMessages( + pipelineId, + candidateId + ); + const normalizedMessages = storedMessages + .map(mapConversationMessageToAgentChatMessage) + .filter((item): item is AgentChatMessage => item !== null); + if (normalizedMessages.length > 0) { + setChatMessages(normalizedMessages); + reloaded = true; + break; + } + } catch { + // Ignore refresh failures; keep streamed content visible. + } + } + if (!reloaded) { + // Keep existing streamed messages without surfacing a false error state. + } } catch (error) { if ((error as Error).message === "Request cancelled") { setChatMessages((prev) => @@ -1907,9 +1958,15 @@ export default function App() { chatMessages.map((message) => (
- {message.role === "assistant" ? "Agent" : "You"} + + {message.role === "assistant" + ? "Agent" + : message.role === "tool" + ? "Tool" + : "You"} +
{message.content || (chatSending && message.role === "assistant" ? "..." : "")} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 6c5aca5..43d7da9 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -611,6 +611,10 @@ button:disabled { border-left: 3px solid #26a269; } +.chat-modal-message.tool { + border-left: 3px solid #8e6bd8; +} + .chat-modal-message p { margin: 6px 0 0 0; white-space: pre-wrap;