feat(沙箱): md 产物支持 AI 写作编辑与划词改写
- 新增 MarkdownAiEditor,复用 AI 写作的 TipTap 编辑器与 AI 改写流程 - 沙箱 md 增加 AI 写作视图切换,默认仍为预览;单文件隐藏文件名避免工具栏错位 - 单智能体聊天页开启 allowVirtualMarkdownEdit,生成完成后可编辑 - 会商总结页续看时自动收起研讨原料侧栏 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
44d7304f8e
commit
9268c73776
4 files changed
+230
-4
No files matched your search
@@ -11,6 +11,7 @@ import {
|
||||
LoaderIcon,
|
||||
PackageIcon,
|
||||
SaveIcon,
|
||||
SparklesIcon,
|
||||
UploadCloudIcon,
|
||||
XIcon,
|
||||
} from "lucide-react";
|
||||
@@ -37,6 +38,7 @@ import {
|
||||
} from "@/components/ui/select";
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||
import { CodeEditor } from "@/components/workspace/code-editor";
|
||||
import { MarkdownAiEditor } from "@/open-canvas/components/artifact/MarkdownAiEditor";
|
||||
import { publishArtifactToKnowledge } from "@/core/agents/api";
|
||||
import { useAgent } from "@/core/agents/hooks";
|
||||
import { apiFetch } from "@/core/api";
|
||||
@@ -213,6 +215,10 @@ export function ArtifactFileDetail({
|
||||
!useWriteFileStreaming &&
|
||||
!isSkillFile &&
|
||||
!isMock;
|
||||
// 「AI 写作」md 展示开关:只要是可编辑的 markdown 就提供「AI 写作」视图(在 源码/预览 旁多一个
|
||||
// 切换项),用户可随时切过去体验划词「AI 改写」。默认仍是「预览」,避免编辑器在内容加载期间
|
||||
// 挂载导致白屏 + 避免复杂 md(表格/公式/HTML)误入有损编辑。
|
||||
const canUseAiEditor = canEditArtifact;
|
||||
const [draftContent, setDraftContent] = useState("");
|
||||
const [hasLocalEdits, setHasLocalEdits] = useState(false);
|
||||
const updateArtifact = useUpdateArtifactContent();
|
||||
@@ -230,7 +236,7 @@ export function ArtifactFileDetail({
|
||||
return "FILE";
|
||||
}, [filepath, isSkillFile, isSpreadsheetFile, language]);
|
||||
|
||||
const [viewMode, setViewMode] = useState<"code" | "preview">("code");
|
||||
const [viewMode, setViewMode] = useState<"code" | "preview" | "edit">("code");
|
||||
const [allowAutoViewSwitch, setAllowAutoViewSwitch] = useState(true);
|
||||
const [isInstalling, setIsInstalling] = useState(false);
|
||||
const [showPreviewSwitchPulse, setShowPreviewSwitchPulse] = useState(false);
|
||||
@@ -267,6 +273,7 @@ export function ArtifactFileDetail({
|
||||
return;
|
||||
}
|
||||
|
||||
// md/mermaid 默认预览(AI 写作视图作为可选切换项,由用户手动进入)。
|
||||
if (isSupportPreview) {
|
||||
setViewMode("preview");
|
||||
return;
|
||||
@@ -598,7 +605,9 @@ export function ArtifactFileDetail({
|
||||
{fileTypeLabel}
|
||||
</span>
|
||||
<ArtifactTitle className="min-w-0">
|
||||
{useWriteFileStreaming ? (
|
||||
{/* markdown:隐藏文件名(仅留 MD 徽标),把横向空间让给工具栏,避免窄面板下
|
||||
工具栏换行错位;多文件仍保留切换下拉(靠它切文件)。文件名仍可在下载/另存为时取到。 */}
|
||||
{language === "markdown" && !hasMultipleArtifacts ? null : useWriteFileStreaming ? (
|
||||
<div className="truncate px-3">{getFileName(filepath)}</div>
|
||||
) : hasMultipleArtifacts ? (
|
||||
<Select value={filepath} onValueChange={select}>
|
||||
@@ -638,10 +647,19 @@ export function ArtifactFileDetail({
|
||||
onValueChange={(value) => {
|
||||
if (value) {
|
||||
setAllowAutoViewSwitch(false);
|
||||
setViewMode(value as "code" | "preview");
|
||||
setViewMode(value as "code" | "preview" | "edit");
|
||||
}
|
||||
}}
|
||||
>
|
||||
{canUseAiEditor && (
|
||||
<ToggleGroupItem
|
||||
className="text-muted-foreground h-8 min-w-10 rounded-full border-0 bg-transparent px-3 shadow-none data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-[0_6px_14px_-10px_rgba(15,23,42,0.35)]"
|
||||
value="edit"
|
||||
aria-label="AI 写作编辑"
|
||||
>
|
||||
<SparklesIcon />
|
||||
</ToggleGroupItem>
|
||||
)}
|
||||
<ToggleGroupItem
|
||||
className="text-muted-foreground h-8 min-w-10 rounded-full border-0 bg-transparent px-3 shadow-none data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-[0_6px_14px_-10px_rgba(15,23,42,0.35)]"
|
||||
value="code"
|
||||
@@ -803,6 +821,17 @@ export function ArtifactFileDetail({
|
||||
滑动到底部并继续自动下滑
|
||||
</button>
|
||||
)}
|
||||
{viewMode === "edit" && canUseAiEditor && (
|
||||
<MarkdownAiEditor
|
||||
// 编辑用原始内容(与源码模式一致,不脱敏);保存仍走头部「保存 Markdown」按钮。
|
||||
markdown={displayContent ?? ""}
|
||||
onChange={(value) => {
|
||||
setDraftContent(value);
|
||||
setHasLocalEdits(true);
|
||||
}}
|
||||
threadId={threadId}
|
||||
/>
|
||||
)}
|
||||
{isSupportPreview &&
|
||||
viewMode === "preview" &&
|
||||
(language === "markdown" ||
|
||||
|
||||
@@ -423,6 +423,7 @@ const ChatBox: React.FC<{
|
||||
className="size-full"
|
||||
filepath={selectedArtifact}
|
||||
threadId={threadId}
|
||||
allowVirtualMarkdownEdit
|
||||
/>
|
||||
</TabsContent>
|
||||
<TabsContent value="references" className="min-h-0 flex-1 overflow-y-auto p-0">
|
||||
@@ -437,6 +438,7 @@ const ChatBox: React.FC<{
|
||||
className="size-full"
|
||||
filepath={selectedArtifact}
|
||||
threadId={threadId}
|
||||
allowVirtualMarkdownEdit
|
||||
/>
|
||||
) : hasCitationReferences ? (
|
||||
<div className="relative size-full overflow-hidden">
|
||||
|
||||
Reference in new issue
Block a user