specification/v0_9/docs/evolution_guide.md
This document serves as a comprehensive guide to the changes between A2UI version 0.8.1 and version 0.9. It details the shifts in philosophy, architecture, and implementation, providing a reference for stakeholders and developers migrating between versions.
Version 0.9 represents a fundamental philosophical shift from "Structured Output First" to "Prompt First."
| Feature | v0.8.1 | v0.9 |
|---|---|---|
| Philosophy | Structured Output / Function Calling | Prompt-First / In-Context Schema |
| Message Types | beginRendering, surfaceUpdate, ... | createSurface, updateComponents, ... |
| Surface Creation | Explicit beginRendering | Explicit createSurface |
| Component Type | Key-based wrapper ({"Text": ...}) | Property-based discriminator ("component": "Text") |
| Data Model Update | Array of Key-Value Pairs | Standard JSON Object |
| Data Binding | dataBinding / literalString | path / Native JSON types |
| Button Context | Array of Key-Value pairs | Standard JSON Object |
| Button Variant | Boolean (primary: true) | Enum (variant: "primary") |
| Catalog | Separate component and function catalogs | Unified Catalog (basic_catalog.json) |
| Auxiliary Rules | N/A | basic_catalog_rules.txt |
| Validation | Basic Schema | Strict ValidationFailed feedback loop |
| Data Synchronization | Implicit | Explicit Client->Server data syncing (sendDataModel) |
v0.8.1:
server_to_client.json often contained deep definitions or relied on complex oneOf structures that were hard to decompose.basic_catalog_definition.json existed but was often implicitly coupled.v0.9:
common_types.json: Reusable primitives (IDs, paths) and logic/expression types.server_to_client.json: The "envelope" defining the message types.basic_catalog.json: The unified catalog of UI components and functions.server_to_client.json now uses a relative reference to catalog.json as a placeholder. This allows developers to alias catalog.json to basic_catalog.json (or any custom catalog) during validation, enabling the use of custom component sets without modifying the core envelope schema.v0.8.1:
surfaceUpdate were optional keys.v0.9:
oneOf constraint in server_to_client.json.v0.9:
basic_catalog_rules.txt.beginRendering Replaced by createSurfacev0.8.1 (beginRendering):
beginRendering message to tell the client "I am done sending the initial batch of components, you can draw now."v0.9 (createSurface):
beginRendering is REPLACED by createSurface.createSurface signals the client to create a new surface and prepare for rendering.createSurface includes a theme property to specify theme parameters (like primaryColor). This replaces the styles property in v0.8.ComponentId 'root'." The "root" attribute that beginRendering had has been removed. The client is expected to render as soon as it has a valid tree with a root component.createSurface now requires a catalogId (URI) to explicitly state which unified catalog (components and functions) is being used.Example:
v0.8.1 (beginRendering):
{
"beginRendering": {
"surfaceId": "user_profile_card",
"root": "root",
"styles": {
"primaryColor": "#007bff"
}
}
}
v0.9 (createSurface):
{
"version": "v0.9",
"createSurface": {
"surfaceId": "user_profile_card",
"catalogId": "https://a2ui.org/specification/v0_9/basic_catalog.json",
"theme": {
"primaryColor": "#007bff"
}
}
}
v0.8.1 (surfaceUpdate):
{ "id": "...", "component": { "Text": { "text": "..." } } }v0.9 (updateComponents):
surfaceUpdate -> updateComponents.component.{ "id": "...", "component": "Text", "text": "..." }component: "Text") is much easier for LLMs to generate consistently than a dynamic key ("Text": {...}). It also simplifies polymorphism in many JSON parsers.Specifying an unknown surfaceId will cause an error. It is recommended that clients implement a namespacing scheme internally to prevent separate agents from creating surfaces with the same ID, and to prevent agents from modifying surfaces created by other agents.
v0.8.1:
{
"surfaceUpdate": {
"surfaceId": "main",
"components": [
{
"id": "title",
"component": {
"Text": { "text": { "literalString": "Hello" } }
}
}
]
}
}
v0.9:
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Column",
"children": ["title"]
},
{
"id": "title",
"component": "Text",
"text": "Hello"
}
]
}
}
v0.8.1 (dataModelUpdate):
contents property was an array of key-value pair objects.valueString, valueNumber, valueBoolean.[{ "key": "name", "valueString": "Alice" }]v0.9 (updateDataModel):
dataModelUpdate -> updateDataModel.value property is now a standard JSON object.{ "name": "Alice" }pathv0.8.1:
dataBinding in childrenProperty templates.path in BoundValue objects.v0.9:
path.v0.8.1:
{ "literalString": "foo" } or { "path": "/foo" }.literalNumber, literalBoolean).v0.9:
DynamicString, DynamicNumber, etc. are defined in common_types.json.string OR { "path": "..." }.{ "text": "Hello" } is valid. { "value": { "path": "/msg" } } is valid. No need for { "text": { "literalString": "Hello" } }.v0.8.1:
{ "text": "static" } OR { "text": { "path": "/var" } }.v0.9:
formatString function, which supports ${expression} syntax for interpolation.${formatDate(value: ${/timestamp}, format: 'yyyy-MM-dd')}).${...} is ONLY supported within the formatString function. It is not supported in general for string properties, in order to strictly separate data binding definitions from static content.formatString function.v0.8.1:
v0.9:
createSurface introduced sendDataModel (boolean).updateDataModel using simple path/value pairs.sendDataModel is true, the client includes the full data model in every A2A message metadata.v0.8.1:
context: [{ "key": "id", "value": { "literalString": "123" } }]v0.9:
context: { "id": "123" }v0.8.1:
primary: true or primary: false.v0.9:
variant: "primary" or variant: "borderless".Text and Image) that use variant for styling hints. 'borderless' provides a standard way to represent clickable text or icons without a button-like frame.v0.8.1:
textFieldType (e.g., "email", "password").validationRegexp.v0.9:
variant.checks (generic list of function calls).Text and Image components which already used variant. Validation is now more flexible and reusable. Also, text was renamed to value to match other input components.v0.8.1:
MultipleChoice.selections (typed wrapper), maxAllowedSelections (integer).v0.9:
ChoicePicker.value (array), variant (enum: multipleSelection, mutuallyExclusive). The maxAllowedSelections property was removed.ChoicePicker is a more generic name that covers both radio buttons (mutually exclusive) and checkboxes (multiple selection). The variant controls the behavior, simplifying the component surface area.v0.8.1:
minValue, maxValue.v0.9:
min, max.v0.9 introduces a strict ValidationFailed error format in client_to_server.json.
Purpose: To allow the "Prompt-Generate-Validate" loop to work effectively.
Mechanism: If the LLM generates invalid JSON, the system sends back a structured error:
{
"error": {
"code": "VALIDATION_FAILED",
"surfaceId": "...",
"path": "/components/0/text",
"message": "Expected string, got number"
}
}
Result: The LLM sees this and can "self-correct" in the next turn.
For developers migrating from earlier versions, here is a quick reference of property renaming:
| Component | Old Name | New Name |
|---|---|---|
| Row / Column | distribution | justify |
| Row / Column | alignment | align |
| Modal | entryPointChild | trigger |
| Modal | contentChild | content |
| Tabs | tabItems | tabs |
| TextField | text | value |
| Many | usageHint | variant |
| Client Message | userAction | action |
| Common Type | childrenProperty | ChildList |