Skip to content

Commit 06501d7

Browse files
Merge pull request #712 from MervinPraison/claude/issue-491-20250628_070020
feat: implement agent-to-agent handoffs
2 parents e34b00a + fc9e410 commit 06501d7

File tree

9 files changed

+1131
-1
lines changed

9 files changed

+1131
-1
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""
2+
Advanced handoff example with callbacks, input types, and filters.
3+
4+
This example demonstrates advanced handoff features including:
5+
- Custom handoff callbacks
6+
- Structured input data
7+
- Input filters
8+
- Custom tool names and descriptions
9+
"""
10+
11+
from praisonaiagents import Agent, handoff, handoff_filters, prompt_with_handoff_instructions
12+
from pydantic import BaseModel
13+
from typing import Optional
14+
import logging
15+
16+
logging.basicConfig(level=logging.INFO)
17+
18+
19+
# Define structured input for escalation
20+
class EscalationData(BaseModel):
21+
reason: str
22+
priority: Optional[str] = "normal"
23+
customer_sentiment: Optional[str] = None
24+
25+
26+
# Callback function for logging handoffs
27+
def log_handoff(source_agent: Agent):
28+
"""Log when a handoff occurs"""
29+
logging.info(f"Handoff initiated from {source_agent.name}")
30+
31+
32+
# Callback function with input data
33+
def log_escalation(source_agent: Agent, input_data: EscalationData):
34+
"""Log escalation with structured data"""
35+
logging.info(f"ESCALATION from {source_agent.name}: {input_data.reason} (Priority: {input_data.priority})")
36+
37+
38+
# Create specialized agents
39+
faq_agent = Agent(
40+
name="FAQ Agent",
41+
role="FAQ Specialist",
42+
goal="Answer frequently asked questions using knowledge base",
43+
backstory="I have access to comprehensive FAQ documentation and can quickly provide accurate answers."
44+
)
45+
46+
escalation_agent = Agent(
47+
name="Escalation Agent",
48+
role="Senior Support Manager",
49+
goal="Handle escalated issues that require special attention",
50+
backstory="I handle complex cases that need senior-level intervention and decision-making."
51+
)
52+
53+
# Create support agent with custom handoffs
54+
support_agent = Agent(
55+
name="Support Agent",
56+
role="Customer Support Representative",
57+
goal="Provide first-line support and escalate when necessary",
58+
backstory="I help customers with their issues and know when to involve specialists.",
59+
instructions=prompt_with_handoff_instructions(
60+
"""Help customers with their requests. You should:
61+
1. Try to resolve issues yourself first
62+
2. Transfer to FAQ Agent for common questions you can't answer
63+
3. Escalate to senior management for complex or sensitive issues
64+
65+
When escalating, always provide a clear reason and assess the priority.""",
66+
None # Agent will be set later
67+
),
68+
handoffs=[
69+
# Simple handoff with callback
70+
handoff(
71+
faq_agent,
72+
on_handoff=log_handoff,
73+
input_filter=handoff_filters.remove_all_tools # Remove tool calls from history
74+
),
75+
# Advanced handoff with structured input
76+
handoff(
77+
escalation_agent,
78+
tool_name_override="escalate_to_manager",
79+
tool_description_override="Escalate complex or sensitive issues to senior management",
80+
on_handoff=log_escalation,
81+
input_type=EscalationData
82+
)
83+
]
84+
)
85+
86+
# Update the instructions with the agent reference
87+
support_agent.instructions = prompt_with_handoff_instructions(
88+
support_agent.instructions,
89+
support_agent
90+
)
91+
92+
93+
# Example with custom input filter
94+
def custom_filter(data):
95+
"""Keep only last 3 messages and remove system messages"""
96+
data = handoff_filters.keep_last_n_messages(3)(data)
97+
data = handoff_filters.remove_system_messages(data)
98+
return data
99+
100+
101+
# Agent with custom filtered handoff
102+
filtered_agent = Agent(
103+
name="Filtered Support",
104+
role="Support with Privacy",
105+
goal="Handle support while maintaining privacy",
106+
backstory="I ensure customer privacy by filtering sensitive conversation history.",
107+
handoffs=[
108+
handoff(
109+
faq_agent,
110+
tool_description_override="Transfer to FAQ (filtered history)",
111+
input_filter=custom_filter
112+
)
113+
]
114+
)
115+
116+
# Example usage
117+
if __name__ == "__main__":
118+
print("=== Advanced Handoff Examples ===\n")
119+
120+
# Test escalation with structured data
121+
print("Test 1: Escalation with structured input")
122+
response = support_agent.chat(
123+
"I've been waiting for my refund for 3 weeks and I'm very frustrated! "
124+
"I need this resolved immediately or I'll take legal action!"
125+
)
126+
print(f"Response: {response}\n")
127+
128+
# Test FAQ handoff
129+
print("\nTest 2: FAQ handoff with filtering")
130+
response = support_agent.chat(
131+
"How do I reset my password? I can't find the option in settings."
132+
)
133+
print(f"Response: {response}\n")
134+
135+
# Test filtered handoff
136+
print("\nTest 3: Filtered handoff")
137+
# Add some conversation history
138+
filtered_agent.chat("My account number is 12345")
139+
filtered_agent.chat("I have a sensitive issue")
140+
response = filtered_agent.chat("I need help with FAQ about privacy policy")
141+
print(f"Response: {response}\n")
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
Basic handoff example demonstrating agent-to-agent delegation.
3+
4+
This example shows how agents can hand off tasks to specialized agents.
5+
"""
6+
7+
from praisonaiagents import Agent
8+
9+
# Create specialized agents
10+
billing_agent = Agent(
11+
name="Billing Agent",
12+
role="Billing Specialist",
13+
goal="Handle all billing-related inquiries and tasks",
14+
backstory="I am an expert in billing systems, payment processing, and invoice management."
15+
)
16+
17+
refund_agent = Agent(
18+
name="Refund Agent",
19+
role="Refund Specialist",
20+
goal="Process refund requests and handle refund-related issues",
21+
backstory="I specialize in processing refunds, evaluating refund eligibility, and ensuring customer satisfaction."
22+
)
23+
24+
technical_support_agent = Agent(
25+
name="Technical Support",
26+
role="Technical Support Specialist",
27+
goal="Resolve technical issues and provide technical assistance",
28+
backstory="I am skilled in troubleshooting technical problems and providing solutions."
29+
)
30+
31+
# Create a triage agent with handoffs to specialized agents
32+
triage_agent = Agent(
33+
name="Triage Agent",
34+
role="Customer Service Triage",
35+
goal="Understand customer needs and route them to the appropriate specialist",
36+
backstory="I analyze customer requests and direct them to the most suitable specialist for efficient resolution.",
37+
instructions="""Analyze the customer's request and determine which specialist can best help:
38+
- For billing questions, payment issues, or invoices, transfer to the Billing Agent
39+
- For refund requests or refund status inquiries, transfer to the Refund Agent
40+
- For technical problems or product issues, transfer to Technical Support
41+
42+
Always explain why you're transferring the customer before doing so.""",
43+
handoffs=[billing_agent, refund_agent, technical_support_agent]
44+
)
45+
46+
# Example usage
47+
if __name__ == "__main__":
48+
print("=== Customer Service Triage System ===\n")
49+
50+
# Test different types of requests
51+
test_requests = [
52+
"I need a refund for my last purchase",
53+
"Why was I charged twice on my credit card?",
54+
"The app keeps crashing when I try to login"
55+
]
56+
57+
for request in test_requests:
58+
print(f"\nCustomer: {request}")
59+
response = triage_agent.chat(request)
60+
print(f"Response: {response}")
61+
print("-" * 50)
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
"""
2+
Complete customer service workflow example with handoffs.
3+
4+
This example demonstrates a realistic customer service scenario with:
5+
- Order status checking
6+
- Refund processing
7+
- Technical support
8+
- FAQ handling
9+
- Escalation management
10+
"""
11+
12+
from praisonaiagents import Agent, handoff, RECOMMENDED_PROMPT_PREFIX
13+
import random
14+
15+
16+
# Mock functions for demonstration
17+
def check_order_status(order_id: str) -> str:
18+
"""Check the status of an order"""
19+
statuses = ["shipped", "processing", "delivered", "pending"]
20+
return f"Order {order_id} is {random.choice(statuses)}"
21+
22+
23+
def process_refund(order_id: str, reason: str) -> str:
24+
"""Process a refund request"""
25+
return f"Refund initiated for order {order_id}. Reason: {reason}. Expected in 3-5 business days."
26+
27+
28+
def get_faq_answer(question: str) -> str:
29+
"""Get answer from FAQ database"""
30+
faqs = {
31+
"shipping": "Standard shipping takes 5-7 business days. Express shipping takes 2-3 business days.",
32+
"returns": "You can return items within 30 days of purchase in original condition.",
33+
"warranty": "All products come with a 1-year manufacturer warranty.",
34+
"payment": "We accept credit cards, debit cards, PayPal, and Apple Pay."
35+
}
36+
for key, answer in faqs.items():
37+
if key in question.lower():
38+
return answer
39+
return "I'll need to check our documentation for that specific question."
40+
41+
42+
# Create specialized agents with tools
43+
order_agent = Agent(
44+
name="Order Specialist",
45+
role="Order Management Specialist",
46+
goal="Handle all order-related inquiries including tracking, modifications, and status updates",
47+
backstory="I specialize in order management and have access to the order tracking system.",
48+
tools=[check_order_status],
49+
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
50+
51+
I can help with:
52+
- Checking order status
53+
- Tracking shipments
54+
- Order modifications
55+
- Delivery issues
56+
57+
For refunds, I'll transfer you to our Refund Specialist.
58+
For technical issues, I'll connect you with Technical Support."""
59+
)
60+
61+
refund_agent = Agent(
62+
name="Refund Specialist",
63+
role="Refund and Returns Specialist",
64+
goal="Process refunds and handle return requests efficiently",
65+
backstory="I'm authorized to process refunds and handle all return-related matters.",
66+
tools=[process_refund],
67+
instructions="""I process refunds and returns. I need the order ID and reason for the refund.
68+
I ensure all refunds are processed according to our policy."""
69+
)
70+
71+
faq_agent = Agent(
72+
name="FAQ Assistant",
73+
role="Knowledge Base Specialist",
74+
goal="Provide quick answers to frequently asked questions",
75+
backstory="I have access to our comprehensive FAQ database.",
76+
tools=[get_faq_answer],
77+
instructions="I provide answers to common questions about shipping, returns, warranty, and payments."
78+
)
79+
80+
technical_agent = Agent(
81+
name="Technical Support",
82+
role="Technical Support Engineer",
83+
goal="Resolve technical issues with products and services",
84+
backstory="I'm trained in troubleshooting all our products and technical services.",
85+
instructions="""I help with:
86+
- Product setup and configuration
87+
- Troubleshooting technical issues
88+
- Software problems
89+
- Hardware diagnostics"""
90+
)
91+
92+
escalation_agent = Agent(
93+
name="Senior Manager",
94+
role="Customer Experience Manager",
95+
goal="Handle escalated issues and ensure customer satisfaction",
96+
backstory="I'm a senior manager with authority to make exceptions and handle complex cases.",
97+
instructions="""I handle:
98+
- Escalated complaints
99+
- Special requests requiring manager approval
100+
- Complex issues that need executive decisions
101+
- Customer retention situations"""
102+
)
103+
104+
# Create main customer service agent with handoffs
105+
customer_service_agent = Agent(
106+
name="Customer Service",
107+
role="Customer Service Representative",
108+
goal="Provide excellent customer service by understanding needs and routing to the right specialist",
109+
backstory="I'm your first point of contact and I'll make sure you get the help you need.",
110+
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
111+
112+
Welcome! I'm here to help you today. I can assist with various requests or connect you with the right specialist:
113+
114+
- For order tracking and status → Order Specialist
115+
- For refunds and returns → Refund Specialist
116+
- For common questions → FAQ Assistant
117+
- For technical problems → Technical Support
118+
- For complaints or special requests → Senior Manager
119+
120+
How can I help you today?""",
121+
handoffs=[
122+
order_agent,
123+
refund_agent,
124+
faq_agent,
125+
technical_agent,
126+
handoff(
127+
escalation_agent,
128+
tool_description_override="Escalate to senior management for complex issues or complaints"
129+
)
130+
]
131+
)
132+
133+
# Example interaction
134+
if __name__ == "__main__":
135+
print("=== Customer Service System ===")
136+
print("Welcome to our customer service! Type 'quit' to exit.\n")
137+
138+
# Simulated customer interactions
139+
test_scenarios = [
140+
"I need to check the status of my order #12345",
141+
"I want a refund for order #67890, the product was damaged",
142+
"What's your return policy?",
143+
"My device won't turn on after the update",
144+
"I'm very unhappy with the service and want to speak to a manager!",
145+
"How long does shipping usually take?"
146+
]
147+
148+
print("Running automated test scenarios:\n")
149+
for scenario in test_scenarios:
150+
print(f"Customer: {scenario}")
151+
response = customer_service_agent.chat(scenario)
152+
print(f"Agent: {response}")
153+
print("-" * 80)
154+
155+
# Interactive mode
156+
print("\nNow entering interactive mode. You can ask questions directly:")
157+
while True:
158+
user_input = input("\nYou: ")
159+
if user_input.lower() == 'quit':
160+
break
161+
response = customer_service_agent.chat(user_input)
162+
print(f"Agent: {response}")

0 commit comments

Comments
 (0)