File size: 7,301 Bytes
f5d79b8
2ac8bdd
f5d79b8
 
 
 
 
 
 
 
 
 
 
2ac8bdd
f5d79b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ac8bdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5d79b8
 
2ac8bdd
f5d79b8
 
 
 
 
 
2ac8bdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5d79b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ac8bdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5d79b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ac8bdd
 
f5d79b8
 
 
2ac8bdd
 
 
 
 
 
 
 
 
 
 
f5d79b8
 
 
 
 
 
2ac8bdd
f5d79b8
2ac8bdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5d79b8
 
 
 
 
 
 
 
 
 
 
 
2ac8bdd
f5d79b8
 
 
 
 
 
 
 
2d5b292
f5d79b8
 
 
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
"""
Typed Pydantic models for the Customer Support Triage, Legal, Clinical, and Engineering OpenEnv environments.
All models follow the OpenEnv specification for Observation, Action, and Reward.
"""

from __future__ import annotations
from typing import Any, Dict, List, Literal, Optional
from pydantic import BaseModel, Field
import enum


# ─────────────────────────── Enumerations ────────────────────────────

# Support Enums
class TicketCategory(str, enum.Enum):
    BILLING = "billing"
    TECHNICAL = "technical"
    ACCOUNT = "account"
    FEATURE_REQUEST = "feature_request"
    ABUSE = "abuse"
    UNKNOWN = "unknown"

class TicketPriority(str, enum.Enum):
    P1_CRITICAL = "P1"
    P2_HIGH = "P2"
    P3_MEDIUM = "P3"
    P4_LOW = "P4"

class TicketStatus(str, enum.Enum):
    OPEN = "open"
    IN_PROGRESS = "in_progress"
    PENDING_CUSTOMER = "pending_customer"
    ESCALATED = "escalated"
    RESOLVED = "resolved"
    CLOSED = "closed"

# Legal Enums
class ClauseType(str, enum.Enum):
    INDEMNITY = "indemnity"
    LIABILITY = "liability"
    IP = "ip"
    TERMINATION = "termination"
    UNKNOWN = "unknown"

class RiskLevel(str, enum.Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"

# Clinical Enums
class BodySystem(str, enum.Enum):
    CARDIAC = "cardiac"
    RESPIRATORY = "respiratory"
    NEUROLOGIC = "neurologic"
    GI = "gi"
    MUSCULOSKELETAL = "musculoskeletal"
    OTHER = "other"

# PR Enums
class PRType(str, enum.Enum):
    BUG_FIX = "bug_fix"
    FEATURE = "feature"
    REFACTOR = "refactor"
    SECURITY = "security"

class AgentAction(str, enum.Enum):
    # Support
    CLASSIFY = "classify"
    DRAFT_RESPONSE = "draft_response"
    ASSIGN_TICKET = "assign_ticket"
    ESCALATE = "escalate"
    RESOLVE = "resolve"
    CLOSE = "close"
    
    # Legal
    IDENTIFY_CLAUSE = "identify_clause"
    FLAG_RISK = "flag_risk"
    REDLINE = "redline"
    
    # Clinical
    CLASSIFY_TRIAGE = "classify_triage"
    ASSIGN_ESI = "assign_esi"
    WRITE_TRIAGE_NOTE = "write_triage_note"
    
    # Engineering
    CLASSIFY_PR = "classify_pr"
    IDENTIFY_BUG = "identify_bug"
    REVIEW_PR = "review_pr"
    
    NO_OP = "no_op"


# ─────────────────────────── Sub-models ───────────────────────────────

class Ticket(BaseModel):
    ticket_id: str
    subject: str
    body: str
    customer_id: str
    customer_tier: Literal["free", "pro", "enterprise"]
    created_at: str
    sla_deadline: str
    category: Optional[TicketCategory] = None
    priority: Optional[TicketPriority] = None
    status: TicketStatus = TicketStatus.OPEN
    assigned_agent: Optional[str] = None
    previous_interactions: List[Dict[str, str]] = Field(default_factory=list)
    sentiment_score: float = Field(default=0.0, ge=-1.0, le=1.0)
    tags: List[str] = Field(default_factory=list)

class LegalClause(BaseModel):
    clause_id: str
    text: str
    contract_type: str
    counterparty: str
    true_clause_type: Optional[ClauseType] = None
    true_risk_level: Optional[RiskLevel] = None
    true_risk_justification: Optional[str] = None

class ClinicalPatient(BaseModel):
    patient_id: str
    age: int
    gender: str
    chief_complaint: str
    vitals: Dict[str, str]
    history: str
    true_body_system: Optional[BodySystem] = None
    true_esi_level: Optional[int] = None
    true_triage_note: Optional[str] = None

class PullRequest(BaseModel):
    pr_id: str
    title: str
    description: str
    diff: str
    author: str
    true_pr_type: Optional[PRType] = None
    true_bug_description: Optional[str] = None
    true_review_comment: Optional[str] = None

class AgentInfo(BaseModel):
    agent_id: str
    name: str
    specialization: List[TicketCategory]
    current_load: int = 0
    max_load: int = 5
    availability: bool = True

class KnowledgeBaseArticle(BaseModel):
    article_id: str
    title: str
    content: str
    applicable_categories: List[TicketCategory]
    relevance_score: float = Field(default=0.0, ge=0.0, le=1.0)


# ─────────────────────────── Core Models ──────────────────────────────

class Observation(BaseModel):
    """
    What the agent sees at each step. Includes the current domain object
    (ticket, clause, patient, or PR).
    """
    task_id: str = Field(description="Active task identifier")
    step: int = Field(description="Current step number within episode")
    
    current_ticket: Optional[Ticket] = Field(default=None)
    current_clause: Optional[LegalClause] = Field(default=None)
    current_patient: Optional[ClinicalPatient] = Field(default=None)
    current_pr: Optional[PullRequest] = Field(default=None)
    
    ticket_queue: List[Ticket] = Field(default_factory=list)
    agents: List[AgentInfo] = Field(default_factory=list)
    knowledge_base: List[KnowledgeBaseArticle] = Field(default_factory=list)
    sla_status: Dict[str, str] = Field(default_factory=dict)
    valid_actions: List[str] = Field(default_factory=list)
    episode_done: bool = False
    info: Dict[str, Any] = Field(default_factory=dict)


class Action(BaseModel):
    """
    An action the agent takes. Fields requested depend on action_type.
    """
    action_type: AgentAction

    # Support
    ticket_id: Optional[str] = None
    category: Optional[TicketCategory] = None
    priority: Optional[TicketPriority] = None
    response_text: Optional[str] = None
    target_agent_id: Optional[str] = None
    resolution_summary: Optional[str] = None

    # Legal
    clause_id: Optional[str] = None
    clause_type: Optional[ClauseType] = None
    risk_level: Optional[RiskLevel] = None
    redline_text: Optional[str] = None
    
    # Clinical
    patient_id: Optional[str] = None
    body_system: Optional[BodySystem] = None
    esi_level: Optional[int] = Field(None, ge=1, le=5)
    triage_note: Optional[str] = None

    # Engineering
    pr_id: Optional[str] = None
    pr_type: Optional[PRType] = None
    bug_description: Optional[str] = None
    review_comment: Optional[str] = None

    reasoning: Optional[str] = None


class Reward(BaseModel):
    """
    Step-level reward signal with breakdown for interpretability.
    """
    total: float = Field(description="Total reward for this step", ge=-1.0, le=1.0)
    classification_accuracy: float = Field(default=0.0, ge=0.0, le=1.0)
    response_quality: float = Field(default=0.0, ge=0.0, le=1.0)
    sla_compliance: float = Field(default=0.0, ge=-1.0, le=1.0)
    first_contact_resolution: float = Field(default=0.0, ge=0.0, le=1.0)
    customer_satisfaction: float = Field(default=0.0, ge=-1.0, le=1.0)
    penalty: float = Field(default=0.0, le=0.0)
    breakdown: Dict[str, float] = Field(default_factory=dict)


class EpisodeResult(BaseModel):
    """Final episode result returned from /grader."""
    task_id: str
    episode_id: str
    total_steps: int
    final_score: float = Field(gt=0.0, lt=1.0)
    reward_history: List[float]
    metrics: Dict[str, Any]
    passed: bool