"""ORM model for roundtable-planning business chains. A "business chain" (业务链条) is a named, reusable, *ordered* list of agents the user assembles in the chain editor. In Step 2 the coordinator dispatches to the seats following this order (see ``multi-agent-business-chain-dev.md``). Persisted per user (like ``roundtable_drafts``) so it follows the account across devices/sessions. ``seats`` is stored as a JSON array serialized into ``PortableLongText`` (MySQL ``LONGTEXT``) rather than ``PortableJSON`` for headroom, mirroring the sibling roundtable persistence modules. """ from __future__ import annotations from datetime import UTC, datetime from sqlalchemy import String from sqlalchemy.orm import Mapped, mapped_column from deerflow.persistence.base import Base from deerflow.persistence.types import BeijingDateTime, PortableLongText class RoundtableChainRow(Base): __tablename__ = "roundtable_chains" id: Mapped[str] = mapped_column(String(64), primary_key=True) user_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True) # Human-readable chain title shown on the picker card. title: Mapped[str] = mapped_column(String(512), nullable=False, default="") # Optional free-text description. description: Mapped[str | None] = mapped_column(String(2048), nullable=True) # JSON: ordered [{"agent_id": str, "name": str, "description": str}, ...]. # seats[0] is the first seat to speak. Stored as LONGTEXT-backed JSON string. seats: Mapped[str | None] = mapped_column(PortableLongText, nullable=True) created_at: Mapped[datetime] = mapped_column( BeijingDateTime(), nullable=False, default=lambda: datetime.now(UTC) ) updated_at: Mapped[datetime] = mapped_column( BeijingDateTime(), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC), )