Skip to content

Conversation

@naaa760
Copy link

@naaa760 naaa760 commented Nov 14, 2025

  • adds Vercel AI Gateway as a provider to support chat, transcription, and speech models.

Changes:

  • Added VercelAIGatewayProvider class
  • Integrated into provider factory with automatic detection for provider-prefixed models
  • Added transcription and speech endpoint support
  • Uses Vercel AI Gateway pricing API for accurate cost calculation
  • Added SDK support (TypeScript & React)

fix: #573

@vercel
Copy link
Contributor

vercel bot commented Nov 14, 2025

@naaa760 is attempting to deploy a commit to the Merit Systems Team on Vercel.

A member of the Team first needs to authorize it.

Comment on lines +83 to +87
const cost = getCostPerToken(
this.getModel(),
prompt_tokens,
completion_tokens
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handleChatCompletionResponse method will throw an UnknownModelError when processing responses for provider-prefixed models (e.g., "openai/gpt-4", "anthropic/claude-3") because it attempts to look up pricing for the full prefixed model name, which doesn't exist in the pricing database.

View Details
📝 Patch Details
diff --git a/packages/app/server/src/providers/VercelAIGatewayProvider.ts b/packages/app/server/src/providers/VercelAIGatewayProvider.ts
index aefc3062..39bf3e5f 100644
--- a/packages/app/server/src/providers/VercelAIGatewayProvider.ts
+++ b/packages/app/server/src/providers/VercelAIGatewayProvider.ts
@@ -10,6 +10,19 @@ import { Decimal } from '@prisma/client/runtime/library';
 export class VercelAIGatewayProvider extends BaseProvider {
   private readonly VERCEL_AI_GATEWAY_BASE_URL = 'https://ai-gateway.vercel.sh/v1';
 
+  /**
+   * Extract base model name from provider-prefixed model (e.g., "openai/gpt-4" -> "gpt-4")
+   * Returns the original model if no prefix is found
+   */
+  private getBaseModelName(): string {
+    const model = this.getModel();
+    if (model.includes('/')) {
+      const [, ...modelParts] = model.split('/');
+      return modelParts.join('/');
+    }
+    return model;
+  }
+
   getType(): ProviderType {
     return ProviderType.VERCEL_AI_GATEWAY;
   }
@@ -81,7 +94,7 @@ export class VercelAIGatewayProvider extends BaseProvider {
     }
 
     const cost = getCostPerToken(
-      this.getModel(),
+      this.getBaseModelName(),
       prompt_tokens,
       completion_tokens
     );
@@ -110,17 +123,18 @@ export class VercelAIGatewayProvider extends BaseProvider {
     let cost = new Decimal(0);
     let metadata: LlmTransactionMetadata;
     const model = this.getModel();
+    const baseModel = this.getBaseModelName();
 
-    const modelPrice = getModelPrice(model);
+    const modelPrice = getModelPrice(baseModel);
     
     if (endpointType === 'transcription') {
       try {
         const transcriptionData = JSON.parse(data);
         const text = transcriptionData.text || '';
         
-        if (modelPrice && isValidModel(model)) {
+        if (modelPrice && isValidModel(baseModel)) {
           const textTokens = Math.ceil(text.length / 4);
-          cost = getCostPerToken(model, 0, textTokens);
+          cost = getCostPerToken(baseModel, 0, textTokens);
         } else {
           cost = new Decimal(0.01);
         }
@@ -135,7 +149,7 @@ export class VercelAIGatewayProvider extends BaseProvider {
         };
       } catch (error) {
         logger.error(`Error parsing transcription response: ${error}`);
-        cost = modelPrice && isValidModel(model) ? new Decimal(0) : new Decimal(0.01);
+        cost = modelPrice && isValidModel(baseModel) ? new Decimal(0) : new Decimal(0.01);
         metadata = {
           providerId: 'transcription',
           provider: this.getType(),
@@ -149,9 +163,9 @@ export class VercelAIGatewayProvider extends BaseProvider {
       const inputText = (requestBody?.input as string) || '';
       const characterCount = inputText.length;
       
-      if (modelPrice && isValidModel(model)) {
+      if (modelPrice && isValidModel(baseModel)) {
         const inputTokens = Math.ceil(characterCount / 4);
-        cost = getCostPerToken(model, inputTokens, 0);
+        cost = getCostPerToken(baseModel, inputTokens, 0);
       } else {
         const costPerCharacter = new Decimal(0.000015);
         cost = costPerCharacter.mul(characterCount);
@@ -166,7 +180,7 @@ export class VercelAIGatewayProvider extends BaseProvider {
         totalTokens: characterCount,
       };
     } else {
-      cost = modelPrice && isValidModel(model) ? new Decimal(0) : new Decimal(0.01);
+      cost = modelPrice && isValidModel(baseModel) ? new Decimal(0) : new Decimal(0.01);
       metadata = {
         providerId: 'audio',
         provider: this.getType(),
@@ -184,4 +198,3 @@ export class VercelAIGatewayProvider extends BaseProvider {
     };
   }
 }
-

Analysis

VercelAIGatewayProvider throws UnknownModelError for provider-prefixed models

What fails: VercelAIGatewayProvider.handleChatCompletionResponse() calls getCostPerToken(this.getModel(), ...) with provider-prefixed model names like "openai/gpt-4", but pricing database only contains base model names like "gpt-4"

How to reproduce:

// Create provider with prefixed model and process a chat completion response
const provider = new VercelAIGatewayProvider(false, 'openai/gpt-4');
const mockResponse = JSON.stringify({
  usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 }
});
provider.handleBody(mockResponse); // Throws UnknownModelError

Result: getCostPerToken() calls isValidModel("openai/gpt-4") which returns false, then throws UnknownModelError: Invalid model: openai/gpt-4

Expected: Should extract base model "gpt-4" for pricing lookup per Vercel AI Gateway docs which confirm "creator/model-name" format is correct

Note: Same issue affects handleAudioResponse() method for transcription and speech endpoints

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the Vercel AI Gateway as a Provider

1 participant