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

fix(cli): resolve race condition causing provider switch during mode changes (#11205)

When using slash commands with `mode:` frontmatter (e.g., `/cli-release`
with `mode: code`), the CLI would fail with "Could not resolve
authentication method" from the Anthropic SDK, even when using a
non-Anthropic provider like `--provider roo`.

Root cause: In `markWebviewReady()`, the `webviewDidLaunch` message was
sent before `updateSettings`, creating a race condition. The
`webviewDidLaunch` handler's "first-time init" sync would read
`getState()` before CLI-provided settings were applied to the context
proxy. Since `getState()` defaults `apiProvider` to "anthropic" when
unset, this default was saved to the provider profile. When a slash
command triggered `handleModeSwitch()`, it found this corrupted profile
with `apiProvider: "anthropic"` (but no API key) and activated it,
overwriting the CLI's working roo provider configuration.

Fix:
1. Reorder `markWebviewReady()` to send `updateSettings` before
   `webviewDidLaunch`, ensuring the context proxy has CLI-provided
   values when the initialization handler runs.
2. Guard the first-time init sync with `checkExistKey(apiConfiguration)`
   to prevent saving a profile with only the default "anthropic"
   fallback and no actual API keys configured.

Co-authored-by: Claude Opus 4.5 <[email protected]>
Chris Estreich 1 неделя назад
Родитель
Сommit
aa49871a5d
2 измененных файлов с 19 добавлено и 9 удалено
  1. 8 4
      apps/cli/src/agent/extension-host.ts
  2. 11 5
      src/core/webview/webviewMessageHandler.ts

+ 8 - 4
apps/cli/src/agent/extension-host.ts

@@ -428,12 +428,16 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
 	public markWebviewReady(): void {
 		this.isReady = true
 
-		// Send initial webview messages to trigger proper extension initialization.
-		// This is critical for the extension to start sending state updates properly.
-		this.sendToExtension({ type: "webviewDidLaunch" })
-
+		// Apply CLI settings to the runtime config and context proxy BEFORE
+		// sending webviewDidLaunch. This prevents a race condition where the
+		// webviewDidLaunch handler's first-time init sync reads default state
+		// (apiProvider: "anthropic") instead of the CLI-provided settings.
 		setRuntimeConfigValues("roo-cline", this.initialSettings as Record<string, unknown>)
 		this.sendToExtension({ type: "updateSettings", updatedSettings: this.initialSettings })
+
+		// Now trigger extension initialization. The context proxy should already
+		// have CLI-provided values when the webviewDidLaunch handler runs.
+		this.sendToExtension({ type: "webviewDidLaunch" })
 	}
 
 	public isInInitialSetup(): boolean {

+ 11 - 5
src/core/webview/webviewMessageHandler.ts

@@ -498,12 +498,18 @@ export const webviewMessageHandler = async (
 						if (!checkExistKey(listApiConfig[0])) {
 							const { apiConfiguration } = await provider.getState()
 
-							await provider.providerSettingsManager.saveConfig(
-								listApiConfig[0].name ?? "default",
-								apiConfiguration,
-							)
+							// Only save if the current configuration has meaningful settings
+							// (e.g., API keys). This prevents saving a default "anthropic"
+							// fallback when no real config exists, which can happen during
+							// CLI initialization before provider settings are applied.
+							if (checkExistKey(apiConfiguration)) {
+								await provider.providerSettingsManager.saveConfig(
+									listApiConfig[0].name ?? "default",
+									apiConfiguration,
+								)
 
-							listApiConfig[0].apiProvider = apiConfiguration.apiProvider
+								listApiConfig[0].apiProvider = apiConfiguration.apiProvider
+							}
 						}
 					}