Skip to content

Commit 8c929ba

Browse files
committed
Do a more complete mode switch from switch_mode command
1 parent f502199 commit 8c929ba

File tree

4 files changed

+108
-35
lines changed

4 files changed

+108
-35
lines changed

.changeset/stupid-parrots-grin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Fix bug where the saved API provider for a mode wasn't being selected after a mode switch command

src/core/Cline.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,11 +2065,10 @@ export class Cline {
20652065
break
20662066
}
20672067

2068-
// Switch the mode
2068+
// Switch the mode using shared handler
20692069
const provider = this.providerRef.deref()
20702070
if (provider) {
2071-
await provider.updateGlobalState("mode", mode_slug)
2072-
await provider.postStateToWebview()
2071+
await provider.handleModeSwitch(mode_slug)
20732072
}
20742073
pushToolResult(
20752074
`Successfully switched from ${getModeBySlug(currentMode)?.name ?? currentMode} mode to ${

src/core/webview/ClineProvider.ts

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -781,38 +781,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
781781
await this.postStateToWebview()
782782
break
783783
case "mode":
784-
const newMode = message.text as Mode
785-
await this.updateGlobalState("mode", newMode)
786-
787-
// Load the saved API config for the new mode if it exists
788-
const savedConfigId = await this.configManager.getModeConfigId(newMode)
789-
const listApiConfig = await this.configManager.listConfig()
790-
791-
// Update listApiConfigMeta first to ensure UI has latest data
792-
await this.updateGlobalState("listApiConfigMeta", listApiConfig)
793-
794-
// If this mode has a saved config, use it
795-
if (savedConfigId) {
796-
const config = listApiConfig?.find((c) => c.id === savedConfigId)
797-
if (config?.name) {
798-
const apiConfig = await this.configManager.loadConfig(config.name)
799-
await Promise.all([
800-
this.updateGlobalState("currentApiConfigName", config.name),
801-
this.updateApiConfiguration(apiConfig),
802-
])
803-
}
804-
} else {
805-
// If no saved config for this mode, save current config as default
806-
const currentApiConfigName = await this.getGlobalState("currentApiConfigName")
807-
if (currentApiConfigName) {
808-
const config = listApiConfig?.find((c) => c.name === currentApiConfigName)
809-
if (config?.id) {
810-
await this.configManager.setModeConfig(newMode, config.id)
811-
}
812-
}
813-
}
814-
815-
await this.postStateToWebview()
784+
await this.handleModeSwitch(message.text as Mode)
816785
break
817786
case "updateSupportPrompt":
818787
try {
@@ -1241,6 +1210,44 @@ export class ClineProvider implements vscode.WebviewViewProvider {
12411210
)
12421211
}
12431212

1213+
/**
1214+
* Handle switching to a new mode, including updating the associated API configuration
1215+
* @param newMode The mode to switch to
1216+
*/
1217+
public async handleModeSwitch(newMode: Mode) {
1218+
await this.updateGlobalState("mode", newMode)
1219+
1220+
// Load the saved API config for the new mode if it exists
1221+
const savedConfigId = await this.configManager.getModeConfigId(newMode)
1222+
const listApiConfig = await this.configManager.listConfig()
1223+
1224+
// Update listApiConfigMeta first to ensure UI has latest data
1225+
await this.updateGlobalState("listApiConfigMeta", listApiConfig)
1226+
1227+
// If this mode has a saved config, use it
1228+
if (savedConfigId) {
1229+
const config = listApiConfig?.find((c) => c.id === savedConfigId)
1230+
if (config?.name) {
1231+
const apiConfig = await this.configManager.loadConfig(config.name)
1232+
await Promise.all([
1233+
this.updateGlobalState("currentApiConfigName", config.name),
1234+
this.updateApiConfiguration(apiConfig),
1235+
])
1236+
}
1237+
} else {
1238+
// If no saved config for this mode, save current config as default
1239+
const currentApiConfigName = await this.getGlobalState("currentApiConfigName")
1240+
if (currentApiConfigName) {
1241+
const config = listApiConfig?.find((c) => c.name === currentApiConfigName)
1242+
if (config?.id) {
1243+
await this.configManager.setModeConfig(newMode, config.id)
1244+
}
1245+
}
1246+
}
1247+
1248+
await this.postStateToWebview()
1249+
}
1250+
12441251
private async updateApiConfiguration(apiConfiguration: ApiConfiguration) {
12451252
// Update mode's default config
12461253
const { mode } = await this.getState()

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,68 @@ describe("ClineProvider", () => {
11001100
})
11011101
})
11021102

1103+
describe("handleModeSwitch", () => {
1104+
beforeEach(() => {
1105+
// Set up webview for each test
1106+
provider.resolveWebviewView(mockWebviewView)
1107+
})
1108+
1109+
test("loads saved API config when switching modes", async () => {
1110+
// Mock ConfigManager methods
1111+
provider.configManager = {
1112+
getModeConfigId: jest.fn().mockResolvedValue("saved-config-id"),
1113+
listConfig: jest
1114+
.fn()
1115+
.mockResolvedValue([{ name: "saved-config", id: "saved-config-id", apiProvider: "anthropic" }]),
1116+
loadConfig: jest.fn().mockResolvedValue({ apiProvider: "anthropic" }),
1117+
setModeConfig: jest.fn(),
1118+
} as any
1119+
1120+
// Switch to architect mode
1121+
await provider.handleModeSwitch("architect")
1122+
1123+
// Verify mode was updated
1124+
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
1125+
1126+
// Verify saved config was loaded
1127+
expect(provider.configManager.getModeConfigId).toHaveBeenCalledWith("architect")
1128+
expect(provider.configManager.loadConfig).toHaveBeenCalledWith("saved-config")
1129+
expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "saved-config")
1130+
1131+
// Verify state was posted to webview
1132+
expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: "state" }))
1133+
})
1134+
1135+
test("saves current config when switching to mode without config", async () => {
1136+
// Mock ConfigManager methods
1137+
provider.configManager = {
1138+
getModeConfigId: jest.fn().mockResolvedValue(undefined),
1139+
listConfig: jest
1140+
.fn()
1141+
.mockResolvedValue([{ name: "current-config", id: "current-id", apiProvider: "anthropic" }]),
1142+
setModeConfig: jest.fn(),
1143+
} as any
1144+
1145+
// Mock current config name
1146+
mockContext.globalState.get = jest.fn((key: string) => {
1147+
if (key === "currentApiConfigName") return "current-config"
1148+
return undefined
1149+
})
1150+
1151+
// Switch to architect mode
1152+
await provider.handleModeSwitch("architect")
1153+
1154+
// Verify mode was updated
1155+
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
1156+
1157+
// Verify current config was saved as default for new mode
1158+
expect(provider.configManager.setModeConfig).toHaveBeenCalledWith("architect", "current-id")
1159+
1160+
// Verify state was posted to webview
1161+
expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: "state" }))
1162+
})
1163+
})
1164+
11031165
describe("updateCustomMode", () => {
11041166
test("updates both file and state when updating custom mode", async () => {
11051167
provider.resolveWebviewView(mockWebviewView)

0 commit comments

Comments
 (0)