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
// 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