flutter_ai_elements library
Composable, themeable Flutter UI for AI chat.
Adopts the Vercel AI Elements component vocabulary while rendering through a
mobile-first AiThemeExtension — no shadcn or forui dependency. Built from
base Flutter widgets so any design system can restyle it via theme tokens.
Presentational vs. bound widgets
- Presentational (
AiMessageBubble,AiConversationView,AiComposer,AiLoader) take plain data and callbacks; reusable and easy to test. - Bound (
AiChat,AiPromptInput) wire those to aUseChatControllerfromflutter_ai_clientfor a drop-in chat surface.
Re-exports flutter_ai_client (and transitively flutter_ai_core) so a
single import provides the controller, models, and UI.
Classes
- AiAnimatedResponse
- Reveals a streamed answer with a trailing blur fade-in — the Apple-Intelligence / Siri look — instead of a hard typewriter edge.
- AiAttachment
- A compact preview of a FilePart attachment.
- AiAvatar
- A small circular avatar identifying a message's author.
- AiBranch
- A compact "‹ 2/3 ›" control for navigating between alternate versions of a message (e.g. successive regenerations).
- AiChainOfThought
- A collapsible, vertical timeline of reasoning steps.
- AiChat
- A live, drop-in chat transcript bound to a UseChatController.
- AiChatView
-
A batteries-included chat surface: the AiChat transcript above an
AiPromptInput, laid out and safe-area-aware. Drop it straight into a
Scaffoldbody — the fastest path frompub addto a working chat: - AiCodeBlock
- A monospace code block with a header showing the language and a copy button.
- AiComposer
-
A modern message composer: a rounded input with a leading attach (
+) button beside the field, and a trailing pair — a secondary mic and a main button that is Live (voice) while the field is empty and swaps to Send once you type (hiding the mic), or Stop while streaming. - AiConfirmation
- An approve/deny card for actions an agent wants to take (running a tool, sending an email, making a purchase) — the human-in-the-loop gate.
- AiContextMeter
-
A compact context-window usage meter: a label, a
used / totaltoken readout, and a thin progress bar that turns amber/red as it fills. - AiConversation
- An ordered, immutable transcript of AiMessages.
- AiConversationList
- A ChatGPT-style conversation list / sidebar: a "New chat" action above a scrollable list of ChatThreads, with select and (optional) delete.
- AiConversationView
- A scrolling list of message bubbles.
- AiDataView
-
Renders a DataPart via a registry, showing fallback (or nothing) when
the part's
dataTypeis not registered. - AiEmbedding
- A single embedding vector produced by an EmbeddingProvider.
- AiEmptyState
- A centered placeholder shown when a conversation has no messages yet.
- AiErrorBanner
- An inline banner surfacing an error, with optional retry and dismiss.
- AiImage
- Displays an AI-generated (or attached) image with rounded corners, a loading placeholder, an error fallback, and tap-to-zoom into a full-screen, pinch-zoomable viewer.
- AiInlineCitation
-
A small numbered citation badge (e.g.
1) shown inline with text or after a claim, tappable to open or reveal the source. - AiLiveController
- Drives a live-voice loop — listen → send → speak → re-listen — by mapping an AiVoiceEngine onto a UseChatController, and exposes the AiLiveSession props (status, amplitude, transcript, muted) as a ChangeNotifier.
- AiLiveSession
- A full-screen, engine-agnostic Live voice surface, modelled on modern assistant voice modes: a luminous sky-orb that opens centered, then drops and shrinks to dock above the controls while the conversation fades in behind it so you can read along. The orb's interior is an animated, cloud-lit sky that breathes and reacts to audio amplitude.
- AiLoader
- A three-dot "thinking" indicator shown while the assistant is preparing a response.
- AiLocalizations
-
The user-facing strings used by
flutter_ai_elementswidgets. - AiLocalizationsDelegate
- Serves a fixed AiLocalizations instance. Provide a translated instance to localize, or implement your own delegate to switch by locale.
- AiLocalizationsScope
-
Overrides the AiLocalizations for the widgets below it — the simplest way
to translate or customize labels, with no
localizationsDelegateswiring: - AiMessage
- A single turn in a conversation, authored by one AiRole.
- AiMessageActions
- A compact row of per-message actions: copy, and optionally regenerate and edit.
- AiMessageBubble
- A single chat bubble that renders one AiMessage's parts.
- AiModelOption
- A selectable model option.
- AiModelSelector
- A compact "model ▾" chip that opens a bottom sheet to switch models.
- AiOrb
-
A small, calm voice/loading orb — a luminous sphere that gently breathes
and reacts to audio amplitude. The compact counterpart to the full-screen
orb in
AiLiveSession, usable inline (e.g. in a composer or status row). - AiPart
-
A single typed segment of an
AiMessage. - AiPromptInput
- A composer bound to a UseChatController.
- AiReasoning
- A collapsible disclosure for the model's reasoning ("chain of thought").
- AiRequestOptions
- Provider-neutral knobs for a generation request.
- AiResponse
- Renders a useful subset of Markdown — headings, bold/italic, inline code, fenced code blocks, ordered/unordered lists, blockquotes, and links — with no external dependency.
- AiResponseFormat
- Requests structured output constrained to a JSON schema.
- AiShimmer
- An animated shimmer placeholder for pending content — a row of grey bars with a highlight sweeping across them.
- AiSources
- A wrapped list of citation chips built from SourceParts.
- AiStreamEvent
-
A single incremental update emitted by an
LlmProviderduring generation. - AiSuggestions
- A horizontally scrolling row of tappable suggested prompts.
- AiTask
- A collapsible "task" card showing a titled checklist the agent works through — each item with a pending/active/complete/error indicator.
- AiTaskItem
- One line item within an AiTask.
- AiThemeExtension
-
The design tokens that style every
flutter_ai_elementswidget. - AiThoughtStep
- One step in an AiChainOfThought.
- AiToolCallSignal
-
A cancellation signal handed to an
onToolCallsexecutor as its second argument. - AiToolGroup
- A vertically stacked list of AiToolInvocation cards — the recommended way to present parallel tool calls.
- AiToolInvocation
- A collapsible card showing a single tool call: its name, lifecycle state, arguments, and (once available) result.
- AiUsage
- Token usage for a model turn, with an optional cost estimate.
- AiVoiceEngine
-
The audio side of a live voice session: speech-to-text in, text-to-speech
out. Implement it over your engine of choice (
speech_to_text+flutter_tts, a realtime API, …); AiLiveController drives the rest. - AiWidgetRegistry
-
A name→widget allowlist for generative UI: the model emits a DataPart
with a
dataTypediscriminator and a JSON payload, and the registry maps it to a Flutter widget. - ChatObserver
-
Observes the agent lifecycle of a
UseChatControllerfor tracing, metrics, and logging. - ChatStore
- Persists and restores AiConversations so a chat survives app restarts.
- ChatThread
- A lightweight summary of a stored conversation, for a thread list / sidebar.
- ChatThreadStore
- A ChatStore that can also enumerate and delete threads — enough to drive a conversation list / sidebar.
- DataPart
- A structured data payload that drives generative UI.
- EmbeddingProvider
- An optional capability a provider MAY implement to turn text into embedding vectors (for semantic search, clustering, and RAG retrieval).
- FilePart
- A file attachment: an image, document, or audio clip.
- InMemoryChatThreadStore
- An in-memory ChatThreadStore — handy for demos, tests, and prototyping before wiring real storage. Titles are derived via autoTitle on save.
- JsonAccumulator
- Accumulates a JSON document that arrives in fragments and parses it tolerantly while still incomplete.
- KeyValueChatThreadStore
-
A persistent ChatThreadStore backed by any KeyValueStore, so a chat
drawer survives app restarts without pulling a storage plugin into the
package. Each conversation is stored as JSON under
"$prefix$id", with a small index under"${prefix}index"for listThreads. Titles are derived via autoTitle on save. - KeyValueStore
-
A minimal async key→string storage — the seam a KeyValueChatThreadStore
persists through. Keeps the package plugin-free: back it with
shared_preferences, a file, secure storage, or an HTTP API in a few lines: - LlmProvider
- The contract every model backend implements: turn a conversation into a stream of incremental AiStreamEvents.
- MarkdownTextRenderer
- An AiTextRenderer that renders Markdown via AiResponse. The default renderer for assistant content.
- MessageFinished
- Marks message messageId complete, carrying the reason generation ended.
- MessageProcessor
- Folds a stream of AiStreamEvents into evolving AiConversation state.
- MessageStarted
- Announces a new message and its author, before any content arrives.
- MutationResult
-
The outcome of applying one stream event to a
MessageProcessor. - PartReceived
- Appends a fully-formed part (a file, source, or data payload) to message messageId.
- PlainTextRenderer
-
A renderer that emits a plain Text widget (opt in; the widgets default to
MarkdownTextRenderer). - ReasoningDelta
- Appends delta to the reasoning of message messageId.
- ReasoningPart
- The model's intermediate reasoning ("chain of thought").
- SourcePart
- A citation or source referenced by the model, rendered as a link or chip.
- StreamErrorEvent
- Reports an error during generation.
- TextDelta
- Appends delta to the prose of message messageId.
- TextPart
- Human- or model-authored prose, typically rendered as Markdown.
-
TextRenderer<
T> - A strategy for turning message text into a rendered representation.
- TokenCounter
- An optional capability a provider MAY implement to count the tokens a request would consume before sending it.
- ToolCallDelta
- Appends a fragment of argument JSON to tool call toolCallId.
- ToolCallPart
- A request from the model to invoke a tool.
- ToolCallReady
- Signals that tool call toolCallId has received all its arguments.
- ToolCallStarted
- Opens a tool call within message messageId.
- ToolDefinition
- A declaration of a tool the model may call: its name, purpose, and the JSON Schema describing its arguments.
- ToolResultPart
- The output of a tool, fed back to the model and shown to the user.
- ToolResultReceived
- Delivers the output of tool call toolCallId into message messageId.
- UseChatController
- Drives a chat conversation against any LlmProvider, exposing state as a Listenable (this class is a ChangeNotifier).
Enums
- AiConfirmationTone
- The visual weight of an AiConfirmation, which restyles its confirm button.
- AiLiveStatus
- The phase of a live voice session.
- AiMessageActionKind
- The per-message actions, used to control ordering via AiMessageActions.order and AiMessageActions.trailing.
- AiMessageStatus
- The delivery state of an AiMessage.
- AiMessageStyle
- How an assistant message is laid out.
- AiRole
- The author of a message in a conversation.
- AiTaskStatus
- The state of an AiTaskItem.
- ChatStatus
- The lifecycle state of a chat turn driven by a controller.
- FinishReason
- Why the model stopped generating a message.
- ReasoningEffort
- How much effort a reasoning-capable model should spend on internal thinking before answering.
- ToolCallState
- The lifecycle stage of a single tool call.
Extensions
- GenerateObject on LlmProvider
- Structured-output helpers layered on top of any LlmProvider.
Functions
-
attachStore(
UseChatController controller, ChatStore store, String id, {Duration debounce = const Duration(milliseconds: 400)}) → VoidCallback -
Auto-saves
controller's conversation tostoreunderidwhenever it changes and the turn has settled, coalescing rapid changes overdebounce. -
autoTitle(
AiConversation conversation, {String fallback = 'New chat', int maxLength = 40}) → String -
Derives a short title from a conversation's first user message, falling back
to
fallback. Trims tomaxLengthcharacters. -
keepLastMessages(
int count) → AiConversation Function(AiConversation) -
History-trimming strategies for
UseChatController.trimHistory. -
keepLastWithSummary(
{required String summary(), required int count, String summaryLabel = 'Summary of earlier conversation:'}) → AiConversation Function(AiConversation) -
Keeps the system prefix plus a rolling summary of older turns, plus the
most recent
countnon-system messages. -
llmExceptionFor(
int status, String body, {Duration? retryAfter}) → LlmException -
Maps an HTTP
statusto the matching LlmException subtype. -
showAiMessageActions(
BuildContext context, {required AiMessage message, VoidCallback? onCopy, VoidCallback? onRegenerate, VoidCallback? onEdit}) → Future< void> - Presents the per-message actions in a native bottom sheet — the idiomatic mobile pattern, triggered from a long-press on a message.
-
suggestFollowUps(
AiConversation conversation, LlmProvider provider, {int count = 3, AiRequestOptions? options}) → Future< List< String> > -
Generates up to
countshort follow-up prompts a user might send next, given the currentconversation, via a one-off call toprovider. -
trimToApproxTokenBudget(
int maxTokens, {int charsPerToken = 4}) → AiConversation Function(AiConversation) -
Keeps the system prefix plus as many of the most recent non-system messages
as fit within
maxTokens, estimated from text length. -
validateJsonSchema(
Object? value, Map< String, Object?> schema, {String path = 'args'}) → List<String> -
Validates
valueagainstschema, returning a list of violation messages (empty when valid).pathnames the root in messages (defaults toargs).
Typedefs
-
AiDataWidgetBuilder
= Widget Function(BuildContext context, Map<
String, Object?> data) - Builds a widget for a DataPart's payload.
-
AiTextRenderer
= TextRenderer<
Widget> -
A
TextRendererthat produces a Flutter Widget — the rendering seam used throughout the UI. -
CodeHighlighter
= List<
TextSpan> ? Function(String code, String? language, TextStyle base) -
Turns
codeinlanguageinto styled spans for syntax highlighting, usingbaseas the baseline text style (family/size/default color).
Exceptions / Errors
- AgentLoopException
-
Surfaced on UseChatController.error when the agent loop is halted because
the model requested the same tool call (identical name + args) more than the
controller's
maxIdenticalToolCallslimit — a runaway-loop guard that stops the turn instead of looping (and spending tokens) up tomaxSteps. - AiToolCallCancelled
- Thrown by AiToolCallSignal.throwIfCancelled when the turn was cancelled.
- LlmAuthException
- Authentication/authorization failure (HTTP 401/403) — usually a bad or missing API key.
- LlmException
- A failed provider HTTP request, surfaced on StreamErrorEvent.error so hosts can branch on the type (auth vs. rate-limit vs. server) instead of string-matching a message.
- LlmRateLimitException
- Rate limited (HTTP 429). Honor retryAfter before retrying.
- LlmRequestException
- A non-retryable client error (other 4xx) — e.g. a malformed request.
- LlmServerException
- Server-side failure (HTTP 5xx, incl. Anthropic 529 overloaded).