""" app/models.py Pydantic request/response models used by the HTTP API. """ from __future__ import annotations from datetime import datetime from enum import Enum from typing import Optional from pydantic import BaseModel, field_validator # --------------------------------------------------------------------------- # Enumerations # --------------------------------------------------------------------------- class InstructionStatus(str, Enum): pending = "pending" consumed = "consumed" class ResultType(str, Enum): instruction = "instruction" empty = "empty" default_response = "default_response" # --------------------------------------------------------------------------- # Instruction models # --------------------------------------------------------------------------- class InstructionItem(BaseModel): id: str content: str status: InstructionStatus created_at: datetime updated_at: datetime consumed_at: Optional[datetime] = None consumed_by_agent_id: Optional[str] = None position: int class InstructionListResponse(BaseModel): items: list[InstructionItem] class InstructionCreateResponse(BaseModel): item: InstructionItem class CreateInstructionRequest(BaseModel): content: str @field_validator("content") @classmethod def content_not_empty(cls, v: str) -> str: if not v.strip(): raise ValueError("content must not be blank") return v.strip() class UpdateInstructionRequest(BaseModel): content: str @field_validator("content") @classmethod def content_not_empty(cls, v: str) -> str: if not v.strip(): raise ValueError("content must not be blank") return v.strip() # --------------------------------------------------------------------------- # Status models # --------------------------------------------------------------------------- class ServerInfo(BaseModel): status: str started_at: datetime class AgentInfo(BaseModel): connected: bool last_seen_at: Optional[datetime] = None last_fetch_at: Optional[datetime] = None agent_id: Optional[str] = None class QueueCounts(BaseModel): pending_count: int consumed_count: int class StatusResponse(BaseModel): server: ServerInfo agent: AgentInfo queue: QueueCounts settings: "ConfigResponse" # --------------------------------------------------------------------------- # Config models # --------------------------------------------------------------------------- class ConfigResponse(BaseModel): default_wait_seconds: int default_empty_response: str agent_stale_after_seconds: int class UpdateConfigRequest(BaseModel): default_wait_seconds: Optional[int] = None default_empty_response: Optional[str] = None agent_stale_after_seconds: Optional[int] = None # --------------------------------------------------------------------------- # Health model # --------------------------------------------------------------------------- class HealthResponse(BaseModel): status: str server_time: datetime # --------------------------------------------------------------------------- # MCP tool response models # --------------------------------------------------------------------------- class InstructionPayload(BaseModel): id: str content: str consumed_at: datetime class GetUserRequestResponse(BaseModel): status: str result_type: ResultType instruction: Optional[InstructionPayload] = None response: Optional[str] = None remaining_pending: int waited_seconds: int