@@ -4,7 +4,7 @@ import * as vscode from 'vscode'
4
4
import * as llmModule from '../../core/llm'
5
5
import { CONFIG_KEYS , SUPPORTED_PROVIDERS } from '../../core/llm/constants'
6
6
import * as workspaceConfigUtils from '../../utils/workspace-config'
7
- import { selectProvider } from '../providerCommands'
7
+ import { selectLLM , selectProvider } from '../providerCommands'
8
8
9
9
suite ( 'Provider Commands Tests' , ( ) => {
10
10
let sandbox : sinon . SinonSandbox
@@ -211,4 +211,161 @@ suite('Provider Commands Tests', () => {
211
211
assert . ok ( showInformationMessageStub . firstCall . args [ 0 ] . includes ( 'Successfully configured' ) )
212
212
} )
213
213
} )
214
+
215
+ suite ( 'selectLLM' , ( ) => {
216
+ test ( 'should return false when provider or API key is not configured' , async ( ) => {
217
+ // Simulate missing provider and API key
218
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( undefined )
219
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( undefined )
220
+
221
+ const result = await selectLLM ( )
222
+
223
+ assert . strictEqual ( result , false )
224
+ assert . strictEqual ( showWarningMessageStub . calledOnce , true )
225
+ assert . strictEqual (
226
+ showWarningMessageStub . firstCall . args [ 0 ] ,
227
+ 'Provider and API key must be configured first. Use the "Select LLM Provider" command.'
228
+ )
229
+ assert . strictEqual ( showQuickPickStub . called , false ) // No further prompts
230
+ } )
231
+
232
+ test ( 'should return false when provider code is invalid' , async ( ) => {
233
+ // Simulate configured but invalid provider
234
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( 'invalid-provider' )
235
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( 'test-api-key' )
236
+
237
+ const result = await selectLLM ( )
238
+
239
+ assert . strictEqual ( result , false )
240
+ assert . strictEqual ( showErrorMessageStub . calledOnce , true )
241
+ assert . strictEqual (
242
+ showErrorMessageStub . firstCall . args [ 0 ] ,
243
+ "Configuration Error: Invalid provider code 'invalid-provider'."
244
+ )
245
+ assert . strictEqual ( showQuickPickStub . called , false ) // No further prompts
246
+ } )
247
+
248
+ test ( 'should return false when model selection is cancelled' , async ( ) => {
249
+ // Mock valid configuration
250
+ const mockProvider = SUPPORTED_PROVIDERS [ 0 ]
251
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( mockProvider . code )
252
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( 'test-api-key' )
253
+ configGet . withArgs ( CONFIG_KEYS . MODEL ) . returns ( 'current-model' )
254
+
255
+ // Simulate user cancelling model selection
256
+ showQuickPickStub . resolves ( undefined )
257
+
258
+ const result = await selectLLM ( )
259
+
260
+ assert . strictEqual ( result , false )
261
+ assert . strictEqual ( showQuickPickStub . calledOnce , true )
262
+ assert . strictEqual ( showInformationMessageStub . calledOnce , true )
263
+ assert . strictEqual ( showInformationMessageStub . firstCall . args [ 0 ] , 'Model selection cancelled.' )
264
+ } )
265
+
266
+ test ( 'should handle model fetch errors and fall back to input box' , async ( ) => {
267
+ // Mock valid configuration
268
+ const mockProvider = SUPPORTED_PROVIDERS [ 0 ]
269
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( mockProvider . code )
270
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( 'test-api-key' )
271
+ configGet . withArgs ( CONFIG_KEYS . MODEL ) . returns ( 'current-model' )
272
+
273
+ // Simulate models fetch error
274
+ fetchModelsStub . rejects ( new Error ( 'Network error' ) )
275
+
276
+ // Mock model input (after fetch error)
277
+ showInputBoxStub . resolves ( 'new-model' )
278
+
279
+ const result = await selectLLM ( )
280
+
281
+ assert . strictEqual ( result , true )
282
+ assert . strictEqual ( showWarningMessageStub . calledOnce , true )
283
+ assert . ok ( showWarningMessageStub . firstCall . args [ 0 ] . includes ( 'Could not fetch models' ) )
284
+ assert . strictEqual ( showInputBoxStub . calledOnce , true )
285
+ assert . strictEqual ( updateModelConfigStub . calledOnceWith ( 'new-model' ) , true )
286
+ } )
287
+
288
+ test ( 'should return true without updating when selected model is the same as current' , async ( ) => {
289
+ // Mock valid configuration
290
+ const mockProvider = SUPPORTED_PROVIDERS [ 0 ]
291
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( mockProvider . code )
292
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( 'test-api-key' )
293
+ configGet . withArgs ( CONFIG_KEYS . MODEL ) . returns ( 'current-model' )
294
+
295
+ // Simulate user selecting the same model
296
+ showQuickPickStub . resolves ( 'current-model' )
297
+
298
+ const result = await selectLLM ( )
299
+
300
+ assert . strictEqual ( result , true )
301
+ assert . strictEqual ( showQuickPickStub . calledOnce , true )
302
+ assert . strictEqual ( showInformationMessageStub . calledOnce , true )
303
+ assert . strictEqual (
304
+ showInformationMessageStub . firstCall . args [ 0 ] ,
305
+ 'Selected model is the same as the current one. No changes made.'
306
+ )
307
+ assert . strictEqual ( updateModelConfigStub . called , false ) // Config not updated
308
+ } )
309
+
310
+ test ( 'should successfully update model configuration for OpenAI-compatible provider' , async ( ) => {
311
+ // Find the OpenAI Compatible provider
312
+ const openAICompatibleProvider = SUPPORTED_PROVIDERS . find (
313
+ p => p . code === 'openai-compatible'
314
+ ) !
315
+
316
+ // Mock valid configuration
317
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( openAICompatibleProvider . code )
318
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( 'test-api-key' )
319
+ configGet . withArgs ( CONFIG_KEYS . OPENAI_BASE_URL ) . returns ( 'https://custom-api.com' )
320
+ configGet . withArgs ( CONFIG_KEYS . MODEL ) . returns ( 'current-model' )
321
+
322
+ // Simulate user selecting a different model
323
+ showQuickPickStub . resolves ( 'new-model' )
324
+
325
+ const result = await selectLLM ( )
326
+
327
+ assert . strictEqual ( result , true )
328
+ assert . strictEqual ( showQuickPickStub . calledOnce , true )
329
+ assert . strictEqual ( createProviderStub . calledOnce , true )
330
+ assert . deepStrictEqual ( createProviderStub . firstCall . args , [
331
+ openAICompatibleProvider . code ,
332
+ {
333
+ apiKey : 'test-api-key' ,
334
+ baseUrl : 'https://custom-api.com'
335
+ }
336
+ ] )
337
+ assert . strictEqual ( updateModelConfigStub . calledOnceWith ( 'new-model' ) , true )
338
+ assert . strictEqual ( showInformationMessageStub . calledOnce , true )
339
+ assert . strictEqual (
340
+ showInformationMessageStub . firstCall . args [ 0 ] ,
341
+ 'Successfully updated LLM model to new-model'
342
+ )
343
+ } )
344
+
345
+ test ( 'should handle config update errors' , async ( ) => {
346
+ // Mock valid configuration
347
+ const mockProvider = SUPPORTED_PROVIDERS [ 0 ]
348
+ configGet . withArgs ( CONFIG_KEYS . PROVIDER ) . returns ( mockProvider . code )
349
+ configGet . withArgs ( CONFIG_KEYS . API_KEY ) . returns ( 'test-api-key' )
350
+ configGet . withArgs ( CONFIG_KEYS . MODEL ) . returns ( 'current-model' )
351
+
352
+ // Simulate user selecting a new model
353
+ showQuickPickStub . resolves ( 'new-model' )
354
+
355
+ // Mock configuration update error
356
+ const updateError = new Error ( 'Configuration update failed' )
357
+ updateModelConfigStub . rejects ( updateError )
358
+
359
+ const result = await selectLLM ( )
360
+
361
+ assert . strictEqual ( result , false )
362
+ assert . strictEqual ( showQuickPickStub . calledOnce , true )
363
+ assert . strictEqual ( updateModelConfigStub . calledOnceWith ( 'new-model' ) , true )
364
+ assert . strictEqual ( showErrorMessageStub . calledOnce , true )
365
+ assert . strictEqual (
366
+ showErrorMessageStub . firstCall . args [ 0 ] ,
367
+ 'Failed to save model configuration: Configuration update failed'
368
+ )
369
+ } )
370
+ } )
214
371
} )
0 commit comments