Create a simple Shiny app for live chatting using an ellmer::Chat object.
Note that these functions will mutate the input client object as
you chat because your turns will be appended to the history.
The app created by chat_app() is suitable for interactive use by a single
user. For multi-user Shiny apps, use the Shiny module chat functions –
chat_mod_ui() and chat_mod_server() – and be sure to create a new chat
client for each user session.
Usage
chat_app(client, ..., bookmark_store = "url")
chat_mod_ui(id, ..., client = deprecated(), messages = NULL)
chat_mod_server(
id,
client,
greeting = NULL,
bookmark_on_input = TRUE,
bookmark_on_response = TRUE
)Arguments
- client
A chat object created by ellmer, e.g.
ellmer::chat_openai()and friends. This argument is deprecated inchat_mod_ui()because the client state is now managed bychat_mod_server().- ...
In
chat_app(), additional arguments are passed toshiny::shinyApp(). Inchat_mod_ui(), additional arguments are passed tochat_ui().- bookmark_store
The bookmarking store to use for the app. Passed to
enable_bookmarkinginshiny::shinyApp(). Defaults to"url", which uses the URL to store the chat state. URL-based bookmarking is limited in size; use"server"to store the state on the server side without size limitations; or disable bookmarking by setting this to"disable".- id
The chat module ID.
- messages
Initial messages shown in the chat, used only when
client(inchat_mod_ui()) doesn't already contain turns. Passed tomessagesinchat_ui().- greeting
Optional greeting to set when the module initializes. Accepts a static value (string,
htmltools::HTML(),htmltools::tagList(), orchat_greeting()) or a function that generates the greeting dynamically. See the Greeting section below for details.- bookmark_on_input
A logical value determines if the bookmark should be updated when the user submits a message. Default is
TRUE.- bookmark_on_response
A logical value determines if the bookmark should be updated when the response stream completes. Default is
TRUE.
Value
chat_app()returns ashiny::shinyApp()object.chat_mod_ui()returns the UI for a shinychat module.chat_mod_server()includes the shinychat module server logic, and returns an environment containing:last_input: A reactive value containing the last user input.last_turn: A reactive value containing the last assistant turn.update_user_input(): A function to update the chat input or submit a new user input. Takes the same arguments asupdate_chat_user_input(), except foridandsession, which are supplied automatically.append(): A function to append a new message to the chat UI. Takes the same arguments aschat_append(), except foridandsession, which are supplied automatically.clear(): A function to clear the chat history and the chat UI.clear()takes an optional list ofmessagesused to initialize the chat after clearing.messagesshould be a list of messages, where each message is a list withroleandcontentfields. Theclient_historyargument controls how the chat client's history is updated after clearing. It can be one of:"clear"the chat history;"set"the chat history tomessages;"append"messagesto the existing chat history; or"keep"the existing chat history.set_greeting(): A function to set, stream, or clear the chat greeting. Pass achat_greeting()object, a plain string, orNULLto clear. Streaming greetings run inside an shiny::ExtendedTask so the session stays responsive; if called while a greeting is already streaming, the new greeting is queued. If the greeting has already been dismissed, callingset_greeting()updates the content but does not make it visible again; callclear(greeting = TRUE)first to show a new greeting after dismissal.status: A reactive value indicating the current chat interaction state. Returns"idle"when no response is in progress, or"streaming"while a response is actively being received.client: The current chat client object (an active binding that always reflects the latest client, even afterset_client()is called).set_client(new_client, sync = TRUE): Replace the chat client used by the module. WhensyncisTRUE(the default), the new client inherits conversation turns, system prompt, and tools from the previous client so the conversation continues seamlessly. Setsync = FALSEto use the new client as-is. If a response is currently streaming, the swap is deferred until the stream completes. If called multiple times while streaming, only the most recent new client is used.
Functions
chat_app(): A simple Shiny app for live chatting. Note that this app is suitable for interactive use by a single user; do not usechat_app()in a multi-user Shiny app context.chat_mod_ui(): A simple chat app module UI.chat_mod_server(): A simple chat app module server.
Greeting
When greeting is a function, the module calls it each time the
greeting_requested event fires — on first view when the chat is empty,
and again after clear(greeting = TRUE). The function should return a
chat_greeting() (typically wrapping a stream). Static values (strings,
chat_greeting() objects) are set once at init and do not regenerate.
The module detects named arguments in the greeting function to decide
what to pass. Currently the only recognized argument is client.
function(client) (recommended). The module clones the client
passed to chat_mod_server(), wipes its turn history, and passes the
fresh clone as client. This avoids manually creating and configuring
a separate client:
chat_mod_server("chat", client, greeting = function(client) {
stream <- client$stream_async("Generate a short welcome message.")
chat_greeting(stream)
})function() (zero arguments). You create and manage your own client:
chat_mod_server("chat", client, greeting = function() {
greeter <- ellmer::chat_openai(model = "gpt-4o")
stream <- greeter$stream_async("Generate a short welcome message.")
chat_greeting(stream)
})Static value. Set once; does not regenerate after clear():
chat_mod_server("chat", client, greeting = "## Welcome!\n\nHow can I help?")The returned set_greeting() helper is available for cases where you need
to set a greeting outside the greeting lifecycle.
Examples
if (FALSE) { # \dontrun{
# Interactive in the console ----
client <- ellmer::chat_anthropic()
chat_app(client)
# Inside a Shiny app ----
library(shiny)
library(bslib)
library(shinychat)
ui <- page_fillable(
titlePanel("shinychat example"),
layout_columns(
card(
card_header("Chat with Claude"),
chat_mod_ui(
"claude",
messages = list(
"Hi! Use this chat interface to chat with Anthropic's `claude-3-5-sonnet`."
)
)
),
card(
card_header("Chat with ChatGPT"),
chat_mod_ui(
"openai",
messages = list(
"Hi! Use this chat interface to chat with OpenAI's `gpt-4o`."
)
)
)
)
)
server <- function(input, output, session) {
claude <- ellmer::chat_anthropic(model = "claude-3-5-sonnet-latest") # Requires ANTHROPIC_API_KEY
openai <- ellmer::chat_openai(model = "gpt-4o") # Requires OPENAI_API_KEY
chat_mod_server("claude", claude)
chat_mod_server("openai", openai)
}
shinyApp(ui, server)
} # }