feat(ai): add Vercel AI Gateway routing support (#1051)

* feat(ai): add Vercel AI Gateway routing support

Add vercelGatewayRouting to OpenAICompletionsCompat, parallel to
openRouterRouting. When a model targets ai-gateway.vercel.sh and has
vercelGatewayRouting configured, the openai-completions provider passes
providerOptions.gateway with only/order in the request body.

Changes:
- types.ts: VercelGatewayRouting interface + field on OpenAICompletionsCompat
- openai-completions.ts: buildParams passes providerOptions.gateway,
  detectCompat/getCompat include the new field
- model-registry.ts: VercelGatewayRoutingSchema for models.json validation
- test: updated Required<OpenAICompletionsCompat> in test fixture

* docs(coding-agent): add vercelGatewayRouting to custom models documentation
This commit is contained in:
Ben Vargas 2026-01-29 17:44:51 -07:00 committed by GitHub
parent d1560a9640
commit e045a9f142
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 67 additions and 0 deletions

View file

@ -452,6 +452,17 @@ function buildParams(model: Model<"openai-completions">, context: Context, optio
(params as any).provider = model.compat.openRouterRouting;
}
// Vercel AI Gateway provider routing preferences
if (model.baseUrl.includes("ai-gateway.vercel.sh") && model.compat?.vercelGatewayRouting) {
const routing = model.compat.vercelGatewayRouting;
if (routing.only || routing.order) {
const gatewayOptions: Record<string, string[]> = {};
if (routing.only) gatewayOptions.only = routing.only;
if (routing.order) gatewayOptions.order = routing.order;
(params as any).providerOptions = { gateway: gatewayOptions };
}
}
return params;
}
@ -797,6 +808,7 @@ function detectCompat(model: Model<"openai-completions">): Required<OpenAIComple
requiresMistralToolIds: isMistral,
thinkingFormat: isZai ? "zai" : "openai",
openRouterRouting: {},
vercelGatewayRouting: {},
};
}
@ -821,5 +833,6 @@ function getCompat(model: Model<"openai-completions">): Required<OpenAICompletio
requiresMistralToolIds: model.compat.requiresMistralToolIds ?? detected.requiresMistralToolIds,
thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
openRouterRouting: model.compat.openRouterRouting ?? {},
vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
};
}

View file

@ -218,6 +218,8 @@ export interface OpenAICompletionsCompat {
thinkingFormat?: "openai" | "zai";
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
openRouterRouting?: OpenRouterRouting;
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
vercelGatewayRouting?: VercelGatewayRouting;
}
/** Compatibility settings for OpenAI Responses APIs. */
@ -237,6 +239,18 @@ export interface OpenRouterRouting {
order?: string[];
}
/**
* Vercel AI Gateway routing preferences.
* Controls which upstream providers the gateway routes requests to.
* @see https://vercel.com/docs/ai-gateway/models-and-providers/provider-options
*/
export interface VercelGatewayRouting {
/** List of provider slugs to exclusively use for this request (e.g., ["bedrock", "anthropic"]). */
only?: string[];
/** List of provider slugs to try in order (e.g., ["anthropic", "openai"]). */
order?: string[];
}
// Model interface for the unified model system
export interface Model<TApi extends Api> {
id: string;

View file

@ -31,6 +31,7 @@ const compat: Required<OpenAICompletionsCompat> = {
requiresMistralToolIds: false,
thinkingFormat: "openai",
openRouterRouting: {},
vercelGatewayRouting: {},
};
function buildToolResult(toolCallId: string, timestamp: number): ToolResultMessage {