"""Pydantic request/response models for the platform SDK REST API.""" from __future__ import annotations from datetime import datetime from typing import Any, Literal from pydantic import BaseModel, Field class TaskConstraintsModel(BaseModel): driver_type: str | None = None capability_tags: list[str] = Field(default_factory=list) class TaskSubmissionRequest(BaseModel): goal: str | None = None workflow_definition_id: str | None = None constraints: TaskConstraintsModel = Field(default_factory=TaskConstraintsModel) class TaskSubmissionResponse(BaseModel): task_id: str class TaskStatusResponse(BaseModel): id: str status: str goal: str | None = None workflow_definition_id: str | None = None assigned_device_id: str | None = None assigned_host_id: str | None = None attempt_count: int = 0 lease_expires_at: datetime | None = None failure_reason: str | None = None class TaskListItem(BaseModel): id: str status: str goal: str | None = None workflow_definition_id: str | None = None assigned_device_id: str | None = None assigned_host_id: str | None = None attempt_count: int = 0 failure_reason: str | None = None created_at: datetime class TaskListResponse(BaseModel): items: list[TaskListItem] total: int limit: int offset: int class TaskAttemptResponse(BaseModel): task_id: str attempt: int lease_id: str host_id: str device_id: str status: str lease_expires_at: datetime created_at: datetime completed_at: datetime | None = None failure_reason: str | None = None terminal_result: dict[str, Any] | None = None class DeviceResponse(BaseModel): device_id: str host_id: str driver_type: str status: str capability_tags: list[str] = Field(default_factory=list) class HostResponse(BaseModel): host_id: str address: str | None = None last_seen_at: str class PluginRegistrationRequest(BaseModel): name: str version: str entry_point_kind: Literal["driver", "tool", "skill"] target: str class PluginResponse(BaseModel): name: str version: str entry_point_kind: str target: str wired: bool class LoginRequest(BaseModel): username: str = Field(min_length=1, max_length=64) password: str = Field(min_length=1, max_length=256) class PasswordChangeRequest(BaseModel): current_password: str = Field(min_length=1, max_length=256) new_password: str = Field(min_length=1, max_length=256) class UserResponse(BaseModel): id: str username: str display_name: str role: Literal["viewer", "operator", "admin"] enabled: bool must_change_password: bool scopes: list[str] created_at: datetime updated_at: datetime last_login_at: datetime | None = None class UserListResponse(BaseModel): items: list[UserResponse] limit: int offset: int class UserCreateRequest(BaseModel): username: str = Field(min_length=1, max_length=64) display_name: str = Field(min_length=1, max_length=120) role: Literal["viewer", "operator", "admin"] password: str = Field(min_length=1, max_length=256) class UserUpdateRequest(BaseModel): display_name: str | None = Field(default=None, min_length=1, max_length=120) role: Literal["viewer", "operator", "admin"] | None = None enabled: bool | None = None class PasswordResetRequest(BaseModel): password: str = Field(min_length=1, max_length=256) class ErrorResponse(BaseModel): detail: str