GenUI Prompt First: How Flutter's GenUI Now Builds UI From System Prompts
Flutter's GenUI package moved from Structured Output First to Prompt First with A2UI v0.9. Here is what changed, why it matters, and how to wire PromptBuilder, TransportAdapter, and SurfaceController.
Published on • October 9, 2026
AI Assistant

Generative UI (GenUI) is the pattern where an agent does not only generate content — it decides how that content is displayed and made interactive. In Flutter, the genui package implements this by connecting to an agent over the A2UI protocol and rendering the result from a widget catalog in your own project. Importantly, the UI is not generated as code: it is generated at runtime as JSON that describes widgets your app already ships.
With the May 2026 update driven by A2UI v0.9, GenUI changed how that JSON gets produced. The package moved from Structured Output First to Prompt First — and the difference matters if you are building agentic Flutter apps in 2026.
The two approaches
Structured Output First (the old way) streamed A2UI messages through the provider’s structured-output APIs — JSON mode or function calling — with the schema passed out-of-band via API parameters.
Prompt First (the new way) puts everything in plain text: the agent includes blocks of JSON directly in its responses, and the UI schema plus A2UI formatting rules are injected into the system prompt as plain text.
Why the switch
Google’s stated rationale for the change:
- Deeply nested schemas confused models. Structured-output constraints fought the model’s natural text-generation tendencies.
- Catalog size limits. Structured outputs imposed caps on how large and complex your widget catalog could get.
- Debugging was painful. Constraints lived in the network layer where you could not easily see or edit them.
Prompt First moves the source of truth to where LLMs actually excel: system instructions. Modern models are trained to follow detailed system prompts and examples, and now the schema is plain text you can inspect, edit, and version per app.
PromptBuilder: the new entry point
The PromptBuilder class takes your catalog and prompt fragments and produces the system prompt containing schema definitions and A2UI formatting rules:
final promptBuilder = PromptBuilder.chat(
catalog: catalog,
systemPromptFragments: [
'You are a helpful travel assistant.',
],
);
final systemPrompt = promptBuilder.systemPrompt;
// Pass systemPrompt to your LLM of choice
Your app is now responsible for getting the right prompt into context. That sounds like more work — it is the price of owning the connection.
The three-layer architecture
Alongside Prompt First, genui was decoupled. The old ContentGenerator class was removed and replaced with three layers:
| Layer | Class | Responsibility |
|---|---|---|
| Engine | SurfaceController | State and rendering |
| Transport | A2uiTransportAdapter | Streams messages between agent and renderer |
| Facade | Conversation | High-level chat API |
Provider wrapper packages (genui_dartantic, genui_google_generative_ai, genui_firebase_ai) are gone from the tree. You own chat history, retry, error handling, model choice, and lifecycle.
final controller = SurfaceController(
catalogs: [BasicCatalogItems.asCatalog()],
);
late final adapter = A2uiTransportAdapter(
onSend: (ChatMessage msg) async {
final buffer = StringBuffer();
for (final part in msg.parts) {
if (part.isUiInteractionPart) {
buffer.write(part.asUiInteractionPart!.interaction);
} else if (part is TextPart) {
buffer.write(part.text);
}
}
final response = await myAgentClient.sendRequest(buffer.toString());
adapter.addChunk(response); // parsed as an A2UI stream
},
);
final conversation = Conversation(
controller: controller,
transport: adapter,
);
The benefits: any AI source without waiting for a package update, loose coupling (only tokens move between layers), and simple testing with mock or hard-coded token sources.
How a response becomes UI
Inside onSend, you call your LLM and pipe the response text back through adapter.addChunk(response). The A2uiParserTransformer parses chunks into GenerationEvents — plain text vs. A2UI messages — and the SurfaceController applies them. Your widget tree then renders the surface:
return Surface(host: conversation.host, surfaceId: id);
The surfaceId arrives via ConversationSurfaceAdded events, and user input flows back through conversation.sendRequest(ChatMessage.user(text)).
A2UI v0.9 breaking changes
If you are migrating, expect renames and structural changes:
beginRendering→createSurface- Flat discriminators:
{"component": "Text", "text": "Hello"}instead of nested{"Text": {...}} - Simplified data binding:
{"path": "/path/to/var"} distribution→justify,alignment→align,usageHint→variantGenUiConversation→Conversation,GenUiController→SurfaceController,GenUiSurface→Surface- New sibling package
genai_primitives(types:ChatMessage,MessagePart,ToolDefinition)
Gotchas before you ship
- The repo is labeled highly experimental — the API will change. A redesign into modular
a2ui_core,a2ui_agent, anda2ui_flutterpackages is already announced. - Current stable is
genui 0.10.4on pub.dev, requiring Flutter 3.35.7+. - You must build and wire the LLM call yourself — no more provider wrappers.
- iOS/macOS builds need the
com.apple.security.network.cliententitlement for outbound requests. - The
DataModelis observable: widgets bound to it rebuild when the model updates, which is how the agent mutates UI state after the initial render.
Wrapping up
Prompt First makes GenUI debugging tractable: the schema is text you can read in your editor, not a constraint buried in an API parameter. Combined with the Engine/Transport/Facade split, you get a Flutter package that renders agent-driven UI while staying agnostic about which model produces it. It is still experimental — but it is the direction A2UI is heading.
References
- New updates to A2UI and Flutter’s GenUI package - the announcement of Prompt First and the architecture decoupling
- flutter/genui on GitHub - package source, status, and upcoming redesign
- genui on pub.dev - package API, Conversation, SurfaceController, and catalog
- A2UI ecosystem - protocol adoption and integrations