Merge pull request #550 from RooVetGit/fix_switch_mode_command

Do a more complete mode switch from switch_mode command
This commit is contained in:
Matt Rubens
2025-01-24 23:30:06 -05:00
committed by GitHub
4 changed files with 108 additions and 35 deletions

View File

@@ -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

View File

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

View File

@@ -781,38 +781,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.postStateToWebview() await this.postStateToWebview()
break break
case "mode": case "mode":
const newMode = message.text as Mode await this.handleModeSwitch(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()
break break
case "updateSupportPrompt": case "updateSupportPrompt":
try { 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) { private async updateApiConfiguration(apiConfiguration: ApiConfiguration) {
// Update mode's default config // Update mode's default config
const { mode } = await this.getState() const { mode } = await this.getState()

View File

@@ -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", () => { describe("updateCustomMode", () => {
test("updates both file and state when updating custom mode", async () => { test("updates both file and state when updating custom mode", async () => {
provider.resolveWebviewView(mockWebviewView) provider.resolveWebviewView(mockWebviewView)