express.Chat
express.Chat(id, *, messages=(), on_error='auto', tokenizer=None)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. |
| 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. |
| set_user_message | Deprecated. Use update_user_input(value=value) instead. |
| transform_assistant_response | Deprecated. Assistant response transformation features will be removed in a future version. |
| transform_user_input | Deprecated. User input transformation features will be removed in a future version. |
| ui | Create a UI element for this Chat. |
| update_user_input | Update the user input. |
| user_input | Reactively read the user’s message. |
append_message
express.Chat.append_message(message, *, icon=None)Append a message to the chat.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| message | Any | 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). |
required |
| icon | HTML | Tag | TagList | None | 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. |
None |
Note
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
submitCSS class or adata-suggestion-submit="true"attribute to the suggestion element. - Holding the
Ctrl/Cmdkey 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.
Use .append_message_stream() instead of this method when stream=True (or similar) is specified in model’s completion method.
append_message_stream
express.Chat.append_message_stream(message, *, icon=None)Append a message as a stream of message chunks.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| message | Iterable[Any] | AsyncIterable[Any] | 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). |
required |
| icon | HTML | Tag | None | 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. |
None |
Note
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.
Use this method (over `.append_message()`) when `stream=True` (or similar) is
specified in model's completion method.
Returns
| Name | Type | Description |
|---|---|---|
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
express.Chat.clear_messages()Clear all chat messages.
destroy
express.Chat.destroy()Destroy the chat instance.
enable_bookmarking
express.Chat.enable_bookmarking(
client,
/,
*,
bookmark_store=None,
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. In order for this method to actually work correctly, a bookmark_store= must be specified in shiny.express.app_opts().
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_store | 'Optional[BookmarkStore]' | A convenience parameter to set the shiny.express.app_opts(bookmark_store=) which is required for bookmarking (and .enable_bookmarking()). If None, no value will be set. |
None |
| 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. |
message_stream_context
express.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 `.clear()` 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 way to `.clear()` the stream back to
it's initial state. 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.clear() await msg.clear() 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
`.clear()` the stream back to it's initial state when ready to display the
"final" content.
messages
express.Chat.messages(
format=MISSING,
token_limits=None,
transform_user='all',
transform_assistant=False,
)Reactively read chat messages
Obtain chat messages within a reactive context.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| format | 'MISSING_TYPE | ProviderMessageFormat' | Deprecated. Provider-specific message formatting will be removed in a future version. | MISSING |
| token_limits | tuple[int, int] | None | Deprecated. Token counting and message trimming features will be removed in a future version. | None |
| transform_user | Literal['all', 'last', 'none'] | Deprecated. Message transformation features will be removed in a future version. | 'all' |
| transform_assistant | bool | Deprecated. Message transformation features will be removed in a future version. | False |
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.
Returns
| Name | Type | Description |
|---|---|---|
| tuple[ChatMessage, …] | A tuple of chat messages. |
on_user_submit
express.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 an optional argument, which will be the user input message.
In many cases, the implementation of fn should also do the following:
- 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.
- 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.
set_user_message
express.Chat.set_user_message(value)Deprecated. Use update_user_input(value=value) instead.
transform_assistant_response
express.Chat.transform_assistant_response(fn=None)Deprecated. Assistant response transformation features will be removed in a future version.
transform_user_input
express.Chat.transform_user_input(fn=None)Deprecated. User input transformation features will be removed in a future version.
ui
express.Chat.ui(
messages=None,
placeholder='Enter a message...',
width='min(680px, 100%)',
height='auto',
fill=True,
icon_assistant=None,
**kwargs,
)Create a UI element for this Chat.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| messages | Optional[Iterable[str | TagChild | ChatMessageDict | ChatMessage | Any]] | A sequence of messages to display in the chat. Each message can be either a string or a dictionary with content and role keys. The content key should contain the message text, and the role key can be “assistant” or “user”. |
None |
| placeholder | str | Placeholder text for the chat input. | 'Enter a message...' |
| width | 'CssUnit' | The width of the UI element. | 'min(680px, 100%)' |
| height | 'CssUnit' | The height of the UI element. | 'auto' |
| fill | bool | Whether the chat should vertically take available space inside a fillable container. | True |
| icon_assistant | HTML | Tag | TagList | None | The icon to use for the assistant chat messages. Can be a HTML or a tag in the form of :class:~htmltools.HTML or :class:~htmltools.Tag. If None, a default robot icon is used. |
None |
| kwargs | TagAttrValue | Additional attributes for the chat container element. | {} |
update_user_input
express.Chat.update_user_input(
value=None,
placeholder=None,
submit=False,
focus=False,
)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. |
False |
user_input
express.Chat.user_input(transform=False)Reactively read the user’s message.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| transform | bool | Whether to apply the user input transformation function (if one was provided). | False |
Returns
| Name | Type | Description |
|---|---|---|
| str | None | The user input message (before any transformation). |
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:
- Taking a reactive dependency on the user’s input outside of a
.on_user_submit()callback. - Maintaining message state separately from
.messages().