215 lines
5.4 KiB
Python
215 lines
5.4 KiB
Python
"""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)
|
|
target_host_id: str | None = Field(default=None, min_length=1)
|
|
target_device_id: str | None = Field(default=None, min_length=1)
|
|
|
|
|
|
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
|
|
target_host_id: str | None = None
|
|
target_device_id: 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
|
|
target_host_id: str | None = None
|
|
target_device_id: 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
|
|
planner_transport: Literal["direct", "cloud"] = "direct"
|
|
|
|
|
|
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
|
|
|
|
|
|
class DeviceTargetModel(BaseModel):
|
|
host_id: str = Field(min_length=1)
|
|
device_id: str = Field(min_length=1)
|
|
|
|
|
|
class UserSubmissionPolicyRequest(BaseModel):
|
|
submission_enabled: bool = True
|
|
allowed_host_ids: list[str] | None = None
|
|
allowed_device_targets: list[DeviceTargetModel] | None = None
|
|
expected_revision: int | None = Field(default=None, ge=0)
|
|
|
|
|
|
class UserSubmissionPolicyResponse(BaseModel):
|
|
user_id: str
|
|
revision: int
|
|
submission_enabled: bool
|
|
allowed_host_ids: list[str] | None = None
|
|
allowed_device_targets: list[DeviceTargetModel] | None = None
|
|
updated_at: datetime
|
|
|
|
|
|
class HostGovernancePolicyRequest(BaseModel):
|
|
self_submission_enabled: bool = True
|
|
max_active_tasks: int | None = Field(default=None, ge=1)
|
|
daily_token_budget: int | None = Field(default=None, ge=1)
|
|
expected_revision: int | None = Field(default=None, ge=0)
|
|
|
|
|
|
class HostGovernancePolicyResponse(BaseModel):
|
|
host_id: str
|
|
revision: int
|
|
self_submission_enabled: bool
|
|
max_active_tasks: int | None = None
|
|
daily_token_budget: int | None = None
|
|
updated_at: datetime
|
|
|
|
|
|
class HostTokenUsageSummaryResponse(BaseModel):
|
|
host_id: str
|
|
usage_day: str
|
|
daily_token_budget: int | None = None
|
|
used_tokens: int
|
|
reserved_tokens: int
|
|
remaining_tokens: int | None = None
|
|
|
|
|
|
class TokenUsageEventResponse(BaseModel):
|
|
id: str
|
|
host_id: str
|
|
usage_day: str
|
|
task_id: str | None = None
|
|
attempt: int | None = None
|
|
provider: str
|
|
model: str
|
|
input_tokens: int | None = None
|
|
output_tokens: int | None = None
|
|
total_tokens: int
|
|
occurred_at: datetime
|