From a832bd805cc0441e47d233d847beea38e1cae356 Mon Sep 17 00:00:00 2001 From: Molecule AI Fullstack Engineer Date: Sun, 10 May 2026 21:18:55 +0000 Subject: [PATCH] fix(canvas): extractMessageText uses only first direct text field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: `extractMessageText` in ConversationTraceModal joined text from ALL result.parts[].text + result.parts[].root.text entries, concatenating "Direct text\nRoot text" when only "Direct text" was expected. Fix: scan all parts for the first direct `text` field and return it. Only fall back to `parts[0].root.text` when no direct text exists. Subsequent parts' root.text fields are ignored when a direct text was found in an earlier part — matching the test contract. Fixes: ConversationTraceModal.test.tsx "prefers parts[].text over parts[].root.text" (test was failing with concat output). Co-Authored-By: Claude Opus 4.7 --- .../src/components/ConversationTraceModal.tsx | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/canvas/src/components/ConversationTraceModal.tsx b/canvas/src/components/ConversationTraceModal.tsx index 63afe664..c585781a 100644 --- a/canvas/src/components/ConversationTraceModal.tsx +++ b/canvas/src/components/ConversationTraceModal.tsx @@ -31,17 +31,25 @@ export function extractMessageText(body: Record | null): string if (text) return text; // Response: result.parts[].text or result.parts[].root.text + // Use the first part that has a direct text field; within that part, + // prefer direct text over root.text. Subsequent parts' root.text fields + // are ignored when a direct text exists in an earlier part. const result = body.result as Record | undefined; const rParts = (result?.parts || []) as Array>; - const rText = rParts - .map((p) => { - if (p.text) return p.text as string; - const root = p.root as Record | undefined; - return (root?.text as string) || ""; - }) - .filter(Boolean) - .join("\n"); - if (rText) return rText; + const firstPartWithText = rParts.find( + (p) => typeof p.text === "string" && (p.text as string) !== "" + ); + if (firstPartWithText) { + return firstPartWithText.text as string; + } + // No direct text found; use root.text from the first part (if present). + const firstPart = rParts[0]; + if (firstPart) { + const root = firstPart.root as Record | undefined; + if (typeof root?.text === "string" && root.text !== "") { + return root.text as string; + } + } if (typeof body.result === "string") return body.result; } catch { /* ignore */ }