@@ -236,16 +236,61 @@ chat_append <- function(id, response, role = c("assistant", "user"), session = g
236236# ' `msg` is the first chunk of a multi-chunk message. If `"end"`, then `msg`
237237# ' is the last chunk of a multi-chunk message. If `TRUE`, then `msg` is an
238238# ' intermediate chunk of a multi-chunk message. Default is `FALSE`.
239- # ' @param operation The operation to perform on the message. If `NULL`, then
240- # ' `msg` replaces the latest message. If `"append"`, then `msg` is appended
241- # ' to the latest message. Default is `NULL`.
239+ # ' @param operation The operation to perform on the message. If `"append"`,
240+ # ' then the new content is appended to the existing message content. If
241+ # ' `"replace"`, then the existing message content is replaced by the new
242+ # ' content. Ignored if `chunk` is `FALSE`.
242243# ' @param session The Shiny session object
243244# '
244245# ' @returns Returns nothing (\code{invisible(NULL)}).
245246# '
246247# ' @importFrom shiny getDefaultReactiveDomain
248+ # '
249+ # ' @examplesIf interactive()
250+ # ' library(shiny)
251+ # ' library(coro)
252+ # ' library(bslib)
253+ # ' library(shinychat)
254+ # '
255+ # ' # Dumbest chatbot in the world: ignores user input and chooses
256+ # ' # a random, vague response. For a chatbot, try {elmer}.
257+ # ' fake_chatbot <- async_generator(function(id, input) {
258+ # ' responses <- c(
259+ # ' "What does that suggest to you?",
260+ # ' "I see.",
261+ # ' "I'm not sure I understand you fully.",
262+ # ' "What do you think?",
263+ # ' "Can you elaborate on that?",
264+ # ' "Interesting question! Let's examine thi... **See more**"
265+ # ' )
266+ # '
267+ # ' # Use low-level chat_append_message() to temporarily set a progress message
268+ # ' chat_append_message(id, list(role = "assistant", content = "_Thinking..._ "))
269+ # ' await(async_sleep(1))
270+ # ' # Clear the progress message
271+ # ' chat_append_message(id, list(role = "assistant", content = ""), operation = "replace")
272+ # '
273+ # ' for (chunk in strsplit(sample(responses, 1), "")[[1]]) {
274+ # ' yield(chunk)
275+ # ' await(async_sleep(0.02))
276+ # ' }
277+ # ' })
278+ # '
279+ # ' ui <- page_fillable(
280+ # ' chat_ui("chat", fill = TRUE)
281+ # ' )
282+ # '
283+ # ' server <- function(input, output, session) {
284+ # ' observeEvent(input$chat_user_input, {
285+ # ' response <- fake_chatbot("chat", input$chat_user_input)
286+ # ' chat_append("chat", response)
287+ # ' })
288+ # ' }
289+ # '
290+ # ' shinyApp(ui, server)
291+ # '
247292# ' @export
248- chat_append_message <- function (id , msg , chunk = FALSE , operation = NULL , session = getDefaultReactiveDomain()) {
293+ chat_append_message <- function (id , msg , chunk = TRUE , operation = c( " append " , " replace " ) , session = getDefaultReactiveDomain()) {
249294 if (! is.list(msg )) {
250295 rlang :: abort(" msg must be a named list with 'role' and 'content' fields" )
251296 }
@@ -276,6 +321,11 @@ chat_append_message <- function(id, msg, chunk = FALSE, operation = NULL, sessio
276321 content_type <- " html"
277322 }
278323
324+ operation <- match.arg(operation )
325+ if (identical(operation , " replace" )) {
326+ operation <- NULL
327+ }
328+
279329 msg <- list (
280330 content = msg [[" content" ]],
281331 role = msg [[" role" ]],
0 commit comments