diff --git a/components/chat-message-display.tsx b/components/chat-message-display.tsx
index f4b2dc7..5e00e6d 100644
--- a/components/chat-message-display.tsx
+++ b/components/chat-message-display.tsx
@@ -282,27 +282,64 @@ export function ChatMessageDisplay({
}
const handleDisplayChart = useCallback(
- (xml: string) => {
+ (xml: string, showToast = false) => {
const currentXml = xml || ""
const convertedXml = convertToLegalXml(currentXml)
if (convertedXml !== previousXML.current) {
- // If chartXML is empty, create a default mxfile structure to use with replaceNodes
- // This ensures the XML is properly wrapped in mxfile/diagram/mxGraphModel format
- const baseXML =
- chartXML ||
- ``
- const replacedXML = replaceNodes(baseXML, convertedXml)
+ // Parse and validate XML BEFORE calling replaceNodes
+ const parser = new DOMParser()
+ const testDoc = parser.parseFromString(convertedXml, "text/xml")
+ const parseError = testDoc.querySelector("parsererror")
- const validationError = validateMxCellStructure(replacedXML)
- if (!validationError) {
- previousXML.current = convertedXml
- // Skip validation in loadDiagram since we already validated above
- onDisplayChart(replacedXML, true)
- } else {
- console.log(
- "[ChatMessageDisplay] XML validation failed:",
- validationError,
+ if (parseError) {
+ console.error(
+ "[ChatMessageDisplay] Malformed XML detected - skipping update",
)
+ // Only show toast if this is the final XML (not during streaming)
+ if (showToast) {
+ toast.error(
+ "AI generated invalid diagram XML. Please try regenerating.",
+ )
+ }
+ return // Skip this update
+ }
+
+ try {
+ // If chartXML is empty, create a default mxfile structure to use with replaceNodes
+ // This ensures the XML is properly wrapped in mxfile/diagram/mxGraphModel format
+ const baseXML =
+ chartXML ||
+ ``
+ const replacedXML = replaceNodes(baseXML, convertedXml)
+
+ const validationError = validateMxCellStructure(replacedXML)
+ if (!validationError) {
+ previousXML.current = convertedXml
+ // Skip validation in loadDiagram since we already validated above
+ onDisplayChart(replacedXML, true)
+ } else {
+ console.error(
+ "[ChatMessageDisplay] XML validation failed:",
+ validationError,
+ )
+ // Only show toast if this is the final XML (not during streaming)
+ if (showToast) {
+ toast.error(
+ "Diagram validation failed. Please try regenerating.",
+ )
+ }
+ }
+ } catch (error) {
+ console.error(
+ "[ChatMessageDisplay] Error processing XML:",
+ error,
+ )
+ // Only show toast if this is the final XML (not during streaming)
+ if (showToast) {
+ toast.error(
+ "Failed to process diagram. Please try regenerating.",
+ )
+ }
}
}
},
@@ -345,12 +382,14 @@ export function ChatMessageDisplay({
state === "input-streaming" ||
state === "input-available"
) {
- handleDisplayChart(xml)
+ // During streaming, don't show toast (XML may be incomplete)
+ handleDisplayChart(xml, false)
} else if (
state === "output-available" &&
!processedToolCalls.current.has(toolCallId)
) {
- handleDisplayChart(xml)
+ // Show toast only if final XML is malformed
+ handleDisplayChart(xml, true)
processedToolCalls.current.add(toolCallId)
}
}