diff --git a/a2a/README.md b/a2a/README.md index d1f594b..0860041 100644 --- a/a2a/README.md +++ b/a2a/README.md @@ -148,11 +148,12 @@ The Chat Client UCP Profile can be found at http://localhost:3000/profile/agent- 2. Type `"show me cookies available in stock"` and press enter 3. The agent will return products available in stock 4. Click **"Add to Checkout"** for any product -5. The agent will ask for required information such as email address, shipping address, etc. -6. Once the required information is provided, click **"Complete Payment"** -7. The UI shows available mock payment options -8. Select a payment method and click **"Confirm Purchase"** -9. The agent will create an order and return the order confirmation +5. [Optional] Type `"apply discount code 10OFF"` to get a 10% discount +6. The agent will ask for required information such as email address, shipping address, etc. +7. Once the required information is provided, click **"Complete Payment"** +8. The UI shows available mock payment options +9. Select a payment method and click **"Confirm Purchase"** +10. The agent will create an order and return the order confirmation diff --git a/a2a/business_agent/src/business_agent/agent.py b/a2a/business_agent/src/business_agent/agent.py index 5046e64..c76b60b 100644 --- a/a2a/business_agent/src/business_agent/agent.py +++ b/a2a/business_agent/src/business_agent/agent.py @@ -209,6 +209,32 @@ def get_checkout(tool_context: ToolContext) -> dict: } +def apply_discount_code(tool_context: ToolContext, discount_code: str) -> dict: + """Apply a discount code to the checkout. + + Args: + tool_context: The tool context for the current request. + discount_code: The discount code to apply. + + Returns: + dict: Returns the response from the tool with success or error status. + + """ + checkout_id = _get_current_checkout_id(tool_context) + + if not checkout_id: + return _create_error_response("A Checkout has not yet been created.") + + if store.apply_discount(checkout_id, discount_code): + checkout = store.get_checkout(checkout_id) + return { + UCP_CHECKOUT_KEY: checkout.model_dump(mode="json"), + "status": "success", + } + else: + return _create_error_response("Invalid discount code.") + + def update_customer_details( tool_context: ToolContext, first_name: str, @@ -450,7 +476,8 @@ def modify_output_after_agent( " search for the products and then add the matching products to" " checkout session.If the user asks to replace products," " use remove_from_checkout and add_to_checkout tools to replace the" - " products to match the user request" + " products to match the user request. If the user provides a discount" + " code, apply it to the checkout." ), tools=[ search_shopping_catalog, @@ -461,6 +488,7 @@ def modify_output_after_agent( start_payment, update_customer_details, complete_checkout, + apply_discount_code, ], after_tool_callback=after_tool_modifier, after_agent_callback=modify_output_after_agent, diff --git a/a2a/business_agent/src/business_agent/data/agent_card.json b/a2a/business_agent/src/business_agent/data/agent_card.json index 4732431..c57440d 100644 --- a/a2a/business_agent/src/business_agent/data/agent_card.json +++ b/a2a/business_agent/src/business_agent/data/agent_card.json @@ -77,6 +77,18 @@ "tags": [ "checkout" ] + }, + { + "description": "Applies a discount to the current checkout session", + "examples": [ + "Apply discount code 10OFF" + ], + "id": "apply_discount", + "name": "Apply Discount", + "tags": [ + "checkout", + "discount" + ] } ], "url": "http://localhost:10999", diff --git a/a2a/business_agent/src/business_agent/data/ucp.json b/a2a/business_agent/src/business_agent/data/ucp.json index 034ff6d..f2ea630 100644 --- a/a2a/business_agent/src/business_agent/data/ucp.json +++ b/a2a/business_agent/src/business_agent/data/ucp.json @@ -23,6 +23,13 @@ "spec": "https://ucp.dev/specs/shopping/fulfillment", "schema": "https://ucp.dev/schemas/shopping/fulfillment.json", "extends": "dev.ucp.shopping.checkout" + }, + { + "name": "dev.ucp.shopping.discount", + "version": "2026-01-11", + "spec": "https://ucp.dev/specs/shopping/discount", + "schema": "https://ucp.dev/schemas/shopping/discount.json", + "extends": "dev.ucp.shopping.discount" } ] }, diff --git a/a2a/business_agent/src/business_agent/store.py b/a2a/business_agent/src/business_agent/store.py index 26fe800..1e2790b 100644 --- a/a2a/business_agent/src/business_agent/store.py +++ b/a2a/business_agent/src/business_agent/store.py @@ -76,6 +76,7 @@ def __init__(self): self._products = {} self._checkouts = {} self._orders = {} + self._discounts = {} self._initialize_ucp_metadata() self._initialize_products() @@ -349,6 +350,9 @@ def _recalculate_checkout(self, checkout: Checkout) -> None: subtotal = items_base_amount - items_discount discount = 0 + if checkout.id in self._discounts: + discount_percentage = self._discounts[checkout.id] + discount = int(subtotal * discount_percentage / 100) totals = [ Total( @@ -484,6 +488,9 @@ def start_payment(self, checkout_id: str) -> Checkout | str: if ( isinstance(checkout, FulfillmentCheckout) and checkout.fulfillment is None + ) and not any( + line_item.item.id == "donation" + for line_item in checkout.line_items ): messages.append("Provide a fulfillment address") @@ -557,3 +564,22 @@ def _get_fulfillment_options(self) -> list[FulfillmentOptionResponse]: ], ), ] + + def apply_discount(self, checkout_id: str, discount_code: str) -> bool: + """Apply a discount to the checkout. + + Args: + checkout_id (str): ID of the checkout to apply the discount to. + discount_code (str): The discount code to apply. + + Returns: + bool: True if the discount was applied, False otherwise. + + """ + if discount_code == "10OFF": + self._discounts[checkout_id] = 10 + checkout = self.get_checkout(checkout_id) + if checkout: + self._recalculate_checkout(checkout) + return True + return False