惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
宝玉的分享
宝玉的分享
月光博客
月光博客
小众软件
小众软件
Jina AI
Jina AI
WordPress大学
WordPress大学
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 【当耐特】
博客园 - 三生石上(FineUI控件)
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
G
Google Developers Blog
M
MIT News - Artificial intelligence
N
Netflix TechBlog - Medium
云风的 BLOG
云风的 BLOG
MyScale Blog
MyScale Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Blog — PlanetScale
Blog — PlanetScale

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Day 3: Generative UI Gen 2 — Declarative Specs with A2UI
Ravi · 2026-06-12 · via DEV Community

Day 3: Generative UI Gen 2 — Declarative Specs with A2UI

This is Day 3 of my 6-part series on how LLMs rewrote the user interface over the past year. Day 2 covered static generative UI with AG-UI — and ended on its core limitation: the agent can only show what you've pre-built.

Moving up the freedom axis

Gen 1's contract was "pick from my components." Gen 2's contract is more interesting: "compose a UI from my primitives."

The agent doesn't return code, and it doesn't just pick a component — it returns a declarative description of an interface: a tree of abstract components (cards, rows, text, inputs) plus the data to fill them. Your client renders that description using its own native widgets. The agent decides structure; you still decide implementation, styling, and what's allowed.

This is the pattern behind A2UI (Agent-to-User Interface), the open protocol Google released in late 2025. It came out of a real constraint: Google needed agents to send rich UI across trust boundaries — a third-party agent rendering inside Gemini, say — where executing agent-generated code is a non-starter.

The core idea: UI as a JSONL stream

A2UI transmits UI as a stream of JSON Lines. Each line is one message; the client builds the interface incrementally as lines arrive — so the UI paints progressively, like streamed text, instead of popping in at the end.

Four server-to-client message types do all the work: surfaceUpdate (add/update components), dataModelUpdate (set data), beginRendering (signal first paint with the root id), and deleteSurface (remove a UI region).

Here's an actual minimal stream that renders a profile card:

{"surfaceUpdate": {"components": [{"id": "root", "component": {"Column": {"children": {"explicitList": ["profile_card"]}}}}]}}
{"surfaceUpdate": {"components": [{"id": "profile_card", "component": {"Card": {"child": "card_content"}}}]}}
{"surfaceUpdate": {"components": [{"id": "card_content", "component": {"Column": {"children": {"explicitList": ["name_text", "bio_text"]}}}}]}}
{"surfaceUpdate": {"components": [{"id": "name_text", "component": {"Text": {"usageHint": "h3", "text": {"literalString": "A2A Fan"}}}}]}}
{"surfaceUpdate": {"components": [{"id": "bio_text", "component": {"Text": {"text": {"literalString": "Building beautiful apps from a single codebase."}}}}]}}
{"dataModelUpdate": {"contents": {}}}
{"beginRendering": {"root": "root"}}

Two design choices worth noticing:

It's an adjacency list, not a nested tree. Components reference children by id ("children": {"explicitList": [...]}) instead of nesting. That's deliberate: flat structures are easier for an LLM to generate correctly token-by-token, and easier to stream — the spec's first design requirement is literally "must be easily generated by a Transformer LLM."

Structure and state are decoupled. Components describe shape; the data model holds values. Update a price? Send a tiny dataModelUpdate — no need to resend the component tree. Bindings connect the two:

{"surfaceUpdate": {"components": [
  {"id": "price_text", "component": {"Text": {"text": {"path": "/flight/price"}}}}
]}}
{"dataModelUpdate": {"contents": {"flight": {"price": "$267"}}}}

Interactions flow back as events

When the user taps a button, the client doesn't run agent code — it sends a userAction message back to the agent (error is the only other client-to-server type). The agent responds with new stream messages. The loop is: agent streams UI → user acts → event goes back → agent streams an update. The primary data stream stays unidirectional, which keeps the security story clean.

Catalogs: the trust boundary made explicit

The piece that makes A2UI deployable across platforms is the catalog — a client-defined contract listing which component types it can render (Card, Row, Text, DateTimeInput, …) and their properties. The agent can only reference types in the catalog. Anything else is rejected.

This is also the cross-platform answer Gen 1 lacked. The same JSONL stream renders as React components on web, Flutter widgets on mobile, SwiftUI views on iOS — each client maps abstract types to its own native widgets via its registry. Write the agent once; every surface renders it natively. There's a standard catalog per protocol version, and you can negotiate custom ones (the server advertises supported catalogs in its A2A Agent Card; the client declares what it accepts).

Security falls out of the design: A2UI is data, not code. No script execution, no UI injection beyond what your catalog allows, no iframe of mystery origin. For regulated industries, that sentence is the whole pitch.

Where Gen 2 sits in practice

Compared to Gen 1, you trade some safety guarantees for a lot of expressiveness:

Gen 1 (AG-UI static) Gen 2 (A2UI declarative)
Agent controls Which component + props Full UI structure from primitives
You control Everything else Catalog, rendering, styling
Novel layouts No — prebuilt only Yes — composed at runtime
Cross-platform Re-implement per client Same stream, native render everywhere
Failure mode Weird data in a good component Weird layout from good components

That last row is the honest caveat: when the agent composes structure, it can compose bad structure — a form with the submit button above the fields, a 14-component card where 4 would do. Your catalog constrains vocabulary, not taste. Teams shipping Gen 2 typically add layout linting or few-shot examples of good composition in the agent prompt.

The deeper limit: the agent is still confined to your primitives. It can't ship an interactive chart type you never built, or a custom visualization for a domain it just learned about. For that you need to hand the agent a real, sandboxed UI surface — which is Gen 3, MCP Apps, and tomorrow's post.

What's next

  • Day 4: Generative UI Gen 3 — MCP Apps and open-ended surfaces
  • Day 5: Beyond chat — canvas interfaces, adaptive UX, and the security bill coming due

If you want to explore A2UI today: the spec, quickstart, and a live composer are at a2ui.org, and the project is open source on GitHub. See you tomorrow.