diff --git a/src/__tests__/integration/contextSummarizer.integration.test.ts b/src/__tests__/integration/contextSummarizer.integration.test.ts index aeb055ea69..4652eb5f09 100644 --- a/src/__tests__/integration/contextSummarizer.integration.test.ts +++ b/src/__tests__/integration/contextSummarizer.integration.test.ts @@ -329,7 +329,7 @@ Continue with implementation.`); const logs = [createMockLog({ text: 'Test' })]; await expect(service.summarizeContext(baseRequest, logs, () => {})).rejects.toThrow( - 'Context summarization failed' + 'IPC failed' ); }); }); diff --git a/src/__tests__/renderer/hooks/useSummarizeHandler.test.ts b/src/__tests__/renderer/hooks/useSummarizeHandler.test.ts index dd914b2621..bd76302602 100644 --- a/src/__tests__/renderer/hooks/useSummarizeHandler.test.ts +++ b/src/__tests__/renderer/hooks/useSummarizeHandler.test.ts @@ -740,7 +740,7 @@ describe('handleSummarizeAndContinue (Tier 3E)', () => { expect(notifyToast).toHaveBeenCalledWith( expect.objectContaining({ type: 'error', - message: 'Failed to compact context. Check the tab for details.', + message: 'Failed to compact context: Summarization failed', }) ); }); @@ -778,7 +778,7 @@ describe('handleSummarizeAndContinue (Tier 3E)', () => { expect(notifyToast).toHaveBeenCalledWith( expect.objectContaining({ type: 'error', - message: 'An unexpected error occurred during compaction.', + message: 'An unexpected error occurred during compaction: store write failed', sessionId: 'session-1', tabId: 'tab-1', }) diff --git a/src/__tests__/renderer/services/contextSummarizer.test.ts b/src/__tests__/renderer/services/contextSummarizer.test.ts index 243eab1cc2..1bcef09b7d 100644 --- a/src/__tests__/renderer/services/contextSummarizer.test.ts +++ b/src/__tests__/renderer/services/contextSummarizer.test.ts @@ -323,13 +323,16 @@ Continue with implementation.`); expect(consoleLog).toHaveBeenCalledWith('[ContextSummarizer] Received response, length:', 0); }); - it('should handle IPC errors gracefully', async () => { + it('should propagate the underlying IPC error', async () => { + // Preserving the inner message lets the renderer surface real + // causes (e.g. "Agent X is not available") in the failure toast + // instead of a generic "Context summarization failed". mockGroomContext.mockRejectedValue(new Error('IPC failed')); const logs = [createMockLog({ text: 'Test' })]; await expect(service.summarizeContext(baseRequest, logs, () => {})).rejects.toThrow( - 'Context summarization failed' + 'IPC failed' ); }); }); diff --git a/src/renderer/hooks/agent/useSummarizeAndContinue.ts b/src/renderer/hooks/agent/useSummarizeAndContinue.ts index 4f75d65684..5586957096 100644 --- a/src/renderer/hooks/agent/useSummarizeAndContinue.ts +++ b/src/renderer/hooks/agent/useSummarizeAndContinue.ts @@ -398,11 +398,18 @@ export function useSummarizeAndContinue(session: Session | null): UseSummarizeAn // Clear the summarization state for this tab clearTabState(targetTabId); } else { - // startSummarize returned null (error already set in operationStore) + // startSummarize returned null after setting an error state in + // operationStore. Pull the actual error so the toast can + // surface it directly instead of pointing users at a "tab" + // that never renders details. + const tabState = useOperationStore.getState().summarizeStates.get(targetTabId); + const detail = tabState?.error?.trim(); notifyToast({ type: 'error', title: 'Compaction Failed', - message: 'Failed to compact context. Check the tab for details.', + message: detail + ? `Failed to compact context: ${detail}` + : 'Failed to compact context.', sessionId: sourceSessionId, tabId: targetTabId, }); @@ -410,10 +417,13 @@ export function useSummarizeAndContinue(session: Session | null): UseSummarizeAn }) .catch((err) => { console.error('[handleSummarizeAndContinue] Unexpected error:', err); + const detail = err instanceof Error ? err.message : String(err); notifyToast({ type: 'error', title: 'Compaction Failed', - message: 'An unexpected error occurred during compaction.', + message: detail + ? `An unexpected error occurred during compaction: ${detail}` + : 'An unexpected error occurred during compaction.', sessionId: sourceSessionId, tabId: targetTabId, }); diff --git a/src/renderer/services/contextSummarizer.ts b/src/renderer/services/contextSummarizer.ts index b77304ad03..9a64c0af2e 100644 --- a/src/renderer/services/contextSummarizer.ts +++ b/src/renderer/services/contextSummarizer.ts @@ -208,9 +208,14 @@ export class ContextSummarizationService { originalTokens, compactedTokens, }; - } catch { - // The groomContext API handles its own cleanup - rethrow - throw new Error('Context summarization failed'); + } catch (err) { + // Preserve the underlying error message so callers can surface it to + // the user. Wrapping with a generic string here used to swallow the + // real cause (e.g. "Agent X is not available", spawn ENAMETOOLONG) + // and the resulting "Compaction Failed" toast told users to "check + // the tab" — but no tab actually showed details. + if (err instanceof Error) throw err; + throw new Error(typeof err === 'string' ? err : 'Context summarization failed'); } }