Skip to contents

Format ellmer content for shinychat

Usage

contents_shinychat(content)

Arguments

content

An ellmer::Content object.

Value

Returns text, HTML, or web component tags formatted for use in chat_ui().

Extending contents_shinychat()

You can extend contents_shinychat() to handle custom content types in your application. contents_shinychat() is an S7 generic. If you haven't worked with S7 before, you can learn more about S7 classes, generics and methods in the S7 documentation.

For most tool-result customization, use tool_result_display() in the result's extra = list(display = ...). It keeps shinychat's compact activity row and drill-down card while letting you set a title, label, result preview, and rich card content. The Tool Calling UI article describes that recommended path.

We'll work through a short example creating a custom display for the results of a tool that gets local weather forecasts. We first need to create a custom class that extends ellmer::ContentToolResult.

library(ellmer)

WeatherToolResult <- S7::new_class(
  "WeatherToolResult",
  parent = ContentToolResult,
  properties = list(
    location_name = S7::class_character
  )
)

Next, we'll create a simple ellmer::tool() that gets the weather forecast for a location and returns our custom WeatherToolResult class. The custom class works just like a regular ContentToolResult, but it has an additional location_name property.

get_weather_forecast <- tool(
  function(lat, lon, location_name) {
    WeatherToolResult(
      weathR::point_tomorrow(lat, lon, short = FALSE),
      location_name = location_name
    )
  },
  name = "get_weather_forecast",
  description = "Get the weather forecast for a location.",
  arguments = list(
    lat = type_number("Latitude"),
    lon = type_number("Longitude"),
    location_name = type_string("Name of the location for display to the user")
  )
)

Finally, define the external generic and implement a method for your custom class:

contents_shinychat <- S7::new_external_generic(
  package = "shinychat",
  name = "contents_shinychat",
  dispatch_args = "contents"
)

S7::method(contents_shinychat, WeatherToolResult) <- function(content) {
  # Your custom rendering logic here
}

Use S7::super() when you want to extend shinychat's default card. The resulting output still participates in the normal compact activity row and drill-down card:

S7::method(contents_shinychat, WeatherToolResult) <- function(content) {
  # Call the super method for ContentToolResult to get shinychat's defaults
  res <- contents_shinychat(S7::super(content, ContentToolResult))

  # Then update the result object with more specific content
  # In this case, we render the tool result dataframe as a {gt} table...
  res$value <- gt::as_raw_html(gt::gt(content@value))
  res$value_type <- "html"
  # ...and update the tool result title to include the location name
  res$title <- paste("Got weather forecast for", content@location_name)
  res$label <- content@location_name
  res$value_preview <- paste(nrow(content@value), "hourly readings")

  res
}

Alternatively, return arbitrary HTML or Shiny UI directly from the method to replace the default card completely. While the tool runs, shinychat still shows its activity row. When the custom result settles, shinychat renders that UI as standalone output and removes the call from the activity row.

This extension point is for fully custom standalone output. To customize the default card, use tool_result_display() instead of constructing a generic display list yourself.