78 lines
4.9 KiB
Python
78 lines
4.9 KiB
Python
"""ORM rows for the independent enterprise-research workbench."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
from sqlalchemy import Index, String, Text, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from deerflow.persistence.base import Base
|
|
from deerflow.persistence.types import BeijingDateTime, PortableJSON, PortableLongText
|
|
|
|
|
|
class EnterpriseResearchTaskRow(Base):
|
|
"""A user-owned research task plus its bounded WeKnora evidence snapshot."""
|
|
|
|
__tablename__ = "enterprise_research_tasks"
|
|
__table_args__ = (Index("ix_enterprise_research_tasks_owner_updated", "user_id", "updated_at"),)
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
user_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
|
|
subject: Mapped[str] = mapped_column(String(256), nullable=False)
|
|
focus: Mapped[str] = mapped_column(Text, nullable=False, default="", server_default="")
|
|
template_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
knowledge_base_ids: Mapped[list[str]] = mapped_column(PortableJSON(), nullable=False, default=list)
|
|
queries: Mapped[list[str]] = mapped_column(PortableJSON(), nullable=False, default=list)
|
|
# Nullable keeps upgrades safe: the generic schema reconciler can add this
|
|
# field to a phase-one table without an unsafe MySQL TEXT default.
|
|
selected_source_ids: Mapped[list[str] | None] = mapped_column(PortableJSON(), nullable=True, default=list)
|
|
# A WeKnora result can contain a long document chunk. MySQL TEXT is only
|
|
# 64 KiB, so evidence uses LONGTEXT through PortableLongText.
|
|
sources_json: Mapped[str] = mapped_column(PortableLongText(), nullable=False, default="[]", server_default="[]")
|
|
plan_markdown: Mapped[str | None] = mapped_column(PortableLongText(), nullable=True)
|
|
report_markdown: Mapped[str | None] = mapped_column(PortableLongText(), nullable=True)
|
|
report_summary: Mapped[str | None] = mapped_column(PortableLongText(), nullable=True)
|
|
report_model_name: Mapped[str | None] = mapped_column(String(256), nullable=True)
|
|
active_report_job_id: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False, default="draft", server_default="draft")
|
|
warning: 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)
|
|
)
|
|
|
|
|
|
class EnterpriseResearchReportJobRow(Base):
|
|
"""A report job whose plan/evidence are frozen when the user starts it."""
|
|
|
|
__tablename__ = "enterprise_research_report_jobs"
|
|
__table_args__ = (
|
|
Index("ix_enterprise_research_report_jobs_task_owner_updated", "task_id", "user_id", "updated_at"),
|
|
UniqueConstraint("active_dedupe_key", name="uq_enterprise_research_report_jobs_active"),
|
|
)
|
|
|
|
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
|
task_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
|
user_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False, default="queued", server_default="queued")
|
|
phase: Mapped[str] = mapped_column(String(32), nullable=False, default="queued", server_default="queued")
|
|
model_name: Mapped[str | None] = mapped_column(String(256), nullable=True)
|
|
# Present only for queued/running rows. NULL terminal rows keep unlimited
|
|
# history while this key rejects cross-process duplicate starts.
|
|
active_dedupe_key: Mapped[str | None] = mapped_column(String(256), nullable=True)
|
|
action: Mapped[str | None] = mapped_column(String(32), nullable=True, default="initial")
|
|
instruction: Mapped[str | None] = mapped_column(PortableLongText(), nullable=True)
|
|
style: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
target_length: Mapped[int | None] = mapped_column(nullable=True)
|
|
plan_snapshot: Mapped[str] = mapped_column(PortableLongText(), nullable=False)
|
|
sources_json: Mapped[str] = mapped_column(PortableLongText(), nullable=False)
|
|
original_report: Mapped[str | None] = mapped_column(PortableLongText(), nullable=True)
|
|
report_markdown: Mapped[str] = mapped_column(PortableLongText(), nullable=False, default="", server_default="")
|
|
report_summary: Mapped[str | None] = mapped_column(PortableLongText(), nullable=True)
|
|
error_message: 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)
|
|
)
|