Skip to main content
Pass tool renderers, data renderers and artifact kinds to ChatProvider. Registration uses exact, case-sensitive kind values. The composer’s / commands, @ mention sources and features go there too; see Composer commands.
Tool kinds without a registration use the generic tool card: a closed card with a wrench icon, the tool’s name and a one-line summary of its input. While the call runs the icon is a spinner; when it finishes the icon turns green, and a failed or denied call turns it red and starts the title with Failed: or Denied:. Opening it shows the input, then the output, error or denial reason, scrolling past 240px. An output in MCP’s CallToolResult shape, { content: [...] }, shows its { type: 'text', text } items as text and its { type: 'image', data, mimeType } items with an image/* type as images, in order; anything else shows as JSON. Artifact kinds without a registration show their title, kind, and serialized content rather than throwing.

Tool cards

toolCard(kind, describe) returns a tool renderer that draws each call of kind as the same card, with your own icon, title and body. describe gets the call’s part and returns what the card shows:
A card with no links or body has no chevron and doesn’t open. The card’s status comes from the part’s state: running until the call has an output, then done, error or denied. To draw the card yourself, for example inside your own renderer, use ToolCard. It takes icon, status ('running' | 'done' | 'error' | 'denied'), title, subtitle and the body as children, plus Radix Collapsible’s open, defaultOpen and onOpenChange. LinkList shows rows of links, each with the site’s icon, the page’s title, its host and an optional snippet. Every row opens in a new tab.
Site icons come from ChatProvider’s faviconUrl. Without it, each row shows the host’s first letter and no request leaves the page.

Tool renderer options

The component receives:

Data renderer options

A data-<kind> message part uses the first dataRenderers entry whose kind matches. Parts without one show their JSON payload. data-paste, data-page-context and data-prompt keep FrogBot’s own rendering. CompactionPart is the built-in renderer for a chat compaction. It isn’t registered by default:
It reads CompactionPartData: While status is running, it shows Compacting… with a spinner and no closing divider. Data in any other shape shows as JSON. SteeredPart renders a data-steered part, a message the user steered into a running reply, as a user bubble where the reply took it. Register it as { kind: 'steered', render: SteeredPart }. It reads SteeredPartData, { messageId: string, text: string }; data in any other shape shows as JSON.

Artifact options

artifactPersistence on ChatProvider takes:

Composer commands

commands, mentionSources, composerFeatures and composerHistory on ChatProvider extend the composer, in <Chat> or a standalone Composer.
Typing / as the whole input opens a menu of the enabled commands whose id or title contains the text after it. Typing @ at the start or after a space searches every mention source and groups the results by source. In both menus Tab or Enter picks, Up and Down or Ctrl+N and Ctrl+P move, and Escape closes the menu. Picking a command without arguments clears the input and runs it. Picking one with arguments writes /id ; sending /id rest then calls execute(rest). Either way the text clears, attachments stay, nothing is sent or added to history, and it works while a reply streams. In <Chat>, a command that rejects shows Command failed: <message>. Picking a mention inserts a chip that reads @label. One Backspace removes it. <Chat> sends the chip’s @label in the text and a data-mention part for it; see Composer prompt. Up in an empty input recalls the last sent prompt, chips included; Up and Down then page through the list while the caret is at the start or end, and Down past the newest empties the input. FrogBot keeps 100 prompts, newest first, without repeating the newest. Commands and attachments are not kept. Import Lexical from @frogbotai/ui/lexical, which re-exports lexical and useLexicalComposerContext, so a feature uses the composer’s own copy.

Command options

Mention source options

Mention item options

Composer feature options

defaultComposerFeatures holds slash, mentions, paste, history and keybindings. A composerFeatures list replaces it, and the last feature with a key wins, so [...defaultComposerFeatures, { key: 'history' }] turns prompt history off. Editing a sent message uses only mentions and keybindings.

Composer history storage options

The default keeps the list in localStorage under frogbot:composer-history, and loads an empty list from data it can’t read. Errors from load and save are ignored.

Answer client tools

A renderer for a client tool receives addToolOutput(output) and dismiss() while its call is waiting for an answer in the latest assistant message. addToolOutput submits the answer, and the chat resubmits once every call in the step has one. dismiss declines the call without calling the model again. Both props are absent while the reply is streaming and for calls that were already answered, so render the part read-only when they are missing. QuestionToolRender is the built-in renderer for the question tool. Custom chat surfaces that render ToolPart outside Chat can supply the same actions through ToolActionsContext.

Read-only conversations

In a channel conversation, Chat is read-only, and every tool renderer receives isReadonly: true and channelLabel instead of the answer callbacks. addToolOutput and dismiss are never passed, even for a call that is still waiting. Use channelLabel, such as Slack, for copy like “Waiting for an answer in Slack”.
Custom surfaces set isReadonly and channelLabel on ToolActionsContext to get the same behavior. Add initialize and onStreamPart to an artifact registration when data parts progressively build an artifact. Add artifactPersistence to ChatProvider to provide application-specific load and save functions.