Component

Agent chat shell

Agent chat

A resizable AI chat shell for conversations, tools, and text or audio handoff.

Demo

Store-backed agent workspace

A Pinia setup store drives conversation loading, sidebar selection, closable split panels, streaming assistant parts, text/audio mode switching, and custom tool-call rendering.

Agent conversation

Ask, inspect, and continue the work in one thread.

No messages yet

Select a conversation or start a new one.

Enter to send, Shift + Enter for a new line

Demo API

Last request and response

idle

Request

{}

Response

{}

Active agent

Loading agent

The selected conversation controls this panel.

Request log

Architecture

Reusable component split

Shell

DomAgentChatShell composes the sidebar, conversation, and aside using split panels. Apps can use it full screen or replace any pane with slots.

Conversation

DomAgentConversation owns the header, scroll-contained message viewport, composer footer, autoscroll, and tool rendering.

List

DomAgentConversationList is a dedicated conversation picker for full app shells, popovers, drawers, and focused chat panels.

Data contract

Message parts

The conversation component renders ordered message parts. Text, audio, handoff, reasoning summaries, tool calls, and tool results can appear in one assistant message while a stream is still active.

Use reasoning parts for safe reasoning summaries or product-owned traces. Keep hidden model reasoning private unless your backend intentionally stores a reviewed trace that users are allowed to inspect.

agent-message.jsjs

API

Streaming endpoint shape

The demo API uses callbacks so it can run in the docs without infrastructure. A production endpoint can deliver the same events over SSE, a WebSocket, a fetch stream, or a queue worker bridge.

Tool calls are ordinary message parts. If the frontend has no renderer for a tool, the conversation uses the generic argument/result card. If a renderer exists, it receives the full tool part and parent message.

agent-chat-api.txttxt

Custom tools

Renderer map

tool-renderers.vuevue
WeatherToolCard.vuevue

Store

Pinia integration

The exported store factory keeps the component transport-free. It owns active conversation state, panel state, composer state, stream cancellation, and request logging, while your API adapter owns persistence and streaming transport.

useFlexAiAgentStore.jsjs
useAgentChatDemoStore.jsjs
agentChatMockApi.jsjs

Reference

Props

Control props

NameTypeTSDefaultDescription
conversationsarrayArray<unknown>[]Conversation summaries for the sidebar.
conversationobjectRecord<string, unknown>Active conversation record.
messagesarrayArray<unknown>[]Messages for the active conversation.
agentsarrayArray<unknown>[]Agents available to the chat shell.
activeConversationIdstringstring''Selected conversation id.
modelValuestringstring''Controlled composer text.
mode'text' | 'audio'string'text'Active composer mode.
searchstringstring''Controlled sidebar search value.
streamingbooleanbooleanfalseWhether the active assistant response is streaming.
loadingbooleanbooleanfalseWhether active conversation messages are loading.
sidebarOpenbooleanbooleantrueControls the conversation sidebar visibility.
asideOpenbooleanbooleantrueControls the contextual aside visibility.
sidebarSizenumbernumber300Resizable sidebar width in pixels.
asideSizenumbernumber340Resizable aside width in pixels.
minSidebarnumbernumber240Minimum sidebar width while open.
minConversationnumbernumber420Minimum center conversation width.
minAsidenumbernumber280Minimum aside width while open.
toolComponentsobjectRecord<string, unknown>{}Tool renderer component map passed through to DomAgentConversation.
titlestringstring'Agent workspace'Accessible label for the chat application shell.

Auto-generated from Agent chat shell.props and inline _edit hints.

Events

NamePayloadDescription
@update:modelValuestringPasses composer updates from the conversation component.
@update:mode'text' | 'audio'Passes audio/text mode changes from the conversation component.
@update:searchstringPasses sidebar search updates.
@update:sidebarOpenbooleanFired when the sidebar is opened or closed.
@update:asideOpenbooleanFired when the aside is opened or closed.
@update:sidebarSizenumberFired when the sidebar splitter changes width.
@update:asideSizenumberFired when the aside splitter changes width.
@select-conversationconversationFired when a sidebar row is selected.
@new-conversationundefinedFired when the sidebar new button is activated.
@submit({ content, mode, conversation })Fired when the composer submits.
@stop({ conversation })Fired when streaming is stopped.
@tool-action({ action, tool, message })Fired by generic or custom tool renderers.

Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.

Slots

NameScopeDescription
#sidebar{ conversations, activeConversationId }Replace the conversation sidebar.
#conversation{ conversation, messages, activeAgent }Replace the main conversation component.
#aside{ conversation, activeAgent, toolParts }Replace the contextual aside.

DomAgentConversation

Props

Control props

NameTypeTSDefaultDescription
conversationobjectRecord<string, unknown>Active conversation record. Used for the header, status, and empty state context.
messagesarrayArray<unknown>[]Ordered conversation messages. Messages may contain text, reasoning, audio, handoff, and tool-call parts.
agentsarrayArray<unknown>[]Agents that can author assistant messages or be displayed in the header.
modelValuestringstring''Controlled composer text.
mode'text' | 'audio'string'text'Active composer modality.
streamingbooleanbooleanfalseShow the stop control and live status while the assistant response streams.
loadingbooleanbooleanfalseShow a loading state before conversation messages are available.
autoScrollbooleanbooleantrueKeep the scroller pinned to the bottom while new content arrives.
showHeaderbooleanbooleantrueRender the built-in conversation header.
showFooterbooleanbooleantrueRender the built-in composer footer.
showReasoningbooleanbooleantrueRender reasoning summary parts when the supplied message data includes them.
placeholderstringstring'Ask the agent to plan, inspect, or create...'Composer placeholder text.
emptyTextstringstring'Select a conversation or start a new one.'Message shown when there are no messages.
disabledbooleanbooleanfalseDisable composer input and send controls.
toolComponentsobjectRecord<string, unknown>{}Component map keyed by tool rendererKey or tool name. Falls back to the generic tool card.
maxMessageWidthstringstring'48rem'CSS max-width applied to message bubbles.

Auto-generated from Agent conversation.props and inline _edit hints.

Events

NamePayloadDescription
@update:modelValuestringFired when the composer text changes.
@update:mode'text' | 'audio'Fired when the composer switches between text and audio mode.
@submit({ content, mode, conversation })Fired when the user submits the composer.
@stop({ conversation })Fired when the user stops an active stream.
@tool-action({ action, tool, message })Fired by generic and custom tool renderers for approvals, retries, and inspection.
@scroll-bottom({ conversation })Fired when the built-in jump-to-bottom control is used.

Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.

Slots

NameScopeDescription
#header-leading{ conversation, activeAgent }Controls shown before the title, useful for opening an app sidebar.
#header-actions{ conversation, activeAgent, streaming }Controls shown at the end of the header.
#message{ message, activeAgent, parts }Replace the full message renderer.
#tool{ tool, message, component, action }Replace generic tool rendering without supplying toolComponents.
#composer-actions{ mode, setMode, disabled, streaming }Extra controls inside the composer row.
#footer{ value, mode, submit, setMode }Replace the built-in composer footer.
#emptyCustom empty conversation state.

DomAgentConversationList

Props

Control props

NameTypeTSDefaultDescription
conversationsarrayArray<unknown>[]Conversation summaries shown in the navigation list.
agentsarrayArray<unknown>[]Agent records used to label each conversation.
activeConversationIdstringstring''Selected conversation id.
searchstringstring''Controlled conversation search value.
loadingbooleanbooleanfalseShow loading rows while conversations are fetched.
titlestringstring'Conversations'Sidebar heading.
showNewButtonbooleanbooleantrueShow the built-in new conversation button.
emptyTextstringstring'No conversations match this view.'Message shown when the filtered list is empty.

Auto-generated from Agent conversation list.props and inline _edit hints.

Events

NamePayloadDescription
@update:searchstringFired when the sidebar search changes.
@selectconversationFired when a conversation row is selected.
@newundefinedFired when the new conversation action is activated.

Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.

Slots

NameScopeDescription
#actions{ conversations }Extra controls beside the heading.
#conversation{ conversation, active, agent }Replace a conversation row.
#emptyCustom empty state.