feat(roundtable): 第二/三步沙箱 md 文件支持用户编辑
复用主聊天页同款 ArtifactFileDetail 编辑能力:新增 allowVirtualMarkdownEdit 开关,圆桌沙箱里 write-file 虚拟 md 在流式结束后切回真实 artifacts API (可加载 + PATCH 保存),由 Step2SandboxLayout 与 HighFidelityReport 启用。 主聊天页等其它调用方默认关闭、行为不变。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8751ee7361
commit
49101ef0e8
3 files changed
+31
-5
No files matched your search
@@ -121,12 +121,19 @@ export function ArtifactFileDetail({
|
|||||||
filepath: filepathFromProps,
|
filepath: filepathFromProps,
|
||||||
threadId,
|
threadId,
|
||||||
onClose,
|
onClose,
|
||||||
|
allowVirtualMarkdownEdit = false,
|
||||||
}: {
|
}: {
|
||||||
className?: string;
|
className?: string;
|
||||||
filepath: string;
|
filepath: string;
|
||||||
threadId: string;
|
threadId: string;
|
||||||
/** 覆盖默认关闭行为(仅 setOpen(false));圆桌 Step3 文件预览用于退出沙箱模式。 */
|
/** 覆盖默认关闭行为(仅 setOpen(false));圆桌 Step3 文件预览用于退出沙箱模式。 */
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
|
/**
|
||||||
|
* 圆桌沙箱(Step2/Step3)用:流式结束后,把 `write-file:` 虚拟 md 预览切回真实
|
||||||
|
* artifacts API(可加载 + PATCH 保存),从而支持用户编辑(对齐主聊天页 md 可编辑)。
|
||||||
|
* 默认 false —— 主聊天页等其它调用方行为不变。
|
||||||
|
*/
|
||||||
|
allowVirtualMarkdownEdit?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { artifacts, setOpen, select } = useArtifacts();
|
const { artifacts, setOpen, select } = useArtifacts();
|
||||||
@@ -141,10 +148,6 @@ export function ArtifactFileDetail({
|
|||||||
}
|
}
|
||||||
return filepathFromProps;
|
return filepathFromProps;
|
||||||
}, [filepathFromProps, isWriteFileVirtual]);
|
}, [filepathFromProps, isWriteFileVirtual]);
|
||||||
/** write_file 流式预览走 tool args 文本;图片等二进制产物始终走 artifacts API。 */
|
|
||||||
const useWriteFileStreaming = useMemo(() => {
|
|
||||||
return isWriteFileVirtual && !isImageFile(filepath);
|
|
||||||
}, [filepath, isWriteFileVirtual]);
|
|
||||||
const isSkillFile = useMemo(() => {
|
const isSkillFile = useMemo(() => {
|
||||||
return filepath.endsWith(".skill");
|
return filepath.endsWith(".skill");
|
||||||
}, [filepath]);
|
}, [filepath]);
|
||||||
@@ -153,6 +156,24 @@ export function ArtifactFileDetail({
|
|||||||
const isSpreadsheetFile = useMemo(() => {
|
const isSpreadsheetFile = useMemo(() => {
|
||||||
return /\.xlsx$/i.test(filepath);
|
return /\.xlsx$/i.test(filepath);
|
||||||
}, [filepath]);
|
}, [filepath]);
|
||||||
|
// 圆桌沙箱:write_file 虚拟预览的 md 在流式结束(thread 非 loading)后,切回真实
|
||||||
|
// artifacts API 加载并允许编辑/保存。流式进行中仍走内存 stub 只读预览;仅
|
||||||
|
// allowVirtualMarkdownEdit 开启的调用方(Step2/Step3 沙箱)生效,主聊天页不受影响。
|
||||||
|
const editVirtualMarkdown = useMemo(() => {
|
||||||
|
return (
|
||||||
|
allowVirtualMarkdownEdit &&
|
||||||
|
isWriteFileVirtual &&
|
||||||
|
!isImageFile(filepath) &&
|
||||||
|
!isMock &&
|
||||||
|
!thread.isLoading &&
|
||||||
|
checkCodeFile(filepath).language === "markdown"
|
||||||
|
);
|
||||||
|
}, [allowVirtualMarkdownEdit, isWriteFileVirtual, filepath, isMock, thread.isLoading]);
|
||||||
|
/** write_file 流式预览走 tool args 文本;图片等二进制产物始终走 artifacts API;
|
||||||
|
* 圆桌结束后可编辑的 md(editVirtualMarkdown)亦回到真实 API(可加载 + PATCH 保存)。 */
|
||||||
|
const useWriteFileStreaming = useMemo(() => {
|
||||||
|
return isWriteFileVirtual && !isImageFile(filepath) && !editVirtualMarkdown;
|
||||||
|
}, [filepath, isWriteFileVirtual, editVirtualMarkdown]);
|
||||||
const { isCodeFile, language } = useMemo(() => {
|
const { isCodeFile, language } = useMemo(() => {
|
||||||
if (useWriteFileStreaming) {
|
if (useWriteFileStreaming) {
|
||||||
let nextLanguage = checkCodeFile(filepath).language;
|
let nextLanguage = checkCodeFile(filepath).language;
|
||||||
@@ -173,7 +194,10 @@ export function ArtifactFileDetail({
|
|||||||
}, [language]);
|
}, [language]);
|
||||||
const { content, isApplyingEdit } = useArtifactContent({
|
const { content, isApplyingEdit } = useArtifactContent({
|
||||||
threadId,
|
threadId,
|
||||||
filepath: filepathFromProps,
|
// editVirtualMarkdown:用解码后的真实路径走 artifacts API(而非 write-file 虚拟
|
||||||
|
// URL),这样保存后 useUpdateArtifactContent 写入的查询缓存才能命中,编辑内容
|
||||||
|
// 不会被旧的内存 stub 值覆盖回退。
|
||||||
|
filepath: editVirtualMarkdown ? filepath : filepathFromProps,
|
||||||
enabled: isCodeFile && !useWriteFileStreaming,
|
enabled: isCodeFile && !useWriteFileStreaming,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1009,6 +1009,7 @@ export const HighFidelityReport: React.FC<HighFidelityReportProps> = ({
|
|||||||
filepath={fileSandboxVirtualUrl}
|
filepath={fileSandboxVirtualUrl}
|
||||||
threadId={fileSandboxTarget.threadId}
|
threadId={fileSandboxTarget.threadId}
|
||||||
onClose={handleCloseFileSandbox}
|
onClose={handleCloseFileSandbox}
|
||||||
|
allowVirtualMarkdownEdit
|
||||||
/>
|
/>
|
||||||
</ThreadContext.Provider>
|
</ThreadContext.Provider>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ export function Step2SandboxLayout({
|
|||||||
filepath={selectedArtifact}
|
filepath={selectedArtifact}
|
||||||
threadId={previewThreadId}
|
threadId={previewThreadId}
|
||||||
onClose={artifactsFill && onArtifactsClose ? handleArtifactsClose : undefined}
|
onClose={artifactsFill && onArtifactsClose ? handleArtifactsClose : undefined}
|
||||||
|
allowVirtualMarkdownEdit
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="relative flex size-full justify-center">
|
<div className="relative flex size-full justify-center">
|
||||||
|
|||||||
Reference in new issue
Block a user