"""ORM model for run metadata.""" from __future__ import annotations from datetime import UTC, datetime from sqlalchemy import Index, String, Text from sqlalchemy.orm import Mapped, mapped_column from deerflow.persistence.base import Base from deerflow.persistence.types import BeijingDateTime, PortableJSON class RunRow(Base): __tablename__ = "runs" run_id: Mapped[str] = mapped_column(String(64), primary_key=True) thread_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) assistant_id: Mapped[str | None] = mapped_column(String(128)) user_id: Mapped[str | None] = mapped_column(String(64), index=True) status: Mapped[str] = mapped_column(String(20), default="pending") # "pending" | "running" | "success" | "error" | "timeout" | "interrupted" model_name: Mapped[str | None] = mapped_column(String(128)) multitask_strategy: Mapped[str] = mapped_column(String(20), default="reject") metadata_json: Mapped[dict] = mapped_column(PortableJSON(), default=dict) kwargs_json: Mapped[dict] = mapped_column(PortableJSON(), default=dict) error: Mapped[str | None] = mapped_column(Text) # Convenience fields (for listing pages without querying RunEventStore) message_count: Mapped[int] = mapped_column(default=0) first_human_message: Mapped[str | None] = mapped_column(Text) last_ai_message: Mapped[str | None] = mapped_column(Text) # Token usage (accumulated in-memory by RunJournal, written on run completion) total_input_tokens: Mapped[int] = mapped_column(default=0) total_output_tokens: Mapped[int] = mapped_column(default=0) total_tokens: Mapped[int] = mapped_column(default=0) llm_call_count: Mapped[int] = mapped_column(default=0) lead_agent_tokens: Mapped[int] = mapped_column(default=0) subagent_tokens: Mapped[int] = mapped_column(default=0) middleware_tokens: Mapped[int] = mapped_column(default=0) # Follow-up association follow_up_to_run_id: Mapped[str | None] = mapped_column(String(64)) created_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC)) updated_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC)) __table_args__ = ( Index("ix_runs_thread_status", "thread_id", "status"), Index("ix_runs_created_user_status", "created_at", "user_id", "status"), Index("ix_runs_user_created", "user_id", "created_at"), Index("ix_runs_thread_created", "thread_id", "created_at"), Index("ix_runs_created_assistant_user", "created_at", "assistant_id", "user_id"), Index("ix_runs_created_model_user", "created_at", "model_name", "user_id"), )