"""SQLAlchemy ORM models for sessions, messages, tool_runs, skill_prefs.""" from __future__ import annotations from datetime import datetime, timezone from sqlalchemy import JSON, ForeignKey, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from app.storage.db import Base def _utcnow() -> datetime: return datetime.now(timezone.utc) class Session(Base): __tablename__ = "sessions" id: Mapped[str] = mapped_column(String(64), primary_key=True) user_id: Mapped[str] = mapped_column(String(64), default="default", index=True) title: Mapped[str] = mapped_column(String(255), default="新对话") created_at: Mapped[datetime] = mapped_column(default=_utcnow) updated_at: Mapped[datetime] = mapped_column(default=_utcnow, onupdate=_utcnow) messages: Mapped[list["Message"]] = relationship( back_populates="session", cascade="all, delete-orphan", order_by="Message.created_at" ) class Message(Base): __tablename__ = "messages" id: Mapped[str] = mapped_column(String(64), primary_key=True) session_id: Mapped[str] = mapped_column( String(64), ForeignKey("sessions.id", ondelete="CASCADE"), index=True ) role: Mapped[str] = mapped_column(String(16)) # user/assistant/system/tool content: Mapped[str] = mapped_column(Text, default="") tool_calls_json: Mapped[str | None] = mapped_column(Text, nullable=True) tool_call_id: Mapped[str | None] = mapped_column(String(64), nullable=True) thinking_json: Mapped[str | None] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column(default=_utcnow, index=True) session: Mapped[Session] = relationship(back_populates="messages") class ToolRun(Base): __tablename__ = "tool_runs" id: Mapped[str] = mapped_column(String(64), primary_key=True) message_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) session_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) skill_name: Mapped[str] = mapped_column(String(64), index=True) args_json: Mapped[str | None] = mapped_column(Text, nullable=True) result_json: Mapped[str | None] = mapped_column(Text, nullable=True) ok: Mapped[int] = mapped_column(Integer, default=1) duration_ms: Mapped[int] = mapped_column(Integer, default=0) trace_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) created_at: Mapped[datetime] = mapped_column(default=_utcnow) class SkillPref(Base): __tablename__ = "skill_prefs" user_id: Mapped[str] = mapped_column(String(64), primary_key=True) skill_name: Mapped[str] = mapped_column(String(64), primary_key=True) enabled: Mapped[int] = mapped_column(Integer, default=1) config_json: Mapped[str | None] = mapped_column(Text, nullable=True) updated_at: Mapped[datetime] = mapped_column(default=_utcnow, onupdate=_utcnow)