feat(pkg-r): restore chat's displayed UI faithfully from bookmarks - #290
Open
cpsievert wants to merge 2 commits into
Open
feat(pkg-r): restore chat's displayed UI faithfully from bookmarks#290cpsievert wants to merge 2 commits into
cpsievert wants to merge 2 commits into
Conversation
2 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
This PR (stacked on #287) changes shinychat’s bookmarking/restore behavior so chat_restore() can reconstitute the exact UI that was displayed in the browser at bookmark time (for bookmarkStore = "server"), rather than re-deriving UI from LLM turns and potentially losing display-only transformations.
Changes:
- Capture and persist a browser-reported “displayed messages” snapshot into server bookmarks and replay it on restore (with versioned decode + fallback to turn-derived UI).
- Move response-triggered bookmarking from “stream ended” to “browser echoed a settled transcript ending in an assistant reply”.
- Exclude page-markup messages (
chat_ui(messages=)) from the reported snapshot to avoid duplication on restore; update tests/docs/dist accordingly.
Reviewed changes
Copilot reviewed 15 out of 23 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg-r/tests/testthat/test-chat_restore.R | Adds unit coverage for UI snapshot codec, restore fallback, and response-bookmark observer behavior. |
| pkg-r/R/client_state.R | Adds UI snapshot encode/decode + shared gzip/base64 codec; reuses codec for client_get_state() state. |
| pkg-r/R/chat_restore.R | Saves/restores UI snapshots for server bookmarks; changes response-bookmark trigger to _messages echo; adds submission guard. |
| pkg-r/R/chat.R | Updates docstring and removes stream-end bookmark chaining; clarifies history/bookmark interaction. |
| pkg-r/R/markdown-stream.R | Removes stream-end bookmark chaining from markdown_stream(). |
| pkg-r/NEWS.md | Release notes for UI-faithful restore and page-markup message handling. |
| pkg-r/NAMESPACE | Formatting-only import grouping changes. |
| pkg-r/man/chat_ui.Rd | Documents that chat_ui(messages=) markup isn’t persisted and can be cleared by history replay. |
| pkg-r/man/chat_restore.Rd | Documents server-snapshot restore behavior and fallbacks. |
| pkg-r/inst/lib/shiny/GIT_VERSION | Updates packaged JS asset version pointer. |
| pkg-py/src/shinychat/www/GIT_VERSION | Updates packaged JS asset version pointer for Python package. |
| pkg-r/DESCRIPTION | Updates roxygen2 config version. |
| js/src/chat/state.ts | Adds fromMarkup flag and excludes markup-parsed messages from reported snapshots. |
| js/src/chat/chat-entry.ts | Marks initial markup-parsed messages as fromMarkup. |
| js/tests/chat/state.test.ts | Tests that markup messages are excluded from buildMessagesSnapshot(). |
| js/tests/chat/chat-entry.test.ts | Tests that markup messages do not appear in the snapshot reported to Shiny. |
| js/tests/markdown/reservedElementsRendering.test.tsx | Tests that server-built “islands” render when content is correctly labeled as HTML. |
| js/dist/shinychat.js | Updated built bundle reflecting snapshot scope changes and other JS updates. |
Files not reviewed (2)
- pkg-r/man/chat_restore.Rd: Generated file
- pkg-r/man/chat_ui.Rd: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
cpsievert
force-pushed
the
feat/chat-restore-faithful-ui
branch
from
August 5, 2026 21:17
01f410a to
3ea2a44
Compare
cpsievert
added a commit
that referenced
this pull request
Aug 5, 2026
decode_ui_snapshot() already falls back to the turn-derived UI for a snapshot from the wrong format version, but a snapshot that decodes fine (right version, valid JSON) and still has a malformed message -- e.g. bit-level corruption that survives gzip/base64/serializeJSON round-tripping intact -- would previously reach restore_history_message() and error there, mid-replay. That's the wrong place to catch it: restore_history_message() sends each message to the client as it's called, so an error partway through can't be undone by falling back afterward -- the client would end up with the first N snapshot messages *and* the full turn-derived replay stacked on top. Validate every message before replaying any of them instead, so a bad snapshot routes to the fallback cleanly, same as a bad version. Caught by Copilot's review on #290.
cpsievert
force-pushed
the
feat/chat-restore-faithful-ui
branch
from
August 13, 2026 01:10
50f0fe9 to
9213dff
Compare
cpsievert
changed the base branch from
security/markdown-reserved-elements
to
main
August 13, 2026 01:10
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
chat_restore()previously re-derived displayed chat UI from the LLM client's turns on restore. Display-only transformations applied between receiving and rendering a message could therefore be lost.markdown_stream()completion bookmarking.chat_ui(messages = )are excluded from the snapshot because the page re-renders them on restore.Test plan
npm test(974 passed)Rscript -e 'devtools::test("pkg-r")'(887 passed; one browser-dependent test skipped because Chrome is unavailable)Known follow-up