-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from StreetLamb/pizza-example
Pizza example
- Loading branch information
Showing
9 changed files
with
363 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Food ordering example | ||
|
||
Demostrate orchestrating multiple agents in a food ordering workflow. | ||
|
||
## Setup | ||
|
||
Run Temporal locally: | ||
```shell | ||
temporal server start-dev | ||
``` | ||
|
||
Ensure you have `OPENAI_API_KEY` in the .env file: | ||
``` | ||
OPENAI_API_KEY=<YOUR_OPENAI_API_KEY> | ||
``` | ||
|
||
Start the worker: | ||
```shell | ||
python run_worker.py | ||
``` | ||
|
||
In another terminal, run the client: | ||
```shell | ||
python send_message.py | ||
``` |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from rojak.agents import OpenAIAgent | ||
from rojak.types import RetryOptions, RetryPolicy | ||
|
||
|
||
retry_options = RetryOptions( | ||
retry_policy=RetryPolicy(non_retryable_error_types=["TypeError"]) | ||
) | ||
triage_agent = OpenAIAgent( | ||
name="Triage Agent", | ||
instructions=""" | ||
You are the Triage Agent. Your role is to assist customers by identifying their needs and routing them to the correct agent: | ||
- **Food Ordering** (`to_food_order`): For menu recommendations, adding/removing items, viewing or modifying the cart. | ||
- **Payment** (`to_payment`): For payments, payment method queries, receipts, or payment issues. | ||
- **Feedback** (`to_feedback`): For reviews, ratings, comments, or complaints. | ||
If unsure, guide customers by explaining options (ordering, payment, feedback). For multi-step needs, start with the immediate priority and redirect after. | ||
Always ensure clear, polite, and accurate communication during handoffs. | ||
""", | ||
functions=["to_food_order", "to_payment", "to_feedback"], | ||
tool_choice="required", | ||
retry_options=retry_options, | ||
) | ||
|
||
food_order_agent = OpenAIAgent( | ||
name="Food Ordering Agent", | ||
instructions={"type": "function", "name": "food_ordering_instructions"}, | ||
functions=[ | ||
"to_triage", | ||
"add_to_cart", | ||
"remove_from_cart", | ||
"get_cart", | ||
"get_menu", | ||
], | ||
retry_options=retry_options, | ||
) | ||
|
||
|
||
payment_agent = OpenAIAgent( | ||
name="Payment Agent", | ||
instructions=""" | ||
You are the Payment Agent. Your role is to securely and efficiently handle the payment process for customers. | ||
Start by confirming the payment amount and presenting the available payment methods (e.g., credit card, mobile wallet, or cash). | ||
Use the `process_payment` function to finalize the transaction and provide a receipt. | ||
In case of a failed transaction, assist customers by suggesting alternative payment options or troubleshooting the issue. | ||
Always maintain a courteous and professional tone, ensuring customers feel supported throughout the payment process. | ||
Redirect customers to the Triage Agent if they need help with non-payment tasks. | ||
""", | ||
functions=["to_triage", "process_payment", "get_receipt"], | ||
retry_options=retry_options, | ||
) | ||
|
||
feedback_agent = OpenAIAgent( | ||
name="Feedback Agent", | ||
instructions=""" | ||
You are the Feedback Agent. Your role is to collect and manage customer feedback to improve the overall experience. | ||
Ask customers to rate their experience and provide detailed comments about the food, service, or satisfaction level. | ||
Use the `provide_feedback` function to log their input. | ||
If the customer has complaints, acknowledge them empathetically and offer to escalate the issue to the relevant team. | ||
Encourage constructive feedback and thank customers for their time and insights. | ||
Redirect customers to the Triage Agent if they wish to engage with other services after providing feedback. | ||
""", | ||
functions=["to_triage", "provide_feedback"], | ||
retry_options=retry_options, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
from .agents import ( | ||
triage_agent, | ||
food_order_agent, | ||
payment_agent, | ||
feedback_agent, | ||
) | ||
from copy import deepcopy | ||
|
||
|
||
def food_ordering_instructions(context_variables): | ||
return f""" | ||
You are the Food Ordering Agent. Your role is to assist customers in selecting and managing their food orders. | ||
- **Recommendations**: Start by retrieving the available menu using the `get_menu` function. Guide customers in choosing items based on their preferences or suggest popular options. Provide clear and concise descriptions of menu items. | ||
- **Adding to Order**: When customers request to add items, confirm their selection against the menu. Use the `get_menu` function to ensure the item is available. If the item exists, proceed to add it using the `add_to_cart` function. For unavailable items, politely inform the customer and suggest alternatives from the menu. | ||
- **Order Management**: Customers may also want to modify their order. Use the `get_cart` function to show the current order details and confirm requested changes. Use `remove_from_cart` to delete specific items as needed and provide an updated summary of the cart. | ||
- **Guiding and Redirecting**: If customers are unsure of what they want, offer assistance by highlighting popular dishes or providing recommendations. Redirect customers to the Triage Agent if they need help beyond ordering or recommendations. | ||
- **Tone and Accuracy**: Maintain a polite and professional tone, ensuring order details are accurate at every step. Always summarize the current state of the cart after any action. | ||
Redirect customers to the Triage Agent if they need help with non-ordering tasks. | ||
Remember: Customers can only order items listed in the menu. Validate all item requests before proceeding with any order changes. | ||
Customer Preferences: {context_variables.get("preferences", "N/A")} | ||
""" | ||
|
||
|
||
def to_food_order(): | ||
"""Route to the food order agent.""" | ||
return food_order_agent | ||
|
||
|
||
def to_payment(): | ||
"""Route to the payment agent.""" | ||
return payment_agent | ||
|
||
|
||
def to_feedback(): | ||
"""Route to the feedback agent.""" | ||
return feedback_agent | ||
|
||
|
||
def to_triage(): | ||
"""Route to the triage agent.""" | ||
return triage_agent | ||
|
||
|
||
def get_menu(): | ||
"""Return a list of menu items for a pizza place.""" | ||
menu = [ | ||
{"name": "Margherita Pizza", "cost": 12.99}, | ||
{"name": "Pepperoni Pizza", "cost": 14.49}, | ||
{"name": "BBQ Chicken Pizza", "cost": 15.99}, | ||
{"name": "Veggie Supreme Pizza", "cost": 13.99}, | ||
{"name": "Meat Lovers Pizza", "cost": 16.99}, | ||
{"name": "Garlic Knots", "cost": 5.99}, | ||
{"name": "Cheesy Breadsticks", "cost": 6.49}, | ||
{"name": "Classic Caesar Salad", "cost": 9.49}, | ||
{"name": "Buffalo Wings (8 pieces)", "cost": 10.99}, | ||
{"name": "Mozzarella Sticks", "cost": 7.99}, | ||
{"name": "Chocolate Chip Cannoli", "cost": 4.99}, | ||
{"name": "Tiramisu Slice", "cost": 5.99}, | ||
{"name": "Fountain Soda", "cost": 2.49}, | ||
{"name": "Sparkling Lemonade", "cost": 3.49}, | ||
{"name": "Iced Tea", "cost": 2.99}, | ||
{"name": "Craft Beer (Pint)", "cost": 6.99}, | ||
{"name": "House Red Wine (Glass)", "cost": 7.99}, | ||
] | ||
return menu | ||
|
||
|
||
def add_to_cart(item: str, cost: int, quantity: int, context_variables: dict): | ||
"""Add an item to the cart.""" | ||
if item in context_variables["cart"]: | ||
context_variables["cart"][item]["quantity"] += quantity | ||
else: | ||
context_variables["cart"][item] = {"quantity": quantity, "unit_cost": cost} | ||
return f"Added {quantity} of {item} to your cart." | ||
|
||
|
||
def remove_from_cart(item: str, quantity: int, context_variables: dict): | ||
"""Remove an item from the cart by quantity.""" | ||
if item in context_variables["cart"]: | ||
if quantity >= context_variables["cart"][item]["quantity"]: | ||
del context_variables["cart"][item] | ||
return f"Removed {item} from your cart." | ||
else: | ||
context_variables["cart"][item]["quantity"] -= quantity | ||
return f"Decreased quantity of {item} by {quantity}." | ||
else: | ||
return f"{item} is not in your cart." | ||
|
||
|
||
def get_cart(context_variables: dict): | ||
"""Return the contents of the cart.""" | ||
cart = context_variables.get("cart", {}) | ||
if cart: | ||
cart_items = [ | ||
f"{item} (x{details['quantity']}) - ${details['quantity'] * details['unit_cost']:.2f}" | ||
for item, details in cart.items() | ||
] | ||
return f"Your cart contains: {', '.join(cart_items)}" | ||
else: | ||
return "Your cart is empty." | ||
|
||
|
||
def process_payment(context_variables: dict): | ||
"""Process the payment and clear the cart.""" | ||
context_variables["receipt"] = deepcopy(context_variables["cart"]) | ||
context_variables["cart"] = {} | ||
return "Payment processed successfully!" | ||
|
||
|
||
def get_receipt(context_variables: dict): | ||
"""Return the receipt.""" | ||
receipt = context_variables.get("receipt", {}) | ||
if receipt: | ||
receipt_items = [ | ||
f"{item} (x{details['quantity']}) - ${details['quantity'] * details['unit_cost']:.2f}" | ||
for item, details in receipt.items() | ||
] | ||
return f"Your receipt contains: {', '.join(receipt_items)}" | ||
else: | ||
return "No receipt available." | ||
|
||
|
||
def provide_feedback(): | ||
"""Submit a review.""" | ||
return "Review submitted successfully!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# main.py | ||
from temporalio.client import Client | ||
from rojak import Rojak | ||
from rojak.agents import OpenAIAgentActivities, OpenAIAgentOptions | ||
import asyncio | ||
from examples.pizza.functions import ( | ||
to_food_order, | ||
to_payment, | ||
to_feedback, | ||
to_triage, | ||
get_menu, | ||
add_to_cart, | ||
remove_from_cart, | ||
get_cart, | ||
process_payment, | ||
get_receipt, | ||
provide_feedback, | ||
food_ordering_instructions, | ||
) | ||
|
||
|
||
async def main(): | ||
# Create client connected to server at the given address | ||
client = await Client.connect("localhost:7233") | ||
|
||
openai_activities = OpenAIAgentActivities( | ||
OpenAIAgentOptions( | ||
all_functions=[ | ||
to_food_order, | ||
to_payment, | ||
to_feedback, | ||
to_triage, | ||
get_menu, | ||
add_to_cart, | ||
remove_from_cart, | ||
get_cart, | ||
process_payment, | ||
get_receipt, | ||
provide_feedback, | ||
food_ordering_instructions, | ||
] | ||
) | ||
) | ||
|
||
rojak = Rojak(client, task_queue="tasks") | ||
worker = await rojak.create_worker([openai_activities]) | ||
await worker.run() | ||
|
||
|
||
if __name__ == "__main__": | ||
print("Starting worker") | ||
print("Then run 'python send_messages.py' to start sending messages.") | ||
|
||
asyncio.run(main()) |
Oops, something went wrong.