import { describe, it, expect } from 'bun:test'; /** * Tests for SDKAgent resume parameter logic * * The resume parameter should ONLY be passed when: * 1. memorySessionId exists (was captured from a previous SDK response) * 2. lastPromptNumber > 1 (this is a continuation within the same SDK session) * * On worker restart or crash recovery, memorySessionId may exist from a previous * SDK session but we must NOT resume because the SDK context was lost. */ describe('SDKAgent Resume Parameter Logic', () => { /** * Helper function that mirrors the logic in SDKAgent.startSession() * This is the exact condition used at SDKAgent.ts line 99 */ function shouldPassResumeParameter(session: { memorySessionId: string | null; lastPromptNumber: number; }): boolean { const hasRealMemorySessionId = !!session.memorySessionId; return hasRealMemorySessionId && session.lastPromptNumber > 1; } describe('INIT prompt scenarios (lastPromptNumber === 1)', () => { it('should NOT pass resume parameter when lastPromptNumber === 1 even if memorySessionId exists', () => { // Scenario: Worker restart with stale memorySessionId from previous session const session = { memorySessionId: 'stale-session-id-from-previous-run', lastPromptNumber: 1, // INIT prompt }; const hasRealMemorySessionId = !!session.memorySessionId; const shouldResume = shouldPassResumeParameter(session); expect(hasRealMemorySessionId).toBe(true); // memorySessionId exists expect(shouldResume).toBe(false); // but should NOT resume because it's INIT }); it('should NOT pass resume parameter when memorySessionId is null and lastPromptNumber === 1', () => { // Scenario: Fresh session, first prompt ever const session = { memorySessionId: null, lastPromptNumber: 1, }; const hasRealMemorySessionId = !!session.memorySessionId; const shouldResume = shouldPassResumeParameter(session); expect(hasRealMemorySessionId).toBe(false); expect(shouldResume).toBe(false); }); }); describe('CONTINUATION prompt scenarios (lastPromptNumber > 1)', () => { it('should pass resume parameter when lastPromptNumber > 1 AND memorySessionId exists', () => { // Scenario: Normal continuation within same SDK session const session = { memorySessionId: 'valid-session-id', lastPromptNumber: 2, // CONTINUATION prompt }; const hasRealMemorySessionId = !!session.memorySessionId; const shouldResume = shouldPassResumeParameter(session); expect(hasRealMemorySessionId).toBe(true); expect(shouldResume).toBe(true); }); it('should pass resume parameter for higher prompt numbers', () => { // Scenario: Later in a multi-turn conversation const session = { memorySessionId: 'valid-session-id', lastPromptNumber: 5, // 5th prompt in session }; const shouldResume = shouldPassResumeParameter(session); expect(shouldResume).toBe(true); }); it('should NOT pass resume parameter when memorySessionId is null even for lastPromptNumber > 1', () => { // Scenario: Bug case - somehow got to prompt 2 without capturing memorySessionId // This shouldn't happen in practice but we should handle it safely const session = { memorySessionId: null, lastPromptNumber: 2, }; const hasRealMemorySessionId = !!session.memorySessionId; const shouldResume = shouldPassResumeParameter(session); expect(hasRealMemorySessionId).toBe(false); expect(shouldResume).toBe(false); }); }); describe('Edge cases', () => { it('should handle empty string memorySessionId as falsy', () => { // Empty string should be treated as "no session ID" const session = { memorySessionId: '' as unknown as null, lastPromptNumber: 2, }; const hasRealMemorySessionId = !!session.memorySessionId; const shouldResume = shouldPassResumeParameter(session); expect(hasRealMemorySessionId).toBe(false); expect(shouldResume).toBe(false); }); it('should handle undefined memorySessionId as falsy', () => { const session = { memorySessionId: undefined as unknown as null, lastPromptNumber: 2, }; const hasRealMemorySessionId = !!session.memorySessionId; const shouldResume = shouldPassResumeParameter(session); expect(hasRealMemorySessionId).toBe(false); expect(shouldResume).toBe(false); }); }); describe('Bug reproduction: stale session resume crash', () => { it('should NOT resume when worker restarts with stale memorySessionId', () => { // This is the exact bug scenario from the logs: // [17:30:21.773] Starting SDK query { // hasRealMemorySessionId=true, // resume_parameter=5439891b-..., // lastPromptNumber=1 ← NEW SDK session! // } // [17:30:24.450] Generator failed {error=Claude Code process exited with code 1} const session = { memorySessionId: '5439891b-7d4b-4ee3-8662-c000f66bc199', // Stale from previous session lastPromptNumber: 1, // But this is a NEW session after restart }; const shouldResume = shouldPassResumeParameter(session); // The fix: should NOT try to resume, should start fresh expect(shouldResume).toBe(false); }); it('should resume correctly for normal continuation (not after restart)', () => { // Normal case: same SDK session, continuing conversation const session = { memorySessionId: '5439891b-7d4b-4ee3-8662-c000f66bc199', lastPromptNumber: 2, // Second prompt in SAME session }; const shouldResume = shouldPassResumeParameter(session); // Should resume - same session, valid memorySessionId expect(shouldResume).toBe(true); }); }); });