| """Agent session and execution step models — persistent, auditable agent lifecycle."""
|
|
|
| import uuid
|
| from datetime import datetime, timezone
|
| from sqlalchemy import String, Integer, Float, DateTime, Text, ForeignKey, JSON, Boolean
|
| from sqlalchemy.orm import Mapped, mapped_column, relationship
|
| from mac.database import Base
|
|
|
|
|
| def _utcnow():
|
| return datetime.now(timezone.utc)
|
|
|
|
|
| def _gen_uuid():
|
| return str(uuid.uuid4())
|
|
|
|
|
| class AgentSession(Base):
|
| """A durable agent execution session tied to a user."""
|
| __tablename__ = "agent_sessions"
|
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_gen_uuid)
|
| user_id: Mapped[str] = mapped_column(String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
|
| query: Mapped[str] = mapped_column(Text, nullable=False)
|
| status: Mapped[str] = mapped_column(String(20), nullable=False, default="planning")
|
|
|
| final_response: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| plan: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
| step_count: Mapped[int] = mapped_column(Integer, default=0)
|
| current_step: Mapped[int] = mapped_column(Integer, default=0)
|
| tokens_used: Mapped[int] = mapped_column(Integer, default=0)
|
| latency_ms: Mapped[int] = mapped_column(Integer, default=0)
|
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_utcnow, index=True)
|
| updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_utcnow, onupdate=_utcnow)
|
|
|
| steps: Mapped[list["AgentStep"]] = relationship(
|
| back_populates="session", cascade="all, delete-orphan", order_by="AgentStep.step_number"
|
| )
|
|
|
|
|
| class AgentStep(Base):
|
| """Individual execution step within an agent session."""
|
| __tablename__ = "agent_steps"
|
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_gen_uuid)
|
| session_id: Mapped[str] = mapped_column(String(36), ForeignKey("agent_sessions.id", ondelete="CASCADE"), nullable=False, index=True)
|
| step_number: Mapped[int] = mapped_column(Integer, nullable=False)
|
| title: Mapped[str] = mapped_column(String(200), nullable=False)
|
| description: Mapped[str] = mapped_column(Text, nullable=True)
|
| tool: Mapped[str] = mapped_column(String(50), nullable=False, default="none")
|
| status: Mapped[str] = mapped_column(String(20), nullable=False, default="pending")
|
|
|
| result: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
| error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
| completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
| session: Mapped["AgentSession"] = relationship(back_populates="steps")
|
|
|