import uuid from datetime import datetime from sqlalchemy import String, Integer, DateTime, ForeignKey, Index, func, Text from sqlalchemy import Uuid from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base, JSONType class AgentRegistry(Base): __tablename__ = "agent_registry" id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4, ) name: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) display_name: Mapped[str | None] = mapped_column(String(100), nullable=True) agent_type: Mapped[str] = mapped_column(String(50), nullable=False) description: Mapped[str | None] = mapped_column(Text, nullable=True) version: Mapped[str | None] = mapped_column(String(20), nullable=True) endpoint: Mapped[str | None] = mapped_column(String(500), nullable=True) status: Mapped[str] = mapped_column(String(20), server_default="offline", nullable=False) capabilities: Mapped[dict | None] = mapped_column(JSONType, nullable=True) last_heartbeat: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) # Relationships configs: Mapped[list["AgentConfig"]] = relationship( "AgentConfig", back_populates="agent", cascade="all, delete-orphan" ) tasks: Mapped[list["AgentTask"]] = relationship( "AgentTask", back_populates="agent" ) task_logs: Mapped[list["AgentTaskLog"]] = relationship( "AgentTaskLog", back_populates="agent" ) __table_args__ = ( Index("idx_agent_registry_name", "name"), Index("idx_agent_registry_agent_type", "agent_type"), Index("idx_agent_registry_status", "status"), ) class AgentConfig(Base): __tablename__ = "agent_configs" id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4, ) agent_id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), ForeignKey("agent_registry.id", ondelete="CASCADE"), nullable=False, ) config_key: Mapped[str] = mapped_column(String(100), nullable=False) config_value: Mapped[dict] = mapped_column(JSONType, nullable=False) description: Mapped[str | None] = mapped_column(String(500), nullable=True) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) updated_by: Mapped[str | None] = mapped_column( String(36), ForeignKey("users.id", ondelete="SET NULL"), nullable=True, ) # Relationships agent: Mapped["AgentRegistry"] = relationship( "AgentRegistry", back_populates="configs" ) updater: Mapped["User | None"] = relationship( "User", foreign_keys=[updated_by] ) __table_args__ = ( Index("idx_agent_configs_agent_id", "agent_id"), Index("idx_agent_configs_agent_key", "agent_id", "config_key", unique=True), ) class AgentTask(Base): __tablename__ = "agent_tasks" id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4, ) agent_id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), ForeignKey("agent_registry.id", ondelete="CASCADE"), nullable=False, ) task_type: Mapped[str] = mapped_column(String(50), nullable=False) status: Mapped[str] = mapped_column(String(20), server_default="pending", nullable=False) priority: Mapped[int] = mapped_column(Integer, server_default="0", nullable=False) input_data: Mapped[dict | None] = mapped_column(JSONType, nullable=True) output_data: Mapped[dict | None] = mapped_column(JSONType, nullable=True) error_message: Mapped[str | None] = mapped_column(Text, nullable=True) created_by: Mapped[str | None] = mapped_column( String(36), ForeignKey("users.id", ondelete="SET NULL"), nullable=True, ) organization_id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, ) project_id: Mapped[uuid.UUID | None] = mapped_column( Uuid(as_uuid=True), ForeignKey("lifecycle_projects.id", ondelete="SET NULL"), nullable=True, ) scheduled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, ) # Relationships agent: Mapped["AgentRegistry"] = relationship( "AgentRegistry", back_populates="tasks" ) organization: Mapped["Organization"] = relationship( "Organization", back_populates="agents" ) project: Mapped["LifecycleProject | None"] = relationship( "LifecycleProject" ) creator: Mapped["User | None"] = relationship( "User", foreign_keys=[created_by] ) logs: Mapped[list["AgentTaskLog"]] = relationship( "AgentTaskLog", back_populates="task", cascade="all, delete-orphan" ) __table_args__ = ( Index("idx_agent_tasks_agent_id", "agent_id"), Index("idx_agent_tasks_status", "status"), Index("idx_agent_tasks_organization_id", "organization_id"), Index("idx_agent_tasks_project_id", "project_id"), Index("idx_agent_tasks_created_by", "created_by"), Index("idx_agent_tasks_task_type", "task_type"), ) class AgentTaskLog(Base): __tablename__ = "agent_task_logs" id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4, ) task_id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), ForeignKey("agent_tasks.id", ondelete="CASCADE"), nullable=False, ) agent_id: Mapped[uuid.UUID] = mapped_column( Uuid(as_uuid=True), ForeignKey("agent_registry.id", ondelete="CASCADE"), nullable=False, ) log_level: Mapped[str] = mapped_column(String(10), nullable=False) message: Mapped[str] = mapped_column(Text, nullable=False) extra_metadata: Mapped[dict | None] = mapped_column("metadata", JSONType, nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, ) # Relationships task: Mapped["AgentTask"] = relationship( "AgentTask", back_populates="logs" ) agent: Mapped["AgentRegistry"] = relationship( "AgentRegistry", back_populates="task_logs" ) __table_args__ = ( Index("idx_agent_task_logs_task_id", "task_id"), Index("idx_agent_task_logs_agent_id", "agent_id"), Index("idx_agent_task_logs_created_at", "created_at"), )