From 8ad90e37d58f33ed30f4546c962d5b552136c6ae Mon Sep 17 00:00:00 2001 From: Pedram Amini Date: Mon, 22 Dec 2025 18:45:54 -0600 Subject: [PATCH] MAESTRO: Clear thinking logs when process is interrupted (Phase 6.1) Filter out LogEntry items with source='thinking' in all interrupt and kill code paths in handleInterrupt(): - When busy tabs are interrupted and queued items exist - When going to idle with no queued items - When adding kill log after successful kill - When processing next queued item after kill - When kill succeeds with no queued items - When kill fails and adding error log This ensures thinking content is cleaned up when users cancel or kill AI processes, preventing stale thinking entries from remaining in the conversation history. --- src/renderer/App.tsx | 69 +++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 2bc141e3..2f048d3f 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -5503,8 +5503,10 @@ export default function MaestroConsole() { return { ...tab, state: 'busy' as const, thinkingStartTime: Date.now() }; } // Set any other busy tabs to idle (they were interrupted) and add canceled log + // Also clear any thinking logs since the process was interrupted if (tab.state === 'busy') { - const updatedLogs = canceledLog ? [...tab.logs, canceledLog] : tab.logs; + const logsWithoutThinking = tab.logs.filter(log => log.source !== 'thinking'); + const updatedLogs = canceledLog ? [...logsWithoutThinking, canceledLog] : logsWithoutThinking; return { ...tab, state: 'idle' as const, thinkingStartTime: undefined, logs: updatedLogs }; } return tab; @@ -5539,18 +5541,23 @@ export default function MaestroConsole() { } // No queued items, just go to idle and add canceled log to the active tab + // Also clear any thinking logs since the process was interrupted const activeTabForCancel = getActiveTab(s); const updatedAiTabsForIdle = canceledLog && activeTabForCancel - ? s.aiTabs.map(tab => - tab.id === activeTabForCancel.id - ? { ...tab, logs: [...tab.logs, canceledLog], state: 'idle' as const, thinkingStartTime: undefined } - : tab - ) - : s.aiTabs.map(tab => - tab.state === 'busy' - ? { ...tab, state: 'idle' as const, thinkingStartTime: undefined } - : tab - ); + ? s.aiTabs.map(tab => { + if (tab.id === activeTabForCancel.id) { + const logsWithoutThinking = tab.logs.filter(log => log.source !== 'thinking'); + return { ...tab, logs: [...logsWithoutThinking, canceledLog], state: 'idle' as const, thinkingStartTime: undefined }; + } + return tab; + }) + : s.aiTabs.map(tab => { + if (tab.state === 'busy') { + const logsWithoutThinking = tab.logs.filter(log => log.source !== 'thinking'); + return { ...tab, state: 'idle' as const, thinkingStartTime: undefined, logs: logsWithoutThinking }; + } + return tab; + }); return { ...s, @@ -5601,14 +5608,18 @@ export default function MaestroConsole() { setSessions(prev => prev.map(s => { if (s.id !== activeSession.id) return s; - // Add kill log to the appropriate place + // Add kill log to the appropriate place and clear thinking logs let updatedSession = { ...s }; if (currentMode === 'ai') { const tab = getActiveTab(s); if (tab) { - updatedSession.aiTabs = s.aiTabs.map(t => - t.id === tab.id ? { ...t, logs: [...t.logs, killLog] } : t - ); + updatedSession.aiTabs = s.aiTabs.map(t => { + if (t.id === tab.id) { + const logsWithoutThinking = t.logs.filter(log => log.source !== 'thinking'); + return { ...t, logs: [...logsWithoutThinking, killLog] }; + } + return t; + }); } } else { updatedSession.shellLogs = [...s.shellLogs, killLog]; @@ -5631,13 +5642,14 @@ export default function MaestroConsole() { }; } - // Set tabs appropriately + // Set tabs appropriately and clear thinking logs from interrupted tabs let updatedAiTabs = updatedSession.aiTabs.map(tab => { if (tab.id === targetTab.id) { return { ...tab, state: 'busy' as const, thinkingStartTime: Date.now() }; } if (tab.state === 'busy') { - return { ...tab, state: 'idle' as const, thinkingStartTime: undefined }; + const logsWithoutThinking = tab.logs.filter(log => log.source !== 'thinking'); + return { ...tab, state: 'idle' as const, thinkingStartTime: undefined, logs: logsWithoutThinking }; } return tab; }); @@ -5670,7 +5682,7 @@ export default function MaestroConsole() { }; } - // No queued items, just go to idle + // No queued items, just go to idle and clear thinking logs if (currentMode === 'ai') { const tab = getActiveTab(s); if (!tab) return { ...updatedSession, state: 'idle', busySource: undefined, thinkingStartTime: undefined }; @@ -5679,9 +5691,13 @@ export default function MaestroConsole() { state: 'idle', busySource: undefined, thinkingStartTime: undefined, - aiTabs: updatedSession.aiTabs.map(t => - t.id === tab.id ? { ...t, state: 'idle' as const, thinkingStartTime: undefined } : t - ) + aiTabs: updatedSession.aiTabs.map(t => { + if (t.id === tab.id) { + const logsWithoutThinking = t.logs.filter(log => log.source !== 'thinking'); + return { ...t, state: 'idle' as const, thinkingStartTime: undefined, logs: logsWithoutThinking }; + } + return t; + }) }; } return { ...updatedSession, state: 'idle', busySource: undefined, thinkingStartTime: undefined }; @@ -5712,9 +5728,14 @@ export default function MaestroConsole() { state: 'idle', busySource: undefined, thinkingStartTime: undefined, - aiTabs: s.aiTabs.map(t => - t.id === tab.id ? { ...t, state: 'idle' as const, thinkingStartTime: undefined, logs: [...t.logs, errorLog] } : t - ) + aiTabs: s.aiTabs.map(t => { + if (t.id === tab.id) { + // Clear thinking logs even on error + const logsWithoutThinking = t.logs.filter(log => log.source !== 'thinking'); + return { ...t, state: 'idle' as const, thinkingStartTime: undefined, logs: [...logsWithoutThinking, errorLog] }; + } + return t; + }) }; } return { ...s, shellLogs: [...s.shellLogs, errorLog], state: 'idle', busySource: undefined, thinkingStartTime: undefined };