Skip to content

Commit 6bde947

Browse files
committed
Simplify the process of setting the "active" provider profile
1 parent ee2033c commit 6bde947

File tree

6 files changed

+119
-163
lines changed

6 files changed

+119
-163
lines changed

src/core/config/ProviderSettingsManager.ts

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -259,51 +259,47 @@ export class ProviderSettingsManager {
259259
}
260260

261261
/**
262-
* Load a config by name and set it as the current config.
262+
* Activate a profile by name or ID.
263263
*/
264-
public async loadConfig(name: string) {
264+
public async activateProfile(
265+
params: { name: string } | { id: string },
266+
): Promise<ProviderSettingsWithId & { name: string }> {
265267
try {
266268
return await this.lock(async () => {
267269
const providerProfiles = await this.load()
268-
const providerSettings = providerProfiles.apiConfigs[name]
270+
let name: string
271+
let providerSettings: ProviderSettingsWithId
269272

270-
if (!providerSettings) {
271-
throw new Error(`Config '${name}' not found`)
272-
}
273+
if ("name" in params) {
274+
name = params.name
273275

274-
providerProfiles.currentApiConfigName = name
275-
await this.store(providerProfiles)
276+
if (!providerProfiles.apiConfigs[name]) {
277+
throw new Error(`Config with name '${name}' not found`)
278+
}
276279

277-
return providerSettings
278-
})
279-
} catch (error) {
280-
throw new Error(`Failed to load config: ${error}`)
281-
}
282-
}
280+
providerSettings = providerProfiles.apiConfigs[name]
281+
} else {
282+
const id = params.id
283283

284-
/**
285-
* Load a config by ID and set it as the current config.
286-
*/
287-
public async loadConfigById(id: string) {
288-
try {
289-
return await this.lock(async () => {
290-
const providerProfiles = await this.load()
291-
const providerSettings = Object.entries(providerProfiles.apiConfigs).find(
292-
([_, apiConfig]) => apiConfig.id === id,
293-
)
284+
const entry = Object.entries(providerProfiles.apiConfigs).find(
285+
([_, apiConfig]) => apiConfig.id === id,
286+
)
287+
288+
if (!entry) {
289+
throw new Error(`Config with ID '${id}' not found`)
290+
}
294291

295-
if (!providerSettings) {
296-
throw new Error(`Config with ID '${id}' not found`)
292+
name = entry[0]
293+
providerSettings = entry[1]
297294
}
298295

299-
const [name, apiConfig] = providerSettings
300296
providerProfiles.currentApiConfigName = name
301297
await this.store(providerProfiles)
302298

303-
return { config: apiConfig, name }
299+
return { name, ...providerSettings }
304300
})
305301
} catch (error) {
306-
throw new Error(`Failed to load config by ID: ${error}`)
302+
throw new Error(`Failed to load config: ${error}`)
307303
}
308304
}
309305

src/core/config/__tests__/ProviderSettingsManager.test.ts

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -391,17 +391,15 @@ describe("ProviderSettingsManager", () => {
391391
mockGlobalState.get.mockResolvedValue(42)
392392
mockSecrets.get.mockResolvedValue(JSON.stringify(existingConfig))
393393

394-
const config = await providerSettingsManager.loadConfig("test")
394+
const { name, ...providerSettings } = await providerSettingsManager.activateProfile({ name: "test" })
395395

396-
expect(config).toEqual({
397-
apiProvider: "anthropic",
398-
apiKey: "test-key",
399-
id: "test-id",
400-
})
396+
expect(name).toBe("test")
397+
expect(providerSettings).toEqual({ apiProvider: "anthropic", apiKey: "test-key", id: "test-id" })
401398

402-
// Get the stored config to check the structure
399+
// Get the stored config to check the structure.
403400
const storedConfig = JSON.parse(mockSecrets.store.mock.calls[1][1])
404401
expect(storedConfig.currentApiConfigName).toBe("test")
402+
405403
expect(storedConfig.apiConfigs.test).toEqual({
406404
apiProvider: "anthropic",
407405
apiKey: "test-key",
@@ -413,37 +411,25 @@ describe("ProviderSettingsManager", () => {
413411
mockSecrets.get.mockResolvedValue(
414412
JSON.stringify({
415413
currentApiConfigName: "default",
416-
apiConfigs: {
417-
default: {
418-
config: {},
419-
id: "default",
420-
},
421-
},
414+
apiConfigs: { default: { config: {}, id: "default" } },
422415
}),
423416
)
424417

425-
await expect(providerSettingsManager.loadConfig("nonexistent")).rejects.toThrow(
426-
"Config 'nonexistent' not found",
418+
await expect(providerSettingsManager.activateProfile({ name: "nonexistent" })).rejects.toThrow(
419+
"Config with name 'nonexistent' not found",
427420
)
428421
})
429422

430423
it("should throw error if secrets storage fails", async () => {
431424
mockSecrets.get.mockResolvedValue(
432425
JSON.stringify({
433426
currentApiConfigName: "default",
434-
apiConfigs: {
435-
test: {
436-
config: {
437-
apiProvider: "anthropic",
438-
},
439-
id: "test-id",
440-
},
441-
},
427+
apiConfigs: { test: { config: { apiProvider: "anthropic" }, id: "test-id" } },
442428
}),
443429
)
444430
mockSecrets.store.mockRejectedValueOnce(new Error("Storage failed"))
445431

446-
await expect(providerSettingsManager.loadConfig("test")).rejects.toThrow(
432+
await expect(providerSettingsManager.activateProfile({ name: "test" })).rejects.toThrow(
447433
"Failed to load config: Error: Failed to write provider profiles to secrets: Error: Storage failed",
448434
)
449435
})
@@ -494,12 +480,7 @@ describe("ProviderSettingsManager", () => {
494480
mockSecrets.get.mockResolvedValue(
495481
JSON.stringify({
496482
currentApiConfigName: "test",
497-
apiConfigs: {
498-
test: {
499-
apiProvider: "anthropic",
500-
id: "test-id",
501-
},
502-
},
483+
apiConfigs: { test: { apiProvider: "anthropic", id: "test-id" } },
503484
}),
504485
)
505486

@@ -514,18 +495,8 @@ describe("ProviderSettingsManager", () => {
514495
it("should return true for existing config", async () => {
515496
const existingConfig: ProviderProfiles = {
516497
currentApiConfigName: "default",
517-
apiConfigs: {
518-
default: {
519-
id: "default",
520-
},
521-
test: {
522-
apiProvider: "anthropic",
523-
id: "test-id",
524-
},
525-
},
526-
migrations: {
527-
rateLimitSecondsMigrated: false,
528-
},
498+
apiConfigs: { default: { id: "default" }, test: { apiProvider: "anthropic", id: "test-id" } },
499+
migrations: { rateLimitSecondsMigrated: false },
529500
}
530501

531502
mockSecrets.get.mockResolvedValue(JSON.stringify(existingConfig))
@@ -536,10 +507,7 @@ describe("ProviderSettingsManager", () => {
536507

537508
it("should return false for non-existent config", async () => {
538509
mockSecrets.get.mockResolvedValue(
539-
JSON.stringify({
540-
currentApiConfigName: "default",
541-
apiConfigs: { default: {} },
542-
}),
510+
JSON.stringify({ currentApiConfigName: "default", apiConfigs: { default: {} } }),
543511
)
544512

545513
const hasConfig = await providerSettingsManager.hasConfig("nonexistent")

src/core/webview/ClineProvider.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,9 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
784784
const config = listApiConfig?.find((c) => c.id === savedConfigId)
785785

786786
if (config?.name) {
787-
const apiConfig = await this.providerSettingsManager.loadConfig(config.name)
787+
const { name: _, ...apiConfig } = await this.providerSettingsManager.activateProfile({
788+
name: config.name,
789+
})
788790

789791
await Promise.all([
790792
this.updateGlobalState("currentApiConfigName", config.name),
@@ -807,6 +809,18 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
807809
await this.postStateToWebview()
808810
}
809811

812+
async activateProviderProfile(args: { name: string } | { id: string }) {
813+
const { name, ...providerSettings } = await this.providerSettingsManager.activateProfile(args)
814+
815+
await Promise.all([
816+
this.contextProxy.setValue("listApiConfigMeta", await this.providerSettingsManager.listConfig()),
817+
this.contextProxy.setValue("currentApiConfigName", name),
818+
this.updateApiConfiguration(providerSettings),
819+
])
820+
821+
await this.postStateToWebview()
822+
}
823+
810824
async updateApiConfiguration(providerSettings: ProviderSettings) {
811825
// Update mode's default config.
812826
const { mode } = await this.getState()

src/core/webview/__tests__/ClineProvider.test.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ describe("ClineProvider", () => {
603603
;(provider as any).providerSettingsManager = {
604604
getModeConfigId: jest.fn().mockResolvedValue("test-id"),
605605
listConfig: jest.fn().mockResolvedValue([{ name: "test-config", id: "test-id", apiProvider: "anthropic" }]),
606-
loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
606+
activateProfile: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
607607
setModeConfig: jest.fn(),
608608
} as any
609609

@@ -612,7 +612,7 @@ describe("ClineProvider", () => {
612612

613613
// Should load the saved config for architect mode
614614
expect(provider.providerSettingsManager.getModeConfigId).toHaveBeenCalledWith("architect")
615-
expect(provider.providerSettingsManager.loadConfig).toHaveBeenCalledWith("test-config")
615+
expect(provider.providerSettingsManager.activateProfile).toHaveBeenCalledWith({ name: "test-config" })
616616
expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "test-config")
617617
})
618618

@@ -642,8 +642,7 @@ describe("ClineProvider", () => {
642642
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
643643

644644
;(provider as any).providerSettingsManager = {
645-
loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic", id: "new-id" }),
646-
loadConfigById: jest
645+
activateProfile: jest
647646
.fn()
648647
.mockResolvedValue({ config: { apiProvider: "anthropic", id: "new-id" }, name: "new-config" }),
649648
listConfig: jest.fn().mockResolvedValue([{ name: "new-config", id: "new-id", apiProvider: "anthropic" }]),
@@ -666,7 +665,7 @@ describe("ClineProvider", () => {
666665
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
667666

668667
;(provider as any).providerSettingsManager = {
669-
loadConfigById: jest.fn().mockResolvedValue({
668+
activateProfile: jest.fn().mockResolvedValue({
670669
config: { apiProvider: "anthropic", id: "config-id-123" },
671670
name: "config-by-id",
672671
}),
@@ -686,8 +685,8 @@ describe("ClineProvider", () => {
686685
// Should save new config as default for architect mode
687686
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "config-id-123")
688687

689-
// Ensure the loadConfigById method was called with the correct ID
690-
expect(provider.providerSettingsManager.loadConfigById).toHaveBeenCalledWith("config-id-123")
688+
// Ensure the `activateProfile` method was called with the correct ID
689+
expect(provider.providerSettingsManager.activateProfile).toHaveBeenCalledWith({ id: "config-id-123" })
691690
})
692691

693692
test("handles browserToolEnabled setting", async () => {
@@ -1542,13 +1541,13 @@ describe("ClineProvider", () => {
15421541
await provider.resolveWebviewView(mockWebviewView)
15431542
})
15441543

1545-
test("loads saved API config when switching modes", async () => {
1544+
it("loads saved API config when switching modes", async () => {
15461545
;(provider as any).providerSettingsManager = {
15471546
getModeConfigId: jest.fn().mockResolvedValue("saved-config-id"),
15481547
listConfig: jest
15491548
.fn()
15501549
.mockResolvedValue([{ name: "saved-config", id: "saved-config-id", apiProvider: "anthropic" }]),
1551-
loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
1550+
activateProfile: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
15521551
setModeConfig: jest.fn(),
15531552
} as any
15541553

@@ -1560,7 +1559,7 @@ describe("ClineProvider", () => {
15601559

15611560
// Verify saved config was loaded
15621561
expect(provider.providerSettingsManager.getModeConfigId).toHaveBeenCalledWith("architect")
1563-
expect(provider.providerSettingsManager.loadConfig).toHaveBeenCalledWith("saved-config")
1562+
expect(provider.providerSettingsManager.activateProfile).toHaveBeenCalledWith({ name: "saved-config" })
15641563
expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "saved-config")
15651564

15661565
// Verify state was posted to webview

0 commit comments

Comments
 (0)