From aba934e8b4b2364ce196cdb697c3591536980cb2 Mon Sep 17 00:00:00 2001 From: Laine Date: Thu, 10 Apr 2025 16:57:15 -0400 Subject: [PATCH 1/7] Initial add of ecommercie - order status goal and tools --- tools/__init__.py | 7 ++ tools/data/customer_order_data.json | 15 ++++ tools/ecommerce/get_order_status.py | 26 +++++++ tools/ecommerce/track_package.py | 104 ++++++++++++++++++++++++++++ tools/goal_registry.py | 39 +++++++++++ tools/tool_registry.py | 30 ++++++++ 6 files changed, 221 insertions(+) create mode 100644 tools/data/customer_order_data.json create mode 100644 tools/ecommerce/get_order_status.py create mode 100644 tools/ecommerce/track_package.py diff --git a/tools/__init__.py b/tools/__init__.py index 61d3545..7171456 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -17,6 +17,9 @@ from .fin.check_account_valid import check_account_valid from .fin.get_account_balances import get_account_balance from .fin.move_money import move_money +from .ecommerce.get_order_status import get_order_status +from .ecommerce.track_package import track_package + from .give_hint import give_hint from .guess_location import guess_location @@ -54,6 +57,10 @@ def get_handler(tool_name: str): return get_account_balance if tool_name == "FinMoveMoneyOrder": return move_money + if tool_name == "GetOrderStatus": + return get_order_status + if tool_name == "TrackPackage": + return track_package if tool_name == "GiveHint": return give_hint if tool_name == "GuessLocation": diff --git a/tools/data/customer_order_data.json b/tools/data/customer_order_data.json new file mode 100644 index 0000000..bc5e7c4 --- /dev/null +++ b/tools/data/customer_order_data.json @@ -0,0 +1,15 @@ +{ + "orders": [ + { + "id": "123", + "email": "matt.murdock@nelsonmurdock.com", + "status": "paid" + }, + { + "id": "456", + "email": "foggy.nelson@nelsonmurdock.com", + "status": "shipped", + "tracking_id": "9434609206094724509058" + } + ] +} \ No newline at end of file diff --git a/tools/ecommerce/get_order_status.py b/tools/ecommerce/get_order_status.py new file mode 100644 index 0000000..4b14cf0 --- /dev/null +++ b/tools/ecommerce/get_order_status.py @@ -0,0 +1,26 @@ +from pathlib import Path +import json + +# this is made to demonstrate functionality but it could just as durably be an API call +# called as part of a temporal activity with automatic retries +def get_order_status(args: dict) -> dict: + + order_id = args.get("order_id") + + file_path = Path(__file__).resolve().parent.parent / "data" / "customer_order_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + order_list = data["orders"] + + for order in order_list: + if order["id"] == order_id: + if order["status"] == "shipped": + return{"status": order["status"], "tracking_id": order["tracking_id"]} + else: + return{"status": order["status"]} + + return_msg = "Order " + order_id + " not found." + return {"error": return_msg} \ No newline at end of file diff --git a/tools/ecommerce/track_package.py b/tools/ecommerce/track_package.py new file mode 100644 index 0000000..5ed8dd1 --- /dev/null +++ b/tools/ecommerce/track_package.py @@ -0,0 +1,104 @@ +import http +import os +import json + +def track_package_faked(args: dict) -> dict: + + tracking_id = args.get("tracking_id") + + #return_msg = "Account not found with email address " + email + " or account ID: " + account_id + return {"tracking_info": "delivered, probably"} + +'''Format of response: +{ + "TrackingNumber": "", + "Delivered": false, + "Carrier": "USPS", + "ServiceType": "USPS Ground Advantage", + "PickupDate": "", + "ScheduledDeliveryDate": "April 14, 2025", + "ScheduledDeliveryDateInDateTimeFromat": "2025-04-14T00:00:00", + "StatusCode": "In Transit from Origin Processing", + "Status": "Departed Post Office", + "StatusSummary": "Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035.", + "Message": "", + "DeliveredDateTime": "", + "DeliveredDateTimeInDateTimeFormat": null, + "SignatureName": "", + "DestinationCity": "CITY", + "DestinationState": "ST", + "DestinationZip": "12345", + "DestinationCountry": null, + "EventDate": "2025-04-10T07:06:00", + "TrackingDetails": [ + { + "EventDateTime": "April 10, 2025 7:06 am", + "Event": "Departed Post Office", + "EventAddress": "IRON RIDGE WI 53035", + "State": "WI", + "City": "IRON RIDGE", + "Zip": "53035", + "EventDateTimeInDateTimeFormat": "2025-04-10T07:06:00" + }, + { + "EventDateTime": "April 9, 2025 11:29 am", + "Event": "USPS picked up item", + "EventAddress": "IRON RIDGE WI 53035", + "State": "WI", + "City": "IRON RIDGE", + "Zip": "53035", + "EventDateTimeInDateTimeFormat": "2025-04-09T11:29:00" + }, + { + "EventDateTime": "April 7, 2025 6:29 am", + "Event": "Shipping Label Created, USPS Awaiting Item", + "EventAddress": "IRON RIDGE WI 53035", + "State": "WI", + "City": "IRON RIDGE", + "Zip": "53035", + "EventDateTimeInDateTimeFormat": "2025-04-07T06:29:00" + } + ] +} +''' +def track_package(args: dict) -> dict: + + tracking_id = args.get("tracking_id") + + api_key = os.getenv("PACKAGE_RAPIDAPI_KEY") + api_host = os.getenv("PACKAGE_RAPIDAPI_HOST", "trackingpackage.p.rapidapi.com") + + conn = http.client.HTTPSConnection(api_host) + headers = { + "x-rapidapi-key": api_key, + "x-rapidapi-host": api_host, + "Authorization": "Basic Ym9sZGNoYXQ6TGZYfm0zY2d1QzkuKz9SLw==", + } + + path = f"/TrackingPackage?trackingNumber={tracking_id}" + + conn.request("GET", path, headers=headers) + res = conn.getresponse() + data = res.read() + data_decoded = data.decode("utf-8") + conn.close() + + try: + json_data = json.loads(data_decoded) + except json.JSONDecodeError: + return {"error": "Invalid JSON response"} + + scheduled_delivery_date = json_data["ScheduledDeliveryDate"] + carrier = json_data["Carrier"] + status_summary = json_data["StatusSummary"] + tracking_link = "" + if carrier == "USPS": + tracking_link = f"https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1={tracking_id}" + #tracking_details = json_data.get("TrackingDetails", []) + + return { + "scheduled_delivery_date": scheduled_delivery_date, + "carrier": carrier, + "status_summary": status_summary, + "tracking_link": tracking_link, + } \ No newline at end of file diff --git a/tools/goal_registry.py b/tools/goal_registry.py index 19f62fb..9cc0d96 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -95,6 +95,7 @@ goal_pirate_treasure = AgentGoal( ), ) +# ----- Travel Goals --- goal_match_train_invoice = AgentGoal( id = "goal_match_train_invoice", category_tag="travel-trains", @@ -180,6 +181,7 @@ goal_event_flight_invoice = AgentGoal( ), ) +# ----- HR Goals --- # This goal uses the data/employee_pto_data.json file as dummy data. goal_hr_schedule_pto = AgentGoal( id = "goal_hr_schedule_pto", @@ -268,6 +270,7 @@ goal_hr_check_paycheck_bank_integration_status = AgentGoal( ), ) +# ----- FinServ Goals --- # this tool checks account balances, and uses ./data/customer_account_data.json as dummy data goal_fin_check_account_balances = AgentGoal( id = "goal_fin_check_account_balances", @@ -340,6 +343,41 @@ goal_fin_move_money = AgentGoal( ), ) +# ----- E-Commerce Goals --- +#todo: add goal to list all orders for last X amount of time? +#todo: add goal to reorder? +# this tool checks account balances, and uses ./data/customer_account_data.json as dummy data +goal_ecomm_order_status = AgentGoal( + id = "goal_ecomm_order_status", + category_tag="ecommerce", + agent_name="Check Order Status", + agent_friendly_description="Check the status of your order.", + tools=[ + tool_registry.ecomm_get_order_status, + tool_registry.ecomm_track_package, + ], + description="The user wants to learn the status of a specific order. If the status is 'shipped', they might want to get the package tracking information. To assist with that goal, help the user gather args for these tools in order: " + "1. GetOrderStatus: get the status of the order" + "2. TrackPackage: provide tracking information for the package. This tool is optional and should only be offered if the status is 'shipped' - otherwise, skip this tool and do not mention it to the user.", + starter_prompt=starter_prompt_generic, + example_conversation_history="\n ".join( + [ + "user: I'd like to know the status of my order", + "agent: Sure! I can help you out with that. May I have your email address or order number?", + "user: email is bob.johnson@emailzzz.com ", + "user_confirmed_tool_run: ", + "tool_result: { 'status': 'shipped', 'tracking_id': 'abc123' }", + "agent: Your order has been shipped. Would you like to see the tracking inforation?", + "user: Yes", + "user_confirmed_tool_run: ", + "tool_result: { 'scheduled_delivery_date': 'April 30, 2025', 'carrier': 'USPS', 'status_summary': 'Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035.', 'tracking_link': 'https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=12345", + "agent: Your package is scheduled to be delivered on April 30, 2025 via USPS. Here is the most recent status from them regarding your package: \n" + "Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035. \n" + "You can find the full tracking details here: tracking_link !", + ] + ), +) + #Add the goals to a list for more generic processing, like listing available agents goal_list: List[AgentGoal] = [] goal_list.append(goal_choose_agent_type) @@ -351,6 +389,7 @@ goal_list.append(goal_hr_check_pto) goal_list.append(goal_hr_check_paycheck_bank_integration_status) goal_list.append(goal_fin_check_account_balances) goal_list.append(goal_fin_move_money) +goal_list.append(goal_ecomm_order_status) diff --git a/tools/tool_registry.py b/tools/tool_registry.py index 24fad84..ec402fb 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -316,4 +316,34 @@ financial_move_money = ToolDefinition( description="account number to move the money to", ), ], +) + +# ----- ECommerce Use Case Tools ----- +ecomm_get_order_status = ToolDefinition( + name="GetOrderStatus", + description="Get status of order by order number.", + arguments=[ + ToolArgument( + name="order_id", + type="string", + description="ID of order to determine status of", + ), + ], +) + +ecomm_track_package = ToolDefinition( + name="TrackPackage", + description="Get tracking information for a package by shipping provider and tracking ID", + arguments=[ + ToolArgument( + name="tracking_id", + type="string", + description="ID of package to track", + ), + ToolArgument( + name="userConfirmation", + type="string", + description="Indication of user's desire to get package tracking information", + ), + ], ) \ No newline at end of file From 4e0ff0e53558ef73d6cfc6425f525a68a121e14a Mon Sep 17 00:00:00 2001 From: Laine Date: Fri, 11 Apr 2025 17:14:10 -0400 Subject: [PATCH 2/7] Rename get_order_status to get_order, add ecommerce list orders goal --- .env.example | 3 +- tools/__init__.py | 11 ++- tools/data/customer_order_data.json | 76 +++++++++++++++++-- .../{get_order_status.py => get_order.py} | 11 +-- tools/ecommerce/list_orders.py | 30 ++++++++ tools/ecommerce/track_package.py | 11 ++- tools/goal_registry.py | 65 ++++++++++++---- tools/search_flights.py | 4 +- tools/tool_registry.py | 18 ++++- 9 files changed, 193 insertions(+), 36 deletions(-) rename tools/ecommerce/{get_order_status.py => get_order.py} (71%) create mode 100644 tools/ecommerce/list_orders.py diff --git a/.env.example b/.env.example index ef6bf09..ead99c0 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ RAPIDAPI_KEY=9df2cb5... -RAPIDAPI_HOST=sky-scrapper.p.rapidapi.com +RAPIDAPI_HOST_FLIGHTS=sky-scrapper.p.rapidapi.com #For travel flight information tool +RAPIDAPI_HOST_PACKAGE=trackingpackage.p.rapidapi.com #For eCommerce order status package tracking tool FOOTBALL_DATA_API_KEY=.... STRIPE_API_KEY=sk_test_51J... diff --git a/tools/__init__.py b/tools/__init__.py index 7171456..4bb37b3 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -17,8 +17,9 @@ from .fin.check_account_valid import check_account_valid from .fin.get_account_balances import get_account_balance from .fin.move_money import move_money -from .ecommerce.get_order_status import get_order_status +from .ecommerce.get_order import get_order from .ecommerce.track_package import track_package +from .ecommerce.list_orders import list_orders from .give_hint import give_hint from .guess_location import guess_location @@ -57,10 +58,12 @@ def get_handler(tool_name: str): return get_account_balance if tool_name == "FinMoveMoneyOrder": return move_money - if tool_name == "GetOrderStatus": - return get_order_status + if tool_name == "GetOrder": + return get_order if tool_name == "TrackPackage": - return track_package + return track_package + if tool_name == "ListOrders": + return list_orders if tool_name == "GiveHint": return give_hint if tool_name == "GuessLocation": diff --git a/tools/data/customer_order_data.json b/tools/data/customer_order_data.json index bc5e7c4..8281351 100644 --- a/tools/data/customer_order_data.json +++ b/tools/data/customer_order_data.json @@ -1,15 +1,81 @@ { "orders": [ { - "id": "123", + "id": "100", + "summary": "Lawyer Books", "email": "matt.murdock@nelsonmurdock.com", - "status": "paid" + "status": "cancelled", + "order_date": "2025-03-30", + "last_update": "2025-04-01" }, { - "id": "456", + "id": "101", + "summary": "Bonking Sticks", + "email": "matt.murdock@nelsonmurdock.com", + "status": "paid", + "order_date": "2025-04-01", + "last_order_update": "2025-04-01" + }, + { + "id": "102", + "summary": "Red Sunglasses", + "email": "matt.murdock@nelsonmurdock.com", + "status": "shipped", + "order_date": "2025-04-01", + "last_order_update": "2025-04-01", + "tracking_id": "1Z111111" + }, + { + "id": "200", + "summary": "Paper", "email": "foggy.nelson@nelsonmurdock.com", "status": "shipped", - "tracking_id": "9434609206094724509058" - } + "order_date": "2025-04-03", + "last_update": "2025-04-06", + "tracking_id": "991111" + }, + { + "id": "300", + "summary": "Chemistry Books", + "email": "heisenberg@blue-meth.com", + "status": "shipped", + "order_date": "2025-03-30", + "last_update": "2025-04-06", + "tracking_id": "991111" + }, + { + "id": "301", + "summary": "Book: Being a Cool Bro", + "email": "heisenberg@blue-meth.com", + "status": "cancelled", + "order_date": "2025-04-01", + "last_update": "2025-04-02" + }, + { + "id": "302", + "summary": "Black Hat", + "email": "heisenberg@blue-meth.com", + "status": "delivered", + "order_date": "2025-04-01", + "last_update": "2025-04-06", + "tracking_id": "1Z11111" + }, + { + "id": "400", + "summary": "Giant Graphic Hoodie", + "email": "jessenotpinkman@blue-meth.com", + "status": "shipped", + "order_date": "2025-04-03", + "last_update": "2025-04-09", + "tracking_id": "1Z111111" + }, + { + "id": "401", + "summary": "Giant Pants", + "email": "jessenotpinkman@blue-meth.com", + "status": "processing", + "order_date": "2025-04-03", + "last_update": "2025-04-09" + } ] } \ No newline at end of file diff --git a/tools/ecommerce/get_order_status.py b/tools/ecommerce/get_order.py similarity index 71% rename from tools/ecommerce/get_order_status.py rename to tools/ecommerce/get_order.py index 4b14cf0..5634b7a 100644 --- a/tools/ecommerce/get_order_status.py +++ b/tools/ecommerce/get_order.py @@ -3,7 +3,7 @@ import json # this is made to demonstrate functionality but it could just as durably be an API call # called as part of a temporal activity with automatic retries -def get_order_status(args: dict) -> dict: +def get_order(args: dict) -> dict: order_id = args.get("order_id") @@ -17,10 +17,11 @@ def get_order_status(args: dict) -> dict: for order in order_list: if order["id"] == order_id: - if order["status"] == "shipped": - return{"status": order["status"], "tracking_id": order["tracking_id"]} - else: - return{"status": order["status"]} + return order +# if order["status"] == "shipped": + # return{"status": order["status"], "tracking_id": order["tracking_id"]} + # else: + # return{"status": order["status"]} return_msg = "Order " + order_id + " not found." return {"error": return_msg} \ No newline at end of file diff --git a/tools/ecommerce/list_orders.py b/tools/ecommerce/list_orders.py new file mode 100644 index 0000000..740aa20 --- /dev/null +++ b/tools/ecommerce/list_orders.py @@ -0,0 +1,30 @@ +from pathlib import Path +import json + +def sorting(e): + return e['order_date'] + +def list_orders(args: dict) -> dict: + + email_address = args.get("email_address") + + file_path = Path(__file__).resolve().parent.parent / "data" / "customer_order_data.json" + if not file_path.exists(): + return {"error": "Data file not found."} + + with open(file_path, "r") as file: + data = json.load(file) + order_list = data["orders"] + + rtn_order_list = [] + for order in order_list: + if order["email"] == email_address: + rtn_order_list.append(order) + + if len(rtn_order_list) > 0: + rtn_order_list.sort(key=sorting) + return {"orders": rtn_order_list} + else: + return_msg = "No orders for customer " + email_address + " found." + return {"error": return_msg} + diff --git a/tools/ecommerce/track_package.py b/tools/ecommerce/track_package.py index 5ed8dd1..971eb11 100644 --- a/tools/ecommerce/track_package.py +++ b/tools/ecommerce/track_package.py @@ -65,8 +65,8 @@ def track_package(args: dict) -> dict: tracking_id = args.get("tracking_id") - api_key = os.getenv("PACKAGE_RAPIDAPI_KEY") - api_host = os.getenv("PACKAGE_RAPIDAPI_HOST", "trackingpackage.p.rapidapi.com") + api_key = os.getenv("RAPIDAPI_KEY") + api_host = os.getenv("RAPIDAPI_HOST_PACKAGE", "trackingpackage.p.rapidapi.com") conn = http.client.HTTPSConnection(api_host) headers = { @@ -91,14 +91,19 @@ def track_package(args: dict) -> dict: scheduled_delivery_date = json_data["ScheduledDeliveryDate"] carrier = json_data["Carrier"] status_summary = json_data["StatusSummary"] + tracking_details = json_data.get("TrackingDetails", []) + if tracking_details is not None and tracking_details[0] is not None: + last_tracking_update = tracking_details[0]["EventDateTimeInDateTimeFormat"] tracking_link = "" if carrier == "USPS": tracking_link = f"https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1={tracking_id}" - #tracking_details = json_data.get("TrackingDetails", []) + elif carrier == "UPS": + tracking_link = f"https://www.ups.com/track?track=yes&trackNums={tracking_id}" return { "scheduled_delivery_date": scheduled_delivery_date, "carrier": carrier, "status_summary": status_summary, "tracking_link": tracking_link, + "last_tracking_update": last_tracking_update } \ No newline at end of file diff --git a/tools/goal_registry.py b/tools/goal_registry.py index 9cc0d96..bf6cdde 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -345,7 +345,6 @@ goal_fin_move_money = AgentGoal( # ----- E-Commerce Goals --- #todo: add goal to list all orders for last X amount of time? -#todo: add goal to reorder? # this tool checks account balances, and uses ./data/customer_account_data.json as dummy data goal_ecomm_order_status = AgentGoal( id = "goal_ecomm_order_status", @@ -353,12 +352,12 @@ goal_ecomm_order_status = AgentGoal( agent_name="Check Order Status", agent_friendly_description="Check the status of your order.", tools=[ - tool_registry.ecomm_get_order_status, + tool_registry.ecomm_get_order, tool_registry.ecomm_track_package, ], - description="The user wants to learn the status of a specific order. If the status is 'shipped', they might want to get the package tracking information. To assist with that goal, help the user gather args for these tools in order: " - "1. GetOrderStatus: get the status of the order" - "2. TrackPackage: provide tracking information for the package. This tool is optional and should only be offered if the status is 'shipped' - otherwise, skip this tool and do not mention it to the user.", + description="The user wants to learn the status of a specific order. If the status is 'shipped' or 'delivered', they might want to get the package tracking information. To assist with that goal, help the user gather args for these tools in order: " + "1. GetOrder: get information about an order" + "2. TrackPackage: provide tracking information for the package. This tool is optional and should only be offered if the status is 'shipped' OR 'delivered' - otherwise, skip this tool and do not mention it to the user.", starter_prompt=starter_prompt_generic, example_conversation_history="\n ".join( [ @@ -366,18 +365,60 @@ goal_ecomm_order_status = AgentGoal( "agent: Sure! I can help you out with that. May I have your email address or order number?", "user: email is bob.johnson@emailzzz.com ", "user_confirmed_tool_run: ", - "tool_result: { 'status': 'shipped', 'tracking_id': 'abc123' }", - "agent: Your order has been shipped. Would you like to see the tracking inforation?", + "tool_result: { 'id': '102', 'summary': 'Red Sunglasses', 'email': 'matt.murdock@nelsonmurdock.com', 'status': 'shipped', 'order_date': '2025-04-01', 'last_order_update': '2025-04-06', 'tracking_id': '039813852990618' }", + "agent: Your order 'Red Sunglasses,' placed April 1, 2025, was shipped on April 6, 2025. Would you like to see the tracking inforation?", "user: Yes", "user_confirmed_tool_run: ", - "tool_result: { 'scheduled_delivery_date': 'April 30, 2025', 'carrier': 'USPS', 'status_summary': 'Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035.', 'tracking_link': 'https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=12345", - "agent: Your package is scheduled to be delivered on April 30, 2025 via USPS. Here is the most recent status from them regarding your package: \n" + "tool_result: { 'scheduled_delivery_date': 'April 30, 2025', 'carrier': 'USPS', 'status_summary': 'Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035.', 'tracking_link': 'https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=12345','last_tracking_update': '2025-03-22T16:14:48'}", + "agent: Your package is scheduled to be delivered on April 30, 2025 via USPS. Here is the most recent status from them regarding your package, updated as of March 22: \n" "Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035. \n" "You can find the full tracking details here: tracking_link !", ] ), ) +goal_ecomm_list_orders = AgentGoal( + id = "goal_ecomm_list_orders", + category_tag="ecommerce", + agent_name="List All Orders", + agent_friendly_description="List all orders for a user.", + tools=[ + tool_registry.ecomm_list_orders, + tool_registry.ecomm_get_order, + tool_registry.ecomm_track_package, + ], + description="The user wants to see all of their orders. They may want more details about specific orders, and if the status of an order is 'shipped' or 'delivered', they might want to get the package tracking information. To assist with that goal, help the user gather args for this tool: " + "1. ListOrders: list orders for a user" + " and then offer the following tools, in a loop, until the user indicates they are done:" + "2. GetOrder: get information about an order. This tool is optional." + "3. TrackPackage: provide tracking information for the package. This tool is optional and should only be offered if the status is 'shipped' OR 'delivered' - otherwise, skip this tool and do not mention it to the user.", + starter_prompt=starter_prompt_generic, + example_conversation_history="\n ".join( + [ + "user: I'd like to see all of my orders.", + "agent: Sure! I can help you out with that. May I have your email address?", + "user: email is bob.johnson@emailzzz.com ", + "user_confirmed_tool_run: ", + "tool_result: a list of orders including [{'id': '102', 'summary': 'Red Sunglasses', 'email': 'matt.murdock@nelsonmurdock.com', 'status': 'shipped', 'order_date': '2025-04-01', 'last_order_update': '2025-04-06', 'tracking_id': '039813852990618' }, { 'id': '103', 'summary': 'Blue Sunglasses', 'email': 'matt.murdock@nelsonmurdock.com', 'status': 'paid', 'order_date': '2025-04-03', 'last_order_update': '2025-04-07' }]", + "agent: Your orders are as follows: \n", + "1. Red Sunglasses, ordered 4/1/2025 \n", + "2. Blue Sunglasses, ordered 4/3/2025 \n", + "Would you like more information about any of your orders?" + "user: Yes, the Red Sunglasses", + "agent: Your order 'Red Sunglasses,' placed April 1, 2025, was shipped on April 6, 2025. Would you like to see the tracking inforation?", + "user: Yes", + "user_confirmed_tool_run: ", + "tool_result: { 'scheduled_delivery_date': 'April 30, 2025', 'carrier': 'USPS', 'status_summary': 'Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035.', 'tracking_link': 'https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=12345','last_tracking_update': '2025-03-22T16:14:48'}", + "agent: Your package is scheduled to be delivered on April 30, 2025 via USPS. Here is the most recent status from them regarding your package \n, updated as of March 22: \n" + "Your item has left our acceptance facility and is in transit to a sorting facility on April 10, 2025 at 7:06 am in IRON RIDGE, WI 53035. \n" + "You can find the full tracking details here: tracking_link ! \n" + "Would you like more information about any of your other orders?", + "user: No" + "agent: Thanks, and have a great day!" + ] + ), +) + #Add the goals to a list for more generic processing, like listing available agents goal_list: List[AgentGoal] = [] goal_list.append(goal_choose_agent_type) @@ -389,7 +430,5 @@ goal_list.append(goal_hr_check_pto) goal_list.append(goal_hr_check_paycheck_bank_integration_status) goal_list.append(goal_fin_check_account_balances) goal_list.append(goal_fin_move_money) -goal_list.append(goal_ecomm_order_status) - - - +goal_list.append(goal_ecomm_list_orders) +goal_list.append(goal_ecomm_order_status) \ No newline at end of file diff --git a/tools/search_flights.py b/tools/search_flights.py index a2335f0..24a907d 100644 --- a/tools/search_flights.py +++ b/tools/search_flights.py @@ -11,7 +11,7 @@ def search_airport(query: str) -> list: """ load_dotenv(override=True) api_key = os.getenv("RAPIDAPI_KEY", "YOUR_DEFAULT_KEY") - api_host = os.getenv("RAPIDAPI_HOST", "sky-scrapper.p.rapidapi.com") + api_host = os.getenv("RAPIDAPI_HOST_FLIGHTS", "sky-scrapper.p.rapidapi.com") conn = http.client.HTTPSConnection(api_host) headers = { @@ -73,7 +73,7 @@ def search_flights_real_api( # Step 2: Call flight search with resolved codes load_dotenv(override=True) api_key = os.getenv("RAPIDAPI_KEY", "YOUR_DEFAULT_KEY") - api_host = os.getenv("RAPIDAPI_HOST", "sky-scrapper.p.rapidapi.com") + api_host = os.getenv("RAPIDAPI_HOST_FLIGHTS", "sky-scrapper.p.rapidapi.com") conn = http.client.HTTPSConnection(api_host) headers = { diff --git a/tools/tool_registry.py b/tools/tool_registry.py index ec402fb..a8eaa2a 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -319,9 +319,21 @@ financial_move_money = ToolDefinition( ) # ----- ECommerce Use Case Tools ----- -ecomm_get_order_status = ToolDefinition( - name="GetOrderStatus", - description="Get status of order by order number.", +ecomm_list_orders = ToolDefinition( + name="ListOrders", + description="Get all orders for a certain email address.", + arguments=[ + ToolArgument( + name="email_address", + type="string", + description="Email address of user by which to find orders", + ), + ], +) + +ecomm_get_order = ToolDefinition( + name="GetOrder", + description="Get infromation about an order by order ID.", arguments=[ ToolArgument( name="order_id", From dddd2977b9cde023366d6e1710f8b7e13e56fe7b Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Sun, 13 Apr 2025 17:03:50 -0400 Subject: [PATCH 3/7] adding ecommerce to .env.example and some error handling in track_package --- .env.example | 2 +- tools/ecommerce/track_package.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index ead99c0..844fd27 100644 --- a/.env.example +++ b/.env.example @@ -43,7 +43,7 @@ AGENT_GOAL=goal_choose_agent_type # for multi-goal start #Choose which category(ies) of goals you want to be listed by the Agent Goal picker if enabled above # - options are system (always included), hr, travel, or all. -GOAL_CATEGORIES=hr,travel-flights,travel-trains,fin # default is all +GOAL_CATEGORIES=hr,travel-flights,travel-trains,fin,ecommerce # default is all #GOAL_CATEGORIES=travel-flights # Set if the workflow should wait for the user to click a confirm button (and if the UI should show the confirm button and tool args) diff --git a/tools/ecommerce/track_package.py b/tools/ecommerce/track_package.py index 971eb11..55b14fd 100644 --- a/tools/ecommerce/track_package.py +++ b/tools/ecommerce/track_package.py @@ -92,7 +92,8 @@ def track_package(args: dict) -> dict: carrier = json_data["Carrier"] status_summary = json_data["StatusSummary"] tracking_details = json_data.get("TrackingDetails", []) - if tracking_details is not None and tracking_details[0] is not None: + last_tracking_update = "" + if tracking_details and tracking_details is not None and tracking_details[0] is not None: last_tracking_update = tracking_details[0]["EventDateTimeInDateTimeFormat"] tracking_link = "" if carrier == "USPS": From ac44d35acbd609713bcf119c2c0e088718bf5356 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Tue, 15 Apr 2025 16:46:09 -0400 Subject: [PATCH 4/7] changes to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2d708e1..208ebe6 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,5 @@ coverage.xml # PyCharm / IntelliJ settings .idea/ -.env \ No newline at end of file +.env +.env* \ No newline at end of file From 6f9079ba124682f4e44e44d686305b7dabc35913 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Wed, 16 Apr 2025 16:23:31 -0400 Subject: [PATCH 5/7] updates to todo --- todo.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/todo.md b/todo.md index f06d42b..da49eb0 100644 --- a/todo.md +++ b/todo.md @@ -18,6 +18,11 @@ [ ] new loan/fraud check/update with start
+[ ] for demo simulate failure - add utilities/simulated failures from pipeline demo
+ +[ ] ecommerce goals
+- [ ] add to docs
+- [ ] decide about api key names with Laine
[ ] ask the ai agent how it did at the end of the conversation, was it efficient? successful? insert a search attribute to document that before return
- Insight into the agent’s performance
From e62b105872a376efbb64a4d3c67756c0168d5b38 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Thu, 17 Apr 2025 05:23:17 -0400 Subject: [PATCH 6/7] adding to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4c8f868..c2d2dde 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ coverage.xml .env *.env +.env* From cf55f0eaee5af9d7c4e8b937b8f8e69229baf8f1 Mon Sep 17 00:00:00 2001 From: Joshua Smith Date: Thu, 17 Apr 2025 08:59:15 -0400 Subject: [PATCH 7/7] fixing some post-merge bugs --- tools/goal_registry.py | 3 +++ tools/tool_registry.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tools/goal_registry.py b/tools/goal_registry.py index c22eb21..f86b59b 100644 --- a/tools/goal_registry.py +++ b/tools/goal_registry.py @@ -371,6 +371,9 @@ goal_fin_loan_application = AgentGoal( "user_confirmed_tool_run: ", "tool_result: { 'status': submitted, 'detailed_status': loan application is submitted and initial validation is complete, 'confirmation id': 333421, 'next_step': You'll receive a confirmation for final approval in three business days }", "agent: I have submitted your loan application process and the initial validation is successful. Your application ID is 333421. You'll receive a notification for final approval from us in three business days. " + ] + ), +) # ----- E-Commerce Goals --- #todo: add goal to list all orders for last X amount of time? diff --git a/tools/tool_registry.py b/tools/tool_registry.py index efc3cf3..ed19e63 100644 --- a/tools/tool_registry.py +++ b/tools/tool_registry.py @@ -333,6 +333,9 @@ financial_submit_loan_approval = ToolDefinition( name="amount", type="string", description="amount requested for the loan", + ), + ], +) # ----- ECommerce Use Case Tools ----- ecomm_list_orders = ToolDefinition(