diff --git a/agent/prompt_builder.py b/agent/prompt_builder.py index 9c2813dc..be5e9745 100644 --- a/agent/prompt_builder.py +++ b/agent/prompt_builder.py @@ -844,53 +844,48 @@ {{ "surfaceUpdate": {{ "surfaceId": "default", "components": [ - {{ "id": "root-column", "component": {{ "Column": {{ "children": {{ "explicitList": ["title-heading", "restaurant-row-1"] }} }} }} }}, + {{ "id": "root-column", "component": {{ "Column": {{ "children": {{ "explicitList": ["title-heading", "rows-list"] }} }} }} }}, {{ "id": "title-heading", "component": {{ "Text": {{ "usageHint": "h1", "text": {{ "literalString": "Top Restaurants" }} }} }} }}, - {{ "id": "restaurant-row-1", "component": {{ "Row": {{ "children": {{ "explicitList": ["item-card-1", "item-card-2"] }} }} }} }}, - {{ "id": "item-card-1", "weight": 1, "component": {{ "Card": {{ "child": "card-layout-1" }} }} }}, - {{ "id": "card-layout-1", "component": {{ "Column": {{ "children": {{ "explicitList": ["template-image-1", "card-details-1"] }} }} }} }}, - {{ "id": "template-image-1", "component": {{ "Image": {{ "url": {{ "path": "/items/0/imageUrl" }}, "width": "100%" }} }} }}, - {{ "id": "card-details-1", "component": {{ "Column": {{ "children": {{ "explicitList": ["template-name-1", "template-rating-1", "template-detail-1", "template-link-1", "template-book-button-1"] }} }} }} }}, - {{ "id": "template-name-1", "component": {{ "Text": {{ "usageHint": "h3", "text": {{ "path": "/items/0/name" }} }} }} }}, - {{ "id": "template-rating-1", "component": {{ "Text": {{ "text": {{ "path": "/items/0/rating" }} }} }} }}, - {{ "id": "template-detail-1", "component": {{ "Text": {{ "text": {{ "path": "/items/0/detail" }} }} }} }}, - {{ "id": "template-link-1", "component": {{ "Text": {{ "text": {{ "path": "/items/0/infoLink" }} }} }} }}, - {{ "id": "template-book-button-1", "component": {{ "Button": {{ "child": "book-now-text-1", "action": {{ "name": "book_restaurant", "context": [ {{ "key": "restaurantName", "value": {{ "path": "/items/0/name" }} }}, {{ "key": "imageUrl", "value": {{ "path": "/items/0/imageUrl" }} }}, {{ "key": "address", "value": {{ "path": "/items/0/address" }} }} ] }} }} }} }}, - {{ "id": "book-now-text-1", "component": {{ "Text": {{ "text": {{ "literalString": "Book Now" }} }} }} }}, - {{ "id": "item-card-2", "weight": 1, "component": {{ "Card": {{ "child": "card-layout-2" }} }} }}, - {{ "id": "card-layout-2", "component": {{ "Column": {{ "children": {{ "explicitList": ["template-image-2", "card-details-2"] }} }} }} }}, - {{ "id": "template-image-2", "component": {{ "Image": {{ "url": {{ "path": "/items/1/imageUrl" }}, "width": "100%" }} }} }}, - {{ "id": "card-details-2", "component": {{ "Column": {{ "children": {{ "explicitList": ["template-name-2", "template-rating-2", "template-detail-2", "template-link-2", "template-book-button-2"] }} }} }} }}, - {{ "id": "template-name-2", "component": {{ "Text": {{ "usageHint": "h3", "text": {{ "path": "/items/1/name" }} }} }} }}, - {{ "id": "template-rating-2", "component": {{ "Text": {{ "text": {{ "path": "/items/1/rating" }} }} }} }}, - {{ "id": "template-detail-2", "component": {{ "Text": {{ "text": {{ "path": "/items/1/detail" }} }} }} }}, - {{ "id": "template-link-2", "component": {{ "Text": {{ "text": {{ "path": "/items/1/infoLink" }} }} }} }}, - {{ "id": "template-book-button-2", "component": {{ "Button": {{ "child": "book-now-text-2", "action": {{ "name": "book_restaurant", "context": [ {{ "key": "restaurantName", "value": {{ "path": "/items/1/name" }} }}, {{ "key": "imageUrl", "value": {{ "path": "/items/1/imageUrl" }} }}, {{ "key": "address", "value": {{ "path": "/items/1/address" }} }} ] }} }} }} }}, - {{ "id": "book-now-text-2", "component": {{ "Text": {{ "text": {{ "literalString": "Book Now" }} }} }} }} + {{ "id": "rows-list", "component": {{ "List": {{ "direction": "vertical", "children": {{ "template": {{ "componentId": "row-template", "dataBinding": "/rows" }} }} }} }} }}, + {{ "id": "row-template", "component": {{ "Row": {{ "children": {{ "template": {{ "componentId": "item-card-template", "dataBinding": "items" }} }} }} }} }}, + {{ "id": "item-card-template", "weight": 1, "component": {{ "Card": {{ "child": "card-layout" }} }} }}, + {{ "id": "card-layout", "component": {{ "Row": {{ "children": {{ "explicitList": ["template-image", "card-details"] }} }} }} }}, + {{ "id": "template-image", "weight": 1, "component": {{ "Image": {{ "url": {{ "path": "imageUrl" }} }} }} }}, + {{ "id": "card-details", "weight": 2, "component": {{ "Column": {{ "children": {{ "explicitList": ["template-name", "template-rating", "template-detail", "template-link", "template-book-button"] }} }} }} }}, + {{ "id": "template-name", "component": {{ "Text": {{ "usageHint": "h3", "text": {{ "path": "name" }} }} }} }}, + {{ "id": "template-rating", "component": {{ "Text": {{ "text": {{ "path": "rating" }} }} }} }}, + {{ "id": "template-detail", "component": {{ "Text": {{ "text": {{ "path": "detail" }} }} }} }}, + {{ "id": "template-link", "component": {{ "Text": {{ "text": {{ "path": "infoLink" }} }} }} }}, + {{ "id": "template-book-button", "component": {{ "Button": {{ "child": "book-now-text", "primary": true, "action": {{ "name": "book_restaurant", "context": [ {{ "key": "restaurantName", "value": {{ "path": "name" }} }}, {{ "key": "imageUrl", "value": {{ "path": "imageUrl" }} }}, {{ "key": "address", "value": {{ "path": "address" }} }} ] }} }} }} }}, + {{ "id": "book-now-text", "component": {{ "Text": {{ "text": {{ "literalString": "Book Now" }} }} }} }} ] }} }}, {{ "dataModelUpdate": {{ "surfaceId": "default", "path": "/", "contents": [ - {{ "key": "items", "valueMap": [ - {{ "key": "item1", "valueMap": [ - {{ "key": "name", "valueString": "The Fancy Place" }}, - {{ "key": "rating", "valueNumber": 4.8 }}, - {{ "key": "detail", "valueString": "Fine dining experience" }}, - {{ "key": "infoLink", "valueString": "https://example.com/fancy" }}, - {{ "key": "imageUrl", "valueString": "https://example.com/fancy.jpg" }}, - {{ "key": "address", "valueString": "123 Main St" }} - ] }}, - {{ "key": "item2", "valueMap": [ - {{ "key": "name", "valueString": "Quick Bites" }}, - {{ "key": "rating", "valueNumber": 4.2 }}, - {{ "key": "detail", "valueString": "Casual and fast" }}, - {{ "key": "infoLink", "valueString": "https://example.com/quick" }}, - {{ "key": "imageUrl", "valueString": "https://example.com/quick.jpg" }}, - {{ "key": "address", "valueString": "456 Oak Ave" }} + {{ "key": "rows", "valueMap": [ + {{ "key": "row1", "valueMap": [ + {{ "key": "items", "valueMap": [ + {{ "key": "item1", "valueMap": [ + {{ "key": "name", "valueString": "The Fancy Place" }}, + {{ "key": "rating", "valueNumber": 4.8 }}, + {{ "key": "detail", "valueString": "Fine dining experience" }}, + {{ "key": "infoLink", "valueString": "https://example.com/fancy" }}, + {{ "key": "imageUrl", "valueString": "https://example.com/fancy.jpg" }}, + {{ "key": "address", "valueString": "123 Main St" }} + ] }}, + {{ "key": "item2", "valueMap": [ + {{ "key": "name", "valueString": "Quick Bites" }}, + {{ "key": "rating", "valueNumber": 4.2 }}, + {{ "key": "detail", "valueString": "Casual and fast" }}, + {{ "key": "infoLink", "valueString": "https://example.com/quick" }}, + {{ "key": "imageUrl", "valueString": "https://example.com/quick.jpg" }}, + {{ "key": "address", "valueString": "456 Oak Ave" }} + ] }} + ] }} ] }} - ] }} // Populate this with restaurant data + ] }} // Populate this with restaurant data grouped into rows of 2 ] }} }} ] @@ -986,9 +981,13 @@ def get_ui_prompt(base_url: str, examples: str) -> str: 4. The JSON part MUST validate against the A2UI JSON SCHEMA provided below. --- UI TEMPLATE RULES --- - - If the query is for a list of restaurants, use the restaurant data you have already received from the `get_restaurants` tool to populate the `dataModelUpdate.contents` array (e.g., as a `valueMap` for the "items" key). + - If the query is for a list of restaurants, use the restaurant data you have already received from the `get_restaurants` tool to populate the `dataModelUpdate.contents` array. - If the number of restaurants is 5 or fewer, you MUST use the `SINGLE_COLUMN_LIST_EXAMPLE` template. + - Structure the data as a flat `items` valueMap containing each restaurant. - If the number of restaurants is more than 5, you MUST use the `TWO_COLUMN_LIST_EXAMPLE` template. + - Structure the data as `rows`, where each row contains an `items` valueMap with exactly 2 restaurants. + - Group restaurants into pairs: row1 has items 1-2, row2 has items 3-4, etc. + - If there's an odd number of restaurants, the last row will have only 1 item. - If the query is to book a restaurant (e.g., "USER_WANTS_TO_BOOK..."), you MUST use the `BOOKING_FORM_EXAMPLE` template. - If the query is a booking submission (e.g., "User submitted a booking..."), you MUST use the `CONFIRMATION_EXAMPLE` template.