From fd97a7cba4ba5788f4e8a4601bfd42ed8b16edee Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sat, 2 May 2026 15:24:27 -0500 Subject: [PATCH] chore: uptick --- apps/desktop/src/app/shell/app-shell.tsx | 8 +++----- apps/desktop/src/lib/chat-messages.test.ts | 22 +++++----------------- apps/desktop/src/lib/chat-messages.ts | 7 +------ 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/apps/desktop/src/app/shell/app-shell.tsx b/apps/desktop/src/app/shell/app-shell.tsx index 6d9992a296..6a90f32063 100644 --- a/apps/desktop/src/app/shell/app-shell.tsx +++ b/apps/desktop/src/app/shell/app-shell.tsx @@ -74,10 +74,6 @@ export function AppShell({ const titlebarToolCount = (titlebarTools?.filter(tool => !tool.hidden).length ?? 0) + (rightRailOpen ? 1 : 0) + 2 - const previewToolbarGap = showPreviewRail - ? 'max(0px, calc(var(--shell-right-sidebar-width) - (3 * var(--titlebar-control-size)) + 0.2rem))' - : '0px' - // Always keep the shell as fixed columns because sidebar/chat/preview/inspector // are always rendered as grid children. Hidden rails collapse to 0px so they // don't float over the chat surface or reorder into a new row. @@ -132,7 +128,9 @@ export function AppShell({ '--shell-preview-pane-width': previewColumn, '--shell-right-sidebar-width': inspectorColumn, '--shell-right-region-width': 'calc(var(--shell-preview-pane-width) + var(--shell-right-sidebar-width))', - '--shell-preview-toolbar-gap': previewToolbarGap, + '--shell-preview-toolbar-gap': showPreviewRail + ? 'max(0px, calc(var(--shell-right-sidebar-width) - (3 * var(--titlebar-control-size)) + 0.2rem))' + : '0px', '--titlebar-height': `${TITLEBAR_HEIGHT}px`, '--titlebar-content-inset': `${titlebarContentInset}px`, '--titlebar-controls-left': `${titlebarControls.left}px`, diff --git a/apps/desktop/src/lib/chat-messages.test.ts b/apps/desktop/src/lib/chat-messages.test.ts index 9bef8803fd..dda3194aab 100644 --- a/apps/desktop/src/lib/chat-messages.test.ts +++ b/apps/desktop/src/lib/chat-messages.test.ts @@ -3,33 +3,21 @@ import { describe, expect, it } from 'vitest' import { appendAssistantTextPart, chatMessageText, renderMediaTags, toChatMessages, upsertToolPart } from './chat-messages' describe('toChatMessages', () => { - it('merges queued tool-only assistant rows into the previous assistant bubble', () => { + it('keeps a turn with interleaved tool-only rows in a single bubble', () => { const messages = toChatMessages([ { role: 'assistant', content: 'Planning.', timestamp: 1 }, { role: 'assistant', content: '', timestamp: 2, - tool_calls: [{ id: 'tc-terminal', function: { name: 'terminal', arguments: '{"command":"ls"}' } }] + tool_calls: [{ id: 'tc', function: { name: 'terminal', arguments: '{}' } }] }, { role: 'assistant', content: 'Done.', timestamp: 3 } ]) - const assistants = messages.filter(m => m.role === 'assistant') - - expect(assistants).toHaveLength(1) - expect(chatMessageText(assistants[0])).toContain('Planning') - expect(chatMessageText(assistants[0])).toContain('Done') - expect(assistants[0].parts.some(p => p.type === 'tool-call' && p.toolName === 'terminal')).toBe(true) - const ordered = assistants[0].parts.map(p => p.type) - - expect(ordered.filter(t => t === 'text')).toHaveLength(2) - const toolIdx = assistants[0].parts.findIndex(p => p.type === 'tool-call') - - expect(ordered.slice(0, toolIdx)).toContain('text') - expect( - assistants[0].parts.findIndex((p, i) => p.type === 'text' && i > toolIdx) - ).toBeGreaterThanOrEqual(0) + expect(messages).toHaveLength(1) + expect(messages[0].parts.map(p => p.type)).toEqual(['text', 'tool-call', 'text']) + expect(chatMessageText(messages[0])).toBe('Planning.Done.') }) it('hides attached context payloads from user message display', () => { diff --git a/apps/desktop/src/lib/chat-messages.ts b/apps/desktop/src/lib/chat-messages.ts index 60aa9fd571..5b71f2e36e 100644 --- a/apps/desktop/src/lib/chat-messages.ts +++ b/apps/desktop/src/lib/chat-messages.ts @@ -516,17 +516,12 @@ export function toChatMessages(messages: SessionMessage[]): ChatMessage[] { if (message.role === 'assistant' && pendingToolParts.length) { const last = result.at(-1) - // Session logs interleave tool-only assistant rows with later prose; appending onto - // the previous bubble keeps one turn contiguous (vs unshift splitting the UI). if (last?.role === 'assistant') { last.parts = [...last.parts, ...pendingToolParts, ...parts] + last.timestamp = message.timestamp ?? last.timestamp pendingToolParts = [] pendingToolTimestamp = undefined - if (message.timestamp !== undefined) { - last.timestamp = message.timestamp - } - return }