Просмотр исходного кода

Merge pull request #550 from RooVetGit/fix_switch_mode_command

Do a more complete mode switch from switch_mode command
Matt Rubens 11 месяцев назад
Родитель
Сommit
bf49b3ea61

+ 5 - 0
.changeset/stupid-parrots-grin.md

@@ -0,0 +1,5 @@
+---
+"roo-cline": patch
+---
+
+Fix bug where the saved API provider for a mode wasn't being selected after a mode switch command

+ 2 - 3
src/core/Cline.ts

@@ -2065,11 +2065,10 @@ export class Cline {
 									break
 								}
 
-								// Switch the mode
+								// Switch the mode using shared handler
 								const provider = this.providerRef.deref()
 								if (provider) {
-									await provider.updateGlobalState("mode", mode_slug)
-									await provider.postStateToWebview()
+									await provider.handleModeSwitch(mode_slug)
 								}
 								pushToolResult(
 									`Successfully switched from ${getModeBySlug(currentMode)?.name ?? currentMode} mode to ${

+ 39 - 32
src/core/webview/ClineProvider.ts

@@ -781,38 +781,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 						await this.postStateToWebview()
 						break
 					case "mode":
-						const newMode = message.text as Mode
-						await this.updateGlobalState("mode", newMode)
-
-						// Load the saved API config for the new mode if it exists
-						const savedConfigId = await this.configManager.getModeConfigId(newMode)
-						const listApiConfig = await this.configManager.listConfig()
-
-						// Update listApiConfigMeta first to ensure UI has latest data
-						await this.updateGlobalState("listApiConfigMeta", listApiConfig)
-
-						// If this mode has a saved config, use it
-						if (savedConfigId) {
-							const config = listApiConfig?.find((c) => c.id === savedConfigId)
-							if (config?.name) {
-								const apiConfig = await this.configManager.loadConfig(config.name)
-								await Promise.all([
-									this.updateGlobalState("currentApiConfigName", config.name),
-									this.updateApiConfiguration(apiConfig),
-								])
-							}
-						} else {
-							// If no saved config for this mode, save current config as default
-							const currentApiConfigName = await this.getGlobalState("currentApiConfigName")
-							if (currentApiConfigName) {
-								const config = listApiConfig?.find((c) => c.name === currentApiConfigName)
-								if (config?.id) {
-									await this.configManager.setModeConfig(newMode, config.id)
-								}
-							}
-						}
-
-						await this.postStateToWebview()
+						await this.handleModeSwitch(message.text as Mode)
 						break
 					case "updateSupportPrompt":
 						try {
@@ -1241,6 +1210,44 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 		)
 	}
 
+	/**
+	 * Handle switching to a new mode, including updating the associated API configuration
+	 * @param newMode The mode to switch to
+	 */
+	public async handleModeSwitch(newMode: Mode) {
+		await this.updateGlobalState("mode", newMode)
+
+		// Load the saved API config for the new mode if it exists
+		const savedConfigId = await this.configManager.getModeConfigId(newMode)
+		const listApiConfig = await this.configManager.listConfig()
+
+		// Update listApiConfigMeta first to ensure UI has latest data
+		await this.updateGlobalState("listApiConfigMeta", listApiConfig)
+
+		// If this mode has a saved config, use it
+		if (savedConfigId) {
+			const config = listApiConfig?.find((c) => c.id === savedConfigId)
+			if (config?.name) {
+				const apiConfig = await this.configManager.loadConfig(config.name)
+				await Promise.all([
+					this.updateGlobalState("currentApiConfigName", config.name),
+					this.updateApiConfiguration(apiConfig),
+				])
+			}
+		} else {
+			// If no saved config for this mode, save current config as default
+			const currentApiConfigName = await this.getGlobalState("currentApiConfigName")
+			if (currentApiConfigName) {
+				const config = listApiConfig?.find((c) => c.name === currentApiConfigName)
+				if (config?.id) {
+					await this.configManager.setModeConfig(newMode, config.id)
+				}
+			}
+		}
+
+		await this.postStateToWebview()
+	}
+
 	private async updateApiConfiguration(apiConfiguration: ApiConfiguration) {
 		// Update mode's default config
 		const { mode } = await this.getState()

+ 62 - 0
src/core/webview/__tests__/ClineProvider.test.ts

@@ -1100,6 +1100,68 @@ describe("ClineProvider", () => {
 		})
 	})
 
+	describe("handleModeSwitch", () => {
+		beforeEach(() => {
+			// Set up webview for each test
+			provider.resolveWebviewView(mockWebviewView)
+		})
+
+		test("loads saved API config when switching modes", async () => {
+			// Mock ConfigManager methods
+			provider.configManager = {
+				getModeConfigId: jest.fn().mockResolvedValue("saved-config-id"),
+				listConfig: jest
+					.fn()
+					.mockResolvedValue([{ name: "saved-config", id: "saved-config-id", apiProvider: "anthropic" }]),
+				loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
+				setModeConfig: jest.fn(),
+			} as any
+
+			// Switch to architect mode
+			await provider.handleModeSwitch("architect")
+
+			// Verify mode was updated
+			expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
+
+			// Verify saved config was loaded
+			expect(provider.configManager.getModeConfigId).toHaveBeenCalledWith("architect")
+			expect(provider.configManager.loadConfig).toHaveBeenCalledWith("saved-config")
+			expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "saved-config")
+
+			// Verify state was posted to webview
+			expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: "state" }))
+		})
+
+		test("saves current config when switching to mode without config", async () => {
+			// Mock ConfigManager methods
+			provider.configManager = {
+				getModeConfigId: jest.fn().mockResolvedValue(undefined),
+				listConfig: jest
+					.fn()
+					.mockResolvedValue([{ name: "current-config", id: "current-id", apiProvider: "anthropic" }]),
+				setModeConfig: jest.fn(),
+			} as any
+
+			// Mock current config name
+			mockContext.globalState.get = jest.fn((key: string) => {
+				if (key === "currentApiConfigName") return "current-config"
+				return undefined
+			})
+
+			// Switch to architect mode
+			await provider.handleModeSwitch("architect")
+
+			// Verify mode was updated
+			expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
+
+			// Verify current config was saved as default for new mode
+			expect(provider.configManager.setModeConfig).toHaveBeenCalledWith("architect", "current-id")
+
+			// Verify state was posted to webview
+			expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: "state" }))
+		})
+	})
+
 	describe("updateCustomMode", () => {
 		test("updates both file and state when updating custom mode", async () => {
 			provider.resolveWebviewView(mockWebviewView)