diff --git a/src/renderer/src/components/ChatView.tsx b/src/renderer/src/components/ChatView.tsx index b3f230ad19..5a33659bb0 100644 --- a/src/renderer/src/components/ChatView.tsx +++ b/src/renderer/src/components/ChatView.tsx @@ -377,6 +377,9 @@ function TextContentBlock({ content }: { content: string }) { // Thought block view - expanded, collapsible function ThoughtBlockView({ text }: { text: string }) { + // Skip rendering if content is empty or only whitespace + if (!text || !text.trim()) return null + const [isExpanded, setIsExpanded] = useState(false) const isLong = text.length > 200 diff --git a/src/renderer/src/hooks/useApp.ts b/src/renderer/src/hooks/useApp.ts index 8eeb8ca737..81b9f47c1a 100644 --- a/src/renderer/src/hooks/useApp.ts +++ b/src/renderer/src/hooks/useApp.ts @@ -1,7 +1,7 @@ /** * Main application state hook */ -import { useState, useEffect, useCallback, useRef } from 'react' +import { useState, useEffect, useCallback } from 'react' import type { MulticaSession, StoredSessionUpdate, @@ -56,9 +56,6 @@ export function useApp(): AppState & AppActions { ? runningSessionsStatus.processingSessionIds.includes(currentSession.id) : false - // Track streaming text for current message - const streamingTextRef = useRef('') - // Load sessions on mount useEffect(() => { loadSessions() @@ -71,71 +68,24 @@ export function useApp(): AppState & AppActions { // Subscribe to agent events useEffect(() => { const unsubMessage = window.electronAPI.onAgentMessage((message) => { - // Log all incoming ACP messages for debugging - console.log('[ACP Message]', JSON.stringify(message, null, 2)) - // Only process messages for the current session // message.sessionId is ACP Agent Session ID, compare with currentAgentSessionId if (!currentAgentSessionId || message.sessionId !== currentAgentSessionId) { - console.log('[ACP] Ignoring message for different session:', message.sessionId, 'current:', currentAgentSessionId) return } - const update = message.update - const updateType = update?.sessionUpdate - console.log('[ACP Update Type]', updateType) - - // Handle streaming text accumulation for agent messages - if (updateType === 'agent_message_chunk' && update.content?.type === 'text') { - streamingTextRef.current += update.content.text - } - - // Add the update to session updates for real-time display + // Pass through original update without any accumulation + // ChatView is responsible for accumulating chunks into complete messages setSessionUpdates((prev) => { - const now = new Date().toISOString() - - // For agent_message_chunk, we want to show accumulated text - if (updateType === 'agent_message_chunk') { - const streamingUpdate: StoredSessionUpdate = { - timestamp: now, - update: { - sessionId: message.sessionId, - update: { - sessionUpdate: 'agent_message_chunk', - content: { type: 'text', text: streamingTextRef.current }, - }, - }, - } - - // Replace last streaming update if it was also agent_message_chunk - const lastIdx = prev.length - 1 - if (lastIdx >= 0) { - const last = prev[lastIdx] - if ( - last.update.update && - 'sessionUpdate' in last.update.update && - last.update.update.sessionUpdate === 'agent_message_chunk' - ) { - return [...prev.slice(0, lastIdx), streamingUpdate] - } - } - return [...prev, streamingUpdate] - } - - // For all other update types, add them directly const newUpdate = { - timestamp: now, + timestamp: new Date().toISOString(), update: { sessionId: message.sessionId, - update: update, + update: message.update, }, } as StoredSessionUpdate return [...prev, newUpdate] }) - - if (message.done) { - streamingTextRef.current = '' - } }) const unsubStatus = window.electronAPI.onAgentStatus((status) => { @@ -238,7 +188,6 @@ export function useApp(): AppState & AppActions { try { setError(null) - streamingTextRef.current = '' // Add user message to updates (use a custom marker for UI display) // 'user_message' is a custom type not in ACP SDK, used for UI purposes only