-
Notifications
You must be signed in to change notification settings - Fork 23
Open
Description
When streaming long markdown content, the browser can freeze as markdown is re-parsed on every incoming chunk. This is especially noticeable when using LLMs with tool calls, where each tool result can add substantial content to the stream.
Reprex
library(shiny)
library(bslib)
library(shinychat)
library(coro)
# Simulate a long streaming response with "tool call" outputs
fake_stream <- async_generator(function(input) {
yield("I'll run several analyses for you.\n\n")
await(async_sleep(0.2))
for (i in 1:8) {
yield(sprintf("**Running tool %d: analyze_data**\n\n", i))
await(async_sleep(0.05))
# Large code block (simulates tool output)
code <- paste0("```r\n# Results for dataset ", i, "\n",
paste(sprintf("row_%02d <- c(%s)\n", 1:40,
sapply(1:40, function(x) paste(sample(1:99, 8), collapse = ", "))),
collapse = ""), "```\n\n")
for (chunk in strsplit(code, "(?<=.{50})", perl = TRUE)[[1]]) {
yield(chunk)
await(async_sleep(0.008))
}
# Markdown table
table <- paste0(
"| Metric | Value | SE | CI Low | CI High | p |\n",
"|--------|-------|-----|--------|---------|------|\n",
paste(sprintf("| %s | %.2f | %.2f | %.2f | %.2f | %.4f |\n",
c("Mean","Median","SD","Var","Skew","Kurt","Min","Max","Range","IQR"),
runif(10,0,100), runif(10,0,5), runif(10,-5,0),
runif(10,0,5), runif(10,0,0.1)), collapse = ""), "\n")
for (char in strsplit(table, "")[[1]]) {
yield(char)
await(async_sleep(0.003))
}
}
yield("All analyses complete!")
})
ui <- page_fillable(
p("Send any message to trigger a long streaming response."),
chat_ui("chat", fill = TRUE)
)
server <- function(input, output, session) {
observeEvent(input$chat_user_input, {
chat_append("chat", fake_stream(input$chat_user_input))
})
}
shinyApp(ui, server)The browser becomes increasingly unresponsive as the response grows, eventually freezing for several seconds. In extreme cases, it completely freezes that app.
Proposed solution
I have a local fix that implements incremental markdown rendering. It uses block-based rendering and throttling based on content size.
Would a PR be welcome? If so, should I only modify the .ts or should I also build and copy to both packages?
Abbreviated Session info
shiny 1.12.1.9000
bslib 0.9.0.9002
coro 1.1.0
shinychat 0.3.0.9000
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels