From 8b732b43eea295a8439feaaa9ff4691c92c7a8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E5=AE=8F=E5=87=AF?= Date: Tue, 4 Aug 2026 00:54:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E5=90=8C=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E4=BA=8C=E6=AC=A1=20write=5Ffile=20=E6=97=B6=E9=87=8D=E6=8C=82?= =?UTF-8?q?=E5=B2=97=E4=BD=8D=E4=BC=9A=E5=95=86=E6=B2=99=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按 tool-call 身份区分预览,避免同路径重写复用旧 previewKey 导致沙箱不刷新。 Co-authored-by: Cursor --- .../components/PositionNodeChat.tsx | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/frontend-web/src/position-roundtable/components/PositionNodeChat.tsx b/frontend-web/src/position-roundtable/components/PositionNodeChat.tsx index 600d4c2b..f566fbb1 100644 --- a/frontend-web/src/position-roundtable/components/PositionNodeChat.tsx +++ b/frontend-web/src/position-roundtable/components/PositionNodeChat.tsx @@ -757,20 +757,28 @@ export function PositionNodeChat({ } // One write_file call should open at most one preview. The parent further // guards manual close state, because it owns the page-wide singleton sandbox. - // A report is often rewritten to the same output path. The tool-call key - // (not just the path) makes that a new previewable delivery. + // A report is often rewritten to the same output path — identity must be the + // tool-call key, not the path, otherwise a second write keeps the old panel + // and the sandbox never clears / remounts for the rewrite. + const toolCallKey = newStreamingArtifact.key; + const toolCallId = toolCallKey.includes(":") + ? toolCallKey.slice(toolCallKey.lastIndexOf(":") + 1) + : undefined; const startedPreview = activeWriteFilePreviewRef.current; - const previewKey = - startedPreview?.path === newStreamingArtifact.sourcePath - ? startedPreview.previewKey - : newStreamingArtifact.key; - if (!startedPreview || startedPreview.path !== newStreamingArtifact.sourcePath) { - activeWriteFilePreviewRef.current = { - path: newStreamingArtifact.sourcePath, - previewKey, - toolCallId: startedPreview?.toolCallId, - }; - } + const isSameToolCall = + startedPreview != null && + (startedPreview.previewKey === toolCallKey || + (toolCallId != null && + (startedPreview.toolCallId === toolCallId || + startedPreview.previewKey.endsWith(`:${toolCallId}`)))); + // Same tool call may upgrade a provisional filename → real path; keep the + // open panel. A different tool call is a new delivery even on the same path. + const previewKey = isSameToolCall ? startedPreview.previewKey : toolCallKey; + activeWriteFilePreviewRef.current = { + path: newStreamingArtifact.sourcePath, + previewKey, + toolCallId: toolCallId ?? startedPreview?.toolCallId, + }; // The path takes part in the identity so that a preview opened under a // provisional name is re-published once the real path streams in. The // preview key stays the same, so the parent treats it as an update of the