Skip to content

Commit ec92552

Browse files
authored
Merge branch 'main' into feature/response-api-conversation-memory
2 parents 7b642c1 + f1d651b commit ec92552

12 files changed

Lines changed: 998 additions & 26 deletions

File tree

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Add is_deleted column in assistant table
2+
3+
Revision ID: e8ee93526b37
4+
Revises: 4aa1f48c6321
5+
Create Date: 2025-07-21 12:40:03.791321
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "e8ee93526b37"
14+
down_revision = "4aa1f48c6321"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
op.add_column(
21+
"openai_assistant", sa.Column("is_deleted", sa.Boolean(), nullable=False)
22+
)
23+
op.add_column(
24+
"openai_assistant", sa.Column("deleted_at", sa.DateTime(), nullable=True)
25+
)
26+
27+
28+
def downgrade():
29+
op.drop_column("openai_assistant", "deleted_at")
30+
op.drop_column("openai_assistant", "is_deleted")

backend/app/api/routes/assistants.py

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
from typing import Annotated
22

3-
from fastapi import APIRouter, Depends, Path
3+
from fastapi import APIRouter, Depends, Path, HTTPException, Query
44
from sqlmodel import Session
55

66
from app.api.deps import get_db, get_current_user_org_project
77
from app.crud import (
88
fetch_assistant_from_openai,
99
sync_assistant,
10+
create_assistant,
11+
update_assistant,
12+
get_assistant_by_id,
13+
get_assistants_by_project,
14+
delete_assistant,
1015
)
11-
from app.models import UserProjectOrg
16+
from app.models import UserProjectOrg, AssistantCreate, AssistantUpdate, Assistant
1217
from app.utils import APIResponse, get_openai_client
1318

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

1621

1722
@router.post(
1823
"/{assistant_id}/ingest",
19-
response_model=APIResponse,
24+
response_model=APIResponse[Assistant],
2025
status_code=201,
2126
)
2227
def ingest_assistant_route(
@@ -41,3 +46,109 @@ def ingest_assistant_route(
4146
)
4247

4348
return APIResponse.success_response(assistant)
49+
50+
51+
@router.post("/", response_model=APIResponse[Assistant], status_code=201)
52+
def create_assistant_route(
53+
assistant_in: AssistantCreate,
54+
session: Session = Depends(get_db),
55+
current_user: UserProjectOrg = Depends(get_current_user_org_project),
56+
):
57+
"""
58+
Create a new assistant in the local DB, checking that vector store IDs exist in OpenAI first.
59+
"""
60+
client = get_openai_client(
61+
session, current_user.organization_id, current_user.project_id
62+
)
63+
assistant = create_assistant(
64+
session=session,
65+
openai_client=client,
66+
assistant=assistant_in,
67+
project_id=current_user.project_id,
68+
organization_id=current_user.organization_id,
69+
)
70+
return APIResponse.success_response(assistant)
71+
72+
73+
@router.patch("/{assistant_id}", response_model=APIResponse[Assistant])
74+
def update_assistant_route(
75+
assistant_id: Annotated[str, Path(description="Assistant ID to update")],
76+
assistant_update: AssistantUpdate,
77+
session: Session = Depends(get_db),
78+
current_user: UserProjectOrg = Depends(get_current_user_org_project),
79+
):
80+
"""
81+
Update an existing assistant with provided fields. Supports replacing, adding, or removing vector store IDs.
82+
"""
83+
client = get_openai_client(
84+
session, current_user.organization_id, current_user.project_id
85+
)
86+
updated_assistant = update_assistant(
87+
session=session,
88+
assistant_id=assistant_id,
89+
openai_client=client,
90+
project_id=current_user.project_id,
91+
assistant_update=assistant_update,
92+
)
93+
return APIResponse.success_response(updated_assistant)
94+
95+
96+
@router.get(
97+
"/{assistant_id}",
98+
response_model=APIResponse[Assistant],
99+
summary="Get a single assistant by its ID",
100+
)
101+
def get_assistant_route(
102+
assistant_id: str = Path(..., description="The assistant_id to fetch"),
103+
session: Session = Depends(get_db),
104+
current_user: UserProjectOrg = Depends(get_current_user_org_project),
105+
):
106+
"""
107+
Fetch a single assistant by its assistant_id.
108+
"""
109+
assistant = get_assistant_by_id(session, assistant_id, current_user.project_id)
110+
if not assistant:
111+
raise HTTPException(
112+
status_code=404, detail=f"Assistant with ID {assistant_id} not found."
113+
)
114+
return APIResponse.success_response(assistant)
115+
116+
117+
@router.get(
118+
"/",
119+
response_model=APIResponse[list[Assistant]],
120+
summary="List all assistants in the current project",
121+
)
122+
def list_assistants_route(
123+
session: Session = Depends(get_db),
124+
current_user: UserProjectOrg = Depends(get_current_user_org_project),
125+
skip: int = Query(0, ge=0, description="How many items to skip"),
126+
limit: int = Query(100, ge=1, le=100, description="Maximum items to return"),
127+
):
128+
"""
129+
List all assistants in the current project and organization.
130+
"""
131+
132+
assistants = get_assistants_by_project(
133+
session=session, project_id=current_user.project_id, skip=skip, limit=limit
134+
)
135+
return APIResponse.success_response(assistants)
136+
137+
138+
@router.delete("/{assistant_id}", response_model=APIResponse)
139+
def delete_assistant_route(
140+
assistant_id: Annotated[str, Path(description="Assistant ID to delete")],
141+
session: Session = Depends(get_db),
142+
current_user: UserProjectOrg = Depends(get_current_user_org_project),
143+
):
144+
"""
145+
Soft delete an assistant by marking it as deleted.
146+
"""
147+
delete_assistant(
148+
session=session,
149+
assistant_id=assistant_id,
150+
project_id=current_user.project_id,
151+
)
152+
return APIResponse.success_response(
153+
data={"message": "Assistant deleted successfully."}
154+
)

backend/app/api/routes/responses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ async def responses(
242242
f"Processing response request for assistant_id={mask_string(request.assistant_id)}, project_id={project_id}, organization_id={organization_id}"
243243
)
244244

245-
assistant = get_assistant_by_id(_session, request.assistant_id, organization_id)
245+
assistant = get_assistant_by_id(_session, request.assistant_id, project_id)
246246
if not assistant:
247247
logger.warning(
248248
f"Assistant not found: assistant_id={mask_string(request.assistant_id)}, project_id={project_id}, organization_id={organization_id}",

backend/app/crud/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,8 @@
5959
get_assistant_by_id,
6060
fetch_assistant_from_openai,
6161
sync_assistant,
62+
create_assistant,
63+
update_assistant,
64+
get_assistants_by_project,
65+
delete_assistant,
6266
)

0 commit comments

Comments
 (0)