gateway icon indicating copy to clipboard operation
gateway copied to clipboard

fix: apply override_params to FormData request bodies

Open AgileEduLabs opened this issue 4 months ago โ€ข 2 comments

Description

Transform the javascript FormData object based on the supplied override_params. Modified transformToProviderRequest.ts on line 235:

  if (requestBody instanceof FormData) {
    if (typeof providerOptions.overrideParams === 'undefined') {
      return requestBody;
    }

    for (const [k, v] of Object.entries(providerOptions.overrideParams)) {
      requestBody.delete(k); // If the key already exists, delete it first so we always overwrite.

      // Value can be string, Blob, File, or an array of those.
      const values = Array.isArray(v) ? v : [v];
      for (const val of values) {
        requestBody.append(k, val);
      }
    }

    return requestBody;

  }

Motivation

Currently portkey.audio.transcriptions.create does not respect the override_params of the gateway config object. For example, if we change the model name in override_params, we would expect it to use the model name as specified in the config object. However, this values in the config object are ignored.

If override_params cannot modify the model name on the gateway, then the gateway features are essentially useless. You won't be able to do any sort of meaningful fallback nor loadbalancing, because each provider has their own model name.

The source of the problem lies in transformToProviderRequest.ts on line 235. If body is FormData, then override parameters are not applied and instead the function returns early with the requestBody unmodified:

if (requestBody instanceof FormData || requestBody instanceof ArrayBuffer)
    return requestBody;

At first glance this makes sense because you cannot apply a simple spread operator to FormData nor ArrayBuffer, so we just ignore the override_params and return early.

However, the more elegant solution is to transform the javascript FormData object based on the override_params. Since requestBody is already a JavaScript FormData object, the computational cost of overriding the keys is negligible. This is in keeping with the spirit of the gateway's lightweight nature:

  for (const [k, v] of Object.entries(providerOptions.overrideParams)) {
      requestBody.delete(k); // If the key already exists, delete it first so we always overwrite.

      // Value can be string, Blob, File, or an array of those.
      const values = Array.isArray(v) ? v : [v];
      for (const val of values) {
        requestBody.append(k, val);
      }
    }

This pull request is to fix the issue as outlined in https://github.com/Portkey-AI/gateway/issues/1217

Type of Change

  • [x] Bug fix (non-breaking change which fixes an issue)
  • [ ] New feature (non-breaking change which adds functionality)
  • [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • [ ] Documentation update
  • [ ] Refactoring (no functional changes)

How Has This Been Tested?

  • [ ] Unit Tests
  • [ ] Integration Tests
  • [x] Manual Testing

Screenshots (if applicable)

Checklist

  • [x] My code follows the style guidelines of this project
  • [x] I have performed a self-review of my own code
  • [x] I have commented my code, particularly in hard-to-understand areas
  • [ ] I have made corresponding changes to the documentation
  • [x] My changes generate no new warnings
  • [ ] I have added tests that prove my fix is effective or that my feature works
  • [x] New and existing unit tests pass locally with my changes

Related Issues

AgileEduLabs avatar Jul 25 '25 03:07 AgileEduLabs

Code Quality bug fix

Summary By MatterAI MatterAI logo

๐Ÿ”„ What Changed

This PR adds support for applying overrideParams to FormData request bodies. Previously, the override functionality was only available for other request body types, but not for FormData objects. The implementation now properly handles FormData objects by deleting existing keys and appending new values, supporting both single values and arrays of values.

๐Ÿ” Impact of the Change

This change ensures consistent behavior across all request body types when using the overrideParams option. Users can now override parameters in FormData requests, which is particularly useful for file uploads and multipart form submissions where specific parameters need to be modified before sending to the provider.

๐Ÿ“ Total Files Changed

  • src/services/transformToProviderRequest.ts: Added logic to handle FormData request bodies with overrideParams, including deletion of existing keys and appending new values.

๐Ÿงช Test Added

N/A - No tests were included in this PR based on the provided JSON data.

๐Ÿ”’ Security Vulnerabilities

N/A - No security vulnerabilities were identified in this change.

[!TIP]

Quality Recommendations

  1. Add unit tests to verify the FormData override functionality works as expected

  2. Consider adding type checking for the values in overrideParams to ensure they're compatible with FormData.append()

  3. Add error handling for potential exceptions during FormData manipulation

Sequence Diagram

sequenceDiagram
    participant Client
    participant transformToProviderRequest
    participant FormData

    Client->>transformToProviderRequest: Call with requestBody (FormData) and providerOptions
    Note over transformToProviderRequest: Check if requestBody is FormData
    alt requestBody is FormData
        alt providerOptions.overrideParams is undefined
            transformToProviderRequest-->>Client: Return original FormData unchanged
        else providerOptions.overrideParams exists
            loop For each [key, value] in overrideParams
                transformToProviderRequest->>FormData: delete(key)
                Note over transformToProviderRequest: Convert value to array if not already
                loop For each val in values array
                    transformToProviderRequest->>FormData: append(key, val)
                end
            end
            transformToProviderRequest-->>Client: Return modified FormData
        end
    else requestBody is ArrayBuffer
        transformToProviderRequest-->>Client: Return original ArrayBuffer unchanged
    end

matter-code-review[bot] avatar Jul 25 '25 03:07 matter-code-review[bot]

@AgileEduLabs I think we need to take a more nuanced approach with regards to the tts and stt routes unification, though we currently support loading and transforming multipart form data for these routes, It is not scalable, I want to verify if we can transform these on the fly with stream transforms, similar to how we are doing for file uploads

narengogi avatar Aug 04 '25 13:08 narengogi