diff --git a/specification/v1_0/docs/a2ui_protocol.md b/specification/v1_0/docs/a2ui_protocol.md index bbd1b93833..c877ce5d15 100644 --- a/specification/v1_0/docs/a2ui_protocol.md +++ b/specification/v1_0/docs/a2ui_protocol.md @@ -172,7 +172,7 @@ The envelope defines several message types, and every message streamed by the se ### `createSurface` -This message signals the client to create a new surface and begin rendering it. A surface must be created before any `updateComponents` or `updateDataModel` messages can be sent to it. While typically achieved by the agent sending a `createSurface` message, an agent may skip this if it knows the surface has already been created (e.g., by another agent). Once a surface is created, its `surfaceId` and `catalogId` are fixed; to reconfigure them, the surface must be deleted and recreated. +This message signals the client to create a new surface and begin rendering it. A surface must be created before any `updateComponents` or `updateDataModel` messages can be sent to it. Once a surface is created, its `surfaceId` and optional `catalogId` are fixed; to reconfigure them, the surface must be deleted and recreated. It is an error to try to create a surface with a `surfaceId` that already exists without first deleting it; `surfaceId` must be globally unique for the renderer's lifetime. Orchestrators with subagents are empowered to manage surface IDs as needed to prevent conflicts (e.g., prefixing the subagent's name to the `surfaceId` or requiring subagents to use UUIDs). @@ -181,7 +181,7 @@ One of the components in one of the component lists MUST have an `id` of `root` **Properties:** - `surfaceId` (string, required): The unique identifier for the UI surface to be rendered. This must be globally unique for the renderer's lifetime. -- `catalogId` (string, required): A string that uniquely identifies the catalog (components and functions) used for this surface. Note that `catalogId` is a string identifier, not a resolvable URI; while it is conventionally formatted as a URI (e.g., `https://mycompany.com/1.0/somecatalog`) to avoid naming collisions across organizations, it does not need to point to any deployed resource or downloadable file. Client and server developers must agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other. +- `catalogId` (string, optional): A string that uniquely identifies the default catalog to use for components and functions on this surface. Components and functions can override this by setting `catalogId` on component and function objects. An error will be thrown if catalogId is not set on createSurface or on the component or function. Note that `catalogId` is a string identifier, not a resolvable URI. Client and server developers must agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other. - `surfaceProperties` (object, optional): A JSON object containing surface properties (e.g., `agentDisplayName`) defined in the catalog's surfaceProperties schema. - `sendDataModel` (boolean, optional): If true, the client will send the full data model of this surface in the metadata of every message sent to the server (via the Transport's metadata mechanism). This ensures the surface owner receives the full current state of the UI alongside the user's action or query. Defaults to false. - `components` (array, optional): A list containing UI components for the surface, allowing the client to build and populate the UI tree immediately on surface creation. Conforms to the `ComponentsList` schema. @@ -194,7 +194,6 @@ One of the components in one of the component lists MUST have an `id` of `root` "version": "v1.0", "createSurface": { "surfaceId": "user_profile_card", - "catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json", "surfaceProperties": { "agentDisplayName": "Weather Bot" }, @@ -354,6 +353,7 @@ This message is sent by the server to execute a function registered on the clien - `wantResponse` (boolean, optional, default `false`): Specifies whether the server expects a response payload back from the client. If set to `true`, the client MUST reply with either a `functionResponse` or an `error` message. - `callFunction` (object, required): The description of the function call. - `call` (string, required): The registered name of the function to execute. + - `catalogId` (string, required): The catalog ID for this function. - `args` (object, optional): Arguments passed to the function, as defined by its schema in the catalog. **Security Boundaries and Verification:** @@ -374,6 +374,7 @@ Server sends this message to the client: "wantResponse": true, "callFunction": { "call": "getScreenResolution", + "catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json", "args": { "screenIndex": 0 } @@ -428,6 +429,8 @@ Each object in the `components` array of an `updateComponents` message defines a - `id` (`ComponentId`, required): A unique string that identifies this specific component instance. This is used for parent-child references. - `component` (string, required): Specifies the component's type (e.g., `"Text"`). +- `catalogId` (string, optional): A string that uniquely identifies the catalog for this component. If ommitted, the catalogId in createSurface will be used as the catalog. + - **Component Properties**: Other properties relevant to the specific component type (e.g., `text`, `url`, `children`) are included directly in the component object. This structure is designed to be both flexible and strictly validated. @@ -446,6 +449,15 @@ Every catalog follows the standard `Catalog` object definition: - **functions** (object, optional): A map of client-side validation or utility functions supported by the catalog, where each key is the function name and its value is its definition. All function names MUST conform to the UAX #31 entity naming rules defined below. The client determines a function's execution boundary (e.g., clientOnly status) at runtime by reading its configuration from the active catalog definition. - **surfaceProperties** (object, optional): A schema defining the catalog's customizable visual properties. +#### Mixable catalogs and component catalog resolution + +Clients can support components from multiple catalogs simultaneously (mixable catalogs). To resolve which catalog a component came from, either `createSurface.catalogId` (at the surface level) or `catalogId` on the component base MUST be set. The renderer resolves component catalogs using the following order of precedence: + +1. The component's `catalogId`, if specified on the component. +2. The `createSurface` message's `catalogId`, if specified on the surface. + +If `catalogId` is provided on an individual component, it overrides the surface's default `catalogId`. It is an error if a component's catalog cannot be resolved (i.e., neither `component.catalogId` nor `createSurface.catalogId` is set). + #### Catalog Entity Naming Rules To ensure complete cross-language compatibility across client SDKs, parsers, and code generators, all catalog entity identifiers—specifically **component names**, **function names**, and **argument/property names**—MUST adhere strictly to [Unicode Standard Annex #31 (UAX #31)](https://www.unicode.org/reports/tr31/) variable naming rules. diff --git a/specification/v1_0/docs/evolution_guide.md b/specification/v1_0/docs/evolution_guide.md index 5cf4b05a18..0dcf8ac95d 100644 --- a/specification/v1_0/docs/evolution_guide.md +++ b/specification/v1_0/docs/evolution_guide.md @@ -14,6 +14,8 @@ Version 1.0 differs from 0.9 in the following ways: - Standard JSON Schema metadata fields (`$schema`, `$id`, `title`, and `description`) are supported in catalogs, preventing validation failures on inline catalogs with strict property checks. - Identifier naming rules across all catalog entities (component names, function names, and argument keys) must conform to Unicode Standard Annex #31 (UAX #31). - The `@index` built-in function dynamically retrieves iteration indices during list template rendering. The `@` prefix is reserved for core system context evaluations. +- The `supportedCatalogIds` in `a2uiClientCapabilities` are all mixable, meaning a client can updateComponents with components from multiple catalogs simultaneously. +- Components and functions can set `catalogId` on their object which overrides the `catalogId` in createSurface, to specify which catalog a component or function comes from since they can now be mixed across catalogs. The `catalogId` property on `createSurface` is now optional. You must specify either `createSurface.catalogId` or `component.catalogId` / `function.catalogId`. ## 2. Changes @@ -39,7 +41,8 @@ Version 1.0 differs from 0.9 in the following ways: - Added `actionResponse` message structure (`ActionResponseMessage`) to allow the server to respond to a specific action call using a unique `actionId` with a `value` or `error`. - Added `callFunction` message structure (`CallFunctionMessage`) to support server-initiated function execution. Removed `callableFrom` and `returnType` properties from the wire payload, relying on runtime catalog verification. -- Updated the `createSurface` message (`CreateSurfaceMessage`) to rename the `theme` field to `surfaceProperties`, and allowed passing initial `components` and `dataModel` directly inside the payload. +- Updated the `createSurface` message (`CreateSurfaceMessage`) to rename the `theme` field to `surfaceProperties`, allowed passing initial `components` and `dataModel` directly inside the payload, and removed `catalogId`. +- Update `createSurface` message to make `catalogId` optional, and to allow specifying `catalogId` on components and function calls so that components can be mixed between catalogs. Require that one of these are set. - Updated all protocol version references and envelopes from `v0.9` or `v0.9.1` to `v1.0`. ### 2.4. Client-to-server events @@ -59,6 +62,7 @@ Version 1.0 differs from 0.9 in the following ways: - Standardized the official MIME type to `application/a2ui+json` to conform to IANA media type guidelines. - Updated capabilities namespace in transport metadata and A2A metadata parameters from `v0.9`/`v0.9.1` to `v1.0`. +- Explicitly defined that `supportedCatalogIds` in `a2uiClientCapabilities` are mixable. ### 2.7. Data encoding diff --git a/specification/v1_0/json/client_capabilities.json b/specification/v1_0/json/client_capabilities.json index 2cbb7e756c..181bbcfe4f 100644 --- a/specification/v1_0/json/client_capabilities.json +++ b/specification/v1_0/json/client_capabilities.json @@ -11,7 +11,7 @@ "properties": { "supportedCatalogIds": { "type": "array", - "description": "An array of string identifiers for each of the component and function catalogs supported by the client.", + "description": "An array of string identifiers for each of the component and function catalogs supported by the client. Multiple catalogs can be mixed in a surface.", "items": {"type": "string"} }, "inlineCatalogs": { diff --git a/specification/v1_0/json/common_types.json b/specification/v1_0/json/common_types.json index 980d8b1a13..1d229a7b51 100644 --- a/specification/v1_0/json/common_types.json +++ b/specification/v1_0/json/common_types.json @@ -32,6 +32,10 @@ "id": { "$ref": "#/$defs/ComponentId" }, + "catalogId": { + "type": "string", + "description": "The catalog ID for this component. If omitted, the catalogId in createSurface will be used." + }, "accessibility": { "$ref": "#/$defs/AccessibilityAttributes" } @@ -188,6 +192,10 @@ "type": "string", "description": "The name of the function to call." }, + "catalogId": { + "type": "string", + "description": "The catalog ID for this function. If omitted, the catalogId in createSurface will be used." + }, "args": { "type": "object", "description": "Arguments passed to the function.", diff --git a/specification/v1_0/json/server_to_client.json b/specification/v1_0/json/server_to_client.json index 7ecc8cdca2..1adaf347ca 100644 --- a/specification/v1_0/json/server_to_client.json +++ b/specification/v1_0/json/server_to_client.json @@ -28,8 +28,8 @@ "description": "The unique identifier for the UI surface to be rendered. It must be globally unique for the renderer's lifetime." }, "catalogId": { - "description": "A string that uniquely identifies this catalog. It is recommended to prefix this with an internet domain that you own, to avoid conflicts e.g. mycompany.com:somecatalog'.", - "type": "string" + "type": "string", + "description": "A string that uniquely identifies the catalog (components and functions) used for this surface." }, "surfaceProperties": { "$ref": "catalog.json#/$defs/surfaceProperties", @@ -48,7 +48,7 @@ "additionalProperties": true } }, - "required": ["surfaceId", "catalogId"], + "required": ["surfaceId"], "additionalProperties": false } }, @@ -71,7 +71,7 @@ }, "updateComponents": { "type": "object", - "description": "Updates a surface with a new set of components. This message can be sent multiple times to update the component tree of an existing surface. One of the components in one of the components lists MUST have an 'id' of 'root' to serve as the root of the component tree. The createSurface message MUST have been previously sent with the 'catalogId' that is in this message.", + "description": "Updates a surface with a new set of components. This message can be sent multiple times to update the component tree of an existing surface. One of the components in one of the components lists MUST have an 'id' of 'root' to serve as the root of the component tree.", "properties": { "surfaceId": { "type": "string", @@ -96,7 +96,7 @@ }, "updateDataModel": { "type": "object", - "description": "Updates the data model for an existing surface. This message can be sent multiple times to update the data model. The createSurface message MUST have been previously sent with the 'catalogId' that is in this message.", + "description": "Updates the data model for an existing surface. This message can be sent multiple times to update the data model.", "properties": { "surfaceId": { "type": "string", @@ -126,7 +126,7 @@ }, "deleteSurface": { "type": "object", - "description": "Signals the client to delete the surface identified by 'surfaceId'. The createSurface message MUST have been previously sent with the 'catalogId' that is in this message.", + "description": "Signals the client to delete the surface identified by 'surfaceId'.", "properties": { "surfaceId": { "type": "string",