Files
resolutionflow/backend/app/models/ai_chat_session.py
chihlasm 4527bfced6 feat: extend AI chat session with tree_id and archived_at
Add tree_id FK (CASCADE) for editor-embedded sessions and archived_at
timestamp column to ai_chat_sessions table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:40:36 -05:00

100 lines
3.1 KiB
Python

"""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,
)