feat: openAI Files API Implementation#1982
Draft
sivanantha321 wants to merge 16 commits intoenvoyproxy:mainfrom
Draft
feat: openAI Files API Implementation#1982sivanantha321 wants to merge 16 commits intoenvoyproxy:mainfrom
sivanantha321 wants to merge 16 commits intoenvoyproxy:mainfrom
Conversation
Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
- Refactor server to support method-based routing for processors using regex. - Introduce new tracing capabilities for OpenAI file operations including retrieval and deletion. - Implement translators for OpenAI file API endpoints: retrieve, retrieve content and delete files. Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…penAI Files API Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
- Update Translator.RequestBody signature to include request headers in internal/translator/translator.go. - Update translator implementations to accept the new signature in all OpenAI/Anthropic/Cohere translators. - Update translator tests to match the new signature across those files. File upload now requires model_name - Enforce presence of model_name in file upload multipart parsing in internal/endpointspec/endpointspec.go. - Encode the model into file IDs on create responses and rewrite Content-Length in internal/translator/openai_file.go. Decode file/batch IDs from request path (header‑only requests) - Add path‑based decoding for file/batch requests and set model + original/decoded ID headers in internal/extproc/processor_impl.go. - Add new header keys in internal/internalapi/internalapi.go. Update extproc mocks/tests for the new headers and decoding behavior. - Use decoded ID for routing + return original ID on retrieve/delete/content - Route retrieve/delete/content requests using decoded file IDs and echo original IDs in responses in internal/translator/openai_file.go Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…y management Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…res_after handling Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…erences Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…corders Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
- Implemented new processor filters for file operations including creation, retrieval, and deletion. - Added tests for file processing routes and header manipulations. - Introduced encoding and decoding functions for file IDs with model names. - Enhanced tracing capabilities for file-related operations. - Added comprehensive unit tests for the new functionality in the translator package. Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…ty; add unit tests for noOpMetrics Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…upstream Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1982 +/- ##
==========================================
+ Coverage 84.33% 84.46% +0.12%
==========================================
Files 130 133 +3
Lines 17987 18517 +530
==========================================
+ Hits 15170 15641 +471
- Misses 1873 1907 +34
- Partials 944 969 +25 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
…pstream Signed-off-by: Sivanantham Chinnaiyan <sivanantham.chinnaiyan@ideas2it.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This commit implements the OpenAI Files API in the Envoy AI Gateway, adding support for four file operations. The Files API is a prerequisite for the Batch Processing API (proposal #007), as batch jobs reference files uploaded via this API.
Implemented Endpoints
POST/v1/filesmultipart/form-datawith purpose, expiration, and amodel_nameextra field for routingGET/v1/files/{file_id}GET/v1/files/{file_id}/contentDELETE/v1/files/{file_id}File ID Encoding & Multi-Backend Routing
A core challenge of the Files API in a gateway context is routing stickiness: once a file is uploaded to a specific backend (e.g., OpenAI, Azure), all subsequent operations on that file (retrieve, retrieve content, delete) must be routed to the same backend. Otherwise, the backend will return a "file not found" error.
To solve this without requiring the client to pass extra routing headers on every request, the gateway encodes the model/backend information directly into the file ID returned to the client. This is inspired by LiteLLM's approach.
Encoding Format
Key properties:
file-,batch_) so the ID looks valid to clients and SDKsRouting Flow — Example API Usage
Step 1: Upload a file — Client includes
model_nameas an extra multipart field:The gateway routes to the backend mapped to
gpt-4o-mini, and on the response, encodes the file ID:{ "id": "file-aWQ6ZmlsZS1hYmMxMjM7bW9kZWw6Z3B0LTRvLW1pbmk", "object": "file", "purpose": "fine-tune", "filename": "training_data.jsonl" }Step 2: Retrieve the file — Client uses the encoded ID as-is:
curl https://gateway.example.com/v1/files/file-aWQ6ZmlsZS1hYmMxMjM7bW9kZWw6Z3B0LTRvLW1pbmk \ -H "Authorization: Bearer $API_KEY"The gateway:
model: gpt-4o-miniandoriginal ID: file-abc123GET /v1/files/file-abc123to the upstreamStep 3: Retrieve file content:
curl https://gateway.example.com/v1/files/file-aWQ6ZmlsZS1hYmMxMjM7bW9kZWw6Z3B0LTRvLW1pbmk/content \ -H "Authorization: Bearer $API_KEY"Step 4: Delete the file:
curl -X DELETE https://gateway.example.com/v1/files/file-aWQ6ZmlsZS1hYmMxMjM7bW9kZWw6Z3B0LTRvLW1pbmk \ -H "Authorization: Bearer $API_KEY"The same decode → route → re-encode pattern applies for all operations.
Implementation Details
The encoding/decoding is implemented via two functions in
internal/translator/util.go:EncodeIDWithModel(id, modelName, idType)— used inResponseBodyofCreateFiletranslator to encode the file ID returned by the upstreamDecodeFileID(encodedID)— used in the processor/server layer to extract the model name and original ID from incoming requestsInternal headers (
OriginalFileIDHeaderKey,DecodedFileIDHeaderKey) carry the original and decoded file IDs through the request processing pipeline so that translators for Retrieve, RetrieveContent, and Delete can:Tracing: Non-Standard OpenInference Approach
The OpenInference specification does not define semantic conventions for file operations. OpenInference has well-defined span types for LLM/chat completions, embeddings, etc., but file upload/retrieve/delete are not part of the specification.
This PR implements tracing for file operations using a non-standard adaptation of the OpenInference conventions:
CreateFileRecorderCreateFileopenai.FileNewParamsopenai.FileObjectoutput.file_idon successRetrieveFileRecorderRetrieveFilestruct{}(no body)openai.FileObjectoutput.file_idon successRetrieveFileContentRecorderRetrieveFileContentstruct{}(no body)struct{}(raw bytes)DeleteFileRecorderDeleteFilestruct{}(no body)openai.FileDeletedoutput.file_idon successWhat's non-standard:
openinference.span.kind = "LLM"andllm.system = "openai"— borrowing from existing OpenInference conventions even though file operations are not LLM inference calls. This is because OpenInference has no dedicated span kind for file/storage operations.trace.SpanKindInternal(consistent with other OpenInference spans in the codebase).openinference.span.kindandllm.systemare set, since file operations don't have model/prompt/token semantics.output.file_idandoutput.mime_typewhich are not part of the OpenInference spec.RetrieveFileContentrecords no output attributes at all, since the response is raw binary file data.NoopChunkRecordersince file operations are never streamed.Key Changes Across 65 Files (+4,501 / -245)
API Schema Types (
internal/apischema/openai/openai.go):FileNewParams,FileObject,FileDeleted,FilePurpose,FileObjectPurpose,FileObjectStatus,FileNewParamsExpiresAfterUnmarshalMultipart/MarshalMultipartmethods onFileNewParamsfor handlingmultipart/form-dataencodingEndpoint Specs (
internal/endpointspec/endpointspec.go):CreateFileEndpointSpec,RetrieveFileEndpointSpec,RetrieveFileContentEndpointSpec,DeleteFileEndpointSpecParseBodysignature extended withrequestHeaders map[string]stringparameter to support Content-Type parsing for multipart requestsCreateFileEndpointSpec.ParseBodyvalidatesmultipart/form-dataContent-Type and boundary, then parses the body viaUnmarshalMultipartstruct{}since these are body-less operations (GET/DELETE)Server Routing (
internal/extproc/server.go):/v1/files/{file_id}) and method differentiation (GET vs DELETE on the same path)Processor (
internal/extproc/processor_impl.go):ProcessRequestHeaderssupport for body-less requests (GET/DELETE/HEAD) so routing can be initialized without waiting for a request bodyinitRequestextracted as a shared initialization path for both header-phase and body-phase processingTranslators (
internal/translator/openai_file.go):EncodeIDWithModel/DecodeFileIDininternal/translator/util.gofor multi-backend routing via encoded file IDsMetrics (
internal/metrics/noop_metrics.go):NoopMetrics/NoopMetricsFactoryfor endpoints that don't yet have dedicated metricsTests:
EncodeIDWithModel/DecodeFileIDround-trip encodingParseBodysignature and regex-based routingRelated Issues/PRs (if applicable)
Related: Proposal #007 — Batch Processing API Support
Special notes for reviewers (if applicable)
ParseBodyinterface change (addedrequestHeadersparameter) touches all existing endpoint spec implementations — each gains an unused_ map[string]stringparameter to satisfy the interface.map[string]ProcessorFactoryto a[]Routewith regex + http method matching is a significant architectural change that affects all existing route registrations.NoopMetricsFactory— a TODO is noted for adding dedicated metrics support.model_nameis required as an extra multipart field during file upload — this is a gateway-specific requirement not present in the standard OpenAI Files API.