% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/stream-controller.R
\name{stream_controller}
\alias{stream_controller}
\title{Create a stream controller}
\usage{
stream_controller()
}
\value{
An \code{ellmer_stream_controller} object with the following
elements:
\itemize{
\item \verb{$cancel(reason = "cancelled")}: Cancel the stream. The \code{reason}
string is stored on the controller and used as the
\link[=Turn]{AssistantPartialTurn}'s \code{reason} property.
\item \verb{$reset()}: Clear the cancelled state and reason.
\item \verb{$cancelled}: A logical flag indicating whether the controller
has been cancelled.
\item \verb{$reason}: The cancellation reason string, or \code{NULL} if not
cancelled.
}
}
\description{
Creates a controller that can cancel an in-progress stream. Pass it to
\link{Chat}'s \verb{$stream()} or \verb{$stream_async()} via the \code{controller} argument,
then call \verb{$cancel()} from anywhere (e.g. a Shiny observer) to stop the
stream after the next chunk arrives.

The same controller can be reused across multiple streams. Call
\verb{$reset()} to clear the cancelled state, or pass it directly to a new
\verb{$stream()} call — it will be reset automatically.
}
\section{Async cancellation in Shiny}{


In a Shiny app, use an \link[shiny:ExtendedTask]{ExtendedTask} for
non-blocking chat and a \code{stream_controller()} to wire up a cancel
button:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{controller <- stream_controller()

chat_task <- ExtendedTask$new(function(user_query, controller = NULL) \{
  chat <- chat_openai(model = "gpt-4.1-nano")
  stream <- chat$stream_async(user_query, controller = controller)
  shinychat::markdown_stream("response", stream)
\})

observeEvent(input$ask, \{
  controller <<- stream_controller()
  chat_task$invoke(input$query, controller = controller)
\})

observeEvent(input$cancel, \{
  controller$cancel()
\})
}\if{html}{\out{</div>}}
}

\examples{
\dontshow{if (rlang::is_interactive()) withAutoprint(\{ # examplesIf}
chat <- chat_openai(model = "gpt-5.4-nano")

ctrl <- stream_controller()
stream <- chat$stream("Write a short story.", controller = ctrl)

i <- 0
coro::loop(for (chunk in stream) {
  i <- i + 1
  if (i > 10) ctrl$cancel()
})

chat
\dontshow{\}) # examplesIf}
}
