diff --git a/CHANGELOG.md b/CHANGELOG.md index 111251c28..085acac65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * To enable bookmarking in Express mode, set `shiny.express.app_opts(bookmark_store=)` during the app's initial construction. * To enable bookmarking in Core mode, set `shiny.App(bookmark_store=)` when constructing the `app` object. -* Added a new `.enable_bookmarking(client)` method to `ui.Chat()`. This method will attach bookmark hooks to save and restore the chat's messages and client state. (#1951) +* Added a new `.enable_bookmarking(client)` method to `ui.Chat()`. This method will attach bookmark hooks to save and restore the chat's messages and client state. (#1951, #1954) * Both `ui.Chat()` and `ui.MarkdownStream()` now support the inclusion of Shiny UI elements inside of messages. This allows for gathering input from the user (e.g., `ui.input_select()`), displaying of rich output (e.g., `render.DataGrid()`), and more. (#1868) diff --git a/shiny/ui/_chat_bookmark.py b/shiny/ui/_chat_bookmark.py index 07cb5bca3..ffad560fd 100644 --- a/shiny/ui/_chat_bookmark.py +++ b/shiny/ui/_chat_bookmark.py @@ -72,7 +72,10 @@ def get_chatlas_state( async def get_state() -> Jsonifiable: turns: list[Turn[Any]] = client.get_turns() - return [turn.model_dump(mode="json") for turn in turns] + return { + "version": 1, + "turns": [turn.model_dump(mode="json") for turn in turns], + } return get_state @@ -84,12 +87,26 @@ def set_chatlas_state( assert isinstance(client, Chat) + # TODO-future: Use pydantic model for validation + # instead of manual validation async def set_state(value: Jsonifiable) -> None: - if not isinstance(value, list): - raise ValueError("Chatlas bookmark value was not a list of objects") + if not isinstance(value, dict): + raise ValueError("Chatlas bookmark value was not a dictionary") - turns: list[Turn[Any]] = [Turn.model_validate(turn_obj) for turn_obj in value] + version = value.get("version") + if version != 1: + raise ValueError(f"Unsupported Chatlas bookmark version: {version}") + turns_arr = value.get("turns") + + if not isinstance(turns_arr, list): + raise ValueError( + "Chatlas bookmark value was not a list of chat message information" + ) + + turns: list[Turn[Any]] = [ + Turn.model_validate(turn_obj) for turn_obj in turns_arr + ] client.set_turns(turns) # pyright: ignore[reportUnknownMemberType] return set_state