-
Notifications
You must be signed in to change notification settings - Fork 132
fix: hide implicit alibaba region #1914
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
Changes from all commits
8accdbb
9048c1f
199286c
6141a4e
07d991f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -254,18 +254,18 @@ function filterRegionsByAvailableKeys( | |
| }); | ||
| } | ||
|
|
||
| function preferConcreteRegionalMappings( | ||
| function preferProviderRootMappings( | ||
| providers: ProviderModelMapping[], | ||
| ): ProviderModelMapping[] { | ||
| const providersWithRegions = new Set( | ||
| const providersWithRootMappings = new Set( | ||
| providers | ||
| .filter((mapping) => mapping.region) | ||
| .filter((mapping) => !mapping.region) | ||
| .map((mapping) => mapping.providerId), | ||
| ); | ||
|
|
||
| return providers.filter( | ||
| (mapping) => | ||
| !providersWithRegions.has(mapping.providerId) || Boolean(mapping.region), | ||
| !providersWithRootMappings.has(mapping.providerId) || !mapping.region, | ||
| ); | ||
| } | ||
|
|
||
|
|
@@ -1691,7 +1691,7 @@ chat.openapi(completions, async (c) => { | |
| } | ||
| const candidateAllowedProviders = candidateIam.allowedProviders; | ||
|
|
||
| const candidateProviders = preferConcreteRegionalMappings( | ||
| const candidateProviders = preferProviderRootMappings( | ||
| project.mode === "credits" | ||
| ? filterRegionsByAvailableKeys( | ||
| expandAllProviderRegions( | ||
|
|
@@ -1834,6 +1834,7 @@ chat.openapi(completions, async (c) => { | |
| { | ||
| metricsMap, | ||
| isStreaming: stream, | ||
| includeProviderScoreRegions: false, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Passing Useful? React with 👍 / 👎. |
||
| promptTokens: routingPromptTokens, | ||
| }, | ||
| ); | ||
|
|
@@ -2108,9 +2109,7 @@ chat.openapi(completions, async (c) => { | |
|
|
||
| // Attempt to re-route to alternative providers (same pattern as low-uptime fallback) | ||
| const providerIds = modelInfo.providers | ||
| .filter( | ||
| (p) => !(p.providerId === usedProvider && p.region === usedRegion), | ||
| ) | ||
| .filter((p) => p.providerId !== usedProvider) | ||
| .map((p) => p.providerId); | ||
|
|
||
| if (providerIds.length > 0) { | ||
|
|
@@ -2127,39 +2126,18 @@ chat.openapi(completions, async (c) => { | |
| .filter((p) => hasProviderEnvironmentToken(p.id as Provider)) | ||
| .map((p) => p.id); | ||
|
|
||
| const availableModelProviders = preferConcreteRegionalMappings( | ||
| iamFilteredModelProviders, | ||
| ).filter((provider) => { | ||
| if (!availableProviders.includes(provider.providerId)) { | ||
| return false; | ||
| } | ||
| if ( | ||
| provider.providerId === usedProvider && | ||
| provider.region === usedRegion | ||
| ) { | ||
| return false; | ||
| } | ||
| if (webSearchTool && provider.webSearch !== true) { | ||
| return false; | ||
| } | ||
| if ( | ||
| response_format?.type === "json_object" || | ||
| response_format?.type === "json_schema" | ||
| ) { | ||
| if (provider.jsonOutput !== true) { | ||
| return false; | ||
| } | ||
| } | ||
| if (response_format?.type === "json_schema") { | ||
| if (provider.jsonOutputSchema !== true) { | ||
| return false; | ||
| } | ||
| } | ||
| if (hasImages && provider.vision !== true) { | ||
| return false; | ||
| } | ||
| return true; | ||
| }); | ||
| const availableModelProviders = filterEligibleModelProviders( | ||
| preferProviderRootMappings(expandedIamFilteredModelProviders), | ||
| { | ||
| allProviderVariants: modelInfo.providers, | ||
| availableProviders, | ||
| webSearchTool, | ||
| responseFormatType: response_format?.type, | ||
| hasImages, | ||
| maxTokens: max_tokens, | ||
| reasoningEffort: reasoning_effort, | ||
| }, | ||
| ).filter((provider) => provider.providerId !== usedProvider); | ||
|
|
||
|
Comment on lines
+2129
to
2141
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Provider-key region locks can be bypassed after root-mapping preference. At Line 1781 (and similarly at Line 1478 and Line 1624), root mappings are preferred before eligibility filtering. Since 💡 Suggested fixdiff --git a/apps/gateway/src/chat/chat.ts b/apps/gateway/src/chat/chat.ts
@@
const lockedRegion = options.providerLockedRegions?.get(
provider.providerId,
);
- if (lockedRegion && provider.region && provider.region !== lockedRegion) {
- return false;
- }
+ if (lockedRegion) {
+ // Enforce explicit provider-key region pin.
+ if (!provider.region || provider.region !== lockedRegion) {
+ return false;
+ }
+ }Also applies to: 1624-1634, 1781-1791 🤖 Prompt for AI Agents |
||
| // Also filter out rate-limited alternatives | ||
| const rateLimitedAlternatives = await filterRateLimitedProviders( | ||
|
|
@@ -2206,6 +2184,7 @@ chat.openapi(completions, async (c) => { | |
| { | ||
| metricsMap: allMetricsMap, | ||
| isStreaming: stream, | ||
| includeProviderScoreRegions: false, | ||
| promptTokens: routingPromptTokens, | ||
| }, | ||
| ); | ||
|
|
@@ -2285,9 +2264,7 @@ chat.openapi(completions, async (c) => { | |
| const currentUptime = metrics.uptime; | ||
| // Get available providers for routing | ||
| const providerIds = modelInfo.providers | ||
| .filter( | ||
| (p) => !(p.providerId === usedProvider && p.region === usedRegion), | ||
| ) // Exclude the exact low-uptime provider+region pair | ||
| .filter((p) => p.providerId !== usedProvider) | ||
| .map((p) => p.providerId); | ||
|
Comment on lines
2266
to
2268
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This change drops all mappings for Useful? React with 👍 / 👎. |
||
|
|
||
| if (providerIds.length > 0) { | ||
|
|
@@ -2308,7 +2285,7 @@ chat.openapi(completions, async (c) => { | |
| // If web search is requested, also filter to providers that support it | ||
| // If JSON output is requested, also filter to providers that support it | ||
| const availableModelProviders = filterEligibleModelProviders( | ||
| preferConcreteRegionalMappings(expandedIamFilteredModelProviders), | ||
| preferProviderRootMappings(expandedIamFilteredModelProviders), | ||
| { | ||
| allProviderVariants: modelInfo.providers, | ||
| availableProviders, | ||
|
|
@@ -2318,13 +2295,7 @@ chat.openapi(completions, async (c) => { | |
| maxTokens: max_tokens, | ||
| reasoningEffort: reasoning_effort, | ||
| }, | ||
| ).filter( | ||
| (provider) => | ||
| !( | ||
| provider.providerId === usedProvider && | ||
| provider.region === usedRegion | ||
| ), | ||
| ); | ||
| ).filter((provider) => provider.providerId !== usedProvider); | ||
|
|
||
| if (availableModelProviders.length > 0) { | ||
| const rawModelForFallback = models.find((m) => m.id === baseModelId); | ||
|
|
@@ -2388,6 +2359,7 @@ chat.openapi(completions, async (c) => { | |
| { | ||
| metricsMap: allMetricsMap, | ||
| isStreaming: stream, | ||
| includeProviderScoreRegions: false, | ||
| promptTokens: routingPromptTokens, | ||
| }, | ||
| ); | ||
|
|
@@ -2486,7 +2458,7 @@ chat.openapi(completions, async (c) => { | |
|
|
||
| // Filter model providers to only those eligible for this request | ||
| const availableModelProviders = filterEligibleModelProviders( | ||
| preferConcreteRegionalMappings(expandedIamFilteredModelProviders), | ||
| preferProviderRootMappings(expandedIamFilteredModelProviders), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Passing Useful? React with 👍 / 👎. |
||
| { | ||
| allProviderVariants: modelInfo.providers, | ||
| availableProviders, | ||
|
|
@@ -2583,6 +2555,7 @@ chat.openapi(completions, async (c) => { | |
| { | ||
| metricsMap, | ||
| isStreaming: stream, | ||
| includeProviderScoreRegions: false, | ||
| promptTokens: routingPromptTokens, | ||
| }, | ||
| ); | ||
|
|
@@ -2657,7 +2630,10 @@ chat.openapi(completions, async (c) => { | |
| selectionReason = "fallback-first-available"; | ||
| } | ||
|
|
||
| let routingMetadataProviders = allModelProviders; | ||
| let routingMetadataProviders = | ||
| selectionReason === "direct-provider-specified" | ||
| ? allModelProviders | ||
| : preferProviderRootMappings(allModelProviders); | ||
| let directProviderRegionWasExplicit = false; | ||
|
|
||
| if ( | ||
|
|
@@ -2752,6 +2728,8 @@ chat.openapi(completions, async (c) => { | |
| { | ||
| metricsMap, | ||
| isStreaming: stream, | ||
| includeProviderScoreRegions: | ||
| selectionReason === "direct-provider-specified", | ||
| promptTokens: routingPromptTokens, | ||
| }, | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| ); | ||
|
|
@@ -2781,13 +2759,18 @@ chat.openapi(completions, async (c) => { | |
| throughput: metrics?.throughput ?? 0, | ||
| }; | ||
| }); | ||
| const includeRoutingScoreRegions = | ||
| selectionReason === "direct-provider-specified"; | ||
|
|
||
| routingMetadata = addContentFilterRoutingMetadata( | ||
| { | ||
| availableProviders: routingMetadataProviders.map((p) => p.providerId), | ||
| selectedProvider: usedProvider, | ||
| selectionReason, | ||
| providerScores: allProviderScores, | ||
| providerScores: allProviderScores.map((score) => ({ | ||
| ...score, | ||
| region: includeRoutingScoreRegions ? score.region : undefined, | ||
| })), | ||
| ...getNoFallbackRoutingMetadata(noFallback, xNoFallbackHeaderSet), | ||
| }, | ||
| contentFilterMatched, | ||
|
|
@@ -2864,9 +2847,13 @@ chat.openapi(completions, async (c) => { | |
|
|
||
| // Create the model mapping values according to new schema | ||
| let usedModelMapping = usedModel; // Store the original provider model name | ||
| const includeUsedModelRegion = | ||
| routingMetadata?.selectionReason === "direct-provider-specified"; | ||
| let usedModelFormatted = formatUsedModelForDisplay( | ||
| usedProvider, | ||
| usedRegion ? `${baseModelName}:${usedRegion}` : baseModelName, | ||
| includeUsedModelRegion && usedRegion | ||
| ? `${baseModelName}:${usedRegion}` | ||
| : baseModelName, | ||
|
Comment on lines
+2850
to
+2856
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep This boolean now follows 💡 Possible fix- const includeUsedModelRegion =
- routingMetadata?.selectionReason === "direct-provider-specified";
+ const includeUsedModelRegion =
+ routingMetadata?.selectionReason === "direct-provider-specified" &&
+ routingMetadata.providerScores.some(
+ (score) => score.providerId === usedProvider && Boolean(score.region),
+ );Also applies to: 3397-3402 🤖 Prompt for AI Agents |
||
| customProviderName, | ||
| ); // Store in LLMGateway format | ||
|
|
||
|
|
@@ -3396,7 +3383,7 @@ chat.openapi(completions, async (c) => { | |
| ); | ||
|
|
||
| // If region is still unset but the provider supports regions, resolve the | ||
| // default region so it appears in logs and metadata. | ||
| // default region for request execution. | ||
| if (!usedRegion) { | ||
| const providerDef = providers.find((p) => p.id === usedProvider) as | ||
| | { regionConfig?: { defaultRegion: string } } | ||
|
|
@@ -3407,7 +3394,7 @@ chat.openapi(completions, async (c) => { | |
| } | ||
|
|
||
| // Re-compute usedModelFormatted now that region may have been resolved | ||
| if (usedRegion) { | ||
| if (includeUsedModelRegion && usedRegion) { | ||
| usedModelFormatted = formatUsedModelForDisplay( | ||
| usedProvider, | ||
| `${baseModelName}:${usedRegion}`, | ||
|
|
||
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.
This filter now drops concrete regional rows whenever a provider has a root row, so routing selects a root
modelName(no:region) even for regional providers. In API-key/hybrid mode,usedRegionis later populated from the provider key, but downstream validation still matches mappings by exact(providerId, modelName, region)(e.g.finalModelInfo.providers.find(...)used for max token and supported-parameter checks), which no longer matches and silently skips those guards. For regional providers like Alibaba, this can let invalidmax_tokens/unsupported params through to upstream instead of being rejected by the gateway.Useful? React with 👍 / 👎.