From 232005a7dfd92ce7aa5721096661c0516aa99ee0 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 11 Jun 2026 15:17:05 +0100 Subject: [PATCH] Hide the selected-route transcript row when the header badge already carries it Every assistant turn rendered a 'Using ' status row that repeats the route badge in the turn header, so a restored session read as a column of duplicate route chips. Keep the row only when it adds information: the header has no route attribution, the selected route differs from the turn's final model, or a later mid-turn switch makes the starting route part of the story. --- .../src/components/AI/Chat/MessageItem.tsx | 17 ++++- .../AI/Chat/__tests__/MessageItem.test.tsx | 64 +++++++++++++++++++ 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/frontend-modern/src/components/AI/Chat/MessageItem.tsx b/frontend-modern/src/components/AI/Chat/MessageItem.tsx index 43e1b2c784..859a21e6d7 100644 --- a/frontend-modern/src/components/AI/Chat/MessageItem.tsx +++ b/frontend-modern/src/components/AI/Chat/MessageItem.tsx @@ -304,8 +304,21 @@ export const MessageItem: Component = (props) => { return !!evt.pendingTool; case 'tool_cancel': return !!evt.toolCancel; - case 'model_switch': - return !!evt.model?.trim(); + case 'model_switch': { + if (!evt.model?.trim()) return false; + if (!isSelectedModelRouteEvent(evt)) return true; + // A plain selected-route row repeats the route badge already shown in + // the turn header. Keep it only when it adds information: the header + // has no route, the route differs from the turn's final model, or a + // later switch makes the starting route part of the turn's story. + const hasRouteSwitch = (props.message.streamEvents || []).some( + (event) => + event.type === 'model_switch' && + !!event.model?.trim() && + !isSelectedModelRouteEvent(event), + ); + return hasRouteSwitch || !props.message.model || evt.model !== props.message.model; + } case 'approval': return !!evt.approval; case 'question': diff --git a/frontend-modern/src/components/AI/Chat/__tests__/MessageItem.test.tsx b/frontend-modern/src/components/AI/Chat/__tests__/MessageItem.test.tsx index 9208e15929..f36280b878 100644 --- a/frontend-modern/src/components/AI/Chat/__tests__/MessageItem.test.tsx +++ b/frontend-modern/src/components/AI/Chat/__tests__/MessageItem.test.tsx @@ -1170,6 +1170,70 @@ describe('MessageItem', () => { ).toHaveTextContent('Using Qwen 3.7 Plus via OpenRouter'); }); + it('hides the selected-route row when the turn header badge already shows the same route', () => { + const events: StreamDisplayEvent[] = [ + { + type: 'model_switch', + model: 'openrouter:qwen/qwen3.7-plus', + modelEvent: 'selected', + }, + ]; + + render(() => ( + + model === 'openrouter:qwen/qwen3.7-plus' ? 'Qwen 3.7 Plus via OpenRouter' : model + } + {...makeHandlers()} + /> + )); + + expect( + screen.queryByRole('status', { name: 'Assistant model route selected' }), + ).not.toBeInTheDocument(); + // The route is still visible exactly once, in the header badge. + expect(screen.getByText('Qwen 3.7 Plus via OpenRouter')).toBeInTheDocument(); + }); + + it('keeps the selected-route row when a later switch makes it part of the turn story', () => { + const events: StreamDisplayEvent[] = [ + { + type: 'model_switch', + model: 'openrouter:qwen/qwen3.7-plus', + modelEvent: 'selected', + }, + { + type: 'model_switch', + failedModel: 'openrouter:qwen/qwen3.7-plus', + model: 'gemini:gemini-3.1-flash-lite', + }, + ]; + + render(() => ( + model} + {...makeHandlers()} + /> + )); + + expect( + screen.getByRole('status', { name: 'Assistant model route selected' }), + ).toBeInTheDocument(); + expect( + screen.getByRole('status', { name: 'Assistant model route changed' }), + ).toBeInTheDocument(); + }); + it('does not render request-start progress as a transcript row next to selected model route evidence (footer-owned)', () => { const events: StreamDisplayEvent[] = [ {