diff --git a/frontend/src/lib/components/copilot/chat/ToolDiffCard.svelte b/frontend/src/lib/components/copilot/chat/ToolDiffCard.svelte index b360dc3ac5..94e33374c3 100644 --- a/frontend/src/lib/components/copilot/chat/ToolDiffCard.svelte +++ b/frontend/src/lib/components/copilot/chat/ToolDiffCard.svelte @@ -13,9 +13,10 @@ interface Props { message: ToolDisplayMessage + hidePreviewChip?: boolean } - let { message }: Props = $props() + let { message, hidePreviewChip = false }: Props = $props() const diff = $derived(toolCodeDiff(message)) const isStreaming = $derived(Boolean(message.isStreamingArguments)) @@ -56,7 +57,7 @@ const isRunning = $derived(Boolean(message.isLoading && !message.needsConfirmation)) const showPreviewChip = $derived( - Boolean(message.previewCard && !message.isLoading && !message.error) + Boolean(!hidePreviewChip && message.previewCard && !message.isLoading && !message.error) ) diff --git a/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte b/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte index 15a7e2ea66..7e92c55c89 100644 --- a/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte +++ b/frontend/src/lib/components/copilot/chat/ToolExecutionDisplay.svelte @@ -197,7 +197,7 @@ {:else if isRunCard} {:else if isDiffCard} - + {:else if planState} diff --git a/frontend/src/lib/components/copilot/chat/toolGroups.test.ts b/frontend/src/lib/components/copilot/chat/toolGroups.test.ts index a4fc4ce0a8..4dd3b376fe 100644 --- a/frontend/src/lib/components/copilot/chat/toolGroups.test.ts +++ b/frontend/src/lib/components/copilot/chat/toolGroups.test.ts @@ -187,6 +187,19 @@ describe('groupToolRuns', () => { ).toEqual([{ edit: [0, 1, 2] }, { edit: [3, 4] }]) }) + it('folds app edits that carry a file diff, but not a script edit with one', () => { + const app = { path: 'f/a/x' } + const diff = { codeDiff: { before: 'a', after: 'b' } } + expect( + shape([ + tool('init_app', app), + tool('write_app_file', { ...app, file_path: '/App.tsx' }, diff), + tool('delete_app_runnable', { ...app, key: 'greet' }, diff), + tool('write_script', { path: 'f/a/s' }, diff) + ]) + ).toEqual([{ edit: [0, 1, 2] }, 3]) + }) + it('leaves a flow read that prepares an edit to the edit group, not the lookups before it', () => { const flow = { type: 'flow', path: 'f/a/flow' } expect( diff --git a/frontend/src/lib/components/copilot/chat/toolGroups.ts b/frontend/src/lib/components/copilot/chat/toolGroups.ts index 94936d4293..f3e3ad0aa9 100644 --- a/frontend/src/lib/components/copilot/chat/toolGroups.ts +++ b/frontend/src/lib/components/copilot/chat/toolGroups.ts @@ -116,7 +116,9 @@ function groupableCall(message: DisplayMessage): ToolDisplayMessage | undefined if (message.needsConfirmation || message.blockedByPlanMode) return undefined if (message.heldForFolderInstructions) return undefined if (message.runForm || message.inspectedRun || message.userQuestion) return undefined - if (message.codeDiff || message.imageUrl || message.webSearchSources) return undefined + // An app edit's diff covers one file of many, so it stays a row inside the app's group. + if (message.codeDiff && EDIT_TOOLS[message.toolName] !== 'app') return undefined + if (message.imageUrl || message.webSearchSources) return undefined if (!message.error && webSearchResultOf(message.result)) return undefined // The user's own refusal is a decision, not a failure to fold away. if (message.declinedByUser) return undefined