11import type { CancellationToken , Disposable , Event , MessageItem , ProgressOptions } from 'vscode' ;
2- import { env , EventEmitter , window } from 'vscode' ;
2+ import { env , EventEmitter , ThemeIcon , window } from 'vscode' ;
33import type { AIPrimaryProviders , AIProviderAndModel , AIProviders , SupportedAIModels } from '../../constants.ai' ;
44import { primaryAIProviders } from '../../constants.ai' ;
55import type { AIGenerateDraftEventData , Source , TelemetryEvents } from '../../constants.telemetry' ;
@@ -11,7 +11,7 @@ import type { GitRevisionReference } from '../../git/models/reference';
1111import type { Repository } from '../../git/models/repository' ;
1212import { uncommitted , uncommittedStaged } from '../../git/models/revision' ;
1313import { assertsCommitHasFullDetails } from '../../git/utils/commit.utils' ;
14- import { showAIModelPicker } from '../../quickpicks/aiModelPicker ' ;
14+ import { showAIModelPicker , showAIProviderPicker } from '../../quickpicks/aiPicker ' ;
1515import { configuration } from '../../system/-webview/configuration' ;
1616import type { Storage } from '../../system/-webview/storage' ;
1717import { supportedInVSCodeVersion } from '../../system/-webview/vscode' ;
@@ -22,6 +22,7 @@ import { lazy } from '../../system/lazy';
2222import type { Deferred } from '../../system/promise' ;
2323import { getSettledValue } from '../../system/promise' ;
2424import type { ServerConnection } from '../gk/serverConnection' ;
25+ import { ensureAccountQuickPick } from '../gk/utils/-webview/acount.utils' ;
2526import type { AIActionType , AIModel , AIModelDescriptor } from './models/model' ;
2627import type { PromptTemplateContext } from './models/promptTemplates' ;
2728import type { AIProvider , AIRequestResult } from './models/provider' ;
@@ -184,10 +185,48 @@ export class AIProviderService implements Disposable {
184185
185186 if ( options ?. silent ) return undefined ;
186187
187- const pick = await showAIModelPicker ( this . container , cfg ) ;
188- if ( pick == null ) return undefined ;
188+ let chosenProvider : AIProviders | undefined = undefined ;
189+ let chosenModel : AIModel | undefined = undefined ;
190+
191+ if ( ! options ?. force ) {
192+ const vsCodeModels = await this . getModels ( 'vscode' ) ;
193+ if ( vsCodeModels . length !== 0 ) {
194+ chosenProvider = 'vscode' ;
195+ } else if ( ( await this . container . subscription . getSubscription ( ) ) . account ?. verified ) {
196+ chosenProvider = 'gitkraken' ;
197+ const gitkrakenModels = await this . getModels ( 'gitkraken' ) ;
198+ chosenModel = gitkrakenModels . find ( m => m . default ) ;
199+ }
200+ }
201+
202+ if ( chosenProvider == null ) {
203+ chosenProvider = ( await showAIProviderPicker ( this . container , cfg ) ) ?. provider ;
204+ if ( chosenProvider == null ) return ;
205+ if (
206+ ( chosenProvider === 'gitkraken' ||
207+ ( chosenProvider !== 'vscode' &&
208+ ( await this . container . storage . getSecret ( `gitlens.${ chosenProvider } .key` ) ) == null ) ) &&
209+ ! ( await ensureAccountQuickPick (
210+ this . container ,
211+ {
212+ label : 'Use AI-powered GitLens features like Generate Commit Message, Explain Commit, and more.' ,
213+ iconPath : new ThemeIcon ( 'sparkle' ) ,
214+ } ,
215+ source ,
216+ ) )
217+ ) {
218+ return ;
219+ }
220+ }
189221
190- const model = await this . getOrUpdateModel ( pick . model ) ;
222+ if ( ! ( await this . ensureProviderConfigured ( chosenProvider ) ) ) return ;
223+
224+ if ( chosenModel == null ) {
225+ chosenModel = ( await showAIModelPicker ( this . container , chosenProvider , cfg ) ) ?. model ;
226+ if ( chosenModel == null ) return ;
227+ }
228+
229+ const model = await this . getOrUpdateModel ( chosenModel ) ;
191230
192231 this . container . telemetry . sendEvent (
193232 'ai/switchModel' ,
@@ -204,6 +243,24 @@ export class AIProviderService implements Disposable {
204243 return model ;
205244 }
206245
246+ private async ensureProviderConfigured ( providerId : AIProviders ) : Promise < boolean > {
247+ const key = await this . container . storage . getSecret ( `gitlens.${ providerId } .key` ) ;
248+ if ( key != null ) return true ;
249+
250+ if ( this . _provider != null && providerId === this . _provider . id ) return this . _provider . ensureConfigured ( ) ;
251+ const type = await _supportedProviderTypes . get ( providerId ) ?. value ;
252+ if ( type == null ) {
253+ return false ;
254+ }
255+
256+ const p = new type ( this . container , this . connection ) ;
257+ try {
258+ return await p . ensureConfigured ( ) ;
259+ } finally {
260+ p . dispose ( ) ;
261+ }
262+ }
263+
207264 private getOrUpdateModel ( model : AIModel ) : Promise < AIModel | undefined > ;
208265 private getOrUpdateModel < T extends AIProviders > ( providerId : T , modelId : string ) : Promise < AIModel | undefined > ;
209266 private async getOrUpdateModel (
@@ -592,6 +649,14 @@ export class AIProviderService implements Disposable {
592649 return changes ;
593650 }
594651
652+ async resetProvider ( provider : AIProviders ) : Promise < void > {
653+ void env . clipboard . writeText ( ( await this . container . storage . getSecret ( `gitlens.${ provider } .key` ) ) ?? '' ) ;
654+ void this . container . storage . deleteSecret ( `gitlens.${ provider } .key` ) ;
655+
656+ void this . container . storage . delete ( `confirm:ai:tos:${ provider } ` ) ;
657+ void this . container . storage . deleteWorkspace ( `confirm:ai:tos:${ provider } ` ) ;
658+ }
659+
595660 async reset ( all ?: boolean ) : Promise < void > {
596661 let { _provider : provider } = this ;
597662 if ( provider == null ) {
@@ -625,11 +690,7 @@ export class AIProviderService implements Disposable {
625690 }
626691
627692 if ( provider != null && result === resetCurrent ) {
628- void env . clipboard . writeText ( ( await this . container . storage . getSecret ( `gitlens.${ provider . id } .key` ) ) ?? '' ) ;
629- void this . container . storage . deleteSecret ( `gitlens.${ provider . id } .key` ) ;
630-
631- void this . container . storage . delete ( `confirm:ai:tos:${ provider . id } ` ) ;
632- void this . container . storage . deleteWorkspace ( `confirm:ai:tos:${ provider . id } ` ) ;
693+ void this . resetProvider ( provider . id ) ;
633694 } else if ( result === resetAll ) {
634695 const keys = [ ] ;
635696 for ( const [ providerId ] of _supportedProviderTypes ) {
0 commit comments