Spaces:
Sleeping
Sleeping
| """ | |
| models.py β PhishGuard-Env Pydantic Models | |
| ========================================== | |
| Typed request / response schemas used by env.py (FastAPI). | |
| PhishAction : Body schema for POST /step | |
| StepResponse : Response schema for POST /step (OpenEnv grader compliance) | |
| ResetResponse : Response schema for POST /reset | |
| BUG FIX (v1.0.2 β v1.0.3) | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| StepResponse.task_id was typed as `str` but the episode-already-over guard | |
| branch in env.py returns task_id=None. Pydantic would raise a validation | |
| error on every post-episode /step call. | |
| Fix: task_id is now Optional[str] with a default of None. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any, Dict, List, Optional | |
| from pydantic import BaseModel, Field | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # REQUEST MODELS | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class PhishAction(BaseModel): | |
| """ | |
| Action submitted by the agent to POST /step. | |
| Fields | |
| ------ | |
| action : One of MARK_SAFE | MOVE_TO_SPAM | QUARANTINE | BLOCK_DOMAIN | |
| reasoning : Optional one-sentence technical justification (for logging). | |
| """ | |
| action: str = Field( | |
| max_length=64, | |
| description="Triage decision. Must be exactly one of: " | |
| "MARK_SAFE | MOVE_TO_SPAM | QUARANTINE | BLOCK_DOMAIN" | |
| ) | |
| reasoning: Optional[str] = Field( | |
| default=None, | |
| description="One-sentence technical justification for the triage decision", | |
| ) | |
| class ResetRequest(BaseModel): | |
| """Body schema for POST /reset.""" | |
| difficulty: str = Field( | |
| default="easy", | |
| description="Difficulty level: easy | medium | hard", | |
| ) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # RESPONSE MODELS (OpenEnv spec β all fields required by validator) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class StepResponse(BaseModel): | |
| """ | |
| Full response for POST /step. | |
| The OpenEnv validator inspects `task_id` and `is_correct` on every step | |
| to count how many distinct tasks have been graded. | |
| task_id is Optional[str] (not str) because the episode-already-over guard | |
| branch returns None β a non-optional field would cause a Pydantic | |
| ValidationError on every post-episode call. | |
| """ | |
| observation: Optional[Dict[str, Any]] = Field( | |
| description="Next email dict, or null when the episode is done" | |
| ) | |
| reward: float = Field( | |
| description="Step reward strictly in (0.0, 1.0)" | |
| ) | |
| done: bool = Field( | |
| description="True when all scenarios are complete or health reaches 0" | |
| ) | |
| task_id: Optional[str] = Field( # BUG FIX: was `str`, must be Optional | |
| default=None, | |
| description="Scenario ID e.g. 'lv3' β required by OpenEnv validator" | |
| ) | |
| is_correct: bool = Field( | |
| description="True when reward >= R_PERFECT (0.95)" | |
| ) | |
| info: Dict[str, Any] = Field( | |
| description="Full grader info payload" | |
| ) | |
| class ResetResponse(BaseModel): | |
| """Response for POST /reset.""" | |
| observation: Dict[str, Any] = Field( | |
| description="First email observation for this episode" | |
| ) | |
| task_id: str = Field( | |
| description="ID of the first scenario in this episode" | |
| ) | |
| task_group: str = Field( | |
| description="Difficulty level of the first scenario: easy | medium | hard" | |
| ) | |
| difficulty: str = Field( | |
| description="Active difficulty level for this episode" | |
| ) | |
| total_tasks: int = Field( | |
| description="Total number of scenarios in this level" | |
| ) |