From 4471a3f26d37fcf78280ae8eeaeb5e8021f6d8e9 Mon Sep 17 00:00:00 2001 From: Daniel Anderson-Little Date: Sun, 2 Aug 2026 23:21:17 -0400 Subject: [PATCH] fix(tui): purge hidden tool images --- .../src/modes/controllers/input-controller.ts | 1 + .../src/modes/controllers/selector-controller.ts | 1 + .../test/input-controller-keybindings.test.ts | 4 ++++ .../controllers/input-controller-tool-expansion.test.ts | 9 +++++++-- .../test/selector-settings-side-effects.test.ts | 9 ++++++++- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/coding-agent/src/modes/controllers/input-controller.ts b/packages/coding-agent/src/modes/controllers/input-controller.ts index 105ec3333..7954a9db8 100644 --- a/packages/coding-agent/src/modes/controllers/input-controller.ts +++ b/packages/coding-agent/src/modes/controllers/input-controller.ts @@ -1878,6 +1878,7 @@ export class InputController { } } + if (this.ctx.hideToolActivity) this.ctx.ui.clearInlineImages(); this.ctx.ui.resetDisplay(); this.ctx.showStatus(`Tool activity: ${this.ctx.hideToolActivity ? "hidden" : "visible"}`); } diff --git a/packages/coding-agent/src/modes/controllers/selector-controller.ts b/packages/coding-agent/src/modes/controllers/selector-controller.ts index 468728a14..bdc66bca5 100644 --- a/packages/coding-agent/src/modes/controllers/selector-controller.ts +++ b/packages/coding-agent/src/modes/controllers/selector-controller.ts @@ -487,6 +487,7 @@ export class SelectorController { child.setToolResultImagesVisible(!hidden); } } + if (hidden) this.ctx.ui.clearInlineImages(); this.ctx.ui.resetDisplay(); break; } diff --git a/packages/coding-agent/test/input-controller-keybindings.test.ts b/packages/coding-agent/test/input-controller-keybindings.test.ts index cb75c44ab..1a4b63893 100644 --- a/packages/coding-agent/test/input-controller-keybindings.test.ts +++ b/packages/coding-agent/test/input-controller-keybindings.test.ts @@ -74,6 +74,7 @@ async function createContext() { customHandlers.clear(); }); const resetDisplay = vi.fn(); + const clearInlineImages = vi.fn(); const showModelSelector = vi.fn(); const requestRender = vi.fn(); const showError = vi.fn(); @@ -142,6 +143,7 @@ async function createContext() { ui: { requestRender, resetDisplay, + clearInlineImages, addInputListener, addStartListener, getFocused: vi.fn(() => focused), @@ -234,6 +236,7 @@ async function createContext() { retry, abort, resetDisplay, + clearInlineImages, refreshAppearance, resetDisplayAfterAppearanceRefresh, handleBtwBranchKey, @@ -283,6 +286,7 @@ describe("InputController keybinding setup", () => { expect(ctx.hideToolActivity).toBe(true); expect(ctx.settings.set).toHaveBeenCalledWith("display.hideToolActivity", true); + expect(spies.clearInlineImages).toHaveBeenCalledTimes(1); expect(spies.resetDisplay).toHaveBeenCalledTimes(1); }); diff --git a/packages/coding-agent/test/modes/controllers/input-controller-tool-expansion.test.ts b/packages/coding-agent/test/modes/controllers/input-controller-tool-expansion.test.ts index 3d91e89a4..3422c0acb 100644 --- a/packages/coding-agent/test/modes/controllers/input-controller-tool-expansion.test.ts +++ b/packages/coding-agent/test/modes/controllers/input-controller-tool-expansion.test.ts @@ -60,6 +60,7 @@ describe("InputController tool activity visibility", () => { const addChild = vi.fn(); const rebuildChatFromMessages = vi.fn(); const set = vi.fn(); + const clearInlineImages = vi.fn(); const resetDisplay = vi.fn(); const showStatus = vi.fn(); const ctx = { @@ -69,7 +70,7 @@ describe("InputController tool activity visibility", () => { chatContainer: { children, clear, addChild }, rebuildChatFromMessages, showStatus, - ui: { resetDisplay }, + ui: { clearInlineImages, resetDisplay }, }; const controller = new InputController(ctx as unknown as InteractiveModeContext) as unknown as InputController & { toggleToolActivityVisibility(): void; @@ -83,7 +84,9 @@ describe("InputController tool activity visibility", () => { expect(clear).not.toHaveBeenCalled(); expect(addChild).not.toHaveBeenCalled(); expect(rebuildChatFromMessages).not.toHaveBeenCalled(); - expect(resetDisplay).toHaveBeenCalled(); + expect(clearInlineImages).toHaveBeenCalledTimes(1); + expect(resetDisplay).toHaveBeenCalledTimes(1); + expect(clearInlineImages.mock.invocationCallOrder[0]).toBeLessThan(resetDisplay.mock.invocationCallOrder[0]); expect(showStatus).toHaveBeenLastCalledWith("Tool activity: hidden"); expect(setToolResultImagesVisible).toHaveBeenLastCalledWith(false); @@ -96,6 +99,8 @@ describe("InputController tool activity visibility", () => { expect(clear).not.toHaveBeenCalled(); expect(addChild).not.toHaveBeenCalled(); expect(rebuildChatFromMessages).not.toHaveBeenCalled(); + expect(clearInlineImages).toHaveBeenCalledTimes(1); + expect(resetDisplay).toHaveBeenCalledTimes(2); expect(showStatus).toHaveBeenLastCalledWith("Tool activity: visible"); expect(setToolResultImagesVisible).toHaveBeenLastCalledWith(true); }); diff --git a/packages/coding-agent/test/selector-settings-side-effects.test.ts b/packages/coding-agent/test/selector-settings-side-effects.test.ts index d74c2f260..3cff7a77d 100644 --- a/packages/coding-agent/test/selector-settings-side-effects.test.ts +++ b/packages/coding-agent/test/selector-settings-side-effects.test.ts @@ -141,12 +141,13 @@ describe("selector setting side effects", () => { const setToolResultImagesVisible = vi.fn(); const assistant = Object.create(AssistantMessageComponent.prototype) as AssistantMessageComponent; assistant.setToolResultImagesVisible = setToolResultImagesVisible; + const clearInlineImages = vi.fn(); const resetDisplay = vi.fn(); const ctx = { hideToolActivity: !hidden, toolOutputExpanded: true, chatContainer: { children: [tool, readGroup, assistant] }, - ui: { resetDisplay }, + ui: { clearInlineImages, resetDisplay }, }; const controller = new SelectorController(ctx as unknown as InteractiveModeContext); @@ -159,7 +160,13 @@ describe("selector setting side effects", () => { expect(setToolExpanded).toHaveBeenCalledTimes(hidden ? 0 : 1); expect(setReadExpanded).toHaveBeenCalledTimes(hidden ? 0 : 1); expect(ctx.toolOutputExpanded).toBe(hidden); + expect(clearInlineImages).toHaveBeenCalledTimes(hidden ? 1 : 0); expect(resetDisplay).toHaveBeenCalledTimes(1); + if (hidden) { + expect(clearInlineImages.mock.invocationCallOrder[0]).toBeLessThan( + resetDisplay.mock.invocationCallOrder[0], + ); + } }); }