Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 6b186b4

Browse files
committed
fix: preserve selected model during AI-initiated mode switches
When the AI agent uses the switch_mode tool, the user's selected model should not change. Previously, handleModeSwitch would load mode-specific API configurations even for AI-initiated switches, unexpectedly changing the model mid-task. This adds a preserveApiConfig option to handleModeSwitch and passes it from SwitchModeTool so the current API config is preserved. User-initiated mode switches from the UI continue to load per-mode configs as before. Closes #12237
1 parent ad25634 commit 6b186b4

3 files changed

Lines changed: 30 additions & 5 deletions

File tree

src/core/tools/SwitchModeTool.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ export class SwitchModeTool extends BaseTool<"switch_mode"> {
5555
return
5656
}
5757

58-
// Switch the mode using shared handler
59-
await task.providerRef.deref()?.handleModeSwitch(mode_slug)
58+
// Switch the mode using shared handler, preserving the current API config
59+
// so the user's selected model doesn't change during AI-initiated switches.
60+
await task.providerRef.deref()?.handleModeSwitch(mode_slug, { preserveApiConfig: true })
6061

6162
pushToolResult(
6263
`Successfully switched from ${getModeBySlug(currentMode)?.name ?? currentMode} mode to ${

src/core/webview/ClineProvider.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,7 +1391,7 @@ export class ClineProvider
13911391
* Handle switching to a new mode, including updating the associated API configuration
13921392
* @param newMode The mode to switch to
13931393
*/
1394-
public async handleModeSwitch(newMode: Mode) {
1394+
public async handleModeSwitch(newMode: Mode, options?: { preserveApiConfig?: boolean }) {
13951395
const task = this.getCurrentTask()
13961396

13971397
if (task) {
@@ -1426,9 +1426,11 @@ export class ClineProvider
14261426

14271427
this.emit(RooCodeEventName.ModeChanged, newMode)
14281428

1429-
// If workspace lock is on, keep the current API config — don't load mode-specific config
1429+
// If workspace lock is on, or the caller explicitly requested preserving the current
1430+
// API config (e.g. AI-initiated mode switches via the switch_mode tool), keep the
1431+
// current API config — don't load mode-specific config.
14301432
const lockApiConfigAcrossModes = this.context.workspaceState.get("lockApiConfigAcrossModes", false)
1431-
if (lockApiConfigAcrossModes) {
1433+
if (lockApiConfigAcrossModes || options?.preserveApiConfig) {
14321434
await this.postStateToWebview()
14331435
return
14341436
}

src/core/webview/__tests__/ClineProvider.lockApiConfig.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,28 @@ describe("ClineProvider - Lock API Config Across Modes", () => {
342342
expect(activateProviderProfileSpy).not.toHaveBeenCalled()
343343
})
344344

345+
it("skips mode-specific config lookup/load when preserveApiConfig option is true", async () => {
346+
await mockContext.workspaceState.update("lockApiConfigAcrossModes", false)
347+
348+
const getModeConfigIdSpy = vi
349+
.spyOn(provider.providerSettingsManager, "getModeConfigId")
350+
.mockResolvedValue("architect-profile-id")
351+
const listConfigSpy = vi
352+
.spyOn(provider.providerSettingsManager, "listConfig")
353+
.mockResolvedValue([
354+
{ name: "architect-profile", id: "architect-profile-id", apiProvider: "anthropic" },
355+
])
356+
const activateProviderProfileSpy = vi
357+
.spyOn(provider, "activateProviderProfile")
358+
.mockResolvedValue(undefined)
359+
360+
await provider.handleModeSwitch("architect", { preserveApiConfig: true })
361+
362+
expect(getModeConfigIdSpy).not.toHaveBeenCalled()
363+
expect(listConfigSpy).not.toHaveBeenCalled()
364+
expect(activateProviderProfileSpy).not.toHaveBeenCalled()
365+
})
366+
345367
it("keeps normal mode-specific lookup/load behavior when lockApiConfigAcrossModes is false", async () => {
346368
await mockContext.workspaceState.update("lockApiConfigAcrossModes", false)
347369

0 commit comments

Comments
 (0)