diff --git a/fern/openapi.json b/fern/openapi.json index 762bf34a..26a2ecd6 100644 --- a/fern/openapi.json +++ b/fern/openapi.json @@ -3802,6 +3802,80 @@ } } }, + "/v1/folders/{folder_id}/files/{file_id}": { + "get": { + "tags": ["folders"], + "summary": "Retrieve File", + "description": "Retrieve a file from a folder by ID.", + "operationId": "retrieve_file", + "parameters": [ + { + "name": "folder_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 43, + "maxLength": 43, + "pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", + "description": "The ID of the source in the format 'source-'", + "examples": ["source-123e4567-e89b-42d3-8456-426614174000"], + "title": "Folder Id" + }, + "description": "The ID of the source in the format 'source-'" + }, + { + "name": "file_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 41, + "maxLength": 41, + "pattern": "^file-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", + "description": "The ID of the file in the format 'file-'", + "examples": ["file-123e4567-e89b-42d3-8456-426614174000"], + "title": "File Id" + }, + "description": "The ID of the file in the format 'file-'" + }, + { + "name": "include_content", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Whether to include full file content", + "default": false, + "title": "Include Content" + }, + "description": "Whether to include full file content" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileMetadata" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, "/v1/folders/{folder_id}/{file_id}": { "delete": { "tags": ["folders"], diff --git a/letta/server/rest_api/routers/v1/folders.py b/letta/server/rest_api/routers/v1/folders.py index 6ab57b9e..2faec95d 100644 --- a/letta/server/rest_api/routers/v1/folders.py +++ b/letta/server/rest_api/routers/v1/folders.py @@ -470,6 +470,30 @@ async def list_files_for_folder( ) +@router.get("/{folder_id}/files/{file_id}", response_model=FileMetadata, operation_id="retrieve_file") +async def retrieve_file( + folder_id: FolderId, + file_id: FileId, + include_content: bool = Query(False, description="Whether to include full file content"), + server: "SyncServer" = Depends(get_letta_server), + headers: HeaderParams = Depends(get_headers), +): + """ + Retrieve a file from a folder by ID. + """ + actor = await server.user_manager.get_actor_or_default_async(actor_id=headers.actor_id) + + # NoResultFound will propagate and be handled as 404 by the global exception handler + file_metadata = await server.file_manager.get_file_by_id( + file_id=file_id, actor=actor, include_content=include_content, strip_directory_prefix=True + ) + + if file_metadata.source_id != folder_id: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"File with id={file_id} not found in folder {folder_id}") + + return file_metadata + + # @router.get("/{folder_id}/files/{file_id}", response_model=FileMetadata, operation_id="get_file_metadata") # async def get_file_metadata( # folder_id: str,