Files
letta-server/letta/orm/run.py
Kian Jones 25d54dd896 chore: enable F821, F401, W293 (#9503)
* auto fixes

* auto fix pt2 and transitive deps and undefined var checking locals()

* manual fixes (ignored or letta-code fixed)

* fix circular import
2026-02-24 10:55:08 -08:00

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