173 lines
4.9 KiB
Python

"""
Pydantic schemas for API request/response serialization.
"""
from datetime import datetime
from typing import Optional, List, Any
from pydantic import BaseModel, Field
from app.models import (
ProjectStatus, WorkflowType, TaskStatus, TaskType,
TaskPriority, AgentExecutionStatus,
)
# ─── Task Schemas ──────────────────────────────────────────────────────────────
class TaskCreate(BaseModel):
task_id: str = Field(..., examples=["TASK-001"])
type: TaskType = TaskType.BACKEND
title: str
priority: TaskPriority = TaskPriority.P3
assigned_to: Optional[str] = None
dependencies: List[str] = []
acceptance_criteria: Optional[str] = None
class TaskResponse(BaseModel):
id: int
project_id: int
task_id: str
type: TaskType
title: str
priority: TaskPriority
assigned_to: Optional[str]
status: TaskStatus
dependencies: Any
acceptance_criteria: Optional[str]
agent_payloads: Any
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
# ─── AuditLog Schemas ─────────────────────────────────────────────────────────
class AuditLogResponse(BaseModel):
id: int
project_id: int
timestamp: datetime
agent: str
action: str
target: Optional[str]
message: Optional[str]
source: str
model_config = {"from_attributes": True}
# ─── AgentExecution Schemas ────────────────────────────────────────────────────
class AgentExecutionResponse(BaseModel):
id: int
project_id: int
agent_name: str
status: AgentExecutionStatus
pid: Optional[int]
started_at: datetime
finished_at: Optional[datetime]
exit_code: Optional[int]
error_output: Optional[str]
model_config = {"from_attributes": True}
# ─── Project Schemas ───────────────────────────────────────────────────────────
class ProjectCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=200)
description: str = ""
workflow_type: WorkflowType = WorkflowType.SOFTWARE_DESIGN
test_mode: bool = False
class ProjectUpdate(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
workflow_type: Optional[WorkflowType] = None
class ProjectSummary(BaseModel):
id: int
name: str
slug: str
status: ProjectStatus
workflow_type: WorkflowType
test_mode: bool
task_count: int = 0
tasks_done: int = 0
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
class ProjectDetail(BaseModel):
id: int
name: str
slug: str
description: str
status: ProjectStatus
workflow_type: WorkflowType
test_mode: bool
gitea_repo: Optional[str]
deployment_target: Optional[str]
created_at: datetime
updated_at: datetime
tasks: List[TaskResponse] = []
audit_logs: List[AuditLogResponse] = []
agent_executions: List[AgentExecutionResponse] = []
model_config = {"from_attributes": True}
# ─── Agent Schemas ─────────────────────────────────────────────────────────────
class AgentStatus(BaseModel):
name: str
display_name: str
model: str
current_status: str = "idle" # idle | running | failed
current_project: Optional[str] = None
total_executions: int = 0
success_count: int = 0
failure_count: int = 0
# ─── Config Schemas ────────────────────────────────────────────────────────────
class ConfigResponse(BaseModel):
OPENCLAW_WORKSPACE: str
GITEA_SERVER: str
DEPLOYMENT_SERVER: str
DEPLOYMENT_USER: str
TELEGRAM_CHAT_ID: str
LOG_LEVEL: str
# Secrets are masked
GITEA_OPENCLAW_TOKEN: str = "***"
DEPLOYMENT_PWD: str = "***"
TELEGRAM_BOT_TOKEN: str = "***"
class ConfigUpdate(BaseModel):
OPENCLAW_WORKSPACE: Optional[str] = None
GITEA_SERVER: Optional[str] = None
DEPLOYMENT_SERVER: Optional[str] = None
DEPLOYMENT_USER: Optional[str] = None
LOG_LEVEL: Optional[str] = None
# ─── WebSocket Messages ───────────────────────────────────────────────────────
class WSMessage(BaseModel):
type: str # "agent_status" | "log" | "project_update"
data: Any