diff --git a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx index ffbf4a524..600ef6f3d 100644 --- a/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx +++ b/app/canvas/[id]/CanvasEditorLegacyPageClient.tsx @@ -1140,6 +1140,8 @@ const FLOATING_PANEL_INSET = 16; const DOCKED_PANEL_INSET = 0; const FLOATING_UI_GAP = 16; const FLOATING_BOTTOM_INSET = 20; +const FLOATING_TOOLBAR_ESTIMATED_WIDTH = 680; +const FLOATING_TOOLBAR_SIDE_DOCK_CLEARANCE = 48; const WORKFLOW_AGENT_CONTEXT_START = "【视频画布同步上下文】"; const WORKFLOW_AGENT_CONTEXT_END = "【/视频画布同步上下文】"; const AGENT_RESULT_MODE_LABELS: Record = @@ -1988,6 +1990,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { const [videoCanvasInsertMenu, setVideoCanvasInsertMenu] = useState(null); const videoCanvasInsertMenuRef = useRef(null); + const floatingToolbarContentRef = useRef(null); const [isVideoCanvasFileListOpen, setIsVideoCanvasFileListOpen] = useState(false); const [isVideoCanvasMarkerPanelOpen, setIsVideoCanvasMarkerPanelOpen] = @@ -1995,6 +1998,8 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { // 面板模式: 'chat' 聊天面板, 'fileList' 文件列表 const [panelMode, setPanelMode] = useState<"chat" | "fileList">("chat"); const [viewportWidth, setViewportWidth] = useState(0); + const [horizontalFloatingToolbarWidth, setHorizontalFloatingToolbarWidth] = + useState(0); const [workflowInputs, setWorkflowInputs] = useState({ primarySku: "", secondarySku: "", @@ -3003,6 +3008,23 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { const panelOcclusionRight = isFloatingSidebarVisible ? resolvedPanelWidth + DOCKED_PANEL_INSET : 0; + const visibleCanvasWidth = + viewportWidth > 0 ? Math.max(viewportWidth - panelOcclusionRight, 0) : 0; + const horizontalFloatingToolbarWidthForDocking = + horizontalFloatingToolbarWidth || FLOATING_TOOLBAR_ESTIMATED_WIDTH; + const shouldDockFloatingToolbarToSide = + !isVideoMode && + isFloatingSidebarVisible && + visibleCanvasWidth > 0 && + visibleCanvasWidth < + horizontalFloatingToolbarWidthForDocking + + FLOATING_TOOLBAR_SIDE_DOCK_CLEARANCE * 2; + const floatingToolbarTooltipSide = shouldDockFloatingToolbarToSide + ? "right" + : "top"; + const floatingToolbarDropdownSide = shouldDockFloatingToolbarToSide + ? "right" + : "bottom"; const floatingToolbarOffset = isFloatingSidebarVisible ? -(panelOcclusionRight / 2) : 0; @@ -3487,6 +3509,43 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { ); }, [viewportWidth]); + useEffect(() => { + if (typeof window === "undefined") { + return; + } + + const toolbarElement = floatingToolbarContentRef.current; + if (!toolbarElement) { + return; + } + + const measureHorizontalToolbar = () => { + if (toolbarElement.dataset.canvasToolbarOrientation !== "horizontal") { + return; + } + + const nextWidth = Math.ceil(toolbarElement.getBoundingClientRect().width); + if (!Number.isFinite(nextWidth) || nextWidth <= 0) { + return; + } + + setHorizontalFloatingToolbarWidth((currentWidth) => + Math.abs(currentWidth - nextWidth) > 1 ? nextWidth : currentWidth + ); + }; + + measureHorizontalToolbar(); + + const resizeObserver = new ResizeObserver(measureHorizontalToolbar); + resizeObserver.observe(toolbarElement); + window.addEventListener("resize", measureHorizontalToolbar); + + return () => { + resizeObserver.disconnect(); + window.removeEventListener("resize", measureHorizontalToolbar); + }; + }, []); + useEffect(() => { if ( !isFloatingPanelWidthStorageReady || @@ -10720,17 +10779,38 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { {/* 5. Floating Toolbar (Bottom) */}
@@ -10759,7 +10839,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + {getCanvasToolbarItem(canvasToolbarConfig, "selectTool").label}{" "} (V) @@ -10786,7 +10866,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { - + { getCanvasToolbarItem( canvasToolbarConfig, @@ -10795,7 +10875,10 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { } - + handleAddAgentImageSlotNode()} > @@ -10843,7 +10926,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + {getCanvasToolbarItem(canvasToolbarConfig, "panTool").label} (H) @@ -10872,7 +10955,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { )} - + { getCanvasToolbarItem(canvasToolbarConfig, "saveCanvas") .label @@ -10903,7 +10986,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem(canvasToolbarConfig, "cloudFiles") .label @@ -10939,7 +11022,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem(canvasToolbarConfig, "markerPanel") .label @@ -10976,7 +11059,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem( canvasToolbarConfig, @@ -11023,7 +11106,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + {getCanvasToolbarItem(canvasToolbarConfig, "styleMode").label} @@ -11052,7 +11135,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + {getCanvasToolbarItem(canvasToolbarConfig, "stylePro").label} @@ -11081,7 +11164,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem(canvasToolbarConfig, "batchProcessing") .label @@ -11112,7 +11195,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem( canvasToolbarConfig, @@ -11144,7 +11227,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem( canvasToolbarConfig, @@ -11173,7 +11256,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem(canvasToolbarConfig, "addVideoInput") .label @@ -11207,9 +11290,9 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) {
@@ -11306,7 +11389,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { resolveCanvasToolbarItemWithFallback( canvasToolbarConfig, @@ -11353,7 +11436,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + {selectedImageNode ? resolveCanvasToolbarItemWithFallback( canvasToolbarConfig, @@ -11398,7 +11481,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + {getCanvasToolbarItem(canvasToolbarConfig, "model3d").label} @@ -11422,7 +11505,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem( canvasToolbarConfig, @@ -11457,7 +11540,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { )} - + { getCanvasToolbarItem( canvasToolbarConfig, @@ -11490,7 +11573,7 @@ export default function CanvasEditorLegacyPage({ params }: PageProps) { /> - + { getCanvasToolbarItem( canvasToolbarConfig, diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index c3bf1eee6..4255c8565 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -362,6 +362,17 @@ function normalizeClawdComposerText(value: string) { .trim(); } +function buildClawdSkillTagPrompt(tag: Pick | null) { + if (!tag) return ""; + + const tagName = String(tag.name || "").trim() || "快捷标签"; + const tagPrompt = String(tag.prompt || "").trim(); + return [ + `【快捷标签:${tagName}】`, + tagPrompt || `用户选择了「${tagName}」快捷标签,请按该标签对应能力处理。`, + ].join("\n"); +} + type ClawdComposerSubmissionSnapshot = { chatId: string; canvasId?: string; @@ -1591,6 +1602,8 @@ interface CanvasChatSession { title: string; createdAt: number; updatedAt: number; + clawdSkillTagId?: string | null; + clawdSkillTagPromptApplied?: boolean; } const CANVAS_CHAT_QUERY_PARAM = "chat"; @@ -2054,6 +2067,51 @@ export function CanvasChatPanel({ [activeChatId, chatSessions.length, releaseSendGuard, replaceChatSessionQuery] ); + const setSessionClawdSkillTag = useCallback( + ( + chatSessionId: string, + tagId: string | null, + options?: { promptApplied?: boolean } + ) => { + if (!chatSessionId) return; + const normalizedTagId = String(tagId || "").trim() || null; + setChatSessions((prevSessions) => + prevSessions.map((session) => + session.id === chatSessionId + ? { + ...session, + clawdSkillTagId: normalizedTagId, + clawdSkillTagPromptApplied: + normalizedTagId === null + ? false + : options?.promptApplied === true, + updatedAt: Date.now(), + } + : session + ) + ); + }, + [] + ); + + const markSessionClawdSkillTagPromptApplied = useCallback( + (chatSessionId: string, tagId: string) => { + if (!chatSessionId || !tagId) return; + setChatSessions((prevSessions) => + prevSessions.map((session) => + session.id === chatSessionId && session.clawdSkillTagId === tagId + ? { + ...session, + clawdSkillTagPromptApplied: true, + updatedAt: Date.now(), + } + : session + ) + ); + }, + [] + ); + const handleTypewriterActiveChange = useCallback((typingKey: string, active: boolean) => { setActiveTypingSections((prev) => { if (active) { @@ -2351,13 +2409,19 @@ export function CanvasChatPanel({ const saved = localStorage.getItem(sessionStorageKey); const parsed = saved ? (JSON.parse(saved) as CanvasChatSession[]) : []; - const sanitized = parsed + const sanitized: CanvasChatSession[] = parsed .filter((session) => session?.id) - .map((session) => ({ + .map((session): CanvasChatSession => ({ id: session.id, title: (session.title || "").trim() || "新对话", createdAt: Number(session.createdAt) || now, updatedAt: Number(session.updatedAt) || now, + clawdSkillTagId: + typeof (session as CanvasChatSession).clawdSkillTagId === "string" + ? (session as CanvasChatSession).clawdSkillTagId || null + : null, + clawdSkillTagPromptApplied: + (session as CanvasChatSession).clawdSkillTagPromptApplied === true, })); let nextSessions = sanitized; @@ -3584,6 +3648,17 @@ export function CanvasChatPanel({ () => canvasSkillTags.find((tag) => tag.id === selectedSkillTagId) || null, [canvasSkillTags, selectedSkillTagId] ); + const activeChatSession = useMemo( + () => chatSessions.find((session) => session.id === activeChatId) || null, + [activeChatId, chatSessions] + ); + const activeClawdSkillTag = useMemo(() => { + const tagId = String(activeChatSession?.clawdSkillTagId || "").trim(); + if (!tagId) return null; + return canvasSkillTags.find((tag) => tag.id === tagId) || null; + }, [activeChatSession?.clawdSkillTagId, canvasSkillTags]); + const activeClawdSkillTagPromptApplied = + activeChatSession?.clawdSkillTagPromptApplied === true; const selectedAgentPreset = useMemo( () => (agentPresetResponse?.success && agentPresetResponse.data ? agentPresetResponse.data : null), [agentPresetResponse] @@ -3600,6 +3675,10 @@ export function CanvasChatPanel({ () => getCanvasSkillIconComponent(selectedSkillTag?.iconName), [selectedSkillTag?.iconName] ); + const ActiveClawdSkillTagIcon = useMemo( + () => getCanvasSkillIconComponent(activeClawdSkillTag?.iconName), + [activeClawdSkillTag?.iconName] + ); useEffect(() => { if (!selectedSkillTagId) return; @@ -4571,21 +4650,21 @@ export function CanvasChatPanel({ ]); const handleSelectGenerationMode = useCallback( - (mode: CanvasComposerMode) => { + (mode: CanvasComposerMode): string | null => { hiddenPromptRef.current = null; autoContextRef.current = null; if (mode === "clawd" && !isClawdModeEnabled) { toast.error(`${CLAW_MODE_LABEL} 未开启`); - return; + return null; } if (mode === "agent") { if (!effectiveAgentEnabled) { - return; + return null; } } if (mode === "detail" && !canUseDetailGeneration) { toast.error("AI详情生成功能未开启"); - return; + return null; } const preferredImageModelId = @@ -4600,7 +4679,7 @@ export function CanvasChatPanel({ : null; if (mode === "image" && !preferredImageModelId) { toast.error("当前没有可用的图像模型"); - return; + return null; } const preferredVideoModelId = @@ -4610,21 +4689,22 @@ export function CanvasChatPanel({ : null; if (mode === "video" && !preferredVideoModelId) { toast.error("当前没有可用的视频模型"); - return; + return null; } const isSwitchingMode = mode !== activeComposerMode; + let targetChatSessionId = activeChatId; if ( isSwitchingMode && (getSendGuard(activeChatId).inFlight || isClawdSubmitting || isDetailGenerating) ) { toast.message("当前对话正在处理中,完成后再切换模式"); - return; + return null; } if (isSwitchingMode && hasActiveChatContext()) { const modeLabel = getCanvasComposerModeSessionLabel(mode); - startNewChatSession({ + targetChatSessionId = startNewChatSession({ title: `${modeLabel} 对话`, toastMessage: `已为 ${modeLabel} 新建聊天窗口`, }); @@ -4635,7 +4715,7 @@ export function CanvasChatPanel({ if (mode === "clawd") { setIsDetailGenerationMode(false); - return; + return targetChatSessionId; } if (mode === "agent") { @@ -4648,7 +4728,7 @@ export function CanvasChatPanel({ currentModelIdRef.current = preferredAgentModelId; setSelectedModelId(preferredAgentModelId); setIsDetailGenerationMode(false); - return; + return targetChatSessionId; } if (mode === "detail") { @@ -4657,7 +4737,7 @@ export function CanvasChatPanel({ setSelectedModelId(detailModelId); setIsDetailGenerationMode(true); setIsDetailWorkbenchCollapsed(true); - return; + return targetChatSessionId; } if (mode === "image") { @@ -4665,13 +4745,14 @@ export function CanvasChatPanel({ currentModelIdRef.current = nextImageModelId; setSelectedModelId(nextImageModelId); setIsDetailGenerationMode(false); - return; + return targetChatSessionId; } const nextVideoModelId = preferredVideoModelId || ""; currentModelIdRef.current = nextVideoModelId; setSelectedModelId(nextVideoModelId); setIsDetailGenerationMode(false); + return targetChatSessionId; }, [ canUseDetailGeneration, @@ -4707,6 +4788,42 @@ export function CanvasChatPanel({ isClawdModeEnabled, ]); + const handleSelectCanvasSkillTag = useCallback( + (tag: CanvasSkillTag) => { + if (!isClawdModeEnabled) { + toast.error(`${CLAW_MODE_LABEL} 未开启`); + return; + } + + if (getSendGuard(activeChatId).inFlight || isClawdSubmitting || isDetailGenerating) { + toast.message("当前对话正在处理中,完成后再切换模式"); + return; + } + + const targetChatSessionId = handleSelectGenerationMode("clawd"); + if (!targetChatSessionId) { + return; + } + setSessionClawdSkillTag(targetChatSessionId, tag.id, { + promptApplied: false, + }); + window.setTimeout(() => { + setSelectedSkillTagId(tag.id); + const editor = textareaRef.current as HTMLDivElement | null; + editor?.focus(); + }, 0); + }, + [ + activeChatId, + getSendGuard, + handleSelectGenerationMode, + isClawdModeEnabled, + isClawdSubmitting, + isDetailGenerating, + setSessionClawdSkillTag, + ] + ); + useEffect(() => { if (!effectiveAgentEnabled || typeof window === "undefined") return; const targetWindow = window as CanvasAgentPendingRequestWindow; @@ -9535,26 +9652,51 @@ export function CanvasChatPanel({ const textContent = normalizeClawdComposerText(input); const tableFilesSnapshot = [...clawdTableFiles]; const hasTableFiles = tableFilesSnapshot.length > 0; + const clawdSkillTagForRequest = activeClawdSkillTag || selectedSkillTag; + const shouldIncludeClawdSkillTagPrompt = Boolean( + clawdSkillTagForRequest && !activeClawdSkillTagPromptApplied + ); + const clawdSkillTagPrompt = shouldIncludeClawdSkillTagPrompt + ? buildClawdSkillTagPrompt(clawdSkillTagForRequest) + : ""; + const hasPendingClawdSkillTagPrompt = Boolean(clawdSkillTagPrompt); const attachmentsSnapshot = [...attachments]; const imageAttachmentsSnapshot = attachmentsSnapshot .map((attachment) => sanitizeChatAttachment(attachment)) .filter((attachment): attachment is PickedObjectAttachment => Boolean(attachment)); const hasImageAttachments = imageAttachmentsSnapshot.length > 0; - if (!textContent && !hasTableFiles && !hasImageAttachments) { + if ( + !textContent && + !hasTableFiles && + !hasImageAttachments && + !hasPendingClawdSkillTagPrompt + ) { return; } const baseRequestMessage = - textContent || getClawdDefaultPrompt(hasTableFiles, hasImageAttachments); + textContent || + (clawdSkillTagForRequest && hasPendingClawdSkillTagPrompt + ? `请按「${clawdSkillTagForRequest.name}」快捷功能处理。` + : getClawdDefaultPrompt(hasTableFiles, hasImageAttachments)); const imageReferenceText = buildClawdImageReferenceText( imageAttachmentsSnapshot ); - const requestMessage = [baseRequestMessage, imageReferenceText] + const requestMessage = [ + baseRequestMessage, + clawdSkillTagPrompt, + imageReferenceText, + ] .filter(Boolean) .join("\n\n"); + const optimisticBaseMessage = + textContent || + (clawdSkillTagForRequest && hasPendingClawdSkillTagPrompt + ? `快捷功能:${clawdSkillTagForRequest.name}` + : baseRequestMessage); const optimisticMessageText = [ - buildClawdTableDisplayText(baseRequestMessage, tableFilesSnapshot), + buildClawdTableDisplayText(optimisticBaseMessage, tableFilesSnapshot), buildClawdImageDisplayText(imageAttachmentsSnapshot), ] .filter(Boolean) @@ -9563,6 +9705,8 @@ export function CanvasChatPanel({ chatId: activeChatId, mode: "clawd", text: requestMessage, + skillTagId: clawdSkillTagForRequest?.id || null, + skillTagPrompt: clawdSkillTagPrompt, tableFiles: tableFilesSnapshot .map((file) => `${file.name}:${file.size}:${file.lastModified}`) .sort(), @@ -9578,7 +9722,7 @@ export function CanvasChatPanel({ } const nextProcessingHint = shouldShowClawdProcessingHint( - textContent, + [textContent, clawdSkillTagPrompt].filter(Boolean).join("\n\n"), hasTableFiles, hasImageAttachments ) @@ -9615,6 +9759,9 @@ export function CanvasChatPanel({ startedAt: clawdSubmissionStartedAt, submittedTexts: [ textContent, + clawdSkillTagForRequest?.name || "", + clawdSkillTagForRequest?.prompt || "", + clawdSkillTagPrompt, baseRequestMessage, requestMessage, optimisticMessageText, @@ -9637,6 +9784,7 @@ export function CanvasChatPanel({ }); setAttachments([]); setClawdTableFiles([]); + setSelectedSkillTagId(null); clearSelection(); try { @@ -9666,6 +9814,13 @@ export function CanvasChatPanel({ throw new Error(responseData?.error || `${CLAW_MODE_LABEL} 请求失败`); } + if (clawdSkillTagPrompt && clawdSkillTagForRequest) { + markSessionClawdSkillTagPromptApplied( + activeChatId, + clawdSkillTagForRequest.id + ); + } + const returnedMessages = Array.isArray(responseData?.messages) ? (responseData.messages as ChatMessage[]) : []; @@ -9711,6 +9866,9 @@ export function CanvasChatPanel({ toast.error(error instanceof Error ? error.message : `${CLAW_MODE_LABEL} 请求失败`); setClawdTableFiles(tableFilesSnapshot); setAttachments(attachmentsSnapshot); + if (clawdSkillTagForRequest && hasPendingClawdSkillTagPrompt) { + setSelectedSkillTagId(clawdSkillTagForRequest.id); + } const editableDiv = textareaRef.current as HTMLDivElement | null; const currentEditorText = (editableDiv?.textContent || "") .replace(/\u200b/g, " ") @@ -10042,9 +10200,11 @@ export function CanvasChatPanel({ chatScope, rawChatId, input, - attachments, - clawdTableFiles, - hasAgentUploadSlots, + attachments, + clawdTableFiles, + activeClawdSkillTag, + activeClawdSkillTagPromptApplied, + hasAgentUploadSlots, hasWorkflowContext, selectedSkillTag, selectedAgentPreset, @@ -10081,8 +10241,9 @@ export function CanvasChatPanel({ clearRestoredClawdComposerText, shouldBlockDuplicateSend, status, - mutate, - buildHistoryMessagesUrl, + mutate, + markSessionClawdSkillTagPromptApplied, + buildHistoryMessagesUrl, workflowContext, ]); @@ -10713,7 +10874,9 @@ export function CanvasChatPanel({ const hasEnoughAgentUploads = !hasAgentUploadSlots || attachments.length >= agentRequiredUploadCount; const composerPlaceholder = isWorkspacePresentation ? isClawdMode - ? `输入要交给 ${CLAW_MODE_LABEL} 的问题,可上传图片或表格` + ? activeClawdSkillTag + ? `继续向 ${CLAW_MODE_LABEL} 提问,当前使用「${activeClawdSkillTag.name}」` + : `输入要交给 ${CLAW_MODE_LABEL} 的问题,可上传图片或表格` : isDetailGenerationMode ? "可选补充:风格、情绪氛围、禁用元素、期望生成张数(如:生成8张)" : isVideoWorkspace @@ -10724,7 +10887,9 @@ export function CanvasChatPanel({ ? "可选补充本次生图要求,例如:高级感、暖灰色、近景特写、生成3张。" : "可选补充本次生成要求,例如:更高级、更生活化、暖调灯光。" : isClawdMode - ? `输入要交给 ${CLAW_MODE_LABEL} 的问题,可上传图片或表格` + ? activeClawdSkillTag + ? `继续向 ${CLAW_MODE_LABEL} 提问,当前使用「${activeClawdSkillTag.name}」` + : `输入要交给 ${CLAW_MODE_LABEL} 的问题,可上传图片或表格` : isDetailGenerationMode ? "可选补充:风格、情绪氛围、禁用元素、期望生成张数(如:生成8张)" : isVideoWorkspace @@ -10749,7 +10914,12 @@ export function CanvasChatPanel({ ? Math.min(100, Math.round((detailProgress.current / detailProgress.total) * 100)) : 0; const canSend = isClawdMode - ? Boolean(input.trim() || attachments.length > 0 || clawdTableFiles.length > 0) && !isClawdSubmitting + ? Boolean( + input.trim() || + attachments.length > 0 || + clawdTableFiles.length > 0 || + (activeClawdSkillTag && !activeClawdSkillTagPromptApplied) + ) && !isClawdSubmitting : isDetailGenerationMode ? detailValidationIssues.length === 0 && !isDetailGenerating : hasInputOrAttachments && @@ -11332,6 +11502,42 @@ export function CanvasChatPanel({ > {displayCanvasName} + {isClawdMode && activeClawdSkillTag ? ( + + {activeClawdSkillTag.iconUrl ? ( + {activeClawdSkillTag.name} { + if (event.currentTarget.src !== activeClawdSkillTag.iconUrl) { + event.currentTarget.src = activeClawdSkillTag.iconUrl || ""; + } + }} + /> + ) : ( + + )} + {activeClawdSkillTag.name} + + {activeClawdSkillTagPromptApplied ? "使用中" : "待带入"} + + + ) : null}
@@ -11625,11 +11831,7 @@ export function CanvasChatPanel({
- )} + ) : null} {!isDetailGenerationMode && hasWorkflowContext && workflowContext && (