Skip to content

fix: persist chat responses to survive navigation#45

Merged
rogerchappel merged 2 commits into
mainfrom
fix/chat-response-lost-on-navigate
Apr 4, 2026
Merged

fix: persist chat responses to survive navigation#45
rogerchappel merged 2 commits into
mainfrom
fix/chat-response-lost-on-navigate

Conversation

@rogerchappel
Copy link
Copy Markdown
Owner

Summary

  • Fixes MC fix: tune iOS VAD thresholds to reduce keyboard noise sensitivity #401 (CRITICAL): Agent responses were lost when navigating away from chat during streaming
  • Streaming content is now tracked via refs and persisted to DB + localStorage on component unmount
  • Message loading on mount now merges all sources (gateway + DB + localStorage) instead of short-circuiting, ensuring persisted messages are never missed
  • Cancelled (Escape) responses are also persisted to DB

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 the while(true) reader loop was abandoned mid-flight.

What changed

Single file: src/app/chat/page.tsx

  1. Ref-based streaming trackingstreamingContentRef and streamingAgentRef mirror the streaming state so cleanup effects can read them
  2. Unmount persistence — A cleanup effect fires on unmount: if streaming was in progress, it persists the partial response (marked _(interrupted)_) to both DB and localStorage
  3. Merged message loading — On mount, messages are now loaded from all three sources (gateway, DB, localStorage), deduplicated by ID, and sorted by timestamp. Previously, gateway results caused DB to be skipped entirely
  4. Cancelled response persistence — Escape-cancelled responses now also persist to DB via persistMessage

Test plan

  • Start a chat with an agent, send a message that triggers a long response
  • While agent is streaming, navigate to /tasks
  • Navigate back to /chat — the partial response should appear with _(interrupted)_ suffix
  • Send a message, let it complete fully, navigate away and back — full response preserved
  • Press Escape during streaming — cancelled response persists across navigation
  • Verify typecheck passes (pnpm typecheck)

Closes MC #401

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

Copy link
Copy Markdown
Owner Author

@rogerchappel rogerchappel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 useEffect cleanup that calls persistMessage on 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>
@rogerchappel rogerchappel force-pushed the fix/chat-response-lost-on-navigate branch from fae472e to be04dcd Compare April 4, 2026 21:23
@rogerchappel rogerchappel merged commit c7d6bde into main Apr 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant