fix(chat): cross-tab isolation, stream/history consistency, and reasoning replay - #82
Merged
Merged
Conversation
… replay Fixes a batch of issues found in end-to-end functional testing: Multi-tab session integrity - Persist the chat tree with per-chat granularity merge instead of whole-tree overwrite; sync across tabs via the storage event - Make the current-chat pointer tab-private (sessionStorage first), so tabs no longer steal each other's restore target - Guard SSE run-following with Web Locks so only one tab follows a given background run (eliminates duplicated / cross-bleeding bubbles) - Restoring a session no longer mints a fresh chat id when the previous one is not yet known to the backend (duplicated tabs stay on the same conversation) Stream vs. history consistency - Record content_offset on each persisted tool call and rebuild history by interleaving text and tool cards in the original streaming order - Visible text preceding a <think> open tag is no longer dropped when rebuilding history segments Structured reasoning (reasoning_content channel) - Persist thinking deltas as interleaved <think> blocks so the thought process replays after a refresh - When the first model round produces no </think>, emit a structured- reasoning marker and reclassify provisionally-buffered body text back into the answer (fixes answers being trapped inside the thinking block for models with an empty reasoning channel) Other fixes - Edit-and-resend now stops the in-flight stream instead of silently ignoring the click; editing no longer force-scrolls to the bottom - Wheel-up during streaming immediately detaches follow-to-bottom - Persist per-answer duration (extra_data.duration_ms) so it survives refresh; unify the display unit - Share-page printing expands the inner scroll container so all pages print (previously only the first page) - Renaming with empty input keeps the original title; manual renames are flagged (title_manually_set) and never overwritten by the auto-summary; renames made mid-stream sync after the stream ends - Favorite-card previews and conversation search operate on the visible answer text only (thinking content excluded) - Attachments uploaded while a stream is running are no longer cleared when it finishes - Message loading retries with backoff instead of sticking on the skeleton after a transient failure - Knowledge-base document search now searches the whole library server-side (title/filename) and paginates the filtered result
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
This PR lands a batch of stability and correctness fixes for the chat experience, discovered during full end-to-end functional testing, plus first-class support for models that deliver reasoning through the structured
reasoning_contentchannel.Multi-tab session integrity
localStorageis now written with per-chat granularity merge (newestupdatedAtwins) instead of whole-tree overwrite, and tabs sync via thestorageevent. Two tabs chatting in parallel no longer clobber each other's conversations.sessionStoragefirst,localStorageas fallback for fresh tabs), so refreshing one tab can no longer hijack another tab's restore target.Stream vs. history consistency
content_offset(the length of the accumulated answer when the call was emitted). History rebuilds interleave text and tool cards in the original streaming order — a refreshed page now shows exactly what the live stream showed.<think>open tag is no longer dropped when rebuilding history segments.Structured reasoning channel
<think>…</think>blocks (same storage format as inline-thinking models), so the thought process replays after a refresh.</think>in its text, the backend emits a structured-reasoning protocol marker; the frontend then reclassifies provisionally-buffered text back into the answer body. This fixes answers being trapped inside the thinking block when a reasoning-capable model produces no reasoning for a trivial prompt.Other fixes
extra_data.duration_ms) and survives refresh; display unit unified.title_manually_setand are never overwritten by auto-summary; renames made mid-stream sync to the backend once the session exists.</think>fragments) is excluded from matches and snippets.Testing