Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions specification/v0_9/docs/a2ui_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ The following example demonstrates a complete interaction to render a Contact Fo

```jsonl
{"createSurface":{"surfaceId":"contact_form_1","catalogId":"https://a2ui.dev/specification/v0_9/standard_catalog.json"}}
{"updateComponents":{"surfaceId":"contact_form_1","components":[{"id":"root","component":"Card","child":"form_container"},{"id":"form_container","component":"Column","children":["header_row","name_row","email_group","phone_group","pref_group","divider_1","newsletter_checkbox","submit_button"],"justify":"start","align":"stretch"},{"id":"header_row","component":"Row","children":["header_icon","header_text"],"align":"center"},{"id":"header_icon","component":"Icon","name":"mail"},{"id":"header_text","component":"Text","text":"# Contact Us","variant":"h2"},{"id":"name_row","component":"Row","children":["first_name_group","last_name_group"],"justify":"spaceBetween"},{"id":"first_name_group","component":"Column","children":["first_name_label","first_name_field"],"weight":1},{"id":"first_name_label","component":"Text","text":"First Name","variant":"caption"},{"id":"first_name_field","component":"TextField","label":"First Name","value":{"path":"/contact/firstName"},"variant":"shortText"},{"id":"last_name_group","component":"Column","children":["last_name_label","last_name_field"],"weight":1},{"id":"last_name_label","component":"Text","text":"Last Name","variant":"caption"},{"id":"last_name_field","component":"TextField","label":"Last Name","value":{"path":"/contact/lastName"},"variant":"shortText"},{"id":"email_group","component":"Column","children":["email_label","email_field"]},{"id":"email_label","component":"Text","text":"Email Address","variant":"caption"},{"id":"email_field","component":"TextField","label":"Email","value":{"path":"/contact/email"},"variant":"shortText","checks":[{"call":"required","message":"Email is required."},{"call":"email","message":"Please enter a valid email address."}]},{"id":"phone_group","component":"Column","children":["phone_label","phone_field"]},{"id":"phone_label","component":"Text","text":"Phone Number","variant":"caption"},{"id":"phone_field","component":"TextField","label":"Phone","value":{"path":"/contact/phone"},"variant":"shortText","checks":[{"call":"regex","args":{"pattern":"^\\d{10}$"},"message":"Phone number must be 10 digits."}]},{"id":"pref_group","component":"Column","children":["pref_label","pref_picker"]},{"id":"pref_label","component":"Text","text":"Preferred Contact Method","variant":"caption"},{"id":"pref_picker","component":"ChoicePicker","variant":"mutuallyExclusive","options":[{"label":"Email","value":"email"},{"label":"Phone","value":"phone"},{"label":"SMS","value":"sms"}],"value":{"path":"/contact/preference"}},{"id":"divider_1","component":"Divider","axis":"horizontal"},{"id":"newsletter_checkbox","component":"CheckBox","label":"Subscribe to our newsletter","value":{"path":"/contact/subscribe"}},{"id":"submit_button_label","component":"Text","text":"Send Message"},{"id":"submit_button","component":"Button","child":"submit_button_label","primary":true,"action":{"name":"submitContactForm","context":{"formId":"contact_form_1","clientTime":{"call":"now","returnType":"string"},"isNewsletterSubscribed":{"path":"/contact/subscribe"}}}}]}}
{"updateComponents":{"surfaceId":"contact_form_1","components":[{"id":"root","component":"Card","child":"form_container"},{"id":"form_container","component":"Column","children":["header_row","name_row","email_group","phone_group","pref_group","divider_1","newsletter_checkbox","submit_button"],"justify":"start","align":"stretch"},{"id":"header_row","component":"Row","children":["header_icon","header_text"],"align":"center"},{"id":"header_icon","component":"Icon","name":"mail"},{"id":"header_text","component":"Text","text":"# Contact Us","variant":"h2"},{"id":"name_row","component":"Row","children":["first_name_group","last_name_group"],"justify":"spaceBetween"},{"id":"first_name_group","component":"Column","children":["first_name_label","first_name_field"],"weight":1},{"id":"first_name_label","component":"Text","text":"First Name","variant":"caption"},{"id":"first_name_field","component":"TextField","label":"First Name","value":{"path":"/contact/firstName"},"variant":"shortText"},{"id":"last_name_group","component":"Column","children":["last_name_label","last_name_field"],"weight":1},{"id":"last_name_label","component":"Text","text":"Last Name","variant":"caption"},{"id":"last_name_field","component":"TextField","label":"Last Name","value":{"path":"/contact/lastName"},"variant":"shortText"},{"id":"email_group","component":"Column","children":["email_label","email_field"]},{"id":"email_label","component":"Text","text":"Email Address","variant":"caption"},{"id":"email_field","component":"TextField","label":"Email","value":{"path":"/contact/email"},"variant":"shortText","checks":[{"call":"required","message":"Email is required."},{"call":"email","message":"Please enter a valid email address."}]},{"id":"phone_group","component":"Column","children":["phone_label","phone_field"]},{"id":"phone_label","component":"Text","text":"Phone Number","variant":"caption"},{"id":"phone_field","component":"TextField","label":"Phone","value":{"path":"/contact/phone"},"variant":"shortText","checks":[{"call":"regex","args":{"pattern":"^\\d{10}$"},"message":"Phone number must be 10 digits."}]},{"id":"pref_group","component":"Column","children":["pref_label","pref_picker"]},{"id":"pref_label","component":"Text","text":"Preferred Contact Method","variant":"caption"},{"id":"pref_picker","component":"ChoicePicker","variant":"mutuallyExclusive","options":[{"label":"Email","value":"email"},{"label":"Phone","value":"phone"},{"label":"SMS","value":"sms"}],"value":{"path":"/contact/preference"}},{"id":"divider_1","component":"Divider","axis":"horizontal"},{"id":"newsletter_checkbox","component":"CheckBox","label":"Subscribe to our newsletter","value":{"path":"/contact/subscribe"}},{"id":"submit_button_label","component":"Text","text":"Send Message"},{"id":"submit_button","component":"Button","child":"submit_button_label","variant":"primary","action":{"name":"submitContactForm","context":{"formId":"contact_form_1","clientTime":{"call":"now","returnType":"string"},"isNewsletterSubscribed":{"path":"/contact/subscribe"}}}}]}}
{"updateDataModel":{"surfaceId":"contact_form_1","path":"/contact","value":{"firstName":"John","lastName":"Doe"}}}
{"deleteSurface":{"surfaceId":"contact_form_1"}}
```
Expand Down Expand Up @@ -561,7 +561,7 @@ The [`standard_catalog.json`] provides the baseline set of components and functi
| **Tabs** | A set of tabs, each with a title and child component. |
| **Divider** | A horizontal or vertical dividing line. |
| **Modal** | A dialog that appears over the main content triggered by a button in the main content. |
| **Button** | A clickable button that dispatches an action. |
| **Button** | A clickable button that dispatches an action. Supports 'primary' and 'borderless' variants. |
| **CheckBox** | A checkbox with a label and a boolean value. |
| **TextField** | A field for user text input. |
| **DateTimeInput** | An input for date and/or time. |
Expand Down
43 changes: 28 additions & 15 deletions specification/v0_9/docs/evolution_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ Version 0.9 represents a fundamental philosophical shift from "Structured Output

### Summary Table

| 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 |
| **Catalog** | Separate component and function catalogs | Unified Catalog (`standard_catalog.json`) |
| **Auxiliary Rules** | N/A | `standard_catalog_rules.txt` |
| **Validation** | Basic Schema | Strict `ValidationFailed` feedback loop |
| 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 (`standard_catalog.json`) |
| **Auxiliary Rules** | N/A | `standard_catalog_rules.txt` |
| **Validation** | Basic Schema | Strict `ValidationFailed` feedback loop |
| **Data Synchronization** | Implicit | Explicit Client->Server data syncing (`attachDataModel`) |

## 2. Architectural & Schema Changes
Expand Down Expand Up @@ -256,7 +257,19 @@ Specifying an unknown surfaceId will cause an error. It is recommended that clie
- **Standard Map**: `context: { "id": "123" }`
- **Reason**: Token efficiency. LLMs understand JSON objects as maps natively.

### 6.2. TextField
### 6.2. Button Variant

**v0.8.1:**

- **Boolean**: `primary: true` or `primary: false`.
- **Limited**: Only two styles were explicitly supported.

**v0.9:**

- **Enum**: `variant: "primary"` or `variant: "borderless"`.
- **Reason**: More flexible and consistent with other components (like `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.

### 6.3. TextField

**v0.8.1:**

Expand All @@ -269,7 +282,7 @@ Specifying an unknown surfaceId will cause an error. It is recommended that clie
- Validation: **`checks`** (generic list of function calls).
- **Reason**: Consistency with `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.

### 6.3. ChoicePicker (vs MultipleChoice)
### 6.4. ChoicePicker (vs MultipleChoice)

**v0.8.1:**

Expand All @@ -282,7 +295,7 @@ Specifying an unknown surfaceId will cause an error. It is recommended that clie
- Properties: **`value`** (array), **`variant`** (enum: `multipleSelection`, `mutuallyExclusive`). The `maxAllowedSelections` property was removed.
- **Reason**: `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.

### 6.4. Slider
### 6.5. Slider

**v0.8.1:**

Expand Down
7 changes: 4 additions & 3 deletions specification/v0_9/json/standard_catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -415,9 +415,10 @@
"type": "string",
"description": "The ID of the child component. Use a 'Text' component for a labeled button. Only use an 'Icon' if the requirements explicitly ask for an icon-only button. Do NOT define the child component inline."
},
"primary": {
"type": "boolean",
"description": "Indicates if this button should be styled as the primary action."
"variant": {
"type": "string",
"description": "A hint for the button style. If omitted, a default button style is used. 'primary' indicates this is the main call-to-action button. 'borderless' means the button has no visual border or background, making its child content appear like a clickable link.",
"enum": ["primary", "borderless"]
},
"action": {
"type": "object",
Expand Down
57 changes: 57 additions & 0 deletions specification/v0_9/test/cases/button_checks.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,63 @@
]
}
}
},
{
"description": "Button with variant 'primary'",
"valid": true,
"data": {
"updateComponents": {
"surfaceId": "test_surface",
"components": [
{
"id": "btn_primary",
"component": "Button",
"child": "txt_primary",
"action": { "name": "submit" },
"variant": "primary"
},
{ "id": "txt_primary", "component": "Text", "text": "Submit" }
]
}
}
},
{
"description": "Button with variant 'borderless'",
"valid": true,
"data": {
"updateComponents": {
"surfaceId": "test_surface",
"components": [
{
"id": "btn_borderless",
"component": "Button",
"child": "txt_borderless",
"action": { "name": "cancel" },
"variant": "borderless"
},
{ "id": "txt_borderless", "component": "Text", "text": "Cancel" }
]
}
}
},
{
"description": "Button with deprecated 'primary' property (should fail)",
"valid": false,
"data": {
"updateComponents": {
"surfaceId": "test_surface",
"components": [
{
"id": "btn_dep",
"component": "Button",
"child": "txt_dep",
"action": { "name": "submit" },
"primary": true
},
{ "id": "txt_dep", "component": "Text", "text": "Submit" }
]
}
}
}
]
}
Loading
Loading