Skip to content

Feature request: bookmark and restore greeting in chat_restore() #262

Description

@gadenbuie

Feature request: bookmark and restore greeting in chat_restore()

Summary

chat_restore() currently saves and restores the ellmer client's turn history, but it has no support for the chat greeting. Apps that generate dynamic greetings (via chat_set_greeting() / the greeting_requested input) must implement their own persistence logic if they want the greeting to survive a bookmark restore.

Current behavior

chat_restore() serializes and restores the chat client's turns. The greeting — whether static (passed to chat_ui()) or dynamic (set via chat_set_greeting()) — is not part of that state. After a bookmark restore, the chat history is repopulated but the greeting area is empty. The greeting_requested input fires again, causing a dynamic greeting to be regenerated, which costs an extra LLM call and may produce a different greeting than the original.

Desired behavior

chat_restore() (or a companion API) should let apps save and restore the greeting text alongside the chat history, so that:

  1. A previously generated greeting is re-displayed verbatim on restore (no extra LLM call).
  2. Apps don't have to manage a parallel reactiveVal + onBookmark/onRestore pair just for the greeting.

Workaround

querychat currently works around this by manually storing the generated greeting in a current_greeting reactiveVal and re-applying it with chat_set_greeting() on restore — roughly:

current_greeting <- reactiveVal(NULL)

observeEvent(input$chat_greeting_requested, {
  stream <- greeting_client$stream_async(GREETING_PROMPT)
  chat_set_greeting(id, chat_greeting(stream, dismissible = FALSE))
  # ... capture the streamed text into current_greeting for later bookmark persistence
})

session$onBookmark(function(state) {
  state$values$greeting <- current_greeting()
})

session$onRestore(function(state) {
  greeting <- state$values$greeting
  if (!is.null(greeting)) {
    chat_set_greeting(id, chat_greeting(greeting, dismissible = FALSE))
    current_greeting(greeting)
  }
})

This is a reasonable amount of boilerplate, but it would be cleaner if chat_restore() handled it automatically — perhaps via a greeting reactive argument analogous to the client argument.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority: MediumValid bug or well-defined request with moderate impact or a workaround.ai-triage:doneMarks an issue whose AI triage workflow is complete.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions