diff --git a/specification/v0_10/docs/a2ui_protocol.md b/specification/v0_10/docs/a2ui_protocol.md index d8bcf2701..3026e3230 100644 --- a/specification/v0_10/docs/a2ui_protocol.md +++ b/specification/v0_10/docs/a2ui_protocol.md @@ -167,7 +167,7 @@ Validators determine which fields represent structural links by looking for thes ## Envelope message structure -The envelope defines four primary message types, and every message streamed by the server must be a JSON object containing exactly one of the following keys: `createSurface`, `updateComponents`, `updateDataModel`, or `deleteSurface`. The key indicates the type of message, and these are the messages that make up each message in the protocol stream. +The envelope defines several message types, and every message streamed by the server must be a JSON object containing exactly one of the following keys: `createSurface`, `updateComponents`, `updateDataModel`, `deleteSurface`, or `actionResponse`. The key indicates the type of message, and these are the messages that make up each message in the protocol stream. ### `createSurface` @@ -275,6 +275,51 @@ This message instructs the client to remove a surface and all its associated com } ``` +### `actionResponse` + +This message is sent by the server to respond to a client-initiated `action` that requested a response via `wantResponse: true`. + +**Properties:** + +- `actionId` (string, required): The unique ID of the action call this response belongs to. MUST match the `actionId` sent by the client. +- `actionResponse` (object, required): The payload containing the response. + - `value` (any): The return value of the action. Present on success. + - `error` (object): Error details if the action failed. + - `code` (string): Error code. + - `message` (string): Description of the error. + +Exactly one of `value` or `error` must be present. + +**Example:** + +Client sends this to the server: +```json +{ + "version": "v0.10", + "action": { + "name": "get_typeahead_suggestions", + "surfaceId": "mysurface", + "sourceComponentId": "myinput", + "context": { + "prefix": "app" + }, + "wantResponse": true, + "actionId": "get_typeahead_suggestions_1" + } +} +``` + +Server responds with: +```json +{ + "version": "v0.10", + "actionId": "get_typeahead_suggestions_1", + "actionResponse": { + "value": ["apple", "application", "approved"] + } +} +``` + ## Example Stream The following example demonstrates a complete interaction to render a Contact Form, expressed as a JSONL stream. @@ -343,7 +388,10 @@ Interactive components (like `Button`) use an `action` property to define what h #### Server actions -To send an event to the server, use the `event` property within the `action` object. It requires a `name` and an optional `context`. +To send an event to the server, use the `event` property within the `action` object. It requires a `name` and supports an optional `context`, `wantResponse`, and `responsePath`. + +- `wantResponse` (boolean, optional): If true, the client expects an `actionResponse` from the server. Defaults to false. +- `responsePath` (string, optional): A JSON Pointer path in the local data model where the response `value` should be saved. ```json { @@ -813,6 +861,7 @@ This message is sent when the user interacts with a component that has an `actio - `sourceComponentId` (string, required): The ID of the component that triggered the action. - `timestamp` (string, required): An ISO 8601 timestamp. - `context` (object, required): A JSON object containing any context provided in the component's `action` property. +- `actionId` (string, optional): A unique ID for this action call, generated by the client if `wantResponse` is true. ### Capabilities & metadata diff --git a/specification/v0_10/docs/evolution_guide.md b/specification/v0_10/docs/evolution_guide.md index fe9471ce0..f30fb1928 100644 --- a/specification/v0_10/docs/evolution_guide.md +++ b/specification/v0_10/docs/evolution_guide.md @@ -6,6 +6,7 @@ This document serves as a comprehensive guide to the changes between A2UI versio Version 0.10 differs from 0.9 in the following ways: +- **Client-to-Server RPC**: Introduced `actionResponse` enabling synchronous responses to client-initiated actions. Added `actionId` for response correlation. - ## 2. Changes @@ -16,10 +17,12 @@ Version 0.10 differs from 0.9 in the following ways: ### 2.2. Server-to-Client Message List Schema +- Added `ActionResponseMessage` to allow the server to respond to a specific action call using an `actionId`. - ### 2.3. Client-to-Server Message List Schema +- Added `actionId` to the `action` message properties, which the client generates if a response is expected (`wantResponse: true`). - ### 2.4. Client Capabilities Schema @@ -40,10 +43,13 @@ Version 0.10 differs from 0.9 in the following ways: ### 2.8. Server-to-Client Messages +- Added `actionResponse` message structure to support synchronous responses with a `value` or `error`. - ### 2.9. Client-to-Server Events +- Updated `action` message to include `actionId`. +- Updated `Action` type in `common_types.json` to include `wantResponse` and `responsePath` on event triggers. - ## 3. Migration Guide diff --git a/specification/v0_10/json/client_to_server.json b/specification/v0_10/json/client_to_server.json index 82f8a9206..f0aa24b40 100644 --- a/specification/v0_10/json/client_to_server.json +++ b/specification/v0_10/json/client_to_server.json @@ -35,6 +35,15 @@ "type": "object", "description": "A JSON object containing the key-value pairs from the component's action.event.context, after resolving all data bindings.", "additionalProperties": true + }, + "wantResponse": { + "type": "boolean", + "description": "If true, the client expects an actionResponse from the server.", + "default": false + }, + "actionId": { + "type": "string", + "description": "Unique ID for this action call. Only needed if wantResponse is true." } }, "required": [ diff --git a/specification/v0_10/json/common_types.json b/specification/v0_10/json/common_types.json index 3d2e6679a..044b50622 100644 --- a/specification/v0_10/json/common_types.json +++ b/specification/v0_10/json/common_types.json @@ -311,6 +311,15 @@ "additionalProperties": { "$ref": "#/$defs/DynamicValue" } + }, + "wantResponse": { + "type": "boolean", + "description": "If true, the client expects an actionResponse from the server.", + "default": false + }, + "responsePath": { + "type": "string", + "description": "Optional JSON Pointer path where the client should save the response value in its local data model." } }, "required": ["name"], diff --git a/specification/v0_10/json/server_to_client.json b/specification/v0_10/json/server_to_client.json index 650478427..f5122c973 100644 --- a/specification/v0_10/json/server_to_client.json +++ b/specification/v0_10/json/server_to_client.json @@ -9,7 +9,8 @@ { "$ref": "#/$defs/UpdateComponentsMessage" }, { "$ref": "#/$defs/UpdateDataModelMessage" }, { "$ref": "#/$defs/DeleteSurfaceMessage" }, - { "$ref": "#/$defs/CallFunctionMessage" } + { "$ref": "#/$defs/CallFunctionMessage" }, + { "$ref": "#/$defs/ActionResponseMessage" } ], "$defs": { "CreateSurfaceMessage": { @@ -166,6 +167,44 @@ }, "required": ["version", "callFunction", "functionCallId"], "additionalProperties": false + }, + "ActionResponseMessage": { + "type": "object", + "description": "A response to a client-initiated action.", + "properties": { + "version": { + "const": "v0.10" + }, + "actionId": { + "type": "string", + "description": "The ID of the action call this response belongs to." + }, + "actionResponse": { + "type": "object", + "properties": { + "value": { + "description": "The return value of the action.", + "type": [ "string", "number", "boolean", "array", "object", "null" ] + }, + "error": { + "type": "object", + "properties": { + "code": { "type": "string" }, + "message": { "type": "string" } + }, + "required": [ "code", "message" ], + "additionalProperties": false + } + }, + "oneOf": [ + { "required": [ "value" ] }, + { "required": [ "error" ] } + ], + "additionalProperties": false + } + }, + "required": [ "version", "actionResponse", "actionId" ], + "additionalProperties": false } } }