""" Database models for conversations. Following core-api patterns: SQLAlchemy 2.0 with async support. """ from datetime import datetime from uuid import UUID, uuid4 from sqlalchemy import ForeignKey, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from src.db.models import Base class Conversation(Base): """ A conversation session with an agent. Tracks message history, token usage, and metadata. """ __tablename__ = "conversations" id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4) user_id: Mapped[str] = mapped_column(String(255), index=True) agent_type: Mapped[str] = mapped_column(String(50), default="explore", insert_default="explore") title: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None) working_dir: Mapped[str] = mapped_column(String(1024), default=".", insert_default=".") total_tokens: Mapped[int] = mapped_column(default=0, insert_default=0) created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow) updated_at: Mapped[datetime | None] = mapped_column( default=datetime.utcnow, onupdate=datetime.utcnow, nullable=True ) # Relationships messages: Mapped[list["Message"]] = relationship( back_populates="conversation", cascade="all, delete-orphan", order_by="Message.created_at", ) def __repr__(self) -> str: return f"" class Message(Base): """ A single message in a conversation. Tracks role, content, token count, and summarization state. """ __tablename__ = "messages" id: Mapped[UUID] = mapped_column(primary_key=True, default=uuid4) conversation_id: Mapped[UUID] = mapped_column( ForeignKey("conversations.id", ondelete="CASCADE"), index=True ) role: Mapped[str] = mapped_column(String(20)) # user, assistant, system, summary content: Mapped[str] = mapped_column(Text) token_count: Mapped[int] = mapped_column(default=0, insert_default=0) is_summary: Mapped[bool] = mapped_column(default=False, insert_default=False) summarizes_up_to: Mapped[UUID | None] = mapped_column(nullable=True, default=None) created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow) # Relationships conversation: Mapped["Conversation"] = relationship(back_populates="messages") def __repr__(self) -> str: preview = self.content[:30] + "..." if len(self.content) > 30 else self.content return f""