diff --git a/packages/genui/lib/src/model/a2ui_message.dart b/packages/genui/lib/src/model/a2ui_message.dart index df0d7f305..57ef8a169 100644 --- a/packages/genui/lib/src/model/a2ui_message.dart +++ b/packages/genui/lib/src/model/a2ui_message.dart @@ -89,36 +89,44 @@ sealed class A2uiMessage { /// Returns the JSON schema for an A2UI message. static Schema a2uiMessageSchema(Catalog catalog) { return S.combined( - allOf: [ + title: 'A2UI Message Schema', + description: + 'Describes a JSON payload for an A2UI (Agent to UI) message, ' + 'which is used to dynamically construct and update user interfaces.', + oneOf: [ S.object( - title: 'A2UI Message Schema', - description: - 'Describes a JSON payload for an A2UI (Agent to UI) message. ' - 'A message MUST contain exactly ONE of the action properties.', properties: { 'version': S.string(constValue: 'v0.9'), 'createSurface': A2uiSchemas.createSurfaceSchema(), + }, + required: ['version', 'createSurface'], + additionalProperties: false, + ), + S.object( + properties: { + 'version': S.string(constValue: 'v0.9'), 'updateComponents': A2uiSchemas.updateComponentsSchema(catalog), + }, + required: ['version', 'updateComponents'], + additionalProperties: false, + ), + S.object( + properties: { + 'version': S.string(constValue: 'v0.9'), 'updateDataModel': A2uiSchemas.updateDataModelSchema(), + }, + required: ['version', 'updateDataModel'], + additionalProperties: false, + ), + S.object( + properties: { + 'version': S.string(constValue: 'v0.9'), 'deleteSurface': A2uiSchemas.deleteSurfaceSchema(), }, - required: ['version'], + required: ['version', 'deleteSurface'], + additionalProperties: false, ), ], - anyOf: [ - { - 'required': ['createSurface'], - }, - { - 'required': ['updateComponents'], - }, - { - 'required': ['updateDataModel'], - }, - { - 'required': ['deleteSurface'], - }, - ], ); } } diff --git a/packages/genui/lib/src/model/a2ui_schemas.dart b/packages/genui/lib/src/model/a2ui_schemas.dart index fc8583602..0da98b2df 100644 --- a/packages/genui/lib/src/model/a2ui_schemas.dart +++ b/packages/genui/lib/src/model/a2ui_schemas.dart @@ -398,6 +398,11 @@ abstract final class A2uiSchemas { /// Schema for a createSurface message. static Schema createSurfaceSchema() => S.object( + description: + 'Signals the client to create a new surface and begin rendering it. ' + "When this message is sent, the client will expect 'updateComponents' " + "and/or 'updateDataModel' messages for the same surfaceId that define " + 'the component tree.', properties: { surfaceIdKey: S.string(description: 'The unique ID for the surface.'), 'catalogId': S.string(description: 'The URI of the component catalog.'), @@ -414,12 +419,21 @@ abstract final class A2uiSchemas { /// Schema for a deleteSurface message. static Schema deleteSurfaceSchema() => S.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.", properties: {surfaceIdKey: S.string()}, required: [surfaceIdKey], ); /// Schema for a updateDataModel message. static Schema updateDataModelSchema() => S.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.', properties: { surfaceIdKey: S.string(), 'path': S.combined(type: JsonType.string, defaultValue: '/'), @@ -445,6 +459,13 @@ abstract final class A2uiSchemas { .toList(); return S.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.", properties: { surfaceIdKey: S.string( description: 'The unique identifier for the UI surface.', diff --git a/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_false.txt b/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_false.txt index e8677efdb..79be8c966 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_false.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_false.txt @@ -127,11 +127,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -139,6 +139,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -162,9 +163,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -253,9 +269,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -271,9 +302,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -285,30 +331,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_true.txt b/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_true.txt index 5e8179ebf..6a23db96c 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_true.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/all_operations_with_dataModel_true.txt @@ -129,11 +129,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -141,6 +141,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -164,9 +165,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -255,9 +271,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -273,9 +304,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -287,30 +333,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_false.txt b/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_false.txt index 9b0b36e04..40281e27a 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_false.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_false.txt @@ -125,11 +125,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -137,6 +137,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -160,9 +161,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -251,9 +267,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -269,9 +300,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -283,30 +329,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_true.txt b/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_true.txt index 2415cb23f..45d0910d5 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_true.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/create_and_update_with_dataModel_true.txt @@ -127,11 +127,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -139,6 +139,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -162,9 +163,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -253,9 +269,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -271,9 +302,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -285,30 +331,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_false.txt b/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_false.txt index e97f8940f..2be5392bd 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_false.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_false.txt @@ -122,11 +122,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -134,6 +134,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -157,9 +158,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -248,9 +264,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -266,9 +297,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -280,30 +326,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_true.txt b/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_true.txt index 31a468da0..209ae94e1 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_true.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/create_only_with_dataModel_true.txt @@ -124,11 +124,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -136,6 +136,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -159,9 +160,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -250,9 +266,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -268,9 +299,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -282,30 +328,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_false.txt b/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_false.txt index 32e59a090..779d76e4f 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_false.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_false.txt @@ -117,11 +117,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -129,6 +129,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -152,9 +153,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -243,9 +259,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -261,9 +292,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -275,30 +321,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_true.txt b/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_true.txt index ccc7d09cd..0f4f0fa09 100644 --- a/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_true.txt +++ b/packages/genui/test/facade/prompt_builder_test.golden/update_only_with_dataModel_true.txt @@ -119,11 +119,11 @@ When constructing UI, you must output a VALID A2UI JSON object representing one -----A2UI_JSON_SCHEMA_START----- { - "allOf": [ + "title": "A2UI Message Schema", + "description": "Describes a JSON payload for an A2UI (Agent to UI) message, which is used to dynamically construct and update user interfaces.", + "oneOf": [ { "type": "object", - "title": "A2UI Message Schema", - "description": "Describes a JSON payload for an A2UI (Agent to UI) message. A message MUST contain exactly ONE of the action properties.", "properties": { "version": { "type": "string", @@ -131,6 +131,7 @@ When constructing UI, you must output a VALID A2UI JSON object representing one }, "createSurface": { "type": "object", + "description": "Signals the client to create a new surface and begin rendering it. When this message is sent, the client will expect 'updateComponents' and/or 'updateDataModel' messages for the same surfaceId that define the component tree.", "properties": { "surfaceId": { "type": "string", @@ -154,9 +155,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "catalogId" ] + } + }, + "required": [ + "version", + "createSurface" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string", @@ -245,9 +261,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "surfaceId", "components" ] + } + }, + "required": [ + "version", + "updateComponents" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -263,9 +294,24 @@ When constructing UI, you must output a VALID A2UI JSON object representing one "required": [ "surfaceId" ] + } + }, + "required": [ + "version", + "updateDataModel" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "version": { + "type": "string", + "const": "v0.9" }, "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.", "properties": { "surfaceId": { "type": "string" @@ -277,30 +323,10 @@ When constructing UI, you must output a VALID A2UI JSON object representing one } }, "required": [ - "version" - ] - } - ], - "anyOf": [ - { - "required": [ - "createSurface" - ] - }, - { - "required": [ - "updateComponents" - ] - }, - { - "required": [ - "updateDataModel" - ] - }, - { - "required": [ + "version", "deleteSurface" - ] + ], + "additionalProperties": false } ] } diff --git a/packages/genui/test/model/a2ui_message_test.dart b/packages/genui/test/model/a2ui_message_test.dart index bab54c0a4..20022d989 100644 --- a/packages/genui/test/model/a2ui_message_test.dart +++ b/packages/genui/test/model/a2ui_message_test.dart @@ -140,22 +140,22 @@ void main() { final Schema schema = A2uiMessage.a2uiMessageSchema(catalog); final json = jsonDecode(schema.toJson()) as Map; - // Structure is combined -> allOf -> [object] - expect(json['allOf'], isA>()); - final allOf = json['allOf'] as List; - expect(allOf, isNotEmpty); - final mainSchema = allOf.first as Map; - - final properties = mainSchema['properties'] as Map; - expect(properties, contains('version')); - - final required = mainSchema['required'] as List; - expect(required, contains('version')); - - final versionSchema = properties['version'] as Map; - // Depending on json_schema_builder version, it might be 'const' or 'enum' - // But we expect it to enforce 'v0.9' - expect(versionSchema, containsPair('const', 'v0.9')); + // Structure is combined -> oneOf -> [object, ...] + expect(json['oneOf'], isA>()); + final oneOf = json['oneOf'] as List; + expect(oneOf, isNotEmpty); + + // Every variant must require 'version' and enforce 'v0.9' + for (final variant in oneOf) { + final variantMap = variant as Map; + final required = variantMap['required'] as List; + expect(required, contains('version')); + + final properties = variantMap['properties'] as Map; + expect(properties, contains('version')); + final versionSchema = properties['version'] as Map; + expect(versionSchema, containsPair('const', 'v0.9')); + } }); }); }