File size: 4,476 Bytes
9c1645f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Pydantic v2 models for SupportOps Arena environment state.
All models use Pydantic v2 syntax exclusively.
"""

from pydantic import BaseModel, Field, field_validator, model_validator
from enum import Enum
from datetime import datetime
import uuid
from typing import Any


# ─── Enums ───────────────────────────────────────────────────

class NetworkStatus(str, Enum):
    """Network connectivity status."""
    HEALTHY = "HEALTHY"
    DEGRADED = "DEGRADED"
    DOWN = "DOWN"
    UNKNOWN = "UNKNOWN"


class VPNStatus(str, Enum):
    """VPN connection status."""
    CONNECTED = "CONNECTED"
    FAILED = "FAILED"
    TIMEOUT = "TIMEOUT"
    NA = "N/A"


class AuthStatus(str, Enum):
    """Authentication system status."""
    OK = "OK"
    LOCKED = "LOCKED"
    EXPIRED = "EXPIRED"
    MFA_FAIL = "MFA_FAIL"


class ServiceHealth(str, Enum):
    """Service health status."""
    HEALTHY = "HEALTHY"
    DEGRADED = "DEGRADED"
    DOWN = "DOWN"
    UNKNOWN = "UNKNOWN"


class TaskLevel(str, Enum):
    """Task difficulty level."""
    EASY = "easy"
    MEDIUM = "medium"
    HARD = "hard"


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

class UserContext(BaseModel):
    """User context information."""
    department: str
    role: str
    device_type: str
    os_version: str
    location: str  # "onsite" | "remote"

    model_config = {"frozen": False}


class LogEntry(BaseModel):
    """System log entry."""
    timestamp: str
    level: str  # "INFO" | "WARN" | "ERROR" | "DEBUG"
    service: str
    message: str
    is_misleading: bool = False  # Hidden from agent, used by grader

    model_config = {"frozen": False}


class ActionRecord(BaseModel):
    """Record of a past action in action_history."""
    step: int
    action_name: str
    rationale: str | None = None
    reward_received: float
    timestamp: str

    model_config = {"frozen": False}


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

class EnvObservation(BaseModel):
    """
    What the AGENT sees. No hidden info.
    This is the observation returned to the agent at each step.
    """
    ticket_id: str
    ticket_summary: str
    user_context: UserContext
    network_status: NetworkStatus
    vpn_status: VPNStatus
    auth_status: AuthStatus
    service_health: dict[str, ServiceHealth]
    system_logs: list[LogEntry]
    action_history: list[ActionRecord]
    step_count: int
    escalation_allowed: bool
    confidence_score: float | None = None  # Optional agent field
    task_level: TaskLevel
    steps_remaining: int

    model_config = {"frozen": False}


class HiddenState(BaseModel):
    """
    Internal ground truth. NEVER sent to agent.
    Only accessible via state() method for graders.
    """
    root_cause: str
    root_cause_category: str  # "network" | "auth" | "dns" | "vpn" | "sso" | "hardware"
    correct_remediation: str  # Which ActionType resolves this
    correct_remediation_alts: list[str] = Field(default_factory=list)  # Acceptable alternates
    misleading_log_index: int | None = None  # Which log entry is the red herring
    severity: str  # "low" | "medium" | "high" | "critical"
    affected_users_count: int  # Side-effect blast radius
    ticket_variant_id: str  # For adversary tracking

    model_config = {"frozen": False}


class EnvState(BaseModel):
    """
    Full internal state. Graders only.
    Contains both observable and hidden state.
    """
    episode_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    task_level: TaskLevel
    observation: EnvObservation
    hidden: HiddenState
    cumulative_reward: float = 0.0
    done: bool = False
    created_at: str = Field(default_factory=lambda: datetime.utcnow().isoformat())
    action_log: list[ActionRecord] = Field(default_factory=list)
    diagnostic_steps_taken: int = 0  # Tracks unlock threshold

    model_config = {"frozen": False}


class StepResult(BaseModel):
    """
    Result returned from environment step() method.
    Standard RL tuple: (observation, reward, done, info).
    """
    observation: EnvObservation
    reward: float
    done: bool
    info: dict[str, Any]

    model_config = {"frozen": False}