diff --git a/docs/_static/llama-stack-spec.html b/docs/_static/llama-stack-spec.html index d88462909..f338aeea0 100644 --- a/docs/_static/llama-stack-spec.html +++ b/docs/_static/llama-stack-spec.html @@ -633,90 +633,6 @@ } } }, - "/v1/files": { - "get": { - "responses": { - "200": { - "description": "A ListBucketResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListBucketResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "List all buckets.", - "parameters": [ - { - "name": "bucket", - "in": "query", - "description": "Bucket name (valid chars: a-zA-Z0-9_-).", - "required": true, - "schema": { - "type": "string" - } - } - ] - }, - "post": { - "responses": { - "200": { - "description": "A FileUploadResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FileUploadResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "Create a new upload session for a file identified by a bucket and key.", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateUploadSessionRequest" - } - } - }, - "required": true - } - } - }, "/v1/agents/{agent_id}": { "get": { "responses": { @@ -901,101 +817,6 @@ ] } }, - "/v1/files/{bucket}/{key}": { - "get": { - "responses": { - "200": { - "description": "A FileResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FileResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "Get a file info identified by a bucket and key.", - "parameters": [ - { - "name": "bucket", - "in": "path", - "description": "Bucket name (valid chars: a-zA-Z0-9_-).", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "key", - "in": "path", - "description": "Key under which the file is stored (valid chars: a-zA-Z0-9_-/.).", - "required": true, - "schema": { - "type": "string" - } - } - ] - }, - "delete": { - "responses": { - "200": { - "description": "OK" - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "Delete a file identified by a bucket and key.", - "parameters": [ - { - "name": "bucket", - "in": "path", - "description": "Bucket name (valid chars: a-zA-Z0-9_-).", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "key", - "in": "path", - "description": "Key under which the file is stored (valid chars: a-zA-Z0-9_-/.).", - "required": true, - "schema": { - "type": "string" - } - } - ] - } - }, "/v1/inference/embeddings": { "post": { "responses": { @@ -1979,108 +1800,6 @@ "parameters": [] } }, - "/v1/files/session:{upload_id}": { - "get": { - "responses": { - "200": { - "description": "A FileUploadResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FileUploadResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "Returns information about an existsing upload session.", - "parameters": [ - { - "name": "upload_id", - "in": "path", - "description": "ID of the upload session.", - "required": true, - "schema": { - "type": "string" - } - } - ] - }, - "post": { - "responses": { - "200": { - "description": "A FileResponse or None if the upload is not complete.", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "$ref": "#/components/schemas/FileResponse" - }, - { - "type": "null" - } - ] - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "Upload file content to an existing upload session. On the server, request body will have the raw bytes that are uploaded.", - "parameters": [ - { - "name": "upload_id", - "in": "path", - "description": "ID of the upload session.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - }, - "required": true - } - } - }, "/v1/vector-dbs/{vector_db_id}": { "get": { "responses": { @@ -2877,49 +2596,6 @@ } } }, - "/v1/files/{bucket}": { - "get": { - "responses": { - "200": { - "description": "A ListFileResponse.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListFileResponse" - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest400" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests429" - }, - "500": { - "$ref": "#/components/responses/InternalServerError500" - }, - "default": { - "$ref": "#/components/responses/DefaultError" - } - }, - "tags": [ - "Files" - ], - "description": "List all files in a bucket.", - "parameters": [ - { - "name": "bucket", - "in": "path", - "description": "Bucket name (valid chars: a-zA-Z0-9_-).", - "required": true, - "schema": { - "type": "string" - } - } - ] - } - }, "/v1/models": { "get": { "responses": { @@ -3607,6 +3283,90 @@ } } }, + "/v1/openai/v1/files/{file_id}": { + "get": { + "responses": { + "200": { + "description": "An OpenAIFileObject containing file information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAIFileObject" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest400" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests429" + }, + "500": { + "$ref": "#/components/responses/InternalServerError500" + }, + "default": { + "$ref": "#/components/responses/DefaultError" + } + }, + "tags": [ + "Files" + ], + "description": "Returns information about a specific file.", + "parameters": [ + { + "name": "file_id", + "in": "path", + "description": "The ID of the file to use for this request.", + "required": true, + "schema": { + "type": "string" + } + } + ] + }, + "delete": { + "responses": { + "200": { + "description": "An OpenAIFileDeleteResponse indicating successful deletion.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAIFileDeleteResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest400" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests429" + }, + "500": { + "$ref": "#/components/responses/InternalServerError500" + }, + "default": { + "$ref": "#/components/responses/DefaultError" + } + }, + "tags": [ + "Files" + ], + "description": "Delete a file.", + "parameters": [ + { + "name": "file_id", + "in": "path", + "description": "The ID of the file to use for this request.", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, "/v1/openai/v1/embeddings": { "post": { "responses": { @@ -3650,6 +3410,130 @@ } } }, + "/v1/openai/v1/files": { + "get": { + "responses": { + "200": { + "description": "An ListOpenAIFileResponse containing the list of files.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOpenAIFileResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest400" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests429" + }, + "500": { + "$ref": "#/components/responses/InternalServerError500" + }, + "default": { + "$ref": "#/components/responses/DefaultError" + } + }, + "tags": [ + "Files" + ], + "description": "Returns a list of files that belong to the user's organization.", + "parameters": [ + { + "name": "after", + "in": "query", + "description": "A cursor for use in pagination. `after` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include after=obj_foo in order to fetch the next page of the list.", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "A limit on the number of objects to be returned. Limit can range between 1 and 10,000, and the default is 10,000.", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "order", + "in": "query", + "description": "Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and `desc` for descending order.", + "required": false, + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + { + "name": "purpose", + "in": "query", + "description": "Only return files with the given purpose.", + "required": false, + "schema": { + "$ref": "#/components/schemas/OpenAIFilePurpose" + } + } + ] + }, + "post": { + "responses": { + "200": { + "description": "An OpenAIFileObject representing the uploaded file.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpenAIFileObject" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest400" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests429" + }, + "500": { + "$ref": "#/components/responses/InternalServerError500" + }, + "default": { + "$ref": "#/components/responses/DefaultError" + } + }, + "tags": [ + "Files" + ], + "description": "Upload a file that can be used across various endpoints.\nThe file upload should be a multipart form request with:\n- file: The File object (not file name) to be uploaded.\n- purpose: The intended purpose of the uploaded file.", + "parameters": [], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "purpose": { + "$ref": "#/components/schemas/OpenAIFilePurpose" + } + }, + "required": [ + "file", + "purpose" + ] + } + } + }, + "required": true + } + } + }, "/v1/openai/v1/models": { "get": { "responses": { @@ -3683,6 +3567,49 @@ "parameters": [] } }, + "/v1/openai/v1/files/{file_id}/content": { + "get": { + "responses": { + "200": { + "description": "The raw file content as a binary response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Response" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest400" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests429" + }, + "500": { + "$ref": "#/components/responses/InternalServerError500" + }, + "default": { + "$ref": "#/components/responses/DefaultError" + } + }, + "tags": [ + "Files" + ], + "description": "Returns the contents of the specified file.", + "parameters": [ + { + "name": "file_id", + "in": "path", + "description": "The ID of the file to use for this request.", + "required": true, + "schema": { + "type": "string" + } + } + ] + } + }, "/v1/post-training/preference-optimize": { "post": { "responses": { @@ -7672,65 +7599,6 @@ ], "title": "OpenAIResponseObjectStreamResponseOutputTextDelta" }, - "CreateUploadSessionRequest": { - "type": "object", - "properties": { - "bucket": { - "type": "string", - "description": "Bucket under which the file is stored (valid chars: a-zA-Z0-9_-)." - }, - "key": { - "type": "string", - "description": "Key under which the file is stored (valid chars: a-zA-Z0-9_-/.)." - }, - "mime_type": { - "type": "string", - "description": "MIME type of the file." - }, - "size": { - "type": "integer", - "description": "File size in bytes." - } - }, - "additionalProperties": false, - "required": [ - "bucket", - "key", - "mime_type", - "size" - ], - "title": "CreateUploadSessionRequest" - }, - "FileUploadResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "ID of the upload session" - }, - "url": { - "type": "string", - "description": "Upload URL for the file or file parts" - }, - "offset": { - "type": "integer", - "description": "Upload content offset" - }, - "size": { - "type": "integer", - "description": "Upload content size" - } - }, - "additionalProperties": false, - "required": [ - "id", - "url", - "offset", - "size" - ], - "title": "FileUploadResponse", - "description": "Response after initiating a file upload session." - }, "EmbeddingsRequest": { "type": "object", "properties": { @@ -8994,46 +8862,6 @@ "title": "URIDataSource", "description": "A dataset that can be obtained from a URI." }, - "FileResponse": { - "type": "object", - "properties": { - "bucket": { - "type": "string", - "description": "Bucket under which the file is stored (valid chars: a-zA-Z0-9_-)" - }, - "key": { - "type": "string", - "description": "Key under which the file is stored (valid chars: a-zA-Z0-9_-/.)" - }, - "mime_type": { - "type": "string", - "description": "MIME type of the file" - }, - "url": { - "type": "string", - "description": "Upload URL for the file contents" - }, - "bytes": { - "type": "integer", - "description": "Size of the file in bytes" - }, - "created_at": { - "type": "integer", - "description": "Timestamp of when the file was created" - } - }, - "additionalProperties": false, - "required": [ - "bucket", - "key", - "mime_type", - "url", - "bytes", - "created_at" - ], - "title": "FileResponse", - "description": "Response representing a file entry." - }, "Model": { "type": "object", "properties": { @@ -10347,37 +10175,6 @@ ], "title": "Job" }, - "BucketResponse": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - }, - "additionalProperties": false, - "required": [ - "name" - ], - "title": "BucketResponse" - }, - "ListBucketResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BucketResponse" - }, - "description": "List of FileResponse entries" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "ListBucketResponse", - "description": "Response representing a list of file entries." - }, "ListBenchmarksResponse": { "type": "object", "properties": { @@ -10495,24 +10292,6 @@ ], "title": "ListDatasetsResponse" }, - "ListFileResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileResponse" - }, - "description": "List of FileResponse entries" - } - }, - "additionalProperties": false, - "required": [ - "data" - ], - "title": "ListFileResponse", - "description": "Response representing a list of file entries." - }, "ListModelsResponse": { "type": "object", "properties": { @@ -11820,6 +11599,33 @@ "title": "OpenAICompletionChoice", "description": "A choice from an OpenAI-compatible completion response." }, + "OpenAIFileDeleteResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The file identifier that was deleted" + }, + "object": { + "type": "string", + "const": "file", + "default": "file", + "description": "The object type, which is always \"file\"" + }, + "deleted": { + "type": "boolean", + "description": "Whether the file was successfully deleted" + } + }, + "additionalProperties": false, + "required": [ + "id", + "object", + "deleted" + ], + "title": "OpenAIFileDeleteResponse", + "description": "Response for deleting a file in OpenAI Files API." + }, "OpenaiEmbeddingsRequest": { "type": "object", "properties": { @@ -11953,6 +11759,101 @@ "title": "OpenAIEmbeddingsResponse", "description": "Response from an OpenAI-compatible embeddings request." }, + "OpenAIFilePurpose": { + "type": "string", + "enum": [ + "assistants" + ], + "title": "OpenAIFilePurpose", + "description": "Valid purpose values for OpenAI Files API." + }, + "ListOpenAIFileResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OpenAIFileObject" + }, + "description": "List of file objects" + }, + "has_more": { + "type": "boolean" + }, + "first_id": { + "type": "string" + }, + "last_id": { + "type": "string" + }, + "object": { + "type": "string", + "const": "list", + "default": "list", + "description": "The object type, which is always \"list\"" + } + }, + "additionalProperties": false, + "required": [ + "data", + "has_more", + "first_id", + "last_id", + "object" + ], + "title": "ListOpenAIFileResponse", + "description": "Response for listing files in OpenAI Files API." + }, + "OpenAIFileObject": { + "type": "object", + "properties": { + "object": { + "type": "string", + "const": "file", + "default": "file", + "description": "The object type, which is always \"file\"" + }, + "id": { + "type": "string", + "description": "The file identifier, which can be referenced in the API endpoints" + }, + "bytes": { + "type": "integer", + "description": "The size of the file, in bytes" + }, + "created_at": { + "type": "integer", + "description": "The Unix timestamp (in seconds) for when the file was created" + }, + "expires_at": { + "type": "integer", + "description": "The Unix timestamp (in seconds) for when the file expires" + }, + "filename": { + "type": "string", + "description": "The name of the file" + }, + "purpose": { + "type": "string", + "enum": [ + "assistants" + ], + "description": "The intended purpose of the file" + } + }, + "additionalProperties": false, + "required": [ + "object", + "id", + "bytes", + "created_at", + "expires_at", + "filename", + "purpose" + ], + "title": "OpenAIFileObject", + "description": "OpenAI File object as defined in the OpenAI Files API." + }, "OpenAIModel": { "type": "object", "properties": { @@ -11997,6 +11898,10 @@ ], "title": "OpenAIListModelsResponse" }, + "Response": { + "type": "object", + "title": "Response" + }, "DPOAlignmentConfig": { "type": "object", "properties": { diff --git a/docs/_static/llama-stack-spec.yaml b/docs/_static/llama-stack-spec.yaml index 7638c3cbd..a87c6a80b 100644 --- a/docs/_static/llama-stack-spec.yaml +++ b/docs/_static/llama-stack-spec.yaml @@ -427,64 +427,6 @@ paths: schema: $ref: '#/components/schemas/CreateOpenaiResponseRequest' required: true - /v1/files: - get: - responses: - '200': - description: A ListBucketResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/ListBucketResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: List all buckets. - parameters: - - name: bucket - in: query - description: 'Bucket name (valid chars: a-zA-Z0-9_-).' - required: true - schema: - type: string - post: - responses: - '200': - description: A FileUploadResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/FileUploadResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: >- - Create a new upload session for a file identified by a bucket and key. - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/CreateUploadSessionRequest' - required: true /v1/agents/{agent_id}: get: responses: @@ -616,75 +558,6 @@ paths: required: true schema: type: string - /v1/files/{bucket}/{key}: - get: - responses: - '200': - description: A FileResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/FileResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: >- - Get a file info identified by a bucket and key. - parameters: - - name: bucket - in: path - description: 'Bucket name (valid chars: a-zA-Z0-9_-).' - required: true - schema: - type: string - - name: key - in: path - description: >- - Key under which the file is stored (valid chars: a-zA-Z0-9_-/.). - required: true - schema: - type: string - delete: - responses: - '200': - description: OK - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: >- - Delete a file identified by a bucket and key. - parameters: - - name: bucket - in: path - description: 'Bucket name (valid chars: a-zA-Z0-9_-).' - required: true - schema: - type: string - - name: key - in: path - description: >- - Key under which the file is stored (valid chars: a-zA-Z0-9_-/.). - required: true - schema: - type: string /v1/inference/embeddings: post: responses: @@ -1363,76 +1236,6 @@ paths: - PostTraining (Coming Soon) description: Get all training jobs. parameters: [] - /v1/files/session:{upload_id}: - get: - responses: - '200': - description: A FileUploadResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/FileUploadResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: >- - Returns information about an existsing upload session. - parameters: - - name: upload_id - in: path - description: ID of the upload session. - required: true - schema: - type: string - post: - responses: - '200': - description: >- - A FileResponse or None if the upload is not complete. - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/FileResponse' - - type: 'null' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: >- - Upload file content to an existing upload session. On the server, request - body will have the raw bytes that are uploaded. - parameters: - - name: upload_id - in: path - description: ID of the upload session. - required: true - schema: - type: string - requestBody: - content: - application/octet-stream: - schema: - type: string - format: binary - required: true /v1/vector-dbs/{vector_db_id}: get: responses: @@ -2005,35 +1808,6 @@ paths: schema: $ref: '#/components/schemas/RegisterDatasetRequest' required: true - /v1/files/{bucket}: - get: - responses: - '200': - description: A ListFileResponse. - content: - application/json: - schema: - $ref: '#/components/schemas/ListFileResponse' - '400': - $ref: '#/components/responses/BadRequest400' - '429': - $ref: >- - #/components/responses/TooManyRequests429 - '500': - $ref: >- - #/components/responses/InternalServerError500 - default: - $ref: '#/components/responses/DefaultError' - tags: - - Files - description: List all files in a bucket. - parameters: - - name: bucket - in: path - description: 'Bucket name (valid chars: a-zA-Z0-9_-).' - required: true - schema: - type: string /v1/models: get: responses: @@ -2520,6 +2294,68 @@ paths: schema: $ref: '#/components/schemas/OpenaiCompletionRequest' required: true + /v1/openai/v1/files/{file_id}: + get: + responses: + '200': + description: >- + An OpenAIFileObject containing file information. + content: + application/json: + schema: + $ref: '#/components/schemas/OpenAIFileObject' + '400': + $ref: '#/components/responses/BadRequest400' + '429': + $ref: >- + #/components/responses/TooManyRequests429 + '500': + $ref: >- + #/components/responses/InternalServerError500 + default: + $ref: '#/components/responses/DefaultError' + tags: + - Files + description: >- + Returns information about a specific file. + parameters: + - name: file_id + in: path + description: >- + The ID of the file to use for this request. + required: true + schema: + type: string + delete: + responses: + '200': + description: >- + An OpenAIFileDeleteResponse indicating successful deletion. + content: + application/json: + schema: + $ref: '#/components/schemas/OpenAIFileDeleteResponse' + '400': + $ref: '#/components/responses/BadRequest400' + '429': + $ref: >- + #/components/responses/TooManyRequests429 + '500': + $ref: >- + #/components/responses/InternalServerError500 + default: + $ref: '#/components/responses/DefaultError' + tags: + - Files + description: Delete a file. + parameters: + - name: file_id + in: path + description: >- + The ID of the file to use for this request. + required: true + schema: + type: string /v1/openai/v1/embeddings: post: responses: @@ -2552,6 +2388,109 @@ paths: schema: $ref: '#/components/schemas/OpenaiEmbeddingsRequest' required: true + /v1/openai/v1/files: + get: + responses: + '200': + description: >- + An ListOpenAIFileResponse containing the list of files. + content: + application/json: + schema: + $ref: '#/components/schemas/ListOpenAIFileResponse' + '400': + $ref: '#/components/responses/BadRequest400' + '429': + $ref: >- + #/components/responses/TooManyRequests429 + '500': + $ref: >- + #/components/responses/InternalServerError500 + default: + $ref: '#/components/responses/DefaultError' + tags: + - Files + description: >- + Returns a list of files that belong to the user's organization. + parameters: + - name: after + in: query + description: >- + A cursor for use in pagination. `after` is an object ID that defines your + place in the list. For instance, if you make a list request and receive + 100 objects, ending with obj_foo, your subsequent call can include after=obj_foo + in order to fetch the next page of the list. + required: false + schema: + type: string + - name: limit + in: query + description: >- + A limit on the number of objects to be returned. Limit can range between + 1 and 10,000, and the default is 10,000. + required: false + schema: + type: integer + - name: order + in: query + description: >- + Sort order by the `created_at` timestamp of the objects. `asc` for ascending + order and `desc` for descending order. + required: false + schema: + $ref: '#/components/schemas/Order' + - name: purpose + in: query + description: >- + Only return files with the given purpose. + required: false + schema: + $ref: '#/components/schemas/OpenAIFilePurpose' + post: + responses: + '200': + description: >- + An OpenAIFileObject representing the uploaded file. + content: + application/json: + schema: + $ref: '#/components/schemas/OpenAIFileObject' + '400': + $ref: '#/components/responses/BadRequest400' + '429': + $ref: >- + #/components/responses/TooManyRequests429 + '500': + $ref: >- + #/components/responses/InternalServerError500 + default: + $ref: '#/components/responses/DefaultError' + tags: + - Files + description: >- + Upload a file that can be used across various endpoints. + + The file upload should be a multipart form request with: + + - file: The File object (not file name) to be uploaded. + + - purpose: The intended purpose of the uploaded file. + parameters: [] + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + purpose: + $ref: '#/components/schemas/OpenAIFilePurpose' + required: + - file + - purpose + required: true /v1/openai/v1/models: get: responses: @@ -2575,6 +2514,38 @@ paths: - Models description: List models using the OpenAI API. parameters: [] + /v1/openai/v1/files/{file_id}/content: + get: + responses: + '200': + description: >- + The raw file content as a binary response. + content: + application/json: + schema: + $ref: '#/components/schemas/Response' + '400': + $ref: '#/components/responses/BadRequest400' + '429': + $ref: >- + #/components/responses/TooManyRequests429 + '500': + $ref: >- + #/components/responses/InternalServerError500 + default: + $ref: '#/components/responses/DefaultError' + tags: + - Files + description: >- + Returns the contents of the specified file. + parameters: + - name: file_id + in: path + description: >- + The ID of the file to use for this request. + required: true + schema: + type: string /v1/post-training/preference-optimize: post: responses: @@ -5391,54 +5362,6 @@ components: - type title: >- OpenAIResponseObjectStreamResponseOutputTextDelta - CreateUploadSessionRequest: - type: object - properties: - bucket: - type: string - description: >- - Bucket under which the file is stored (valid chars: a-zA-Z0-9_-). - key: - type: string - description: >- - Key under which the file is stored (valid chars: a-zA-Z0-9_-/.). - mime_type: - type: string - description: MIME type of the file. - size: - type: integer - description: File size in bytes. - additionalProperties: false - required: - - bucket - - key - - mime_type - - size - title: CreateUploadSessionRequest - FileUploadResponse: - type: object - properties: - id: - type: string - description: ID of the upload session - url: - type: string - description: Upload URL for the file or file parts - offset: - type: integer - description: Upload content offset - size: - type: integer - description: Upload content size - additionalProperties: false - required: - - id - - url - - offset - - size - title: FileUploadResponse - description: >- - Response after initiating a file upload session. EmbeddingsRequest: type: object properties: @@ -6343,39 +6266,6 @@ components: title: URIDataSource description: >- A dataset that can be obtained from a URI. - FileResponse: - type: object - properties: - bucket: - type: string - description: >- - Bucket under which the file is stored (valid chars: a-zA-Z0-9_-) - key: - type: string - description: >- - Key under which the file is stored (valid chars: a-zA-Z0-9_-/.) - mime_type: - type: string - description: MIME type of the file - url: - type: string - description: Upload URL for the file contents - bytes: - type: integer - description: Size of the file in bytes - created_at: - type: integer - description: Timestamp of when the file was created - additionalProperties: false - required: - - bucket - - key - - mime_type - - url - - bytes - - created_at - title: FileResponse - description: Response representing a file entry. Model: type: object properties: @@ -7227,29 +7117,6 @@ components: - job_id - status title: Job - BucketResponse: - type: object - properties: - name: - type: string - additionalProperties: false - required: - - name - title: BucketResponse - ListBucketResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/BucketResponse' - description: List of FileResponse entries - additionalProperties: false - required: - - data - title: ListBucketResponse - description: >- - Response representing a list of file entries. ListBenchmarksResponse: type: object properties: @@ -7339,20 +7206,6 @@ components: required: - data title: ListDatasetsResponse - ListFileResponse: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/FileResponse' - description: List of FileResponse entries - additionalProperties: false - required: - - data - title: ListFileResponse - description: >- - Response representing a list of file entries. ListModelsResponse: type: object properties: @@ -8229,6 +8082,29 @@ components: title: OpenAICompletionChoice description: >- A choice from an OpenAI-compatible completion response. + OpenAIFileDeleteResponse: + type: object + properties: + id: + type: string + description: The file identifier that was deleted + object: + type: string + const: file + default: file + description: The object type, which is always "file" + deleted: + type: boolean + description: >- + Whether the file was successfully deleted + additionalProperties: false + required: + - id + - object + - deleted + title: OpenAIFileDeleteResponse + description: >- + Response for deleting a file in OpenAI Files API. OpenaiEmbeddingsRequest: type: object properties: @@ -8341,6 +8217,85 @@ components: title: OpenAIEmbeddingsResponse description: >- Response from an OpenAI-compatible embeddings request. + OpenAIFilePurpose: + type: string + enum: + - assistants + title: OpenAIFilePurpose + description: >- + Valid purpose values for OpenAI Files API. + ListOpenAIFileResponse: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/OpenAIFileObject' + description: List of file objects + has_more: + type: boolean + first_id: + type: string + last_id: + type: string + object: + type: string + const: list + default: list + description: The object type, which is always "list" + additionalProperties: false + required: + - data + - has_more + - first_id + - last_id + - object + title: ListOpenAIFileResponse + description: >- + Response for listing files in OpenAI Files API. + OpenAIFileObject: + type: object + properties: + object: + type: string + const: file + default: file + description: The object type, which is always "file" + id: + type: string + description: >- + The file identifier, which can be referenced in the API endpoints + bytes: + type: integer + description: The size of the file, in bytes + created_at: + type: integer + description: >- + The Unix timestamp (in seconds) for when the file was created + expires_at: + type: integer + description: >- + The Unix timestamp (in seconds) for when the file expires + filename: + type: string + description: The name of the file + purpose: + type: string + enum: + - assistants + description: The intended purpose of the file + additionalProperties: false + required: + - object + - id + - bytes + - created_at + - expires_at + - filename + - purpose + title: OpenAIFileObject + description: >- + OpenAI File object as defined in the OpenAI Files API. OpenAIModel: type: object properties: @@ -8373,6 +8328,9 @@ components: required: - data title: OpenAIListModelsResponse + Response: + type: object + title: Response DPOAlignmentConfig: type: object properties: diff --git a/docs/openapi_generator/pyopenapi/generator.py b/docs/openapi_generator/pyopenapi/generator.py index 5b7a685c1..e2c73e33c 100644 --- a/docs/openapi_generator/pyopenapi/generator.py +++ b/docs/openapi_generator/pyopenapi/generator.py @@ -30,6 +30,9 @@ from llama_stack.strong_typing.schema import ( Schema, SchemaOptions, ) +from typing import get_origin, get_args +from typing import Annotated +from fastapi import UploadFile from llama_stack.strong_typing.serialization import json_dump_string, object_to_json from .operations import ( @@ -618,6 +621,45 @@ class Generator: }, required=True, ) + # data passed in request body as multipart/form-data + elif op.multipart_params: + builder = ContentBuilder(self.schema_builder) + + # Create schema properties for multipart form fields + properties = {} + required_fields = [] + + for name, param_type in op.multipart_params: + if get_origin(param_type) is Annotated: + base_type = get_args(param_type)[0] + else: + base_type = param_type + if base_type is UploadFile: + # File upload + properties[name] = { + "type": "string", + "format": "binary" + } + else: + # Form field + properties[name] = self.schema_builder.classdef_to_ref(base_type) + + required_fields.append(name) + + multipart_schema = { + "type": "object", + "properties": properties, + "required": required_fields + } + + requestBody = RequestBody( + content={ + "multipart/form-data": { + "schema": multipart_schema + } + }, + required=True, + ) # data passed in payload as JSON and mapped to request parameters elif op.request_params: builder = ContentBuilder(self.schema_builder) diff --git a/docs/openapi_generator/pyopenapi/operations.py b/docs/openapi_generator/pyopenapi/operations.py index 5c78b9124..045e33848 100644 --- a/docs/openapi_generator/pyopenapi/operations.py +++ b/docs/openapi_generator/pyopenapi/operations.py @@ -17,6 +17,12 @@ from termcolor import colored from llama_stack.strong_typing.inspection import get_signature +from typing import get_origin, get_args + +from fastapi import UploadFile +from fastapi.params import File, Form +from typing import Annotated + def split_prefix( s: str, sep: str, prefix: Union[str, Iterable[str]] @@ -82,6 +88,7 @@ class EndpointOperation: :param path_params: Parameters of the operation signature that are passed in the path component of the URL string. :param query_params: Parameters of the operation signature that are passed in the query string as `key=value` pairs. :param request_params: The parameter that corresponds to the data transmitted in the request body. + :param multipart_params: Parameters that indicate multipart/form-data request body. :param event_type: The Python type of the data that is transmitted out-of-band (e.g. via websockets) while the operation is in progress. :param response_type: The Python type of the data that is transmitted in the response body. :param http_method: The HTTP method used to invoke the endpoint such as POST, GET or PUT. @@ -98,6 +105,7 @@ class EndpointOperation: path_params: List[OperationParameter] query_params: List[OperationParameter] request_params: Optional[OperationParameter] + multipart_params: List[OperationParameter] event_type: Optional[type] response_type: type http_method: HTTPMethod @@ -252,6 +260,7 @@ def get_endpoint_operations( path_params = [] query_params = [] request_params = [] + multipart_params = [] for param_name, parameter in signature.parameters.items(): param_type = _get_annotation_type(parameter.annotation, func_ref) @@ -266,6 +275,8 @@ def get_endpoint_operations( f"parameter '{param_name}' in function '{func_name}' has no type annotation" ) + is_multipart = _is_multipart_param(param_type) + if prefix in ["get", "delete"]: if route_params is not None and param_name in route_params: path_params.append((param_name, param_type)) @@ -274,6 +285,8 @@ def get_endpoint_operations( else: if route_params is not None and param_name in route_params: path_params.append((param_name, param_type)) + elif is_multipart: + multipart_params.append((param_name, param_type)) else: request_params.append((param_name, param_type)) @@ -333,6 +346,7 @@ def get_endpoint_operations( path_params=path_params, query_params=query_params, request_params=request_params, + multipart_params=multipart_params, event_type=event_type, response_type=response_type, http_method=http_method, @@ -377,3 +391,34 @@ def get_endpoint_events(endpoint: type) -> Dict[str, type]: results[param_type.__name__] = param_type return results + + +def _is_multipart_param(param_type: type) -> bool: + """ + Check if a parameter type indicates multipart form data. + + Returns True if the type is: + - UploadFile + - Annotated[UploadFile, File()] + - Annotated[str, Form()] + - Annotated[Any, File()] + - Annotated[Any, Form()] + """ + if param_type is UploadFile: + return True + + # Check for Annotated types + origin = get_origin(param_type) + if origin is None: + return False + + if origin is Annotated: + args = get_args(param_type) + if len(args) < 2: + return False + + # Check the annotations for File() or Form() + for annotation in args[1:]: + if isinstance(annotation, (File, Form)): + return True + return False diff --git a/docs/openapi_generator/pyopenapi/utility.py b/docs/openapi_generator/pyopenapi/utility.py index 12a69050c..7e54c6fbb 100644 --- a/docs/openapi_generator/pyopenapi/utility.py +++ b/docs/openapi_generator/pyopenapi/utility.py @@ -153,6 +153,12 @@ def _validate_api_delete_method_returns_none(method) -> str | None: return "has no return type annotation" return_type = hints['return'] + + # Allow OpenAI endpoints to return response objects since they follow OpenAI specification + method_name = getattr(method, '__name__', '') + if method_name.startswith('openai_'): + return None + if return_type is not None and return_type is not type(None): return "does not return None where None is mandatory" diff --git a/llama_stack/apis/files/files.py b/llama_stack/apis/files/files.py index 1d762a68a..4dfeed448 100644 --- a/llama_stack/apis/files/files.py +++ b/llama_stack/apis/files/files.py @@ -4,179 +4,158 @@ # This source code is licensed under the terms described in the LICENSE file in # the root directory of this source tree. -from typing import Protocol, runtime_checkable +from enum import Enum +from typing import Annotated, Literal, Protocol, runtime_checkable +from fastapi import File, Form, Response, UploadFile from pydantic import BaseModel +from llama_stack.apis.common.responses import Order from llama_stack.providers.utils.telemetry.trace_protocol import trace_protocol from llama_stack.schema_utils import json_schema_type, webmethod -@json_schema_type -class FileUploadResponse(BaseModel): +# OpenAI Files API Models +class OpenAIFilePurpose(str, Enum): + """ + Valid purpose values for OpenAI Files API. """ - Response after initiating a file upload session. - :param id: ID of the upload session - :param url: Upload URL for the file or file parts - :param offset: Upload content offset - :param size: Upload content size + ASSISTANTS = "assistants" + # TODO: Add other purposes as needed + + +@json_schema_type +class OpenAIFileObject(BaseModel): + """ + OpenAI File object as defined in the OpenAI Files API. + + :param object: The object type, which is always "file" + :param id: The file identifier, which can be referenced in the API endpoints + :param bytes: The size of the file, in bytes + :param created_at: The Unix timestamp (in seconds) for when the file was created + :param expires_at: The Unix timestamp (in seconds) for when the file expires + :param filename: The name of the file + :param purpose: The intended purpose of the file + """ + + object: Literal["file"] = "file" + id: str + bytes: int + created_at: int + expires_at: int + filename: str + purpose: OpenAIFilePurpose + + +@json_schema_type +class ListOpenAIFileResponse(BaseModel): + """ + Response for listing files in OpenAI Files API. + + :param data: List of file objects + :param object: The object type, which is always "list" + """ + + data: list[OpenAIFileObject] + has_more: bool + first_id: str + last_id: str + object: Literal["list"] = "list" + + +@json_schema_type +class OpenAIFileDeleteResponse(BaseModel): + """ + Response for deleting a file in OpenAI Files API. + + :param id: The file identifier that was deleted + :param object: The object type, which is always "file" + :param deleted: Whether the file was successfully deleted """ id: str - url: str - offset: int - size: int - - -@json_schema_type -class BucketResponse(BaseModel): - name: str - - -@json_schema_type -class ListBucketResponse(BaseModel): - """ - Response representing a list of file entries. - - :param data: List of FileResponse entries - """ - - data: list[BucketResponse] - - -@json_schema_type -class FileResponse(BaseModel): - """ - Response representing a file entry. - - :param bucket: Bucket under which the file is stored (valid chars: a-zA-Z0-9_-) - :param key: Key under which the file is stored (valid chars: a-zA-Z0-9_-/.) - :param mime_type: MIME type of the file - :param url: Upload URL for the file contents - :param bytes: Size of the file in bytes - :param created_at: Timestamp of when the file was created - """ - - bucket: str - key: str - mime_type: str - url: str - bytes: int - created_at: int - - -@json_schema_type -class ListFileResponse(BaseModel): - """ - Response representing a list of file entries. - - :param data: List of FileResponse entries - """ - - data: list[FileResponse] + object: Literal["file"] = "file" + deleted: bool @runtime_checkable @trace_protocol class Files(Protocol): - @webmethod(route="/files", method="POST") - async def create_upload_session( + # OpenAI Files API Endpoints + @webmethod(route="/openai/v1/files", method="POST") + async def openai_upload_file( self, - bucket: str, - key: str, - mime_type: str, - size: int, - ) -> FileUploadResponse: + file: Annotated[UploadFile, File()], + purpose: Annotated[OpenAIFilePurpose, Form()], + ) -> OpenAIFileObject: """ - Create a new upload session for a file identified by a bucket and key. + Upload a file that can be used across various endpoints. - :param bucket: Bucket under which the file is stored (valid chars: a-zA-Z0-9_-). - :param key: Key under which the file is stored (valid chars: a-zA-Z0-9_-/.). - :param mime_type: MIME type of the file. - :param size: File size in bytes. - :returns: A FileUploadResponse. + The file upload should be a multipart form request with: + - file: The File object (not file name) to be uploaded. + - purpose: The intended purpose of the uploaded file. + + :param file: The uploaded file object containing content and metadata (filename, content_type, etc.). + :param purpose: The intended purpose of the uploaded file (e.g., "assistants", "fine-tune"). + :returns: An OpenAIFileObject representing the uploaded file. """ ... - @webmethod(route="/files/session:{upload_id}", method="POST", raw_bytes_request_body=True) - async def upload_content_to_session( + @webmethod(route="/openai/v1/files", method="GET") + async def openai_list_files( self, - upload_id: str, - ) -> FileResponse | None: + after: str | None = None, + limit: int | None = 10000, + order: Order | None = Order.desc, + purpose: OpenAIFilePurpose | None = None, + ) -> ListOpenAIFileResponse: """ - Upload file content to an existing upload session. - On the server, request body will have the raw bytes that are uploaded. + Returns a list of files that belong to the user's organization. - :param upload_id: ID of the upload session. - :returns: A FileResponse or None if the upload is not complete. + :param after: A cursor for use in pagination. `after` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include after=obj_foo in order to fetch the next page of the list. + :param limit: A limit on the number of objects to be returned. Limit can range between 1 and 10,000, and the default is 10,000. + :param order: Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and `desc` for descending order. + :param purpose: Only return files with the given purpose. + :returns: An ListOpenAIFileResponse containing the list of files. """ ... - @webmethod(route="/files/session:{upload_id}", method="GET") - async def get_upload_session_info( + @webmethod(route="/openai/v1/files/{file_id}", method="GET") + async def openai_retrieve_file( self, - upload_id: str, - ) -> FileUploadResponse: + file_id: str, + ) -> OpenAIFileObject: """ - Returns information about an existsing upload session. + Returns information about a specific file. - :param upload_id: ID of the upload session. - :returns: A FileUploadResponse. + :param file_id: The ID of the file to use for this request. + :returns: An OpenAIFileObject containing file information. """ ... - @webmethod(route="/files", method="GET") - async def list_all_buckets( + @webmethod(route="/openai/v1/files/{file_id}", method="DELETE") + async def openai_delete_file( self, - bucket: str, - ) -> ListBucketResponse: + file_id: str, + ) -> OpenAIFileDeleteResponse: """ - List all buckets. + Delete a file. - :param bucket: Bucket name (valid chars: a-zA-Z0-9_-). - :returns: A ListBucketResponse. + :param file_id: The ID of the file to use for this request. + :returns: An OpenAIFileDeleteResponse indicating successful deletion. """ ... - @webmethod(route="/files/{bucket}", method="GET") - async def list_files_in_bucket( + @webmethod(route="/openai/v1/files/{file_id}/content", method="GET") + async def openai_retrieve_file_content( self, - bucket: str, - ) -> ListFileResponse: + file_id: str, + ) -> Response: """ - List all files in a bucket. + Returns the contents of the specified file. - :param bucket: Bucket name (valid chars: a-zA-Z0-9_-). - :returns: A ListFileResponse. - """ - ... - - @webmethod(route="/files/{bucket}/{key:path}", method="GET") - async def get_file( - self, - bucket: str, - key: str, - ) -> FileResponse: - """ - Get a file info identified by a bucket and key. - - :param bucket: Bucket name (valid chars: a-zA-Z0-9_-). - :param key: Key under which the file is stored (valid chars: a-zA-Z0-9_-/.). - :returns: A FileResponse. - """ - ... - - @webmethod(route="/files/{bucket}/{key:path}", method="DELETE") - async def delete_file( - self, - bucket: str, - key: str, - ) -> None: - """ - Delete a file identified by a bucket and key. - - :param bucket: Bucket name (valid chars: a-zA-Z0-9_-). - :param key: Key under which the file is stored (valid chars: a-zA-Z0-9_-/.). + :param file_id: The ID of the file to use for this request. + :returns: The raw file content as a binary response. """ ...