Nothing
#' @title Stream Renderer: Enhanced CLI output
#' @description
#' Internal utilities for rendering streaming output and tool execution
#' status in the R console using the cli package.
#' @name stream_renderer
#' @keywords internal
NULL
#' @title Create a Stream Renderer (cli / terminal backend)
#' @description
#' The built-in terminal backend for the agent-output [Renderer] contract,
#' rendering a streaming response (thinking indicators, streamed text, and tool
#' execution status) to the R console via the cli package. It conforms to the
#' [Renderer] interface (`process_chunk`, `start_thinking`, `stop_thinking`,
#' `render_tool_start`, `render_tool_result`, `reset_for_new_step`), so it can be
#' swapped for any other backend (web, capture, custom UI) via the `renderer`
#' argument of [stream_text()].
#' @seealso [Renderer], [create_null_renderer()], [create_capture_renderer()]
#' @return A list of functions implementing the [Renderer] contract.
#' @keywords internal
create_stream_renderer <- function() {
state <- new.env(parent = emptyenv())
state$first_chunk <- TRUE
state$is_thinking <- FALSE
state$current_tool <- NULL
has_cli <- requireNamespace("cli", quietly = TRUE)
# Create the markdown rendering stream processor
mk_renderer <- create_markdown_stream_renderer()
# Helper to clear a line (simple version)
clear_line <- function() {
cat("\r", paste(rep(" ", getOption("width", 80)), collapse = ""), "\r", sep = "")
}
# Reset state for new generation step (used in multi-step agent loops)
reset_for_new_step <- function() {
state$first_chunk <- TRUE
state$is_thinking <- FALSE
state$current_tool <- NULL
# Reset the markdown renderer state
mk_renderer$reset()
}
# Check if thinking indicator should be shown
show_thinking <- should_show_thinking()
# 1. Thinking Indicator
start_thinking <- function() {
if (!interactive() || state$is_thinking || !show_thinking) return()
state$is_thinking <- TRUE
if (has_cli) {
cat(cli::col_grey(cli::symbol$ellipsis, " Thinking..."))
} else {
cat("... Thinking")
}
utils::flush.console()
}
stop_thinking <- function() {
if (!state$is_thinking || !show_thinking) return()
# Clear the thinking line
cat("\r", paste(rep(" ", 20), collapse = ""), "\r", sep = "")
state$is_thinking <- FALSE
utils::flush.console()
}
# 2. Text Streaming
process_chunk <- function(text, done) {
if (state$is_thinking) {
stop_thinking()
}
if (!is.null(text) && nzchar(text)) {
if (state$first_chunk) {
state$first_chunk <- FALSE
}
# Delegate to markdown renderer
mk_renderer$process_chunk(text, done = FALSE)
utils::flush.console()
}
if (isTRUE(done)) {
mk_renderer$process_chunk(NULL, done = TRUE)
return()
}
invisible(NULL)
}
# 3. Tool Execution
render_tool_start <- function(name, arguments) {
stop_thinking()
state$current_tool <- name
cli_tool_start(name, arguments)
utils::flush.console()
}
render_tool_result <- function(name, result, success = TRUE, raw_result = result) {
state$current_tool <- NULL
cli_tool_result(name, result, success, raw_result = raw_result)
utils::flush.console()
}
list(
start_thinking = start_thinking,
stop_thinking = stop_thinking,
process_chunk = process_chunk,
render_tool_start = render_tool_start,
render_tool_result = render_tool_result,
reset_for_new_step = reset_for_new_step
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.