villsim/backend/api/schemas.py

186 lines
4.1 KiB
Python

"""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
can_act: bool
current_action: AgentActionSchema
last_action_result: str
# ============== 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_money_in_circulation: int
professions: 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]
trades: list[dict]
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]
# ============== 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