From b305f4ab084367266cd48640326ac8c2e2bee1bd Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Thu, 5 Feb 2026 18:11:43 +1100 Subject: [PATCH] shows thinking --- ui/desktop/src/components/GooseMessage.tsx | 9 ++++++++- ui/desktop/src/hooks/usePiChat.ts | 8 +++----- ui/desktop/src/pi/index.ts | 14 ++++++-------- ui/desktop/src/types/message.ts | 12 ++++++++++++ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/ui/desktop/src/components/GooseMessage.tsx b/ui/desktop/src/components/GooseMessage.tsx index 16de3de51c..26068a55f9 100644 --- a/ui/desktop/src/components/GooseMessage.tsx +++ b/ui/desktop/src/components/GooseMessage.tsx @@ -5,6 +5,7 @@ import MarkdownContent from './MarkdownContent'; import ToolCallWithResponse from './ToolCallWithResponse'; import { getTextAndImageContent, + getThinkingContent, getToolRequests, getToolResponses, getToolConfirmationContent, @@ -62,7 +63,13 @@ export default function GooseMessage({ }; }; - const { displayText, cotText } = splitChainOfThought(textContent); + const { displayText, cotText: taggedThinking } = splitChainOfThought(textContent); + + // Get thinking from content type (extended thinking from Claude/Pi) + const contentThinking = getThinkingContent(message); + + // Combine both sources of thinking (tagged inline and content type) + const cotText = [taggedThinking, contentThinking].filter(Boolean).join('\n\n') || null; const timestamp = useMemo(() => formatMessageTimestamp(message.created), [message.created]); const toolRequests = getToolRequests(message); diff --git a/ui/desktop/src/hooks/usePiChat.ts b/ui/desktop/src/hooks/usePiChat.ts index 4f59d021d3..51c7939735 100644 --- a/ui/desktop/src/hooks/usePiChat.ts +++ b/ui/desktop/src/hooks/usePiChat.ts @@ -299,11 +299,9 @@ export function usePiChat({ } }; - const handlePiComplete = (_e: unknown, data?: { messages?: Message[] }) => { - // Update with final messages if provided - if (data?.messages) { - dispatch({ type: 'SET_MESSAGES', payload: data.messages }); - } + const handlePiComplete = (_e: unknown, _data?: { messages?: Message[] }) => { + // Don't replace messages - we've been updating them incrementally + // The final messages are already in state from message_update/message_end events dispatch({ type: 'STREAM_FINISH' }); onStreamFinish(); }; diff --git a/ui/desktop/src/pi/index.ts b/ui/desktop/src/pi/index.ts index 2b15c04d92..15c57e09b7 100644 --- a/ui/desktop/src/pi/index.ts +++ b/ui/desktop/src/pi/index.ts @@ -345,7 +345,7 @@ export async function promptPi( return; } - // Create user message + // Add user message to session for persistence (UI already shows it via usePiChat) const userMessage: GooseMessage = { id: `msg_${Date.now()}_user`, role: 'user', @@ -353,14 +353,12 @@ export async function promptPi( content: [{ type: 'text', text: message }], metadata: { userVisible: true, agentVisible: true }, }; - - // Add user message to conversation currentSession.conversation.push(userMessage); currentSession.message_count++; currentSession.updated_at = new Date().toISOString(); - // Update session name from first message - if (currentSession.conversation.length === 1) { + // Update session name from first user message + if (currentSession.conversation.filter(m => m.role === 'user').length === 1) { currentSession.name = generateSessionName(currentSession.conversation); } @@ -387,11 +385,11 @@ export async function promptPi( onNotification(result.notification); } - // Send translated message to renderer - if (result.message) { + // Send translated message to renderer (skip user messages - UI already has them) + if (result.message && result.message.role !== 'user') { onEvent(piEvent, result.message); - // Update conversation with assistant messages + // Update conversation with assistant messages for persistence if (result.message.role === 'assistant') { // Find or add this message in conversation const existingIdx = currentSession!.conversation.findIndex(m => m.id === result.message!.id); diff --git a/ui/desktop/src/types/message.ts b/ui/desktop/src/types/message.ts index 43423578ed..7a3ea21848 100644 --- a/ui/desktop/src/types/message.ts +++ b/ui/desktop/src/types/message.ts @@ -87,6 +87,18 @@ export function getTextAndImageContent(message: Message): { return { textContent, imagePaths }; } +export function getThinkingContent(message: Message): string | null { + const thinkingParts: string[] = []; + + for (const content of message.content) { + if (content.type === 'thinking' && content.thinking) { + thinkingParts.push(content.thinking); + } + } + + return thinkingParts.length > 0 ? thinkingParts.join('\n\n') : null; +} + export function getToolRequests(message: Message): (ToolRequest & { type: 'toolRequest' })[] { return message.content.filter( (content): content is ToolRequest & { type: 'toolRequest' } => content.type === 'toolRequest'