-
Notifications
You must be signed in to change notification settings - Fork 2.6k
feat: add OpenRouter multi-provider failover support #7365
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
feat: add OpenRouter multi-provider failover support #7365
Conversation
- Add support for up to 4 OpenRouter providers with automatic failover - Implement priority-based provider selection in UI with dynamic dropdowns - Add comprehensive test coverage for multi-provider functionality - Enable seamless switching between single and multi-provider modes - Ensure primary provider's context window and pricing is used for model info
| <Checkbox | ||
| checked={apiConfiguration?.openRouterFailoverEnabled ?? true} | ||
| onChange={handleInputChange("openRouterFailoverEnabled", noTransform)}> | ||
| Enable automatic failover |
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.
Please use the translation function (e.g., t('settings:providers.openRouter.multiProvider.failoverEnabled')) for the checkbox label instead of the hardcoded string "Enable automatic failover".
| Enable automatic failover | |
| {t('settings:providers.openRouter.multiProvider.failoverEnabled')} |
This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.
| {apiConfiguration?.openRouterFailoverEnabled ? ( | ||
| <div key="multi-provider-mode"> | ||
| <label className="block font-medium mb-2"> | ||
| Multiple Providers (up to 4) |
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 multi-provider mode title is hardcoded as 'Multiple Providers (up to 4)'. Use a translatable string (e.g., t('settings:providers.openRouter.multiProvider.title')).
| Multiple Providers (up to 4) | |
| {t('settings:providers.openRouter.multiProvider.title')} |
This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.
| key={`provider-${index}-${apiConfiguration?.openRouterFailoverEnabled}`} | ||
| className="mb-2"> | ||
| <label className="block text-sm font-medium mb-1"> | ||
| {index === 0 |
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.
Provider role labels ('Primary Provider', 'Secondary Provider', etc.) are hardcoded. These should be replaced with translation keys (e.g., t('settings:providers.openRouter.multiProvider.primaryProvider')) for consistency.
This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.
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.
Thank you for your contribution! I've reviewed the OpenRouter multi-provider failover implementation and found several issues that need attention before merging.
| {apiConfiguration?.openRouterFailoverEnabled ? ( | ||
| <div key="multi-provider-mode"> | ||
| <label className="block font-medium mb-2"> | ||
| Multiple Providers (up to 4) |
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.
Missing i18n translations here. These hardcoded English strings break internationalization:
- "Multiple Providers (up to 4)"
- "Primary Provider", "Secondary Provider", etc.
- "Configure multiple providers in priority order..."
Consider using translation keys like:
| Multiple Providers (up to 4) | |
| <label className="block font-medium mb-2"> | |
| {t("settings:providers.openRouter.multiProvider.title")} | |
| </label> |
| <Checkbox | ||
| checked={apiConfiguration?.openRouterFailoverEnabled ?? true} | ||
| onChange={handleInputChange("openRouterFailoverEnabled", noTransform)}> | ||
| Enable automatic failover |
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.
These hardcoded strings should use i18n translation keys:
| Enable automatic failover | |
| {t("settings:providers.openRouter.multiProvider.failoverEnabled")} |
and
| Enable automatic failover | |
| <div className="text-sm text-vscode-descriptionForeground mt-1"> | |
| {t("settings:providers.openRouter.multiProvider.failoverDescription")} | |
| </div> |
| } | ||
|
|
||
| // This should never be reached, but just in case | ||
| throw lastError || new Error("All OpenRouter providers failed") |
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 error message doesn't provide useful context about which providers were tried or what errors occurred. Consider:
| throw lastError || new Error("All OpenRouter providers failed") | |
| const providersSummary = providers.join(', '); | |
| throw lastError || new Error(`All OpenRouter providers failed (tried: ${providersSummary}). Last error: ${lastError?.message || 'Unknown'}`); |
| for (let providerIndex = 0; providerIndex < providers.length; providerIndex++) { | ||
| try { | ||
| const currentProvider = providers[providerIndex] | ||
| console.log( |
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.
Consider using a proper logging service or making these debug-only logs. Production console logs can impact performance and clutter user consoles:
| console.log( | |
| if (process.env.NODE_ENV === 'development') { | |
| console.log( | |
| `[OpenRouter] Attempting request with provider: ${currentProvider} (${providerIndex + 1}/${providers.length})`, | |
| ) | |
| } |
| openRouterBaseUrl: z.string().optional(), | ||
| openRouterSpecificProvider: z.string().optional(), | ||
| openRouterSpecificProvider: z.string().optional(), // Keep for backward compatibility | ||
| openRouterProviders: z.array(z.string()).max(4).optional(), // New multi-provider support |
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 4-provider limit is a magic number. Consider defining it as a constant for better maintainability:
| openRouterProviders: z.array(z.string()).max(4).optional(), // New multi-provider support | |
| const MAX_OPENROUTER_PROVIDERS = 4; | |
| // ... | |
| openRouterProviders: z.array(z.string()).max(MAX_OPENROUTER_PROVIDERS).optional(), |
| const providers = (handler as any).getProvidersToUse() | ||
| expect(providers).toEqual(["multi1", "multi2"]) | ||
| }) | ||
| }) |
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.
Consider adding integration tests that simulate actual API failures with mock responses. The current tests only verify the logic but don't test the actual failover behavior with real-world error scenarios.
| /** | ||
| * Get the list of providers to use, supporting both new multi-provider and legacy single provider config | ||
| */ | ||
| private getProvidersToUse(): string[] { |
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.
Consider adding JSDoc comments to explain the purpose and parameters of these new methods. This would improve code maintainability:
| private getProvidersToUse(): string[] { | |
| /** | |
| * Get the list of providers to use for requests, supporting both multi-provider and legacy configurations | |
| * @returns Array of provider names in priority order | |
| */ | |
| private getProvidersToUse(): string[] { |
| "title": "OpenRouter Provider Routing", | ||
| "description": "OpenRouter routes requests to the best available providers for your model. By default, requests are load balanced across the top providers to maximize uptime. However, you can choose a specific provider to use for this model.", | ||
| "learnMore": "Learn more about provider routing" | ||
| }, |
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.
Good that you started adding i18n keys here, but the implementation is incomplete. You need to add all the missing keys mentioned in my other comments:
- multiProvider.failoverEnabled
- multiProvider.failoverDescription
- The provider priority labels
Also ensure these are added to all other locale files.
|
@roomote-agent Don't be shy, you can address all the issues you have found then switch to translate and fix translations as well. make sure you do it in same PR and not create new branches |
|
Hi @shariqriazz! I see the review comments and will address all the issues found:
I'll work on these fixes and also ensure all translations are properly added across all locale files. Working on it now! |
|
Hi @shariqriazz! ✅ All requested changes have been completed and pushed to the PR: Changes Made:🌐 i18n Fixes
📝 Code Quality Improvements
✅ Testing
The changes maintain backward compatibility while addressing all the review feedback. The CI checks from the previous commit are showing failures, but those should be resolved with this new commit once the CI runs again. |
|
+1 required |
Important
Adds multi-provider failover support for OpenRouter with UI updates and comprehensive test coverage, ensuring backward compatibility.
openrouter.ts.ApiOptions.tsxwith dynamic dropdowns.useSelectedModel.ts.openrouter-multi-provider.spec.tsanduseSelectedModel-multiProvider.spec.ts.ApiOptions.tsxandOpenRouter.tsxto enable seamless switching between single and multi-provider modes.openRouterSpecificProviderfor backward compatibility inprovider-settings.ts.This description was created by
for f586d7e. You can customize this summary. It will automatically update as commits are pushed.