| """ |
| Pydantic schemas for Explainability Agent v2 (Phase 4.3). |
| Defines input/output types for generating driver and admin explanations. |
| |
| Phase 8: Added personalized model version for learning-based explanations. |
| """ |
|
|
| from typing import Dict, List, Optional |
| from pydantic import BaseModel, Field |
|
|
|
|
| class DriverExplanationInput(BaseModel): |
| """Input data for generating explanations for a single driver.""" |
| |
| |
| driver_id: str |
| driver_name: str |
| num_drivers: int = Field(..., description="Total number of drivers in this allocation") |
| |
| |
| today_effort: float = Field(..., description="Effort score for today's route") |
| today_rank: int = Field(..., description="Rank among drivers (1=hardest, N=easiest)") |
| route_id: str = Field(..., description="ID of assigned route") |
| route_summary: Dict = Field( |
| ..., |
| description="Route details: num_packages, total_weight_kg, num_stops, difficulty_score, estimated_time_minutes" |
| ) |
| |
| |
| effort_breakdown: Dict[str, float] = Field( |
| default_factory=dict, |
| description="Breakdown: physical_effort, route_complexity, time_pressure" |
| ) |
| |
| |
| global_avg_effort: float |
| global_std_effort: float |
| global_gini_index: float |
| global_max_gap: float |
| |
| |
| history_efforts_last_7_days: List[float] = Field( |
| default_factory=list, |
| description="Effort scores for the last 7 days" |
| ) |
| history_hard_days_last_7: int = Field( |
| default=0, |
| description="Count of days with above-threshold effort in last 7 days" |
| ) |
| |
| |
| is_recovery_day: bool = Field( |
| default=False, |
| description="True if driver is on scheduled recovery" |
| ) |
| had_manual_override: bool = Field( |
| default=False, |
| description="True if admin manually overrode this assignment" |
| ) |
| complexity_debt: float = Field( |
| default=0.0, |
| description="Cumulative complexity debt from recent hard days" |
| ) |
| |
| |
| is_ev_driver: bool = Field( |
| default=False, |
| description="True if driver uses an electric vehicle" |
| ) |
| ev_charging_overhead: float = Field( |
| default=0.0, |
| description="Effort overhead from EV charging/range constraints" |
| ) |
| |
| |
| liaison_decision: Optional[str] = Field( |
| default=None, |
| description="ACCEPT, COUNTER, or FORCE_ACCEPT from Driver Liaison" |
| ) |
| swap_applied: bool = Field( |
| default=False, |
| description="True if a swap was applied during Final Resolution" |
| ) |
| |
| |
| personalized_model_version: Optional[int] = Field( |
| default=None, |
| description="Version of personalized XGBoost model used for this driver" |
| ) |
| personalized_model_mse: Optional[float] = Field( |
| default=None, |
| description="Current MSE of the personalized model" |
| ) |
|
|
|
|
| class DriverExplanationOutput(BaseModel): |
| """Output from ExplainabilityAgent for a single driver.""" |
| |
| driver_explanation: str = Field( |
| ..., |
| description="Short explanation for driver-facing views (1-3 sentences)" |
| ) |
| admin_explanation: str = Field( |
| ..., |
| description="Detailed explanation for admin views (multi-sentence with metrics)" |
| ) |
| category: str = Field( |
| ..., |
| description="Classification category: NEAR_AVG, HEAVY_WITH_SWAP, HEAVY_NO_SWAP, RECOVERY, LIGHT_RECOVERY, LIGHT, HEAVY, LEARNING_OPTIMIZED" |
| ) |
|
|
|
|