diff --git a/specification/v1_0/catalogs/basic/catalog.json b/specification/v1_0/catalogs/basic/catalog.json index ad070a4e8..d0fd59744 100644 --- a/specification/v1_0/catalogs/basic/catalog.json +++ b/specification/v1_0/catalogs/basic/catalog.json @@ -12,9 +12,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -30,6 +27,10 @@ "description": "A hint for the base text style.", "enum": ["caption", "body"], "default": "body" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "text"] @@ -43,9 +44,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -71,6 +69,10 @@ "description": "A hint for the image size and style.", "enum": ["icon", "avatar", "smallFeature", "mediumFeature", "largeFeature", "header"], "default": "mediumFeature" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "url"] @@ -84,9 +86,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -171,6 +170,10 @@ "additionalProperties": false } ] + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "name"] @@ -184,9 +187,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -200,6 +200,10 @@ "posterUrl": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString", "description": "The URL of the poster image to display before the video plays." + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "url"] @@ -213,9 +217,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -229,6 +230,10 @@ "description": { "description": "A description of the audio, such as a title or summary.", "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "url"] @@ -242,9 +247,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "description": "A layout component that arranges its children horizontally. To create a grid layout, nest Columns within this Row.", @@ -275,6 +277,10 @@ "description": "Defines the alignment of children along the cross axis (vertically). This is similar to the CSS 'align-items' property, but uses camelCase values (e.g., 'start').", "enum": ["start", "center", "end", "stretch"], "default": "stretch" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "children"] @@ -288,9 +294,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "description": "A layout component that arranges its children vertically. To create a grid layout, nest Rows within this Column.", @@ -321,6 +324,10 @@ "description": "Defines the alignment of children along the cross axis (horizontally). This is similar to the CSS 'align-items' property.", "enum": ["center", "end", "start", "stretch"], "default": "stretch" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "children"] @@ -334,9 +341,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -358,6 +362,10 @@ "description": "Defines the alignment of children along the cross axis.", "enum": ["start", "center", "end", "stretch"], "default": "stretch" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "children"] @@ -371,9 +379,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -383,6 +388,10 @@ "child": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentId", "description": "The ID of the single child component to be rendered inside the card. To display multiple elements, you MUST wrap them in a layout component (like Column or Row) and pass that container's ID here. Do NOT pass multiple IDs or a non-existent ID. Do NOT define the child component inline." + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "child"] @@ -396,9 +405,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -424,6 +430,10 @@ "required": ["title", "child"], "additionalProperties": false } + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "tabs"] @@ -437,9 +447,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -453,6 +460,10 @@ "content": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentId", "description": "The ID of the component to be displayed inside the modal. Do NOT define the component inline." + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "trigger", "content"] @@ -466,9 +477,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "type": "object", "properties": { @@ -480,6 +488,10 @@ "description": "The orientation of the divider.", "enum": ["horizontal", "vertical"], "default": "horizontal" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component"] @@ -493,9 +505,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" }, @@ -517,6 +526,10 @@ }, "action": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Action" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "child", "action"] @@ -530,9 +543,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" }, @@ -559,6 +569,10 @@ "description": "The type of input field to display.", "enum": ["longText", "number", "shortText", "obscured"], "default": "shortText" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "label"] @@ -572,9 +586,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" }, @@ -591,6 +602,10 @@ "value": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicBoolean", "description": "The current state of the checkbox (true for checked, false for unchecked)." + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "label", "value"] @@ -604,9 +619,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" }, @@ -660,6 +672,10 @@ "type": "boolean", "description": "If true, displays a search input to filter the options.", "default": false + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "options", "value"] @@ -673,9 +689,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" }, @@ -706,6 +719,10 @@ "type": "integer", "minimum": 1, "description": "The number of discrete divisions in the slider range. If specified, the slider will snap to discrete values." + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "value", "max"] @@ -719,9 +736,6 @@ { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" }, - { - "$ref": "#/$defs/CatalogComponentCommon" - }, { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" }, @@ -800,6 +814,10 @@ "label": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString", "description": "The text label for the input field." + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "value"] @@ -1222,15 +1240,6 @@ } }, "$defs": { - "CatalogComponentCommon": { - "type": "object", - "properties": { - "weight": { - "type": "number", - "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." - } - } - }, "surfaceProperties": { "type": "object", "properties": { diff --git a/specification/v1_0/catalogs/minimal/catalog.json b/specification/v1_0/catalogs/minimal/catalog.json index 7b1bc39bf..42b29fac3 100644 --- a/specification/v1_0/catalogs/minimal/catalog.json +++ b/specification/v1_0/catalogs/minimal/catalog.json @@ -8,18 +8,25 @@ "Text": { "type": "object", "allOf": [ - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon"}, - {"$ref": "#/$defs/CatalogComponentCommon"}, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" + }, { "type": "object", "properties": { - "component": {"const": "Text"}, + "component": { + "const": "Text" + }, "text": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString" }, "variant": { "type": "string", "enum": ["caption", "body"] + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "text"] @@ -30,12 +37,15 @@ "Row": { "type": "object", "allOf": [ - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon"}, - {"$ref": "#/$defs/CatalogComponentCommon"}, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" + }, { "type": "object", "properties": { - "component": {"const": "Row"}, + "component": { + "const": "Row" + }, "children": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ChildList" }, @@ -54,6 +64,10 @@ "align": { "type": "string", "enum": ["start", "center", "end", "stretch"] + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "children"] @@ -64,12 +78,15 @@ "Column": { "type": "object", "allOf": [ - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon"}, - {"$ref": "#/$defs/CatalogComponentCommon"}, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" + }, { "type": "object", "properties": { - "component": {"const": "Column"}, + "component": { + "const": "Column" + }, "children": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ChildList" }, @@ -88,6 +105,10 @@ "align": { "type": "string", "enum": ["center", "end", "start", "stretch"] + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "children"] @@ -98,13 +119,18 @@ "Button": { "type": "object", "allOf": [ - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon"}, - {"$ref": "#/$defs/CatalogComponentCommon"}, - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable"}, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" + }, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" + }, { "type": "object", "properties": { - "component": {"const": "Button"}, + "component": { + "const": "Button" + }, "child": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentId" }, @@ -114,6 +140,10 @@ }, "action": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Action" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." } }, "required": ["component", "child", "action"] @@ -124,13 +154,18 @@ "TextField": { "type": "object", "allOf": [ - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon"}, - {"$ref": "#/$defs/CatalogComponentCommon"}, - {"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable"}, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon" + }, + { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Checkable" + }, { "type": "object", "properties": { - "component": {"const": "TextField"}, + "component": { + "const": "TextField" + }, "label": { "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString" }, @@ -141,7 +176,13 @@ "type": "string", "enum": ["longText", "number", "shortText", "obscured"] }, - "validationRegexp": {"type": "string"} + "validationRegexp": { + "type": "string" + }, + "weight": { + "type": "number", + "description": "The relative weight of this component within a Row or Column. This is similar to the CSS 'flex-grow' property. Note: this may ONLY be set when the component is a direct descendant of a Row or Column." + } }, "required": ["component", "label"] } @@ -155,7 +196,9 @@ "description": "Converts an input string to a capitalized version.", "returnType": "string", "properties": { - "call": {"const": "capitalize"}, + "call": { + "const": "capitalize" + }, "args": { "type": "object", "properties": { @@ -172,12 +215,6 @@ } }, "$defs": { - "CatalogComponentCommon": { - "type": "object", - "properties": { - "weight": {"type": "number"} - } - }, "surfaceProperties": { "type": "object", "properties": {}, @@ -185,16 +222,32 @@ }, "anyComponent": { "oneOf": [ - {"$ref": "#/components/Text"}, - {"$ref": "#/components/Row"}, - {"$ref": "#/components/Column"}, - {"$ref": "#/components/Button"}, - {"$ref": "#/components/TextField"} + { + "$ref": "#/components/Text" + }, + { + "$ref": "#/components/Row" + }, + { + "$ref": "#/components/Column" + }, + { + "$ref": "#/components/Button" + }, + { + "$ref": "#/components/TextField" + } ], - "discriminator": {"propertyName": "component"} + "discriminator": { + "propertyName": "component" + } }, "anyFunction": { - "oneOf": [{"$ref": "#/functions/capitalize"}] + "oneOf": [ + { + "$ref": "#/functions/capitalize" + } + ] } } } diff --git a/specification/v1_0/docs/a2ui_protocol.md b/specification/v1_0/docs/a2ui_protocol.md index 265db473f..221297fce 100644 --- a/specification/v1_0/docs/a2ui_protocol.md +++ b/specification/v1_0/docs/a2ui_protocol.md @@ -473,6 +473,177 @@ To ensure complete cross-language compatibility across client SDKs, parsers, and - `1stItem` (violates initial `Nd`) - `submit-form`, `user#name`, `calc$val` (violates `Pattern_Syntax`) +#### Catalog Schema Rules and Conventions + +To ensure catalog schemas can be translated reliably into alternative, LLM-friendly DSL formats (e.g., HTML-like XML, functional, or compact inline formats), cleanly mapped to type-safe client SDK representations, automatically parsed, and bound seamlessly across platforms, all v1.0 component and function catalog definitions MUST conform to the following strict structural constraints and conventions: + +1. **Strict Top-Level vs. `$defs` Boundary:** + - **Top-Level components and functions:** All component and function schemas MUST be declared directly under the top-level keys `"components"` and `"functions"` respectively. + - **External References inside `$defs`:** Any definition referenced externally (e.g., from the envelope schema `server_to_client.json` or `common_types.json`) MUST reside inside the `"$defs"` object at the catalog root. This strictly includes: + - `surfaceProperties`: Referenced as `catalog.json#/$defs/surfaceProperties`. + - `anyComponent`: Referenced as `catalog.json#/$defs/anyComponent`. + - `anyFunction`: Referenced as `catalog.json#/$defs/anyFunction`. +2. **No Custom `$defs` or Helpers:** + - To prevent unconstrained branching, custom definitions or shared helper schemas inside a catalog are strictly prohibited under `"$defs"`. + - The only allowed keys within the catalog's `"$defs"` object are `anyComponent`, `anyFunction`, and `surfaceProperties`. + - All helper properties (such as common properties factored out of catalog items) MUST be inlined directly inside the properties block of each supporting component schema rather than referenced from a shared helper. +3. **Restricted `$ref` Targets:** + - Local `$ref` targets are restricted to referencing the catalog's top-level components or functions (e.g., `#/components/Text`, `#/functions/required`). + - External `$ref` targets MUST reference the standard types inside `common_types.json` (`https://a2ui.org/specification/v1_0/common_types.json#/$defs/...`), limited to the following allowed schemas: + - `ComponentId` + - `ChildList` + - `DynamicString` + - `DynamicNumber` + - `DynamicBoolean` + - `DynamicStringList` + - `DynamicValue` + - `CheckRule` + - `ComponentCommon` + - `Checkable` + - `Action` +4. **Component Discriminator Rule:** + - Every component schema defined inside the `components` map must have a required property named `component` whose value is a constant (`const`) matching the key under which it is defined. + - Example: The component defined at `components.Text` must declare: + ```json + "properties": { + "component": { + "const": "Text" + } + } + ``` + This enables route-dispatch matching via the `discriminator` block inside `anyComponent` (designating `"propertyName": "component"`). +5. **Standard Component Structure:** + - All components defined in the `components` object must use an `allOf` structure that combines: + 1. An external reference to the baseline identity and accessibility attributes: + `{"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon"}` + 2. A local object schema defining the unique properties of that specific component (e.g., its children, variant, specific layouts). +6. **Strict Function Interface Pattern:** + - Every function schema defined inside the `functions` map must validate a wire-level `FunctionCall` object. This requires: + - A `properties` block with a `call` property containing a constant of the function's name (e.g., `"call": { "const": "email" }`). + - An optional `args` property representing arguments (or absent if the function accepts no arguments). + - Mandatory metadata fields outside the strict JSON validation properties to advertise interface details: + - **`returnType`**: Must be a string enum indicating the return type (`string`, `number`, `boolean`, `array`, `object`, `any`, or `void`). + - **`callableFrom`**: Must be a string enum indicating the execution boundary (`clientOnly`, `remoteOnly`, or `clientOrRemote`). If omitted, it defaults to `clientOnly`. +7. **Strict Top-Level Schema Keys:** + - To keep catalog schemas predictable and prevent custom extensions from polluting the global file space, a `catalog.json` file is restricted to the following root-level keys: + - `$schema` + - `$id` + - `title` + - `description` + - `catalogId` + - `instructions` + - `components` + - `functions` + - `$defs` + - No other top-level keys are permitted. + +##### Example Schema Template + +Below is an annotated, fully compliant `catalog.json` schema template (written in JSONC format with comments) representing a visual, complete model of these rules in action: + +```jsonc +{ + // Rule 7: Strict Top-Level Schema Keys + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json", + "title": "A2UI Basic Catalog Template", + "description": "An annotated example showcasing structural rules and conventions.", + "catalogId": "https://example.com/catalogs/custom-v1", + "instructions": "Design instructions for LLMs when generating layouts under this catalog.", + + // Rule 1: Top-level components declared under top-level "components" map. + "components": { + "Text": { + "type": "object", + // Rule 5: Components must combine ComponentCommon and local properties using "allOf". + "allOf": [ + { + // Rule 3: External references must reference standard types in common_types.json. + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/ComponentCommon", + }, + { + "type": "object", + "properties": { + // Rule 4: Required "component" property must be a constant matching the component key. + "component": { + "const": "Text", + }, + // Leaf properties can be standard JSON primitives or Dynamic wrappers + "text": { + "$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString", + "description": "Text content to display.", + }, + }, + "required": ["component", "text"], + }, + ], + "unevaluatedProperties": false, + }, + }, + + // Rule 1: Top-level functions declared under top-level "functions" map. + "functions": { + "required": { + "type": "object", + "description": "Checks that the value is not null, undefined, or empty.", + // Rule 6: Strict function metadata defined outside the properties block. + "returnType": "boolean", + "callableFrom": "clientOnly", + "properties": { + // Rule 6: Function call schema requires constant with function's name. + "call": { + "const": "required", + }, + "args": { + "type": "object", + "properties": { + "value": { + "description": "The value to check.", + }, + }, + "required": ["value"], + "additionalProperties": false, + }, + }, + "required": ["call", "args"], + "unevaluatedProperties": false, + }, + }, + + // Rule 1 & Rule 2: $defs is restricted strictly to surfaceProperties, anyComponent, and anyFunction. + // Custom definitions or helpers inside a catalog are strictly prohibited under $defs. + "$defs": { + "surfaceProperties": { + "type": "object", + "properties": { + "agentDisplayName": { + "type": "string", + }, + }, + }, + "anyComponent": { + "oneOf": [ + { + // Rule 3: Local refs restricted to top-level components map. + "$ref": "#/components/Text", + }, + ], + "discriminator": { + "propertyName": "component", + }, + }, + "anyFunction": { + "oneOf": [ + { + // Rule 3: Local refs restricted to top-level functions map. + "$ref": "#/functions/required", + }, + ], + }, + }, +} +``` + ### UI composition: the adjacency list model The A2UI protocol defines the UI as a flat list of components. The tree structure is built implicitly using ID references. This is known as an adjacency list model. diff --git a/specification/v1_0/json/client_capabilities.json b/specification/v1_0/json/client_capabilities.json index 9c2635076..3d1a0d1c2 100644 --- a/specification/v1_0/json/client_capabilities.json +++ b/specification/v1_0/json/client_capabilities.json @@ -101,7 +101,29 @@ "properties": { "$schema": {"type": "string"}, "$id": {"type": "string"}, - "$defs": {"type": "object"}, + "$defs": { + "type": "object", + "description": "Standardized schema definitions referenced from outside the catalog file.", + "properties": { + "surfaceProperties": { + "title": "A2UI Surface Properties Schema", + "description": "A JSON Schema that defines the catalog's surface properties.", + "$ref": "https://json-schema.org/draft/2020-12/schema" + }, + "anyComponent": { + "title": "A2UI Any Component Schema", + "description": "Unified validation schema for all components.", + "$ref": "https://json-schema.org/draft/2020-12/schema" + }, + "anyFunction": { + "title": "A2UI Any Function Schema", + "description": "Unified validation schema for all functions.", + "$ref": "https://json-schema.org/draft/2020-12/schema" + } + }, + "required": ["anyComponent", "anyFunction"], + "additionalProperties": false + }, "title": { "type": "string", "description": "The title of the catalog." @@ -131,14 +153,6 @@ "additionalProperties": { "$ref": "#/$defs/FunctionDefinition" } - }, - "surfaceProperties": { - "title": "A2UI Surface Properties", - "description": "A schema that defines a catalog of A2UI surface properties. Each key is a surface property name, and each value is the JSON schema for that property.", - "type": "object", - "additionalProperties": { - "$ref": "https://json-schema.org/draft/2020-12/schema" - } } }, "required": ["catalogId"],