修复:会话消息的工具调用里展开后无法显示新文件的内容

This commit is contained in:
xintaofei
2026-03-29 11:34:32 +08:00
parent 6df6fc1ac0
commit d653a20779
2 changed files with 85 additions and 39 deletions

View File

@@ -351,7 +351,18 @@ function parseUnifiedDiff(diffText: string): ParsedDiffFile[] {
continue continue
} }
const hunk = getActiveHunk() let hunk = getActiveHunk()
// Auto-create an implicit hunk for patch formats (e.g. *** Add File)
// that emit +/- lines without a preceding @@ header.
if (
!hunk &&
(line.startsWith("+") || line.startsWith("-") || line.startsWith(" "))
) {
if (getActiveFile()) {
startHunk("@@")
hunk = getActiveHunk()
}
}
if (!hunk) continue if (!hunk) continue
if (line.startsWith("+") && !line.startsWith("+++")) { if (line.startsWith("+") && !line.startsWith("+++")) {
@@ -487,6 +498,26 @@ function HunkLines({ rows }: { rows: ParsedDiffRow[] }) {
) )
} }
/** Clean file content view for new files (no diff signs or green highlight) */
function NewFileLines({ rows }: { rows: ParsedDiffRow[] }) {
return (
<div className="font-mono text-[12px] leading-[20px]">
{rows.map((row, i) => (
<div key={i} className="flex">
<span className="w-[3.5rem] shrink-0 select-none pr-1 text-right text-muted-foreground/40">
{row.newLine ?? i + 1}
</span>
<span className="flex-1 whitespace-pre pr-3">{row.text}</span>
</div>
))}
</div>
)
}
function isNewFileOnly(file: ParsedDiffFile): boolean {
return file.mode === "added" && file.deletions === 0
}
export function UnifiedDiffPreview({ export function UnifiedDiffPreview({
diffText, diffText,
className, className,
@@ -526,43 +557,52 @@ export function UnifiedDiffPreview({
return ( return (
<div className={cn("h-full overflow-auto", className)}> <div className={cn("h-full overflow-auto", className)}>
<div className="space-y-3"> <div className="space-y-3">
{files.map((file) => ( {files.map((file) => {
<section const newFile = isNewFileOnly(file)
key={file.key} return (
className="flex max-h-[420px] flex-col rounded-lg border border-border bg-background" <section
> key={file.key}
<header className="flex shrink-0 items-center gap-2 border-b border-border bg-muted/40 px-3 py-2 text-[11px]"> className="flex max-h-[420px] flex-col rounded-lg border border-border bg-background"
<span className="shrink-0 rounded border border-border bg-background px-1.5 py-0.5 text-[10px] text-muted-foreground"> >
{t(modeKey(file.mode))} <header className="flex shrink-0 items-center gap-2 border-b border-border bg-muted/40 px-3 py-2 text-[11px]">
</span> <span className="shrink-0 rounded border border-border bg-background px-1.5 py-0.5 text-[10px] text-muted-foreground">
<span {newFile ? "WRITE" : t(modeKey(file.mode))}
className="min-w-0 flex-1 truncate font-mono text-foreground"
title={file.path}
>
{toDisplayPath(file.path, folder?.path ?? null)}
</span>
<span className="ml-auto inline-flex shrink-0 items-center gap-2 font-mono">
<span className="text-green-700 dark:text-green-400">
+{file.additions}
</span> </span>
<span className="text-red-700 dark:text-red-400"> <span
-{file.deletions} className="min-w-0 flex-1 truncate font-mono text-foreground"
title={file.path}
>
{toDisplayPath(file.path, folder?.path ?? null)}
</span> </span>
</span> {!newFile && (
</header> <span className="ml-auto inline-flex shrink-0 items-center gap-2 font-mono">
<span className="text-green-700 dark:text-green-400">
+{file.additions}
</span>
<span className="text-red-700 dark:text-red-400">
-{file.deletions}
</span>
</span>
)}
</header>
<div className="overflow-auto"> <div className="overflow-auto">
<div className="inline-block min-w-full"> <div className="inline-block min-w-full">
{file.hunks.map((hunk, hunkIdx) => ( {newFile
<div key={hunk.key}> ? file.hunks.map((hunk) => (
{hunkIdx > 0 && <HunkSeparator hunk={hunk} />} <NewFileLines key={hunk.key} rows={hunk.rows} />
<HunkLines rows={hunk.rows} /> ))
</div> : file.hunks.map((hunk, hunkIdx) => (
))} <div key={hunk.key}>
{hunkIdx > 0 && <HunkSeparator hunk={hunk} />}
<HunkLines rows={hunk.rows} />
</div>
))}
</div>
</div> </div>
</div> </section>
</section> )
))} })}
</div> </div>
</div> </div>
) )

View File

@@ -203,6 +203,17 @@ function inferFromInput(
const hasPath = hasAnyKey(parsed, ["file_path", "notebook_path", "path"]) const hasPath = hasAnyKey(parsed, ["file_path", "notebook_path", "path"])
if (hasPath) { if (hasPath) {
// Check write-specific input keys first — they take priority over
// kind/title because ACP ToolKind::Edit ("edit") is a category that
// covers both Edit and Write tools. Without this, a Write tool call
// (with {content, file_path}) would be classified as "edit" due to
// its kind, then rendered with EditToolInput which expects
// old_string/new_string and produces blank output for new files.
if (
hasAnyKey(parsed, ["content", "new_source", "cell_type", "edit_mode"])
) {
return "write"
}
if ( if (
normalizedKind === "read" || normalizedKind === "read" ||
normalizedKind === "edit" || normalizedKind === "edit" ||
@@ -219,11 +230,6 @@ function inferFromInput(
) { ) {
return normalizedTitle return normalizedTitle
} }
if (
hasAnyKey(parsed, ["content", "new_source", "cell_type", "edit_mode"])
) {
return "write"
}
return "read" return "read"
} }