from __future__ import annotations from datetime import datetime from enum import Enum from typing import Any from uuid import uuid4 from pydantic import BaseModel, Field class SessionMode(str, Enum): teaching = "teaching" testing = "testing" class StandardKind(str, Enum): part = "part" assembly = "assembly" simulation = "simulation" unknown = "unknown" class SkillStep(BaseModel): id: str = "" order: int = 0 skill: str name: str = "" description: str = "" arguments: dict[str, Any] = Field(default_factory=dict) source_feature: str = "" note: str = "" class StandardAnswer(BaseModel): standard_id: str title: str kind: StandardKind = StandardKind.unknown source_path: str = "" source_type: str = "skillflow" tags: list[str] = Field(default_factory=list) summary: str = "" steps: list[SkillStep] = Field(default_factory=list) raw: dict[str, Any] = Field(default_factory=dict) class LessonStep(BaseModel): step_id: str order: int title: str voice_text: str expected_skill: str expected_arguments: dict[str, Any] = Field(default_factory=dict) source_feature: str = "" check_policy: dict[str, Any] = Field(default_factory=dict) class CompareIssue(BaseModel): severity: str = "error" code: str message: str expected: dict[str, Any] = Field(default_factory=dict) actual: dict[str, Any] = Field(default_factory=dict) class StepCompareResult(BaseModel): ok: bool score: float = 0.0 expected_step: LessonStep | None = None observed_step: SkillStep | None = None issues: list[CompareIssue] = Field(default_factory=list) feedback_text: str = "" class GradeReport(BaseModel): ok: bool score: float max_score: float = 100.0 passed_steps: int = 0 total_steps: int = 0 issues: list[CompareIssue] = Field(default_factory=list) summary: str = "" class LearningSession(BaseModel): session_id: str = Field(default_factory=lambda: f"sess-{uuid4().hex[:10]}") mode: SessionMode standard_id: str title: str current_step_index: int = 0 created_at: datetime = Field(default_factory=datetime.now) lesson_steps: list[LessonStep] = Field(default_factory=list) observed_steps: list[SkillStep] = Field(default_factory=list) reports: list[StepCompareResult] = Field(default_factory=list) final_report: GradeReport | None = None status: str = "active" class StartSessionRequest(BaseModel): standard_id: str class ObservationRequest(BaseModel): steps: list[dict[str, Any]] = Field(default_factory=list) class AuditPartRequest(BaseModel): part_path: str class SubmitTestRequest(BaseModel): steps: list[dict[str, Any]] = Field(default_factory=list) part_path: str = ""