"""Tool Definition Manifest model.""" import uuid from typing import TYPE_CHECKING from sqlalchemy import Boolean, ForeignKey, JSON, String, Text from sqlalchemy import Uuid as UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from src.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin if TYPE_CHECKING: from src.models.user import User class ToolDefinitionManifest(UUIDPrimaryKeyMixin, TimestampMixin, Base): """A declarative manifest that compiles to Dockerfile + Compose. Can be either: - A base definition (is_base=True) with a FROM image and common packages - A tool definition (is_base=False) that references a base + adds specifics """ __tablename__ = "tool_definition_manifests" name: Mapped[str] = mapped_column(String(64), unique=True, nullable=False) display_name: Mapped[str] = mapped_column(String(128), nullable=False) description: Mapped[str | None] = mapped_column(Text, nullable=True) category: Mapped[str | None] = mapped_column(String(64), nullable=True) interface_type: Mapped[str] = mapped_column(String(16), nullable=False) # Base: either a direct image or a reference to another manifest base_image: Mapped[str | None] = mapped_column(String(256), nullable=True) base_definition_id: Mapped[uuid.UUID | None] = mapped_column( UUID(), ForeignKey("tool_definition_manifests.id"), nullable=True, ) base_version: Mapped[str] = mapped_column( String(32), nullable=False, default="latest" ) # The full manifest JSON manifest: Mapped[dict] = mapped_column(JSON, nullable=False) # Caches for quick inspection dockerfile_cache: Mapped[str | None] = mapped_column(Text, nullable=True) compose_cache: Mapped[str | None] = mapped_column(Text, nullable=True) # Versioning version: Mapped[str] = mapped_column(String(32), nullable=False, default="v1") is_base: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) created_by_id: Mapped[uuid.UUID | None] = mapped_column( UUID(), ForeignKey("users.id"), nullable=True, ) # Relationships created_by: Mapped["User | None"] = relationship( foreign_keys=[created_by_id], ) base_definition: Mapped["ToolDefinitionManifest | None"] = relationship( remote_side="ToolDefinitionManifest.id", foreign_keys=[base_definition_id], )