fix(app): deduplicate diff summaries linearly (#37414)

This commit is contained in:
Luke Parker 2026-07-17 12:06:38 +10:00 committed by GitHub
commit 3a1c6df9e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 65 additions and 13 deletions

View file

@ -1,7 +1,8 @@
import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note"
import { AssistantMessage, Part, SessionStatus, SnapshotFileDiff, UserMessage } from "@opencode-ai/sdk/v2"
import { AssistantMessage, Part, SessionStatus, UserMessage } from "@opencode-ai/sdk/v2"
import { groupParts, renderable, type PartGroup } from "@opencode-ai/session-ui/message-part"
import { TimelineRow, type SummaryDiff } from "./timeline-row"
import { uniqueSummaryDiffs } from "./summary-diffs"
export { TimelineRow, type SummaryDiff } from "./timeline-row"
@ -137,14 +138,7 @@ export namespace Timeline {
if (isActive && status === "retry") rows.push(new TimelineRow.Retry({ userMessageID: userMessage.id }))
const diffs = (userMessage.summary?.diffs ?? [])
.reduceRight<SummaryDiff[]>((result, diff) => {
if (!isSummaryDiff(diff)) return result
if (result.some((item) => item.file === diff.file)) return result
result.push(diff)
return result
}, [])
.reverse()
const diffs = uniqueSummaryDiffs(userMessage.summary?.diffs)
if (diffs.length > 0 && (status === "idle" || !isActive)) {
rows.push(
new TimelineRow.DiffSummary({
@ -169,10 +163,6 @@ export namespace Timeline {
return rows
}
function isSummaryDiff(value: SnapshotFileDiff): value is SummaryDiff {
return typeof value.file === "string"
}
function reasoningHeading(text: string) {
const markdown = text.replace(/\r\n?/g, "\n")
const html = markdown.match(/<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/i)

View file

@ -0,0 +1,42 @@
import { describe, expect, test } from "bun:test"
import type { SnapshotFileDiff } from "@opencode-ai/sdk/v2"
import { uniqueSummaryDiffs } from "./summary-diffs"
const diff = (file: string, additions: number) =>
({
file,
additions,
deletions: 0,
}) satisfies SnapshotFileDiff
describe("uniqueSummaryDiffs", () => {
test("drops entries without files and preserves unique input", () => {
const alpha = diff("alpha.ts", 1)
const beta = diff("beta.ts", 1)
const invalid = { additions: 1, deletions: 0 } satisfies SnapshotFileDiff
expect(uniqueSummaryDiffs(undefined)).toEqual([])
expect(uniqueSummaryDiffs([])).toEqual([])
expect(uniqueSummaryDiffs([invalid])).toEqual([])
const result = uniqueSummaryDiffs([alpha, invalid, beta])
expect(result).toEqual([alpha, beta])
expect(result[0]).toBe(alpha)
expect(result[1]).toBe(beta)
})
test("keeps the last diff per file in the legacy display order", () => {
const oldAlpha = diff("alpha.ts", 1)
const oldBeta = diff("beta.ts", 1)
const newAlpha = diff("alpha.ts", 2)
const charlie = diff("charlie.ts", 1)
const newBeta = diff("beta.ts", 2)
const result = uniqueSummaryDiffs([oldAlpha, oldBeta, newAlpha, charlie, newBeta])
expect(result).toEqual([newAlpha, charlie, newBeta])
expect(result[0]).toBe(newAlpha)
expect(result[1]).toBe(charlie)
expect(result[2]).toBe(newBeta)
})
})

View file

@ -0,0 +1,20 @@
import type { SnapshotFileDiff } from "@opencode-ai/sdk/v2"
import type { SummaryDiff } from "./timeline-row"
export function uniqueSummaryDiffs(diffs: SnapshotFileDiff[] | undefined) {
const files = new Set<string>()
return (diffs ?? [])
.reduceRight<SummaryDiff[]>((result, diff) => {
if (!isSummaryDiff(diff)) return result
const file = diff.file
if (files.has(file)) return result
files.add(file)
result.push(diff)
return result
}, [])
.reverse()
}
function isSummaryDiff(diff: SnapshotFileDiff): diff is SummaryDiff {
return typeof diff.file === "string"
}