"""Pydantic models for request/response and internal session state.""" from __future__ import annotations from enum import Enum from typing import Optional from pydantic import BaseModel, Field # --------------------------------------------------------------------------- # Consultation phases # --------------------------------------------------------------------------- class Phase(str, Enum): DISCOVERY = "discovery" EXPLORATION = "exploration" CONSTRAINTS = "constraints" SOLUTION = "solution" REFINEMENT = "refinement" PHASE_ORDER: list[Phase] = [ Phase.DISCOVERY, Phase.EXPLORATION, Phase.CONSTRAINTS, Phase.SOLUTION, Phase.REFINEMENT, ] # Confidence thresholds that trigger phase transitions PHASE_THRESHOLDS: dict[Phase, tuple[float, float]] = { Phase.DISCOVERY: (0.0, 0.20), Phase.EXPLORATION: (0.20, 0.40), Phase.CONSTRAINTS: (0.40, 0.60), Phase.SOLUTION: (0.60, 0.80), Phase.REFINEMENT: (0.80, 1.00), } # --------------------------------------------------------------------------- # API models # --------------------------------------------------------------------------- class ChatRequest(BaseModel): session_id: str = Field(..., description="Unique session identifier") message: str = Field(..., min_length=1, description="User message") class ChatResponse(BaseModel): reply: str phase: Phase confidence: float = Field(ge=0.0, le=1.0) understanding: str = Field(default="", description="Extracted understanding so far") class SessionInfo(BaseModel): session_id: str phase: Phase confidence: float message_count: int created_at: str updated_at: str class NewSessionResponse(BaseModel): session_id: str # --------------------------------------------------------------------------- # Internal state (persisted in SQLite as JSON) # --------------------------------------------------------------------------- class Message(BaseModel): role: str # "user" | "assistant" content: str class SessionState(BaseModel): session_id: str = "" messages: list[Message] = Field(default_factory=list) understanding: str = "" confidence: float = 0.0 phase: Phase = Phase.DISCOVERY topic_start_turn: int = 0 # Turn when current topic started (for phase forcing) created_at: str = "" updated_at: str = ""