From bb62d5dd6d66df5db6ced5fd4eefffde50e48d57 Mon Sep 17 00:00:00 2001 From: Adolanium <94890352+Adolanium@users.noreply.github.com> Date: Sat, 13 Jun 2026 13:47:19 +0300 Subject: [PATCH] fix(coding-agent): rebuild system prompt on model switch setModel and cycleModel updated agent.state.model but never rebuilt the cached system prompt, so the # Environment block kept naming the model the session started on. After switching model the agent reported a stale id. Refresh the prompt on every switch so it names the active model. --- .../coding-agent/src/core/agent-session.ts | 16 +++++++++++ .../agent-session-model-extension.test.ts | 28 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index 206fa6034..932d77870 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -2231,6 +2231,16 @@ export class AgentSession { }); } + /** + * Rebuild the cached base system prompt so the # Environment block reflects the + * current model. Model switches update agent.state.model but the prompt is + * otherwise only rebuilt at init, so without this the model reports a stale id. + */ + private _refreshSystemPromptForModel(): void { + this._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames()); + this.agent.state.systemPrompt = this._baseSystemPrompt; + } + /** * Set model directly. * Validates that auth is configured, saves to session and settings. @@ -2250,6 +2260,8 @@ export class AgentSession { // Re-clamp thinking level for new model's capabilities this.setThinkingLevel(thinkingLevel); + this._refreshSystemPromptForModel(); + await this._emitModelSelect(model, previousModel, "set"); } @@ -2290,6 +2302,8 @@ export class AgentSession { // setThinkingLevel clamps to model capabilities. this.setThinkingLevel(thinkingLevel); + this._refreshSystemPromptForModel(); + await this._emitModelSelect(next.model, currentModel, "cycle"); return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true }; @@ -2315,6 +2329,8 @@ export class AgentSession { // Re-clamp thinking level for new model's capabilities this.setThinkingLevel(thinkingLevel); + this._refreshSystemPromptForModel(); + await this._emitModelSelect(nextModel, currentModel, "cycle"); return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false }; diff --git a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts index f6e61248d..b4b1a1ba2 100644 --- a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts +++ b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts @@ -44,6 +44,34 @@ describe("AgentSession model and extension characterization", () => { ).toEqual([`${nextModel.provider}/${nextModel.id}`]); }); + it("setModel refreshes the system prompt so the provider sees the new model", async () => { + const harness = await createHarness({ + models: [ + { id: "faux-1", name: "One", reasoning: true }, + { id: "faux-2", name: "Two", reasoning: true }, + ], + }); + harnesses.push(harness); + + const seenSystemPrompts: string[] = []; + const capture = (context: { systemPrompt?: string }) => { + seenSystemPrompts.push(context.systemPrompt ?? ""); + return fauxAssistantMessage("ok"); + }; + + harness.setResponses([capture]); + await harness.session.prompt("first"); + + await harness.session.setModel(harness.getModel("faux-2")!); + + harness.appendResponses([capture]); + await harness.session.prompt("second"); + + expect(seenSystemPrompts[0]).toContain("Active model: faux-1"); + expect(seenSystemPrompts[1]).toContain("Active model: faux-2"); + expect(seenSystemPrompts[1]).not.toContain("Active model: faux-1"); + }); + it("cycles through scoped models and preserves the scoped thinking preference", async () => { const harness = await createHarness({ models: [