"""AI Chat Builder session tracking. Stores conversational flow builder state across the multi-phase interview. Sessions expire after 24 hours. """ import uuid from datetime import datetime, timezone from typing import Optional, Any from sqlalchemy import String, DateTime, ForeignKey, Integer from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.dialects.postgresql import UUID, JSONB from app.core.database import Base class AIChatSession(Base): __tablename__ = "ai_chat_sessions" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) user_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) account_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("accounts.id", ondelete="CASCADE"), nullable=False, index=True, ) status: Mapped[str] = mapped_column( String(20), nullable=False, default="active", comment="active | completed | abandoned", ) current_phase: Mapped[str] = mapped_column( String(20), nullable=False, default="scoping", comment="scoping | discovery | enrichment | review | generation", ) flow_type: Mapped[str] = mapped_column( String(20), nullable=False, comment="troubleshooting | procedural", ) conversation_history: Mapped[list[dict[str, Any]]] = mapped_column( JSONB, nullable=False, default=list ) working_tree: Mapped[Optional[dict[str, Any]]] = mapped_column( JSONB, nullable=True ) tree_metadata: Mapped[dict[str, Any]] = mapped_column( JSONB, nullable=False, default=dict ) provider_used: Mapped[Optional[str]] = mapped_column( String(20), nullable=True ) message_count: Mapped[int] = mapped_column( Integer, nullable=False, default=0 ) total_input_tokens: Mapped[int] = mapped_column( Integer, nullable=False, default=0 ) total_output_tokens: Mapped[int] = mapped_column( Integer, nullable=False, default=0 ) generated_tree_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("trees.id", ondelete="SET NULL"), nullable=True, ) expires_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), ) # Editor-embedded session: links to a specific tree/flow tree_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("trees.id", ondelete="CASCADE"), nullable=True, index=True, ) archived_at: Mapped[Optional[datetime]] = mapped_column( DateTime(timezone=True), nullable=True, )