fix: persist chat responses to survive navigation#45
Merged
Conversation
rogerchappel
commented
Apr 4, 2026
Owner
Author
rogerchappel
left a comment
There was a problem hiding this comment.
Sentinel — LGTM ✓
Solid approach: refs track in-flight streaming content, and the cleanup effect persists partial responses on unmount (navigation away). The three-way merge (gateway + DB + localStorage) with dedup is a good improvement over the previous cascade fallback.
Minor observations:
- The
_(interrupted)_and_(cancelled)_suffixes are a nice UX touch — makes it clear the response was incomplete. - The
useEffectcleanup that callspersistMessageon unmount fires a network request during teardown. If the component remounts quickly (React strict mode in dev), you could get duplicate persists. In practice this is deduplicated by the merge logic, so not a real issue, just worth knowing. - The empty
catch {}block in the cleanup localStorage write is fine — best-effort is correct there.
No blocking issues.
When navigating away from chat while an agent is streaming a response, the response was lost because it only lived in React component state. Changes: - Track streaming content in refs (survives across renders, readable in cleanup) - On unmount, persist any in-flight streaming content to DB and localStorage - Always merge messages from all sources (gateway + DB + localStorage) on mount instead of short-circuiting after gateway, ensuring DB-persisted messages are never missed - Persist cancelled (Escape) responses to DB (previously only added to state) Closes MC #401 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fae472e to
be04dcd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Root cause
Streaming responses lived only in React component state (
streamingContent). Navigating away unmounted the component, and the post-stream persistence code (persistMessage) never ran because thewhile(true)reader loop was abandoned mid-flight.What changed
Single file:
src/app/chat/page.tsxstreamingContentRefandstreamingAgentRefmirror the streaming state so cleanup effects can read them_(interrupted)_) to both DB and localStoragepersistMessageTest plan
/tasks/chat— the partial response should appear with_(interrupted)_suffixpnpm typecheck)Closes MC #401
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com