-
Notifications
You must be signed in to change notification settings - Fork 39
feat: add Vercel AI Gateway provider with pricing support #689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
@naaa760 is attempting to deploy a commit to the Merit Systems Team on Vercel. A member of the Team first needs to authorize it. |
| const cost = getCostPerToken( | ||
| this.getModel(), | ||
| prompt_tokens, | ||
| completion_tokens | ||
| ); |
There was a problem hiding this comment.
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 UnknownModelErrorResult: 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
Changes:
VercelAIGatewayProviderclassfix: #573