From 9bb18d3e0e81ebcb5474a79481ed4589eae0e265 Mon Sep 17 00:00:00 2001 From: jacobleft <88961633+jacobleft@users.noreply.github.com> Date: Thu, 13 Aug 2026 19:05:36 +0800 Subject: [PATCH] fix(tui): update welcome banner model name on model_changed event The welcome banner (WelcomeComponent) captures the session's active model name at init time but never receives updates when the model changes. Its setModel() method already existed but was never called after construction. This wires the model_changed agent session event to a new #updateWelcomeModel() method in InteractiveMode, mirroring the existing #updateWelcomeLspServers() pattern. The banner now reflects the live model after: - delayed config/modelRoles load (the startup race where an alphabetically-first provider is picked before config resolves) - explicit /model switches - retry-fallback model swaps --- packages/coding-agent/CHANGELOG.md | 4 ++++ .../coding-agent/src/modes/interactive-mode.ts | 14 ++++++++++++++ .../test/modes/components/welcome.test.ts | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 14334fddd..ef6d273c3 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed the welcome banner displaying a stale model name when the session's active model changes after startup (e.g. after a delayed config load or an explicit `/model` switch). The banner now subscribes to `model_changed` events and calls `WelcomeComponent.setModel()`, which already existed but was never wired up. + ## [17.3.0] - 2026-08-13 ### Breaking Changes diff --git a/packages/coding-agent/src/modes/interactive-mode.ts b/packages/coding-agent/src/modes/interactive-mode.ts index acf8f49d4..1c700712f 100644 --- a/packages/coding-agent/src/modes/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive-mode.ts @@ -1170,6 +1170,9 @@ export class InteractiveMode implements InteractiveModeContext { this.#eventBusUnsubscribers.push( this.session.subscribe(event => { + if (event.type === "model_changed") { + this.#updateWelcomeModel(); + } void this.#handleGoalSessionEvent(event); }), onStatusLineSessionAccentChanged(() => { @@ -4423,6 +4426,17 @@ export class InteractiveMode implements InteractiveModeContext { ); } + #updateWelcomeModel(): void { + if (!this.#welcomeComponent) { + return; + } + + this.#welcomeComponent.setModel( + this.session.model?.name ?? "Unknown", + this.session.model?.provider ?? "Unknown", + ); + } + #updateWelcomeLspServers(): void { if (!this.#welcomeComponent) { return; diff --git a/packages/coding-agent/test/modes/components/welcome.test.ts b/packages/coding-agent/test/modes/components/welcome.test.ts index f1d5997d1..5379f99b0 100644 --- a/packages/coding-agent/test/modes/components/welcome.test.ts +++ b/packages/coding-agent/test/modes/components/welcome.test.ts @@ -62,3 +62,21 @@ describe("WelcomeComponent tips", () => { expect(pickWeightedTip([], 0.5)).toBe(""); }); }); + +describe("WelcomeComponent model name", () => { + beforeAll(async () => { + await Settings.init({ inMemory: true }); + await initTheme(false); + }); + + it("updates the rendered model name after setModel()", () => { + const welcome = new WelcomeComponent("1.0.0", "DeepSeek V4 Pro", "deepseek"); + const before = welcome.render(100).join("\n"); + expect(before).toContain("DeepSeek V4 Pro"); + + welcome.setModel("GLM-5.2", "zhipu-coding-plan"); + const after = welcome.render(100).join("\n"); + expect(after).toContain("GLM-5.2"); + expect(after).not.toContain("DeepSeek V4 Pro"); + }); +});