"""Pydantic schemas for API request/response models.""" from typing import Optional from pydantic import BaseModel, Field # ============== Resource Schemas ============== class ResourceSchema(BaseModel): """Schema for a resource item.""" type: str quantity: int created_turn: int decay_rate: Optional[int] = None # ============== Agent Schemas ============== class PositionSchema(BaseModel): """Schema for agent position (float for smooth movement).""" x: float y: float class StatsSchema(BaseModel): """Schema for agent vital stats.""" energy: int hunger: int thirst: int heat: int max_energy: int max_hunger: int max_thirst: int max_heat: int class AgentActionSchema(BaseModel): """Schema for current agent action.""" action_type: str target_position: Optional[PositionSchema] = None target_resource: Optional[str] = None progress: float is_moving: bool message: str class AgentResponse(BaseModel): """Schema for agent data.""" id: str name: str profession: str position: PositionSchema home_position: PositionSchema stats: StatsSchema inventory: list[ResourceSchema] money: int is_alive: bool is_corpse: bool = False can_act: bool current_action: AgentActionSchema last_action_result: str death_turn: int = -1 death_reason: str = "" # Age system age: int = 25 max_age: int = 70 age_category: str = "prime" birth_day: int = 0 generation: int = 0 parent_ids: list[str] = [] children_count: int = 0 # Age modifiers skill_modifier: float = 1.0 energy_cost_modifier: float = 1.0 learning_modifier: float = 1.0 # Personality and skills personality: dict = {} skills: dict = {} actions_performed: dict = {} total_trades: int = 0 total_money_earned: int = 0 action_history: list = [] # ============== Market Schemas ============== class OrderSchema(BaseModel): """Schema for a market order.""" id: str seller_id: str resource_type: str quantity: int price_per_unit: int total_price: int created_turn: int status: str turns_without_sale: int class MarketPriceSchema(BaseModel): """Schema for market price summary.""" lowest_price: Optional[int] highest_price: Optional[int] total_available: int num_orders: int class TradeResultSchema(BaseModel): """Schema for a trade result.""" success: bool order_id: str = "" buyer_id: str = "" seller_id: str = "" resource_type: Optional[str] = None quantity: int = 0 total_paid: int = 0 message: str = "" class MarketStateResponse(BaseModel): """Schema for market state.""" orders: list[OrderSchema] prices: dict[str, MarketPriceSchema] recent_trades: list[TradeResultSchema] # ============== World Schemas ============== class WorldSizeSchema(BaseModel): """Schema for world dimensions.""" width: int height: int class StatisticsSchema(BaseModel): """Schema for world statistics.""" current_turn: int current_day: int step_in_day: int time_of_day: str living_agents: int total_agents_spawned: int total_agents_died: int total_births: int = 0 total_money_in_circulation: int professions: dict[str, int] # Wealth inequality metrics avg_money: float = 0.0 median_money: int = 0 richest_agent: int = 0 poorest_agent: int = 0 gini_coefficient: float = 0.0 # Age demographics age_distribution: dict[str, int] = {} avg_age: float = 0.0 oldest_agent: int = 0 youngest_agent: int = 0 generations: dict[int, int] = {} # Death statistics deaths_by_cause: dict[str, int] = {} # Village storage village_storage: dict[str, int] = {} class ActionLogSchema(BaseModel): """Schema for an action in the turn log.""" agent_id: str agent_name: str decision: dict result: Optional[dict] = None class TurnLogSchema(BaseModel): """Schema for a turn log entry.""" turn: int agent_actions: list[ActionLogSchema] deaths: list[str] births: list[str] = [] trades: list[dict] resources_produced: dict[str, int] = {} resources_consumed: dict[str, int] = {} resources_spoiled: dict[str, int] = {} day_events: dict = {} class ResourceStatsSchema(BaseModel): """Schema for resource statistics.""" produced: dict[str, int] = {} consumed: dict[str, int] = {} spoiled: dict[str, int] = {} in_inventory: dict[str, int] = {} in_market: dict[str, int] = {} class WorldStateResponse(BaseModel): """Full world state response.""" turn: int day: int step_in_day: int time_of_day: str world_size: WorldSizeSchema agents: list[AgentResponse] statistics: StatisticsSchema market: MarketStateResponse mode: str is_running: bool recent_logs: list[TurnLogSchema] resource_stats: ResourceStatsSchema = ResourceStatsSchema() # ============== Control Schemas ============== class ControlResponse(BaseModel): """Response for control operations.""" success: bool message: str turn: Optional[int] = None mode: Optional[str] = None class SetModeRequest(BaseModel): """Request to set simulation mode.""" mode: str = Field(..., pattern="^(manual|auto)$") class InitializeRequest(BaseModel): """Request to initialize simulation.""" num_agents: int = Field(default=8, ge=1, le=50) world_width: int = Field(default=20, ge=5, le=100) world_height: int = Field(default=20, ge=5, le=100) # ============== Error Schemas ============== class ErrorResponse(BaseModel): """Error response.""" error: str detail: Optional[str] = None