diff --git a/ui/suite/chat/chat.html b/ui/suite/chat/chat.html index 8e22778..537bd76 100644 --- a/ui/suite/chat/chat.html +++ b/ui/suite/chat/chat.html @@ -283,40 +283,49 @@ ); } - function addMessage(sender, content, msgId) { - var messages = document.getElementById("messages"); - if (!messages) return; +function addMessage(sender, content, msgId) { + var messages = document.getElementById("messages"); + if (!messages) return; - var div = document.createElement("div"); - div.className = "message " + sender; - if (msgId) div.id = msgId; + var div = document.createElement("div"); + div.className = "message " + sender; + if (msgId) div.id = msgId; - if (sender === "user") { - var processedContent = renderMentionInMessage( - escapeHtml(content), - ); - div.innerHTML = - '
"; - } else { - // Check if content has HTML (any tag, including comments) - var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(content); - console.log("Bot message - hasHtmlTags:", hasHtmlTags, "content length:", content.length); - - var parsed = hasHtmlTags - ? content // Use HTML directly (no escaping!) - : (typeof marked !== "undefined" && marked.parse - ? marked.parse(content) - : escapeHtml(content)); - parsed = renderMentionInMessage(parsed); - div.innerHTML = - '"; - } + if (sender === "user") { + var processedContent = renderMentionInMessage( + escapeHtml(content), + ); + div.innerHTML = + '"; + } else { + // Check if content has HTML (any tag, including comments) + var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(content); + console.log("Bot message - hasHtmlTags:", hasHtmlTags, "content length:", content.length, "msgId:", msgId); - messages.appendChild(div); + var parsed; + if (hasHtmlTags && msgId) { + // Streaming HTML content - show as text initially to avoid broken tags + // Will be rendered as HTML at finalizeStreaming + parsed = escapeHtml(content); + } else if (hasHtmlTags) { + // Complete HTML content - render directly + parsed = content; + } else { + // Markdown content + parsed = typeof marked !== "undefined" && marked.parse + ? marked.parse(content) + : escapeHtml(content); + } + parsed = renderMentionInMessage(parsed); + div.innerHTML = + '"; + } + + messages.appendChild(div); // Auto-scroll to bottom unless user is manually scrolling if (!isUserScrolling) { @@ -735,36 +744,52 @@ return false; } - function updateStreaming(content) { - var el = document.getElementById(streamingMessageId); - if (el) { - // Check if content has HTML tags - var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(content); - var parsed = hasHtmlTags - ? content // Use HTML directly - : (typeof marked !== "undefined" && marked.parse - ? marked.parse(content) - : escapeHtml(content)); - parsed = renderMentionInMessage(parsed); - el.querySelector(".message-content").innerHTML = parsed; - } +function updateStreaming(content) { + var el = document.getElementById(streamingMessageId); + if (el) { + var msgContent = el.querySelector(".message-content"); + // Check if final content will be HTML (full accumulated content) + var willBeHtml = /<\/?[a-zA-Z][^>]*>|/i.test(currentStreamingContent); + if (willBeHtml) { + // For HTML content, show plain text during streaming to avoid broken tags + // HTML will be rendered at finalizeStreaming when complete + msgContent.textContent = content; + } else { + // For markdown, render incrementally + var parsed = typeof marked !== "undefined" && marked.parse + ? marked.parse(content) + : escapeHtml(content); + parsed = renderMentionInMessage(parsed); + msgContent.innerHTML = parsed; + } + } + } } - function finalizeStreaming() { - var el = document.getElementById(streamingMessageId); - if (el) { - // Check if content has HTML tags - var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(currentStreamingContent); - var parsed = hasHtmlTags - ? currentStreamingContent // Use HTML directly - : (typeof marked !== "undefined" && marked.parse - ? marked.parse(currentStreamingContent) - : escapeHtml(currentStreamingContent)); - parsed = renderMentionInMessage(parsed); - el.querySelector(".message-content").innerHTML = parsed; - el.removeAttribute("id"); - setupMentionClickHandlers(el); - } +function finalizeStreaming() { + var el = document.getElementById(streamingMessageId); + if (el) { + var msgContent = el.querySelector(".message-content"); + // Check if content has HTML tags + var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(currentStreamingContent); + if (hasHtmlTags) { + // Render complete HTML at the end + var parsed = renderMentionInMessage(currentStreamingContent); + msgContent.innerHTML = parsed; + } else { + // Render markdown + var parsed = typeof marked !== "undefined" && marked.parse + ? marked.parse(currentStreamingContent) + : escapeHtml(currentStreamingContent); + parsed = renderMentionInMessage(parsed); + msgContent.innerHTML = parsed; + } + el.removeAttribute("id"); + setupMentionClickHandlers(el); + } + streamingMessageId = null; + currentStreamingContent = ""; + } streamingMessageId = null; currentStreamingContent = ""; } diff --git a/ui/suite/partials/chat.html b/ui/suite/partials/chat.html index a055c48..eb4402e 100644 --- a/ui/suite/partials/chat.html +++ b/ui/suite/partials/chat.html @@ -487,40 +487,49 @@ ); } - function addMessage(sender, content, msgId) { - var messages = document.getElementById("messages"); - if (!messages) return; +function addMessage(sender, content, msgId) { + var messages = document.getElementById("messages"); + if (!messages) return; - var div = document.createElement("div"); - div.className = "message " + sender; - if (msgId) div.id = msgId; + var div = document.createElement("div"); + div.className = "message " + sender; + if (msgId) div.id = msgId; - if (sender === "user") { - var processedContent = renderMentionInMessage( - escapeHtml(content), - ); - div.innerHTML = - '"; - } else { - // Check if content has HTML (any tag, including comments) - var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(content); - console.log("Bot message - hasHtmlTags:", hasHtmlTags, "content length:", content.length); - - var parsed = hasHtmlTags - ? content // Use HTML directly (no escaping!) - : (typeof marked !== "undefined" && marked.parse - ? marked.parse(content) - : escapeHtml(content)); - parsed = renderMentionInMessage(parsed); - div.innerHTML = - '"; - } + if (sender === "user") { + var processedContent = renderMentionInMessage( + escapeHtml(content), + ); + div.innerHTML = + '"; + } else { + // Check if content has HTML (any tag, including comments) + var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(content); + console.log("Bot message - hasHtmlTags:", hasHtmlTags, "content length:", content.length, "msgId:", msgId); - messages.appendChild(div); + var parsed; + if (hasHtmlTags && msgId) { + // Streaming HTML content - show as text initially to avoid broken tags + // Will be rendered as HTML at finalizeStreaming + parsed = escapeHtml(content); + } else if (hasHtmlTags) { + // Complete HTML content - render directly + parsed = content; + } else { + // Markdown content + parsed = typeof marked !== "undefined" && marked.parse + ? marked.parse(content) + : escapeHtml(content); + } + parsed = renderMentionInMessage(parsed); + div.innerHTML = + '"; + } + + messages.appendChild(div); // Auto-scroll to bottom unless user is manually scrolling if (!isUserScrolling) { @@ -939,19 +948,26 @@ return false; } - function updateStreaming(content) { - var el = document.getElementById(streamingMessageId); - if (el) { - // Check if content has HTML tags - var hasHtmlTags = /<\/?[a-zA-Z][^>]*>|/i.test(content); - var parsed = hasHtmlTags - ? content // Use HTML directly - : (typeof marked !== "undefined" && marked.parse - ? marked.parse(content) - : escapeHtml(content)); - parsed = renderMentionInMessage(parsed); - el.querySelector(".message-content").innerHTML = parsed; - } +function updateStreaming(content) { + var el = document.getElementById(streamingMessageId); + if (el) { + var msgContent = el.querySelector(".message-content"); + // Check if final content will be HTML (full accumulated content) + var willBeHtml = /<\/?[a-zA-Z][^>]*>|/i.test(currentStreamingContent); + if (willBeHtml) { + // For HTML content, show plain text during streaming to avoid broken tags + // HTML will be rendered at finalizeStreaming when complete + msgContent.textContent = content; + } else { + // For markdown, render incrementally + var parsed = typeof marked !== "undefined" && marked.parse + ? marked.parse(content) + : escapeHtml(content); + parsed = renderMentionInMessage(parsed); + msgContent.innerHTML = parsed; + } + } + } } function finalizeStreaming() {