Spaces:
Sleeping
Sleeping
File size: 15,310 Bytes
81aa69d 6c741e5 81aa69d 6c741e5 81aa69d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | """
Task definitions for the Customer Support Environment.
Contains 3 tasks with increasing difficulty:
1. EASY β Simple FAQ resolution
2. MEDIUM β Conditional refund processing
3. HARD β Complex complaint escalation with angry customer
"""
from typing import Any, Dict, List, Optional
from models import (
CustomerMessage,
CustomerSentiment,
Difficulty,
TicketCategory,
TicketInfo,
TicketPriority,
TicketStatus,
)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Company Policies (shared context)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
COMPANY_POLICIES = {
"refund_policy": (
"Refund Policy: Full refunds are available within 30 days of purchase for "
"unopened items. Opened items can receive a 50% refund within 15 days. "
"Digital products are non-refundable after download. Defective items receive "
"a full refund or replacement at any time with proof of defect. "
"Shipping costs are non-refundable unless the return is due to our error."
),
"shipping_policy": (
"Shipping Policy: Standard shipping takes 5β7 business days. Express shipping "
"takes 2β3 business days. Free shipping on orders over $50. Tracking numbers "
"are sent via email within 24 hours of shipment. International orders may "
"take 10β15 business days."
),
"return_policy": (
"Return Policy: Items must be in original packaging. Return shipping labels "
"are provided for defective items. Customer pays return shipping for change-of-mind "
"returns. Refunds are processed within 5β7 business days after receiving the return."
),
"escalation_policy": (
"Escalation Policy: If a customer expresses extreme dissatisfaction or the "
"issue cannot be resolved in standard steps, offer to escalate to a senior "
"support specialist. Always acknowledge the customer's frustration and offer "
"a concrete next step. Compensation (store credit or discount) may be offered "
"for significant inconvenience, up to 15% of order value."
),
}
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Helper: build a task definition dict
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _task(
task_id: str,
difficulty: Difficulty,
ticket: Dict[str, Any],
initial_message: str,
policy_keys: List[str],
max_steps: int,
expected_keywords: List[str],
grading_rubric: Dict[str, Any],
follow_up_messages: Optional[List[str]] = None,
) -> Dict[str, Any]:
return {
"task_id": task_id,
"difficulty": difficulty,
"ticket": ticket,
"initial_message": initial_message,
"follow_up_messages": follow_up_messages or [],
"policy_context": "\n\n".join(COMPANY_POLICIES[k] for k in policy_keys),
"max_steps": max_steps,
"expected_keywords": expected_keywords,
"grading_rubric": grading_rubric,
}
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# TASK 1 β EASY: Simple FAQ
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TASK_EASY_FAQ = _task(
task_id="easy_faq",
difficulty=Difficulty.EASY,
ticket={
"ticket_id": "TKT-1001",
"category": TicketCategory.FAQ,
"priority": TicketPriority.LOW,
"status": TicketStatus.OPEN,
"customer_name": "Sarah Johnson",
"customer_sentiment": CustomerSentiment.NEUTRAL,
"subject": "Where is my order?",
"order_id": "ORD-55821",
"product_name": "Wireless Bluetooth Headphones",
"purchase_date": "2026-03-28",
"purchase_amount": 79.99,
},
initial_message=(
"Hi, I placed an order about a week ago for Wireless Bluetooth Headphones "
"(order #ORD-55821) and I haven't received any shipping update yet. "
"Can you tell me where my order is?"
),
policy_keys=["shipping_policy"],
max_steps=3,
expected_keywords=[
"tracking", "shipping", "5-7 business days", "5β7 business days",
"email", "order", "ORD-55821",
],
grading_rubric={
"correctness": {
"weight": 0.3,
"criteria": [
{"keyword_group": ["tracking", "track"], "points": 0.4, "desc": "Mentions tracking info"},
{"keyword_group": ["5-7", "5β7", "business days", "5 to 7"], "points": 0.3, "desc": "Mentions shipping timeframe"},
{"keyword_group": ["email", "notification", "update"], "points": 0.3, "desc": "Mentions how they'll receive updates"},
],
},
"tone": {
"weight": 0.3,
"criteria": {
"positive_signals": ["thank", "appreciate", "glad to help", "happy to", "pleased", "welcome"],
"negative_signals": ["not my problem", "deal with it", "figure it out", "whatever", "stupid"],
},
},
"completeness": {
"weight": 0.4,
"criteria": [
{"check": "addresses_question", "points": 0.4, "desc": "Directly answers the question"},
{"check": "provides_next_steps", "points": 0.3, "desc": "Offers next steps or actions"},
{"check": "references_order", "points": 0.3, "desc": "References the specific order"},
],
},
},
)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# TASK 2 β MEDIUM: Refund Request with Conditions
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TASK_MEDIUM_REFUND = _task(
task_id="medium_refund",
difficulty=Difficulty.MEDIUM,
ticket={
"ticket_id": "TKT-2047",
"category": TicketCategory.REFUND,
"priority": TicketPriority.MEDIUM,
"status": TicketStatus.OPEN,
"customer_name": "Michael Chen",
"customer_sentiment": CustomerSentiment.FRUSTRATED,
"subject": "Refund for opened laptop bag",
"order_id": "ORD-43192",
"product_name": "Premium Leather Laptop Bag",
"purchase_date": "2026-03-20",
"purchase_amount": 149.99,
},
initial_message=(
"I bought a Premium Leather Laptop Bag two weeks ago and I've been using it, "
"but the stitching on the handle started coming apart after just 3 days! "
"I want a full refund. This is unacceptable quality for a $150 bag."
),
follow_up_messages=[
"I have photos of the stitching issue. The thread is completely loose on one side. "
"I just want my money back, this is clearly a manufacturing defect.",
"Okay, I can send the bag back. How long will the refund take?",
],
policy_keys=["refund_policy", "return_policy"],
max_steps=5,
expected_keywords=[
"defect", "defective", "full refund", "replacement", "return",
"proof", "photo", "5-7 business days", "5β7 business days",
"shipping label", "return label",
],
grading_rubric={
"correctness": {
"weight": 0.35,
"criteria": [
{"keyword_group": ["defect", "defective", "manufacturing"], "points": 0.3, "desc": "Identifies as defect"},
{"keyword_group": ["full refund", "100%", "complete refund", "full amount"], "points": 0.3, "desc": "Offers full refund for defect"},
{"keyword_group": ["replacement", "replace", "exchange"], "points": 0.2, "desc": "Offers replacement option"},
{"keyword_group": ["return", "send back", "ship back"], "points": 0.2, "desc": "Explains return process"},
],
},
"tone": {
"weight": 0.3,
"criteria": {
"positive_signals": [
"sorry", "apologize", "understand", "frustrat",
"inconvenience", "appreciate", "thank",
],
"negative_signals": [
"your fault", "should have", "too bad",
"nothing we can do", "not our problem",
],
},
},
"completeness": {
"weight": 0.35,
"criteria": [
{"check": "addresses_defect", "points": 0.3, "desc": "Acknowledges the defect issue"},
{"check": "explains_policy", "points": 0.25, "desc": "Explains relevant refund policy"},
{"check": "provides_process", "points": 0.25, "desc": "Outlines the return/refund process"},
{"check": "offers_options", "points": 0.2, "desc": "Gives customer options (refund vs replacement)"},
],
},
},
)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# TASK 3 β HARD: Angry Customer Complaint + Escalation
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TASK_HARD_ESCALATION = _task(
task_id="hard_escalation",
difficulty=Difficulty.HARD,
ticket={
"ticket_id": "TKT-3099",
"category": TicketCategory.COMPLAINT,
"priority": TicketPriority.CRITICAL,
"status": TicketStatus.OPEN,
"customer_name": "David Martinez",
"customer_sentiment": CustomerSentiment.ANGRY,
"subject": "TERRIBLE experience β wrong item, late delivery, rude staff",
"order_id": "ORD-67234",
"product_name": "Smart Home Security Camera System",
"purchase_date": "2026-03-10",
"purchase_amount": 349.99,
},
initial_message=(
"I am FURIOUS. I ordered a Smart Home Security Camera System THREE WEEKS AGO. "
"Not only did it arrive 2 weeks late, but you sent me the WRONG ITEM β I got "
"some cheap webcam instead! And when I called your support line, the agent was "
"incredibly rude and told me to 'just return it and reorder.' This is the worst "
"customer experience I've ever had. I want a full refund, compensation for my "
"wasted time, AND I want to speak with a manager!"
),
follow_up_messages=[
"Don't give me the runaround. I've already wasted 2 hours on the phone with "
"your terrible support team. I want this fixed NOW or I'm filing a complaint "
"with consumer protection and posting this everywhere online.",
"Fine. What exactly are you going to do to make this right? I need specifics, "
"not more empty apologies.",
"Okay, if you can actually guarantee that, then fine. But I want confirmation "
"in writing via email within the hour.",
],
policy_keys=["refund_policy", "return_policy", "shipping_policy", "escalation_policy"],
max_steps=7,
expected_keywords=[
"sincerely apologize", "apologize", "sorry", "understand", "frustration",
"wrong item", "full refund", "compensation", "store credit", "discount",
"escalate", "senior", "manager", "specialist",
"email", "confirmation", "priority", "expedited",
],
grading_rubric={
"correctness": {
"weight": 0.3,
"criteria": [
{"keyword_group": ["wrong item", "incorrect", "wrong product", "mix-up"], "points": 0.2, "desc": "Acknowledges wrong item"},
{"keyword_group": ["full refund", "refund", "money back"], "points": 0.2, "desc": "Offers refund"},
{"keyword_group": ["compensation", "credit", "discount", "coupon"], "points": 0.2, "desc": "Offers compensation"},
{"keyword_group": ["escalat", "senior", "manager", "specialist", "supervisor"], "points": 0.2, "desc": "Offers/performs escalation"},
{"keyword_group": ["email", "confirmation", "writing", "written"], "points": 0.2, "desc": "Offers written confirmation"},
],
},
"tone": {
"weight": 0.4,
"criteria": {
"positive_signals": [
"sincerely", "deeply sorry", "apologize", "understand your frustration",
"completely unacceptable", "you deserve better", "top priority",
"personally ensure", "I understand", "valid concern",
],
"negative_signals": [
"calm down", "relax", "overreacting", "not a big deal",
"your fault", "policy is policy", "nothing I can do",
"take it or leave", "that's not true",
],
},
},
"completeness": {
"weight": 0.3,
"criteria": [
{"check": "acknowledges_all_issues", "points": 0.2, "desc": "Addresses all issues (wrong item, delay, rude staff)"},
{"check": "concrete_resolution", "points": 0.25, "desc": "Provides concrete resolution steps"},
{"check": "timeline", "points": 0.2, "desc": "Gives timelines for resolution"},
{"check": "empathy", "points": 0.2, "desc": "Shows genuine empathy throughout"},
{"check": "follow_up_plan", "points": 0.15, "desc": "Outlines follow-up plan"},
],
},
},
)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Task registry
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TASKS = {
"easy_faq": TASK_EASY_FAQ,
"medium_refund": TASK_MEDIUM_REFUND,
"hard_escalation": TASK_HARD_ESCALATION,
}
TASK_IDS = list(TASKS.keys())
def get_task(task_id: str) -> Dict[str, Any]:
"""Retrieve a task definition by ID."""
if task_id not in TASKS:
raise ValueError(f"Unknown task_id: {task_id!r}. Available: {TASK_IDS}")
return TASKS[task_id]
|