Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Add is_deleted column in assistant table

Revision ID: e8ee93526b37
Revises: 4aa1f48c6321
Create Date: 2025-07-21 12:40:03.791321

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "e8ee93526b37"
down_revision = "4aa1f48c6321"
branch_labels = None
depends_on = None


def upgrade():
op.add_column(
"openai_assistant", sa.Column("is_deleted", sa.Boolean(), nullable=False)
)
op.add_column(
"openai_assistant", sa.Column("deleted_at", sa.DateTime(), nullable=True)
)


def downgrade():
op.drop_column("openai_assistant", "deleted_at")
op.drop_column("openai_assistant", "is_deleted")
117 changes: 114 additions & 3 deletions backend/app/api/routes/assistants.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
from typing import Annotated

from fastapi import APIRouter, Depends, Path
from fastapi import APIRouter, Depends, Path, HTTPException, Query
from sqlmodel import Session

from app.api.deps import get_db, get_current_user_org_project
from app.crud import (
fetch_assistant_from_openai,
sync_assistant,
create_assistant,
update_assistant,
get_assistant_by_id,
get_assistants_by_project,
delete_assistant,
)
from app.models import UserProjectOrg
from app.models import UserProjectOrg, AssistantCreate, AssistantUpdate, Assistant
from app.utils import APIResponse, get_openai_client

router = APIRouter(prefix="/assistant", tags=["Assistants"])


@router.post(
"/{assistant_id}/ingest",
response_model=APIResponse,
response_model=APIResponse[Assistant],
status_code=201,
)
def ingest_assistant_route(
Expand All @@ -41,3 +46,109 @@ def ingest_assistant_route(
)

return APIResponse.success_response(assistant)


@router.post("/", response_model=APIResponse[Assistant], status_code=201)
def create_assistant_route(
assistant_in: AssistantCreate,
session: Session = Depends(get_db),
current_user: UserProjectOrg = Depends(get_current_user_org_project),
):
"""
Create a new assistant in the local DB, checking that vector store IDs exist in OpenAI first.
"""
client = get_openai_client(
session, current_user.organization_id, current_user.project_id
)
assistant = create_assistant(
session=session,
openai_client=client,
assistant=assistant_in,
project_id=current_user.project_id,
organization_id=current_user.organization_id,
)
return APIResponse.success_response(assistant)


@router.patch("/{assistant_id}", response_model=APIResponse[Assistant])
def update_assistant_route(
assistant_id: Annotated[str, Path(description="Assistant ID to update")],
assistant_update: AssistantUpdate,
session: Session = Depends(get_db),
current_user: UserProjectOrg = Depends(get_current_user_org_project),
):
"""
Update an existing assistant with provided fields. Supports replacing, adding, or removing vector store IDs.
"""
client = get_openai_client(
session, current_user.organization_id, current_user.project_id
)
updated_assistant = update_assistant(
session=session,
assistant_id=assistant_id,
openai_client=client,
project_id=current_user.project_id,
assistant_update=assistant_update,
)
return APIResponse.success_response(updated_assistant)


@router.get(
"/{assistant_id}",
response_model=APIResponse[Assistant],
summary="Get a single assistant by its ID",
)
def get_assistant_route(
assistant_id: str = Path(..., description="The assistant_id to fetch"),
session: Session = Depends(get_db),
current_user: UserProjectOrg = Depends(get_current_user_org_project),
):
"""
Fetch a single assistant by its assistant_id.
"""
assistant = get_assistant_by_id(session, assistant_id, current_user.project_id)
if not assistant:
raise HTTPException(
status_code=404, detail=f"Assistant with ID {assistant_id} not found."
)
return APIResponse.success_response(assistant)


@router.get(
"/",
response_model=APIResponse[list[Assistant]],
summary="List all assistants in the current project",
)
def list_assistants_route(
session: Session = Depends(get_db),
current_user: UserProjectOrg = Depends(get_current_user_org_project),
skip: int = Query(0, ge=0, description="How many items to skip"),
limit: int = Query(100, ge=1, le=100, description="Maximum items to return"),
):
"""
List all assistants in the current project and organization.
"""

assistants = get_assistants_by_project(
session=session, project_id=current_user.project_id, skip=skip, limit=limit
)
return APIResponse.success_response(assistants)


@router.delete("/{assistant_id}", response_model=APIResponse)
def delete_assistant_route(
assistant_id: Annotated[str, Path(description="Assistant ID to delete")],
session: Session = Depends(get_db),
current_user: UserProjectOrg = Depends(get_current_user_org_project),
):
"""
Soft delete an assistant by marking it as deleted.
"""
delete_assistant(
session=session,
assistant_id=assistant_id,
project_id=current_user.project_id,
)
return APIResponse.success_response(
data={"message": "Assistant deleted successfully."}
)
2 changes: 1 addition & 1 deletion backend/app/api/routes/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ async def responses(
f"Processing response request for assistant_id={mask_string(request.assistant_id)}, project_id={project_id}, organization_id={organization_id}"
)

assistant = get_assistant_by_id(_session, request.assistant_id, organization_id)
assistant = get_assistant_by_id(_session, request.assistant_id, project_id)
if not assistant:
logger.warning(
f"Assistant not found: assistant_id={mask_string(request.assistant_id)}, project_id={project_id}, organization_id={organization_id}",
Expand Down
4 changes: 4 additions & 0 deletions backend/app/crud/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@
get_assistant_by_id,
fetch_assistant_from_openai,
sync_assistant,
create_assistant,
update_assistant,
get_assistants_by_project,
delete_assistant,
)
Loading