fix(app): collapse deletion-only edit parts (#40536)
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
f0afb6750e
commit
98dd65cd60
@@ -61,6 +61,7 @@ import { TextShimmer } from "@opencode-ai/ui/text-shimmer"
|
|||||||
import { AnimatedCountList } from "./tool-count-summary"
|
import { AnimatedCountList } from "./tool-count-summary"
|
||||||
import { ToolStatusTitle } from "./tool-status-title"
|
import { ToolStatusTitle } from "./tool-status-title"
|
||||||
import { patchFiles } from "./apply-patch-file"
|
import { patchFiles } from "./apply-patch-file"
|
||||||
|
import { partDefaultOpen } from "./part-default-open"
|
||||||
import { animate } from "motion"
|
import { animate } from "motion"
|
||||||
import { attached, inline, kind, typeLabel } from "./message-file"
|
import { attached, inline, kind, typeLabel } from "./message-file"
|
||||||
import { readPartText } from "./message-part-text"
|
import { readPartText } from "./message-part-text"
|
||||||
@@ -718,15 +719,7 @@ export function renderable(part: PartType, showReasoningSummaries = true) {
|
|||||||
return !!PART_MAPPING[part.type]
|
return !!PART_MAPPING[part.type]
|
||||||
}
|
}
|
||||||
|
|
||||||
function toolDefaultOpen(tool: string, shell = false, edit = false) {
|
export { partDefaultOpen } from "./part-default-open"
|
||||||
if (tool === "bash" || tool === "shell") return shell
|
|
||||||
if (tool === "edit" || tool === "write" || tool === "patch" || tool === "apply_patch") return edit
|
|
||||||
}
|
|
||||||
|
|
||||||
export function partDefaultOpen(part: PartType, shell = false, edit = false) {
|
|
||||||
if (part.type !== "tool") return
|
|
||||||
return toolDefaultOpen(part.tool, shell, edit)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AssistantParts(props: {
|
export function AssistantParts(props: {
|
||||||
messages: AssistantMessage[]
|
messages: AssistantMessage[]
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import type { Part as PartType } from "@opencode-ai/sdk/v2"
|
||||||
|
import { partDefaultOpen } from "./part-default-open"
|
||||||
|
|
||||||
|
describe("partDefaultOpen", () => {
|
||||||
|
test("keeps edited files expanded when enabled", () => {
|
||||||
|
expect(partDefaultOpen(tool("edit", { filediff: { additions: 1, deletions: 1 } }), false, true)).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("collapses deletion-only edits when enabled", () => {
|
||||||
|
expect(partDefaultOpen(tool("edit", { filediff: { additions: 0, deletions: 1_200 } }), false, true)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("collapses patches containing only deleted files when enabled", () => {
|
||||||
|
expect(
|
||||||
|
partDefaultOpen(
|
||||||
|
tool("apply_patch", {
|
||||||
|
files: [
|
||||||
|
{ filePath: "one.ts", type: "delete" },
|
||||||
|
{ filePath: "two.ts", type: "delete" },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("keeps mixed patches expanded when enabled", () => {
|
||||||
|
expect(
|
||||||
|
partDefaultOpen(
|
||||||
|
tool("apply_patch", {
|
||||||
|
files: [
|
||||||
|
{ filePath: "one.ts", type: "delete" },
|
||||||
|
{ filePath: "two.ts", type: "update" },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("preserves shell defaults", () => {
|
||||||
|
expect(partDefaultOpen(tool("shell", {}), true, false)).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function tool(name: string, metadata: Record<string, unknown>): PartType {
|
||||||
|
return {
|
||||||
|
id: `part_${name}`,
|
||||||
|
sessionID: "session",
|
||||||
|
messageID: "message",
|
||||||
|
type: "tool",
|
||||||
|
callID: `call_${name}`,
|
||||||
|
tool: name,
|
||||||
|
state: {
|
||||||
|
status: "completed",
|
||||||
|
input: {},
|
||||||
|
output: "",
|
||||||
|
title: name,
|
||||||
|
metadata,
|
||||||
|
time: { start: 0, end: 1 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import type { Part as PartType, ToolPart } from "@opencode-ai/sdk/v2"
|
||||||
|
|
||||||
|
function deletionOnly(part: ToolPart) {
|
||||||
|
if (!("metadata" in part.state)) return false
|
||||||
|
const metadata = part.state.metadata
|
||||||
|
if (!metadata) return false
|
||||||
|
|
||||||
|
const files = metadata.files
|
||||||
|
if (Array.isArray(files) && files.length > 0) {
|
||||||
|
return files.every((file) => !!file && typeof file === "object" && "type" in file && file.type === "delete")
|
||||||
|
}
|
||||||
|
|
||||||
|
const filediff = metadata.filediff
|
||||||
|
if (!filediff || typeof filediff !== "object") return false
|
||||||
|
if (!("additions" in filediff) || !("deletions" in filediff)) return false
|
||||||
|
return filediff.additions === 0 && typeof filediff.deletions === "number" && filediff.deletions > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export function partDefaultOpen(part: PartType, shell = false, edit = false) {
|
||||||
|
if (part.type !== "tool") return
|
||||||
|
if (part.tool === "bash" || part.tool === "shell") return shell
|
||||||
|
if (part.tool === "edit" || part.tool === "write" || part.tool === "patch" || part.tool === "apply_patch") {
|
||||||
|
if (!edit) return false
|
||||||
|
return !deletionOnly(part)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user