51 lines
2.7 KiB
Python
51 lines
2.7 KiB
Python
"""Chat-Sessions und Nachrichten (→ Konzept 6.1)."""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy import JSON, Boolean, ForeignKey, String, Text, Uuid
|
|
from sqlalchemy import false as sa_false
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.core.database import Base, now
|
|
|
|
|
|
class ChatSession(Base):
|
|
__tablename__ = "chat_sessions"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
workspace_id: Mapped[int] = mapped_column(ForeignKey("workspaces.id", ondelete="CASCADE"), index=True)
|
|
title: Mapped[str] = mapped_column(String(200))
|
|
created_by: Mapped[int] = mapped_column(ForeignKey("users.id"))
|
|
created: Mapped[datetime] = mapped_column(default=now)
|
|
# Arbeitsnotiz: automatische Zusammenfassung der Nachrichten bis summary_upto, die nicht mehr
|
|
# vollständig in den Kontext passen (→ lange Coding-Sessions)
|
|
summary: Mapped[str] = mapped_column(Text, default="", server_default="")
|
|
summary_upto: Mapped[int | None]
|
|
# Plan der KI (update_plan): [{"text": …, "status": "open" | "in_progress" | "done"}]
|
|
plan: Mapped[list] = mapped_column(JSON, default=list, server_default="[]")
|
|
# Planungsmodus: nur lesende Tools und update_plan, bis jemand „Plan umsetzen“ klickt
|
|
plan_mode: Mapped[bool] = mapped_column(Boolean, default=False, server_default=sa_false())
|
|
# Ausgangs-Branch je Git-Quelle ({"<source_id>": "feature/x"}), wenn der Chat nicht auf dem Ziel-Branch
|
|
# beginnt; der Chat-Branch zweigt davon ab und hat ihn als Ziel (Abgleich, Pull Request)
|
|
git_base: Mapped[dict] = mapped_column(JSON, default=dict, server_default="{}")
|
|
|
|
|
|
class Message(Base):
|
|
__tablename__ = "messages"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
chat_session_id: Mapped[int] = mapped_column(ForeignKey("chat_sessions.id", ondelete="CASCADE"), index=True)
|
|
role: Mapped[str] = mapped_column(String(20)) # user | assistant
|
|
content: Mapped[str] = mapped_column(Text)
|
|
# Antwort-Elemente der Responses API (u. a. verschlüsseltes Reasoning), unverändert
|
|
# beim nächsten Aufruf zurückgegeben (→ Konzept 8.1)
|
|
items: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list)
|
|
# Verwendetes Modell und Verbrauch, für Nachvollziehbarkeit
|
|
model: Mapped[str] = mapped_column(String(200), default="")
|
|
usage: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict)
|
|
# Run, der die Nachricht ausgelöst (user) bzw. erzeugt (assistant) hat
|
|
run_id: Mapped[uuid.UUID | None] = mapped_column(Uuid, ForeignKey("task_runs.id", ondelete="SET NULL"))
|
|
author_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"))
|
|
created: Mapped[datetime] = mapped_column(default=now)
|