fix(coding-agent/modes): fixed model switches deferred during streaming to apply correctly on completion

- Fixed model switches deferred during streaming to apply correctly when the stream completes, preventing model changes from being lost.
- Added pendingModelSwitch field to track deferred model changes during active streams.
- Added flushPendingModelSwitch() method to apply deferred model switches after streaming completes.
- Modified switchToPlanModel() to defer model changes when a stream is active instead of applying immediately.
- Modified exitPlanMode() to defer model restoration when a stream is active instead of applying immediately.
- Modified EventController to call flushPendingModelSwitch() when stream completion is detected.
This commit is contained in:
can1357
2026-02-05 09:31:54 +01:00
parent f69671676d
commit 251d5a91ef
3 changed files with 26 additions and 2 deletions
+1 -1
View File
@@ -1,7 +1,6 @@
# Changelog
## [Unreleased]
### Added
- Support for image file mentions—images are now automatically detected, resized, and attached when referenced with @filepath syntax
@@ -14,6 +13,7 @@
### Fixed
- Fixed model switches deferred during streaming to apply correctly when the stream completes, preventing model changes from being lost
- Fixed plan mode toggles during streaming to inject plan-mode context immediately, preventing file edits while in plan mode
- Fixed plan mode model switches during streaming to defer model changes until the current turn completes
@@ -269,6 +269,7 @@ export class EventController {
this.ctx.streamingComponent = undefined;
this.ctx.streamingMessage = undefined;
}
await this.ctx.flushPendingModelSwitch();
this.ctx.pendingTools.clear();
this.ctx.ui.requestRender();
this.sendCompletionNotification();
@@ -136,6 +136,7 @@ export class InteractiveMode implements InteractiveModeContext {
private readonly changelogMarkdown: string | undefined;
private planModePreviousTools: string[] | undefined;
private planModePreviousModel: Model | undefined;
private pendingModelSwitch: Model | undefined;
private planModeHasEntered = false;
public readonly lspServers:
| Array<{ name: string; status: "ready" | "error"; fileTypes: string[]; error?: string }>
@@ -533,6 +534,10 @@ export class InteractiveMode implements InteractiveModeContext {
return;
}
this.planModePreviousModel = currentModel;
if (this.session.isStreaming) {
this.pendingModelSwitch = planModel;
return;
}
try {
await this.session.setModelTemporary(planModel);
} catch (error) {
@@ -542,6 +547,20 @@ export class InteractiveMode implements InteractiveModeContext {
}
}
/** Apply any deferred model switch after the current stream ends. */
async flushPendingModelSwitch(): Promise<void> {
const model = this.pendingModelSwitch;
if (!model) return;
this.pendingModelSwitch = undefined;
try {
await this.session.setModelTemporary(model);
} catch (error) {
this.showWarning(
`Failed to switch model after streaming: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
private async enterPlanMode(options?: {
planFilePath?: string;
workflow?: "parallel" | "iterative";
@@ -588,7 +607,11 @@ export class InteractiveMode implements InteractiveModeContext {
await this.session.setActiveToolsByName(previousTools);
}
if (this.planModePreviousModel) {
await this.session.setModelTemporary(this.planModePreviousModel);
if (this.session.isStreaming) {
this.pendingModelSwitch = this.planModePreviousModel;
} else {
await this.session.setModelTemporary(this.planModePreviousModel);
}
}
this.session.setPlanModeState(undefined);