PMFlow/backend/app/models/pmflow_agent_runtime.py

199 lines
12 KiB
Python

"""Durable Agent OS runtime records for PMFlow AI."""
from __future__ import annotations
from typing import Any, Optional
from sqlalchemy import BigInteger, Boolean, ForeignKey, Integer, Text, TIMESTAMP, UniqueConstraint, VARCHAR
from sqlalchemy.orm import Mapped, mapped_column
from .base import Base
from .types import JSONB
class PMFlowAgentRun(Base):
"""Persisted execution container for one PMFlow AI agent turn.
User-facing continuity lives in PMFlowAIThread/PMFlowAIMessage. Runs are
immutable execution records attached to a thread message.
"""
__tablename__ = "pmflow_agent_runs"
__table_args__ = (
UniqueConstraint("tenant_id", "public_run_id", name="uq_pmflow_agent_runs_tenant_public_run_id"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
public_run_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
thread_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("pmflow_ai_threads.id", ondelete="SET NULL"), nullable=True, index=True)
user_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("users.id"), nullable=True, index=True)
qa_session_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("qa_sessions.id"), nullable=True, index=True)
workspace_scope: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True, index=True)
surface: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True)
presentation_mode: Mapped[Optional[str]] = mapped_column(VARCHAR(40), nullable=True)
source_channel: Mapped[Optional[str]] = mapped_column(VARCHAR(40), nullable=True, index=True)
source_ref: Mapped[Optional[str]] = mapped_column(VARCHAR(160), nullable=True, index=True)
title: Mapped[Optional[str]] = mapped_column(VARCHAR(240), nullable=True)
goal: Mapped[str] = mapped_column(Text, nullable=False, default="")
status: Mapped[str] = mapped_column(VARCHAR(32), nullable=False, default="active", index=True)
active_object_refs: Mapped[Any] = mapped_column(JSONB, nullable=True, default=list)
current_step_id: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True)
final_answer: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
last_error: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
run_metadata: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
started_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
completed_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
class PMFlowAIThread(Base):
"""User-visible PMFlow AI conversation/thread."""
__tablename__ = "pmflow_ai_threads"
__table_args__ = (
UniqueConstraint("tenant_id", "public_thread_id", name="uq_pmflow_ai_threads_tenant_public_thread_id"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
public_thread_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
user_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("users.id"), nullable=True, index=True)
qa_session_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("qa_sessions.id", ondelete="SET NULL"), nullable=True, index=True)
workspace_scope: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True, index=True)
surface: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True)
title: Mapped[str] = mapped_column(VARCHAR(240), nullable=False, default="PMFlow AI")
status: Mapped[str] = mapped_column(VARCHAR(32), nullable=False, default="active", index=True)
current_object_refs: Mapped[Any] = mapped_column(JSONB, nullable=True, default=list)
last_run_public_id: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True, index=True)
last_message_preview: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
message_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
thread_metadata: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
started_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
last_message_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
class PMFlowAIMessage(Base):
"""A user or assistant message inside a PMFlow AI thread."""
__tablename__ = "pmflow_ai_messages"
__table_args__ = (
UniqueConstraint("tenant_id", "thread_id", "public_message_id", name="uq_pmflow_ai_messages_tenant_thread_public_message"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
thread_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("pmflow_ai_threads.id", ondelete="CASCADE"), nullable=False, index=True)
public_message_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
role: Mapped[str] = mapped_column(VARCHAR(24), nullable=False, index=True)
message_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0, index=True)
run_public_id: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True, index=True)
qa_record_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("qa_records.id", ondelete="SET NULL"), nullable=True, index=True)
content: Mapped[str] = mapped_column(Text, nullable=False, default="")
message_payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
sent_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
class PMFlowAgentStep(Base):
"""A durable step observed in an Agent OS run."""
__tablename__ = "pmflow_agent_steps"
__table_args__ = (
UniqueConstraint("tenant_id", "run_id", "public_step_id", name="uq_pmflow_agent_steps_tenant_run_public_step"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
run_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("pmflow_agent_runs.id", ondelete="CASCADE"), nullable=False, index=True)
public_step_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
step_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0, index=True)
step_kind: Mapped[str] = mapped_column(VARCHAR(64), nullable=False, default="runtime_step", index=True)
status: Mapped[str] = mapped_column(VARCHAR(32), nullable=False, default="completed", index=True)
input_summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
output_summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
tool_name: Mapped[Optional[str]] = mapped_column(VARCHAR(120), nullable=True, index=True)
duration_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
step_payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
started_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True)
completed_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True)
class PMFlowAgentObservation(Base):
"""Facts and gaps observed by a step or tool during a run."""
__tablename__ = "pmflow_agent_observations"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"run_id",
"public_observation_id",
name="uq_pmflow_agent_observations_tenant_run_public_observation",
),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
run_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("pmflow_agent_runs.id", ondelete="CASCADE"), nullable=False, index=True)
step_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("pmflow_agent_steps.id", ondelete="SET NULL"), nullable=True, index=True)
public_observation_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
source_kind: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, default="agent_runtime", index=True)
customer_safe_summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
confidence: Mapped[Optional[str]] = mapped_column(VARCHAR(32), nullable=True)
facts: Mapped[Any] = mapped_column(JSONB, nullable=True, default=list)
gaps: Mapped[Any] = mapped_column(JSONB, nullable=True, default=list)
raw_payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
observed_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
class PMFlowAgentArtifact(Base):
"""Durable artifacts created by an Agent OS run."""
__tablename__ = "pmflow_agent_artifacts"
__table_args__ = (
UniqueConstraint("tenant_id", "run_id", "public_artifact_id", name="uq_pmflow_agent_artifacts_tenant_run_public_artifact"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
run_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("pmflow_agent_runs.id", ondelete="CASCADE"), nullable=False, index=True)
step_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("pmflow_agent_steps.id", ondelete="SET NULL"), nullable=True, index=True)
public_artifact_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
artifact_kind: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
title: Mapped[Optional[str]] = mapped_column(VARCHAR(240), nullable=True)
status: Mapped[str] = mapped_column(VARCHAR(32), nullable=False, default="created", index=True)
payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
customer_safe_payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
created_by_step_id: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True, index=True)
class PMFlowAgentVerification(Base):
"""Verification result for a run, step or artifact."""
__tablename__ = "pmflow_agent_verifications"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"run_id",
"public_verification_id",
name="uq_pmflow_agent_verifications_tenant_run_public_verification",
),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
run_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("pmflow_agent_runs.id", ondelete="CASCADE"), nullable=False, index=True)
step_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey("pmflow_agent_steps.id", ondelete="SET NULL"), nullable=True, index=True)
public_verification_id: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
target_ref: Mapped[Optional[str]] = mapped_column(VARCHAR(160), nullable=True, index=True)
result: Mapped[str] = mapped_column(VARCHAR(32), nullable=False, default="unknown", index=True)
retry_would_change_state: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
findings: Mapped[Any] = mapped_column(JSONB, nullable=True, default=list)
verification_payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
verified_at: Mapped[Optional[TIMESTAMP]] = mapped_column(TIMESTAMP, nullable=True, index=True)
class PMFlowAgentMemory(Base):
"""Durable run memory and learning references produced by PMFlow AI."""
__tablename__ = "pmflow_agent_memories"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
run_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("pmflow_agent_runs.id", ondelete="CASCADE"), nullable=False, index=True)
memory_kind: Mapped[str] = mapped_column(VARCHAR(80), nullable=False, index=True)
scope_ref: Mapped[Optional[str]] = mapped_column(VARCHAR(160), nullable=True, index=True)
outcome_signal: Mapped[Optional[str]] = mapped_column(VARCHAR(80), nullable=True, index=True)
content: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)
memory_payload: Mapped[Any] = mapped_column(JSONB, nullable=True, default=dict)