From e9fc988ce062f503f5364dca961c6707aa980b39 Mon Sep 17 00:00:00 2001 From: Chaitanya Rahalkar Date: Thu, 12 Jun 2025 22:16:38 -0500 Subject: [PATCH] feat(ui): add chain-of-thought panel above assistant messages --- ui/desktop/src/components/GooseMessage.tsx | 42 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/ui/desktop/src/components/GooseMessage.tsx b/ui/desktop/src/components/GooseMessage.tsx index f001edcc7167..12568d28ea89 100644 --- a/ui/desktop/src/components/GooseMessage.tsx +++ b/ui/desktop/src/components/GooseMessage.tsx @@ -45,12 +45,29 @@ export default function GooseMessage({ // Extract text content from the message let textContent = getTextContent(message); - // Extract image paths from the message - const imagePaths = extractImagePaths(textContent); + // Utility to split Chain-of-Thought (CoT) from the visible assistant response. + // If the text contains a ... block, everything inside is treated as the + // CoT and removed from the user-visible text. + const splitChainOfThought = (text: string): { visibleText: string; cotText: string | null } => { + const regex = /([\s\S]*?)<\/think>/i; + const match = text.match(regex); + if (!match) { + return { visibleText: text, cotText: null }; + } + + const cotRaw = match[1].trim(); + const visible = text.replace(match[0], '').trim(); + return { visibleText: visible, cotText: cotRaw.length > 0 ? cotRaw : null }; + }; + + const { visibleText: textWithoutCot, cotText } = splitChainOfThought(textContent); + + // Extract image paths from the visible part of the message (exclude CoT) + const imagePaths = extractImagePaths(textWithoutCot); // Remove image paths from text for display const displayText = - imagePaths.length > 0 ? removeImagePathsFromText(textContent, imagePaths) : textContent; + imagePaths.length > 0 ? removeImagePathsFromText(textWithoutCot, imagePaths) : textWithoutCot; // Memoize the timestamp const timestamp = useMemo(() => formatMessageTimestamp(message.created), [message.created]); @@ -115,7 +132,20 @@ export default function GooseMessage({ return (
- {textContent && ( + {/* Chain-of-Thought (hidden by default) */} + {cotText && ( +
+ + Show thinking + +
+ +
+
+ )} + + {/* Visible assistant response */} + {displayText && (
{}
@@ -137,7 +167,7 @@ export default function GooseMessage({ {timestamp}
)} - {textContent && message.content.every((content) => content.type === 'text') && ( + {displayText && message.content.every((content) => content.type === 'text') && (
@@ -194,7 +224,7 @@ export default function GooseMessage({ {/* NOTE from alexhancock on 1/14/2025 - disabling again temporarily due to non-determinism in when the forms show up */} {false && metadata && (
- +
)}