Fix blank-session restarts after interrupt or failed run - #1192
Fix blank-session restarts after interrupt or failed run#1192bunnysayzz wants to merge 1 commit into
Conversation
Fixes CodebuffAI#1054. Esc-aborting a session and sending a follow-up could start a brand new, blank conversation because the continuation state (previousRunStateRef) was only synced when run() settled, while the abort listener released the input lock immediately. - SetupStreamingContext gains an onAbort callback invoked synchronously at the top of the abort listener, before the lock is released, so the run owner can checkpoint its latest SDK snapshot. - useSendMessage passes syncRunState(latestRunStateSnapshot) as onAbort, and syncRunState now guards with a generation token so a superseded run settling late can never adopt state, persist a checkpoint, or touch shared queue state over the run that replaced it. - The catch path (failed/expired runs) now also syncs the ref, not just disk, so the next prompt resumes from the last snapshot instead of stale or null history. - loadMostRecentChatState stops adopting/persisting sessionState-less run states, which made the SDK build a blank session on restart. Adds hook-level regression tests through the real createRunConfig / client.run wiring: abort then follow-up carries full history, late superseded runs cannot clobber, the rejected-run path resumes from the last snapshot, and sessionState-less states are never adopted. Helper and storage suites updated.
|
Note for comparison with #1181: our tests already use the DI seam ( |
|
@codebuff-team This is the re-open of #1135 (auto-closed by the force-push history rewrite). You had reviewed it positively on Aug 29, calling it "exactly the kind of bug fix I'd want ported" and asking to audit Quick note comparing with #1181: this PR's test suite already uses the DI seam ( Branch is rebased on the latest main. Ready for another look whenever you get a chance. |
|
Good bug report and a plausible root cause: the abort listener released the input lock before Strengths:
Concerns for the maintainer's review pass, not blockers:
Overall this reads as a genuine fix worth porting, with tests that would catch a regression if the abort ordering broke again. |
Summary
Re-opens #1135 (auto-closed by force-push history rewrite).
Fixes #1054 (chat restarts blank after Esc interrupt / failed run).
Root cause:
previousRunStateRefwas only synced whenclient.run()settled, but Esc releases the input lock inside the abort listener, so a follow-up message could be built from stale/null ref, causing the SDK to start a blank session.Fix
onAbortcheckpoint invoked before input lock release (so the latest SDK state is saved before a follow-up can run)runGenerationRef/runIsCurrent) prevents a superseded run from clobbering newer stateloadMostRecentChatStaterefuses sessionState-less run states (disk poison)Tests
Hook-level regression tests through the real
createRunConfig/client.runwiring via DI seam (setClientFactoryOverrideForTesting). 92 tests green, typecheck/prettier/build clean.Review response
Codebuff-team asked to audit
loadMostRecentChatStatecallers for non-null assumptions. Audit: exactly 1 production caller (use-send-message.ts:177), already guarded byif (loadedState), ref typedRunState | null. Safe. Full details in review comment on #1135.Supersedes #1135 (closed by force-push).