Skip to content

Commit 519a672

Browse files
committed
docs: Align documentation with v0.9 specification
- Replaced legacy v0.8 terminology (e.g., `beginRendering` -> `createSurface`, `usageHint` -> `variant`). - Updated schema examples for components and messages throughout the documentation. - Migrated legacy documentation to `docs/v0_8/` archive. - Updated guides and concepts to reflect v0.9 changes. - Add 'fit' and 'variant' properties to Image component documentation. - Clarify 'updateDataModel' value optionality (omission implies deletion). - Add new 'Client-Side Functions' reference page and link it. - Mention client-side formatting in best practices.
1 parent 1c20b8c commit 519a672

25 files changed

+618
-528
lines changed

docs/concepts/components.md

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ A2UI uses an **adjacency list model** for component hierarchies. Instead of nest
2121

2222
```json
2323
{
24-
"surfaceUpdate": {
24+
"version": "v0.9",
25+
"updateComponents": {
26+
"surfaceId": "main",
2527
"components": [
26-
{"id": "root", "component": {"Column": {"children": {"explicitList": ["greeting", "buttons"]}}}},
27-
{"id": "greeting", "component": {"Text": {"text": {"literalString": "Hello"}}}},
28-
{"id": "buttons", "component": {"Row": {"children": {"explicitList": ["cancel-btn", "ok-btn"]}}}},
29-
{"id": "cancel-btn", "component": {"Button": {"child": "cancel-text", "action": {"name": "cancel"}}}},
30-
{"id": "cancel-text", "component": {"Text": {"text": {"literalString": "Cancel"}}}},
31-
{"id": "ok-btn", "component": {"Button": {"child": "ok-text", "action": {"name": "ok"}}}},
32-
{"id": "ok-text", "component": {"Text": {"text": {"literalString": "OK"}}}}
28+
{"id": "root", "component": "Column", "children": ["greeting", "buttons"]},
29+
{"id": "greeting", "component": "Text", "text": "Hello"},
30+
{"id": "buttons", "component": "Row", "children": ["cancel-btn", "ok-btn"]},
31+
{"id": "cancel-btn", "component": "Button", "child": "cancel-text", "action": {"name": "cancel"}},
32+
{"id": "cancel-text", "component": "Text", "text": "Cancel"},
33+
{"id": "ok-btn", "component": "Button", "child": "ok-text", "action": {"name": "ok"}},
34+
{"id": "ok-text", "component": "Text", "text": "OK"}
3335
]
3436
}
3537
}
@@ -46,7 +48,7 @@ Every component has:
4648
3. **Properties**: Configuration specific to that type
4749

4850
```json
49-
{"id": "welcome", "component": {"Text": {"text": {"literalString": "Hello"}, "usageHint": "h1"}}}
51+
{"id": "welcome", "component": "Text", "text": "Hello", "variant": "h1"}
5052
```
5153

5254
## The Standard Catalog
@@ -62,14 +64,14 @@ For the complete component gallery with examples, see [Component Reference](../r
6264

6365
## Static vs. Dynamic Children
6466

65-
**Static (`explicitList`)** - Fixed list of child IDs:
67+
**Static (`children` array)** - Fixed list of child IDs:
6668
```json
67-
{"children": {"explicitList": ["back-btn", "title", "menu-btn"]}}
69+
{"children": ["back-btn", "title", "menu-btn"]}
6870
```
6971

70-
**Dynamic (`template`)** - Generate children from data array:
72+
**Dynamic (`children` template)** - Generate children from data array:
7173
```json
72-
{"children": {"template": {"dataBinding": "/items", "componentId": "item-template"}}}
74+
{"children": {"template": {"path": "/items", "componentId": "item-template"}}}
7375
```
7476

7577
For each item in `/items`, render the `item-template`. See [Data Binding](data-binding.md) for details.
@@ -78,26 +80,26 @@ For each item in `/items`, render the `item-template`. See [Data Binding](data-b
7880

7981
Components get their values two ways:
8082

81-
- **Literal** - Fixed value: `{"text": {"literalString": "Welcome"}}`
82-
- **Data-bound** - From data model: `{"text": {"path": "/user/name"}}`
83-
84-
LLMs can generate components with literal values or bind them to data paths for dynamic content.
85-
86-
## Composing Surfaces
87-
88-
Components compose into **surfaces** (widgets):
89-
90-
1. LLM generates component definitions via `surfaceUpdate`
91-
2. LLM populates data via `dataModelUpdate`
92-
3. LLM signals render via `beginRendering`
93-
4. Client renders all components as native widgets
94-
95-
A surface is a complete, cohesive UI (form, dashboard, chat, etc.).
96-
97-
## Incremental Updates
98-
99-
- **Add** - Send new `surfaceUpdate` with new component IDs
100-
- **Update** - Send `surfaceUpdate` with existing ID and new properties
83+
81: - **Literal** - Fixed value: `{"text": "Welcome"}`
84+
82: - **Data-bound** - From data model: `{"text": {"path": "/user/name"}}`
85+
83:
86+
84: LLMs can generate components with literal values or bind them to data paths.
87+
85:
88+
86: ## Composing Surfaces
89+
87:
90+
88: Components compose into **surfaces** (widgets):
91+
89:
92+
90: 1. LLM generates component definitions via `updateComponents`
93+
91: 2. LLM populates data via `updateDataModel`
94+
92: 3. LLM signals render via `createSurface`
95+
93: 4. Client renders all components as native widgets
96+
94:
97+
95: A surface is a complete, cohesive UI (form, dashboard, chat, etc.).
98+
96:
99+
97: ## Incremental Updates
100+
98:
101+
99: - **Add** - Send new `updateComponents` with new component IDs
102+
100: - **Update** - Send `updateComponents` with existing ID and new properties
101103
- **Remove** - Update parent's `children` list to exclude removed IDs
102104

103105
The flat structure makes all updates simple ID-based operations.

docs/concepts/data-binding.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,19 @@ Each surface has a JSON object holding state:
4040
```
4141

4242
- `/user/name``"Alice"`
43-
- `/items/0``"Apple"`
43+
- `/user/name``"Alice"`
44+
- `/items/0``"Apple"`
4445

4546
## Literal vs. Path Values
4647

4748
**Literal (fixed):**
4849
```json
49-
{"id": "title", "component": {"Text": {"text": {"literalString": "Welcome"}}}}
50+
{"id": "title", "component": "Text", "text": "Welcome"}
5051
```
5152

5253
**Data-bound (reactive):**
5354
```json
54-
{"id": "username", "component": {"Text": {"text": {"path": "/user/name"}}}}
55+
{"id": "username", "component": "Text", "text": {"path": "/user/name"}}
5556
```
5657

5758
When `/user/name` changes from "Alice" to "Bob", the text **automatically updates** to "Bob".
@@ -61,11 +62,11 @@ When `/user/name` changes from "Alice" to "Bob", the text **automatically update
6162
Components bound to data paths automatically update when the data changes:
6263

6364
```json
64-
{"id": "status", "component": {"Text": {"text": {"path": "/order/status"}}}}
65+
{"id": "status", "component": "Text", "text": {"path": "/order/status"}}
6566
```
6667

67-
- **Initial:** `/order/status` = "Processing..." → displays "Processing..."
68-
- **Update:** Send `dataModelUpdate` with `status: "Shipped"` → displays "Shipped"
68+
- **Initial:** `/order/status` = "Processing..." → displays "Processing..."
69+
- **Update:** Send `updateDataModel` with `status: "Shipped"` → displays "Shipped"
6970

7071
No component updates needed—just data updates.
7172

@@ -76,11 +77,8 @@ Use templates to render arrays:
7677
```json
7778
{
7879
"id": "product-list",
79-
"component": {
80-
"Column": {
81-
"children": {"template": {"dataBinding": "/products", "componentId": "product-card"}}
82-
}
83-
}
80+
"component": "Column",
81+
"children": {"template": {"path": "/products", "componentId": "product-card"}}
8482
}
8583
```
8684

@@ -96,11 +94,11 @@ Use templates to render arrays:
9694
Inside a template, paths are scoped to the array item:
9795

9896
```json
99-
{"id": "product-name", "component": {"Text": {"text": {"path": "/name"}}}}
97+
{"id": "product-name", "component": "Text", "text": {"path": "/name"}}
10098
```
10199

102-
- For `/products/0`, `/name` resolves to `/products/0/name` → "Widget"
103-
- For `/products/1`, `/name` resolves to `/products/1/name` → "Gadget"
100+
- For `/products/0`, `/name` resolves to `/products/0/name` → "Widget"
101+
- For `/products/1`, `/name` resolves to `/products/1/name` → "Gadget"
104102

105103
Adding/removing items automatically updates the rendered components.
106104

@@ -110,15 +108,15 @@ Interactive components update the data model bidirectionally:
110108

111109
| Component | Example | User Action | Data Update |
112110
|-----------|---------|-------------|-------------|
113-
| **TextField** | `{"text": {"path": "/form/name"}}` | Types "Alice" | `/form/name` = "Alice" |
111+
| **TextField** | `{"value": {"path": "/form/name"}}` | Types "Alice" | `/form/name` = "Alice" |
114112
| **CheckBox** | `{"value": {"path": "/form/agreed"}}` | Checks box | `/form/agreed` = true |
115-
| **MultipleChoice** | `{"selections": {"path": "/form/country"}}` | Selects "Canada" | `/form/country` = ["ca"] |
113+
| **ChoicePicker** | `{"value": {"path": "/form/country"}}` | Selects "Canada" | `/form/country` = ["ca"] |
116114

117115
## Best Practices
118116

119117
**1. Use granular updates** - Update only changed paths:
120118
```json
121-
{"dataModelUpdate": {"path": "/user", "contents": [{"key": "name", "valueString": "Alice"}]}}
119+
{"version": "v0.9", "updateDataModel": {"surfaceId": "main", "path": "/user", "value": {"name": "Alice"}}}
122120
```
123121

124122
**2. Organize by domain** - Group related data:
@@ -130,3 +128,9 @@ Interactive components update the data model bidirectionally:
130128
```json
131129
{"price": "$19.99"} // Not: {"price": 19.99}
132130
```
131+
132+
**4. Use Client-Side Formatting** - For dynamic localization or complex updates, use client-side functions:
133+
```json
134+
{"text": {"call": "formatCurrency", "args": {"value": 19.99, "currency": "USD"}}}
135+
```
136+
See the **[Functions Reference](../reference/functions.md)** for a complete list of available functions.

docs/concepts/data-flow.md

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ Client (Stream Reader) → Message Parser → Renderer → Native UI
1717
A2UI defines a sequence of JSON messages that describe the UI. When streamed, these messages are often formatted as **JSON Lines (JSONL)**, where each line is a complete JSON object.
1818

1919
```jsonl
20-
{"surfaceUpdate":{"surfaceId":"main","components":[...]}}
21-
{"dataModelUpdate":{"surfaceId":"main","contents":[{"key":"user","valueMap":[{"key":"name","valueString":"Alice"}]}]}}
22-
{"beginRendering":{"surfaceId":"main","root":"root-component"}}
20+
{"version": "v0.9", "createSurface": {"surfaceId": "main", "catalogId": "..."}}
21+
{"version": "v0.9", "updateComponents": {"surfaceId": "main", "components": [...]}}
22+
{"version": "v0.9", "updateDataModel": {"surfaceId": "main", "value": {"user": "Alice"}}}
2323
```
2424

2525
**Why this format?**
@@ -30,41 +30,55 @@ A sequence of self-contained JSON objects is streaming-friendly, easy for LLMs t
3030

3131
**User:** "Book a table for 2 tomorrow at 7pm"
3232

33-
**1. Agent defines UI structure:**
33+
**1. Agent signals render (v0.9 starts with creation):**
3434

3535
```json
36-
{"surfaceUpdate": {"surfaceId": "booking", "components": [
37-
{"id": "root", "component": {"Column": {"children": {"explicitList": ["header", "guests-field", "submit-btn"]}}}},
38-
{"id": "header", "component": {"Text": {"text": {"literalString": "Confirm Reservation"}, "usageHint": "h1"}}},
39-
{"id": "guests-field", "component": {"TextField": {"label": {"literalString": "Guests"}, "text": {"path": "/reservation/guests"}}}},
40-
{"id": "submit-btn", "component": {"Button": {"child": "submit-text", "action": {"name": "confirm", "context": [{"key": "details", "value": {"path": "/reservation"}}]}}}}
41-
]}}
36+
{"version": "v0.9", "createSurface": {"surfaceId": "booking", "catalogId": "https://a2ui.org/specification/v0_9/standard_catalog.json"}}
4237
```
4338

44-
**2. Agent populates data:**
39+
**2. Agent defines UI structure:**
4540

4641
```json
47-
{"dataModelUpdate": {"surfaceId": "booking", "path": "/reservation", "contents": [
48-
{"key": "datetime", "valueString": "2025-12-16T19:00:00Z"},
49-
{"key": "guests", "valueString": "2"}
50-
]}}
42+
{
43+
"version": "v0.9",
44+
"updateComponents": {
45+
"surfaceId": "booking",
46+
"components": [
47+
{"id": "root", "component": "Column", "children": ["header", "guests-field", "submit-btn"]},
48+
{"id": "header", "component": "Text", "text": "Confirm Reservation", "variant": "h1"},
49+
{"id": "guests-field", "component": "TextField", "label": "Guests", "value": {"path": "/reservation/guests"}},
50+
{"id": "submit-btn", "component": "Button", "child": "submit-text", "action": {"name": "confirm", "context": {"path": "/reservation"}}},
51+
{"id": "submit-text", "component": "Text", "text": "Confirm"}
52+
]
53+
}
54+
}
5155
```
5256

53-
**3. Agent signals render:**
57+
**3. Agent populates data:**
5458

5559
```json
56-
{"beginRendering": {"surfaceId": "booking", "root": "root"}}
60+
{
61+
"version": "v0.9",
62+
"updateDataModel": {
63+
"surfaceId": "booking",
64+
"path": "/reservation",
65+
"value": {
66+
"datetime": "2025-12-16T19:00:00Z",
67+
"guests": 2
68+
}
69+
}
70+
}
5771
```
5872

5973
**4. User edits guests to "3"** → Client updates `/reservation/guests` automatically (no message to agent yet)
6074

6175
**5. User clicks "Confirm"** → Client sends action with updated data:
6276

6377
```json
64-
{"userAction": {"name": "confirm", "surfaceId": "booking", "context": {"details": {"datetime": "2025-12-16T19:00:00Z", "guests": "3"}}}}
78+
{"action": {"name": "confirm", "surfaceId": "booking", "context": {"datetime": "2025-12-16T19:00:00Z", "guests": 3}}}
6579
```
6680

67-
**6. Agent responds** → Updates UI or sends `{"deleteSurface": {"surfaceId": "booking"}}` to clean up
81+
**6. Agent responds** → Updates UI or sends `{"version": "v0.9", "deleteSurface": {"surfaceId": "booking"}}` to clean up
6882

6983
## Transport Options
7084

docs/concepts/overview.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ How components connect to application state using JSON Pointer paths. Covers rea
2525

2626
A2UI uses four message types:
2727

28-
- **`surfaceUpdate`**: Define or update UI components
29-
- **`dataModelUpdate`**: Update application state
30-
- **`beginRendering`**: Signal the client to render
28+
- **`createSurface`**: Initialize a surface and catalog
29+
- **`updateComponents`**: Define or update UI components
30+
- **`updateDataModel`**: Update application state
3131
- **`deleteSurface`**: Remove a UI surface
3232

3333
For complete technical details, see [Message Reference](../reference/messages.md).

docs/guides/agent-development.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ root_agent = Agent(
7676
)
7777
```
7878

79-
Don't forget to set the `GOOGLE_API_KEY` environment variable to run this example.
79+
Don't forget to set the `GOOGLE_API_KEY` environment variable to run this example.
8080

8181
```bash
8282
echo 'GOOGLE_API_KEY="YOUR_API_KEY"' > .env
@@ -92,7 +92,7 @@ Select `my_agent` from the list, and ask questions about restaurants in New York
9292

9393
## Generating A2UI Messages
9494

95-
Getting the LLM to generate A2UI messages requires some prompt engineering.
95+
Getting the LLM to generate A2UI messages requires some prompt engineering.
9696

9797
> ⚠️ **Attention**
9898
>
@@ -131,7 +131,7 @@ To generate the response, you MUST follow these rules:
131131
4. The JSON part MUST validate against the A2UI JSON SCHEMA provided below.
132132
133133
--- UI TEMPLATE RULES ---
134-
- If the query is for a list of restaurants, use the restaurant data you have already received from the `get_restaurants` tool to populate the `dataModelUpdate.contents` array (e.g., as a `valueMap` for the "items" key).
134+
- If the query is for a list of restaurants, use the restaurant data you have already received from the `get_restaurants` tool to populate the `updateDataModel.contents` object (e.g., set the "items" key to the list of restaurants).
135135
- If the number of restaurants is 5 or fewer, you MUST use the `SINGLE_COLUMN_LIST_EXAMPLE` template.
136136
- If the number of restaurants is more than 5, you MUST use the `TWO_COLUMN_LIST_EXAMPLE` template.
137137
- If the query is to book a restaurant (e.g., "USER_WANTS_TO_BOOK..."), you MUST use the `BOOKING_FORM_EXAMPLE` template.
@@ -159,8 +159,9 @@ Your agent will no longer strictly output text. Instead, it will output text and
159159

160160
The `A2UI_SCHEMA` that we imported is a standard JSON schema that defines valid operations like:
161161

162-
* `render` (displaying a UI)
163-
* `update` (changing data in an existing UI)
162+
* `createSurface` (displaying a UI)
163+
* `updateComponents` (changing the UI structure)
164+
* `updateDataModel` (changing data in an existing UI)
164165

165166
Because the output is structured JSON, you may parse and validate it before sending it to the client.
166167

docs/guides/client-setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ TODO: Add action handling examples.
9494
## Error Handling
9595

9696
Common errors to handle:
97-
- **Invalid Surface ID**: Surface referenced before `beginRendering` was received
97+
- **Invalid Surface ID**: Surface referenced before `createSurface` was received
9898
- **Invalid Component ID**: Component IDs must be unique within a surface
9999
- **Invalid Data Path**: Check data model structure and JSON Pointer syntax
100100
- **Schema Validation Failed**: Verify message format matches A2UI specification

docs/guides/custom-components.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ You register entire catalogs with your client application, not individual compon
2323
2. **Client Registers Catalog**: You register the catalog (and its component implementations) with your client app.
2424
3. **Client Announces Support**: The client informs the agent which catalogs it supports.
2525
4. **Agent Selects Catalog**: The agent chooses a catalog for a given UI surface.
26-
5. **Agent Generates UI**: The agent generates `surfaceUpdate` messages using components from that catalog by name.
26+
5. **Agent Generates UI**: The agent generates `updateComponents` messages using components from that catalog by name.
2727

2828
## Defining Custom Catalogs
2929

@@ -45,9 +45,9 @@ TODO: Add detailed guide for defining custom catalogs for each platform.
4545

4646
## Agent-Side: Using Components from a Custom Catalog
4747

48-
Once a catalog is registered on the client, agents can use components from it in `surfaceUpdate` messages.
48+
Once a catalog is registered on the client, agents can use components from it in `updateComponents` messages.
4949

50-
The agent specifies which catalog to use via the `catalogId` in the `beginRendering` message.
50+
The agent specifies which catalog to use via the `catalogId` in the `createSurface` message.
5151

5252
TODO: Add examples of:
5353
- How agents select catalogs

0 commit comments

Comments
 (0)