diff --git a/alembic/versions/ddecfe4902bc_add_prompts.py b/alembic/versions/ddecfe4902bc_add_prompts.py new file mode 100644 index 00000000..6e33a8c2 --- /dev/null +++ b/alembic/versions/ddecfe4902bc_add_prompts.py @@ -0,0 +1,42 @@ +"""add prompts + +Revision ID: ddecfe4902bc +Revises: c4eb5a907b38 +Create Date: 2025-07-21 15:58:13.357459 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "ddecfe4902bc" +down_revision: Union[str, None] = "c4eb5a907b38" +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! ### + op.create_table( + "prompts", + sa.Column("id", sa.String(), nullable=False), + sa.Column("prompt", sa.String(), nullable=False), + sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=True), + sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=True), + sa.Column("is_deleted", sa.Boolean(), server_default=sa.text("FALSE"), nullable=False), + sa.Column("_created_by_id", sa.String(), nullable=True), + sa.Column("_last_updated_by_id", sa.String(), nullable=True), + sa.Column("project_id", sa.String(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("prompts") + # ### end Alembic commands ### diff --git a/letta/orm/__init__.py b/letta/orm/__init__.py index 7b6076ef..3b65941e 100644 --- a/letta/orm/__init__.py +++ b/letta/orm/__init__.py @@ -20,6 +20,7 @@ from letta.orm.mcp_server import MCPServer from letta.orm.message import Message from letta.orm.organization import Organization from letta.orm.passage import AgentPassage, BasePassage, SourcePassage +from letta.orm.prompt import Prompt from letta.orm.provider import Provider from letta.orm.provider_trace import ProviderTrace from letta.orm.sandbox_config import AgentEnvironmentVariable, SandboxConfig, SandboxEnvironmentVariable diff --git a/letta/orm/mixins.py b/letta/orm/mixins.py index febf84de..0ce7042c 100644 --- a/letta/orm/mixins.py +++ b/letta/orm/mixins.py @@ -62,3 +62,11 @@ class SandboxConfigMixin(Base): __abstract__ = True sandbox_config_id: Mapped[str] = mapped_column(String, ForeignKey("sandbox_configs.id")) + + +class ProjectMixin(Base): + """Mixin for models that belong to a project.""" + + __abstract__ = True + + project_id: Mapped[str] = mapped_column(String, nullable=True, doc="The associated project id.") diff --git a/letta/orm/prompt.py b/letta/orm/prompt.py new file mode 100644 index 00000000..572e840d --- /dev/null +++ b/letta/orm/prompt.py @@ -0,0 +1,13 @@ +from sqlalchemy.orm import Mapped, mapped_column + +from letta.orm.mixins import ProjectMixin +from letta.orm.sqlalchemy_base import SqlalchemyBase +from letta.schemas.prompt import Prompt as PydanticPrompt + + +class Prompt(SqlalchemyBase, ProjectMixin): + __pydantic_model__ = PydanticPrompt + __tablename__ = "prompts" + + id: Mapped[str] = mapped_column(primary_key=True, doc="Unique passage identifier") + prompt: Mapped[str] = mapped_column(doc="The string contents of the prompt.") diff --git a/letta/schemas/prompt.py b/letta/schemas/prompt.py new file mode 100644 index 00000000..3e29718a --- /dev/null +++ b/letta/schemas/prompt.py @@ -0,0 +1,9 @@ +from pydantic import Field + +from letta.schemas.letta_base import OrmMetadataBase + + +class Prompt(OrmMetadataBase): + id: str = Field(..., description="The id of the agent. Assigned by the database.") + project_id: str | None = Field(None, description="The associated project id.") + prompt: str = Field(..., description="The string contents of the prompt.")