hyperlinken/ALT_DESIGN
0
1"""2models.py3Pydantic v2 typed models for the IT Helpdesk Triage OpenEnv environment.4Defines the complete Action / Observation / State interface contracts.5"""6 7from __future__ import annotations8 9from enum import Enum10from typing import Any, Dict, List, Optional11 12from pydantic import BaseModel, Field13 14 15# ──────────────────────────────────────────────────────────────────────────────16# Domain Enums17# ──────────────────────────────────────────────────────────────────────────────18 19class TicketCategory(str, Enum):20 """ITIL-aligned classification categories for IT support tickets."""21 HARDWARE = "hardware"22 SOFTWARE = "software"23 NETWORK = "network"24 SECURITY = "security"25 ACCESS = "access"26 DATABASE = "database"27 PERFORMANCE = "performance"28 OTHER = "other"29 30 31class TicketPriority(str, Enum):32 """33 Priority levels following ITIL P1-P4 convention.34 P1 = Critical (complete outage / business-stopping).35 P4 = Low (cosmetic, informational, no business impact).36 """37 P1 = "P1" # Critical – SLA: 1 h38 P2 = "P2" # High – SLA: 4 h39 P3 = "P3" # Medium – SLA: 8 h40 P4 = "P4" # Low – SLA: 48 h41 42 43class AssignedTeam(str, Enum):44 """Available support teams for ticket routing."""45 INFRASTRUCTURE = "infrastructure"46 APPLICATION_SUPPORT = "application_support"47 NETWORK_OPS = "network_ops"48 SECURITY_OPS = "security_ops"49 DATABASE_ADMIN = "database_admin"50 HELPDESK = "helpdesk"51 52 53# ──────────────────────────────────────────────────────────────────────────────54# Action Space55# ──────────────────────────────────────────────────────────────────────────────56 57class TriageAction(BaseModel):58 """59 The complete action an agent submits to triage one ticket.60 Used as the primary Action type across all three tasks.61 """62 ticket_id: str = Field(63 ...,64 description="Exact ID of the ticket being triaged (e.g. 'TKT-E001')."65 )66 category: TicketCategory = Field(67 ...,68 description="Issue classification category."69 )70 priority: TicketPriority = Field(71 ...,72 description="Assigned ITIL priority level (P1-P4)."73 )74 assigned_team: AssignedTeam = Field(75 ...,76 description="Resolver team responsible for this ticket."77 )78 is_part_of_incident: bool = Field(79 default=False,80 description="True when this ticket is a symptom of a declared major incident."81 )82 incident_id: Optional[str] = Field(83 default=None,84 description="Major-incident identifier if applicable (e.g. 'INC-MAJOR-01')."85 )86 resolution_steps: Optional[List[str]] = Field(87 default=None,88 description=(89 "Ordered list of remediation steps. "90 "Required for P1 tickets in the 'incident_escalation' task."91 )92 )93 escalate_to_management: bool = Field(94 default=False,95 description="Whether to page senior management / C-suite for this ticket."96 )97 98 99# ──────────────────────────────────────────────────────────────────────────────100# Observation Space101# ──────────────────────────────────────────────────────────────────────────────102 103class Ticket(BaseModel):104 """A single IT support ticket as seen by the agent."""105 id: str = Field(..., description="Unique ticket identifier.")106 subject: str = Field(..., description="One-line summary of the issue.")107 description: str = Field(..., description="Full free-text description from the reporter.")108 reporter: str = Field(..., description="Full name of the person who raised the ticket.")109 reporter_department: str = Field(..., description="Business department of the reporter.")110 timestamp: str = Field(..., description="ISO-8601 creation timestamp.")111 affected_systems: List[str] = Field(..., description="Hostnames / service identifiers impacted.")112 affected_users_count: int = Field(default=1, description="Number of end-users affected.")113 sla_hours: int = Field(..., description="SLA resolution target in hours.")114 115 116class Observation(BaseModel):117 """118 Returned after every reset() and step() call.119 Contains the next ticket to triage plus episode-level metadata.120 """121 task_id: str = Field(..., description="Active task identifier.")122 current_ticket: Optional[Ticket] = Field(123 default=None,124 description="Ticket awaiting triage. None when the queue is exhausted."125 )126 queue_remaining: int = Field(..., description="Tickets still waiting in the queue.")127 processed_count: int = Field(..., description="Tickets triaged so far this episode.")128 step_number: int = Field(..., description="Current step index (0-based).")129 action_feedback: Optional[str] = Field(130 default=None,131 description="Human-readable correctness feedback on the previous action."132 )133 cumulative_score: float = Field(134 default=0.0, ge=0.0, le=1.0,135 description="Running mean reward across all completed steps."136 )137 episode_done: bool = Field(default=False, description="True when the episode has ended.")138 active_incidents: List[str] = Field(139 default_factory=list,140 description="Incident IDs declared so far in this episode."141 )142 hints: List[str] = Field(143 default_factory=list,144 description="Task-level guidance hints for the agent."145 )146 147 148# ──────────────────────────────────────────────────────────────────────────────149# Step Result150# ──────────────────────────────────────────────────────────────────────────────151 152class StepResult(BaseModel):153 """Full return value of the /step endpoint (OpenEnv convention)."""154 observation: Observation155 reward: float = Field(..., ge=0.0, le=1.0, description="Per-step reward.")156 done: bool157 info: Dict[str, Any] = Field(default_factory=dict)158 159 160# ──────────────────────────────────────────────────────────────────────────────161# Reward Breakdown (internal / surfaced in info)162# ──────────────────────────────────────────────────────────────────────────────163 164class RewardBreakdown(BaseModel):165 """Granular per-dimension reward decomposition returned inside StepResult.info."""166 category_score: float = Field(0.0, ge=0.0, le=1.0)167 priority_score: float = Field(0.0, ge=0.0, le=1.0)168 routing_score: float = Field(0.0, ge=0.0, le=1.0)169 incident_score: float = Field(0.0, ge=0.0, le=1.0)170 escalation_score: float = Field(0.0, ge=0.0, le=1.0)171 resolution_score: float = Field(0.0, ge=0.0, le=1.0)172 penalty: float = Field(0.0, ge=0.0, le=1.0)173 total: float = Field(0.0, ge=0.0, le=1.0)174 175 176# ──────────────────────────────────────────────────────────────────────────────177# Environment State (for /state endpoint)178# ──────────────────────────────────────────────────────────────────────────────179 180class EnvironmentState(BaseModel):181 """Complete serialisable snapshot of the environment (returned by state())."""182 task_id: str183 step_number: int184 episode_complete: bool185 tickets_total: int186 tickets_processed: int187 tickets_remaining: int188 cumulative_score: float189 reward_history: List[float]190 declared_incidents: List[str]191 action_history: List[Dict[str, Any]]192 