@@ -5,7 +5,7 @@ import { asArray } from "../lib/array";
55import { useDeferredClose } from "../lib/useMountTransition" ;
66import { app } from "../lib/bridge" ;
77import { normalizeLangPref , useI18n , useT , type DictKey , type LangPref } from "../lib/i18n" ;
8- import { apiKeyEnvFromProviderName , inferredVisionModels , mergedFetchedProviderModels , providerApiKeyEnvForSave , providerDefaultModel , providerModelCandidates } from "../lib/providerModels" ;
8+ import { apiKeyEnvFromProviderName , inferredVisionModels , mergedFetchedProviderModels , providerApiKeyEnvForSave , providerDefaultModel , providerIsConfigured , providerModelCandidates , providerRequiresKey } from "../lib/providerModels" ;
99import { useUpdater } from "../lib/useUpdater" ;
1010import {
1111 THEME_STYLES ,
@@ -569,7 +569,7 @@ function ShortcutsSection() {
569569function allRefs ( s : SettingsView ) : string [ ] {
570570 const out : string [ ] = [ ] ;
571571 for ( const p of s . providers ) {
572- if ( ! p . added || ! p . keySet ) continue ;
572+ if ( ! p . added || ! providerIsConfigured ( p ) ) continue ;
573573 for ( const m of p . models ) out . push ( `${ p . name } /${ m } ` ) ;
574574 }
575575 return out ;
@@ -754,6 +754,7 @@ function normalizeBotMappingScope(scope: unknown, workspaceRoot: unknown): "glob
754754
755755function normalizeProviderView ( p : ProviderView ) : ProviderView {
756756 const visionModels = asArray ( p . visionModels ) ;
757+ const requiresKey = providerRequiresKey ( p ) ;
757758 return {
758759 ...p ,
759760 builtIn : Boolean ( p . builtIn ) ,
@@ -764,6 +765,8 @@ function normalizeProviderView(p: ProviderView): ProviderView {
764765 modelsUrl : p . modelsUrl ?? "" ,
765766 reasoningProtocol : normalizeReasoningProtocol ( p . reasoningProtocol ) ,
766767 supportedEfforts : asArray ( p . supportedEfforts ) ,
768+ requiresKey,
769+ configured : providerIsConfigured ( { ...p , requiresKey } ) ,
767770 keySource : p . keySource ?? "" ,
768771 keySourcePath : p . keySourcePath ?? "" ,
769772 } ;
@@ -2966,7 +2969,7 @@ function ModelsSection({ s, busy, apply, backgroundApply }: ModelsSectionProps)
29662969 const defaultProviderView = s . providers . find ( ( p ) => p . name === defaultProvider ) ;
29672970 const modelIssue = ! defaultProviderView
29682971 ? t ( "settings.modelUnavailable" , { ref : defaultRef || t ( "common.none" ) } )
2969- : ! defaultProviderView . keySet
2972+ : ! providerIsConfigured ( defaultProviderView )
29702973 ? t ( "settings.modelNeedsKey" , { provider : modelProviderLabel ( defaultProvider , defaultProviderView , t ) } )
29712974 : "" ;
29722975 const agent = s . agent ?? { temperature : 0 , maxSteps : 0 , plannerMaxSteps : 12 , systemPrompt : "" , coldResumePrune : true , reasoningLanguage : "auto" } ;
@@ -2979,11 +2982,11 @@ function ModelsSection({ s, busy, apply, backgroundApply }: ModelsSectionProps)
29792982 const groups = providerAccessGroups ( s . providers . filter ( ( p ) => p . added ) , t ) ;
29802983 const candidates = groups
29812984 . map ( ( group ) => {
2982- const provider = group . providers . find ( ( p ) => p . keySet && p . apiKeyEnv && p . baseUrl ) ;
2985+ const provider = group . providers . find ( ( p ) => providerIsConfigured ( p ) && p . baseUrl ) ;
29832986 return provider ? { group, provider } : null ;
29842987 } )
29852988 . filter ( ( item ) : item is { group : ProviderAccessGroup ; provider : ProviderView } => Boolean ( item ) ) ;
2986- const refreshKey = candidates . map ( ( { group, provider } ) => `${ group . id } :${ provider . apiKeyEnv } ` ) . join ( "|" ) ;
2989+ const refreshKey = candidates . map ( ( { group, provider } ) => `${ group . id } :${ provider . apiKeyEnv || provider . name } : ${ provider . baseUrl } ` ) . join ( "|" ) ;
29872990 if ( ! refreshKey || autoRefreshKeyRef . current === refreshKey ) return ;
29882991 autoRefreshKeyRef . current = refreshKey ;
29892992
@@ -3211,6 +3214,7 @@ function ModelPicker({
32113214 groupID,
32123215 label : firstProvider ? providerGroupLabel ( firstProvider , t ) : groupID ,
32133216 keySet : providerViews . some ( ( p ) => p . keySet ) ,
3217+ requiresKey : providerViews . every ( ( p ) => providerRequiresKey ( p ) ) ,
32143218 options : uniqueModelOptions ( options . filter ( ( opt ) => modelOptionGroupID ( opt ) === groupID ) ) ,
32153219 } ;
32163220 } )
@@ -3279,7 +3283,7 @@ function ModelPicker({
32793283 < div className = "settings-model-picker__group" key = { group . groupID } >
32803284 < div className = "settings-model-picker__group-title" >
32813285 < span > { group . label } </ span >
3282- < small > { group . keySet ? t ( "settings.keySet" ) : t ( "settings.noKey" ) } </ small >
3286+ < small > { providerKeyStatusLabel ( group , t ) } </ small >
32833287 </ div >
32843288 { group . options . map ( ( opt ) => (
32853289 < button
@@ -3319,10 +3323,15 @@ function modelOptionFromRef(ref: string, s: SettingsView): ModelPickerOption | n
33193323}
33203324
33213325function modelOptionMeta ( option : ModelPickerOption , t : ReturnType < typeof useT > ) : string {
3322- const key = option . providerView ?. keySet ? t ( "settings.keySet" ) : t ( "settings.noKey" ) ;
3326+ const key = option . providerView ? providerKeyStatusLabel ( option . providerView , t ) : t ( "settings.noKey" ) ;
33233327 return `${ modelProviderLabel ( option . provider , option . providerView , t ) } · ${ key } ` ;
33243328}
33253329
3330+ function providerKeyStatusLabel ( provider : { keySet : boolean ; requiresKey ?: boolean ; apiKeyEnv ?: string } , t : ReturnType < typeof useT > ) : string {
3331+ if ( ! providerRequiresKey ( provider ) ) return t ( "settings.noKeyRequired" ) ;
3332+ return provider . keySet ? t ( "settings.keySet" ) : t ( "settings.noKey" ) ;
3333+ }
3334+
33263335function modelProviderLabel ( provider : string , providerView : ProviderView | undefined , t : ReturnType < typeof useT > ) : string {
33273336 return providerView ? providerGroupLabel ( providerView , t ) : provider ;
33283337}
@@ -3623,6 +3632,8 @@ type ProviderAccessGroup = {
36233632 providers : ProviderView [ ] ;
36243633 apiKeyEnv : string ;
36253634 keySet : boolean ;
3635+ requiresKey : boolean ;
3636+ configured : boolean ;
36263637 keySource ?: string ;
36273638 keySourcePath ?: string ;
36283639 baseUrl : string ;
@@ -3835,7 +3846,7 @@ function ProviderAccessCard({
38353846 { group . builtIn ? t ( "settings.builtinProviderBadge" ) : t ( "settings.customProviderBadge" ) }
38363847 </ span >
38373848 < span className = { `badge ${ group . keySet ? "badge--project" : "badge--feedback" } ` } >
3838- { group . keySet ? t ( "settings.keySet" ) : t ( "settings.noKey" ) }
3849+ { providerKeyStatusLabel ( group , t ) }
38393850 </ span >
38403851 </ div >
38413852 < div className = "provider-access-card__desc" > { group . description } </ div >
@@ -3853,7 +3864,7 @@ function ProviderAccessCard({
38533864 ) }
38543865 < button
38553866 className = "btn btn--small"
3856- disabled = { busy || fetching || ! group . baseUrl || ! group . apiKeyEnv || ! group . keySet }
3867+ disabled = { busy || fetching || ! group . baseUrl || ! group . configured }
38573868 onClick = { onRefresh }
38583869 >
38593870 { fetching ? t ( "settings.fetchingModels" ) : t ( "settings.fetchModels" ) }
@@ -3885,8 +3896,8 @@ function ProviderAccessCard({
38853896 </ div >
38863897
38873898 < div className = "provider-card-block" >
3888- < div className = "provider-card-block__label" > { t ( group . keySet ? "settings.enabledModels" : "settings.modelList" ) } </ div >
3889- < div className = "provider-model-chips" aria-label = { t ( group . keySet ? "settings.enabledModels" : "settings.modelList" ) } >
3899+ < div className = "provider-card-block__label" > { t ( group . configured ? "settings.enabledModels" : "settings.modelList" ) } </ div >
3900+ < div className = "provider-model-chips" aria-label = { t ( group . configured ? "settings.enabledModels" : "settings.modelList" ) } >
38903901 { visibleModels . length > 0 ? visibleModels . map ( ( model ) => (
38913902 < span className = "provider-model-chip" key = { model } >
38923903 { model }
@@ -3898,7 +3909,7 @@ function ProviderAccessCard({
38983909 </ span >
38993910 ) }
39003911 </ div >
3901- { ! group . keySet && (
3912+ { ! group . configured && group . requiresKey && (
39023913 < div className = "provider-card-status provider-card-status--warn" >
39033914 { t ( "settings.modelsRequireKey" ) }
39043915 </ div >
@@ -4065,6 +4076,8 @@ function providerAccessGroups(providers: ProviderView[], t: ReturnType<typeof us
40654076 if ( existing ) {
40664077 existing . providers . push ( p ) ;
40674078 existing . keySet = existing . keySet || p . keySet ;
4079+ existing . requiresKey = existing . requiresKey && providerRequiresKey ( p ) ;
4080+ existing . configured = existing . configured || providerIsConfigured ( p ) ;
40684081 if ( ! existing . keySource && p . keySource ) existing . keySource = p . keySource ;
40694082 if ( ! existing . keySourcePath && p . keySourcePath ) existing . keySourcePath = p . keySourcePath ;
40704083 existing . models = uniqueStrings ( [ ...existing . models , ...p . models ] ) ;
@@ -4078,6 +4091,8 @@ function providerAccessGroups(providers: ProviderView[], t: ReturnType<typeof us
40784091 providers : [ p ] ,
40794092 apiKeyEnv : p . apiKeyEnv ,
40804093 keySet : p . keySet ,
4094+ requiresKey : providerRequiresKey ( p ) ,
4095+ configured : providerIsConfigured ( p ) ,
40814096 keySource : p . keySource ,
40824097 keySourcePath : p . keySourcePath ,
40834098 baseUrl : p . baseUrl ,
0 commit comments