fix(app): deduplicate diff summaries linearly (#37414)
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note"
|
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 { groupParts, renderable, type PartGroup } from "@opencode-ai/session-ui/message-part"
|
||||||
import { TimelineRow, type SummaryDiff } from "./timeline-row"
|
import { TimelineRow, type SummaryDiff } from "./timeline-row"
|
||||||
|
import { uniqueSummaryDiffs } from "./summary-diffs"
|
||||||
|
|
||||||
export { TimelineRow, type SummaryDiff } from "./timeline-row"
|
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 }))
|
if (isActive && status === "retry") rows.push(new TimelineRow.Retry({ userMessageID: userMessage.id }))
|
||||||
|
|
||||||
const diffs = (userMessage.summary?.diffs ?? [])
|
const diffs = uniqueSummaryDiffs(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()
|
|
||||||
if (diffs.length > 0 && (status === "idle" || !isActive)) {
|
if (diffs.length > 0 && (status === "idle" || !isActive)) {
|
||||||
rows.push(
|
rows.push(
|
||||||
new TimelineRow.DiffSummary({
|
new TimelineRow.DiffSummary({
|
||||||
@@ -169,10 +163,6 @@ export namespace Timeline {
|
|||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSummaryDiff(value: SnapshotFileDiff): value is SummaryDiff {
|
|
||||||
return typeof value.file === "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
function reasoningHeading(text: string) {
|
function reasoningHeading(text: string) {
|
||||||
const markdown = text.replace(/\r\n?/g, "\n")
|
const markdown = text.replace(/\r\n?/g, "\n")
|
||||||
const html = markdown.match(/<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/i)
|
const html = markdown.match(/<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/i)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user