diff --git a/packages/ui/src/components/sections/providers/ProvidersPage.test.ts b/packages/ui/src/components/sections/providers/ProvidersPage.test.ts index f0a5d093..05050304 100644 --- a/packages/ui/src/components/sections/providers/ProvidersPage.test.ts +++ b/packages/ui/src/components/sections/providers/ProvidersPage.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'bun:test'; -import { shouldLoadAvailableProviders } from './providerAvailability'; +import { requiresProviderAuth, shouldLoadAvailableProviders } from './providerAvailability'; import { getOAuthAuthMethods, normalizeAuthType, @@ -15,6 +15,14 @@ describe('ProvidersPage available provider loading', () => { }); }); +describe('ProvidersPage provider authentication', () => { + test('does not require credentials for a custom provider defined in config', () => { + expect(requiresProviderAuth(true, false, true)).toBe(false); + expect(requiresProviderAuth(true, false, false)).toBe(true); + expect(requiresProviderAuth(true, true, false)).toBe(false); + }); +}); + describe('provider auth method helpers', () => { test('normalizeAuthType recognizes oauth and api labels', () => { expect(normalizeAuthType({ type: 'oauth', label: 'Login with Cursor' })).toBe('oauth'); diff --git a/packages/ui/src/components/sections/providers/ProvidersPage.tsx b/packages/ui/src/components/sections/providers/ProvidersPage.tsx index e680b506..6a4655f5 100644 --- a/packages/ui/src/components/sections/providers/ProvidersPage.tsx +++ b/packages/ui/src/components/sections/providers/ProvidersPage.tsx @@ -23,7 +23,7 @@ import type { ModelMetadata } from '@/types'; import { getCurrentIntlLocale, useI18n } from '@/lib/i18n'; import { runtimeFetch } from '@/lib/runtime-fetch'; import { opencodeClient } from '@/lib/opencode/client'; -import { shouldLoadAvailableProviders } from './providerAvailability'; +import { requiresProviderAuth, shouldLoadAvailableProviders } from './providerAvailability'; import { getOAuthAuthMethods, parseAuthPayload, @@ -324,7 +324,8 @@ export const ProvidersPage: React.FC = () => { ? provider.env.filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0) : []; const hasCreds = Boolean(sources.auth.exists) || envEntries.length > 0; - if (!hasCreds) { + const isCustomProvider = Boolean(provider && isConfigDefinedCustomProvider(provider, sources)); + if (requiresProviderAuth(true, hasCreds, isCustomProvider)) { setShowAuthPanel(true); } }, [selectedProviderId, providerSources, providers]); @@ -773,8 +774,12 @@ export const ProvidersPage: React.FC = () => { const hasStoredAuth = Boolean(selectedSources?.auth.exists); const hasEnvCredentials = providerEnv.length > 0; const hasCredentials = hasStoredAuth || hasEnvCredentials; - const authStatusIncomplete = sourcesLoaded && !hasCredentials; - const showModelsSection = providerModels.length > 0 && (!sourcesLoaded || hasCredentials); + const authStatusIncomplete = requiresProviderAuth( + sourcesLoaded, + hasCredentials, + isEditableCustomProvider, + ); + const showModelsSection = providerModels.length > 0 && !authStatusIncomplete; const incompleteAuthHint = !showApiKeyAuth && oauthAuthMethods.length > 0 ? t('settings.providers.page.auth.useReconnectHint') : t('settings.providers.page.auth.incompleteHint'); diff --git a/packages/ui/src/components/sections/providers/providerAvailability.ts b/packages/ui/src/components/sections/providers/providerAvailability.ts index ea6f0386..c2eabab4 100644 --- a/packages/ui/src/components/sections/providers/providerAvailability.ts +++ b/packages/ui/src/components/sections/providers/providerAvailability.ts @@ -1 +1,7 @@ export const shouldLoadAvailableProviders = (isAddMode: boolean): boolean => isAddMode; + +export const requiresProviderAuth = ( + sourcesLoaded: boolean, + hasCredentials: boolean, + isConfigDefinedCustomProvider: boolean, +): boolean => sourcesLoaded && !hasCredentials && !isConfigDefinedCustomProvider;