bug修改

This commit is contained in:
董宏凯 committed 2026-08-26 15:46:49 +08:00
1 parent 910cee9e67
commit 704438b3d2
6 files changed
+278 -36

No files matched your search

@@ -76,6 +76,7 @@ import {
useArtifactContent,
useUpdateArtifactContent,
} from "@/core/artifacts/hooks";
import { isWriteFileInFlight } from "@/core/artifacts/write-file-in-flight";
import { resolveArtifactURL, urlOfArtifact } from "@/core/artifacts/utils";
import {
isSandboxStreamPerfEnabled,
@@ -308,19 +309,33 @@ export function ArtifactFileDetail({
const isSpreadsheetFile = useMemo(() => {
return /\.xlsx$/i.test(filepath);
}, [filepath]);
// 圆桌沙箱:write_file 虚拟预览的 md 在流式结束(thread 非 loading)后,切回真实
// artifacts API 加载并允许编辑/保存。流式进行中仍走内存 stub 只读预览;仅
// allowVirtualMarkdownEdit 开启的调用方(Step2/Step3 沙箱)生效,主聊天页不受影响。
// 仅当「当前这个文件」的 write_file 还没返回 tool result 时才算在写。
// 不能用 thread.isLoading:用户协助后的下一轮问答也会 loading,否则会把已写完的
// md 从 CodeMirror 拽回巨大 textarea,主线程卡住、聊天变成「发送中然后一口气出来」。
const writeFileInFlight = useMemo(() => {
if (!isWriteFileVirtual || isImageFile(filepath)) {
return false;
}
return isWriteFileInFlight(thread, filepathFromProps);
}, [filepath, filepathFromProps, isWriteFileVirtual, thread.messages]);
// 圆桌/主聊天沙箱:write_file 虚拟预览的 md 在该文件写完后切回真实 artifacts API
// (可加载 + PATCH 保存)。后续问答轮次的 loading 不再把预览拽回去。
const editVirtualMarkdown = useMemo(() => {
return (
allowVirtualMarkdownEdit &&
isWriteFileVirtual &&
!isImageFile(filepath) &&
!isMock &&
!thread.isLoading &&
!writeFileInFlight &&
checkCodeFile(filepath).language === "markdown"
);
}, [allowVirtualMarkdownEdit, isWriteFileVirtual, filepath, isMock, thread.isLoading]);
}, [
allowVirtualMarkdownEdit,
isWriteFileVirtual,
filepath,
isMock,
writeFileInFlight,
]);
/** write_file 流式预览走 tool args 文本;图片等二进制产物始终走 artifacts API;
* 圆桌结束后可编辑的 md(editVirtualMarkdown)亦回到真实 API(可加载 + PATCH 保存)。 */
const useWriteFileStreaming = useMemo(() => {
@@ -377,7 +392,7 @@ export function ArtifactFileDetail({
language === "markdown" &&
!isSkillFile &&
!isMock &&
!thread.isLoading &&
!writeFileInFlight &&
(canEditArtifact || useWriteFileStreaming);
const [draftContent, setDraftContent] = useState("");
const [hasLocalEdits, setHasLocalEdits] = useState(false);
@@ -406,7 +421,7 @@ export function ArtifactFileDetail({
? draftContent
: (content ?? ""));
const streamPerfEnabled = isSandboxStreamPerfEnabled();
const isLiveStreaming = thread.isLoading || documentRewriteActive;
const isLiveStreaming = writeFileInFlight || documentRewriteActive;
const sandboxDisplayText = useMemo(() => {
const raw = displayContent ?? "";
if (disableDesensitize) return raw;
@@ -426,7 +441,7 @@ export function ArtifactFileDetail({
const isAutoPreviewLanguage =
language === "html" || language === "markdown" || language === "mermaid";
const isPreviewStreaming =
isAutoPreviewLanguage && (thread.isLoading || documentRewriteActive);
isAutoPreviewLanguage && (writeFileInFlight || documentRewriteActive);
const hasMultipleArtifacts = (artifacts?.length ?? 0) > 1;
const fileTypeLabel = useMemo(() => {
if (isImageFile(filepath)) return "IMG";
@@ -889,7 +904,7 @@ export function ArtifactFileDetail({
}
if (language === "html") {
setViewMode(thread.isLoading ? "code" : "preview");
setViewMode(writeFileInFlight || documentRewriteActive ? "code" : "preview");
return;
}
@@ -899,14 +914,20 @@ export function ArtifactFileDetail({
}
setViewMode("code");
}, [isPreviewStreaming, isSupportPreview, language, thread.isLoading]);
}, [
documentRewriteActive,
isPreviewStreaming,
isSupportPreview,
language,
writeFileInFlight,
]);
useEffect(() => {
if (!allowAutoViewSwitch || !isAutoPreviewLanguage) {
return;
}
if (thread.isLoading) {
if (writeFileInFlight || documentRewriteActive) {
setViewMode("code");
return;
}
@@ -918,7 +939,13 @@ export function ArtifactFileDetail({
}, 1400);
return () => window.clearTimeout(timeoutId);
}, [allowAutoViewSwitch, isAutoPreviewLanguage, isSupportPreview, thread.isLoading]);
}, [
allowAutoViewSwitch,
documentRewriteActive,
isAutoPreviewLanguage,
isSupportPreview,
writeFileInFlight,
]);
const scrollArtifactToBottom = useCallback(
(behavior: ScrollBehavior = "auto") => {
@@ -1015,13 +1042,13 @@ export function ArtifactFileDetail({
}, [filepath, threadId, isMock, isCodeFile, isSpreadsheetFile, isWriteFileVirtual, publicShareCode]);
const handlePauseAutoScroll = useCallback(() => {
if (!thread.isLoading || !autoScrollEnabled) {
if (!isLiveStreaming || !autoScrollEnabled) {
return;
}
setAutoScrollEnabled(false);
setShowResumeAutoScroll(true);
}, [autoScrollEnabled, thread.isLoading]);
}, [autoScrollEnabled, isLiveStreaming]);
const handleResumeAutoScroll = useCallback(() => {
setAutoScrollEnabled(true);
@@ -1774,7 +1801,7 @@ export function ArtifactFileDetail({
}
: undefined
}
isStreaming={thread.isLoading}
isStreaming={writeFileInFlight || documentRewriteActive}
streamingReadonlyFallback={!canEditArtifact}
/>
</div>