Chat

Chat(
    id,
    *,
    client=None,
    history=True,
    greeting=None,
    messages=(),
    on_error='auto',
    tokenizer=DEPRECATED,
)

Create a chat interface.

A UI component for building conversational interfaces. With it, end users can submit messages, which will cause a .on_user_submit() callback to run. That callback gets passed the user input message, which can be used to generate a response. The response can then be appended to the chat using .append_message() or .append_message_stream().

Here’s a rough outline for how to implement a Chat:

from shiny.express import ui

# Create and display chat instance
chat = ui.Chat(id="my_chat")
chat.ui()


# Define a callback to run when the user submits a message
@chat.on_user_submit
async def handle_user_input(user_input: str):
    # Create a response message stream
    response = await my_model.generate_response(user_input, stream=True)
    # Append the response into the chat
    await chat.append_message_stream(response)

In the outline above, my_model.generate_response() is a placeholder for the function that generates a response based on the chat’s messages. This function will look different depending on the model you’re using, but it will generally involve passing the messages to the model and getting a response back. Also, you’ll typically have a choice to stream=True the response generation, and in that case, you’ll use .append_message_stream() instead of .append_message() to append the response to the chat. Streaming is preferrable when available since it allows for more responsive and scalable chat interfaces.

It is also highly recommended to use a package like chatlas to generate responses, especially when responses should be aware of the chat history, support tool calls, etc. See this article to learn more.

Thinking display

When a model produces reasoning or “thinking” tokens, shinychat renders them in a collapsible panel above the response. The panel streams the model’s reasoning in real time, then auto-collapses when the response begins.

Two paths are supported:

  1. chatlas ContentThinking objects. Models with a structured thinking API (e.g., Claude with extended thinking) emit ContentThinking objects during streaming. shinychat detects these and routes them to the thinking panel automatically.

  2. Raw <thinking> tags. Many open-source and local models (DeepSeek, QwQ, Qwen, etc.) emit <thinking>...</thinking> tags in their markdown output. shinychat detects these tags during streaming and renders the enclosed text in the thinking panel with no extra configuration.

Topic labels: You can get labeled sub-sections within the thinking panel by asking the model to emit <topic>...</topic> tags in its reasoning. These show up as section headings inside the panel, and the current topic appears in the collapsed header as a live status indicator.

To use topic labels, add something like this to your system prompt::

When thinking through a problem, wrap brief topic labels in <topic> tags
to indicate what you're currently reasoning about. For example:
<topic>parsing the input</topic>

Topic labels are optional. Without them, the thinking panel still works – it just won’t have sub-section headings.

Parameters

Name Type Description Default
id str A unique identifier for the chat session. In Shiny Core, make sure this id matches a corresponding :func:~shiny.ui.chat_ui call in the UI. required
client 'chatlas.Chat[Any, Any] | None' A chatlas client (e.g., chatlas.ChatOpenAI()). When provided, streaming, cancellation, and conversation history are wired up automatically. This includes registering an :meth:~shinychat.Chat.on_user_submit callback that streams the client’s response to each user message, so you don’t need to write one yourself. Any additional @chat.on_user_submit handlers you register still run, in addition to (not in place of) this one. The resulting :attr:chat.client exposes a :class:~shinychat.types.ChatClient wrapper for swapping models (.set()) and resetting the conversation (.clear()). None
history 'bool | HistoryOptions' Conversation history configuration. True (the default) enables history with default settings; False disables it; pass a :class:~shinychat.types.HistoryOptions instance to customise restore behaviour, storage, user identity, or titling. Only takes effect when a client= is also provided. True
greeting 'str | HTML | Tag | TagList | ChatGreeting | Callable[…, Any] | None' Content to display as a welcome message before any conversation. Can be a string, :class:~htmltools.HTML, :class:~htmltools.Tag, :class:~htmltools.TagList, :class:~shinychat.chat_greeting, or a callable that returns one of those types. A callable greeting is invoked when the chat is visible and empty; if the callable accepts a client parameter (and client= was provided), a deep-copy of the chatlas client with empty turns is passed so the greeting can be LLM-generated without polluting conversation history. None
messages Sequence[Any] Deprecated. Use chat.ui(messages=...) instead. ()
on_error Literal['auto', 'actual', 'sanitize', 'unhandled'] How to handle errors that occur in response to user input. When "unhandled", the app will stop running when an error occurs. Otherwise, a notification is displayed to the user and the app continues to run. * "auto": Sanitize the error message if the app is set to sanitize errors, otherwise display the actual error message. * "actual": Display the actual error message to the user. * "sanitize": Sanitize the error message before displaying it to the user. * "unhandled": Do not display any error message to the user. 'auto'
tokenizer DEPRECATED_TYPE Removed. Raises TypeError if provided. Use your LLM provider (e.g., chatlas, LangChain) to manage token limits instead. DEPRECATED

Attributes

Name Description
latest_message_stream React to changes in the latest message stream.

Methods

Name Description
append_message Append a message to the chat.
append_message_stream Append a message as a stream of message chunks.
clear_messages Clear all chat messages.
destroy Destroy the chat instance.
enable_bookmarking Enable bookmarking for the chat instance.
get_greeting Get the current greeting content.
message_stream_context Message stream context manager.
messages Reactively read chat messages
on_user_submit Define a function to invoke when user input is submitted.
remove_slash_command Remove a previously registered slash command by name.
set_greeting Set or clear the chat greeting.
set_user_message Deprecated. Use update_user_input(value=value) instead.
slash_command Register a slash command and its handler.
transform_assistant_response Deprecated. Assistant response transformation features will be removed in a future version.
update_user_input Update the user input.
user_input Reactively read the user’s latest submission.

append_message

Chat.append_message(message, *, icon=None)
    Append a message to the chat.

Parameters

    message
        A given message can be one of the following:

        * A string, which is interpreted as markdown and rendered to HTML on the
          client.
            * To prevent interpreting as markdown, mark the string as
              :class:`~shiny.ui.HTML`.
        * A UI element (specifically, a :class:`~shiny.ui.TagChild`).
            * This includes :class:`~shiny.ui.TagList`, which take UI elements
              (including strings) as children. In this case, strings are still
              interpreted as markdown as long as they're not inside HTML.
        * A dictionary with `content` and `role` keys. The `content` key can contain
          content as described above, and the `role` key can be "assistant" or
          "user".
        * More generally, any type registered with :func:`shinychat.message_content`.

        **NOTE:** content may include specially formatted **input suggestion** links
        (see note below).
    icon
        An optional icon to display next to the message, currently only used for
        assistant messages. The icon can be any HTML element (e.g., an
        :func:`~shiny.ui.img` tag) or a string of HTML. Pass ``False`` to remove
        the icon for this message, or ``True`` to use the default icon.

Note

    :::{.callout-note title="Input suggestions"}
    Input suggestions are special links that send text to the user input box when
    clicked (or accessed via keyboard). They can be created in the following ways:

    * `<span class='suggestion'>Suggestion text</span>`: An inline text link that
        places 'Suggestion text' in the user input box when clicked.
    * `<img data-suggestion='Suggestion text' src='image.jpg'>`: An image link with
        the same functionality as above.
    * `<span data-suggestion='Suggestion text'>Actual text</span>`: An inline text
        link that places 'Suggestion text' in the user input box when clicked.

    A suggestion can also be submitted automatically by doing one of the following:

    * Adding a `submit` CSS class or a `data-suggestion-submit="true"` attribute to
      the suggestion element.
    * Holding the `Ctrl/Cmd` key while clicking the suggestion link.

    Note that a user may also opt-out of submitting a suggestion by holding the
    `Alt/Option` key while clicking the suggestion link.

    A markdown list (`<ul>` or `<ol>`) in which every item contains a single
    suggestion element is automatically rendered as a grid of clickable cards instead
    of inline chips. Each suggestion accepts an optional `title` attribute (plain
    text), which becomes the card heading; the suggestion's body becomes the card
    description. For ordered lists (`<ol>`), the list-item number is included in the
    heading.
    :::

    :::{.callout-note title="Asides"}
    An aside is a small pill that appears at the end of the paragraph or
    list item it's attached to, showing a popover on hover, click, or
    keyboard focus. Create one by writing (or prompting an LLM to write) an
    inline `<shiny-aside>` tag anywhere in a block's markdown; the tag's
    content becomes the popover body:

    * `<shiny-aside label="a source name" url="https://...">markdown shown in the popover</shiny-aside>`

    `label` controls the text on the identity chip. A safe `url` makes the
    source heading in the popover a link. It also supplies a derived favicon
    unless `icon` overrides it. Without a `label`, the aside falls back to
    a plain numbered marker. The body is ordinary markdown: inline for a
    one-liner, or — by separating it with blank lines — a rich block body
    (paragraphs, lists, code) shown in the popover. Labeled asides in the
    same paragraph or list item collapse into one pill, with each aside kept
    as a separate popover page. Each unlabeled aside remains a separate
    numbered pill. The grouped pill shows a `+N` overflow count only when
    its labeled asides have different labels. Asides that share one label
    use a single face with no count.

    `grounded-span` identifies the answer text that is related to an aside.
    Its value must exactly match text before the tag in the same paragraph
    or list item. When the popover opens, shinychat highlights the most
    recent match. If the value does not match, no text is highlighted.

    Long content wraps and scrolls within the viewport. The popover keeps
    the nearest scoped Bootstrap theme. In a paged popover, page changes
    are announced to assistive technology without repeating the body.

    The favicon is fetched at render time from a third-party service
    (DuckDuckGo's icon service), which receives the cited site's hostname.
    To avoid that request — for privacy, or for offline/air-gapped
    deployments — set the ``SHINYCHAT_ASIDE_FAVICON`` environment variable
    to ``false``. You can still set `icon` to a URL you control; an
    explicit `icon` bypasses the lookup entirely.

    **Examples:**

    * A labeled aside with a grounded span and a one-line body:
      `Hub motors are cheaper<shiny-aside label="eBicycles" url="https://ebicycles.example/hub-vs-mid-drive" grounded-span="Hub motors are cheaper">[Hub Motor vs. Mid-Drive Motor Differences Explained](https://ebicycles.example/hub-vs-mid-drive)</shiny-aside>, and ideal for flatter terrain.`
    * Two asides cited in the same sentence collapse into a single pill
      — the first source's label becomes the face, with a "+1" overflow:
      `...<shiny-aside label="eBicycles" url="https://ebicycles.example">...</shiny-aside><shiny-aside label="WIRED" url="https://wired.example">...</shiny-aside>...`
    * A label-less aside with a rich block body (a blank line starts a
      block body instead of an inline one), falling back to a plain
      numbered pill:
      `Battery quality matters more than raw power<shiny-aside>

Methodology

  • 40 commuter e-bike models
  • released in 2024

` :::

    :::{.callout-note title="Streamed messages"}
    Use `.append_message_stream()` instead of this method when `stream=True` (or
    similar) is specified in model's completion method.
    :::

append_message_stream

Chat.append_message_stream(message, *, icon=None)
    Append a message as a stream of message chunks.

Parameters

    message
        An (async) iterable of message chunks. Each chunk can be one of the
        following:

        * A string, which is interpreted as markdown and rendered to HTML on the
          client.
            * To prevent interpreting as markdown, mark the string as
              :class:`~shiny.ui.HTML`.
        * A UI element (specifically, a :class:`~shiny.ui.TagChild`).
            * This includes :class:`~shiny.ui.TagList`, which take UI elements
              (including strings) as children. In this case, strings are still
              interpreted as markdown as long as they're not inside HTML.
        * A dictionary with `content` and `role` keys. The `content` key can contain
          content as described above, and the `role` key can be "assistant" or
          "user".
        * More generally, any type registered with :func:`shinychat.message_content_chunk`.

        **NOTE:** content may include specially formatted **input suggestion** links
        (see note below).
    icon
        An optional icon to display next to the message, currently only used for
        assistant messages. The icon can be any HTML element (e.g., an
        :func:`~shiny.ui.img` tag) or a string of HTML. Pass ``False`` to remove
        the icon for this message, or ``True`` to use the default icon.

Note

    ```{.callout-note title="Input suggestions"}
    Input suggestions are special links that send text to the user input box when
    clicked (or accessed via keyboard). They can be created in the following ways:

    * `<span class='suggestion'>Suggestion text</span>`: An inline text link that
        places 'Suggestion text' in the user input box when clicked.
    * `<img data-suggestion='Suggestion text' src='image.jpg'>`: An image link with
        the same functionality as above.
    * `<span data-suggestion='Suggestion text'>Actual text</span>`: An inline text
        link that places 'Suggestion text' in the user input box when clicked.

    A suggestion can also be submitted automatically by doing one of the following:

    * Adding a `submit` CSS class or a `data-suggestion-submit="true"` attribute to
      the suggestion element.
    * Holding the `Ctrl/Cmd` key while clicking the suggestion link.

    Note that a user may also opt-out of submitting a suggestion by holding the
    `Alt/Option` key while clicking the suggestion link.

    A markdown list (`<ul>` or `<ol>`) in which every item contains a single
    suggestion element is automatically rendered as a grid of clickable cards instead
    of inline chips. Each suggestion accepts an optional `title` attribute (plain
    text), which becomes the card heading; the suggestion's body becomes the card
    description. For ordered lists (`<ol>`), the list-item number is included in the
    heading.
    ```

    ```{.callout-note title="Asides"}
    An aside is a small pill that appears at the end of the paragraph or
    list item it's attached to, showing a popover on hover, click, or
    keyboard focus. Create one by writing (or prompting an LLM to write) an
    inline `<shiny-aside>` tag anywhere in a block's markdown; the tag's
    content becomes the popover body:

    * `<shiny-aside label="a source name" url="https://...">markdown shown in the popover</shiny-aside>`

    `label` controls the text on the identity chip. A safe `url` makes the
    source heading in the popover a link. It also supplies a derived favicon
    unless `icon` overrides it. Without a `label`, the aside falls back to
    a plain numbered marker. The body is ordinary markdown: inline for a
    one-liner, or — by separating it with blank lines — a rich block body
    (paragraphs, lists, code) shown in the popover. Labeled asides in the
    same paragraph or list item collapse into one pill, with each aside kept
    as a separate popover page. Each unlabeled aside remains a separate
    numbered pill. The grouped pill shows a `+N` overflow count only when
    its labeled asides have different labels. Asides that share one label
    use a single face with no count.

    `grounded-span` identifies the answer text that is related to an aside.
    Its value must exactly match text before the tag in the same paragraph
    or list item. When the popover opens, shinychat highlights the most
    recent match. If the value does not match, no text is highlighted.

    Long content wraps and scrolls within the viewport. The popover keeps
    the nearest scoped Bootstrap theme. In a paged popover, page changes
    are announced to assistive technology without repeating the body.

    The favicon is fetched at render time from a third-party service
    (DuckDuckGo's icon service), which receives the cited site's hostname.
    To avoid that request — for privacy, or for offline/air-gapped
    deployments — set the ``SHINYCHAT_ASIDE_FAVICON`` environment variable
    to ``false``. You can still set `icon` to a URL you control; an
    explicit `icon` bypasses the lookup entirely.

    **Examples:**

    * A labeled aside with a grounded span and a one-line body:
      `Hub motors are cheaper<shiny-aside label="eBicycles" url="https://ebicycles.example/hub-vs-mid-drive" grounded-span="Hub motors are cheaper">[Hub Motor vs. Mid-Drive Motor Differences Explained](https://ebicycles.example/hub-vs-mid-drive)</shiny-aside>, and ideal for flatter terrain.`
    * Two asides cited in the same sentence collapse into a single pill
      — the first source's label becomes the face, with a "+1" overflow:
      `...<shiny-aside label="eBicycles" url="https://ebicycles.example">...</shiny-aside><shiny-aside label="WIRED" url="https://wired.example">...</shiny-aside>...`
    * A label-less aside with a rich block body (a blank line starts a
      block body instead of an inline one), falling back to a plain
      numbered pill:
      `Battery quality matters more than raw power<shiny-aside>

Methodology

  • 40 commuter e-bike models
  • released in 2024

` ```

    ```{.callout-note title="Streamed messages"}
    Use this method (over `.append_message()`) when `stream=True` (or similar) is
    specified in model's completion method.
    ```

Returns

    :
        An extended task that represents the streaming task. The `.result()` method
        of the task can be called in a reactive context to get the final state of the
        stream.

clear_messages

Chat.clear_messages(greeting=False)

Clear all chat messages.

Parameters

Name Type Description Default
greeting bool If True, also clears the greeting in addition to conversation messages. Clearing the greeting causes the {id}_greeting_requested input to fire again (if the chat is visible with no greeting and no messages), enabling a regenerate pattern: clear the greeting, then react to the request to generate a new one via :meth:~shinychat.Chat.set_greeting. False

destroy

Chat.destroy()

Destroy the chat instance.

enable_bookmarking

Chat.enable_bookmarking(client, /, *, bookmark_on='response')

Enable bookmarking for the chat instance.

This method registers on_bookmark and on_restore hooks on session.bookmark (:class:shiny.bookmark.Bookmark) to save/restore chat state on both the Chat and client= instances, including the current greeting content. This means dynamic greetings survive bookmark round-trips without any extra app-level plumbing. In order for this method to actually work correctly, a bookmark_store= must be specified in shiny.App().

Parameters

Name Type Description Default
client 'ClientWithState | chatlas.Chat[Any, Any]' The chat client instance to use for bookmarking. This can be a Chat model provider from chatlas, or more generally, an instance following the ClientWithState protocol. required
bookmark_on Optional[Literal['response']] The event to trigger the bookmarking on. Supported values include: - "response" (the default): a bookmark is triggered when the assistant is done responding. - None: no bookmark is triggered When this method triggers a bookmark, it also updates the URL query string to reflect the bookmarked state. 'response'

Raises

Name Type Description
ValueError If the Shiny App does have bookmarking enabled.

Returns

Name Type Description
CancelCallback A callback to cancel the bookmarking hooks.

get_greeting

Chat.get_greeting()

Get the current greeting content.

Returns

Name Type Description
str or None The current greeting content, or None if no greeting is set or has been cleared.

message_stream_context

Chat.message_stream_context()
    Message stream context manager.

    A context manager for appending streaming messages into the chat. This context
    manager can:

    1. Be used in isolation to append a new streaming message to the chat.
        * Compared to `.append_message_stream()` this method is more flexible but
          isn't non-blocking by default (i.e., it doesn't launch an extended task).
    2. Be nested within itself
        * Nesting is primarily useful for making checkpoints to `.replace()` back
          to (see the example below).
    3. Be used from within a `.append_message_stream()`
        * Useful for inserting additional content from another context into the
          stream (e.g., see the note about tool calls below).

Yields

    :
        A `MessageStream` class instance, which has a method for `.append()`ing
        message content chunks to as well as a `.replace()` method to reset the
        stream back to its initial state (via `.replace("")`). Note that
        `.append()` supports the same message content types as `.append_message()`.

Example

    ```python
    import asyncio

    from shiny import reactive
    from shiny.express import ui

    chat = ui.Chat(id="my_chat")
    chat.ui()


    @reactive.effect
    async def _():
        async with chat.message_stream_context() as msg:
            await msg.append("Starting stream...

Progress:“) async with chat.message_stream_context() as progress: for x in [0, 50, 100]: await progress.append(f” {x}%“) await asyncio.sleep(1) await progress.replace(”“) await msg.replace(”“) await msg.append(”Completed stream”) ```

Note

    A useful pattern for displaying tool calls in a chatbot is for the tool to
    display using `.message_stream_context()` while the the response generation is
    happening through `.append_message_stream()`. This allows the tool to display
    things like progress updates (or other "ephemeral" content) and optionally
    `.replace("")` the stream back to it's initial state when ready to display the
    "final" content.

Note

    `.replace()` resets the stream to the checkpoint captured when this context was
    entered. It raises `ValueError` if the stream's content since that checkpoint
    spans multiple content types (e.g. thinking followed by markdown), because the
    replace wire action carries a single content type. Open a fresh
    `.message_stream_context()` before the mixed content if you need a clean
    checkpoint to replace back to.

messages

Chat.messages(format=DEPRECATED, token_limits=DEPRECATED)

Reactively read chat messages

Obtain chat messages within a reactive context.

Parameters

Name Type Description Default
format DEPRECATED_TYPE Removed. Raises TypeError if provided. Use your LLM provider (e.g., chatlas, LangChain) to manage message formatting instead. DEPRECATED
token_limits DEPRECATED_TYPE Removed. Raises TypeError if provided. Use your LLM provider (e.g., chatlas, LangChain) to manage token limits instead. DEPRECATED

Note

Messages are listed in the order they were added. As a result, when this method is called in a .on_user_submit() callback (as it most often is), the last message will be the most recent one submitted by the user.

Note

This reflects the messages the browser has rendered and reported back, so it is eventually consistent: it returns an empty tuple until the client’s first report, and a message passed to :meth:~shinychat.Chat.append_message does not appear here until the browser has rendered it and echoed its snapshot to the server. Read it reactively (e.g. in an .on_user_submit() callback) rather than expecting it to update synchronously right after appending.

Returns

Name Type Description
tuple[ChatMessageDict, …] A tuple of chat messages. The attachments field, when present, contains :class:~shinychat.Attachment objects. These are Pydantic models, so call .model_dump() on each one before passing them to json.dumps() or any other JSON serializer.

on_user_submit

Chat.on_user_submit(fn=None)

Define a function to invoke when user input is submitted.

Apply this method as a decorator to a function (fn) that should be invoked when the user submits a message. This function can take up to two optional arguments: the user input message (a str) and any attached files (a list[Attachment], where each item exposes mime (MIME type), data_url (a data:<mime>;base64,... URL), and name (the original filename) attributes).

In many cases, the implementation of fn should also do the following:

  1. Generate a response based on the user input.
  • If the response should be aware of chat history, use a package like chatlas to manage the chat state, or use the .messages() method to get the chat history.
  1. Append that response to the chat component using .append_message() ( or .append_message_stream() if the response is streamed).

Parameters

Name Type Description Default
fn UserSubmitFunction | None A function to invoke when user input is submitted. None

Note

This method creates a reactive effect that only gets invalidated when the user submits a message. Thus, the function fn can read other reactive dependencies, but it will only be re-invoked when the user submits a message.

remove_slash_command

Chat.remove_slash_command(name)

Remove a previously registered slash command by name.

Parameters

Name Type Description Default
name str The name of the command to remove (without the leading /). required

set_greeting

Chat.set_greeting(greeting)

Set or clear the chat greeting.

A greeting is displayed at the top of the chat before any conversation messages. It can be static content, streaming content from an async iterator, or None to remove an existing greeting.

If the greeting has already been dismissed, calling this method updates the greeting content but does not make it visible again. To show a new greeting after dismissal, first clear the chat with await chat.clear_messages(greeting=True).

Parameters

Name Type Description Default
greeting 'str | HTML | Tag | TagList | ChatGreeting | None' The greeting content. Can be: * None: clears the current greeting entirely (distinct from dismissal). Use this before setting a new greeting when implementing a regenerate pattern. * A markdown string, :class:~htmltools.HTML, :class:~htmltools.Tag, or :class:~htmltools.TagList: displayed as a stand-alone greeting. * A :func:~shinychat.chat_greeting object with options such as persistent. * A :func:~shinychat.chat_greeting wrapping an :class:~typing.AsyncIterable of strings: streams the greeting content chunk-by-chunk. required

Notes

When no greeting is set and the chat is visible with no messages, an input named {id}_greeting_requested fires (where {id} is the chat’s ID). Use @reactive.event(input.{id}_greeting_requested) to generate a greeting on demand. This input fires on first load and again after :meth:~shinychat.Chat.clear_messages is called with greeting=True. When the user dismisses the greeting, {id}_greeting_dismissed fires with a Date.now() timestamp. If the greeting is later cleared after being dismissed, the input resets to None.

Examples

Static greeting (stand-alone, dismissed on first message by default):

@reactive.effect
async def _():
    await chat.set_greeting(
        "## Welcome!\n\nHow can I help you today?"
    )

Static greeting with custom options:

from shinychat import chat_greeting


@reactive.effect
async def _():
    greeting = chat_greeting(
        "## Welcome!",
        persistent=True,
    )
    await chat.set_greeting(greeting)

Streaming greeting from an async iterator:

@reactive.effect
async def _():
    async def token_stream():
        for token in ["Hello", " there", "!"]:
            yield token

    await chat.set_greeting(chat_greeting(token_stream()))

LLM-generated greeting using greeting_requested:

import chatlas
from shinychat import Chat, chat_greeting

chat_model = chatlas.ChatOpenAI(model="gpt-4o")
chat = Chat(id="chat")


@reactive.effect
@reactive.event(input.chat_greeting_requested)
async def _():
    response = await chat_model.stream_async(
        "Write a short, friendly welcome message."
    )
    await chat.set_greeting(chat_greeting(response))

Regenerate pattern (clear and re-request):

@reactive.effect
@reactive.event(input.regenerate)
async def _():
    await chat.clear_messages(greeting=True)


# greeting_requested fires again after clear_messages(greeting=True),
# so the LLM-generated greeting handler above will run again.

Clear the greeting (e.g., before setting a new one):

await chat.set_greeting(None)

set_user_message

Chat.set_user_message(value)

Deprecated. Use update_user_input(value=value) instead.

slash_command

Chat.slash_command(name, description, fn=MISSING, *, echo=None, force=False)

Register a slash command and its handler.

Can be used as a decorator (handler supplied by decoration) or called directly with fn=. Pass fn=None to register a client-side command — one with no server handler, handled in JavaScript via the shiny:chat-slash-command DOM event (see the docs).

Parameters

Name Type Description Default
name str The slash command name (without the leading /). Must contain only alphanumeric characters, underscores, or hyphens. required
description str A short description shown in the command palette. required
fn UserSubmitFunction | None | MISSING_TYPE The handler function (0 or 1 argument; one argument receives the text after the command name). Omit it to use slash_command as a decorator. Pass None explicitly to register a client-side command with no server handler. MISSING
echo bool | None Whether invoking the command participates in the conversation: adds the /cmd user_input user message, shows a loading state, and stores the invocation in history. Defaults to True when a handler is provided and False otherwise. Set echo=False for a server handler that runs purely for its side effects (e.g. opening a modal). None
force bool Whether to overwrite an existing command with the same name. False

Returns

Name Type Description
Callable[[UserSubmitFunction], UserSubmitFunction] | Callable[[], None] A decorator when fn is omitted; otherwise a callable that removes the command.

transform_assistant_response

Chat.transform_assistant_response(fn=None)

Deprecated. Assistant response transformation features will be removed in a future version.

update_user_input

Chat.update_user_input(
    value=None,
    placeholder=None,
    submit=False,
    focus=False,
    attachments=None,
    attachment_mode='append',
)

Update the user input.

Parameters

Name Type Description Default
value str | None The value to set the user input to. None
placeholder str | None The placeholder text for the user input. None
submit bool Whether to automatically submit the text for the user. Requires value. False
focus bool Whether to move focus to the input element. Requires value or attachments. False
attachments 'list[Attachment] | None' Attachments to stage in the input. Pass an empty list to clear any currently staged attachments. When submit=True the attachments are sent alongside value and then cleared from the input. None
attachment_mode "Literal['append', 'set']" How to combine attachments with any already-staged attachments. "append" (default) adds to the existing set; "set" replaces it. Pass attachment_mode="set" with attachments=[] to clear all staged attachments. 'append'

user_input

Chat.user_input()

Reactively read the user’s latest submission.

Returns

Name Type Description
UserInput | None None before the first user submission; otherwise a named tuple of the submitted text and any attached files. The attachments list is empty unless allow_attachments was enabled in :func:~shinychat.chat_ui. Supports destructuring after a None check:: result = chat.user_input() if result is not None: text, attachments = result

Note

Most users shouldn’t need to use this method directly since the last item in .messages() contains the most recent user input. It can be useful for:

  1. Taking a reactive dependency on the user’s input outside of a .on_user_submit() callback.
  2. Maintaining message state separately from .messages().