mirror of
https://github.com/EvolutionAPI/adk-python.git
synced 2025-07-14 01:41:25 -06:00
339 lines
10 KiB
Python
339 lines
10 KiB
Python
# Copyright 2025 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from google.adk import Agent
|
|
|
|
# A lightweight in-memory mock database
|
|
ORDER_DB = {
|
|
"1": "FINISHED",
|
|
"2": "CANCELED",
|
|
"3": "PENDING",
|
|
"4": "PENDING",
|
|
} # Order id to status mapping. Available states: 'FINISHED', 'PENDING', and 'CANCELED'
|
|
USER_TO_ORDER_DB = {
|
|
"user_a": ["1", "4"],
|
|
"user_b": ["2"],
|
|
"user_c": ["3"],
|
|
} # User id to Order id mapping
|
|
TICKET_DB = [{
|
|
"ticket_id": "1",
|
|
"user_id": "user_a",
|
|
"issue_type": "LOGIN_ISSUE",
|
|
"status": "OPEN",
|
|
}] # Available states: 'OPEN', 'CLOSED', 'ESCALATED'
|
|
USER_INFO_DB = {
|
|
"user_a": {"name": "Alice", "email": "alice@example.com"},
|
|
"user_b": {"name": "Bob", "email": "bob@example.com"},
|
|
}
|
|
|
|
|
|
def reset_data():
|
|
global ORDER_DB
|
|
global USER_TO_ORDER_DB
|
|
global TICKET_DB
|
|
global USER_INFO_DB
|
|
ORDER_DB = {
|
|
"1": "FINISHED",
|
|
"2": "CANCELED",
|
|
"3": "PENDING",
|
|
"4": "PENDING",
|
|
}
|
|
USER_TO_ORDER_DB = {
|
|
"user_a": ["1", "4"],
|
|
"user_b": ["2"],
|
|
"user_c": ["3"],
|
|
}
|
|
TICKET_DB = [{
|
|
"ticket_id": "1",
|
|
"user_id": "user_a",
|
|
"issue_type": "LOGIN_ISSUE",
|
|
"status": "OPEN",
|
|
}]
|
|
USER_INFO_DB = {
|
|
"user_a": {"name": "Alice", "email": "alice@example.com"},
|
|
"user_b": {"name": "Bob", "email": "bob@example.com"},
|
|
}
|
|
|
|
|
|
def get_order_status(order_id: str) -> str:
|
|
"""Get the status of an order.
|
|
|
|
Args:
|
|
order_id (str): The unique identifier of the order.
|
|
|
|
Returns:
|
|
str: The status of the order (e.g., 'FINISHED', 'CANCELED', 'PENDING'),
|
|
or 'Order not found' if the order_id does not exist.
|
|
"""
|
|
return ORDER_DB.get(order_id, "Order not found")
|
|
|
|
|
|
def get_order_ids_for_user(user_id: str) -> list:
|
|
"""Get the list of order IDs assigned to a specific transaction associated with a user.
|
|
|
|
Args:
|
|
user_id (str): The unique identifier of the user.
|
|
|
|
Returns:
|
|
List[str]: A list of order IDs associated with the user, or an empty list
|
|
if no orders are found.
|
|
"""
|
|
return USER_TO_ORDER_DB.get(user_id, [])
|
|
|
|
|
|
def cancel_order(order_id: str) -> str:
|
|
"""Cancel an order if it is in a 'PENDING' state.
|
|
|
|
You should call "get_order_status" to check the status first, before calling
|
|
this tool.
|
|
|
|
Args:
|
|
order_id (str): The unique identifier of the order to be canceled.
|
|
|
|
Returns:
|
|
str: A message indicating whether the order was successfully canceled or
|
|
not.
|
|
"""
|
|
if order_id in ORDER_DB and ORDER_DB[order_id] == "PENDING":
|
|
ORDER_DB[order_id] = "CANCELED"
|
|
return f"Order {order_id} has been canceled."
|
|
return f"Order {order_id} cannot be canceled."
|
|
|
|
|
|
def refund_order(order_id: str) -> str:
|
|
"""Process a refund for an order if it is in a 'CANCELED' state.
|
|
|
|
You should call "get_order_status" to check if status first, before calling
|
|
this tool.
|
|
|
|
Args:
|
|
order_id (str): The unique identifier of the order to be refunded.
|
|
|
|
Returns:
|
|
str: A message indicating whether the order was successfully refunded or
|
|
not.
|
|
"""
|
|
if order_id in ORDER_DB and ORDER_DB[order_id] == "CANCELED":
|
|
return f"Order {order_id} has been refunded."
|
|
return f"Order {order_id} cannot be refunded."
|
|
|
|
|
|
def create_ticket(user_id: str, issue_type: str) -> str:
|
|
"""Create a new support ticket for a user.
|
|
|
|
Args:
|
|
user_id (str): The unique identifier of the user creating the ticket.
|
|
issue_type (str): An issue type the user is facing. Available types:
|
|
'LOGIN_ISSUE', 'ORDER_ISSUE', 'OTHER'.
|
|
|
|
Returns:
|
|
str: A message indicating that the ticket was created successfully,
|
|
including the ticket ID.
|
|
"""
|
|
ticket_id = str(len(TICKET_DB) + 1)
|
|
TICKET_DB.append({
|
|
"ticket_id": ticket_id,
|
|
"user_id": user_id,
|
|
"issue_type": issue_type,
|
|
"status": "OPEN",
|
|
})
|
|
return f"Ticket {ticket_id} created successfully."
|
|
|
|
|
|
def get_ticket_info(ticket_id: str) -> str:
|
|
"""Retrieve the information of a support ticket.
|
|
|
|
current status of a support ticket.
|
|
|
|
Args:
|
|
ticket_id (str): The unique identifier of the ticket.
|
|
|
|
Returns:
|
|
A dictionary contains the following fields, or 'Ticket not found' if the
|
|
ticket_id does not exist:
|
|
- "ticket_id": str, the current ticket id
|
|
- "user_id": str, the associated user id
|
|
- "issue": str, the issue type
|
|
- "status": The current status of the ticket (e.g., 'OPEN', 'CLOSED',
|
|
'ESCALATED')
|
|
|
|
Example: {"ticket_id": "1", "user_id": "user_a", "issue": "Login issue",
|
|
"status": "OPEN"}
|
|
"""
|
|
for ticket in TICKET_DB:
|
|
if ticket["ticket_id"] == ticket_id:
|
|
return ticket
|
|
return "Ticket not found"
|
|
|
|
|
|
def get_tickets_for_user(user_id: str) -> list:
|
|
"""Get all the ticket IDs associated with a user.
|
|
|
|
Args:
|
|
user_id (str): The unique identifier of the user.
|
|
|
|
Returns:
|
|
List[str]: A list of ticket IDs associated with the user.
|
|
If no tickets are found, returns an empty list.
|
|
"""
|
|
return [
|
|
ticket["ticket_id"]
|
|
for ticket in TICKET_DB
|
|
if ticket["user_id"] == user_id
|
|
]
|
|
|
|
|
|
def update_ticket_status(ticket_id: str, status: str) -> str:
|
|
"""Update the status of a support ticket.
|
|
|
|
Args:
|
|
ticket_id (str): The unique identifier of the ticket.
|
|
status (str): The new status to assign to the ticket (e.g., 'OPEN',
|
|
'CLOSED', 'ESCALATED').
|
|
|
|
Returns:
|
|
str: A message indicating whether the ticket status was successfully
|
|
updated.
|
|
"""
|
|
for ticket in TICKET_DB:
|
|
if ticket["ticket_id"] == ticket_id:
|
|
ticket["status"] = status
|
|
return f"Ticket {ticket_id} status updated to {status}."
|
|
return "Ticket not found"
|
|
|
|
|
|
def get_user_info(user_id: str) -> dict:
|
|
"""Retrieve information (name, email) about a user.
|
|
|
|
Args:
|
|
user_id (str): The unique identifier of the user.
|
|
|
|
Returns:
|
|
dict or str: A dictionary containing user information of the following
|
|
fields, or 'User not found' if the user_id does not exist:
|
|
|
|
- name: The name of the user
|
|
- email: The email address of the user
|
|
|
|
For example, {"name": "Chelsea", "email": "123@example.com"}
|
|
"""
|
|
return USER_INFO_DB.get(user_id, "User not found")
|
|
|
|
|
|
def send_email(user_id: str, email: str) -> list:
|
|
"""Send email to user for notification.
|
|
|
|
Args:
|
|
user_id (str): The unique identifier of the user.
|
|
email (str): The email address of the user.
|
|
|
|
Returns:
|
|
str: A message indicating whether the email was successfully sent.
|
|
"""
|
|
if user_id in USER_INFO_DB:
|
|
return f"Email sent to {email} for user id {user_id}"
|
|
return "Cannot find this user"
|
|
|
|
|
|
# def update_user_info(user_id: str, new_info: dict[str, str]) -> str:
|
|
def update_user_info(user_id: str, email: str, name: str) -> str:
|
|
"""Update a user's information.
|
|
|
|
Args:
|
|
user_id (str): The unique identifier of the user.
|
|
new_info (dict): A dictionary containing the fields to be updated (e.g.,
|
|
{'email': 'new_email@example.com'}). Available field keys: 'email' and
|
|
'name'.
|
|
|
|
Returns:
|
|
str: A message indicating whether the user's information was successfully
|
|
updated or not.
|
|
"""
|
|
if user_id in USER_INFO_DB:
|
|
# USER_INFO_DB[user_id].update(new_info)
|
|
if email and name:
|
|
USER_INFO_DB[user_id].update({"email": email, "name": name})
|
|
elif email:
|
|
USER_INFO_DB[user_id].update({"email": email})
|
|
elif name:
|
|
USER_INFO_DB[user_id].update({"name": name})
|
|
else:
|
|
raise ValueError("this should not happen.")
|
|
return f"User {user_id} information updated."
|
|
return "User not found"
|
|
|
|
|
|
def get_user_id_from_cookie() -> str:
|
|
"""Get user ID(username) from the cookie.
|
|
|
|
Only use this function when you do not know user ID(username).
|
|
|
|
Args: None
|
|
|
|
Returns:
|
|
str: The user ID.
|
|
"""
|
|
return "user_a"
|
|
|
|
|
|
root_agent = Agent(
|
|
model="gemini-2.0-flash-001",
|
|
name="Ecommerce_Customer_Service",
|
|
instruction="""
|
|
You are an intelligent customer service assistant for an e-commerce platform. Your goal is to accurately understand user queries and use the appropriate tools to fulfill requests. Follow these guidelines:
|
|
|
|
1. **Understand the Query**:
|
|
- Identify actions and conditions (e.g., create a ticket only for pending orders).
|
|
- Extract necessary details (e.g., user ID, order ID) from the query or infer them from the context.
|
|
|
|
2. **Plan Multi-Step Workflows**:
|
|
- Break down complex queries into sequential steps. For example
|
|
- typical workflow:
|
|
- Retrieve IDs or references first (e.g., orders for a user).
|
|
- Evaluate conditions (e.g., check order status).
|
|
- Perform actions (e.g., create a ticket) only when conditions are met.
|
|
- another typical workflows - order cancellation and refund:
|
|
- Retrieve all orders for the user (`get_order_ids_for_user`).
|
|
- Cancel pending orders (`cancel_order`).
|
|
- Refund canceled orders (`refund_order`).
|
|
- Notify the user (`send_email`).
|
|
- another typical workflows - send user report:
|
|
- Get user id.
|
|
- Get user info(like emails)
|
|
- Send email to user.
|
|
|
|
3. **Avoid Skipping Steps**:
|
|
- Ensure each intermediate step is completed before moving to the next.
|
|
- Do not create tickets or take other actions without verifying the conditions specified in the query.
|
|
|
|
4. **Provide Clear Responses**:
|
|
- Confirm the actions performed, including details like ticket ID or pending orders.
|
|
- Ensure the response aligns with the steps taken and query intent.
|
|
""",
|
|
tools=[
|
|
get_order_status,
|
|
cancel_order,
|
|
get_order_ids_for_user,
|
|
refund_order,
|
|
create_ticket,
|
|
update_ticket_status,
|
|
get_tickets_for_user,
|
|
get_ticket_info,
|
|
get_user_info,
|
|
send_email,
|
|
update_user_info,
|
|
get_user_id_from_cookie,
|
|
],
|
|
)
|