diff --git a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx index 314a5488d..b75967053 100644 --- a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx +++ b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx @@ -3373,6 +3373,26 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { } }, [isAgentMode]); + useEffect(() => { + if (isVideoMode || typeof window === "undefined") return; + + const handleCanvasChatPanelOpenRequest = () => { + setPanelMode("chat"); + setIsPanelOpen(true); + }; + + window.addEventListener( + "canvas-open-chat-panel-request", + handleCanvasChatPanelOpenRequest + ); + return () => { + window.removeEventListener( + "canvas-open-chat-panel-request", + handleCanvasChatPanelOpenRequest + ); + }; + }, [isVideoMode]); + useEffect(() => { if (shouldOpenBatchProcessing && isBatchProcessingEnabled) { router.replace(`/canvas/${id}/batch`); diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 22f897b2f..48b7e3821 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -3594,6 +3594,13 @@ export function CanvasChatPanel({ useEffect(() => { if (!effectiveAgentEnabled || typeof window === "undefined") return; + type PendingCanvasAgentSlotFillRequest = { + nodeId?: string; + label?: string; + }; + const targetWindow = window as Window & { + __canvasAgentPendingSlotFillRequest?: PendingCanvasAgentSlotFillRequest; + }; const focusComposerWithPrompt = (prompt: string) => { handleSelectGenerationMode("agent"); @@ -3618,6 +3625,10 @@ export function CanvasChatPanel({ const handleAgentSlotFillRequest = (event: Event) => { const detail = (event as CustomEvent<{ nodeId?: string; label?: string }>).detail; + const pending = targetWindow.__canvasAgentPendingSlotFillRequest; + if (!pending?.nodeId || pending.nodeId === detail?.nodeId) { + delete targetWindow.__canvasAgentPendingSlotFillRequest; + } const label = String(detail?.label || "这个槽位").trim(); const prompt = `在${label === "这个槽位" ? label : `「${label}」`}生成一张图`; @@ -3660,6 +3671,14 @@ export function CanvasChatPanel({ "canvas-agent-annotation-edit-request", handleAgentAnnotationEditRequest ); + const pendingSlotFillRequest = targetWindow.__canvasAgentPendingSlotFillRequest; + if (pendingSlotFillRequest) { + handleAgentSlotFillRequest( + new CustomEvent("canvas-agent-slot-fill-request", { + detail: pendingSlotFillRequest, + }) + ); + } return () => { window.removeEventListener( "canvas-agent-slot-fill-request", diff --git a/components/canvas/CanvasWorkspace.tsx b/components/canvas/CanvasWorkspace.tsx index a9476e3db..fc46ce170 100644 --- a/components/canvas/CanvasWorkspace.tsx +++ b/components/canvas/CanvasWorkspace.tsx @@ -687,15 +687,28 @@ export function CanvasWorkspace({ const requestFillAgentSlotFromContextMenu = useCallback(() => { if (!agentSlotContextMenu || typeof window === "undefined") return; + const detail = { + nodeId: agentSlotContextMenu.nodeId, + label: agentSlotContextMenu.label, + }; + const targetWindow = window as Window & { + __canvasAgentPendingSlotFillRequest?: typeof detail; + }; selectNode(agentSlotContextMenu.nodeId, false); - window.dispatchEvent( - new CustomEvent("canvas-agent-slot-fill-request", { + targetWindow.__canvasAgentPendingSlotFillRequest = detail; + targetWindow.dispatchEvent( + new CustomEvent("canvas-open-chat-panel-request", { detail: { - nodeId: agentSlotContextMenu.nodeId, - label: agentSlotContextMenu.label, + reason: "agent-slot-fill", + nodeId: detail.nodeId, }, }) ); + targetWindow.dispatchEvent( + new CustomEvent("canvas-agent-slot-fill-request", { + detail, + }) + ); setAgentSlotContextMenu(null); }, [agentSlotContextMenu, selectNode]); diff --git a/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md b/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md index b60bf54a6..b5a723c12 100644 --- a/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md +++ b/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md @@ -931,6 +931,7 @@ components/canvas/nodes/AgentSlotNode.tsx - “设为图片槽” - “设为视频槽” - “允许替换 / 保留版本” +- “填充此槽位”必须同时打开/切回右侧对话面板;若对话面板 lazy 未挂载,需要缓存一次 pending slot fill request,挂载后自动预填槽位生成 prompt。 ### 7.4 工具栏新增 slot 工具 @@ -1524,6 +1525,7 @@ lib/ai/runtime/middlewares/canvas-agent-clarification-gate.ts - 新增 `AgentSlotNode.tsx` - 工具栏增加图片 slot - 右键菜单支持“填充此槽位” +- 槽位右键填充会展开对话框并在面板未挂载时保留 pending request - `buildCanvasAgentContext()` 输出 slots 验收: