Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1463,16 +1463,10 @@ export class ClineProvider
// The task will continue with the current/default configuration.
}
} else {
// If no saved config for this mode, save current config as default.
const currentApiConfigNameAfter = this.getGlobalState("currentApiConfigName")

if (currentApiConfigNameAfter) {
const config = listApiConfig.find((c) => c.name === currentApiConfigNameAfter)

if (config?.id) {
await this.providerSettingsManager.setModeConfig(newMode, config.id)
}
}
// No saved config for this mode — leave the current config active
// without persisting it as the mode's default. This prevents config
// "bleed" where switching modes silently inherits and saves the
// previous mode's API configuration.
}

await this.postStateToWebview()
Expand Down
12 changes: 6 additions & 6 deletions src/core/webview/__tests__/ClineProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ describe("ClineProvider", () => {
expect(mockContext.globalState.update).toHaveBeenCalledWith("currentApiConfigName", "test-config")
})

it("saves current config when switching to mode without config", async () => {
it("does not auto-save current config when switching to mode without config", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]

Expand All @@ -907,8 +907,8 @@ describe("ClineProvider", () => {
// Switch to architect mode
await messageHandler({ type: "mode", text: "architect" })

// Should save current config as default for architect mode
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "current-id")
// Should NOT auto-save current config as default for the new mode
expect(provider.providerSettingsManager.setModeConfig).not.toHaveBeenCalled()
})

it("saves config as default for current mode when loading config", async () => {
Expand Down Expand Up @@ -1483,7 +1483,7 @@ describe("ClineProvider", () => {
expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: "state" }))
})

test("saves current config when switching to mode without config", async () => {
test("does not auto-save current config when switching to mode without config", async () => {
;(provider as any).providerSettingsManager = {
getModeConfigId: vi.fn().mockResolvedValue(undefined),
listConfig: vi
Expand All @@ -1506,8 +1506,8 @@ describe("ClineProvider", () => {
// Verify mode was updated
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")

// Verify current config was saved as default for new mode
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "current-id")
// Should NOT auto-save current config as default for the new mode
expect(provider.providerSettingsManager.setModeConfig).not.toHaveBeenCalled()

// Verify state was posted to webview
expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: "state" }))
Expand Down
20 changes: 15 additions & 5 deletions webview-ui/src/components/modes/ModesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ function getGroupName(group: GroupEntry): ToolGroup {
return Array.isArray(group) ? group[0] : group
}

const ModesView = () => {
interface ModesViewProps {
checkUnsaveChanges?: (then: () => void) => void
}

const ModesView = ({ checkUnsaveChanges }: ModesViewProps) => {
const { t } = useAppTranslation()

const {
Expand Down Expand Up @@ -913,10 +917,16 @@ const ModesView = () => {
<Select
value={currentApiConfigName}
onValueChange={(value) => {
vscode.postMessage({
type: "loadApiConfiguration",
text: value,
})
const doSwitch = () =>
vscode.postMessage({
type: "loadApiConfiguration",
text: value,
})
if (checkUnsaveChanges) {
checkUnsaveChanges(doSwitch)
} else {
doSwitch()
}
}}>
<SelectTrigger className="w-full">
<SelectValue placeholder={t("settings:common.select")} />
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/components/settings/SettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
)}

{/* Modes Section */}
{renderTab === "modes" && <ModesView />}
{renderTab === "modes" && <ModesView checkUnsaveChanges={checkUnsaveChanges} />}

{/* MCP Section */}
{renderTab === "mcp" && <McpView />}
Expand Down
Loading