diff --git a/agenta-backend/agenta_backend/migrations/postgres/data_migrations/projects.py b/agenta-backend/agenta_backend/migrations/postgres/data_migrations/projects.py index 5ba0acc0f6..b2ba4be98b 100644 --- a/agenta-backend/agenta_backend/migrations/postgres/data_migrations/projects.py +++ b/agenta-backend/agenta_backend/migrations/postgres/data_migrations/projects.py @@ -8,9 +8,9 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, Session +from agenta_backend.models.deprecated_models import ProjectScopedAppDB as AppDB from agenta_backend.models.db_models import ( ProjectDB, - AppDB, AppVariantDB, AppVariantRevisionsDB, VariantBaseDB, diff --git a/agenta-backend/agenta_backend/migrations/postgres/versions/0f086ebc2f82_added_the_app_type_column_to_the_app_db_.py b/agenta-backend/agenta_backend/migrations/postgres/versions/0f086ebc2f82_added_the_app_type_column_to_the_app_db_.py new file mode 100644 index 0000000000..aed4283756 --- /dev/null +++ b/agenta-backend/agenta_backend/migrations/postgres/versions/0f086ebc2f82_added_the_app_type_column_to_the_app_db_.py @@ -0,0 +1,60 @@ +"""Added the 'app_type' column to the 'app_db' table + +Revision ID: 0f086ebc2f82 +Revises: 78cde3fc549c +Create Date: 2024-09-09 10:11:05.429116 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = "0f086ebc2f82" +down_revision: Union[str, None] = "847972cfa14a" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + + # Create the enum type first + app_enumtype = sa.Enum( + "CHAT_TEMPLATE", + "COMPLETION_TEMPLATE", + "CUSTOM", + name="app_enumtype", + ) + app_enumtype.create(op.get_bind(), checkfirst=True) + + # Then add the column using the enum type + op.add_column( + "app_db", + sa.Column( + "app_type", + app_enumtype, + nullable=True, + ), + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + + # Drop the column first + op.drop_column("app_db", "app_type") + + # Then drop the enum type + app_enumtype = sa.Enum( + "CHAT_TEMPLATE", + "COMPLETION_TEMPLATE", + "CUSTOM", + name="app_enumtype", + ) + app_enumtype.drop(op.get_bind(), checkfirst=True) + # ### end Alembic commands ### diff --git a/agenta-backend/agenta_backend/models/api/api_models.py b/agenta-backend/agenta_backend/models/api/api_models.py index 472734c9c3..bbf13b41d6 100644 --- a/agenta-backend/agenta_backend/models/api/api_models.py +++ b/agenta-backend/agenta_backend/models/api/api_models.py @@ -227,6 +227,7 @@ class URI(BaseModel): class App(BaseModel): app_id: str app_name: str + app_type: Optional[str] = None updated_at: str diff --git a/agenta-backend/agenta_backend/models/converters.py b/agenta-backend/agenta_backend/models/converters.py index ce2ca870b3..d79b12c0f9 100644 --- a/agenta-backend/agenta_backend/models/converters.py +++ b/agenta-backend/agenta_backend/models/converters.py @@ -2,14 +2,13 @@ """ import uuid -import json import logging from typing import List, Tuple, Any from agenta_backend.services import db_manager from agenta_backend.utils.common import isCloudEE from agenta_backend.models.api.user_models import User -from agenta_backend.models.shared_models import ConfigDB +from agenta_backend.models.shared_models import ConfigDB, AppType from agenta_backend.models.api.evaluation_model import ( CorrectAnswer, Evaluation, @@ -433,6 +432,7 @@ def app_db_to_pydantic(app_db: AppDB) -> App: return App( app_name=app_db.app_name, app_id=str(app_db.id), + app_type=AppType.friendly_tag(app_db.app_type), updated_at=str(app_db.updated_at), ) diff --git a/agenta-backend/agenta_backend/models/db_models.py b/agenta-backend/agenta_backend/models/db_models.py index 10ff94dc36..8142dedc5b 100644 --- a/agenta-backend/agenta_backend/models/db_models.py +++ b/agenta-backend/agenta_backend/models/db_models.py @@ -15,7 +15,7 @@ from sqlalchemy.dialects.postgresql import UUID, JSONB from agenta_backend.dbs.postgres.shared.base import Base -from agenta_backend.models.shared_models import TemplateType +from agenta_backend.models.shared_models import TemplateType, AppType CASCADE_ALL_DELETE = "all, delete-orphan" @@ -106,6 +106,7 @@ class AppDB(Base): nullable=False, ) app_name = Column(String) + app_type = Column(Enum(AppType, name="app_enumtype"), nullable=True) project_id = Column( UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE") ) diff --git a/agenta-backend/agenta_backend/models/deprecated_models.py b/agenta-backend/agenta_backend/models/deprecated_models.py index 4bd4373b4e..80c3c04f65 100644 --- a/agenta-backend/agenta_backend/models/deprecated_models.py +++ b/agenta-backend/agenta_backend/models/deprecated_models.py @@ -15,6 +15,23 @@ DeprecatedBase = declarative_base() +class ProjectScopedAppDB(DeprecatedBase): + __tablename__ = "app_db" + __table_args__ = {"extend_existing": True} + + id = Column( + UUID(as_uuid=True), + primary_key=True, + default=uuid.uuid7, + unique=True, + nullable=False, + ) + app_name = Column(String) + project_id = Column( + UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE") + ) + + class DeprecatedAppDB(DeprecatedBase): __tablename__ = "app_db" __table_args__ = {"extend_existing": True} diff --git a/agenta-backend/agenta_backend/models/shared_models.py b/agenta-backend/agenta_backend/models/shared_models.py index 56affd84f8..d14ea22140 100644 --- a/agenta-backend/agenta_backend/models/shared_models.py +++ b/agenta-backend/agenta_backend/models/shared_models.py @@ -65,3 +65,18 @@ class HumanEvaluationScenarioOutput(BaseModel): class TemplateType(enum.Enum): IMAGE = "image" ZIP = "zip" + + +class AppType(str, enum.Enum): + CHAT_TEMPLATE = "TEMPLATE:simple_chat" + COMPLETION_TEMPLATE = "TEMPLATE:simple_completion" + CUSTOM = "CUSTOM" + + @classmethod + def friendly_tag(cls, app_type: str): + mappings = { + cls.CHAT_TEMPLATE: "chat", + cls.COMPLETION_TEMPLATE: "completion", + cls.CUSTOM: "custom", + } + return mappings.get(app_type, None) diff --git a/agenta-backend/agenta_backend/routers/app_router.py b/agenta-backend/agenta_backend/routers/app_router.py index 86204c8724..34f1145cd9 100644 --- a/agenta-backend/agenta_backend/routers/app_router.py +++ b/agenta-backend/agenta_backend/routers/app_router.py @@ -527,31 +527,32 @@ async def create_app_and_variant_from_template( ) logger.debug( - "Step 5: Creating new app and initializing environments" + "Step 5: Retrieve template from db" if isCloudEE() - else "Step 2: Creating new app and initializing environments" + else "Step 2: Retrieve template from db" + ) + template_db = await db_manager.get_template(payload.template_id) + + logger.debug( + "Step 6: Creating new app and initializing environments" + if isCloudEE() + else "Step 3: Creating new app and initializing environments" ) if app is None: app = await db_manager.create_app_and_envs( - app_name, + app_name=app_name, + template_id=str(template_db.id), project_id=payload.project_id or request.state.project_id, workspace_id=payload.workspace_id, ) - logger.debug( - "Step 6: Retrieve template from db" - if isCloudEE() - else "Step 3: Retrieve template from db" - ) - template_db = await db_manager.get_template(payload.template_id) - repo_name = os.environ.get("AGENTA_TEMPLATE_REPO", "agentaai/templates_v2") - image_name = f"{repo_name}:{template_db.name}" - logger.debug( "Step 7: Creating image instance and adding variant based on image" if isCloudEE() else "Step 4: Creating image instance and adding variant based on image" ) + repo_name = os.environ.get("AGENTA_TEMPLATE_REPO", "agentaai/templates_v2") + image_name = f"{repo_name}:{template_db.name}" app_variant_db = await app_manager.add_variant_based_on_image( app=app, project_id=str(app.project_id), diff --git a/agenta-backend/agenta_backend/services/db_manager.py b/agenta-backend/agenta_backend/services/db_manager.py index dc4842ea67..f12dabdf5d 100644 --- a/agenta-backend/agenta_backend/services/db_manager.py +++ b/agenta-backend/agenta_backend/services/db_manager.py @@ -1,6 +1,7 @@ import os import uuid import logging +from enum import Enum from pathlib import Path from urllib.parse import urlparse from typing import Any, Dict, List, Optional, Tuple @@ -77,6 +78,7 @@ from agenta_backend.models.shared_models import ( Result, + AppType, ConfigDB, TemplateType, CorrectAnswer, @@ -703,14 +705,39 @@ async def create_deployment( raise Exception(f"Error while creating deployment: {e}") +async def get_app_type_from_template_by_id(template_id: Optional[str]) -> str: + """Get the application type from the specified template. + + Args: + template_id (Optional[str]): The ID of the template + + Returns: + AppType (str): The determined application type. Defaults to AppType.CUSTOM. + """ + + if template_id is None: + return AppType.CUSTOM + + template_db = await get_template(template_id=template_id) + if "Completion Prompt" in template_db.title: + return AppType.COMPLETION_TEMPLATE + elif "Chat Prompt" in template_db.title: + return AppType.CHAT_TEMPLATE + return AppType.CUSTOM + + async def create_app_and_envs( - app_name: str, project_id: Optional[str] = None, workspace_id: Optional[str] = None + app_name: str, + template_id: Optional[str] = None, + project_id: Optional[str] = None, + workspace_id: Optional[str] = None, ) -> AppDB: """ Create a new app with the given name and organization ID. Args: app_name (str): The name of the app to create. + template_id (str): The ID of the template. project_id (str): The ID of the project. Returns: @@ -730,8 +757,11 @@ async def create_app_and_envs( if app is not None: raise ValueError("App with the same name already exists") + app_type = await get_app_type_from_template_by_id(template_id=template_id) async with engine.session() as session: - app = AppDB(app_name=app_name, project_id=uuid.UUID(project_id)) + app = AppDB( + app_name=app_name, project_id=uuid.UUID(project_id), app_type=app_type + ) session.add(app) await session.commit() diff --git a/agenta-cli/pyproject.toml b/agenta-cli/pyproject.toml index e140d98586..04eb9ce188 100644 --- a/agenta-cli/pyproject.toml +++ b/agenta-cli/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "agenta" -version = "0.27.7a0" +version = "0.27.7a1" description = "The SDK for agenta is an open-source LLMOps platform." readme = "README.md" authors = ["Mahmoud Mabrouk "] diff --git a/agenta-web/src/components/AppSelector/AppCard.tsx b/agenta-web/src/components/AppSelector/AppCard.tsx index d0e6fa501f..03ed0fdffe 100644 --- a/agenta-web/src/components/AppSelector/AppCard.tsx +++ b/agenta-web/src/components/AppSelector/AppCard.tsx @@ -135,7 +135,7 @@ const AppCard: React.FC<{
Type - Template + {app.app_type}
Last modified: diff --git a/agenta-web/src/lib/Types.ts b/agenta-web/src/lib/Types.ts index e95d56bc41..beab6fa835 100644 --- a/agenta-web/src/lib/Types.ts +++ b/agenta-web/src/lib/Types.ts @@ -24,6 +24,7 @@ export type TestsetCreationMode = "create" | "clone" | "rename" export interface ListAppsItem { app_id: string app_name: string + app_type?: string updated_at: string }