fix: patch approval rendering to reduce churn (#453)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-01-02 17:22:28 -08:00
committed by GitHub
parent cd28bab41a
commit d2e0fc3bc5
5 changed files with 265 additions and 173 deletions

View File

@@ -282,6 +282,143 @@ export const InlineFileEditApproval = memo(
const headerText = getHeaderText(fileEdit);
const diffKind = getDiffKind(fileEdit.toolName);
// Memoize the static diff content so it doesn't re-render on keystroke
// This prevents flicker when typing feedback in the custom input field
// biome-ignore lint/correctness/useExhaustiveDependencies: JSON.stringify(fileEdit.edits) provides stable value comparison for arrays
const memoizedDiffContent = useMemo(
() => (
<>
{/* Top solid line */}
<Text dimColor>{solidLine}</Text>
{/* Header */}
<Text bold color={colors.approval.header}>
{headerText}
</Text>
{/* Dotted separator before diff content */}
<Text dimColor>{dottedLine}</Text>
{/* Diff preview */}
<Box paddingLeft={0}>
{fileEdit.patchInput ? (
// Render patch operations (can be multiple files)
<Box flexDirection="column">
{parsePatchOperations(fileEdit.patchInput).map((op, idx) => {
const { relative } = require("node:path");
const cwd = process.cwd();
const relPath = relative(cwd, op.path);
const displayPath = relPath.startsWith("..")
? op.path
: relPath;
// Look up precomputed diff using toolCallId:path key
const diffKey = fileEdit.toolCallId
? `${fileEdit.toolCallId}:${op.path}`
: undefined;
const opDiff =
diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
if (op.kind === "add") {
return (
<Box key={`patch-add-${op.path}`} flexDirection="column">
{idx > 0 && <Box height={1} />}
<Text dimColor>{displayPath}</Text>
<AdvancedDiffRenderer
precomputed={opDiff}
kind="write"
filePath={op.path}
content={op.content}
showHeader={false}
/>
</Box>
);
} else if (op.kind === "update") {
return (
<Box
key={`patch-update-${op.path}`}
flexDirection="column"
>
{idx > 0 && <Box height={1} />}
<Text dimColor>{displayPath}</Text>
<AdvancedDiffRenderer
precomputed={opDiff}
kind="edit"
filePath={op.path}
oldString={op.oldString}
newString={op.newString}
showHeader={false}
/>
</Box>
);
} else if (op.kind === "delete") {
return (
<Box
key={`patch-delete-${op.path}`}
flexDirection="column"
>
{idx > 0 && <Box height={1} />}
<Text dimColor>{displayPath}</Text>
<Text color="red">File will be deleted</Text>
</Box>
);
}
return null;
})}
</Box>
) : diffKind === "write" ? (
<AdvancedDiffRenderer
precomputed={precomputedDiff}
kind="write"
filePath={fileEdit.filePath}
content={fileEdit.content || ""}
showHeader={false}
/>
) : diffKind === "multi_edit" ? (
<AdvancedDiffRenderer
precomputed={precomputedDiff}
kind="multi_edit"
filePath={fileEdit.filePath}
edits={fileEdit.edits || []}
showHeader={false}
/>
) : (
<AdvancedDiffRenderer
precomputed={precomputedDiff}
kind="edit"
filePath={fileEdit.filePath}
oldString={fileEdit.oldString || ""}
newString={fileEdit.newString || ""}
replaceAll={fileEdit.replaceAll}
showHeader={false}
/>
)}
</Box>
{/* Dotted separator after diff content */}
<Text dimColor>{dottedLine}</Text>
</>
),
// Use primitive values to avoid memo invalidation when parent re-renders.
// Arrays/objects are compared by reference, so we stringify edits for stable comparison.
[
fileEdit.filePath,
fileEdit.content,
fileEdit.oldString,
fileEdit.newString,
fileEdit.replaceAll,
fileEdit.patchInput,
fileEdit.toolCallId,
JSON.stringify(fileEdit.edits),
precomputedDiff,
allDiffs,
solidLine,
dottedLine,
headerText,
diffKind,
],
);
// Hint text based on state
const hintText = isOnCustomOption
? customReason
@@ -291,109 +428,8 @@ export const InlineFileEditApproval = memo(
return (
<Box flexDirection="column">
{/* Top solid line */}
<Text dimColor>{solidLine}</Text>
{/* Header */}
<Text bold color={colors.approval.header}>
{headerText}
</Text>
{/* Dotted separator before diff content */}
<Text dimColor>{dottedLine}</Text>
{/* Diff preview */}
<Box paddingLeft={0}>
{fileEdit.patchInput ? (
// Render patch operations (can be multiple files)
<Box flexDirection="column">
{parsePatchOperations(fileEdit.patchInput).map((op, idx) => {
const { relative } = require("node:path");
const cwd = process.cwd();
const relPath = relative(cwd, op.path);
const displayPath = relPath.startsWith("..")
? op.path
: relPath;
// Look up precomputed diff using toolCallId:path key
const diffKey = fileEdit.toolCallId
? `${fileEdit.toolCallId}:${op.path}`
: undefined;
const opDiff =
diffKey && allDiffs ? allDiffs.get(diffKey) : undefined;
if (op.kind === "add") {
return (
<Box key={`patch-add-${op.path}`} flexDirection="column">
{idx > 0 && <Box height={1} />}
<Text dimColor>{displayPath}</Text>
<AdvancedDiffRenderer
precomputed={opDiff}
kind="write"
filePath={op.path}
content={op.content}
showHeader={false}
/>
</Box>
);
} else if (op.kind === "update") {
return (
<Box key={`patch-update-${op.path}`} flexDirection="column">
{idx > 0 && <Box height={1} />}
<Text dimColor>{displayPath}</Text>
<AdvancedDiffRenderer
precomputed={opDiff}
kind="edit"
filePath={op.path}
oldString={op.oldString}
newString={op.newString}
showHeader={false}
/>
</Box>
);
} else if (op.kind === "delete") {
return (
<Box key={`patch-delete-${op.path}`} flexDirection="column">
{idx > 0 && <Box height={1} />}
<Text dimColor>{displayPath}</Text>
<Text color="red">File will be deleted</Text>
</Box>
);
}
return null;
})}
</Box>
) : diffKind === "write" ? (
<AdvancedDiffRenderer
precomputed={precomputedDiff}
kind="write"
filePath={fileEdit.filePath}
content={fileEdit.content || ""}
showHeader={false}
/>
) : diffKind === "multi_edit" ? (
<AdvancedDiffRenderer
precomputed={precomputedDiff}
kind="multi_edit"
filePath={fileEdit.filePath}
edits={fileEdit.edits || []}
showHeader={false}
/>
) : (
<AdvancedDiffRenderer
precomputed={precomputedDiff}
kind="edit"
filePath={fileEdit.filePath}
oldString={fileEdit.oldString || ""}
newString={fileEdit.newString || ""}
replaceAll={fileEdit.replaceAll}
showHeader={false}
/>
)}
</Box>
{/* Dotted separator after diff content */}
<Text dimColor>{dottedLine}</Text>
{/* Static diff content - memoized to prevent re-render on keystroke */}
{memoizedDiffContent}
{/* Options */}
<Box marginTop={1} flexDirection="column">