from __future__ import annotations from dataclasses import asdict, dataclass, field from datetime import datetime, timezone from enum import Enum from typing import Any from uuid import uuid4 def utc_now() -> str: return datetime.now(timezone.utc).isoformat() class JobStatus(str, Enum): DRAFT = "Draft" AWAITING_CONFIRMATION = "Awaiting confirmation" QUEUED = "Queued" RUNNING = "Running" PAUSED = "Paused" FINISHED = "Finished" FAILED = "Failed" CANCELLED = "Cancelled" INTERRUPTED = "Interrupted" class StepStatus(str, Enum): PENDING = "Pending" RUNNING = "Running" FINISHED = "Finished" FAILED = "Failed" SKIPPED = "Skipped" @dataclass(slots=True) class PlanStep: tool_id: str title: str description: str arguments: dict[str, Any] = field(default_factory=dict) status: StepStatus = StepStatus.PENDING @classmethod def from_dict(cls, data: dict[str, Any]) -> "PlanStep": payload = dict(data) payload["status"] = StepStatus(payload.get("status", StepStatus.PENDING)) return cls(**payload) @dataclass(slots=True) class ExecutionPlan: request: str summary: str steps: list[PlanStep] requires_confirmation: bool = False confirmation_reason: str = "" project_name: str = "Untitled project" id: str = field(default_factory=lambda: uuid4().hex[:10]) created_at: str = field(default_factory=utc_now) orion_review: dict[str, Any] = field(default_factory=dict) @classmethod def from_dict(cls, data: dict[str, Any]) -> "ExecutionPlan": payload = dict(data) payload["steps"] = [PlanStep.from_dict(item) for item in payload["steps"]] return cls(**payload) @dataclass(slots=True) class Job: plan: ExecutionPlan id: str = field(default_factory=lambda: uuid4().hex[:8].upper()) status: JobStatus = JobStatus.DRAFT progress: int = 0 current_step: int = -1 created_at: str = field(default_factory=utc_now) started_at: str | None = None ended_at: str | None = None output_folder: str | None = None logs: list[str] = field(default_factory=list) error: str | None = None preview_path: str | None = None preview_epoch: int = 0 preview_next_epoch: int = 0 preview_prompt: str = "" preview_seed: int | None = None preview_steps: int = 0 preview_kind: str = "training" preview_current: int = 0 preview_total: int = 0 preview_image_index: int = 0 preview_image_count: int = 0 atlas_report: dict[str, Any] = field(default_factory=dict) nova_report: dict[str, Any] = field(default_factory=dict) def to_dict(self) -> dict[str, Any]: payload = asdict(self) payload["status"] = self.status.value for step in payload["plan"]["steps"]: step["status"] = step["status"].value return payload @classmethod def from_dict(cls, data: dict[str, Any]) -> "Job": payload = dict(data) payload["status"] = JobStatus(payload["status"]) payload["plan"] = ExecutionPlan.from_dict(payload["plan"]) return cls(**payload) @dataclass(slots=True) class SystemSnapshot: cpu_percent: float = 0.0 memory_percent: float = 0.0 memory_used_gb: float = 0.0 memory_total_gb: float = 0.0 disk_percent: float = 0.0 disk_used_gb: float = 0.0 disk_total_gb: float = 0.0 gpu_name: str = "No NVIDIA GPU detected" gpu_percent: float = 0.0 vram_percent: float = 0.0 vram_used_gb: float = 0.0 vram_total_gb: float = 0.0 gpu_temperature: float | None = None