fix(frontend): 同路径二次 write_file 时重挂岗位会商沙箱

按 tool-call 身份区分预览,避免同路径重写复用旧 previewKey 导致沙箱不刷新。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
董宏凯andCursor committed 2026-08-04 00:54:15 +08:00
1 parent 69e455274a
commit 8b732b43ee
1 file changed
+21 -13
@@ -757,20 +757,28 @@ export function PositionNodeChat({
} }
// One write_file call should open at most one preview. The parent further // 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. // 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 // A report is often rewritten to the same output path — identity must be the
// (not just the path) makes that a new previewable delivery. // 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 startedPreview = activeWriteFilePreviewRef.current;
const previewKey = const isSameToolCall =
startedPreview?.path === newStreamingArtifact.sourcePath startedPreview != null &&
? startedPreview.previewKey (startedPreview.previewKey === toolCallKey ||
: newStreamingArtifact.key; (toolCallId != null &&
if (!startedPreview || startedPreview.path !== newStreamingArtifact.sourcePath) { (startedPreview.toolCallId === toolCallId ||
activeWriteFilePreviewRef.current = { startedPreview.previewKey.endsWith(`:${toolCallId}`))));
path: newStreamingArtifact.sourcePath, // Same tool call may upgrade a provisional filename → real path; keep the
previewKey, // open panel. A different tool call is a new delivery even on the same path.
toolCallId: startedPreview?.toolCallId, 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 // 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 // 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 // preview key stays the same, so the parent treats it as an update of the