78 lines
4.1 KiB
Python
78 lines
4.1 KiB
Python
import uuid
|
|
from datetime import datetime
|
|
from typing import TYPE_CHECKING, List, Optional
|
|
|
|
from sqlalchemy import JSON, BigInteger, Boolean, DateTime, ForeignKey, Index, String
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from letta.orm.mixins import OrganizationMixin, ProjectMixin, TemplateMixin
|
|
from letta.orm.sqlalchemy_base import SqlalchemyBase
|
|
from letta.schemas.enums import RunStatus
|
|
from letta.schemas.job import LettaRequestConfig
|
|
from letta.schemas.letta_stop_reason import StopReasonType
|
|
from letta.schemas.run import Run as PydanticRun
|
|
|
|
if TYPE_CHECKING:
|
|
from letta.orm.agent import Agent
|
|
from letta.orm.message import Message
|
|
from letta.orm.organization import Organization
|
|
from letta.orm.step import Step
|
|
|
|
|
|
class Run(SqlalchemyBase, OrganizationMixin, ProjectMixin, TemplateMixin):
|
|
"""Runs are created when agents process messages and represent a conversation or processing session.
|
|
Unlike Jobs, Runs are specifically tied to agent interactions and message processing.
|
|
"""
|
|
|
|
__tablename__ = "runs"
|
|
__pydantic_model__ = PydanticRun
|
|
__table_args__ = (
|
|
Index("ix_runs_created_at", "created_at", "id"),
|
|
Index("ix_runs_agent_id", "agent_id"),
|
|
Index("ix_runs_organization_id", "organization_id"),
|
|
Index("ix_runs_conversation_id", "conversation_id"),
|
|
)
|
|
|
|
# Generate run ID with run- prefix
|
|
id: Mapped[str] = mapped_column(String, primary_key=True, default=lambda: f"run-{uuid.uuid4()}")
|
|
|
|
# Core run fields
|
|
status: Mapped[RunStatus] = mapped_column(String, default=RunStatus.created, doc="The current status of the run.")
|
|
completed_at: Mapped[Optional[datetime]] = mapped_column(nullable=True, doc="The unix timestamp of when the run was completed.")
|
|
stop_reason: Mapped[Optional[StopReasonType]] = mapped_column(String, nullable=True, doc="The reason why the run was stopped.")
|
|
background: Mapped[Optional[bool]] = mapped_column(
|
|
Boolean, nullable=True, default=False, doc="Whether the run was created in background mode."
|
|
)
|
|
metadata_: Mapped[Optional[dict]] = mapped_column(JSON, doc="The metadata of the run.")
|
|
request_config: Mapped[Optional[LettaRequestConfig]] = mapped_column(
|
|
JSON, nullable=True, doc="The request configuration for the run, stored as JSON."
|
|
)
|
|
|
|
# Agent relationship - A run belongs to one agent
|
|
agent_id: Mapped[str] = mapped_column(String, ForeignKey("agents.id"), nullable=False, doc="The agent that owns this run.")
|
|
|
|
# Conversation relationship - Optional, a run may be associated with a conversation
|
|
conversation_id: Mapped[Optional[str]] = mapped_column(
|
|
String, ForeignKey("conversations.id", ondelete="SET NULL"), nullable=True, doc="The conversation this run belongs to."
|
|
)
|
|
|
|
# Callback related columns
|
|
callback_url: Mapped[Optional[str]] = mapped_column(String, nullable=True, doc="When set, POST to this URL after run completion.")
|
|
callback_sent_at: Mapped[Optional[datetime]] = mapped_column(nullable=True, doc="Timestamp when the callback was last attempted.")
|
|
callback_status_code: Mapped[Optional[int]] = mapped_column(nullable=True, doc="HTTP status code returned by the callback endpoint.")
|
|
callback_error: Mapped[Optional[str]] = mapped_column(
|
|
nullable=True, doc="Optional error message from attempting to POST the callback endpoint."
|
|
)
|
|
|
|
# Timing metrics (in nanoseconds for precision)
|
|
ttft_ns: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, doc="Time to first token in nanoseconds")
|
|
total_duration_ns: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True, doc="Total run duration in nanoseconds")
|
|
|
|
# Relationships
|
|
agent: Mapped["Agent"] = relationship("Agent", back_populates="runs")
|
|
organization: Mapped[Optional["Organization"]] = relationship("Organization", back_populates="runs")
|
|
|
|
# Steps that are part of this run
|
|
steps: Mapped[List["Step"]] = relationship("Step", back_populates="run", cascade="all, delete-orphan")
|
|
messages: Mapped[List["Message"]] = relationship("Message", back_populates="run", cascade="all, delete-orphan")
|