{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "workflow-01",
	"type": "registry:block",
	"description": "Build powerful AI agent workflows",
	"dependencies": [
		"@xyflow/react",
		"zustand",
		"zod",
		"ai",
		"@ai-sdk/react",
		"@ai-sdk/openai",
		"nanoid",
		"@marcbachmann/cel-js",
		"@uiw/react-codemirror",
		"@codemirror/language",
		"@lezer/highlight",
		"lucide-react",
		"next-themes"
	],
	"registryDependencies": [
		"button",
		"card",
		"dialog",
		"input",
		"textarea",
		"sonner",
		"sidebar",
		"badge",
		"checkbox",
		"collapsible",
		"dropdown-menu",
		"popover",
		"select",
		"switch",
		"tooltip",
		"separator",
		"@simple-ai/chat-input",
		"@simple-ai/chat-message-area",
		"@simple-ai/chat-message",
		"@simple-ai/tool-invocation",
		"@simple-ai/chat-suggestions",
		"@simple-ai/reasoning",
		"@simple-ai/json-schema-editor"
	],
	"files": [
		{
			"path": "./src/registry/blocks/workflow-01/page.tsx",
			"content": "\"use client\";\n\nimport {\n\tBackground,\n\tControls,\n\ttype EdgeTypes,\n\tMiniMap,\n\ttype NodeTypes,\n\tReactFlow,\n\tReactFlowProvider,\n\tuseOnSelectionChange,\n\tuseReactFlow,\n} from \"@xyflow/react\";\nimport { type DragEvent, useCallback, useEffect, useState } from \"react\";\nimport { shallow } from \"zustand/shallow\";\nimport \"@xyflow/react/dist/style.css\";\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport } from \"ai\";\nimport { Workflow } from \"lucide-react\";\nimport { useTheme } from \"next-themes\";\nimport { SidebarTrigger } from \"@/components/ui/sidebar\";\nimport {\n\tAppHeader,\n\tAppHeaderIcon,\n\tAppHeaderSeparator,\n\tAppHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/app-header\";\nimport {\n\tAppLayout,\n\tAppLayoutInset,\n\tAppLayoutSidebar,\n} from \"@/registry/blocks/workflow-01/components/app-layout\";\nimport { Chat } from \"@/registry/blocks/workflow-01/components/chat\";\nimport { NodeEditorPanel } from \"@/registry/blocks/workflow-01/components/node-editor-panel\";\nimport { NodeSelectorPanel } from \"@/registry/blocks/workflow-01/components/node-selector-panel\";\nimport { TemplateSelector } from \"@/registry/blocks/workflow-01/components/template-selector\";\nimport { ThemeToggle } from \"@/registry/blocks/workflow-01/components/theme-toggle\";\nimport { ValidationStatus } from \"@/registry/blocks/workflow-01/components/validation-status\";\nimport { StatusEdge } from \"@/registry/blocks/workflow-01/components/workflow/status-edge\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport {\n\tDEFAULT_TEMPLATE,\n\tgetTemplateById,\n} from \"@/registry/blocks/workflow-01/lib/templates\";\nimport { getAllNodeDefinitions } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\nimport type { WorkflowUIMessage } from \"@/registry/blocks/workflow-01/types/messages\";\nimport type { FlowNode } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nconst nodeDefinitions = getAllNodeDefinitions();\nconst nodeTypes: NodeTypes = {} as NodeTypes;\nfor (const definition of nodeDefinitions) {\n\t// biome-ignore lint/suspicious/noExplicitAny: ReactFlow nodeTypes accepts any component type\n\tnodeTypes[definition.shared.type] = definition.client.component as any;\n}\n\nconst edgeTypes: EdgeTypes = {\n\tstatus: StatusEdge,\n};\n\nexport function Flow() {\n\tconst { theme } = useTheme();\n\tconst store = useWorkflow(\n\t\t(store) => ({\n\t\t\tnodes: store.nodes,\n\t\t\tedges: store.edges,\n\t\t\tonNodesChange: store.onNodesChange,\n\t\t\tonEdgesChange: store.onEdgesChange,\n\t\t\tonConnect: store.onConnect,\n\t\t\tcreateNode: store.createNode,\n\t\t\tinitializeWorkflow: store.initializeWorkflow,\n\t\t\tupdateNode: store.updateNode,\n\t\t}),\n\t\tshallow,\n\t);\n\n\tconst [selectedNodes, setSelectedNodes] = useState<FlowNode[]>([]);\n\tconst [selectedTemplateId, setSelectedTemplateId] = useState<string>(\n\t\tDEFAULT_TEMPLATE.id,\n\t);\n\n\tconst { messages, sendMessage, status, stop, setMessages } =\n\t\tuseChat<WorkflowUIMessage>({\n\t\t\ttransport: new DefaultChatTransport({\n\t\t\t\tapi: \"/api/workflow\",\n\t\t\t}),\n\t\t\tonData: (dataPart) => {\n\t\t\t\tif (dataPart.type === \"data-node-execution-status\") {\n\t\t\t\t\tstore.updateNode({\n\t\t\t\t\t\tid: dataPart.data.nodeId,\n\t\t\t\t\t\tnodeType: dataPart.data.nodeType,\n\t\t\t\t\t\tdata: { status: dataPart.data.status },\n\t\t\t\t\t});\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tdataPart.data.status === \"error\" &&\n\t\t\t\t\t\tdataPart.data.error\n\t\t\t\t\t) {\n\t\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t\t`Node ${dataPart.data.nodeId} error:`,\n\t\t\t\t\t\t\tdataPart.data.error,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\n\tconst isLoading = status === \"streaming\" || status === \"submitted\";\n\n\tuseOnSelectionChange({\n\t\tonChange: ({ nodes }) => {\n\t\t\tsetSelectedNodes(nodes as FlowNode[]);\n\t\t},\n\t});\n\n\tconst handleTemplateSelect = (templateId: string) => {\n\t\tconst template = getTemplateById(templateId);\n\t\tif (template) {\n\t\t\tsetSelectedTemplateId(templateId);\n\t\t\tstore.initializeWorkflow({\n\t\t\t\tnodes: template.nodes,\n\t\t\t\tedges: template.edges,\n\t\t\t});\n\t\t\tsetMessages([]);\n\t\t}\n\t};\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: We want to initialize the workflow only once\n\tuseEffect(() => {\n\t\tstore.initializeWorkflow({\n\t\t\tnodes: DEFAULT_TEMPLATE.nodes,\n\t\t\tedges: DEFAULT_TEMPLATE.edges,\n\t\t});\n\t}, []);\n\n\tconst { screenToFlowPosition } = useReactFlow();\n\n\tconst onDragOver = useCallback((event: DragEvent) => {\n\t\tevent.preventDefault();\n\t\tevent.dataTransfer.dropEffect = \"move\";\n\t}, []);\n\n\tconst onDrop = useCallback(\n\t\t(event: DragEvent) => {\n\t\t\tevent.preventDefault();\n\n\t\t\tconst type = event.dataTransfer.getData(\n\t\t\t\t\"application/reactflow\",\n\t\t\t) as FlowNode[\"type\"];\n\n\t\t\tif (!type) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst position = screenToFlowPosition({\n\t\t\t\tx: event.clientX,\n\t\t\t\ty: event.clientY,\n\t\t\t});\n\n\t\t\tstore.createNode(type, position);\n\t\t},\n\t\t[screenToFlowPosition, store.createNode],\n\t);\n\n\treturn (\n\t\t<AppLayout>\n\t\t\t<AppLayoutInset>\n\t\t\t\t<AppHeader>\n\t\t\t\t\t<AppHeaderIcon>\n\t\t\t\t\t\t<Workflow />\n\t\t\t\t\t</AppHeaderIcon>\n\t\t\t\t\t<AppHeaderTitle className=\"ml-2\">\n\t\t\t\t\t\tWorkflow Builder\n\t\t\t\t\t</AppHeaderTitle>\n\t\t\t\t\t<AppHeaderSeparator />\n\t\t\t\t\t<TemplateSelector\n\t\t\t\t\t\tselectedTemplateId={selectedTemplateId}\n\t\t\t\t\t\tonTemplateSelect={handleTemplateSelect}\n\t\t\t\t\t\tclassName=\"hidden lg:flex\"\n\t\t\t\t\t/>\n\t\t\t\t\t<AppHeaderSeparator />\n\t\t\t\t\t<ThemeToggle />\n\t\t\t\t\t<ValidationStatus />\n\t\t\t\t\t<SidebarTrigger className=\"ml-auto\" />\n\t\t\t\t</AppHeader>\n\n\t\t\t\t<ReactFlow\n\t\t\t\t\tnodes={store.nodes}\n\t\t\t\t\tedges={store.edges}\n\t\t\t\t\tonNodesChange={store.onNodesChange}\n\t\t\t\t\tonEdgesChange={store.onEdgesChange}\n\t\t\t\t\tonConnect={store.onConnect}\n\t\t\t\t\tnodeTypes={nodeTypes}\n\t\t\t\t\tedgeTypes={edgeTypes}\n\t\t\t\t\tonDragOver={onDragOver}\n\t\t\t\t\tonDrop={onDrop}\n\t\t\t\t\tfitView\n\t\t\t\t\tcolorMode={theme === \"dark\" ? \"dark\" : \"light\"}\n\t\t\t\t\tnodesDraggable={!isLoading}\n\t\t\t\t\tnodesConnectable={!isLoading}\n\t\t\t\t\tnodesFocusable={!isLoading}\n\t\t\t\t\tedgesFocusable={!isLoading}\n\t\t\t\t\telementsSelectable={!isLoading}\n\t\t\t\t>\n\t\t\t\t\t<Background />\n\t\t\t\t\t<Controls />\n\t\t\t\t\t<MiniMap />\n\t\t\t\t\t<NodeSelectorPanel />\n\n\t\t\t\t\t{selectedNodes.length === 1 && (\n\t\t\t\t\t\t<NodeEditorPanel nodeId={selectedNodes[0].id} />\n\t\t\t\t\t)}\n\t\t\t\t</ReactFlow>\n\t\t\t</AppLayoutInset>\n\t\t\t<AppLayoutSidebar>\n\t\t\t\t<Chat\n\t\t\t\t\tmessages={messages}\n\t\t\t\t\tsendMessage={sendMessage}\n\t\t\t\t\tstatus={status}\n\t\t\t\t\tstop={stop}\n\t\t\t\t\tsetMessages={setMessages}\n\t\t\t\t\tselectedTemplateId={selectedTemplateId}\n\t\t\t\t/>\n\t\t\t</AppLayoutSidebar>\n\t\t</AppLayout>\n\t);\n}\n\nexport default function Page() {\n\treturn (\n\t\t<div className=\"w-screen h-screen\">\n\t\t\t<ReactFlowProvider>\n\t\t\t\t<Flow />\n\t\t\t</ReactFlowProvider>\n\t\t</div>\n\t);\n}\n",
			"type": "registry:page",
			"target": "app/workflow/page.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/route.ts",
			"content": "import { createUIMessageStream, createUIMessageStreamResponse } from \"ai\";\nimport type { NextRequest } from \"next/server\";\nimport { executeWorkflow } from \"@/registry/blocks/workflow-01/lib/workflow/executor\";\nimport type { WorkflowUIMessage } from \"@/registry/blocks/workflow-01/types/messages\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const maxDuration = 60;\n\nexport async function POST(req: NextRequest) {\n\tconst {\n\t\tmessages,\n\t\tnodes,\n\t\tedges,\n\t}: { messages: WorkflowUIMessage[]; nodes: FlowNode[]; edges: FlowEdge[] } =\n\t\tawait req.json();\n\n\tconst stream = createUIMessageStream<WorkflowUIMessage>({\n\t\texecute: ({ writer }) =>\n\t\t\texecuteWorkflow({ nodes, edges, messages, writer }),\n\t});\n\n\treturn createUIMessageStreamResponse({ stream });\n}\n",
			"type": "registry:page",
			"target": "app/api/workflow/route.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/app-header.tsx",
			"content": "import { Separator } from \"@/components/ui/separator\";\nimport { cn } from \"@/lib/utils\";\n\nexport function AppHeader({ children }: React.ComponentProps<\"div\">) {\n\treturn (\n\t\t<header className=\"group-has-data-[collapsible=icon]/sidebar-wrapper:h-12 flex h-12 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear\">\n\t\t\t<div className=\"flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6\">\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</header>\n\t);\n}\n\nexport function AppHeaderIcon({\n\tchildren,\n\tclassName,\n}: React.ComponentProps<\"span\">) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"flex justify-center items-center [&_svg]:size-5\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</span>\n\t);\n}\n\nexport function AppHeaderTitle({\n\tchildren,\n\tclassName,\n}: React.ComponentProps<\"span\">) {\n\treturn (\n\t\t<span className={cn(\"text-base font-medium\", className)}>\n\t\t\t{children}\n\t\t</span>\n\t);\n}\n\nexport function AppHeaderSeparator({ className }: React.ComponentProps<\"div\">) {\n\treturn (\n\t\t<Separator\n\t\t\torientation=\"vertical\"\n\t\t\tclassName={cn(\"mx-2 data-[orientation=vertical]:h-4\", className)}\n\t\t/>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/app-header.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/app-layout.tsx",
			"content": "import type { ComponentProps } from \"react\";\nimport {\n\tSidebar,\n\tSidebarInset,\n\tSidebarProvider,\n} from \"@/components/ui/sidebar\";\nimport { cn } from \"@/lib/utils\";\n\nexport function AppLayout(props: ComponentProps<typeof SidebarProvider>) {\n\treturn (\n\t\t<SidebarProvider\n\t\t\tdefaultOpen={true}\n\t\t\tstyle={{\n\t\t\t\t// @ts-expect-error CSS custom properties\n\t\t\t\t\"--sidebar-width\": \"28rem\",\n\t\t\t\t\"--sidebar-width-mobile\": \"30rem\",\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport function AppLayoutInset({\n\tclassName,\n\t...props\n}: ComponentProps<typeof SidebarInset>) {\n\treturn <SidebarInset className={className} {...props} />;\n}\n\nexport function AppLayoutSidebar({\n\tclassName,\n\tside = \"right\",\n\t...props\n}: ComponentProps<typeof Sidebar>) {\n\treturn (\n\t\t<Sidebar\n\t\t\tclassName={cn(\"bg-background\", className)}\n\t\t\tside={side}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/app-layout.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/chat.tsx",
			"content": "\"use client\";\n\nimport type { useChat } from \"@ai-sdk/react\";\nimport { Copy, MessagesSquare, RotateCcw, ThumbsUp } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n\tAppHeader,\n\tAppHeaderIcon,\n\tAppHeaderSeparator,\n\tAppHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/app-header\";\nimport {\n\tNodeExecutionStatus,\n\tNodeExecutionStatusBadge,\n\tNodeExecutionStatusContent,\n\tNodeExecutionStatusError,\n\tNodeExecutionStatusHeader,\n\tNodeExecutionStatusIcon,\n\tNodeExecutionStatusType,\n} from \"@/registry/blocks/workflow-01/components/node-execution\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport { getTemplateById } from \"@/registry/blocks/workflow-01/lib/templates\";\nimport type { WorkflowUIMessage } from \"@/registry/blocks/workflow-01/types/messages\";\nimport {\n\tChatInput,\n\tChatInputEditor,\n\tChatInputGroupAddon,\n\tChatInputSubmitButton,\n\tuseChatInput,\n} from \"@/registry/ui/chat-input\";\nimport {\n\tChatMessage,\n\tChatMessageAction,\n\tChatMessageActions,\n\tChatMessageAuthor,\n\tChatMessageAvatar,\n\tChatMessageAvatarAssistantIcon,\n\tChatMessageAvatarUserIcon,\n\tChatMessageContainer,\n\tChatMessageContent,\n\tChatMessageHeader,\n\tChatMessageMarkdown,\n\tChatMessageTimestamp,\n} from \"@/registry/ui/chat-message\";\nimport {\n\tChatMessageArea,\n\tChatMessageAreaContent,\n\tChatMessageAreaScrollButton,\n} from \"@/registry/ui/chat-message-area\";\nimport {\n\tChatSuggestion,\n\tChatSuggestions,\n\tChatSuggestionsContent,\n\tChatSuggestionsHeader,\n\tChatSuggestionsTitle,\n} from \"@/registry/ui/chat-suggestions\";\nimport { Reasoning } from \"@/registry/ui/reasoning\";\nimport {\n\tToolInvocation,\n\tToolInvocationContentCollapsible,\n\tToolInvocationHeader,\n\tToolInvocationName,\n\tToolInvocationRawData,\n} from \"@/registry/ui/tool-invocation\";\n\ninterface ChatHeaderProps {\n\tonReset?: () => void;\n}\n\nfunction ChatHeader({ onReset }: ChatHeaderProps) {\n\treturn (\n\t\t<AppHeader>\n\t\t\t<AppHeaderIcon className=\"hidden md:flex\">\n\t\t\t\t<MessagesSquare />\n\t\t\t</AppHeaderIcon>\n\t\t\t<AppHeaderSeparator className=\"hidden md:block\" />\n\t\t\t<AppHeaderTitle>Chat</AppHeaderTitle>\n\t\t\t{onReset && (\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\tonClick={onReset}\n\t\t\t\t\tclassName=\"ml-auto\"\n\t\t\t\t\ttitle=\"Reset chat messages\"\n\t\t\t\t>\n\t\t\t\t\t<RotateCcw />\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t</AppHeader>\n\t);\n}\n\ntype ReturnOfUseChat = ReturnType<typeof useChat<WorkflowUIMessage>>;\n\ninterface ChatProps extends ComponentPropsWithoutRef<\"div\"> {\n\tmessages: WorkflowUIMessage[];\n\tsendMessage: ReturnOfUseChat[\"sendMessage\"];\n\tstatus: ReturnOfUseChat[\"status\"];\n\tstop: ReturnOfUseChat[\"stop\"];\n\tsetMessages: ReturnOfUseChat[\"setMessages\"];\n\tselectedTemplateId?: string;\n}\n\nexport function Chat({\n\tclassName,\n\tmessages,\n\tsendMessage,\n\tstatus,\n\tstop,\n\tsetMessages,\n\tselectedTemplateId,\n\t...props\n}: ChatProps) {\n\tconst getWorkflowData = useWorkflow((store) => store.getWorkflowData);\n\tconst resetNodeStatuses = useWorkflow((store) => store.resetNodeStatuses);\n\tconst validationState = useWorkflow((store) => store.validationState);\n\n\tconst isLoading = status === \"streaming\" || status === \"submitted\";\n\tconst hasValidationErrors = !validationState.valid;\n\tconst isDisabled = hasValidationErrors;\n\n\tconst currentTemplate = selectedTemplateId\n\t\t? getTemplateById(selectedTemplateId)\n\t\t: undefined;\n\n\tconst { value, onChange, handleSubmit } = useChatInput({\n\t\tonSubmit: (parsedValue) => {\n\t\t\tresetNodeStatuses();\n\n\t\t\tconst workflowData = getWorkflowData();\n\n\t\t\tsendMessage(\n\t\t\t\t{\n\t\t\t\t\trole: \"user\",\n\t\t\t\t\tparts: [{ type: \"text\", text: parsedValue.content }],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tnodes: workflowData.nodes,\n\t\t\t\t\t\tedges: workflowData.edges,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t});\n\n\tconst handleSuggestionClick = (suggestion: string) => {\n\t\tresetNodeStatuses();\n\n\t\tconst workflowData = getWorkflowData();\n\n\t\tsendMessage(\n\t\t\t{\n\t\t\t\trole: \"user\",\n\t\t\t\tparts: [{ type: \"text\", text: suggestion }],\n\t\t\t},\n\t\t\t{\n\t\t\t\tbody: {\n\t\t\t\t\tnodes: workflowData.nodes,\n\t\t\t\t\tedges: workflowData.edges,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t};\n\n\tconst resetMessages = () => {\n\t\tstop();\n\t\tsetMessages([]);\n\t\tresetNodeStatuses();\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"flex-1 flex flex-col overflow-y-auto bg-background\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<ChatHeader onReset={resetMessages} />\n\t\t\t<ChatMessageArea className=\"px-2\">\n\t\t\t\t<ChatMessageAreaContent className=\"pt-4\">\n\t\t\t\t\t{messages.length === 0 ? (\n\t\t\t\t\t\t<NoChatMessages\n\t\t\t\t\t\t\ttemplate={currentTemplate}\n\t\t\t\t\t\t\tonSuggestionClick={handleSuggestionClick}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\tmessages.map((message) => {\n\t\t\t\t\t\t\tconst userName =\n\t\t\t\t\t\t\t\tmessage.role === \"user\" ? \"You\" : \"Assistant\";\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<ChatMessage key={message.id}>\n\t\t\t\t\t\t\t\t\t<ChatMessageActions>\n\t\t\t\t\t\t\t\t\t\t<ChatMessageAction label=\"Copy\">\n\t\t\t\t\t\t\t\t\t\t\t<Copy className=\"size-4\" />\n\t\t\t\t\t\t\t\t\t\t</ChatMessageAction>\n\t\t\t\t\t\t\t\t\t\t<ChatMessageAction label=\"Like\">\n\t\t\t\t\t\t\t\t\t\t\t<ThumbsUp className=\"size-4\" />\n\t\t\t\t\t\t\t\t\t\t</ChatMessageAction>\n\t\t\t\t\t\t\t\t\t</ChatMessageActions>\n\t\t\t\t\t\t\t\t\t<ChatMessageAvatar>\n\t\t\t\t\t\t\t\t\t\t{message.role === \"user\" ? (\n\t\t\t\t\t\t\t\t\t\t\t<ChatMessageAvatarUserIcon />\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<ChatMessageAvatarAssistantIcon />\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</ChatMessageAvatar>\n\n\t\t\t\t\t\t\t\t\t<ChatMessageContainer>\n\t\t\t\t\t\t\t\t\t\t<ChatMessageHeader>\n\t\t\t\t\t\t\t\t\t\t\t<ChatMessageAuthor>\n\t\t\t\t\t\t\t\t\t\t\t\t{userName}\n\t\t\t\t\t\t\t\t\t\t\t</ChatMessageAuthor>\n\t\t\t\t\t\t\t\t\t\t\t<ChatMessageTimestamp\n\t\t\t\t\t\t\t\t\t\t\t\tcreatedAt={new Date()}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t</ChatMessageHeader>\n\n\t\t\t\t\t\t\t\t\t\t<ChatMessageContent className=\"gap-3\">\n\t\t\t\t\t\t\t\t\t\t\t{message.parts.map(\n\t\t\t\t\t\t\t\t\t\t\t\t(part, index) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tswitch (part.type) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcase \"text\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ChatMessageMarkdown\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={`text-${message.id}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcontent={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.text\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcase \"reasoning\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Reasoning\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={`reasoning-${message.id}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcontent={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.text\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisLastPart={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tindex ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tmessage\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.parts\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.length -\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcase \"data-node-execution-status\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatus\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={`status-${message.id}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatusHeader>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatusIcon\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstatus={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.data\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.status\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatusContent>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatusType\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnodeType={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.data\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.nodeType\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatusBadge\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstatus={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.data\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.status\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NodeExecutionStatusContent>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NodeExecutionStatusHeader>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{part.data\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.error && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NodeExecutionStatusError>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.data\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.error\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NodeExecutionStatusError>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NodeExecutionStatus>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(part.type.startsWith(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"tool-\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t) ||\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.type ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"dynamic-tool\") &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"toolCallId\" in part\n\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlet input:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| unknown\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlet output:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| unknown\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlet error:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t| undefined;\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.state ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"output-error\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\terror =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.errorText;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toutput =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.output;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.state ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"input-streaming\" ||\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.state ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"output-error\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"rawInput\" in\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.rawInput !=\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.rawInput;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"input\" in\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart &&\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.input !=\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.input;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.state ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"input-available\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput = part.input;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.state ===\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"output-available\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput = part.input;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toutput =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.output;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst toolName =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"toolName\" in part\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? part.toolName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: part.type.slice(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t5,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ToolInvocation\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.toolCallId\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"w-full\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ToolInvocationHeader>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ToolInvocationName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname={`Used ${toolName}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpart.state\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisError={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!!error\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</ToolInvocationHeader>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{(input !==\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tundefined ||\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toutput !==\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tundefined) && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ToolInvocationContentCollapsible>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{input !==\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tundefined && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ToolInvocationRawData\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Arguments\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{output !==\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tundefined && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ToolInvocationRawData\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdata={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toutput\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle=\"Result\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</ToolInvocationContentCollapsible>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</ToolInvocation>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ChatMessageContent>\n\t\t\t\t\t\t\t\t\t</ChatMessageContainer>\n\t\t\t\t\t\t\t\t</ChatMessage>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})\n\t\t\t\t\t)}\n\t\t\t\t</ChatMessageAreaContent>\n\t\t\t\t<ChatMessageAreaScrollButton alignment=\"center\" />\n\t\t\t</ChatMessageArea>\n\t\t\t<div className=\"px-4 py-4 max-w-2xl mx-auto w-full\">\n\t\t\t\t{hasValidationErrors && (\n\t\t\t\t\t<div className=\"mb-2 p-2 bg-red-50 border border-destructive rounded text-xs text-destructive\">\n\t\t\t\t\t\tFix validation errors before running the workflow\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t<ChatInput\n\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\tisStreaming={isLoading}\n\t\t\t\t\tonStop={stop}\n\t\t\t\t\tdisabled={isDisabled}\n\t\t\t\t>\n\t\t\t\t\t<ChatInputEditor\n\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\tonChange={onChange}\n\t\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t\thasValidationErrors\n\t\t\t\t\t\t\t\t? \"Fix validation errors first...\"\n\t\t\t\t\t\t\t\t: \"Type a message...\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdisabled={isDisabled}\n\t\t\t\t\t/>\n\t\t\t\t\t<ChatInputGroupAddon align=\"block-end\">\n\t\t\t\t\t\t<ChatInputSubmitButton\n\t\t\t\t\t\t\tclassName=\"ml-auto\"\n\t\t\t\t\t\t\tdisabled={isDisabled}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</ChatInputGroupAddon>\n\t\t\t\t</ChatInput>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction NoChatMessages({\n\ttemplate,\n\tonSuggestionClick,\n}: {\n\ttemplate?: ReturnType<typeof getTemplateById>;\n\tonSuggestionClick: (suggestion: string) => void;\n}) {\n\tif (!template || template.suggestions.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col gap-2 p-2 items-center justify-center h-full\">\n\t\t\t\t<p className=\"text-muted-foreground text-lg\">\n\t\t\t\t\tNo chat messages\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t);\n\t}\n\treturn (\n\t\t<div className=\"flex flex-col gap-2 p-2 justify-end items-center h-full\">\n\t\t\t<ChatSuggestions>\n\t\t\t\t<ChatSuggestionsHeader>\n\t\t\t\t\t<ChatSuggestionsTitle>\n\t\t\t\t\t\tTry these prompts:\n\t\t\t\t\t</ChatSuggestionsTitle>\n\t\t\t\t</ChatSuggestionsHeader>\n\t\t\t\t<ChatSuggestionsContent>\n\t\t\t\t\t{template.suggestions.map((suggestion) => (\n\t\t\t\t\t\t<ChatSuggestion\n\t\t\t\t\t\t\tkey={suggestion}\n\t\t\t\t\t\t\tonClick={() => onSuggestionClick(suggestion)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{suggestion}\n\t\t\t\t\t\t</ChatSuggestion>\n\t\t\t\t\t))}\n\t\t\t\t</ChatSuggestionsContent>\n\t\t\t</ChatSuggestions>\n\t\t</div>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/chat.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/editor/condition-editor.tsx",
			"content": "import { HighlightStyle, syntaxHighlighting } from \"@codemirror/language\";\nimport \"./condition-editor.css\";\nimport type { Extension } from \"@codemirror/state\";\nimport {\n\tDecoration,\n\ttype DecorationSet,\n\ttype EditorView,\n\tViewPlugin,\n\ttype ViewUpdate,\n} from \"@codemirror/view\";\nimport { tags } from \"@lezer/highlight\";\nimport CodeMirror, { type ReactCodeMirrorRef } from \"@uiw/react-codemirror\";\nimport { Code, GitBranch, Variable } from \"lucide-react\";\nimport { useTheme } from \"next-themes\";\nimport React from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n\tPopover,\n\tPopoverContent,\n\tPopoverTrigger,\n} from \"@/components/ui/popover\";\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\nimport type {\n\tTaggedVariableInfo,\n\tVariableInfo,\n} from \"@/registry/blocks/workflow-01/lib/workflow/context/variable-resolver\";\nimport { buildVariablePathSet } from \"@/registry/blocks/workflow-01/lib/workflow/context/variable-resolver\";\n\ntype ConditionEditorProps = {\n\tvalue: string;\n\tonChange: (value: string) => void;\n\tavailableVariables: VariableInfo[] | TaggedVariableInfo[];\n\tvalidationError?: string;\n\tplaceholder?: string;\n};\n\nconst OPERATORS = [\n\t{ label: \"==\", description: \"Equal to\" },\n\t{ label: \"!=\", description: \"Not equal to\" },\n\t{ label: \">\", description: \"Greater than\" },\n\t{ label: \"<\", description: \"Less than\" },\n\t{ label: \">=\", description: \"Greater than or equal\" },\n\t{ label: \"<=\", description: \"Less than or equal\" },\n\t{ label: \"&&\", description: \"And\" },\n\t{ label: \"||\", description: \"Or\" },\n\t{ label: \"!\", description: \"Not\" },\n\t{ label: \"+\", description: \"Addition\" },\n\t{ label: \"-\", description: \"Subtraction\" },\n\t{ label: \"*\", description: \"Multiplication\" },\n\t{ label: \"/\", description: \"Division\" },\n\t{ label: \"%\", description: \"Modulo\" },\n\t{ label: \"in\", description: \"In array\" },\n\t{ label: \"matches\", description: \"Regex match\" },\n\t{ label: \"has\", description: \"Check if field exists\" },\n\t{ label: \"size\", description: \"Get size/length\" },\n\t{ label: \"?\", description: \"Ternary operator\" },\n\t{ label: \":\", description: \"Ternary separator\" },\n];\n\nconst celHighlightStyle = HighlightStyle.define([\n\t{ tag: tags.keyword, color: \"#0550ae\" },\n\t{ tag: tags.operator, color: \"#953800\" },\n\t{ tag: tags.number, color: \"#0550ae\" },\n\t{ tag: tags.string, color: \"#0a3069\" },\n]);\n\nfunction createCelDecorations(\n\tview: EditorView,\n\tavailableVariables: VariableInfo[],\n): DecorationSet {\n\tconst decorations: Array<{\n\t\tfrom: number;\n\t\tto: number;\n\t\tdecoration: Decoration;\n\t}> = [];\n\tconst text = view.state.doc.toString();\n\n\t// CEL operators: ==, !=, >=, <=, &&, ||, !, +, -, *, /, %, <, >, ?, :\n\tconst operatorRegex = /(==|!=|>=|<=|&&|\\|\\||[+\\-*/%><!?:])/g;\n\tlet match: RegExpExecArray | null = operatorRegex.exec(text);\n\twhile (match !== null) {\n\t\tdecorations.push({\n\t\t\tfrom: match.index,\n\t\t\tto: match.index + match[0].length,\n\t\t\tdecoration: Decoration.mark({ class: \"cm-cel-operator\" }),\n\t\t});\n\t\tmatch = operatorRegex.exec(text);\n\t}\n\n\t// CEL keywords: true, false, null, in, matches, has, size\n\tconst keywordRegex = /\\b(true|false|null|in|matches|has|size)\\b/g;\n\tmatch = keywordRegex.exec(text);\n\twhile (match !== null) {\n\t\tdecorations.push({\n\t\t\tfrom: match.index,\n\t\t\tto: match.index + match[0].length,\n\t\t\tdecoration: Decoration.mark({ class: \"cm-cel-keyword\" }),\n\t\t});\n\t\tmatch = keywordRegex.exec(text);\n\t}\n\n\tconst numberRegex = /\\b\\d+(\\.\\d+)?\\b/g;\n\tmatch = numberRegex.exec(text);\n\twhile (match !== null) {\n\t\tdecorations.push({\n\t\t\tfrom: match.index,\n\t\t\tto: match.index + match[0].length,\n\t\t\tdecoration: Decoration.mark({ class: \"cm-cel-number\" }),\n\t\t});\n\t\tmatch = numberRegex.exec(text);\n\t}\n\n\tconst stringRegex = /(['\"])((?:\\\\.|(?!\\1).)*?)\\1/g;\n\tmatch = stringRegex.exec(text);\n\twhile (match !== null) {\n\t\tdecorations.push({\n\t\t\tfrom: match.index,\n\t\t\tto: match.index + match[0].length,\n\t\t\tdecoration: Decoration.mark({ class: \"cm-cel-string\" }),\n\t\t});\n\t\tmatch = stringRegex.exec(text);\n\t}\n\n\tconst validPaths = buildVariablePathSet(availableVariables);\n\n\tconst variablePathRegex =\n\t\t/\\b[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*/g;\n\tmatch = variablePathRegex.exec(text);\n\twhile (match !== null) {\n\t\tconst matchedPath = match[0];\n\t\tif (validPaths.has(matchedPath)) {\n\t\t\tdecorations.push({\n\t\t\t\tfrom: match.index,\n\t\t\t\tto: match.index + match[0].length,\n\t\t\t\tdecoration: Decoration.mark({ class: \"cm-cel-variable\" }),\n\t\t\t});\n\t\t}\n\t\tmatch = variablePathRegex.exec(text);\n\t}\n\n\tdecorations.sort((a, b) => a.from - b.from);\n\treturn Decoration.set(\n\t\tdecorations.map((d) => d.decoration.range(d.from, d.to)),\n\t);\n}\n\nfunction createCelHighlightPlugin(\n\tavailableVariables: VariableInfo[],\n): Extension {\n\treturn ViewPlugin.fromClass(\n\t\tclass {\n\t\t\tdecorations: DecorationSet;\n\n\t\t\tconstructor(view: EditorView) {\n\t\t\t\tthis.decorations = createCelDecorations(\n\t\t\t\t\tview,\n\t\t\t\t\tavailableVariables,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tupdate(update: ViewUpdate) {\n\t\t\t\tif (update.docChanged || update.viewportChanged) {\n\t\t\t\t\tthis.decorations = createCelDecorations(\n\t\t\t\t\t\tupdate.view,\n\t\t\t\t\t\tavailableVariables,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tdecorations: (v) => v.decorations,\n\t\t},\n\t);\n}\n\nexport function ConditionEditor({\n\tvalue,\n\tonChange,\n\tavailableVariables,\n\tvalidationError,\n\tplaceholder = \"Enter condition expression\",\n}: ConditionEditorProps) {\n\tconst { theme } = useTheme();\n\tconst editorRef = React.useRef<ReactCodeMirrorRef>(null);\n\n\t// Convert to VariableInfo[] for highlighting (TaggedVariableInfo extends VariableInfo)\n\tconst variablesForHighlighting: VariableInfo[] = availableVariables.map(\n\t\t(v) => ({\n\t\t\tpath: v.path,\n\t\t\ttype: v.type,\n\t\t\tdescription: v.description,\n\t\t\tchildren: v.children,\n\t\t}),\n\t);\n\n\tconst extensions = React.useMemo(() => {\n\t\treturn [\n\t\t\tcreateCelHighlightPlugin(variablesForHighlighting),\n\t\t\tsyntaxHighlighting(celHighlightStyle),\n\t\t];\n\t}, [variablesForHighlighting]);\n\n\tconst insertAtCursor = React.useCallback((text: string) => {\n\t\tif (editorRef.current?.view) {\n\t\t\tconst view = editorRef.current.view;\n\t\t\tconst { from, to } = view.state.selection.main;\n\t\t\tview.dispatch({\n\t\t\t\tchanges: { from, to, insert: text },\n\t\t\t\tselection: { anchor: from + text.length },\n\t\t\t});\n\t\t\tview.focus();\n\t\t}\n\t}, []);\n\n\tconst handleVariableClick = (variable: VariableInfo) => {\n\t\tinsertAtCursor(variable.path);\n\t};\n\n\tconst handleOperatorClick = (operator: string) => {\n\t\tinsertAtCursor(` ${operator} `);\n\t};\n\n\treturn (\n\t\t<div className=\"space-y-2\">\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<Popover>\n\t\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\tclassName=\"gap-2\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Variable className=\"w-3 h-3\" />\n\t\t\t\t\t\t\tVariables\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</PopoverTrigger>\n\t\t\t\t\t<PopoverContent className=\"w-80 p-0\" align=\"start\">\n\t\t\t\t\t\t<div className=\"max-h-[300px] overflow-y-auto\">\n\t\t\t\t\t\t\t<div className=\"p-2 border-b bg-muted/50\">\n\t\t\t\t\t\t\t\t<h4 className=\"text-xs font-semibold\">\n\t\t\t\t\t\t\t\t\tAvailable Variables\n\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{availableVariables.length === 0 ? (\n\t\t\t\t\t\t\t\t<div className=\"p-4 text-xs text-muted-foreground text-center\">\n\t\t\t\t\t\t\t\t\tNo variables available. Connect an input\n\t\t\t\t\t\t\t\t\tnode first.\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<VariableList\n\t\t\t\t\t\t\t\t\tvariables={availableVariables}\n\t\t\t\t\t\t\t\t\tonSelect={handleVariableClick}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</PopoverContent>\n\t\t\t\t</Popover>\n\n\t\t\t\t<Popover>\n\t\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\tclassName=\"gap-2\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Code className=\"w-3 h-3\" />\n\t\t\t\t\t\t\tOperators\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</PopoverTrigger>\n\t\t\t\t\t<PopoverContent className=\"w-64 p-0\" align=\"start\">\n\t\t\t\t\t\t<div className=\"max-h-[300px] overflow-y-auto\">\n\t\t\t\t\t\t\t<div className=\"p-2 border-b bg-muted/50\">\n\t\t\t\t\t\t\t\t<h4 className=\"text-xs font-semibold\">\n\t\t\t\t\t\t\t\t\tCommon Operators\n\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"p-1\">\n\t\t\t\t\t\t\t\t{OPERATORS.map((op) => (\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tkey={op.label}\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\t\t\t\thandleOperatorClick(op.label)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tclassName=\"w-full flex items-center justify-between px-3 py-2 text-xs hover:bg-accent rounded-sm transition-colors\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<code className=\"font-mono font-semibold\">\n\t\t\t\t\t\t\t\t\t\t\t{op.label}\n\t\t\t\t\t\t\t\t\t\t</code>\n\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t{op.description}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</PopoverContent>\n\t\t\t\t</Popover>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"border rounded-md overflow-hidden cel-editor\",\n\t\t\t\t\tvalidationError ? \"border-red-500\" : \"\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<CodeMirror\n\t\t\t\t\tvalue={value}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\textensions={extensions}\n\t\t\t\t\tbasicSetup={{\n\t\t\t\t\t\tlineNumbers: false,\n\t\t\t\t\t\tfoldGutter: false,\n\t\t\t\t\t\thighlightActiveLine: false,\n\t\t\t\t\t\thighlightActiveLineGutter: false,\n\t\t\t\t\t}}\n\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\tclassName=\"text-sm nodrag\"\n\t\t\t\t\theight=\"60px\"\n\t\t\t\t\tref={editorRef}\n\t\t\t\t\ttheme={theme === \"dark\" ? \"dark\" : \"light\"}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t{validationError && (\n\t\t\t\t<div className=\"text-xs text-red-600 dark:text-red-400 px-1\">\n\t\t\t\t\t{validationError}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction VariableList({\n\tvariables,\n\tonSelect,\n\tlevel = 0,\n}: {\n\tvariables: VariableInfo[] | TaggedVariableInfo[];\n\tonSelect: (variable: VariableInfo) => void;\n\tlevel?: number;\n}) {\n\t// Separate common and path-specific variables\n\tconst commonVars: TaggedVariableInfo[] = [];\n\tconst pathSpecificVars: TaggedVariableInfo[] = [];\n\n\tfor (const variable of variables) {\n\t\tif (\"tag\" in variable && variable.tag === \"path-specific\") {\n\t\t\tpathSpecificVars.push(variable);\n\t\t} else {\n\t\t\tcommonVars.push(variable as TaggedVariableInfo);\n\t\t}\n\t}\n\n\treturn (\n\t\t<div className=\"p-1\">\n\t\t\t{commonVars.length > 0 && (\n\t\t\t\t<>\n\t\t\t\t\t{level === 0 && (\n\t\t\t\t\t\t<div className=\"px-2 py-1.5 text-[10px] font-semibold text-muted-foreground uppercase\">\n\t\t\t\t\t\t\tCommon Variables\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{commonVars.map((variable) => (\n\t\t\t\t\t\t<VariableItem\n\t\t\t\t\t\t\tkey={variable.path}\n\t\t\t\t\t\t\tvariable={variable}\n\t\t\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\t\t\tlevel={level}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</>\n\t\t\t)}\n\t\t\t{pathSpecificVars.length > 0 && (\n\t\t\t\t<>\n\t\t\t\t\t{level === 0 && commonVars.length > 0 && (\n\t\t\t\t\t\t<div className=\"h-px bg-border my-1 mx-2\" />\n\t\t\t\t\t)}\n\t\t\t\t\t{level === 0 && (\n\t\t\t\t\t\t<div className=\"px-2 py-1.5 text-[10px] font-semibold text-muted-foreground uppercase\">\n\t\t\t\t\t\t\tPath-Specific Variables\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t{pathSpecificVars.map((variable) => (\n\t\t\t\t\t\t<VariableItem\n\t\t\t\t\t\t\tkey={variable.path}\n\t\t\t\t\t\t\tvariable={variable}\n\t\t\t\t\t\t\tonSelect={onSelect}\n\t\t\t\t\t\t\tlevel={level}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction VariableItem({\n\tvariable,\n\tonSelect,\n\tlevel,\n}: {\n\tvariable: TaggedVariableInfo | VariableInfo;\n\tonSelect: (variable: VariableInfo) => void;\n\tlevel: number;\n}) {\n\tconst isPathSpecific =\n\t\t\"tag\" in variable && variable.tag === \"path-specific\";\n\tconst sourceNodeIds =\n\t\t\"sourceNodeIds\" in variable ? variable.sourceNodeIds : [];\n\n\tconst content = (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tonClick={() => onSelect(variable)}\n\t\t\tclassName={cn(\n\t\t\t\t\"w-full flex items-start gap-2 px-3 py-2 text-xs hover:bg-accent rounded-sm transition-colors\",\n\t\t\t\tisPathSpecific && \"opacity-70\",\n\t\t\t)}\n\t\t\tstyle={{ paddingLeft: `${8 + level * 16}px` }}\n\t\t>\n\t\t\t<div className=\"flex-1 text-left\">\n\t\t\t\t<div className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<div className=\"font-mono font-semibold\">\n\t\t\t\t\t\t{variable.path}\n\t\t\t\t\t</div>\n\t\t\t\t\t{isPathSpecific && (\n\t\t\t\t\t\t<GitBranch className=\"w-3 h-3 text-muted-foreground shrink-0\" />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{variable.description && (\n\t\t\t\t\t<div className=\"text-muted-foreground mt-0.5\">\n\t\t\t\t\t\t{variable.description}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t{isPathSpecific && sourceNodeIds.length > 0 && (\n\t\t\t\t\t<div className=\"text-[10px] text-muted-foreground mt-0.5\">\n\t\t\t\t\t\tFrom: {sourceNodeIds.length} source\n\t\t\t\t\t\t{sourceNodeIds.length > 1 ? \"s\" : \"\"}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<span\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"px-1.5 py-0.5 rounded text-[10px] font-medium shrink-0\",\n\t\t\t\t\t\"bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{variable.type}\n\t\t\t</span>\n\t\t</button>\n\t);\n\n\tif (isPathSpecific && sourceNodeIds.length > 0) {\n\t\treturn (\n\t\t\t<TooltipProvider>\n\t\t\t\t<Tooltip>\n\t\t\t\t\t<TooltipTrigger asChild>{content}</TooltipTrigger>\n\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t<p className=\"text-xs\">\n\t\t\t\t\t\t\tOnly available when input is from:{\" \"}\n\t\t\t\t\t\t\t{sourceNodeIds.join(\", \")}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</TooltipContent>\n\t\t\t\t</Tooltip>\n\t\t\t</TooltipProvider>\n\t\t);\n\t}\n\n\treturn <div key={variable.path}>{content}</div>;\n}\n",
			"type": "registry:component",
			"target": "components/editor/condition-editor.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/editor/condition-editor.css",
			"content": "/* CEL Syntax Highlighting */\n.cel-editor .cm-cel-variable {\n\tcolor: #8250df;\n\tfont-weight: 600;\n}\n\n.cel-editor .cm-cel-operator {\n\tcolor: #cf222e;\n\tfont-weight: 600;\n}\n\n.cel-editor .cm-cel-keyword {\n\tcolor: #0550ae;\n\tfont-weight: 600;\n}\n\n.cel-editor .cm-cel-number {\n\tcolor: #0550ae;\n}\n\n.cel-editor .cm-cel-string {\n\tcolor: #0a3069;\n}\n\n/* Dark mode CEL highlighting */\n.dark .cel-editor .cm-cel-variable {\n\tcolor: #d2a8ff;\n}\n\n.dark .cel-editor .cm-cel-operator {\n\tcolor: #ff7b72;\n}\n\n.dark .cel-editor .cm-cel-keyword {\n\tcolor: #79c0ff;\n}\n\n.dark .cel-editor .cm-cel-number {\n\tcolor: #79c0ff;\n}\n\n.dark .cel-editor .cm-cel-string {\n\tcolor: #a5d6ff;\n}\n",
			"type": "registry:style",
			"target": "components/editor/condition-editor.css"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/node-editor-panel.tsx",
			"content": "import { Panel } from \"@xyflow/react\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport { getNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\nimport type { FlowNode } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport function NodeEditorPanel({ nodeId }: { nodeId: FlowNode[\"id\"] }) {\n\tconst node = useWorkflow((state) => state.getNodeById(nodeId));\n\tif (!node) {\n\t\treturn <NodeEditorPanelNotFound />;\n\t}\n\n\tif (node.type === \"note\") {\n\t\treturn null;\n\t}\n\n\tconst definition = getNodeDefinition(node.type);\n\tif (!definition) {\n\t\treturn <NodeEditorPanelNotFound />;\n\t}\n\n\tconst PanelComponent = definition.client.panelComponent;\n\n\treturn (\n\t\t<Panel\n\t\t\tposition=\"top-right\"\n\t\t\tclassName=\"bg-card p-4 rounded-lg shadow-md border w-96 max-h-[calc(100vh-5rem)] overflow-y-auto\"\n\t\t>\n\t\t\t<h3 className=\"font-semibold text-sm mb-3 capitalize\">\n\t\t\t\t{node.type} Node\n\t\t\t</h3>\n\t\t\t<PanelComponent node={node} />\n\t\t</Panel>\n\t);\n}\n\nfunction NodeEditorPanelNotFound() {\n\treturn (\n\t\t<Panel\n\t\t\tposition=\"top-right\"\n\t\t\tclassName=\"bg-card p-4 rounded-lg shadow-md border w-96 max-h-[calc(100vh-4rem)] overflow-y-auto\"\n\t\t>\n\t\t\t<div>Node not found</div>\n\t\t</Panel>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/node-editor-panel.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/node-execution.tsx",
			"content": "import type { VariantProps } from \"class-variance-authority\";\nimport { AlertCircle, CheckCircleIcon, CircleDashed, Play } from \"lucide-react\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Badge, type badgeVariants } from \"@/components/ui/badge\";\nimport { cn } from \"@/lib/utils\";\nimport { idToReadableText } from \"@/registry/lib/id-to-readable-text\";\n\nexport function NodeExecutionStatus({\n\tclassName,\n\t...props\n}: ComponentProps<\"div\">) {\n\treturn <div className={cn(\"max-w-full\", className)} {...props} />;\n}\n\nexport function NodeExecutionStatusHeader({\n\tclassName,\n\t...props\n}: ComponentProps<\"div\">) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"px-2 py-1.5 flex items-center gap-2 rounded-md bg-muted/40\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport function NodeExecutionStatusIcon({\n\tstatus,\n\tclassName,\n\t...props\n}: ComponentProps<\"svg\"> & {\n\tstatus: \"idle\" | \"running\" | \"processing\" | \"success\" | \"error\";\n}) {\n\tswitch (status) {\n\t\tcase \"idle\":\n\t\t\treturn (\n\t\t\t\t<CircleDashed\n\t\t\t\t\tclassName={cn(\"size-3.5 text-muted-foreground\", className)}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"running\":\n\t\tcase \"processing\":\n\t\t\treturn (\n\t\t\t\t<Play\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"size-3.5 text-blue-500 animate-pulse\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"success\":\n\t\t\treturn (\n\t\t\t\t<CheckCircleIcon\n\t\t\t\t\tclassName={cn(\"size-3.5 text-green-500\", className)}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t);\n\t\tcase \"error\":\n\t\t\treturn (\n\t\t\t\t<AlertCircle\n\t\t\t\t\tclassName={cn(\"size-3.5 text-red-500\", className)}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t);\n\t}\n}\n\nexport function NodeExecutionStatusContent({\n\tchildren,\n\tclassName,\n}: {\n\tchildren: ReactNode;\n\tclassName?: string;\n}) {\n\treturn (\n\t\t<div className={cn(\"flex-1 flex items-center gap-2\", className)}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport function NodeExecutionStatusName({\n\tnodeId,\n\tcapitalize = true,\n\tclassName,\n}: {\n\tnodeId: string;\n\tcapitalize?: boolean;\n\tclassName?: string;\n}) {\n\treturn (\n\t\t<span className={cn(\"font-medium text-sm\", className)}>\n\t\t\t{idToReadableText(nodeId, { capitalize })}\n\t\t</span>\n\t);\n}\n\nexport function NodeExecutionStatusBadge({\n\tstatus,\n\tclassName,\n\t...props\n}: ComponentProps<\"div\"> & {\n\tstatus: \"idle\" | \"running\" | \"processing\" | \"success\" | \"error\";\n}) {\n\tconst getStatusBadgeVariant = (): VariantProps<\n\t\ttypeof badgeVariants\n\t>[\"variant\"] => {\n\t\tswitch (status) {\n\t\t\tcase \"idle\":\n\t\t\t\treturn \"outline\";\n\t\t\tcase \"running\":\n\t\t\tcase \"processing\":\n\t\t\t\treturn \"default\";\n\t\t\tcase \"success\":\n\t\t\t\treturn \"secondary\";\n\t\t\tcase \"error\":\n\t\t\t\treturn \"destructive\";\n\t\t}\n\t};\n\n\tconst getStatusText = () => {\n\t\tswitch (status) {\n\t\t\tcase \"idle\":\n\t\t\t\treturn \"Idle\";\n\t\t\tcase \"running\":\n\t\t\t\treturn \"Running\";\n\t\t\tcase \"processing\":\n\t\t\t\treturn \"Processing\";\n\t\t\tcase \"success\":\n\t\t\t\treturn \"Success\";\n\t\t\tcase \"error\":\n\t\t\t\treturn \"Error\";\n\t\t}\n\t};\n\n\treturn (\n\t\t<Badge\n\t\t\tvariant={getStatusBadgeVariant()}\n\t\t\tclassName={cn(\"text-xs h-4 px-1.5 py-0\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{getStatusText()}\n\t\t</Badge>\n\t);\n}\n\nexport function NodeExecutionStatusType({\n\tnodeType,\n\tcapitalize = true,\n\tclassName,\n\t...props\n}: ComponentProps<\"span\"> & {\n\tnodeType: string;\n\tcapitalize?: boolean;\n}) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"text-xs text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{idToReadableText(nodeType, { capitalize })} node\n\t\t</span>\n\t);\n}\n\nexport function NodeExecutionStatusError({\n\tclassName,\n\t...props\n}: ComponentProps<\"p\">) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"px-2 py-1 mt-1 rounded-md bg-red-50 dark:bg-red-950/20\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<p className=\"text-xs text-red-600 dark:text-red-400\" {...props} />\n\t\t</div>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/node-execution.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/node-selector-panel.tsx",
			"content": "import { Panel } from \"@xyflow/react\";\nimport type React from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { getAllNodeDefinitions } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\n\nconst nodeDefinitions = getAllNodeDefinitions().filter(\n\t(def) => def.shared.type !== \"start\",\n);\nconst nodeTypes = nodeDefinitions.map((def) => ({\n\ttype: def.shared.type,\n\tlabel: def.client.meta.label,\n\ticon: def.client.meta.icon,\n}));\n\nexport function NodeSelectorPanel() {\n\tconst onDragStart = (event: React.DragEvent, nodeType: string) => {\n\t\tevent.dataTransfer.setData(\"application/reactflow\", nodeType);\n\t\tevent.dataTransfer.effectAllowed = \"move\";\n\t};\n\n\treturn (\n\t\t<Panel\n\t\t\tposition=\"top-left\"\n\t\t\tclassName=\"bg-card p-4 rounded-lg shadow-md border w-64\"\n\t\t>\n\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t<h3 className=\"font-semibold text-sm mb-2\">Add Nodes</h3>\n\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t{nodeTypes.map((nodeType) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tkey={nodeType.type}\n\t\t\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\t\t\tclassName=\"cursor-grab justify-start text-left\"\n\t\t\t\t\t\t\tdraggable\n\t\t\t\t\t\t\tonDragStart={(e) => onDragStart(e, nodeType.type)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<nodeType.icon className=\"mr-2\" />\n\t\t\t\t\t\t\t{nodeType.label}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Panel>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/node-selector-panel.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/template-selector.tsx",
			"content": "import { LayoutTemplate } from \"lucide-react\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\nimport { WORKFLOW_TEMPLATES } from \"@/registry/blocks/workflow-01/lib/templates\";\n\ninterface TemplateSelectorProps {\n\tselectedTemplateId: string;\n\tonTemplateSelect: (templateId: string) => void;\n\tclassName?: string;\n}\n\nexport function TemplateSelector({\n\tselectedTemplateId,\n\tonTemplateSelect,\n\tclassName,\n}: TemplateSelectorProps) {\n\tconst selectedTemplate = WORKFLOW_TEMPLATES.find(\n\t\t(template) => template.id === selectedTemplateId,\n\t);\n\n\tconst categories = [...new Set(WORKFLOW_TEMPLATES.map((t) => t.category))];\n\n\treturn (\n\t\t<div className={cn(\"flex items-center gap-2\", className)}>\n\t\t\t<span className=\"text-muted-foreground text-sm\">Template:</span>\n\t\t\t<Select value={selectedTemplateId} onValueChange={onTemplateSelect}>\n\t\t\t\t<SelectTrigger className=\"w-[240px] h-9\">\n\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<LayoutTemplate className=\"h-4 w-4 shrink-0\" />\n\t\t\t\t\t\t<SelectValue>\n\t\t\t\t\t\t\t<span className=\"font-medium text-sm\">\n\t\t\t\t\t\t\t\t{selectedTemplate?.name || \"Select Template\"}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</SelectValue>\n\t\t\t\t\t</div>\n\t\t\t\t</SelectTrigger>\n\t\t\t\t<SelectContent>\n\t\t\t\t\t{categories.map((category) => (\n\t\t\t\t\t\t<div key={category}>\n\t\t\t\t\t\t\t<div className=\"px-2 py-1 text-xs font-semibold text-muted-foreground uppercase tracking-wide\">\n\t\t\t\t\t\t\t\t{category}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{WORKFLOW_TEMPLATES.filter(\n\t\t\t\t\t\t\t\t(t) => t.category === category,\n\t\t\t\t\t\t\t).map((template) => (\n\t\t\t\t\t\t\t\t<SelectItem\n\t\t\t\t\t\t\t\t\tkey={template.id}\n\t\t\t\t\t\t\t\t\tvalue={template.id}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<div className=\"flex flex-col items-start\">\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">\n\t\t\t\t\t\t\t\t\t\t\t{template.name}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t{template.description}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t{category !== categories[categories.length - 1] && (\n\t\t\t\t\t\t\t\t<div className=\"border-b my-1\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</SelectContent>\n\t\t\t</Select>\n\t\t</div>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/template-selector.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/theme-provider.tsx",
			"content": "\"use client\";\n\nimport {\n\tThemeProvider as NextThemesProvider,\n\ttype ThemeProviderProps,\n} from \"next-themes\";\n\nexport function ThemeProvider({ children, ...props }: ThemeProviderProps) {\n\treturn (\n\t\t<NextThemesProvider\n\t\t\tattribute=\"class\"\n\t\t\tdefaultTheme=\"system\"\n\t\t\tenableSystem\n\t\t\tdisableTransitionOnChange\n\t\t\tenableColorScheme\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</NextThemesProvider>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/theme-provider.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/theme-toggle.tsx",
			"content": "\"use client\";\n\nimport { MoonIcon, SunIcon } from \"lucide-react\";\nimport { useTheme } from \"next-themes\";\nimport { type ComponentProps, useCallback } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\nexport const ThemeToggle = ({\n\tclassName,\n\t...props\n}: ComponentProps<typeof Button>) => {\n\tconst { theme, setTheme } = useTheme();\n\n\tconst toggleTheme = useCallback(() => {\n\t\tsetTheme(theme === \"light\" ? \"dark\" : \"light\");\n\t}, [theme, setTheme]);\n\n\treturn (\n\t\t<Button\n\t\t\tvariant=\"ghost\"\n\t\t\tsize=\"icon-sm\"\n\t\t\tclassName={cn(\"group/toggle\", className)}\n\t\t\tonClick={toggleTheme}\n\t\t\t{...props}\n\t\t>\n\t\t\t<SunIcon className=\"hidden [html.dark_&]:block\" />\n\t\t\t<MoonIcon className=\"hidden [html.light_&]:block\" />\n\t\t\t<span className=\"sr-only\">Toggle theme</span>\n\t\t</Button>\n\t);\n};\n",
			"type": "registry:component",
			"target": "components/theme-toggle.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/validation-status.tsx",
			"content": "\"use client\";\n\nimport { AlertCircle, AlertTriangle } from \"lucide-react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport {\n\tPopover,\n\tPopoverContent,\n\tPopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\n\nexport function ValidationStatus() {\n\tconst validationState = useWorkflow((store) => store.validationState);\n\n\tconst hasErrors = validationState.errors.length > 0;\n\tconst hasWarnings = validationState.warnings.length > 0;\n\n\tif (!hasErrors && !hasWarnings) {\n\t\treturn null;\n\t}\n\n\tconst badgeText =\n\t\thasErrors && hasWarnings\n\t\t\t? `${validationState.errors.length} errors, ${validationState.warnings.length} warnings`\n\t\t\t: hasErrors\n\t\t\t\t? `${validationState.errors.length} errors`\n\t\t\t\t: `${validationState.warnings.length} warnings`;\n\n\treturn (\n\t\t<Popover>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<div className=\"cursor-pointer\">\n\t\t\t\t\t<Badge\n\t\t\t\t\t\tvariant={hasErrors ? \"destructive\" : \"secondary\"}\n\t\t\t\t\t\tclassName=\"gap-1\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{hasErrors ? (\n\t\t\t\t\t\t\t<AlertCircle className=\"size-3\" />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<AlertTriangle className=\"size-3\" />\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<span>{badgeText}</span>\n\t\t\t\t\t</Badge>\n\t\t\t\t</div>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-80\">\n\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t<div className=\"font-semibold text-sm\">\n\t\t\t\t\t\t{hasErrors && hasWarnings\n\t\t\t\t\t\t\t? \"Workflow Errors & Warnings\"\n\t\t\t\t\t\t\t: hasErrors\n\t\t\t\t\t\t\t\t? \"Workflow Errors\"\n\t\t\t\t\t\t\t\t: \"Workflow Warnings\"}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{hasErrors && (\n\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t<div className=\"text-xs font-medium text-red-900\">\n\t\t\t\t\t\t\t\tErrors\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"space-y-2 max-h-64 overflow-y-auto\">\n\t\t\t\t\t\t\t\t{validationState.errors.map((error, idx) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={`error-${error.type}-${error.message}-${idx}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"text-xs p-2 bg-red-50 border border-red-200 rounded\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<div className=\"font-medium text-red-900\">\n\t\t\t\t\t\t\t\t\t\t\t{error.type}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t<div className=\"text-red-700 mt-1\">\n\t\t\t\t\t\t\t\t\t\t\t{error.message}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\n\t\t\t\t\t{hasWarnings && (\n\t\t\t\t\t\t<div className=\"space-y-2\">\n\t\t\t\t\t\t\t<div className=\"text-xs font-medium text-yellow-900\">\n\t\t\t\t\t\t\t\tWarnings\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"space-y-2 max-h-64 overflow-y-auto\">\n\t\t\t\t\t\t\t\t{validationState.warnings.map(\n\t\t\t\t\t\t\t\t\t(warning, idx) => (\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tkey={`warning-${warning.type}-${warning.message}-${idx}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"text-xs p-2 bg-yellow-50 border border-yellow-200 rounded\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-yellow-700\">\n\t\t\t\t\t\t\t\t\t\t\t\t{warning.message}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/validation-status.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/index.ts",
			"content": "import { agentNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/agent\";\nimport { endNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/end\";\nimport { ifElseNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/if-else\";\nimport { noteNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/note\";\nimport { startNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/start\";\nimport { waitNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/wait\";\nimport type {\n\tAnyNodeDefinition,\n\tFlowNodeType,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nconst nodeDefinitions = {\n\tagent: agentNodeDefinition,\n\t\"if-else\": ifElseNodeDefinition,\n\tstart: startNodeDefinition,\n\tend: endNodeDefinition,\n\tnote: noteNodeDefinition,\n\twait: waitNodeDefinition,\n} as const;\n\nexport const nodeRegistry = nodeDefinitions;\n\nexport function getNodeDefinition<T extends FlowNodeType>(\n\ttype: T,\n): (typeof nodeRegistry)[T] {\n\treturn nodeRegistry[type];\n}\n\nexport function getAllNodeDefinitions(): AnyNodeDefinition[] {\n\treturn Object.values(nodeRegistry);\n}\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.shared.ts",
			"content": "import type { Node } from \"@xyflow/react\";\nimport { z } from \"zod\";\nimport type {\n\tNodeSharedDefinition,\n\tValidationContext,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nconst textNodeOutputSchema = z.object({\n\ttype: z.literal(\"text\"),\n});\n\nconst structuredNodeOutputSchema = z.object({\n\ttype: z.literal(\"structured\"),\n\tschema: z.any().nullable(), // JSONSchema7, but using any for now\n});\n\nconst nodeOutputSchema = z.discriminatedUnion(\"type\", [\n\ttextNodeOutputSchema,\n\tstructuredNodeOutputSchema,\n]);\n\nexport const agentNodeDataSchema = z.object({\n\tname: z.string(),\n\tmodel: z.string(),\n\tsystemPrompt: z.string(),\n\tstatus: z.enum([\"processing\", \"error\", \"success\", \"idle\"]),\n\tselectedTools: z.array(z.string()),\n\tsourceType: nodeOutputSchema,\n\thideResponseInChat: z.boolean(),\n\texcludeFromConversation: z.boolean(),\n\tmaxSteps: z.number(),\n\tvalidationErrors: z.array(z.any()).optional(),\n});\n\nexport type AgentNodeData = z.infer<typeof agentNodeDataSchema>;\nexport type AgentNode = Node<AgentNodeData, \"agent\">;\n\n/**\n * Validates agent node configuration and connection constraints.\n */\nfunction validateAgentNode(\n\tnode: AgentNode,\n\tcontext: ValidationContext,\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst { edges } = context;\n\n\tconst outgoingEdges = edges.filter((e) => e.source === node.id);\n\tif (outgoingEdges.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Agent node must have one outgoing connection\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t} else if (outgoingEdges.length > 1) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: `Agent node can only have one outgoing connection (found ${outgoingEdges.length})`,\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\tif (\n\t\tnode.data.sourceType.type === \"structured\" &&\n\t\t!node.data.sourceType.schema\n\t) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Agent node with structured output must have a schema\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nexport const agentSharedDefinition: NodeSharedDefinition<AgentNode> = {\n\ttype: \"agent\",\n\tdataSchema: agentNodeDataSchema,\n\tvalidate: validateAgentNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/agent/agent.shared.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.client.tsx",
			"content": "\"use client\";\n\nimport { type NodeProps, Position } from \"@xyflow/react\";\nimport { Bot, ChevronDown, Trash } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { useState } from \"react\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n\tCollapsible,\n\tCollapsibleContent,\n\tCollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { cn } from \"@/lib/utils\";\nimport { ModelSelector } from \"@/registry/blocks/workflow-01/components/model-selector\";\nimport { BaseHandle } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-handle\";\nimport { BaseNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-node\";\nimport {\n\tNodeHeader,\n\tNodeHeaderAction,\n\tNodeHeaderActions,\n\tNodeHeaderIcon,\n\tNodeHeaderStatus,\n\tNodeHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/workflow/primitives/node-header\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport {\n\tWORKFLOW_TOOLS,\n\tworkflowTools,\n} from \"@/registry/blocks/workflow-01/lib/tools\";\nimport {\n\tWORKFLOW_MODELS,\n\ttype workflowModelID,\n} from \"@/registry/blocks/workflow-01/lib/workflow/models\";\nimport type { AgentNode as AgentNodeType } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.shared\";\nimport type { NodeClientDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\nimport { idToReadableText } from \"@/registry/lib/id-to-readable-text\";\nimport {\n\tJsonSchemaEditorDialog,\n\tJsonSchemaPreview,\n\tJsonSchemaPreviewEmpty,\n} from \"@/registry/ui/json-schema-editor\";\n\nexport interface AgentNodeProps extends NodeProps<AgentNodeType> {}\n\nexport function AgentNode({ selected, data, deletable, id }: AgentNodeProps) {\n\tconst deleteNode = useWorkflow((state) => state.deleteNode);\n\tconst canConnectHandle = useWorkflow((store) => store.canConnectHandle);\n\n\tconst validationErrors =\n\t\tdata.validationErrors?.map((error) => ({\n\t\t\tmessage: error.message,\n\t\t})) || [];\n\n\tconst isSourceConnectable = canConnectHandle({\n\t\tnodeId: id,\n\t\thandleId: \"output\",\n\t\ttype: \"source\",\n\t});\n\tconst isTargetConnectable = canConnectHandle({\n\t\tnodeId: id,\n\t\thandleId: \"input\",\n\t\ttype: \"target\",\n\t});\n\n\treturn (\n\t\t<BaseNode\n\t\t\tselected={selected}\n\t\t\tclassName={cn(\"flex flex-col p-0\", {\n\t\t\t\t\"border-orange-500\": data.status === \"processing\",\n\t\t\t\t\"border-red-500\": data.status === \"error\",\n\t\t\t})}\n\t\t>\n\t\t\t<NodeHeader className=\"m-0\">\n\t\t\t\t<NodeHeaderIcon>\n\t\t\t\t\t<Bot />\n\t\t\t\t</NodeHeaderIcon>\n\t\t\t\t<NodeHeaderTitle>Agent</NodeHeaderTitle>\n\t\t\t\t<NodeHeaderActions>\n\t\t\t\t\t<NodeHeaderStatus\n\t\t\t\t\t\tstatus={data.status}\n\t\t\t\t\t\terrors={validationErrors}\n\t\t\t\t\t/>\n\t\t\t\t\t{deletable && (\n\t\t\t\t\t\t<NodeHeaderAction\n\t\t\t\t\t\t\tonClick={() => deleteNode(id)}\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tlabel=\"Delete node\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash />\n\t\t\t\t\t\t</NodeHeaderAction>\n\t\t\t\t\t)}\n\t\t\t\t</NodeHeaderActions>\n\t\t\t</NodeHeader>\n\t\t\t<div className=\"text-left text text-muted-foreground p-2 pl-4 pt-0 max-w-[200px] truncate\">\n\t\t\t\t{data.name}\n\t\t\t</div>\n\n\t\t\t<BaseHandle\n\t\t\t\tid=\"input\"\n\t\t\t\ttype=\"target\"\n\t\t\t\tposition={Position.Left}\n\t\t\t\tisConnectable={isTargetConnectable}\n\t\t\t/>\n\n\t\t\t<BaseHandle\n\t\t\t\tid=\"output\"\n\t\t\t\ttype=\"source\"\n\t\t\t\tposition={Position.Right}\n\t\t\t\tisConnectable={isSourceConnectable}\n\t\t\t/>\n\t\t</BaseNode>\n\t);\n}\n\nexport function AgentNodePanel({ node }: { node: AgentNodeType }) {\n\tconst updateNode = useWorkflow((state) => state.updateNode);\n\tconst [advancedOpen, setAdvancedOpen] = useState(false);\n\n\treturn (\n\t\t<div className=\"space-y-4\">\n\t\t\t<div>\n\t\t\t\t<h4 className=\"font-medium text-sm mb-2\">Configuration</h4>\n\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label\n\t\t\t\t\t\t\thtmlFor={`name-${node.id}`}\n\t\t\t\t\t\t\tclassName=\"block text-xs font-medium mb-1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tName\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tid={`name-${node.id}`}\n\t\t\t\t\t\t\tvalue={node.data.name}\n\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tname: e.target.value,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tplaceholder=\"Enter agent name...\"\n\t\t\t\t\t\t\tclassName=\"text-xs\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label\n\t\t\t\t\t\t\thtmlFor={`model-${node.id}`}\n\t\t\t\t\t\t\tclassName=\"block text-xs font-medium mb-1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tModel\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<ModelSelector\n\t\t\t\t\t\t\tvalue={node.data.model as workflowModelID}\n\t\t\t\t\t\t\tonChange={(model) => {\n\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"block text-xs font-medium mb-2\">\n\t\t\t\t\t\t\tTools\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"space-y-2 rounded-md border border-input p-3 bg-background\">\n\t\t\t\t\t\t\t{WORKFLOW_TOOLS.map((toolId) => {\n\t\t\t\t\t\t\t\tconst isSelected =\n\t\t\t\t\t\t\t\t\tnode.data.selectedTools.includes(toolId);\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={toolId}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-start gap-2\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\tid={`tool-${toolId}-${node.id}`}\n\t\t\t\t\t\t\t\t\t\t\tchecked={isSelected}\n\t\t\t\t\t\t\t\t\t\t\tonCheckedChange={(checked) => {\n\t\t\t\t\t\t\t\t\t\t\t\tconst newSelectedTools = checked\n\t\t\t\t\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...node.data\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.selectedTools,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttoolId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t\t\t\t\t: node.data.selectedTools.filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(t) => t !== toolId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tselectedTools:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnewSelectedTools,\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\t\thtmlFor={`tool-${toolId}-${node.id}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"flex flex-col gap-0.5 cursor-pointer\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs font-medium leading-none\">\n\t\t\t\t\t\t\t\t\t\t\t\t{idToReadableText(toolId)}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{workflowTools[toolId]\n\t\t\t\t\t\t\t\t\t\t\t\t\t.description ??\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"No description\"}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label\n\t\t\t\t\t\t\thtmlFor={`outputType-${node.id}`}\n\t\t\t\t\t\t\tclassName=\"block text-xs font-medium mb-1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tOutput Type\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\tvalue={node.data.sourceType.type}\n\t\t\t\t\t\t\tonValueChange={(value: \"text\" | \"structured\") => {\n\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tsourceType:\n\t\t\t\t\t\t\t\t\t\t\tvalue === \"text\"\n\t\t\t\t\t\t\t\t\t\t\t\t? { type: \"text\" }\n\t\t\t\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"structured\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tschema: null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<SelectTrigger className=\"w-full\">\n\t\t\t\t\t\t\t\t<SelectValue placeholder=\"Select output type\" />\n\t\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t\t<SelectItem value=\"text\">Text</SelectItem>\n\t\t\t\t\t\t\t\t<SelectItem value=\"structured\">\n\t\t\t\t\t\t\t\t\tStructured\n\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t\t</Select>\n\t\t\t\t\t</div>\n\t\t\t\t\t{node.data.sourceType.type === \"structured\" && (\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-2 mb-1\">\n\t\t\t\t\t\t\t\t<div className=\"text-xs font-medium\">\n\t\t\t\t\t\t\t\t\tJSON Schema\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<JsonSchemaEditorDialog\n\t\t\t\t\t\t\t\tschema={node.data.sourceType.schema}\n\t\t\t\t\t\t\t\tonSave={(schema) => {\n\t\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\tsourceType: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"structured\",\n\t\t\t\t\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<div className=\"mt-2\">\n\t\t\t\t\t\t\t\t{node.data.sourceType.schema ? (\n\t\t\t\t\t\t\t\t\t<JsonSchemaPreview\n\t\t\t\t\t\t\t\t\t\tschema={node.data.sourceType.schema}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<JsonSchemaPreviewEmpty />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label\n\t\t\t\t\t\t\thtmlFor={`prompt-${node.id}`}\n\t\t\t\t\t\t\tclassName=\"block text-xs font-medium mb-1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tSystem Prompt\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<Textarea\n\t\t\t\t\t\t\tid={`prompt-${node.id}`}\n\t\t\t\t\t\t\tvalue={node.data.systemPrompt}\n\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tsystemPrompt: e.target.value,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tplaceholder=\"Enter system prompt...\"\n\t\t\t\t\t\t\tclassName=\"min-h-[80px] text-xs resize-none nodrag\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>\n\t\t\t\t\t<CollapsibleTrigger className=\"flex items-center justify-between w-full p-2 rounded-md hover:bg-muted/50 transition-colors\">\n\t\t\t\t\t\t<h4 className=\"font-medium text-sm\">Advanced</h4>\n\t\t\t\t\t\t<ChevronDown\n\t\t\t\t\t\t\tclassName={`h-4 w-4 transition-transform duration-200 ${\n\t\t\t\t\t\t\t\tadvancedOpen ? \"rotate-180\" : \"\"\n\t\t\t\t\t\t\t}`}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</CollapsibleTrigger>\n\t\t\t\t\t<CollapsibleContent className=\"space-y-3 mt-2\">\n\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\thtmlFor={`hideResponse-${node.id}`}\n\t\t\t\t\t\t\t\tclassName=\"text-xs font-medium\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tHide response in chat\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\t\tid={`hideResponse-${node.id}`}\n\t\t\t\t\t\t\t\tchecked={node.data.hideResponseInChat ?? false}\n\t\t\t\t\t\t\t\tonCheckedChange={(checked) => {\n\t\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\thideResponseInChat: checked,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\thtmlFor={`excludeConversation-${node.id}`}\n\t\t\t\t\t\t\t\tclassName=\"text-xs font-medium\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tExclude from conversation history\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\t\tid={`excludeConversation-${node.id}`}\n\t\t\t\t\t\t\t\tchecked={\n\t\t\t\t\t\t\t\t\tnode.data.excludeFromConversation ?? false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tonCheckedChange={(checked) => {\n\t\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\texcludeFromConversation: checked,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\thtmlFor={`maxSteps-${node.id}`}\n\t\t\t\t\t\t\t\tclassName=\"text-xs font-medium\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tMax steps\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid={`maxSteps-${node.id}`}\n\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\tmin=\"1\"\n\t\t\t\t\t\t\t\tmax=\"50\"\n\t\t\t\t\t\t\t\tvalue={node.data.maxSteps ?? 5}\n\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\tconst value = Number.parseInt(\n\t\t\t\t\t\t\t\t\t\te.target.value,\n\t\t\t\t\t\t\t\t\t\t10,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!Number.isNaN(value) &&\n\t\t\t\t\t\t\t\t\t\tvalue >= 1 &&\n\t\t\t\t\t\t\t\t\t\tvalue <= 50\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\t\t\tnodeType: \"agent\",\n\t\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\t\tmaxSteps: value,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName=\"w-16 h-8 text-xs\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CollapsibleContent>\n\t\t\t\t</Collapsible>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function createAgentNode(position: {\n\tx: number;\n\ty: number;\n}): AgentNodeType {\n\treturn {\n\t\tid: nanoid(),\n\t\ttype: \"agent\",\n\t\tposition,\n\t\tdata: {\n\t\t\tname: \"Agent\",\n\t\t\tstatus: \"idle\",\n\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\tsystemPrompt: \"\",\n\t\t\tselectedTools: [],\n\t\t\tsourceType: { type: \"text\" },\n\t\t\thideResponseInChat: false,\n\t\t\texcludeFromConversation: false,\n\t\t\tmaxSteps: 5,\n\t\t},\n\t};\n}\n\nexport const agentClientDefinition: NodeClientDefinition<AgentNodeType> = {\n\tcomponent: AgentNode,\n\tpanelComponent: AgentNodePanel,\n\tcreate: createAgentNode,\n\tmeta: {\n\t\tlabel: \"Agent\",\n\t\ticon: Bot,\n\t\tdescription: \"An AI agent that can process input and generate output\",\n\t},\n};\n",
			"type": "registry:component",
			"target": "lib/workflow/nodes/agent/agent.client.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.server.ts",
			"content": "import {\n\tjsonSchema,\n\tOutput,\n\tsmoothStream,\n\tstepCountIs,\n\tstreamText,\n\ttype Tool,\n} from \"ai\";\nimport {\n\ttype WorkflowToolId,\n\tworkflowTools,\n} from \"@/registry/blocks/workflow-01/lib/tools\";\nimport { workflowModel } from \"@/registry/blocks/workflow-01/lib/workflow/models\";\nimport type { AgentNode } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.shared\";\nimport type {\n\tExecutionContext,\n\tNodeExecutionResult,\n\tNodeServerDefinition,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nasync function executeAgentNode(\n\tcontext: ExecutionContext<AgentNode>,\n): Promise<NodeExecutionResult> {\n\tconst { node, edges, accumulatedMessages, writer } = context;\n\n\tlet output: Parameters<typeof streamText>[0][\"experimental_output\"];\n\n\tif (node.data.sourceType.type === \"structured\") {\n\t\tconst schema = node.data.sourceType.schema;\n\n\t\tif (!schema) {\n\t\t\tthrow new Error(\"Schema is required for structured output\");\n\t\t}\n\n\t\tconst jsonSchemaValue = jsonSchema(schema);\n\t\toutput = Output.object({\n\t\t\tschema: jsonSchemaValue,\n\t\t});\n\t}\n\n\tconst tools = workflowTools;\n\tconst agentTools: Partial<Record<WorkflowToolId, Tool>> = {};\n\n\tfor (const toolId of node.data.selectedTools) {\n\t\tif (tools[toolId as WorkflowToolId]) {\n\t\t\tagentTools[toolId as WorkflowToolId] =\n\t\t\t\ttools[toolId as WorkflowToolId];\n\t\t}\n\t}\n\n\tconst maxSteps = node.data.maxSteps ?? 5;\n\n\tconst streamResult = streamText({\n\t\tmodel: workflowModel.languageModel(node.data.model),\n\t\tsystem: node.data.systemPrompt,\n\t\tmessages: accumulatedMessages,\n\t\ttools: agentTools,\n\t\tstopWhen: stepCountIs(maxSteps),\n\t\tprepareStep: async ({ stepNumber }) => {\n\t\t\tif (stepNumber === maxSteps - 1) {\n\t\t\t\treturn {\n\t\t\t\t\ttoolChoice: \"none\",\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {};\n\t\t},\n\t\texperimental_transform: smoothStream(),\n\t\texperimental_output: output,\n\t});\n\n\tif (!node.data.hideResponseInChat) {\n\t\twriter.merge(\n\t\t\tstreamResult.toUIMessageStream({\n\t\t\t\tsendStart: false,\n\t\t\t\tsendFinish: false,\n\t\t\t\tsendReasoning: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst response = await streamResult.response;\n\tconst text = await streamResult.text;\n\n\tconsole.log(\"text\", text);\n\n\tlet structured: unknown;\n\tif (node.data.sourceType.type === \"structured\") {\n\t\ttry {\n\t\t\tstructured = JSON.parse(text);\n\t\t} catch (e) {\n\t\t\tconsole.error(\"Failed to parse structured output:\", e);\n\t\t}\n\t}\n\n\tif (!node.data.excludeFromConversation) {\n\t\taccumulatedMessages.push(...response.messages);\n\t}\n\n\tconst outgoingEdge = edges.find((edge) => edge.source === node.id);\n\tconst nextNodeId = outgoingEdge ? outgoingEdge.target : null;\n\n\twriter.write({\n\t\ttype: \"data-node-execution-state\",\n\t\tid: node.id,\n\t\tdata: {\n\t\t\tnodeId: node.id,\n\t\t\tnodeType: node.type,\n\t\t\tdata: node.data,\n\t\t},\n\t});\n\n\treturn {\n\t\tresult: {\n\t\t\ttext,\n\t\t\tstructured,\n\t\t},\n\t\tnextNodeId,\n\t};\n}\n\nexport const agentServerDefinition: NodeServerDefinition<AgentNode> = {\n\texecute: executeAgentNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/agent/agent.server.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/agent/index.ts",
			"content": "import { agentClientDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.client\";\nimport { agentServerDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.server\";\nimport {\n\ttype AgentNode,\n\tagentSharedDefinition,\n} from \"@/registry/blocks/workflow-01/lib/workflow/nodes/agent/agent.shared\";\nimport type { NodeDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const agentNodeDefinition: NodeDefinition<AgentNode> = {\n\tshared: agentSharedDefinition,\n\tclient: agentClientDefinition,\n\tserver: agentServerDefinition,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/agent/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.shared.ts",
			"content": "import { Environment } from \"@marcbachmann/cel-js\";\nimport type { Node } from \"@xyflow/react\";\nimport { z } from \"zod\";\nimport {\n\tareSchemasIdentical,\n\tconvertSchemaToCelDeclarations,\n} from \"@/registry/blocks/workflow-01/lib/workflow/context/schema-introspection\";\nimport { getPotentialInputSchemas } from \"@/registry/blocks/workflow-01/lib/workflow/context/variable-resolver\";\nimport type {\n\tNodeSharedDefinition,\n\tValidationContext,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\nimport {\n\tisNodeOfType,\n\ttype ValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nconst dynamicHandleSchema = z.object({\n\tid: z.string(),\n\tlabel: z.string().nullable(),\n\tcondition: z.string(),\n});\n\nexport const ifElseNodeDataSchema = z.object({\n\tstatus: z.enum([\"processing\", \"error\", \"success\", \"idle\"]).optional(),\n\tdynamicSourceHandles: z.array(dynamicHandleSchema),\n\tvalidationErrors: z.array(z.any()).optional(),\n});\n\nexport type IfElseNodeData = z.infer<typeof ifElseNodeDataSchema>;\nexport type IfElseNode = Node<IfElseNodeData, \"if-else\">;\n\n/**\n * Validates if-else node configuration, connection constraints, and condition expressions.\n * Validates that conditions are syntactically correct using CEL and reference available variables.\n * Validates conditions against ALL potential input schemas to ensure safety across converging paths.\n */\nfunction validateIfElseNode(\n\tnode: IfElseNode,\n\tcontext: ValidationContext,\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\n\tconst { nodes, edges } = context;\n\n\tconst outgoingEdges = edges.filter((e) => e.source === node.id);\n\n\tif (outgoingEdges.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"If-else node must have at least one outgoing connection\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\t// Get all potential input schemas for multi-path validation\n\tconst potentialInputSchemas = getPotentialInputSchemas(\n\t\tnode.id,\n\t\tnodes,\n\t\tedges,\n\t);\n\n\t// Check for schema mismatch warning\n\tif (potentialInputSchemas.length > 1) {\n\t\tconst schemas = potentialInputSchemas\n\t\t\t.map((source) => source.schema)\n\t\t\t.filter(\n\t\t\t\t(\n\t\t\t\t\tschema,\n\t\t\t\t): schema is NonNullable<\n\t\t\t\t\t(typeof potentialInputSchemas)[number][\"schema\"]\n\t\t\t\t> => schema !== null,\n\t\t\t);\n\n\t\tif (schemas.length > 1 && !areSchemasIdentical(schemas)) {\n\t\t\terrors.push({\n\t\t\t\ttype: \"invalid-node-config\",\n\t\t\t\tseverity: \"warning\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"Multiple input paths with different schemas detected. Conditions must be valid for all converging paths. Ensure all paths have compatible schemas.\",\n\t\t\t\tnode: { id: node.id },\n\t\t\t});\n\t\t}\n\t}\n\n\tfor (const handle of node.data.dynamicSourceHandles) {\n\t\tconst edgeForHandle = outgoingEdges.find(\n\t\t\t(e) => e.sourceHandle === handle.id,\n\t\t);\n\t\tif (edgeForHandle && !handle.condition.trim()) {\n\t\t\terrors.push({\n\t\t\t\ttype: \"invalid-node-config\",\n\t\t\t\tseverity: \"error\",\n\t\t\t\tmessage: `If-else condition \"${handle.label || handle.id}\" has a connection but no condition expression`,\n\t\t\t\tnode: { id: node.id },\n\t\t\t});\n\t\t}\n\n\t\tif (handle.condition?.trim()) {\n\t\t\tconst hasIncomingEdge = edges.some(\n\t\t\t\t(e) => e.target === node.id && e.targetHandle === \"input\",\n\t\t\t);\n\n\t\t\tif (!hasIncomingEdge) {\n\t\t\t\t// Validate syntax only when no input connection\n\t\t\t\ttry {\n\t\t\t\t\tconst env = new Environment();\n\t\t\t\t\tconst checkResult = env.check(handle.condition);\n\t\t\t\t\tif (!checkResult.valid && checkResult.error) {\n\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\ttype: \"invalid-condition\",\n\t\t\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\t\t\tmessage: \"Invalid condition expression syntax\",\n\t\t\t\t\t\t\tcondition: {\n\t\t\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\t\t\thandleId: handle.id,\n\t\t\t\t\t\t\t\tcondition: handle.condition,\n\t\t\t\t\t\t\t\terror: checkResult.error.message,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\ttype: \"invalid-condition\",\n\t\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\t\tmessage: \"Invalid condition expression syntax\",\n\t\t\t\t\t\tcondition: {\n\t\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\t\thandleId: handle.id,\n\t\t\t\t\t\t\tcondition: handle.condition,\n\t\t\t\t\t\t\terror:\n\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t: String(error),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Validate against all potential input schemas\n\t\t\t\tif (potentialInputSchemas.length === 0) {\n\t\t\t\t\t// No input sources - validate syntax only\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst env = new Environment();\n\t\t\t\t\t\tenv.check(handle.condition);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\ttype: \"invalid-condition\",\n\t\t\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\t\t\tmessage: \"Invalid condition expression syntax\",\n\t\t\t\t\t\t\tcondition: {\n\t\t\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\t\t\thandleId: handle.id,\n\t\t\t\t\t\t\t\tcondition: handle.condition,\n\t\t\t\t\t\t\t\terror:\n\t\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t: String(error),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Validate against each potential input schema\n\t\t\t\t\tfor (const source of potentialInputSchemas) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst env = new Environment();\n\n\t\t\t\t\t\t\t// Register types and variables based on schema\n\t\t\t\t\t\t\tif (source.schema) {\n\t\t\t\t\t\t\t\tconst conversion =\n\t\t\t\t\t\t\t\t\tconvertSchemaToCelDeclarations(\n\t\t\t\t\t\t\t\t\t\tsource.schema,\n\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Register all nested types first (they're already in dependency order)\n\t\t\t\t\t\t\t\tfor (const typeDef of conversion.typeDefinitions) {\n\t\t\t\t\t\t\t\t\t// Create a dummy constructor class for CEL\n\t\t\t\t\t\t\t\t\tclass DummyType {}\n\t\t\t\t\t\t\t\t\tenv.registerType(typeDef.typename, {\n\t\t\t\t\t\t\t\t\t\tctor: DummyType,\n\t\t\t\t\t\t\t\t\t\tfields: typeDef.fields,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Register the root variable\n\t\t\t\t\t\t\t\tenv.registerVariable(\n\t\t\t\t\t\t\t\t\tconversion.variableDeclaration.name,\n\t\t\t\t\t\t\t\t\tconversion.variableDeclaration.type,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Text output - register basic input as string\n\t\t\t\t\t\t\t\tenv.registerVariable(\"input\", \"string\");\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst checkResult = env.check(handle.condition);\n\n\t\t\t\t\t\t\t// Report validation errors\n\t\t\t\t\t\t\tif (!checkResult.valid && checkResult.error) {\n\t\t\t\t\t\t\t\tconst sourceNode = nodes.find(\n\t\t\t\t\t\t\t\t\t(n) => n.id === source.nodeId,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tconst nodeName =\n\t\t\t\t\t\t\t\t\tsourceNode &&\n\t\t\t\t\t\t\t\t\tisNodeOfType(sourceNode, \"agent\")\n\t\t\t\t\t\t\t\t\t\t? sourceNode.data.name\n\t\t\t\t\t\t\t\t\t\t: source.nodeName || source.nodeId;\n\n\t\t\t\t\t\t\t\tconst errorMessage = checkResult.error.message;\n\n\t\t\t\t\t\t\t\t// Extract field name from error message if possible\n\t\t\t\t\t\t\t\tlet enhancedMessage = errorMessage;\n\t\t\t\t\t\t\t\tconst fieldMatch =\n\t\t\t\t\t\t\t\t\terrorMessage.match(/No such key: (\\w+)/);\n\t\t\t\t\t\t\t\tif (fieldMatch) {\n\t\t\t\t\t\t\t\t\tconst fieldName = fieldMatch[1];\n\t\t\t\t\t\t\t\t\tenhancedMessage = `Field 'input.${fieldName}' not found in schema from '${nodeName}'. Ensure all converging paths have compatible schemas.`;\n\t\t\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\t\t\terrorMessage.includes(\"Unknown variable\")\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t// Extract variable name from error\n\t\t\t\t\t\t\t\t\tconst varMatch = errorMessage.match(\n\t\t\t\t\t\t\t\t\t\t/Unknown variable: (\\S+)/,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tif (varMatch) {\n\t\t\t\t\t\t\t\t\t\tconst varName = varMatch[1];\n\t\t\t\t\t\t\t\t\t\tenhancedMessage = `Variable '${varName}' not found in schema from '${nodeName}'. Ensure all converging paths have compatible schemas.`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\t\t\ttype: \"invalid-condition\",\n\t\t\t\t\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\t\t\t\t\tmessage: `Expression failed validation for input from '${nodeName}': ${enhancedMessage}`,\n\t\t\t\t\t\t\t\t\tcondition: {\n\t\t\t\t\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\t\t\t\t\thandleId: handle.id,\n\t\t\t\t\t\t\t\t\t\tcondition: handle.condition,\n\t\t\t\t\t\t\t\t\t\terror: enhancedMessage,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t// Catch syntax errors and other exceptions\n\t\t\t\t\t\t\tconst sourceNode = nodes.find(\n\t\t\t\t\t\t\t\t(n) => n.id === source.nodeId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconst nodeName =\n\t\t\t\t\t\t\t\tsourceNode && isNodeOfType(sourceNode, \"agent\")\n\t\t\t\t\t\t\t\t\t? sourceNode.data.name\n\t\t\t\t\t\t\t\t\t: source.nodeName || source.nodeId;\n\n\t\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\t\ttype: \"invalid-condition\",\n\t\t\t\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\t\t\t\tmessage: `Expression failed validation for input from '${nodeName}': ${\n\t\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t: String(error)\n\t\t\t\t\t\t\t\t}`,\n\t\t\t\t\t\t\t\tcondition: {\n\t\t\t\t\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\t\t\t\t\thandleId: handle.id,\n\t\t\t\t\t\t\t\t\tcondition: handle.condition,\n\t\t\t\t\t\t\t\t\terror:\n\t\t\t\t\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t\t: String(error),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn errors;\n}\n\nexport const ifElseSharedDefinition: NodeSharedDefinition<IfElseNode> = {\n\ttype: \"if-else\",\n\tdataSchema: ifElseNodeDataSchema,\n\tvalidate: validateIfElseNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/if-else/if-else.shared.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.client.tsx",
			"content": "\"use client\";\n\nimport {\n\ttype NodeProps,\n\tPosition,\n\tuseUpdateNodeInternals,\n} from \"@xyflow/react\";\nimport { GitBranch, Plus, Trash } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { useMemo } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { cn } from \"@/lib/utils\";\nimport { ConditionEditor } from \"@/registry/blocks/workflow-01/components/editor/condition-editor\";\nimport { BaseNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-node\";\nimport { LabeledHandle } from \"@/registry/blocks/workflow-01/components/workflow/primitives/labeled-handle\";\nimport {\n\tNodeHeader,\n\tNodeHeaderAction,\n\tNodeHeaderActions,\n\tNodeHeaderIcon,\n\tNodeHeaderStatus,\n\tNodeHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/workflow/primitives/node-header\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport { getUnionOfVariables } from \"@/registry/blocks/workflow-01/lib/workflow/context/variable-resolver\";\nimport type { IfElseNode as IfElseNodeType } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.shared\";\nimport type { NodeClientDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport interface IfElseNodeProps extends NodeProps<IfElseNodeType> {}\n\nexport function IfElseNode({ selected, data, deletable, id }: IfElseNodeProps) {\n\tconst deleteNode = useWorkflow((state) => state.deleteNode);\n\n\tconst validationErrors =\n\t\tdata.validationErrors?.map((error) => ({\n\t\t\tmessage: error.message,\n\t\t})) || [];\n\n\treturn (\n\t\t<BaseNode\n\t\t\tselected={selected}\n\t\t\tclassName={cn(\"flex flex-col p-0\", {\n\t\t\t\t\"border-orange-500\": data.status === \"processing\",\n\t\t\t\t\"border-red-500\": data.status === \"error\",\n\t\t\t})}\n\t\t>\n\t\t\t<NodeHeader className=\"m-0\">\n\t\t\t\t<NodeHeaderIcon>\n\t\t\t\t\t<GitBranch />\n\t\t\t\t</NodeHeaderIcon>\n\t\t\t\t<NodeHeaderTitle>If/Else</NodeHeaderTitle>\n\t\t\t\t<NodeHeaderActions>\n\t\t\t\t\t<NodeHeaderStatus\n\t\t\t\t\t\tstatus={data.status}\n\t\t\t\t\t\terrors={validationErrors}\n\t\t\t\t\t/>\n\t\t\t\t\t{deletable && (\n\t\t\t\t\t\t<NodeHeaderAction\n\t\t\t\t\t\t\tonClick={() => deleteNode(id)}\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tlabel=\"Delete node\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash />\n\t\t\t\t\t\t</NodeHeaderAction>\n\t\t\t\t\t)}\n\t\t\t\t</NodeHeaderActions>\n\t\t\t</NodeHeader>\n\t\t\t<Separator />\n\t\t\t<div className=\"grid grid-cols-3 gap-2 pt-2 pb-4 text-sm\">\n\t\t\t\t<div className=\"col-span-1 flex flex-col gap-2\">\n\t\t\t\t\t<LabeledHandle\n\t\t\t\t\t\tid=\"input\"\n\t\t\t\t\t\ttitle=\"Input\"\n\t\t\t\t\t\ttype=\"target\"\n\t\t\t\t\t\tposition={Position.Left}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"col-span-2 flex flex-col gap-2 justify-self-end\">\n\t\t\t\t\t{data.dynamicSourceHandles.map((handle) => {\n\t\t\t\t\t\tconst displayText =\n\t\t\t\t\t\t\thandle.label || handle.condition || \"-\";\n\t\t\t\t\t\tconst isPlaceholder =\n\t\t\t\t\t\t\t!handle.label && !handle.condition;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<LabeledHandle\n\t\t\t\t\t\t\t\tkey={handle.id}\n\t\t\t\t\t\t\t\tid={handle.id}\n\t\t\t\t\t\t\t\ttitle={displayText}\n\t\t\t\t\t\t\t\tlabelClassName={cn(\n\t\t\t\t\t\t\t\t\t\"max-w-56 truncate\",\n\t\t\t\t\t\t\t\t\tisPlaceholder\n\t\t\t\t\t\t\t\t\t\t? \"text-muted-foreground\"\n\t\t\t\t\t\t\t\t\t\t: \"\",\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\ttype=\"source\"\n\t\t\t\t\t\t\t\tposition={Position.Right}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t\t<LabeledHandle\n\t\t\t\t\t\tid=\"output-else\"\n\t\t\t\t\t\ttitle=\"Else\"\n\t\t\t\t\t\tlabelClassName=\"max-w-32 truncate\"\n\t\t\t\t\t\ttype=\"source\"\n\t\t\t\t\t\tposition={Position.Right}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</BaseNode>\n\t);\n}\n\nexport function IfElseNodePanel({ node }: { node: IfElseNodeType }) {\n\tconst updateNode = useWorkflow((state) => state.updateNode);\n\tconst nodes = useWorkflow((state) => state.nodes);\n\tconst edges = useWorkflow((state) => state.edges);\n\tconst updateNodeInternals = useUpdateNodeInternals();\n\n\tconst availableVariables = useMemo(\n\t\t() => getUnionOfVariables(node.id, nodes, edges),\n\t\t[node.id, nodes, edges],\n\t);\n\n\tconst getConditionError = (handleId: string): string | undefined => {\n\t\treturn node.data.validationErrors?.find(\n\t\t\t(err: {\n\t\t\t\ttype?: string;\n\t\t\t\tcondition?: { handleId?: string; error?: string };\n\t\t\t}) =>\n\t\t\t\terr.type === \"invalid-condition\" &&\n\t\t\t\terr.condition?.handleId === handleId,\n\t\t)?.condition?.error;\n\t};\n\n\tconst addSourceHandle = () => {\n\t\tupdateNode({\n\t\t\tid: node.id,\n\t\t\tnodeType: \"if-else\",\n\t\t\tdata: {\n\t\t\t\tdynamicSourceHandles: [\n\t\t\t\t\t...node.data.dynamicSourceHandles,\n\t\t\t\t\t{\n\t\t\t\t\t\tid: `output-${nanoid()}`,\n\t\t\t\t\t\tlabel: null,\n\t\t\t\t\t\tcondition: \"\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t});\n\t\tupdateNodeInternals(node.id);\n\t};\n\n\tconst updateSourceHandle = (\n\t\thandleId: string,\n\t\tupdates: { label?: string | null; condition?: string },\n\t) => {\n\t\tupdateNode({\n\t\t\tid: node.id,\n\t\t\tnodeType: \"if-else\",\n\t\t\tdata: {\n\t\t\t\tdynamicSourceHandles: node.data.dynamicSourceHandles.map(\n\t\t\t\t\t(handle) =>\n\t\t\t\t\t\thandle.id === handleId\n\t\t\t\t\t\t\t? { ...handle, ...updates }\n\t\t\t\t\t\t\t: handle,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t};\n\n\tconst removeSourceHandle = (handleId: string) => {\n\t\tupdateNode({\n\t\t\tid: node.id,\n\t\t\tnodeType: \"if-else\",\n\t\t\tdata: {\n\t\t\t\tdynamicSourceHandles: node.data.dynamicSourceHandles.filter(\n\t\t\t\t\t(handle) => handle.id !== handleId,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t\tupdateNodeInternals(node.id);\n\t};\n\n\treturn (\n\t\t<div className=\"space-y-4\">\n\t\t\t<div>\n\t\t\t\t<p className=\"text-xs text-gray-600\">\n\t\t\t\t\tThis node routes execution based on a condition. The \"If\"\n\t\t\t\t\toutput executes when the condition is true, and the \"Else\"\n\t\t\t\t\toutput executes when the condition is false.\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<h4 className=\"font-medium text-sm mb-3\">Conditions</h4>\n\t\t\t\t<Separator className=\"my-2\" />\n\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t{node.data.dynamicSourceHandles.map((handle, index) => (\n\t\t\t\t\t\t<div key={handle.id} className=\"space-y-3\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t\t\t\t\t<span className=\"text-sm font-medium\">\n\t\t\t\t\t\t\t\t\tCondition {index + 1}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{node.data.dynamicSourceHandles.length > 1 && (\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\t\t\t\tremoveSourceHandle(handle.id)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tsize=\"icon-sm\"\n\t\t\t\t\t\t\t\t\t\tvariant=\"destructive\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Trash className=\"w-3 h-3\" />\n\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"grid grid-cols-1 gap-2\">\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\thtmlFor={`label-${handle.id}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"text-xs text-gray-600 mb-1 block\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tLabel\n\t\t\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\tid={`label-${handle.id}`}\n\t\t\t\t\t\t\t\t\t\tvalue={handle.label || \"\"}\n\t\t\t\t\t\t\t\t\t\tonChange={(e) =>\n\t\t\t\t\t\t\t\t\t\t\tupdateSourceHandle(handle.id, {\n\t\t\t\t\t\t\t\t\t\t\t\tlabel: e.target.value || null,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Enter label (optional)\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-8 text-sm\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\thtmlFor={`condition-${handle.id}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"text-xs text-gray-600 mb-1 block\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tCondition\n\t\t\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t\t\t<ConditionEditor\n\t\t\t\t\t\t\t\t\t\tvalue={handle.condition}\n\t\t\t\t\t\t\t\t\t\tonChange={(value) =>\n\t\t\t\t\t\t\t\t\t\t\tupdateSourceHandle(handle.id, {\n\t\t\t\t\t\t\t\t\t\t\t\tcondition: value,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tavailableVariables={availableVariables}\n\t\t\t\t\t\t\t\t\t\tvalidationError={getConditionError(\n\t\t\t\t\t\t\t\t\t\t\thandle.id,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Enter condition expression\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{index <\n\t\t\t\t\t\t\t\tnode.data.dynamicSourceHandles.length - 1 && (\n\t\t\t\t\t\t\t\t<Separator className=\"my-2\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div>\n\t\t\t\t<Button onClick={addSourceHandle} size=\"sm\" className=\"w-full\">\n\t\t\t\t\t<Plus className=\"w-4 h-4 mr-2\" />\n\t\t\t\t\tAdd Condition\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function createIfElseNode(position: {\n\tx: number;\n\ty: number;\n}): IfElseNodeType {\n\treturn {\n\t\tid: nanoid(),\n\t\ttype: \"if-else\",\n\t\tposition,\n\t\tdata: {\n\t\t\tstatus: \"idle\",\n\t\t\tdynamicSourceHandles: [\n\t\t\t\t{\n\t\t\t\t\tid: `output-${nanoid()}`,\n\t\t\t\t\tlabel: \"If\",\n\t\t\t\t\tcondition: \"\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t};\n}\n\nexport const ifElseClientDefinition: NodeClientDefinition<IfElseNodeType> = {\n\tcomponent: IfElseNode,\n\tpanelComponent: IfElseNodePanel,\n\tcreate: createIfElseNode,\n\tmeta: {\n\t\tlabel: \"If/Else\",\n\t\ticon: GitBranch,\n\t\tdescription: \"Routes execution based on conditional expressions\",\n\t},\n};\n",
			"type": "registry:component",
			"target": "lib/workflow/nodes/if-else/if-else.client.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.server.ts",
			"content": "import { Environment } from \"@marcbachmann/cel-js\";\nimport type { IfElseNode } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.shared\";\nimport type {\n\tExecutionContext,\n\tNodeExecutionResult,\n\tNodeServerDefinition,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\n// Cache the CEL environment since it's stateless and reusable\nconst celEnv = new Environment();\ncelEnv.registerVariable(\"input\", \"dyn\");\n\nfunction executeIfElseNode(\n\tcontext: ExecutionContext<IfElseNode>,\n): NodeExecutionResult {\n\tconst { node, edges, executionMemory, previousNodeId, writer } = context;\n\n\tconst result = {\n\t\ttext: \"if-else-routing\",\n\t};\n\n\tconst previousContext = executionMemory[previousNodeId];\n\tlet nextNodeId: string | null = null;\n\n\tif (previousContext) {\n\t\tconst evalContext = {\n\t\t\tinput: previousContext.structured\n\t\t\t\t? previousContext.structured\n\t\t\t\t: previousContext.text,\n\t\t};\n\n\t\tfor (const handle of node.data.dynamicSourceHandles) {\n\t\t\tif (!handle.condition || handle.condition.trim() === \"\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst conditionResult = celEnv.evaluate(\n\t\t\t\t\thandle.condition,\n\t\t\t\t\tevalContext,\n\t\t\t\t);\n\n\t\t\t\tif (conditionResult === true) {\n\t\t\t\t\tconst outgoingEdge = edges.find(\n\t\t\t\t\t\t(edge) =>\n\t\t\t\t\t\t\tedge.source === node.id &&\n\t\t\t\t\t\t\tedge.sourceHandle === handle.id,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (outgoingEdge) {\n\t\t\t\t\t\tnextNodeId = outgoingEdge.target;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Silently continue to next condition if evaluation fails\n\t\t\t\t// Validation should have caught this earlier\n\t\t\t}\n\t\t}\n\n\t\tif (!nextNodeId) {\n\t\t\tconst elseEdge = edges.find(\n\t\t\t\t(edge) =>\n\t\t\t\t\tedge.source === node.id &&\n\t\t\t\t\tedge.sourceHandle === \"output-else\",\n\t\t\t);\n\t\t\tnextNodeId = elseEdge ? elseEdge.target : null;\n\t\t}\n\t}\n\n\twriter.write({\n\t\ttype: \"data-node-execution-state\",\n\t\tid: node.id,\n\t\tdata: {\n\t\t\tnodeId: node.id,\n\t\t\tnodeType: node.type,\n\t\t\tdata: node.data,\n\t\t},\n\t});\n\n\treturn { result, nextNodeId };\n}\n\nexport const ifElseServerDefinition: NodeServerDefinition<IfElseNode> = {\n\texecute: executeIfElseNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/if-else/if-else.server.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/if-else/index.ts",
			"content": "import { ifElseClientDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.client\";\nimport { ifElseServerDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.server\";\nimport {\n\ttype IfElseNode,\n\tifElseSharedDefinition,\n} from \"@/registry/blocks/workflow-01/lib/workflow/nodes/if-else/if-else.shared\";\nimport type { NodeDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const ifElseNodeDefinition: NodeDefinition<IfElseNode> = {\n\tshared: ifElseSharedDefinition,\n\tclient: ifElseClientDefinition,\n\tserver: ifElseServerDefinition,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/if-else/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/start/start.shared.ts",
			"content": "import type { Node } from \"@xyflow/react\";\nimport { z } from \"zod\";\nimport type {\n\tNodeSharedDefinition,\n\tValidationContext,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nconst textNodeOutputSchema = z.object({\n\ttype: z.literal(\"text\"),\n});\n\nexport const startNodeDataSchema = z.object({\n\tstatus: z.enum([\"processing\", \"error\", \"success\", \"idle\"]).optional(),\n\tsourceType: textNodeOutputSchema,\n\tvalidationErrors: z.array(z.any()).optional(),\n});\n\nexport type StartNodeData = z.infer<typeof startNodeDataSchema>;\nexport type StartNode = Node<StartNodeData, \"start\">;\n\n/**\n * Validates start node connection constraints: no incoming edges and exactly one outgoing edge.\n */\nfunction validateStartNode(\n\tnode: StartNode,\n\tcontext: ValidationContext,\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst { edges } = context;\n\n\tconst incomingEdges = edges.filter((e) => e.target === node.id);\n\tif (incomingEdges.length > 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Start node cannot have incoming connections\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\tconst outgoingEdges = edges.filter((e) => e.source === node.id);\n\tif (outgoingEdges.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Start node must have exactly one outgoing connection\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t} else if (outgoingEdges.length > 1) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: `Start node can only have one outgoing connection (found ${outgoingEdges.length})`,\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nexport const startSharedDefinition: NodeSharedDefinition<StartNode> = {\n\ttype: \"start\",\n\tdataSchema: startNodeDataSchema,\n\tvalidate: validateStartNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/start/start.shared.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/start/start.client.tsx",
			"content": "\"use client\";\n\nimport { type NodeProps, Position } from \"@xyflow/react\";\nimport { Play } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { cn } from \"@/lib/utils\";\nimport { BaseHandle } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-handle\";\nimport { BaseNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-node\";\nimport {\n\tNodeHeader,\n\tNodeHeaderActions,\n\tNodeHeaderIcon,\n\tNodeHeaderStatus,\n\tNodeHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/workflow/primitives/node-header\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport type { StartNode as StartNodeType } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/start/start.shared\";\nimport type { NodeClientDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport interface StartNodeProps extends NodeProps<StartNodeType> {}\n\nexport function StartNode({ id, selected, data }: StartNodeProps) {\n\tconst canConnectHandle = useWorkflow((store) => store.canConnectHandle);\n\n\tconst validationErrors =\n\t\tdata.validationErrors?.map((error) => ({\n\t\t\tmessage: error.message,\n\t\t})) || [];\n\n\tconst isHandleConnectable = canConnectHandle({\n\t\tnodeId: id,\n\t\thandleId: \"output\",\n\t\ttype: \"source\",\n\t});\n\n\treturn (\n\t\t<BaseNode\n\t\t\tselected={selected}\n\t\t\tclassName={cn(\"flex flex-col p-2\", {\n\t\t\t\t\"border-orange-500\": data.status === \"processing\",\n\t\t\t\t\"border-red-500\": data.status === \"error\",\n\t\t\t})}\n\t\t>\n\t\t\t<NodeHeader className=\"m-0\">\n\t\t\t\t<NodeHeaderIcon>\n\t\t\t\t\t<Play />\n\t\t\t\t</NodeHeaderIcon>\n\t\t\t\t<NodeHeaderTitle>Start</NodeHeaderTitle>\n\t\t\t\t<NodeHeaderActions>\n\t\t\t\t\t<NodeHeaderStatus\n\t\t\t\t\t\tstatus={data.status}\n\t\t\t\t\t\terrors={validationErrors}\n\t\t\t\t\t/>\n\t\t\t\t</NodeHeaderActions>\n\t\t\t</NodeHeader>\n\n\t\t\t<BaseHandle\n\t\t\t\tid=\"output\"\n\t\t\t\ttype=\"source\"\n\t\t\t\tposition={Position.Right}\n\t\t\t\tisConnectable={isHandleConnectable}\n\t\t\t/>\n\t\t</BaseNode>\n\t);\n}\n\nexport function StartNodePanel({ node: _node }: { node: StartNodeType }) {\n\treturn (\n\t\t<div className=\"space-y-4\">\n\t\t\t<div>\n\t\t\t\t<h4 className=\"font-medium text-sm mb-2\">Start Node</h4>\n\t\t\t\t<p className=\"text-xs text-gray-600\">\n\t\t\t\t\tThis node initiates the workflow execution.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function createStartNode(position: {\n\tx: number;\n\ty: number;\n}): StartNodeType {\n\treturn {\n\t\tid: nanoid(),\n\t\ttype: \"start\",\n\t\tposition,\n\t\tdeletable: false,\n\t\tdata: {\n\t\t\tsourceType: { type: \"text\" },\n\t\t},\n\t};\n}\n\nexport const startClientDefinition: NodeClientDefinition<StartNodeType> = {\n\tcomponent: StartNode,\n\tpanelComponent: StartNodePanel,\n\tcreate: createStartNode,\n\tmeta: {\n\t\tlabel: \"Start\",\n\t\ticon: Play,\n\t\tdescription: \"The entry point of the workflow\",\n\t},\n};\n",
			"type": "registry:component",
			"target": "lib/workflow/nodes/start/start.client.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/start/start.server.ts",
			"content": "import type { StartNode } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/start/start.shared\";\nimport type {\n\tExecutionContext,\n\tNodeExecutionResult,\n\tNodeServerDefinition,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nfunction executeStartNode(\n\tcontext: ExecutionContext<StartNode>,\n): NodeExecutionResult {\n\tconst { node, edges, writer } = context;\n\n\tconst result = {\n\t\ttext: \"start\",\n\t};\n\n\tconst outgoingEdge = edges.find((edge) => edge.source === node.id);\n\tconst nextNodeId = outgoingEdge ? outgoingEdge.target : null;\n\n\twriter.write({\n\t\ttype: \"data-node-execution-state\",\n\t\tid: node.id,\n\t\tdata: {\n\t\t\tnodeId: node.id,\n\t\t\tnodeType: node.type,\n\t\t\tdata: node.data,\n\t\t},\n\t});\n\n\treturn { result, nextNodeId };\n}\n\nexport const startServerDefinition: NodeServerDefinition<StartNode> = {\n\texecute: executeStartNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/start/start.server.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/start/index.ts",
			"content": "import { startClientDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/start/start.client\";\nimport { startServerDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/start/start.server\";\nimport {\n\ttype StartNode,\n\tstartSharedDefinition,\n} from \"@/registry/blocks/workflow-01/lib/workflow/nodes/start/start.shared\";\nimport type { NodeDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const startNodeDefinition: NodeDefinition<StartNode> = {\n\tshared: startSharedDefinition,\n\tclient: startClientDefinition,\n\tserver: startServerDefinition,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/start/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/end/end.shared.ts",
			"content": "import type { Node } from \"@xyflow/react\";\nimport { z } from \"zod\";\nimport type {\n\tNodeSharedDefinition,\n\tValidationContext,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const endNodeDataSchema = z.object({\n\tstatus: z.enum([\"processing\", \"error\", \"success\", \"idle\"]).optional(),\n\tvalidationErrors: z.array(z.any()).optional(),\n});\n\nexport type EndNodeData = z.infer<typeof endNodeDataSchema>;\nexport type EndNode = Node<EndNodeData, \"end\">;\n\n/**\n * Validates end node connection constraints: no outgoing edges allowed.\n */\nfunction validateEndNode(\n\tnode: EndNode,\n\tcontext: ValidationContext,\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst { edges } = context;\n\n\tconst outgoingEdges = edges.filter((e) => e.source === node.id);\n\tif (outgoingEdges.length > 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"End node cannot have outgoing connections\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nexport const endSharedDefinition: NodeSharedDefinition<EndNode> = {\n\ttype: \"end\",\n\tdataSchema: endNodeDataSchema,\n\tvalidate: validateEndNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/end/end.shared.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/end/end.client.tsx",
			"content": "\"use client\";\n\nimport { type NodeProps, Position } from \"@xyflow/react\";\nimport { Square, Trash } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { cn } from \"@/lib/utils\";\nimport { BaseHandle } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-handle\";\nimport { BaseNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-node\";\nimport {\n\tNodeHeader,\n\tNodeHeaderAction,\n\tNodeHeaderActions,\n\tNodeHeaderIcon,\n\tNodeHeaderStatus,\n\tNodeHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/workflow/primitives/node-header\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport type { EndNode as EndNodeType } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/end/end.shared\";\nimport type { NodeClientDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport interface EndNodeProps extends NodeProps<EndNodeType> {}\n\nexport function EndNode({ selected, data, deletable, id }: EndNodeProps) {\n\tconst deleteNode = useWorkflow((state) => state.deleteNode);\n\tconst canConnectHandle = useWorkflow((store) => store.canConnectHandle);\n\n\tconst validationErrors =\n\t\tdata.validationErrors?.map((error) => ({\n\t\t\tmessage: error.message,\n\t\t})) || [];\n\n\tconst isTargetConnectable = canConnectHandle({\n\t\tnodeId: id,\n\t\thandleId: \"input\",\n\t\ttype: \"target\",\n\t});\n\n\treturn (\n\t\t<BaseNode\n\t\t\tselected={selected}\n\t\t\tclassName={cn(\"flex flex-col p-2\", {\n\t\t\t\t\"border-orange-500\": data.status === \"processing\",\n\t\t\t\t\"border-red-500\": data.status === \"error\",\n\t\t\t})}\n\t\t>\n\t\t\t<NodeHeader className=\"m-0\">\n\t\t\t\t<NodeHeaderIcon>\n\t\t\t\t\t<Square />\n\t\t\t\t</NodeHeaderIcon>\n\t\t\t\t<NodeHeaderTitle>End</NodeHeaderTitle>\n\t\t\t\t<NodeHeaderActions>\n\t\t\t\t\t<NodeHeaderStatus\n\t\t\t\t\t\tstatus={data.status}\n\t\t\t\t\t\terrors={validationErrors}\n\t\t\t\t\t/>\n\t\t\t\t\t{deletable && (\n\t\t\t\t\t\t<NodeHeaderAction\n\t\t\t\t\t\t\tonClick={() => deleteNode(id)}\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tlabel=\"Delete node\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash />\n\t\t\t\t\t\t</NodeHeaderAction>\n\t\t\t\t\t)}\n\t\t\t\t</NodeHeaderActions>\n\t\t\t</NodeHeader>\n\n\t\t\t<BaseHandle\n\t\t\t\tid=\"input\"\n\t\t\t\ttype=\"target\"\n\t\t\t\tposition={Position.Left}\n\t\t\t\tisConnectable={isTargetConnectable}\n\t\t\t/>\n\t\t</BaseNode>\n\t);\n}\n\nexport function EndNodePanel({ node: _node }: { node: EndNodeType }) {\n\treturn (\n\t\t<div className=\"space-y-4\">\n\t\t\t<div>\n\t\t\t\t<h4 className=\"font-medium text-sm mb-2\">End Node</h4>\n\t\t\t\t<p className=\"text-xs text-gray-600\">\n\t\t\t\t\tThis node terminates the workflow execution.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function createEndNode(position: { x: number; y: number }): EndNodeType {\n\treturn {\n\t\tid: nanoid(),\n\t\ttype: \"end\",\n\t\tposition,\n\t\tdata: {},\n\t};\n}\n\nexport const endClientDefinition: NodeClientDefinition<EndNodeType> = {\n\tcomponent: EndNode,\n\tpanelComponent: EndNodePanel,\n\tcreate: createEndNode,\n\tmeta: {\n\t\tlabel: \"End\",\n\t\ticon: Square,\n\t\tdescription: \"Terminates the workflow execution\",\n\t},\n};\n",
			"type": "registry:component",
			"target": "lib/workflow/nodes/end/end.client.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/end/end.server.ts",
			"content": "import type { EndNode } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/end/end.shared\";\nimport type {\n\tExecutionContext,\n\tNodeExecutionResult,\n\tNodeServerDefinition,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nfunction executeEndNode(\n\tcontext: ExecutionContext<EndNode>,\n): NodeExecutionResult {\n\tconst { node, writer } = context;\n\n\tconst result = {\n\t\ttext: \"end\",\n\t};\n\n\twriter.write({\n\t\ttype: \"data-node-execution-state\",\n\t\tid: node.id,\n\t\tdata: {\n\t\t\tnodeId: node.id,\n\t\t\tnodeType: node.type,\n\t\t\tdata: node.data,\n\t\t},\n\t});\n\n\twriter.write({\n\t\ttype: \"finish\",\n\t});\n\n\treturn { result, nextNodeId: null };\n}\n\nexport const endServerDefinition: NodeServerDefinition<EndNode> = {\n\texecute: executeEndNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/end/end.server.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/end/index.ts",
			"content": "import { endClientDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/end/end.client\";\nimport { endServerDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/end/end.server\";\nimport {\n\ttype EndNode,\n\tendSharedDefinition,\n} from \"@/registry/blocks/workflow-01/lib/workflow/nodes/end/end.shared\";\nimport type { NodeDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const endNodeDefinition: NodeDefinition<EndNode> = {\n\tshared: endSharedDefinition,\n\tclient: endClientDefinition,\n\tserver: endServerDefinition,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/end/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/note/note.shared.ts",
			"content": "import type { Node } from \"@xyflow/react\";\nimport { z } from \"zod\";\nimport type {\n\tNodeSharedDefinition,\n\tValidationContext,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const noteNodeDataSchema = z.object({\n\tcontent: z.string(),\n});\n\nexport type NoteNodeData = z.infer<typeof noteNodeDataSchema>;\nexport type NoteNode = Node<NoteNodeData, \"note\">;\n\nfunction validateNoteNode(\n\t_node: NoteNode,\n\t_context: ValidationContext,\n): ValidationError[] {\n\treturn [];\n}\n\nexport const noteSharedDefinition: NodeSharedDefinition<NoteNode> = {\n\ttype: \"note\",\n\tdataSchema: noteNodeDataSchema,\n\tvalidate: validateNoteNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/note/note.shared.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/note/note.client.tsx",
			"content": "\"use client\";\n\nimport type { NodeProps } from \"@xyflow/react\";\nimport { FileText } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { cn } from \"@/lib/utils\";\nimport { ResizableNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/resizable-node\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport type { NoteNode as NoteNodeType } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/note/note.shared\";\nimport type { NodeClientDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport interface NoteNodeProps extends NodeProps<NoteNodeType> {}\n\nexport function NoteNode({ id, selected, data }: NoteNodeProps) {\n\tconst updateNode = useWorkflow((store) => store.updateNode);\n\n\tconst handleContentChange = (content: string) => {\n\t\tupdateNode({\n\t\t\tid,\n\t\t\tnodeType: \"note\",\n\t\t\tdata: { content },\n\t\t});\n\t};\n\n\treturn (\n\t\t<ResizableNode selected={selected} className=\"p-4\">\n\t\t\t<Textarea\n\t\t\t\tvalue={data.content}\n\t\t\t\tonChange={(e) => handleContentChange(e.target.value)}\n\t\t\t\tplaceholder=\"Enter your note here...\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"h-full w-full resize-none border-none bg-transparent dark:bg-transparent focus-visible:ring-0 p-0 shadow-none\",\n\t\t\t\t\t\"placeholder:text-muted-foreground/50 text-sm\",\n\t\t\t\t\t\"nodrag nopan nowheel cursor-auto\",\n\t\t\t\t)}\n\t\t\t/>\n\t\t</ResizableNode>\n\t);\n}\n\nexport function NoteNodePanel() {\n\treturn null;\n}\n\nexport function createNoteNode(position: {\n\tx: number;\n\ty: number;\n}): NoteNodeType {\n\treturn {\n\t\tid: nanoid(),\n\t\ttype: \"note\",\n\t\tposition,\n\t\tdata: {\n\t\t\tcontent: \"\",\n\t\t},\n\t};\n}\n\nexport const noteClientDefinition: NodeClientDefinition<NoteNodeType> = {\n\tcomponent: NoteNode,\n\tpanelComponent: NoteNodePanel,\n\tcreate: createNoteNode,\n\tmeta: {\n\t\tlabel: \"Note\",\n\t\ticon: FileText,\n\t\tdescription: \"A resizable text note\",\n\t},\n};\n",
			"type": "registry:component",
			"target": "lib/workflow/nodes/note/note.client.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/note/note.server.ts",
			"content": "import type { NoteNode } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/note/note.shared\";\nimport type {\n\tExecutionContext,\n\tNodeExecutionResult,\n\tNodeServerDefinition,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nfunction executeNoteNode(\n\t_context: ExecutionContext<NoteNode>,\n): NodeExecutionResult {\n\tthrow new Error(\"Note nodes should not be executed\");\n}\n\nexport const noteServerDefinition: NodeServerDefinition<NoteNode> = {\n\texecute: executeNoteNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/note/note.server.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/note/index.ts",
			"content": "import { noteClientDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/note/note.client\";\nimport { noteServerDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/note/note.server\";\nimport {\n\ttype NoteNode,\n\tnoteSharedDefinition,\n} from \"@/registry/blocks/workflow-01/lib/workflow/nodes/note/note.shared\";\nimport type { NodeDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const noteNodeDefinition: NodeDefinition<NoteNode> = {\n\tshared: noteSharedDefinition,\n\tclient: noteClientDefinition,\n\tserver: noteServerDefinition,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/note/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.shared.ts",
			"content": "import type { Node } from \"@xyflow/react\";\nimport { z } from \"zod\";\nimport type {\n\tNodeSharedDefinition,\n\tValidationContext,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const waitNodeDataSchema = z.object({\n\tstatus: z.enum([\"processing\", \"error\", \"success\", \"idle\"]).optional(),\n\tduration: z.number().min(1).max(3600), // 1 second to 1 hour\n\tunit: z.enum([\"seconds\", \"minutes\", \"hours\"]),\n\tvalidationErrors: z.array(z.any()).optional(),\n});\n\nexport type WaitNodeData = z.infer<typeof waitNodeDataSchema>;\nexport type WaitNode = Node<WaitNodeData, \"wait\">;\n\n/**\n * Validates wait node configuration and connection constraints.\n * Ensures duration is within allowed limits and node has exactly one incoming and one outgoing connection.\n */\nfunction validateWaitNode(\n\tnode: WaitNode,\n\tcontext: ValidationContext,\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst { edges } = context;\n\n\tconst { duration, unit } = node.data;\n\tif (duration) {\n\t\tlet maxDuration: number;\n\t\tswitch (unit) {\n\t\t\tcase \"seconds\":\n\t\t\t\tmaxDuration = 3600;\n\t\t\t\tbreak;\n\t\t\tcase \"minutes\":\n\t\t\t\tmaxDuration = 60;\n\t\t\t\tbreak;\n\t\t\tcase \"hours\":\n\t\t\t\tmaxDuration = 24;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (duration > maxDuration) {\n\t\t\terrors.push({\n\t\t\t\ttype: \"invalid-node-config\",\n\t\t\t\tseverity: \"error\",\n\t\t\t\tmessage: `Duration exceeds maximum for ${unit} (${maxDuration})`,\n\t\t\t\tnode: { id: node.id },\n\t\t\t});\n\t\t}\n\t}\n\n\tconst incomingEdges = edges.filter((e) => e.target === node.id);\n\tif (incomingEdges.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Wait node must have one incoming connection\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t} else if (incomingEdges.length > 1) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: `Wait node can only have one incoming connection (found ${incomingEdges.length})`,\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\tconst outgoingEdges = edges.filter((e) => e.source === node.id);\n\tif (outgoingEdges.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Wait node must have one outgoing connection\",\n\t\t\tnode: { id: node.id },\n\t\t});\n\t} else if (outgoingEdges.length > 1) {\n\t\terrors.push({\n\t\t\ttype: \"invalid-node-config\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: `Wait node can only have one outgoing connection (found ${outgoingEdges.length})`,\n\t\t\tnode: { id: node.id },\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nexport const waitSharedDefinition: NodeSharedDefinition<WaitNode> = {\n\ttype: \"wait\",\n\tdataSchema: waitNodeDataSchema,\n\tvalidate: validateWaitNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/wait/wait.shared.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.client.tsx",
			"content": "\"use client\";\n\nimport { type NodeProps, Position } from \"@xyflow/react\";\nimport { Clock, Trash } from \"lucide-react\";\nimport { nanoid } from \"nanoid\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\nimport { BaseHandle } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-handle\";\nimport { BaseNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-node\";\nimport {\n\tNodeHeader,\n\tNodeHeaderAction,\n\tNodeHeaderActions,\n\tNodeHeaderIcon,\n\tNodeHeaderStatus,\n\tNodeHeaderTitle,\n} from \"@/registry/blocks/workflow-01/components/workflow/primitives/node-header\";\nimport { useWorkflow } from \"@/registry/blocks/workflow-01/hooks/use-workflow\";\nimport type { WaitNode as WaitNodeType } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.shared\";\nimport type { NodeClientDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport interface WaitNodeProps extends NodeProps<WaitNodeType> {}\n\nexport function WaitNode({ selected, data, deletable, id }: WaitNodeProps) {\n\tconst deleteNode = useWorkflow((state) => state.deleteNode);\n\tconst canConnectHandle = useWorkflow((store) => store.canConnectHandle);\n\n\tconst validationErrors =\n\t\tdata.validationErrors?.map((error) => ({\n\t\t\tmessage: error.message,\n\t\t})) || [];\n\n\tconst isSourceConnectable = canConnectHandle({\n\t\tnodeId: id,\n\t\thandleId: \"output\",\n\t\ttype: \"source\",\n\t});\n\tconst isTargetConnectable = canConnectHandle({\n\t\tnodeId: id,\n\t\thandleId: \"input\",\n\t\ttype: \"target\",\n\t});\n\n\treturn (\n\t\t<BaseNode\n\t\t\tselected={selected}\n\t\t\tclassName={cn(\"flex flex-col p-0\", {\n\t\t\t\t\"border-orange-500\": data.status === \"processing\",\n\t\t\t\t\"border-red-500\": data.status === \"error\",\n\t\t\t})}\n\t\t>\n\t\t\t<NodeHeader className=\"m-0\">\n\t\t\t\t<NodeHeaderIcon>\n\t\t\t\t\t<Clock />\n\t\t\t\t</NodeHeaderIcon>\n\t\t\t\t<NodeHeaderTitle>Wait</NodeHeaderTitle>\n\t\t\t\t<NodeHeaderActions>\n\t\t\t\t\t<NodeHeaderStatus\n\t\t\t\t\t\tstatus={data.status}\n\t\t\t\t\t\terrors={validationErrors}\n\t\t\t\t\t/>\n\t\t\t\t\t{deletable && (\n\t\t\t\t\t\t<NodeHeaderAction\n\t\t\t\t\t\t\tonClick={() => deleteNode(id)}\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tlabel=\"Delete node\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Trash />\n\t\t\t\t\t\t</NodeHeaderAction>\n\t\t\t\t\t)}\n\t\t\t\t</NodeHeaderActions>\n\t\t\t</NodeHeader>\n\t\t\t<div className=\"text-left text text-muted-foreground p-2 pl-4 pt-0 max-w-[200px] truncate\">\n\t\t\t\t{data.duration} {data.unit}\n\t\t\t</div>\n\n\t\t\t<BaseHandle\n\t\t\t\tid=\"input\"\n\t\t\t\ttype=\"target\"\n\t\t\t\tposition={Position.Left}\n\t\t\t\tisConnectable={isTargetConnectable}\n\t\t\t/>\n\n\t\t\t<BaseHandle\n\t\t\t\tid=\"output\"\n\t\t\t\ttype=\"source\"\n\t\t\t\tposition={Position.Right}\n\t\t\t\tisConnectable={isSourceConnectable}\n\t\t\t/>\n\t\t</BaseNode>\n\t);\n}\n\nexport function WaitNodePanel({ node }: { node: WaitNodeType }) {\n\tconst updateNode = useWorkflow((state) => state.updateNode);\n\n\treturn (\n\t\t<div className=\"space-y-4\">\n\t\t\t<div>\n\t\t\t\t<h4 className=\"font-medium text-sm mb-2\">Configuration</h4>\n\t\t\t\t<div className=\"space-y-3\">\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label\n\t\t\t\t\t\t\thtmlFor={`duration-${node.id}`}\n\t\t\t\t\t\t\tclassName=\"block text-xs font-medium mb-1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tDuration\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\tid={`duration-${node.id}`}\n\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\tmin=\"1\"\n\t\t\t\t\t\t\tmax={\n\t\t\t\t\t\t\t\tnode.data.unit === \"hours\"\n\t\t\t\t\t\t\t\t\t? \"24\"\n\t\t\t\t\t\t\t\t\t: node.data.unit === \"minutes\"\n\t\t\t\t\t\t\t\t\t\t? \"60\"\n\t\t\t\t\t\t\t\t\t\t: \"3600\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tvalue={node.data.duration}\n\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\tconst value = Number.parseInt(\n\t\t\t\t\t\t\t\t\te.target.value,\n\t\t\t\t\t\t\t\t\t10,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (!Number.isNaN(value) && value >= 1) {\n\t\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\t\tnodeType: \"wait\",\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\tduration: value,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tplaceholder=\"Enter duration...\"\n\t\t\t\t\t\t\tclassName=\"text-xs\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<label\n\t\t\t\t\t\t\thtmlFor={`unit-${node.id}`}\n\t\t\t\t\t\t\tclassName=\"block text-xs font-medium mb-1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tUnit\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\tvalue={node.data.unit}\n\t\t\t\t\t\t\tonValueChange={(\n\t\t\t\t\t\t\t\tvalue: \"seconds\" | \"minutes\" | \"hours\",\n\t\t\t\t\t\t\t) => {\n\t\t\t\t\t\t\t\tupdateNode({\n\t\t\t\t\t\t\t\t\tid: node.id,\n\t\t\t\t\t\t\t\t\tnodeType: \"wait\",\n\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\tunit: value,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<SelectTrigger className=\"w-full\">\n\t\t\t\t\t\t\t\t<SelectValue placeholder=\"Select unit\" />\n\t\t\t\t\t\t\t</SelectTrigger>\n\t\t\t\t\t\t\t<SelectContent>\n\t\t\t\t\t\t\t\t<SelectItem value=\"seconds\">Seconds</SelectItem>\n\t\t\t\t\t\t\t\t<SelectItem value=\"minutes\">Minutes</SelectItem>\n\t\t\t\t\t\t\t\t<SelectItem value=\"hours\">Hours</SelectItem>\n\t\t\t\t\t\t\t</SelectContent>\n\t\t\t\t\t\t</Select>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h4 className=\"font-medium text-sm mb-2\">Description</h4>\n\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\tThe wait node pauses workflow execution for the specified\n\t\t\t\t\tduration before passing data to the next node.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function createWaitNode(position: {\n\tx: number;\n\ty: number;\n}): WaitNodeType {\n\treturn {\n\t\tid: nanoid(),\n\t\ttype: \"wait\",\n\t\tposition,\n\t\tdata: {\n\t\t\tstatus: \"idle\",\n\t\t\tduration: 5,\n\t\t\tunit: \"seconds\",\n\t\t},\n\t};\n}\n\nexport const waitClientDefinition: NodeClientDefinition<WaitNodeType> = {\n\tcomponent: WaitNode,\n\tpanelComponent: WaitNodePanel,\n\tcreate: createWaitNode,\n\tmeta: {\n\t\tlabel: \"Wait\",\n\t\ticon: Clock,\n\t\tdescription: \"Pause workflow execution for a specified duration\",\n\t},\n};\n",
			"type": "registry:component",
			"target": "lib/workflow/nodes/wait/wait.client.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.server.ts",
			"content": "import type { WaitNode } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.shared\";\nimport type {\n\tExecutionContext,\n\tNodeExecutionResult,\n\tNodeServerDefinition,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nasync function executeWaitNode(\n\tcontext: ExecutionContext<WaitNode>,\n): Promise<NodeExecutionResult> {\n\tconst { node, edges, executionMemory, writer } = context;\n\n\t// Get the input data from the previous node\n\tconst previousResult = executionMemory[context.previousNodeId];\n\tconst inputText = previousResult?.text || \"\";\n\tconst inputStructured = previousResult?.structured;\n\n\t// Calculate delay in milliseconds\n\tconst { duration, unit } = node.data;\n\tlet delayMs: number;\n\tswitch (unit) {\n\t\tcase \"seconds\":\n\t\t\tdelayMs = duration * 1000;\n\t\t\tbreak;\n\t\tcase \"minutes\":\n\t\t\tdelayMs = duration * 60 * 1000;\n\t\t\tbreak;\n\t\tcase \"hours\":\n\t\t\tdelayMs = duration * 60 * 60 * 1000;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tdelayMs = duration * 1000; // fallback to seconds\n\t}\n\n\t// Send initial status update\n\twriter.write({\n\t\ttype: \"data-node-execution-state\",\n\t\tid: node.id,\n\t\tdata: {\n\t\t\tnodeId: node.id,\n\t\t\tnodeType: node.type,\n\t\t\tdata: {\n\t\t\t\t...node.data,\n\t\t\t\tstatus: \"processing\",\n\t\t\t},\n\t\t},\n\t});\n\n\t// Wait for the specified duration\n\tawait new Promise((resolve) => setTimeout(resolve, delayMs));\n\n\t// Send completion status update\n\twriter.write({\n\t\ttype: \"data-node-execution-state\",\n\t\tid: node.id,\n\t\tdata: {\n\t\t\tnodeId: node.id,\n\t\t\tnodeType: node.type,\n\t\t\tdata: {\n\t\t\t\t...node.data,\n\t\t\t\tstatus: \"success\",\n\t\t\t},\n\t\t},\n\t});\n\n\tconst outgoingEdge = edges.find((edge) => edge.source === node.id);\n\tconst nextNodeId = outgoingEdge ? outgoingEdge.target : null;\n\n\treturn {\n\t\tresult: {\n\t\t\ttext: inputText, // Pass through the input data unchanged\n\t\t\tstructured: inputStructured,\n\t\t},\n\t\tnextNodeId,\n\t};\n}\n\nexport const waitServerDefinition: NodeServerDefinition<WaitNode> = {\n\texecute: executeWaitNode,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/wait/wait.server.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/nodes/wait/index.ts",
			"content": "import { waitClientDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.client\";\nimport { waitServerDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.server\";\nimport {\n\ttype WaitNode,\n\twaitSharedDefinition,\n} from \"@/registry/blocks/workflow-01/lib/workflow/nodes/wait/wait.shared\";\nimport type { NodeDefinition } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const waitNodeDefinition: NodeDefinition<WaitNode> = {\n\tshared: waitSharedDefinition,\n\tclient: waitClientDefinition,\n\tserver: waitServerDefinition,\n};\n",
			"type": "registry:lib",
			"target": "lib/workflow/nodes/wait/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/workflow/primitives/base-handle.tsx",
			"content": "import { Handle } from \"@xyflow/react\";\nimport type { ComponentProps } from \"react\";\n\nexport function BaseHandle({ ...props }: ComponentProps<typeof Handle>) {\n\treturn <Handle {...props} />;\n}\n",
			"type": "registry:component",
			"target": "components/workflow/primitives/base-handle.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/workflow/primitives/base-node.tsx",
			"content": "import type { ComponentProps } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport function BaseNode({\n\tclassName,\n\tselected,\n\t...props\n}: ComponentProps<\"div\"> & { selected?: boolean }) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"relative rounded-md border bg-card p-5 text-card-foreground\",\n\t\t\t\tclassName,\n\t\t\t\tselected ? \"border-muted-foreground shadow-lg\" : \"\",\n\t\t\t\t\"hover:ring-1\",\n\t\t\t)}\n\t\t\t// biome-ignore lint/a11y/noNoninteractiveTabindex: Needed\n\t\t\ttabIndex={0}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/workflow/primitives/base-node.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/workflow/primitives/labeled-handle.tsx",
			"content": "\"use client\";\n\nimport type { HandleProps } from \"@xyflow/react\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { BaseHandle } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-handle\";\n\nconst flexDirections = {\n\ttop: \"flex-col\",\n\tright: \"flex-row-reverse justify-end\",\n\tbottom: \"flex-col-reverse justify-end\",\n\tleft: \"flex-row\",\n};\n\nexport function LabeledHandle({\n\tposition,\n\tclassName,\n\thandleClassName,\n\tlabelClassName,\n\ttitle,\n\t...props\n}: ComponentProps<\"div\"> &\n\tHandleProps & {\n\t\tposition: ComponentProps<typeof BaseHandle>[\"position\"];\n\t\thandleClassName?: string;\n\t\tlabelClassName?: string;\n\t\ttitle: string;\n\t}) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex items-center\",\n\t\t\t\tflexDirections[position],\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<BaseHandle\n\t\t\t\tposition={position}\n\t\t\t\tclassName={handleClassName}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t\t{/* biome-ignore lint/a11y/noLabelWithoutControl: Needed */}\n\t\t\t<label className={cn(\"px-3 text-foreground\", labelClassName)}>\n\t\t\t\t{title}\n\t\t\t</label>\n\t\t</div>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/workflow/primitives/labeled-handle.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/workflow/primitives/node-header.tsx",
			"content": "import { Slot } from \"@radix-ui/react-slot\";\nimport { AlertCircle, EllipsisVertical } from \"lucide-react\";\nimport type { ComponentProps } from \"react\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n\tDropdownMenu,\n\tDropdownMenuContent,\n\tDropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\nexport function NodeHeader({\n\tclassName,\n\tchildren,\n\t...props\n}: ComponentProps<\"header\">) {\n\treturn (\n\t\t<header\n\t\t\t{...props}\n\t\t\tclassName={cn(\n\t\t\t\t\"mb-4 flex items-center justify-between gap-2 px-3 py-2\",\n\t\t\t\t\"-mx-5 -mt-5\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<TooltipProvider>{children}</TooltipProvider>\n\t\t</header>\n\t);\n}\n\nexport function NodeHeaderTitle({\n\tclassName,\n\tasChild,\n\t...props\n}: React.HTMLAttributes<HTMLHeadingElement> & { asChild?: boolean }) {\n\tconst Comp = asChild ? Slot : \"h3\";\n\n\treturn (\n\t\t<Comp\n\t\t\t{...props}\n\t\t\tclassName={cn(className, \"user-select-none flex-1 font-semibold\")}\n\t\t/>\n\t);\n}\n\nexport function NodeHeaderIcon({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn <span {...props} className={cn(className, \"*:size-5\")} />;\n}\n\nexport function NodeHeaderActions({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\t{...props}\n\t\t\tclassName={cn(\n\t\t\t\t\"ml-auto flex items-center gap-1 justify-self-end\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t/>\n\t);\n}\n\nexport function NodeHeaderAction({\n\tclassName,\n\tlabel,\n\ttitle,\n\t...props\n}: ComponentProps<typeof Button> & { label: string }) {\n\treturn (\n\t\t<Button\n\t\t\tvariant=\"ghost\"\n\t\t\taria-label={label}\n\t\t\ttitle={title ?? label}\n\t\t\tclassName={cn(className, \"nodrag size-6 p-1\")}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport function NodeHeaderMenuAction({\n\ttrigger,\n\tchildren,\n\t...props\n}: Omit<ComponentProps<typeof Button>, \"onClick\"> & {\n\tlabel: string;\n\ttrigger?: React.ReactNode;\n}) {\n\treturn (\n\t\t<DropdownMenu>\n\t\t\t<DropdownMenuTrigger asChild>\n\t\t\t\t<NodeHeaderAction {...props}>\n\t\t\t\t\t{trigger ?? <EllipsisVertical />}\n\t\t\t\t</NodeHeaderAction>\n\t\t\t</DropdownMenuTrigger>\n\t\t\t<DropdownMenuContent>{children}</DropdownMenuContent>\n\t\t</DropdownMenu>\n\t);\n}\n\nexport const NodeHeaderStatus = ({\n\tstatus,\n\terrors,\n}: {\n\tstatus?: \"idle\" | \"processing\" | \"success\" | \"error\";\n\terrors?: { message: string }[];\n}) => {\n\tconst hasErrors = errors && errors.length > 0;\n\n\tconst statusColors = {\n\t\tidle: \"bg-muted text-muted-foreground\",\n\t\tprocessing: \"bg-orange-500 text-white\",\n\t\tsuccess: \"bg-green-500 text-white\",\n\t\terror: \"bg-red-500 text-white\",\n\t\tvalidation: \"bg-red-600 text-white\",\n\t};\n\n\tif (hasErrors) {\n\t\treturn (\n\t\t\t<Tooltip>\n\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t<Badge\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"mr-2 font-normal flex items-center gap-1\",\n\t\t\t\t\t\t\tstatusColors.validation,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<AlertCircle className=\"w-3 h-3\" />\n\t\t\t\t\t\tError\n\t\t\t\t\t</Badge>\n\t\t\t\t</TooltipTrigger>\n\t\t\t\t<TooltipContent className=\"max-w-xs\">\n\t\t\t\t\t<div className=\"space-y-1\">\n\t\t\t\t\t\t{errors.map((error, idx) => (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={`error-${\n\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: Needed for error message\n\t\t\t\t\t\t\t\t\tidx\n\t\t\t\t\t\t\t\t}`}\n\t\t\t\t\t\t\t\tclassName=\"text-xs\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{error.message}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</TooltipContent>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Badge\n\t\t\tvariant=\"secondary\"\n\t\t\tclassName={cn(\"mr-2 font-normal\", status && statusColors[status])}\n\t\t>\n\t\t\t{status ? status : \"idle\"}\n\t\t</Badge>\n\t);\n};\n\nNodeHeaderStatus.displayName = \"NodeHeaderStatus\";\n",
			"type": "registry:component",
			"target": "components/workflow/primitives/node-header.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/workflow/primitives/resizable-node.tsx",
			"content": "import { NodeResizer } from \"@xyflow/react\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { BaseNode } from \"@/registry/blocks/workflow-01/components/workflow/primitives/base-node\";\n\nexport function ResizableNode({\n\tclassName,\n\tselected,\n\tstyle,\n\tchildren,\n\t...props\n}: ComponentProps<typeof BaseNode>) {\n\treturn (\n\t\t<BaseNode\n\t\t\tstyle={{\n\t\t\t\t...style,\n\t\t\t\tminHeight: 200,\n\t\t\t\tminWidth: 250,\n\t\t\t\tmaxHeight: 800,\n\t\t\t\tmaxWidth: 800,\n\t\t\t}}\n\t\t\tclassName={cn(\"h-full p-0 hover:ring-orange-500\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<NodeResizer isVisible={selected} />\n\t\t\t{children}\n\t\t</BaseNode>\n\t);\n}\n",
			"type": "registry:component",
			"target": "components/workflow/primitives/resizable-node.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/workflow/status-edge.tsx",
			"content": "import {\n\ttype Edge,\n\ttype EdgeProps,\n\tBaseEdge as FlowBaseEdge,\n\tgetBezierPath,\n} from \"@xyflow/react\";\nimport type { CSSProperties } from \"react\";\nimport type { ValidationError } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport type StatusEdgeData = {\n\texecution?: {\n\t\terror?: {\n\t\t\ttype: string;\n\t\t\tmessage: string;\n\t\t\t[key: string]: unknown;\n\t\t};\n\t};\n\tvalidationErrors?: ValidationError[];\n};\n\nexport type StatusEdge = Edge<StatusEdgeData, \"status\">;\n\nexport interface StatusEdgeProps extends EdgeProps<StatusEdge> {}\n\nexport function StatusEdge({\n\tsourceX,\n\tsourceY,\n\ttargetX,\n\ttargetY,\n\tsourcePosition,\n\ttargetPosition,\n\tdata,\n\tselected,\n}: StatusEdgeProps) {\n\tconst [edgePath] = getBezierPath({\n\t\tsourceX,\n\t\tsourceY,\n\t\tsourcePosition,\n\t\ttargetX,\n\t\ttargetY,\n\t\ttargetPosition,\n\t});\n\n\tconst validationErrors = data?.validationErrors || [];\n\tconst hasValidationError = validationErrors.length > 0;\n\n\tconst getEdgeColor = () => {\n\t\tif (hasValidationError) {\n\t\t\treturn \"#ef4444\";\n\t\t}\n\t\t// Execution errors\n\t\tif (data?.execution?.error) {\n\t\t\treturn \"#f97316\";\n\t\t}\n\t\t// Selected state\n\t\tif (selected) {\n\t\t\treturn \"#3b82f6\";\n\t\t}\n\t\treturn \"#b1b1b7\";\n\t};\n\n\tconst edgeStyle: CSSProperties = {\n\t\tstroke: getEdgeColor(),\n\t\tstrokeWidth: hasValidationError ? 3 : selected ? 3 : 2,\n\t\tstrokeDasharray: hasValidationError ? \"5,5\" : \"0\",\n\t\ttransition: \"stroke 0.2s, stroke-width 0.2s, stroke-dasharray 0.2s\",\n\t};\n\n\treturn <FlowBaseEdge path={edgePath} style={edgeStyle} />;\n}\n",
			"type": "registry:component",
			"target": "components/workflow/status-edge.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/components/model-selector.tsx",
			"content": "import type { SelectProps } from \"@radix-ui/react-select\";\nimport type { ElementType, SVGProps } from \"react\";\nimport {\n\tSelect,\n\tSelectContent,\n\tSelectItem,\n\tSelectTrigger,\n\tSelectValue,\n} from \"@/components/ui/select\";\nimport {\n\tWORKFLOW_MODELS,\n\ttype workflowModelID,\n} from \"@/registry/blocks/workflow-01/lib/workflow/models\";\n\ninterface ModelSelectorProps extends SelectProps {\n\tvalue: workflowModelID;\n\tonChange: (value: workflowModelID) => void;\n\tdisabledModels?: workflowModelID[];\n}\n\nexport function ModelSelector({\n\tvalue,\n\tonChange,\n\tdisabledModels,\n\t...props\n}: ModelSelectorProps) {\n\treturn (\n\t\t<Select value={value} onValueChange={onChange} {...props}>\n\t\t\t<SelectTrigger className=\"w-full nodrag\">\n\t\t\t\t<SelectValue placeholder=\"Select model\" />\n\t\t\t</SelectTrigger>\n\t\t\t<SelectContent>\n\t\t\t\t{WORKFLOW_MODELS.map((model) => {\n\t\t\t\t\tconst Icon = ModelIcons[model];\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<SelectItem\n\t\t\t\t\t\t\tkey={model}\n\t\t\t\t\t\t\tvalue={model}\n\t\t\t\t\t\t\tdisabled={disabledModels?.includes(model)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t<Icon className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t<span>{model}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</SelectContent>\n\t\t</Select>\n\t);\n}\n\n// Icons obtained from https://svgl.app/\n\nexport const OpenAI = (props: SVGProps<SVGSVGElement>) => (\n\t<svg\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\twidth=\"1em\"\n\t\theight=\"1em\"\n\t\tpreserveAspectRatio=\"xMidYMid\"\n\t\tviewBox=\"0 0 256 260\"\n\t\t{...props}\n\t>\n\t\t<title>OpenAI</title>\n\t\t<path\n\t\t\tfill=\"currentColor\"\n\t\t\td=\"M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.247 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z\"\n\t\t/>\n\t</svg>\n);\n\nexport const Groq = (props: SVGProps<SVGSVGElement>) => (\n\t<svg\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\tviewBox=\"0 0 201 201\"\n\t\twidth=\"1em\"\n\t\theight=\"1em\"\n\t\t{...props}\n\t>\n\t\t<title>Groq</title>\n\t\t<path fill=\"#F54F35\" d=\"M0 0h201v201H0V0Z\" />\n\t\t<path\n\t\t\tfill=\"#FEFBFB\"\n\t\t\td=\"m128 49 1.895 1.52C136.336 56.288 140.602 64.49 142 73c.097 1.823.148 3.648.161 5.474l.03 3.247.012 3.482.017 3.613c.01 2.522.016 5.044.02 7.565.01 3.84.041 7.68.072 11.521.007 2.455.012 4.91.016 7.364l.038 3.457c-.033 11.717-3.373 21.83-11.475 30.547-4.552 4.23-9.148 7.372-14.891 9.73l-2.387 1.055c-9.275 3.355-20.3 2.397-29.379-1.13-5.016-2.38-9.156-5.17-13.234-8.925 3.678-4.526 7.41-8.394 12-12l3.063 2.375c5.572 3.958 11.135 5.211 17.937 4.625 6.96-1.384 12.455-4.502 17-10 4.174-6.784 4.59-12.222 4.531-20.094l.012-3.473c.003-2.414-.005-4.827-.022-7.241-.02-3.68 0-7.36.026-11.04-.003-2.353-.008-4.705-.016-7.058l.025-3.312c-.098-7.996-1.732-13.21-6.681-19.47-6.786-5.458-13.105-8.211-21.914-7.792-7.327 1.188-13.278 4.7-17.777 10.601C75.472 72.012 73.86 78.07 75 85c2.191 7.547 5.019 13.948 12 18 5.848 3.061 10.892 3.523 17.438 3.688l2.794.103c2.256.082 4.512.147 6.768.209v16c-16.682.673-29.615.654-42.852-10.848-8.28-8.296-13.338-19.55-13.71-31.277.394-9.87 3.93-17.894 9.562-25.875l1.688-2.563C84.698 35.563 110.05 34.436 128 49Z\"\n\t\t/>\n\t</svg>\n);\n\nconst ModelIcons: Record<workflowModelID, ElementType> = {\n\t\"gpt-5-mini\": OpenAI,\n};\n",
			"type": "registry:component",
			"target": "components/model-selector.tsx"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/templates/index.ts",
			"content": "import { CODE_ANALYSIS_TEMPLATE } from \"@/registry/blocks/workflow-01/lib/templates/code-analysis-workflow\";\nimport { CUSTOMER_SUPPORT_TEMPLATE } from \"@/registry/blocks/workflow-01/lib/templates/customer-support-workflow\";\nimport { WAIT_DEMO_TEMPLATE } from \"@/registry/blocks/workflow-01/lib/templates/wait-demo-workflow\";\nimport { WIKIPEDIA_RESEARCH_TEMPLATE } from \"@/registry/blocks/workflow-01/lib/templates/wikipedia-research-workflow\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport type WorkflowTemplate = {\n\tid: string;\n\tname: string;\n\tdescription: string;\n\tcategory: string;\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n\tsuggestions: string[];\n};\n\nexport const WORKFLOW_TEMPLATES: WorkflowTemplate[] = [\n\tCODE_ANALYSIS_TEMPLATE,\n\tWIKIPEDIA_RESEARCH_TEMPLATE,\n\tCUSTOMER_SUPPORT_TEMPLATE,\n\tWAIT_DEMO_TEMPLATE,\n];\n\nexport function getTemplateById(id: string): WorkflowTemplate | undefined {\n\treturn WORKFLOW_TEMPLATES.find((template) => template.id === id);\n}\n\nexport const DEFAULT_TEMPLATE = WORKFLOW_TEMPLATES[0];\n",
			"type": "registry:lib",
			"target": "lib/templates/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/templates/code-analysis-workflow.ts",
			"content": "import { WORKFLOW_MODELS } from \"@/registry/blocks/workflow-01/lib/workflow/models\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const CODE_ANALYSIS_WORKFLOW: { nodes: FlowNode[]; edges: FlowEdge[] } =\n\t{\n\t\tnodes: [\n\t\t\t{\n\t\t\t\tid: \"start-node\",\n\t\t\t\ttype: \"start\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: 0,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 163,\n\t\t\t\t\theight: 58,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"code-analyzer-node\",\n\t\t\t\ttype: \"agent\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 215.16311438267223,\n\t\t\t\t\ty: -0.9015840544455784,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tname: \"Code Analyzer\",\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\thideResponseInChat: false,\n\t\t\t\t\texcludeFromConversation: true,\n\t\t\t\t\tmaxSteps: 5,\n\t\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t'You are a code analysis expert. Analyze the provided code snippet and determine its programming language and key characteristics.\\n\\nReturn a structured analysis with:\\n- language: The primary programming language (e.g., \"typescript\", \"python\", \"javascript\", \"java\", \"csharp\", \"cpp\", \"go\", \"rust\", \"php\", \"ruby\", \"swift\", \"kotlin\")\\n- framework: Any specific framework or library used (if detectable)\\n- complexity: \"simple\", \"medium\", or \"complex\"\\n- has_errors: boolean indicating if there are obvious syntax/logic errors\\n\\nFocus on accurate language detection and provide concise, structured output.',\n\t\t\t\t\tselectedTools: [],\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"structured\",\n\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\tlanguage: {\n\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\"The programming language of the code\",\n\t\t\t\t\t\t\t\t\tenum: [\n\t\t\t\t\t\t\t\t\t\t\"typescript\",\n\t\t\t\t\t\t\t\t\t\t\"javascript\",\n\t\t\t\t\t\t\t\t\t\t\"python\",\n\t\t\t\t\t\t\t\t\t\t\"java\",\n\t\t\t\t\t\t\t\t\t\t\"csharp\",\n\t\t\t\t\t\t\t\t\t\t\"cpp\",\n\t\t\t\t\t\t\t\t\t\t\"go\",\n\t\t\t\t\t\t\t\t\t\t\"rust\",\n\t\t\t\t\t\t\t\t\t\t\"php\",\n\t\t\t\t\t\t\t\t\t\t\"ruby\",\n\t\t\t\t\t\t\t\t\t\t\"swift\",\n\t\t\t\t\t\t\t\t\t\t\"kotlin\",\n\t\t\t\t\t\t\t\t\t\t\"other\",\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tframework: {\n\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\"Framework or library used (if any)\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tcomplexity: {\n\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\tdescription: \"Code complexity level\",\n\t\t\t\t\t\t\t\t\tenum: [\"simple\", \"medium\", \"complex\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\thas_errors: {\n\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\"Whether the code has obvious errors\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\trequired: [\"language\", \"complexity\", \"has_errors\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 182,\n\t\t\t\t\theight: 74,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"language-router-node\",\n\t\t\t\ttype: \"if-else\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 472.28701112265446,\n\t\t\t\t\ty: -72.76601002155019,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\tdynamicSourceHandles: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"output-typescript\",\n\t\t\t\t\t\t\tlabel: \"TypeScript\",\n\t\t\t\t\t\t\tcondition: \"input.language == 'typescript'\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"output-python\",\n\t\t\t\t\t\t\tlabel: \"Python\",\n\t\t\t\t\t\t\tcondition: \"input.language == 'python'\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"output-javascript\",\n\t\t\t\t\t\t\tlabel: \"JavaScript\",\n\t\t\t\t\t\t\tcondition: \"input.language == 'javascript'\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"output-java\",\n\t\t\t\t\t\t\tlabel: \"Java\",\n\t\t\t\t\t\t\tcondition: \"input.language == 'java'\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 189,\n\t\t\t\t\theight: 199,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"typescript-specialist-node\",\n\t\t\t\ttype: \"agent\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 754.0612102200728,\n\t\t\t\t\ty: -98.53418215111799,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tname: \"TypeScript Specialist\",\n\t\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t\"You are a TypeScript expert. Analyze the provided TypeScript code and provide detailed feedback including:\\n\\n1. Code quality assessment\\n2. Type safety evaluation\\n3. Performance considerations\\n4. Best practices compliance\\n5. Suggested improvements\\n\\nBe thorough but concise in your analysis. Focus on TypeScript-specific patterns, type annotations, and modern TypeScript features.\\n\\nBe concise in your output or response.\",\n\t\t\t\t\tselectedTools: [],\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t},\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\thideResponseInChat: false,\n\t\t\t\t\texcludeFromConversation: false,\n\t\t\t\t\tmaxSteps: 5,\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 182,\n\t\t\t\t\theight: 74,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"python-specialist-node\",\n\t\t\t\ttype: \"agent\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 751.2006079269053,\n\t\t\t\t\ty: -0.9982988964702351,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tname: \"Python Specialist\",\n\t\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t\"You are a Python expert. Analyze the provided Python code and provide detailed feedback including:\\n\\n1. Code quality assessment (PEP 8 compliance, readability)\\n2. Performance considerations\\n3. Pythonic patterns and best practices\\n4. Error handling and edge cases\\n5. Suggested improvements\\n\\nFocus on Python-specific idioms, efficient data structures, and modern Python features.\\n\\nBe concise in your output or response.\",\n\t\t\t\t\tselectedTools: [],\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t},\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\thideResponseInChat: false,\n\t\t\t\t\texcludeFromConversation: false,\n\t\t\t\t\tmaxSteps: 5,\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 182,\n\t\t\t\t\theight: 74,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"javascript-specialist-node\",\n\t\t\t\ttype: \"agent\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 743.7281051008781,\n\t\t\t\t\ty: 95.00028418055776,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tname: \"JavaScript Specialist\",\n\t\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t\"You are a JavaScript expert. Analyze the provided JavaScript code and provide detailed feedback including:\\n\\n1. Code quality assessment\\n2. ES6+ features usage\\n3. Performance considerations\\n4. Browser compatibility\\n5. Security considerations\\n6. Suggested improvements\\n\\nFocus on modern JavaScript patterns, asynchronous programming, and best practices.\\n\\nBe concise in your output or response.\",\n\t\t\t\t\tselectedTools: [],\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t},\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\thideResponseInChat: false,\n\t\t\t\t\texcludeFromConversation: false,\n\t\t\t\t\tmaxSteps: 5,\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 182,\n\t\t\t\t\theight: 74,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"java-specialist-node\",\n\t\t\t\ttype: \"agent\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 739.1697040835362,\n\t\t\t\t\ty: 192.00117228002483,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tname: \"Java Specialist\",\n\t\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t\"You are a Java expert. Analyze the provided Java code and provide detailed feedback including:\\n\\n1. Code quality assessment\\n2. Object-oriented design patterns\\n3. Performance considerations\\n4. Memory management\\n5. Exception handling\\n6. Suggested improvements\\n\\nFocus on Java-specific patterns, JVM considerations, and enterprise Java best practices.\\n\\nBe concise in your output or response.\",\n\t\t\t\t\tselectedTools: [],\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t},\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\thideResponseInChat: false,\n\t\t\t\t\texcludeFromConversation: false,\n\t\t\t\t\tmaxSteps: 5,\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 182,\n\t\t\t\t\theight: 74,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"general-specialist-node\",\n\t\t\t\ttype: \"agent\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 740.5465057146021,\n\t\t\t\t\ty: 289.5370555346727,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tname: \"General Code Specialist\",\n\t\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\t\tsystemPrompt:\n\t\t\t\t\t\t\"You are a general programming expert. Analyze the provided code and provide feedback on:\\n\\n1. Overall code quality and structure\\n2. Algorithm efficiency\\n3. Error handling\\n4. Documentation and readability\\n5. General best practices\\n6. Suggested improvements\\n\\nProvide comprehensive analysis regardless of the programming language.\\n\\nBe concise in your output or response.\",\n\t\t\t\t\tselectedTools: [],\n\t\t\t\t\tsourceType: {\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t},\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t\thideResponseInChat: false,\n\t\t\t\t\texcludeFromConversation: false,\n\t\t\t\t\tmaxSteps: 5,\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 200,\n\t\t\t\t\theight: 74,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"end-node\",\n\t\t\t\ttype: \"end\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 1005.9595837857867,\n\t\t\t\t\ty: 82.61297108435885,\n\t\t\t\t},\n\t\t\t\tdata: {},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 181,\n\t\t\t\t\theight: 58,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"workflow-description-note\",\n\t\t\t\ttype: \"note\",\n\t\t\t\tposition: {\n\t\t\t\t\tx: 71.25415144237013,\n\t\t\t\t\ty: 163.5453637058922,\n\t\t\t\t},\n\t\t\t\tdata: {\n\t\t\t\t\tcontent:\n\t\t\t\t\t\t\"Code Analysis Workflow\\n\\nAnalyzes code → detects language → routes to specialized agents (TypeScript, Python, JavaScript, Java) → provides expert feedback.\\n\\nTry different code snippets to see intelligent routing in action!\",\n\t\t\t\t},\n\t\t\t\tmeasured: {\n\t\t\t\t\twidth: 534,\n\t\t\t\t\theight: 229,\n\t\t\t\t},\n\t\t\t\tselected: false,\n\t\t\t\tdragging: false,\n\t\t\t\twidth: 534,\n\t\t\t\theight: 229,\n\t\t\t\tresizing: false,\n\t\t\t},\n\t\t],\n\t\tedges: [\n\t\t\t{\n\t\t\t\tid: \"start-to-analyzer\",\n\t\t\t\tsource: \"start-node\",\n\t\t\t\ttarget: \"code-analyzer-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"analyzer-to-router\",\n\t\t\t\tsource: \"code-analyzer-node\",\n\t\t\t\ttarget: \"language-router-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"router-to-typescript\",\n\t\t\t\tsource: \"language-router-node\",\n\t\t\t\ttarget: \"typescript-specialist-node\",\n\t\t\t\tsourceHandle: \"output-typescript\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"router-to-python\",\n\t\t\t\tsource: \"language-router-node\",\n\t\t\t\ttarget: \"python-specialist-node\",\n\t\t\t\tsourceHandle: \"output-python\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"router-to-javascript\",\n\t\t\t\tsource: \"language-router-node\",\n\t\t\t\ttarget: \"javascript-specialist-node\",\n\t\t\t\tsourceHandle: \"output-javascript\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"router-to-java\",\n\t\t\t\tsource: \"language-router-node\",\n\t\t\t\ttarget: \"java-specialist-node\",\n\t\t\t\tsourceHandle: \"output-java\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"router-to-general\",\n\t\t\t\tsource: \"language-router-node\",\n\t\t\t\ttarget: \"general-specialist-node\",\n\t\t\t\tsourceHandle: \"output-else\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"typescript-to-end\",\n\t\t\t\tsource: \"typescript-specialist-node\",\n\t\t\t\ttarget: \"end-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"python-to-end\",\n\t\t\t\tsource: \"python-specialist-node\",\n\t\t\t\ttarget: \"end-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"javascript-to-end\",\n\t\t\t\tsource: \"javascript-specialist-node\",\n\t\t\t\ttarget: \"end-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"java-to-end\",\n\t\t\t\tsource: \"java-specialist-node\",\n\t\t\t\ttarget: \"end-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"general-to-end\",\n\t\t\t\tsource: \"general-specialist-node\",\n\t\t\t\ttarget: \"end-node\",\n\t\t\t\tsourceHandle: \"output\",\n\t\t\t\ttargetHandle: \"input\",\n\t\t\t\ttype: \"status\",\n\t\t\t\tdata: {},\n\t\t\t},\n\t\t],\n\t};\n\nexport const CODE_ANALYSIS_TEMPLATE = {\n\tid: \"code-analysis\",\n\tname: \"Code Agent\",\n\tdescription: \"Intelligent routing to language-specific code experts\",\n\tcategory: \"Development\",\n\tnodes: CODE_ANALYSIS_WORKFLOW.nodes,\n\tedges: CODE_ANALYSIS_WORKFLOW.edges,\n\tsuggestions: [\n\t\t\"Show me how to write a functional React component\",\n\t\t\"Explain how to create a Python function with error handling\",\n\t\t\"Teach me how to write an efficient SQL query\",\n\t],\n};\n",
			"type": "registry:lib",
			"target": "lib/templates/code-analysis-workflow.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/templates/wikipedia-research-workflow.ts",
			"content": "import { WORKFLOW_MODELS } from \"@/registry/blocks/workflow-01/lib/workflow/models\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const WIKIPEDIA_RESEARCH_WORKFLOW: {\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n} = {\n\tnodes: [\n\t\t{\n\t\t\tid: \"start-node\",\n\t\t\ttype: \"start\",\n\t\t\tposition: {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 163,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"wikipedia-researcher-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 217.03408510688456,\n\t\t\t\ty: -8.288046037379033,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Wikipedia Researcher\",\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t'You are a research assistant powered by Wikipedia. Use the wikipedia-query tool to gather comprehensive research data.\\n\\nYour process:\\n1. Use the \"search\" action to find the most relevant Wikipedia articles for the query\\n2. Use the \"summary\" action to retrieve detailed information from 2-4 key articles\\n3. Extract key facts, dates, people, events, and concepts\\n4. Return structured research data that will be used by another agent for summarization\\n\\nFocus on gathering raw data rather than writing responses. Be thorough in your research.',\n\t\t\t\tselectedTools: [\"wikipedia-query\"],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"structured\",\n\t\t\t\t\tschema: {\n\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\tquery: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tdescription: \"The original research query\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tarticles: {\n\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"List of researched articles with their content\",\n\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttitle: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Article title\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\turl: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Wikipedia article URL\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tsummary: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Key information extracted from the article\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tkey_facts: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Important facts, dates, or concepts\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"title\", \"summary\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmain_topics: {\n\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Main topics covered in the research\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\trelevance_score: {\n\t\t\t\t\t\t\t\ttype: \"number\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Overall relevance score (0-10) of the research to the query\",\n\t\t\t\t\t\t\t\tminimum: 0,\n\t\t\t\t\t\t\t\tmaximum: 10,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\trequired: [\"query\", \"articles\", \"main_topics\"],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 184,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"wikipedia-summarizer-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 487.7124662933777,\n\t\t\t\ty: -5.636883617543333,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Wikipedia Summarizer\",\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a content summarizer that takes structured research data from Wikipedia and creates comprehensive, well-written responses for users.\\n\\nYour process:\\n1. Analyze the structured research data provided\\n2. Synthesize information from multiple articles into a coherent narrative\\n3. Create engaging, well-structured content that answers the original query\\n4. Include relevant citations and source links\\n5. Be thorough but concise, avoiding unnecessary details\\n\\nFormat your response with:\\n- Clear introduction answering the main query\\n- Well-organized sections with descriptive headers\\n- Key facts, dates, and concepts highlighted appropriately\\n- Source citations with links\\n- Professional, informative tone\\n\\nBe concise in your output or response.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 3,\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 189,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"end-node\",\n\t\t\ttype: \"end\",\n\t\t\tposition: {\n\t\t\t\tx: 736.6595162137467,\n\t\t\t\ty: 2.0676419359424294,\n\t\t\t},\n\t\t\tdata: {},\n\t\t\tmeasured: {\n\t\t\t\twidth: 181,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"workflow-description-note\",\n\t\t\ttype: \"note\",\n\t\t\tposition: {\n\t\t\t\tx: 129.98312031522866,\n\t\t\t\ty: -273.7056292586109,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tcontent:\n\t\t\t\t\t\"**Wikipedia Researcher Agent**\\n\\nGathers structured research data from Wikipedia articles using the wikipedia-query tool. Extracts key facts, dates, and concepts for comprehensive research coverage.\",\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 311,\n\t\t\t\theight: 180,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\twidth: 311,\n\t\t\theight: 180,\n\t\t\tresizing: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"OUzYAixsWyDCNwgxEXSnK\",\n\t\t\ttype: \"note\",\n\t\t\tposition: {\n\t\t\t\tx: 514.3267057930115,\n\t\t\t\ty: -276.3323675246679,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tcontent:\n\t\t\t\t\t\"**Wikipedia Summarizer Agent**\\n\\nSynthesizes research data into engaging, well-structured responses with citations. Creates comprehensive narratives from multiple article sources.\",\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 285,\n\t\t\t\theight: 200,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t\twidth: 285,\n\t\t\theight: 200,\n\t\t\tresizing: false,\n\t\t},\n\t],\n\tedges: [\n\t\t{\n\t\t\tid: \"start-to-researcher\",\n\t\t\tsource: \"start-node\",\n\t\t\ttarget: \"wikipedia-researcher-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"researcher-to-summarizer\",\n\t\t\tsource: \"wikipedia-researcher-node\",\n\t\t\ttarget: \"wikipedia-summarizer-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"summarizer-to-end\",\n\t\t\tsource: \"wikipedia-summarizer-node\",\n\t\t\ttarget: \"end-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t],\n};\n\nexport const WIKIPEDIA_RESEARCH_TEMPLATE = {\n\tid: \"wikipedia-research\",\n\tname: \"Wikipedia Agent\",\n\tdescription:\n\t\t\"Comprehensive research workflow using Wikipedia search and summary tools\",\n\tcategory: \"Research\",\n\tnodes: WIKIPEDIA_RESEARCH_WORKFLOW.nodes,\n\tedges: WIKIPEDIA_RESEARCH_WORKFLOW.edges,\n\tsuggestions: [\n\t\t\"Research the history of artificial intelligence\",\n\t\t\"What are the key principles of quantum physics?\",\n\t\t\"Research the biography of Albert Einstein\",\n\t],\n};\n",
			"type": "registry:lib",
			"target": "lib/templates/wikipedia-research-workflow.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/templates/wait-demo-workflow.ts",
			"content": "import { WORKFLOW_MODELS } from \"@/registry/blocks/workflow-01/lib/workflow/models\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const WAIT_DEMO_WORKFLOW: { nodes: FlowNode[]; edges: FlowEdge[] } = {\n\tnodes: [\n\t\t{\n\t\t\tid: \"start-node\",\n\t\t\ttype: \"start\",\n\t\t\tposition: {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 163,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"initial-agent-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 215.16311438267223,\n\t\t\t\ty: -0.9015840544455784,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Task Initiator\",\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a task initiator. Generate a simple task that requires some processing time. For example: 'I need to process customer feedback data' or 'I need to analyze sales reports'. Keep it brief and clear.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 182,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"wait-node\",\n\t\t\ttype: \"wait\",\n\t\t\tposition: {\n\t\t\t\tx: 472.28701112265446,\n\t\t\t\ty: -0.9015840544455784,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tstatus: \"idle\",\n\t\t\t\tduration: 3,\n\t\t\t\tunit: \"seconds\",\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 182,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"processing-agent-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 729.4109078626367,\n\t\t\t\ty: -0.9015840544455784,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Task Processor\",\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a task processor. The previous agent initiated a task, and there was a brief wait (simulating processing time). Now complete the task with a detailed response. Provide a comprehensive and helpful result.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 182,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"end-node\",\n\t\t\ttype: \"end\",\n\t\t\tposition: {\n\t\t\t\tx: 986.534804602619,\n\t\t\t\ty: -0.9015840544455784,\n\t\t\t},\n\t\t\tdata: {},\n\t\t\tmeasured: {\n\t\t\t\twidth: 181,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"workflow-description-note\",\n\t\t\ttype: \"note\",\n\t\t\tposition: {\n\t\t\t\tx: 71.25415144237013,\n\t\t\t\ty: 163.5453637058922,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tcontent:\n\t\t\t\t\t\"Wait Node Demo\\n\\nThis workflow demonstrates the wait/delay node functionality:\\n\\n1. Task Initiator creates a task\\n2. Wait node pauses for 3 seconds (simulating processing)\\n3. Task Processor completes the work\\n\\nThe wait node allows you to:\\n- Add realistic delays to workflows\\n- Simulate processing time\\n- Control execution pacing\\n- Test timing-dependent logic\\n\\nTry adjusting the wait duration!\",\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 600,\n\t\t\t\theight: 250,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t\twidth: 600,\n\t\t\theight: 250,\n\t\t\tresizing: false,\n\t\t},\n\t],\n\tedges: [\n\t\t{\n\t\t\tid: \"start-to-initiator\",\n\t\t\tsource: \"start-node\",\n\t\t\ttarget: \"initial-agent-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"initiator-to-wait\",\n\t\t\tsource: \"initial-agent-node\",\n\t\t\ttarget: \"wait-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"wait-to-processor\",\n\t\t\tsource: \"wait-node\",\n\t\t\ttarget: \"processing-agent-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"processor-to-end\",\n\t\t\tsource: \"processing-agent-node\",\n\t\t\ttarget: \"end-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t],\n};\n\nexport const WAIT_DEMO_TEMPLATE = {\n\tid: \"wait-demo\",\n\tname: \"Wait Node Demo\",\n\tdescription:\n\t\t\"Demonstrates workflow timing control with delay functionality\",\n\tcategory: \"Examples\",\n\tnodes: WAIT_DEMO_WORKFLOW.nodes,\n\tedges: WAIT_DEMO_WORKFLOW.edges,\n\tsuggestions: [\n\t\t\"Process customer feedback with realistic delays\",\n\t\t\"Simulate data processing workflows\",\n\t\t\"Test timing-dependent business logic\",\n\t],\n};\n",
			"type": "registry:lib",
			"target": "lib/templates/wait-demo-workflow.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/templates/customer-support-workflow.ts",
			"content": "import { WORKFLOW_MODELS } from \"@/registry/blocks/workflow-01/lib/workflow/models\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport const CUSTOMER_SUPPORT_WORKFLOW: {\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n} = {\n\tnodes: [\n\t\t{\n\t\t\tid: \"start-node\",\n\t\t\ttype: \"start\",\n\t\t\tposition: {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 163,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"support-classifier-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 214.92718722537256,\n\t\t\t\ty: -6.754208598280512,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Support Classifier\",\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: true,\n\t\t\t\tmaxSteps: 5,\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t'You are a customer support classifier. Analyze the customer inquiry and categorize it appropriately.\\n\\nReturn a structured classification with:\\n- category: The type of issue (\"technical\", \"billing\", \"general\", \"urgent\")\\n- priority: Priority level (\"high\", \"medium\", \"low\")\\n- sentiment: Customer sentiment (\"positive\", \"neutral\", \"negative\")\\n- requires_escalation: boolean indicating if immediate escalation is needed\\n\\nBe accurate and empathetic in your analysis.',\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"structured\",\n\t\t\t\t\tschema: {\n\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\tcategory: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tdescription: \"Type of support issue\",\n\t\t\t\t\t\t\t\tenum: [\n\t\t\t\t\t\t\t\t\t\"technical\",\n\t\t\t\t\t\t\t\t\t\"billing\",\n\t\t\t\t\t\t\t\t\t\"general\",\n\t\t\t\t\t\t\t\t\t\"urgent\",\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpriority: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tdescription: \"Priority level\",\n\t\t\t\t\t\t\t\tenum: [\"high\", \"medium\", \"low\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tsentiment: {\n\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\tdescription: \"Customer sentiment\",\n\t\t\t\t\t\t\t\tenum: [\"positive\", \"neutral\", \"negative\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\trequires_escalation: {\n\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Whether immediate escalation is needed\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\trequired: [\n\t\t\t\t\t\t\t\"category\",\n\t\t\t\t\t\t\t\"priority\",\n\t\t\t\t\t\t\t\"sentiment\",\n\t\t\t\t\t\t\t\"requires_escalation\",\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 182,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"priority-router-node\",\n\t\t\ttype: \"if-else\",\n\t\t\tposition: {\n\t\t\t\tx: 448.6297230272165,\n\t\t\t\ty: -133.98485130502783,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tstatus: \"idle\",\n\t\t\t\tdynamicSourceHandles: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"output-urgent\",\n\t\t\t\t\t\tlabel: \"Urgent\",\n\t\t\t\t\t\tcondition:\n\t\t\t\t\t\t\t\"input.category == 'urgent' || input.requires_escalation == true\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"output-technical\",\n\t\t\t\t\t\tlabel: \"Technical\",\n\t\t\t\t\t\tcondition: \"input.category == 'technical'\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"output-billing\",\n\t\t\t\t\t\tlabel: \"Billing\",\n\t\t\t\t\t\tcondition: \"input.category == 'billing'\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"output-general\",\n\t\t\t\t\t\tlabel: \"General\",\n\t\t\t\t\t\tcondition: \"input.category == 'general'\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 189,\n\t\t\t\theight: 227,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"urgent-support-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 691.3067678450559,\n\t\t\t\ty: -151.7958970383244,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Urgent Support Specialist\",\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a senior support specialist handling urgent customer issues. Your role is to:\\n\\n1. Acknowledge the urgency and customer's concern immediately\\n2. Provide quick, effective solutions or escalation paths\\n3. Maintain calm and professional communication\\n4. Offer immediate next steps and follow-up plan\\n5. Ensure customer feels heard and valued\\n\\nPriority is speed and effectiveness while maintaining quality support.\\n\\nBe concise in your output or response.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 202,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"technical-support-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 694.4691823666877,\n\t\t\t\ty: -64.58868164319044,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Technical Support Specialist\",\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a technical support specialist. Help customers with technical issues by:\\n\\n1. Understanding the technical problem clearly\\n2. Providing step-by-step troubleshooting guidance\\n3. Explaining technical concepts in simple terms\\n4. Offering multiple solution approaches\\n5. Including relevant documentation or resources\\n\\nBe patient, clear, and thorough in your technical guidance.\\n\\nBe concise in your output or response.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 202,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"billing-support-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 698.6857350621967,\n\t\t\t\ty: 25.780948273575284,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"Billing Support Specialist\",\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a billing and account support specialist. Handle billing inquiries by:\\n\\n1. Addressing billing concerns with empathy and clarity\\n2. Explaining charges, invoices, and payment processes\\n3. Providing refund or adjustment guidance when appropriate\\n4. Ensuring data security and privacy\\n5. Offering account management assistance\\n\\nBe transparent, accurate, and customer-focused in all billing matters.\\n\\nBe concise in your output or response.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 202,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"general-support-node\",\n\t\t\ttype: \"agent\",\n\t\t\tposition: {\n\t\t\t\tx: 704.8131893934153,\n\t\t\t\ty: 118.0232543912802,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tname: \"General Support Agent\",\n\t\t\t\tmodel: WORKFLOW_MODELS[0],\n\t\t\t\tsystemPrompt:\n\t\t\t\t\t\"You are a general support agent handling a variety of customer inquiries. Provide help by:\\n\\n1. Listening to customer needs and questions\\n2. Providing clear, helpful information\\n3. Guiding customers to relevant resources\\n4. Offering friendly, professional assistance\\n5. Creating positive customer experiences\\n\\nBe versatile, helpful, and maintain excellent customer service standards.\\n\\nBe concise in your output or response.\",\n\t\t\t\tselectedTools: [],\n\t\t\t\tsourceType: {\n\t\t\t\t\ttype: \"text\",\n\t\t\t\t},\n\t\t\t\tstatus: \"idle\",\n\t\t\t\thideResponseInChat: false,\n\t\t\t\texcludeFromConversation: false,\n\t\t\t\tmaxSteps: 5,\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 193,\n\t\t\t\theight: 74,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"end-node\",\n\t\t\ttype: \"end\",\n\t\t\tposition: {\n\t\t\t\tx: 981.0268121059296,\n\t\t\t\ty: -0.2478087398583213,\n\t\t\t},\n\t\t\tdata: {},\n\t\t\tmeasured: {\n\t\t\t\twidth: 181,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"else-end-node\",\n\t\t\ttype: \"end\",\n\t\t\tposition: {\n\t\t\t\tx: 711.0671595108819,\n\t\t\t\ty: 276.13101979922845,\n\t\t\t},\n\t\t\tdata: {},\n\t\t\tmeasured: {\n\t\t\t\twidth: 181,\n\t\t\t\theight: 58,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t},\n\t\t{\n\t\t\tid: \"workflow-description-note\",\n\t\t\ttype: \"note\",\n\t\t\tposition: {\n\t\t\t\tx: 40.50629062366556,\n\t\t\t\ty: 136.3769204357046,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tcontent:\n\t\t\t\t\t\"Customer Support Workflow\\n\\nIntelligent routing system:\\n1. Classifier analyzes and categorizes inquiries\\n2. Router directs to specialists (Urgent/Technical/Billing/General)\\n3. Else output routes unmatched inquiries to separate end block\\n\\nFeatures: Sentiment analysis, escalation detection, clear routing paths\\n\\nTest with different inquiry types!\",\n\t\t\t},\n\t\t\tmeasured: {\n\t\t\t\twidth: 558,\n\t\t\t\theight: 244,\n\t\t\t},\n\t\t\tselected: false,\n\t\t\tdragging: false,\n\t\t\twidth: 558,\n\t\t\theight: 244,\n\t\t\tresizing: false,\n\t\t},\n\t],\n\tedges: [\n\t\t{\n\t\t\tid: \"start-to-classifier\",\n\t\t\tsource: \"start-node\",\n\t\t\ttarget: \"support-classifier-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"classifier-to-router\",\n\t\t\tsource: \"support-classifier-node\",\n\t\t\ttarget: \"priority-router-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"router-to-urgent\",\n\t\t\tsource: \"priority-router-node\",\n\t\t\ttarget: \"urgent-support-node\",\n\t\t\tsourceHandle: \"output-urgent\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"router-to-technical\",\n\t\t\tsource: \"priority-router-node\",\n\t\t\ttarget: \"technical-support-node\",\n\t\t\tsourceHandle: \"output-technical\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"router-to-billing\",\n\t\t\tsource: \"priority-router-node\",\n\t\t\ttarget: \"billing-support-node\",\n\t\t\tsourceHandle: \"output-billing\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"router-to-general\",\n\t\t\tsource: \"priority-router-node\",\n\t\t\ttarget: \"general-support-node\",\n\t\t\tsourceHandle: \"output-general\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"urgent-to-end\",\n\t\t\tsource: \"urgent-support-node\",\n\t\t\ttarget: \"end-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t\tselected: false,\n\t\t},\n\t\t{\n\t\t\tid: \"technical-to-end\",\n\t\t\tsource: \"technical-support-node\",\n\t\t\ttarget: \"end-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"billing-to-end\",\n\t\t\tsource: \"billing-support-node\",\n\t\t\ttarget: \"end-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"general-to-end\",\n\t\t\tsource: \"general-support-node\",\n\t\t\ttarget: \"end-node\",\n\t\t\tsourceHandle: \"output\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t\t{\n\t\t\tid: \"router-to-else-end\",\n\t\t\tsource: \"priority-router-node\",\n\t\t\ttarget: \"else-end-node\",\n\t\t\tsourceHandle: \"output-else\",\n\t\t\ttargetHandle: \"input\",\n\t\t\ttype: \"status\",\n\t\t\tdata: {},\n\t\t},\n\t],\n};\n\nexport const CUSTOMER_SUPPORT_TEMPLATE = {\n\tid: \"customer-support\",\n\tname: \"Support Agent\",\n\tdescription: \"Intelligent customer support with priority-based routing\",\n\tcategory: \"Business\",\n\tnodes: CUSTOMER_SUPPORT_WORKFLOW.nodes,\n\tedges: CUSTOMER_SUPPORT_WORKFLOW.edges,\n\tsuggestions: [\n\t\t\"I can't log into my account, can you help?\",\n\t\t\"My billing statement shows incorrect charges\",\n\t\t\"The website is loading very slowly, what's wrong?\",\n\t],\n};\n",
			"type": "registry:lib",
			"target": "lib/templates/customer-support-workflow.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/tools/index.ts",
			"content": "import { wikipediaQueryTool } from \"@/registry/blocks/workflow-01/lib/tools/wikipedia-query\";\n\nexport const workflowTools = {\n\t\"wikipedia-query\": wikipediaQueryTool(),\n};\n\nexport const WORKFLOW_TOOLS = Object.keys(workflowTools) as WorkflowToolId[];\n\nexport type WorkflowToolId = keyof typeof workflowTools;\n",
			"type": "registry:lib",
			"target": "lib/tools/index.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/tools/wikipedia-query.ts",
			"content": "import { tool } from \"ai\";\nimport { z } from \"zod\";\n\nconst wikipediaQueryParamsSchema = z.object({\n\taction: z\n\t\t.enum([\"search\", \"summary\"])\n\t\t.describe(\n\t\t\t\"The action to perform: 'search' for finding articles, 'summary' for getting article content\",\n\t\t),\n\tquery: z.string().describe(\"The search query or article title to look up\"),\n\tlimit: z\n\t\t.number()\n\t\t.min(1)\n\t\t.max(10)\n\t\t.optional()\n\t\t.default(5)\n\t\t.describe(\"Maximum number of results to return (for search action)\"),\n});\n\nexport type WikipediaQueryParams = z.infer<typeof wikipediaQueryParamsSchema>;\n\nconst wikipediaQuerySearchResultSchema = z.object({\n\tsuccess: z.literal(true),\n\taction: z.literal(\"search\"),\n\tresults: z.array(\n\t\tz.object({\n\t\t\ttitle: z.string(),\n\t\t\tpageid: z.number(),\n\t\t\tsize: z.number().optional(),\n\t\t\twordcount: z.number().optional(),\n\t\t\tsnippet: z.string().optional(),\n\t\t\ttimestamp: z.string().optional(),\n\t\t}),\n\t),\n\ttotalResults: z.number(),\n});\n\nconst wikipediaQuerySummaryResultSchema = z.object({\n\tsuccess: z.literal(true),\n\taction: z.literal(\"summary\"),\n\ttitle: z.string(),\n\tpageid: z.number(),\n\textract: z.string(),\n\tdescription: z.string().optional(),\n\turl: z.string(),\n\tthumbnail: z\n\t\t.object({\n\t\t\tsource: z.string(),\n\t\t\twidth: z.number(),\n\t\t\theight: z.number(),\n\t\t})\n\t\t.optional(),\n});\n\nconst wikipediaQueryErrorResultSchema = z.object({\n\tsuccess: z.literal(false),\n\tmessage: z.string(),\n});\n\nconst wikipediaQueryResultSchema = z.union([\n\twikipediaQuerySearchResultSchema,\n\twikipediaQuerySummaryResultSchema,\n\twikipediaQueryErrorResultSchema,\n]);\n\nexport type WikipediaQueryResult = z.infer<typeof wikipediaQueryResultSchema>;\n\nexport const wikipediaQueryTool = () =>\n\ttool({\n\t\tdescription:\n\t\t\t\"Search Wikipedia articles or get summaries of specific articles. Use 'search' to find articles by topic, and 'summary' to get detailed information about a specific article.\",\n\t\tinputSchema: wikipediaQueryParamsSchema,\n\t\toutputSchema: wikipediaQueryResultSchema,\n\t\texecute: async ({\n\t\t\taction,\n\t\t\tquery,\n\t\t\tlimit,\n\t\t}): Promise<WikipediaQueryResult> => {\n\t\t\ttry {\n\t\t\t\tif (action === \"search\") {\n\t\t\t\t\tconst searchUrl = `https://en.wikipedia.org/w/api.php?action=opensearch&search=${encodeURIComponent(query)}&limit=${limit}&namespace=0&format=json`;\n\n\t\t\t\t\tconst response = await fetch(searchUrl);\n\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Wikipedia API error: ${response.status}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst data = await response.json();\n\t\t\t\t\tconst [, titles, descriptions] = data;\n\n\t\t\t\t\tconst results = titles.map(\n\t\t\t\t\t\t(title: string, index: number) => ({\n\t\t\t\t\t\t\ttitle,\n\t\t\t\t\t\t\tpageid: 0,\n\t\t\t\t\t\t\tsnippet: descriptions[index] || \"\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\taction: \"search\",\n\t\t\t\t\t\tresults,\n\t\t\t\t\t\ttotalResults: results.length,\n\t\t\t\t\t};\n\t\t\t\t} else if (action === \"summary\") {\n\t\t\t\t\tconst summaryUrl = `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(query.replace(/ /g, \"_\"))}`;\n\n\t\t\t\t\tconst response = await fetch(summaryUrl);\n\n\t\t\t\t\tif (!response.ok) {\n\t\t\t\t\t\tif (response.status === 404) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\tmessage: `Article \"${query}\" not found on Wikipedia. Try using the search action first to find the correct article title.`,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Wikipedia API error: ${response.status}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst data = await response.json();\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\taction: \"summary\",\n\t\t\t\t\t\ttitle: data.title,\n\t\t\t\t\t\tpageid: data.pageid,\n\t\t\t\t\t\textract: data.extract,\n\t\t\t\t\t\tdescription: data.description,\n\t\t\t\t\t\turl: `https://en.wikipedia.org/wiki/${encodeURIComponent(data.title.replace(/ /g, \"_\"))}`,\n\t\t\t\t\t\tthumbnail: data.thumbnail,\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`Unsupported action: ${action}`);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"[wikipediaTool] Error:\", error);\n\t\t\t\tconst message =\n\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: \"Unknown error occurred while accessing Wikipedia\";\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: `Failed to access Wikipedia: ${message}`,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t});\n",
			"type": "registry:lib",
			"target": "lib/tools/wikipedia-query.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/executor.ts",
			"content": "import {\n\tconvertToModelMessages,\n\ttype ModelMessage,\n\ttype UIMessageStreamWriter,\n} from \"ai\";\nimport { getNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\nimport { validateWorkflow } from \"@/registry/blocks/workflow-01/lib/workflow/validation\";\nimport type { WorkflowUIMessage } from \"@/registry/blocks/workflow-01/types/messages\";\nimport type {\n\tExecutionContext,\n\tExecutionResult,\n\tFlowEdge,\n\tFlowNode,\n\tNodeExecutionResult,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\nimport { isNodeOfType } from \"@/registry/blocks/workflow-01/types/workflow\";\n\n/**\n * Main workflow execution function\n */\nexport async function executeWorkflow({\n\tnodes,\n\tedges,\n\tmessages,\n\twriter,\n}: {\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n\tmessages: WorkflowUIMessage[];\n\twriter: UIMessageStreamWriter<WorkflowUIMessage>;\n}): Promise<void> {\n\tconst validation = validateWorkflow(nodes, edges);\n\n\tconst errors = validation.errors.filter((e) => e.severity === \"error\");\n\tif (errors.length > 0) {\n\t\tconst errorMessages = errors.map((e) => `- ${e.message}`).join(\"\\n\");\n\t\tthrow new Error(`Workflow has errors:\\n${errorMessages}`);\n\t}\n\n\t// Log warnings but don't block\n\tconst warnings = validation.errors.filter((e) => e.severity === \"warning\");\n\tif (warnings.length > 0) {\n\t\tconsole.warn(\"Workflow warnings:\", warnings);\n\t}\n\n\tif (validation.warnings.length > 0) {\n\t\tconsole.warn(\"Workflow warnings (legacy):\", validation.warnings);\n\t}\n\n\tconst startNode = nodes.find((node) => isNodeOfType(node, \"start\"));\n\tif (!startNode) {\n\t\tthrow new Error(\"No start node found\");\n\t}\n\n\tconst executionMemory: Record<string, ExecutionResult> = {};\n\tconst initialMessages = convertToModelMessages(messages);\n\tconst accumulatedMessages: ModelMessage[] = initialMessages;\n\n\tlet currentNodeId: string | null = startNode.id;\n\tlet previousNodeId: string = startNode.id;\n\tlet stepCount = 0;\n\tconst MAX_STEPS = 100;\n\n\twhile (currentNodeId) {\n\t\tif (stepCount++ > MAX_STEPS) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Execution exceeded maximum steps (possible infinite loop)\",\n\t\t\t);\n\t\t}\n\n\t\tconst node = nodes.find((n) => n.id === currentNodeId);\n\t\tif (!node) {\n\t\t\tthrow new Error(`Node ${currentNodeId} not found`);\n\t\t}\n\n\t\tif (isNodeOfType(node, \"note\")) {\n\t\t\tthrow new Error(\n\t\t\t\t`Note node ${currentNodeId} found, but should not be executed`,\n\t\t\t);\n\t\t}\n\n\t\tlet executionResult: {\n\t\t\tresult: ExecutionResult;\n\t\t\tnextNodeId: string | null;\n\t\t};\n\n\t\tconst nodeName =\n\t\t\tnode.type === \"agent\"\n\t\t\t\t? (node.data as { name?: string }).name || node.id\n\t\t\t\t: node.id;\n\n\t\ttry {\n\t\t\twriter.write({\n\t\t\t\ttype: \"data-node-execution-status\",\n\t\t\t\tid: node.id,\n\t\t\t\tdata: {\n\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\tnodeType: node.type,\n\t\t\t\t\tname: nodeName,\n\t\t\t\t\tstatus: \"processing\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tconst definition = getNodeDefinition(node.type);\n\t\t\tif (!definition) {\n\t\t\t\tthrow new Error(`Unknown node type: ${node.type}`);\n\t\t\t}\n\n\t\t\tconst context = {\n\t\t\t\tnode,\n\t\t\t\tnodes,\n\t\t\t\tedges,\n\t\t\t\texecutionMemory,\n\t\t\t\taccumulatedMessages,\n\t\t\t\tpreviousNodeId,\n\t\t\t\twriter,\n\t\t\t};\n\t\t\tconst registryResult = await (\n\t\t\t\tdefinition.server.execute as (\n\t\t\t\t\t// biome-ignore lint/suspicious/noExplicitAny: Type assertion needed for registry-based execution\n\t\t\t\t\tcontext: ExecutionContext<any>,\n\t\t\t\t) => Promise<NodeExecutionResult> | NodeExecutionResult\n\t\t\t)(context);\n\t\t\texecutionResult = {\n\t\t\t\tresult: {\n\t\t\t\t\ttext: registryResult.result.text,\n\t\t\t\t\tstructured: registryResult.result.structured,\n\t\t\t\t\tnodeType: node.type,\n\t\t\t\t\tmessages: accumulatedMessages,\n\t\t\t\t},\n\t\t\t\tnextNodeId: registryResult.nextNodeId,\n\t\t\t};\n\n\t\t\twriter.write({\n\t\t\t\ttype: \"data-node-execution-status\",\n\t\t\t\tid: node.id,\n\t\t\t\tdata: {\n\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\tnodeType: node.type,\n\t\t\t\t\tname: nodeName,\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\texecutionMemory[node.id] = executionResult.result;\n\n\t\t\tpreviousNodeId = currentNodeId;\n\t\t\tcurrentNodeId = executionResult.nextNodeId;\n\t\t} catch (error) {\n\t\t\twriter.write({\n\t\t\t\ttype: \"data-node-execution-status\",\n\t\t\t\tid: node.id,\n\t\t\t\tdata: {\n\t\t\t\t\tnodeId: node.id,\n\t\t\t\t\tnodeType: node.type,\n\t\t\t\t\tname: nodeName,\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\terror:\n\t\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t: \"Unknown error\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (!currentNodeId) {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n",
			"type": "registry:lib",
			"target": "lib/workflow/executor.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/models-external.ts",
			"content": "import { openai } from \"@ai-sdk/openai\";\n\nimport {\n\tcustomProvider,\n\tdefaultSettingsMiddleware,\n\twrapLanguageModel,\n} from \"ai\";\n\nconst languageModels = {\n\t\"gpt-5-mini\": wrapLanguageModel({\n\t\tmodel: openai.chat(\"gpt-5-mini\"),\n\t\tmiddleware: defaultSettingsMiddleware({\n\t\t\tsettings: {\n\t\t\t\tproviderOptions: {\n\t\t\t\t\topenai: {\n\t\t\t\t\t\treasoningSummary: \"auto\", // 'auto' for condensed or 'detailed' for comprehensive\n\t\t\t\t\t\treasoningEffort: \"minimal\", // 'minimal' | 'low' | 'medium' | 'high'\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t}),\n};\n\nexport const workflowModel = customProvider({ languageModels });\n\nexport const WORKFLOW_MODELS = Object.keys(languageModels) as workflowModelID[];\n\nexport type workflowModelID = keyof typeof languageModels;\n",
			"type": "registry:lib",
			"target": "lib/workflow/models.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/types/messages.ts",
			"content": "import type { InferUITools, ToolUIPart, UIMessage } from \"ai\";\nimport type { workflowTools } from \"@/registry/blocks/workflow-01/lib/tools\";\nimport type {\n\tFlowNode,\n\tNodeStatus,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\ntype WorkflowAIMetadata = Record<string, unknown>;\n\ntype WorkflowAIDataPart = {\n\t\"node-execution-status\": {\n\t\tnodeId: string;\n\t\tnodeType: FlowNode[\"type\"];\n\t\tname?: string;\n\t\tstatus: NodeStatus;\n\t\terror?: string;\n\t};\n\t\"node-execution-state\": {\n\t\tnodeId: string;\n\t\tnodeType: FlowNode[\"type\"];\n\t\tdata: FlowNode[\"data\"];\n\t};\n};\n\ntype WorkflowAgentToolSet = typeof workflowTools;\ntype WorkflowAITools = InferUITools<WorkflowAgentToolSet>;\n\nexport type WorkflowAIToolUIPart = ToolUIPart<WorkflowAITools>;\n\nexport type WorkflowUIMessage = UIMessage<\n\tWorkflowAIMetadata,\n\tWorkflowAIDataPart,\n\tWorkflowAITools\n>;\n",
			"type": "registry:lib",
			"target": "types/messages.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/types/workflow.ts",
			"content": "import type { NodeProps } from \"@xyflow/react\";\nimport type { JSONSchema7, ModelMessage, UIMessageStreamWriter } from \"ai\";\nimport type { z } from \"zod\";\nimport type { StatusEdge } from \"@/registry/blocks/workflow-01/components/workflow/status-edge\";\nimport type { nodeRegistry } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\nimport type { WorkflowUIMessage } from \"@/registry/blocks/workflow-01/types/messages\";\n\n// ========== NODES ==========\n\nexport type TextNodeOutput = {\n\ttype: \"text\";\n};\n\nexport type StructuredNodeOutput = {\n\ttype: \"structured\";\n\tschema: JSONSchema7;\n};\n\nexport type NodeOutput = TextNodeOutput | StructuredNodeOutput;\n\nexport const NODE_STATUSES = [\n\t\"processing\",\n\t\"error\",\n\t\"success\",\n\t\"idle\",\n] as const;\n\nexport type NodeStatus = (typeof NODE_STATUSES)[number];\n\ntype NodeMap = {\n\t[K in keyof typeof nodeRegistry]: ReturnType<\n\t\t(typeof nodeRegistry)[K][\"client\"][\"create\"]\n\t>;\n};\n\nexport type FlowNode = NodeMap[keyof NodeMap];\nexport type FlowNodeType = FlowNode[\"type\"];\n\nexport type AnyNodeDefinition =\n\t(typeof nodeRegistry)[keyof typeof nodeRegistry];\n\nexport function isNodeOfType<T extends FlowNode[\"type\"]>(\n\tnode: FlowNode,\n\ttype: T,\n): node is Extract<FlowNode, { type: T }> {\n\treturn node.type === type;\n}\n\nexport interface NodeSharedDefinition<TNode extends FlowNode> {\n\ttype: TNode[\"type\"];\n\t// biome-ignore lint/suspicious/noExplicitAny: Zod schema types are complex and vary by node\n\tdataSchema: z.ZodObject<any, any>;\n\tvalidate: (node: TNode, context: ValidationContext) => ValidationError[];\n}\n\nexport interface NodeClientDefinition<TNode extends FlowNode> {\n\tcomponent: React.ComponentType<NodeProps<TNode>>;\n\t// biome-ignore lint/suspicious/noExplicitAny: Panel components may accept additional props\n\tpanelComponent: React.ComponentType<any>;\n\tcreate: (position: { x: number; y: number }) => TNode;\n\tmeta: {\n\t\tlabel: string;\n\t\ticon: React.ComponentType<{ className?: string }>;\n\t\tdescription: string;\n\t};\n}\n\nexport interface NodeServerDefinition<TNode extends FlowNode> {\n\texecute: (\n\t\tcontext: ExecutionContext<TNode>,\n\t) => Promise<NodeExecutionResult> | NodeExecutionResult;\n}\n\nexport interface NodeDefinition<TNode extends FlowNode> {\n\tshared: NodeSharedDefinition<TNode>;\n\tclient: NodeClientDefinition<TNode>;\n\tserver: NodeServerDefinition<TNode>;\n}\n\n// ========== EDGES ==========\n\nexport type FlowEdge = StatusEdge;\n\n// ========== VALIDATION TYPES ==========\n\nexport type ValidationSeverity = \"error\" | \"warning\";\n\ntype NodeHandleErrorInfo = {\n\tid: string;\n\thandleId: string;\n};\n\ntype EdgeErrorInfo = {\n\tid: string;\n\tsource: string;\n\ttarget: string;\n\tsourceHandle: string;\n\ttargetHandle: string;\n};\n\nexport type MultipleSourcesError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"multiple-sources-for-target-handle\";\n\tedges: EdgeErrorInfo[];\n};\n\nexport type MultipleOutgoingError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"multiple-outgoing-from-source-handle\";\n\tedges: EdgeErrorInfo[];\n};\n\nexport type CycleError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"cycle\";\n\tedges: EdgeErrorInfo[];\n};\n\nexport type MissingConnectionError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"missing-required-connection\";\n\tnode: NodeHandleErrorInfo;\n};\n\ntype NodeErrorInfo = {\n\tid: string;\n};\n\ntype ConditionErrorInfo = {\n\tnodeId: string;\n\thandleId: string;\n\tcondition: string;\n\terror: string;\n};\n\nexport type InvalidConditionError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"invalid-condition\";\n\tcondition: ConditionErrorInfo;\n};\n\nexport type NoStartNodeError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"no-start-node\";\n\tcount: number;\n};\n\nexport type NoEndNodeError = {\n\tseverity: \"error\";\n\tmessage: string;\n\ttype: \"no-end-node\";\n};\n\nexport type UnreachableNodeError = {\n\tseverity: \"warning\";\n\tmessage: string;\n\ttype: \"unreachable-node\";\n\tnodes: NodeErrorInfo[];\n};\n\nexport type InvalidNodeConfigError = {\n\tseverity: ValidationSeverity;\n\tmessage: string;\n\ttype: \"invalid-node-config\";\n\tnode: NodeErrorInfo;\n};\n\nexport type ValidationError =\n\t| CycleError\n\t| MultipleSourcesError\n\t| MultipleOutgoingError\n\t| MissingConnectionError\n\t| InvalidConditionError\n\t| NoStartNodeError\n\t| NoEndNodeError\n\t| UnreachableNodeError\n\t| InvalidNodeConfigError;\n\n// ========== EXECUTION TYPES ==========\n\nexport type ExecutionResult = {\n\ttext: string;\n\tstructured?: unknown;\n\tnodeType: FlowNode[\"type\"];\n\tmessages?: ModelMessage[];\n};\n\nexport interface NodeExecutionResult {\n\tresult: {\n\t\ttext: string;\n\t\tstructured?: unknown;\n\t};\n\tnextNodeId: string | null;\n}\n\nexport interface ExecutionContext<TNode extends FlowNode> {\n\tnode: TNode;\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n\texecutionMemory: Record<string, ExecutionResult>;\n\taccumulatedMessages: ModelMessage[];\n\tpreviousNodeId: string;\n\twriter: UIMessageStreamWriter<WorkflowUIMessage>;\n}\n\nexport interface ValidationContext {\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n}\n",
			"type": "registry:lib",
			"target": "types/workflow.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/validation.ts",
			"content": "import { getNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\nimport { isNodeOfType } from \"@/registry/blocks/workflow-01/types/workflow\";\n\ntype ValidationResult = {\n\tvalid: boolean;\n\terrors: ValidationError[];\n\twarnings: ValidationError[];\n};\n\n/**\n * Get all node IDs reachable from the start node using BFS traversal.\n * Returns a Set of node IDs that can be reached from the start node.\n */\nfunction getReachableNodeIds(\n\tnodes: FlowNode[],\n\tedges: FlowEdge[],\n): Set<string> {\n\tconst startNode = nodes.find((node) => isNodeOfType(node, \"start\"));\n\tif (!startNode) {\n\t\treturn new Set<string>();\n\t}\n\n\tconst reachable = new Set<string>();\n\tconst queue: string[] = [startNode.id];\n\n\twhile (queue.length > 0) {\n\t\t// biome-ignore lint/style/noNonNullAssertion: We checked queue.length > 0\n\t\tconst nodeId = queue.shift()!;\n\t\tif (reachable.has(nodeId)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\treachable.add(nodeId);\n\n\t\tconst outgoingEdges = edges.filter((e) => e.source === nodeId);\n\t\tfor (const edge of outgoingEdges) {\n\t\t\tif (!reachable.has(edge.target)) {\n\t\t\t\tqueue.push(edge.target);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn reachable;\n}\n\n/**\n * Get all nodes reachable from the start node.\n * Only validates reachable nodes to avoid cluttering the UI with errors from disconnected nodes.\n */\nfunction getReachableNodes(nodes: FlowNode[], edges: FlowEdge[]): FlowNode[] {\n\tconst reachableIds = getReachableNodeIds(nodes, edges);\n\treturn nodes.filter((node) => reachableIds.has(node.id));\n}\n\n/**\n * Separates validation errors into errors and warnings based on severity.\n */\nfunction separateErrorsAndWarnings(\n\tvalidationErrors: ValidationError[],\n): ValidationResult {\n\tconst errors: ValidationError[] = [];\n\tconst warnings: ValidationError[] = [];\n\n\tfor (const error of validationErrors) {\n\t\tif (error.severity === \"warning\") {\n\t\t\twarnings.push(error);\n\t\t} else {\n\t\t\terrors.push(error);\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t};\n}\n\n/**\n * Validates the entire workflow by running validation phases in order.\n * Only validates reachable nodes to avoid cluttering the UI with errors from disconnected nodes.\n */\nexport function validateWorkflow(\n\tnodes: FlowNode[],\n\tedges: FlowEdge[],\n): ValidationResult {\n\tconst errors: ValidationError[] = [];\n\n\terrors.push(...validateGraphStructure(nodes));\n\terrors.push(...validateEdgeConstraints(edges));\n\terrors.push(...validateNoCycles(nodes, edges));\n\n\tconst reachableNodes = getReachableNodes(nodes, edges);\n\terrors.push(...validateNodeConfigurations(reachableNodes, edges));\n\terrors.push(...validateReachability(nodes, reachableNodes));\n\n\treturn separateErrorsAndWarnings(errors);\n}\n\n/**\n * Check if a connection is valid before making it\n * Used for real-time validation during connection attempts\n */\nexport function isValidConnection({\n\tsourceNodeId,\n\tsourceHandle,\n\ttargetNodeId,\n\ttargetHandle: _targetHandle,\n\tnodes,\n\tedges,\n}: {\n\tsourceNodeId: string;\n\tsourceHandle: string | null;\n\ttargetNodeId: string;\n\ttargetHandle: string | null;\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n}): boolean {\n\tconst sourceNode = nodes.find((n) => n.id === sourceNodeId);\n\tconst targetNode = nodes.find((n) => n.id === targetNodeId);\n\n\tif (!sourceNode || !targetNode) {\n\t\treturn false;\n\t}\n\n\tif (sourceNodeId === targetNodeId) {\n\t\treturn false;\n\t}\n\n\tif (sourceNode.type === \"note\" || targetNode.type === \"note\") {\n\t\treturn false;\n\t}\n\n\tif (targetNode.type === \"start\") {\n\t\treturn false;\n\t}\n\n\tif (sourceNode.type === \"end\") {\n\t\treturn false;\n\t}\n\n\tconst existingSourceEdge = edges.find(\n\t\t(e) => e.source === sourceNodeId && e.sourceHandle === sourceHandle,\n\t);\n\tif (existingSourceEdge) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Check if a specific handle can accept more connections\n * Used for UI feedback to show if a handle is available\n */\nexport function canConnectHandle(params: {\n\tnodeId: string;\n\thandleId: string;\n\ttype: \"source\" | \"target\";\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n}): boolean {\n\tconst { nodeId, handleId, type, nodes, edges } = params;\n\tconst node = nodes.find((n) => n.id === nodeId);\n\n\tif (!node) {\n\t\treturn true;\n\t}\n\n\tif (node.type === \"note\") {\n\t\treturn false;\n\t}\n\n\tif (node.type === \"start\" && type === \"target\") {\n\t\treturn false;\n\t}\n\n\tif (node.type === \"end\" && type === \"source\") {\n\t\treturn false;\n\t}\n\n\tif (type === \"source\") {\n\t\tconst existingEdge = edges.find(\n\t\t\t(e) => e.source === nodeId && e.sourceHandle === handleId,\n\t\t);\n\t\tif (existingEdge) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * Validates graph structure requirements: exactly one start node and at least one end node.\n */\nfunction validateGraphStructure(nodes: FlowNode[]): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\n\tconst startNodes = nodes.filter((node) => isNodeOfType(node, \"start\"));\n\tif (startNodes.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"no-start-node\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Workflow must have exactly one start node\",\n\t\t\tcount: 0,\n\t\t});\n\t} else if (startNodes.length > 1) {\n\t\terrors.push({\n\t\t\ttype: \"no-start-node\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: `Workflow has ${startNodes.length} start nodes, but must have exactly one`,\n\t\t\tcount: startNodes.length,\n\t\t});\n\t}\n\n\tconst endNodes = nodes.filter((node) => isNodeOfType(node, \"end\"));\n\tif (endNodes.length === 0) {\n\t\terrors.push({\n\t\t\ttype: \"no-end-node\",\n\t\t\tseverity: \"error\",\n\t\t\tmessage: \"Workflow must have at least one end node\",\n\t\t});\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validates edge constraints: ensures no source handle has multiple outgoing connections.\n */\nfunction validateEdgeConstraints(edges: FlowEdge[]): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst sourceHandleMap = new Map<string, FlowEdge[]>();\n\n\tfor (const edge of edges) {\n\t\tconst key = `${edge.source}:${edge.sourceHandle || \"default\"}`;\n\t\tconst existing = sourceHandleMap.get(key) || [];\n\t\texisting.push(edge);\n\t\tsourceHandleMap.set(key, existing);\n\t}\n\n\tfor (const [key, edgeGroup] of sourceHandleMap.entries()) {\n\t\tif (edgeGroup.length > 1) {\n\t\t\tconst [sourceId, sourceHandle] = key.split(\":\");\n\t\t\terrors.push({\n\t\t\t\ttype: \"multiple-outgoing-from-source-handle\",\n\t\t\t\tseverity: \"error\",\n\t\t\t\tmessage: `Node ${sourceId} handle \"${sourceHandle}\" has ${edgeGroup.length} outgoing connections (maximum 1 allowed)`,\n\t\t\t\tedges: edgeGroup.map((e) => ({\n\t\t\t\t\tid: e.id,\n\t\t\t\t\tsource: e.source,\n\t\t\t\t\ttarget: e.target,\n\t\t\t\t\tsourceHandle: e.sourceHandle || \"\",\n\t\t\t\t\ttargetHandle: e.targetHandle || \"\",\n\t\t\t\t})),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validates node-specific configuration rules by delegating to each node's validator.\n */\nfunction validateNodeConfigurations(\n\tnodes: FlowNode[],\n\tedges: FlowEdge[],\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\n\tfor (const node of nodes) {\n\t\tconst definition = getNodeDefinition(node.type);\n\t\tif (definition) {\n\t\t\tconst context = { nodes, edges };\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: Type assertion needed for registry-based validation\n\t\t\tconst nodeErrors = definition.shared.validate(node as any, context);\n\t\t\terrors.push(...(nodeErrors as ValidationError[]));\n\t\t} else {\n\t\t\terrors.push({\n\t\t\t\ttype: \"invalid-node-config\",\n\t\t\t\tseverity: \"error\",\n\t\t\t\tmessage: `Unknown node type: ${node.type}`,\n\t\t\t\tnode: { id: node.id },\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validates that the workflow contains no cycles by performing DFS traversal.\n */\nfunction validateNoCycles(\n\tnodes: FlowNode[],\n\tedges: FlowEdge[],\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst visited = new Set<string>();\n\tconst recursionStack = new Set<string>();\n\tconst edgePath: FlowEdge[] = [];\n\n\tconst startNode = nodes.find((node) => isNodeOfType(node, \"start\"));\n\tif (!startNode) {\n\t\treturn errors;\n\t}\n\n\tfunction dfs(nodeId: string): void {\n\t\tvisited.add(nodeId);\n\t\trecursionStack.add(nodeId);\n\n\t\tconst node = nodes.find((n) => n.id === nodeId);\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst outgoingEdges = edges.filter((e) => e.source === nodeId);\n\n\t\tfor (const edge of outgoingEdges) {\n\t\t\tedgePath.push(edge);\n\n\t\t\tif (!visited.has(edge.target)) {\n\t\t\t\tdfs(edge.target);\n\t\t\t} else if (recursionStack.has(edge.target)) {\n\t\t\t\tconst cycleStartIndex = edgePath.findIndex(\n\t\t\t\t\t(e) => e.target === edge.target,\n\t\t\t\t);\n\t\t\t\tconst cycleEdges = edgePath.slice(cycleStartIndex);\n\n\t\t\t\terrors.push({\n\t\t\t\t\ttype: \"cycle\",\n\t\t\t\t\tseverity: \"error\",\n\t\t\t\t\tmessage: `Cycle detected in workflow involving nodes: ${cycleEdges.map((e) => e.source).join(\" → \")} → ${edge.target}`,\n\t\t\t\t\tedges: cycleEdges.map((e) => ({\n\t\t\t\t\t\tid: e.id,\n\t\t\t\t\t\tsource: e.source,\n\t\t\t\t\t\ttarget: e.target,\n\t\t\t\t\t\tsourceHandle: e.sourceHandle || \"\",\n\t\t\t\t\t\ttargetHandle: e.targetHandle || \"\",\n\t\t\t\t\t})),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tedgePath.pop();\n\t\t}\n\n\t\trecursionStack.delete(nodeId);\n\t}\n\n\tdfs(startNode.id);\n\n\treturn errors;\n}\n\n/**\n * Validates reachability and generates warnings for unreachable nodes.\n * Note nodes are excluded from reachability checks as they are informational only.\n */\nfunction validateReachability(\n\tallNodes: FlowNode[],\n\treachableNodes: FlowNode[],\n): ValidationError[] {\n\tconst errors: ValidationError[] = [];\n\tconst reachableIds = new Set(reachableNodes.map((n) => n.id));\n\n\tconst unreachableNodes = allNodes\n\t\t.filter(\n\t\t\t(node) => !reachableIds.has(node.id) && !isNodeOfType(node, \"note\"),\n\t\t)\n\t\t.map((node) => ({ id: node.id }));\n\n\tif (unreachableNodes.length > 0) {\n\t\terrors.push({\n\t\t\ttype: \"unreachable-node\",\n\t\t\tseverity: \"warning\",\n\t\t\tmessage: `${unreachableNodes.length} node(s) are unreachable from the start node`,\n\t\t\tnodes: unreachableNodes,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\n/**\n * Get all node IDs that are affected by a validation error\n */\nfunction getAffectedNodeIds(error: ValidationError): string[] {\n\tswitch (error.type) {\n\t\tcase \"no-start-node\":\n\t\tcase \"no-end-node\":\n\t\t\treturn []; // Global errors, no specific node\n\n\t\tcase \"invalid-node-config\":\n\t\t\treturn [error.node.id];\n\n\t\tcase \"invalid-condition\":\n\t\t\treturn [error.condition.nodeId];\n\n\t\tcase \"unreachable-node\":\n\t\t\treturn error.nodes.map((n) => n.id);\n\n\t\tcase \"cycle\":\n\t\tcase \"multiple-outgoing-from-source-handle\":\n\t\tcase \"multiple-sources-for-target-handle\": {\n\t\t\tconst nodeIds = new Set<string>();\n\t\t\tfor (const edge of error.edges) {\n\t\t\t\tnodeIds.add(edge.source);\n\t\t\t\tnodeIds.add(edge.target);\n\t\t\t}\n\t\t\treturn Array.from(nodeIds);\n\t\t}\n\n\t\tcase \"missing-required-connection\":\n\t\t\treturn [error.node.id];\n\n\t\tdefault: {\n\t\t\t// biome-ignore lint/correctness/noUnusedVariables: exhaustive check\n\t\t\tconst exhaustiveCheck: never = error;\n\t\t\treturn [];\n\t\t}\n\t}\n}\n\n/**\n * Get all edge IDs that are affected by a validation error\n */\nfunction getAffectedEdgeIds(error: ValidationError): string[] {\n\tswitch (error.type) {\n\t\tcase \"cycle\":\n\t\tcase \"multiple-outgoing-from-source-handle\":\n\t\tcase \"multiple-sources-for-target-handle\":\n\t\t\treturn error.edges.map((e) => e.id);\n\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n\n/**\n * Check if a specific node is affected by any validation errors\n */\nexport function getErrorsForNode(\n\tnodeId: string,\n\terrors: ValidationError[],\n): ValidationError[] {\n\treturn errors.filter((error) => getAffectedNodeIds(error).includes(nodeId));\n}\n\n/**\n * Check if a specific edge is affected by any validation errors\n */\nexport function getErrorsForEdge(\n\tedgeId: string,\n\terrors: ValidationError[],\n): ValidationError[] {\n\treturn errors.filter((error) => getAffectedEdgeIds(error).includes(edgeId));\n}\n",
			"type": "registry:lib",
			"target": "lib/workflow/validation.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/context/schema-introspection.ts",
			"content": "import type { JSONSchema7 } from \"ai\";\n\nexport interface ParsedSchemaProperty {\n\ttype: string;\n\tisArray: boolean;\n\tdescription?: string;\n\tproperties?: Record<string, ParsedSchemaProperty>;\n\tenumValues?: string[];\n}\n\nexport interface ParsedSchemaPropertyWithChildren extends ParsedSchemaProperty {\n\tproperties?: Record<string, ParsedSchemaProperty>;\n}\n\nexport function parseJSONSchemaProperty(\n\tprop: Record<string, unknown>,\n): ParsedSchemaProperty {\n\tconst result: ParsedSchemaProperty = {\n\t\ttype: \"string\",\n\t\tisArray: false,\n\t};\n\n\tif (prop.type === \"array\" && prop.items && typeof prop.items === \"object\") {\n\t\tresult.isArray = true;\n\t\tconst items = prop.items as Record<string, unknown>;\n\n\t\tif (typeof items.type === \"string\") {\n\t\t\tresult.type = items.type;\n\t\t}\n\n\t\tif (items.enum && Array.isArray(items.enum)) {\n\t\t\tresult.type = \"enum\";\n\t\t\tresult.enumValues = items.enum.map(String);\n\t\t}\n\n\t\tif (\n\t\t\titems.type === \"object\" &&\n\t\t\titems.properties &&\n\t\t\ttypeof items.properties === \"object\"\n\t\t) {\n\t\t\tresult.type = \"object\";\n\t\t\tresult.properties = {};\n\n\t\t\tfor (const [nestedName, nestedProp] of Object.entries(\n\t\t\t\titems.properties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\tif (typeof nestedProp === \"object\" && nestedProp !== null) {\n\t\t\t\t\tresult.properties[nestedName] = parseJSONSchemaProperty(\n\t\t\t\t\t\tnestedProp as Record<string, unknown>,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif (typeof prop.type === \"string\") {\n\t\t\tresult.type = prop.type;\n\t\t}\n\n\t\tif (prop.enum && Array.isArray(prop.enum)) {\n\t\t\tresult.type = \"enum\";\n\t\t\tresult.enumValues = prop.enum.map(String);\n\t\t}\n\n\t\tif (\n\t\t\tprop.type === \"object\" &&\n\t\t\tprop.properties &&\n\t\t\ttypeof prop.properties === \"object\"\n\t\t) {\n\t\t\tresult.properties = {};\n\n\t\t\tfor (const [nestedName, nestedProp] of Object.entries(\n\t\t\t\tprop.properties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\tif (typeof nestedProp === \"object\" && nestedProp !== null) {\n\t\t\t\t\tresult.properties[nestedName] = parseJSONSchemaProperty(\n\t\t\t\t\t\tnestedProp as Record<string, unknown>,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (prop.description && typeof prop.description === \"string\") {\n\t\tresult.description = prop.description;\n\t}\n\n\treturn result;\n}\n\nexport function parseJSONSchema(\n\tschema: JSONSchema7,\n): Record<string, ParsedSchemaProperty> {\n\tif (!schema || typeof schema !== \"object\" || !schema.properties) {\n\t\treturn {};\n\t}\n\n\tconst properties: Record<string, ParsedSchemaProperty> = {};\n\tfor (const [name, prop] of Object.entries(\n\t\tschema.properties as Record<string, unknown>,\n\t)) {\n\t\tif (typeof prop === \"object\" && prop !== null) {\n\t\t\tproperties[name] = parseJSONSchemaProperty(\n\t\t\t\tprop as Record<string, unknown>,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn properties;\n}\n\n/**\n * Type definition for CEL custom type registration\n */\nexport interface CelTypeDefinition {\n\ttypename: string;\n\tfields: Record<string, string>;\n}\n\n/**\n * Result of converting a JSON Schema to CEL declarations\n */\nexport interface CelSchemaConversion {\n\t/** Type definitions to register (in dependency order - nested types first) */\n\ttypeDefinitions: CelTypeDefinition[];\n\t/** Variable declaration: variable name -> CEL type name */\n\tvariableDeclaration: { name: string; type: string };\n}\n\n/**\n * Map JSON Schema type to CEL type\n */\nfunction mapJsonTypeToCel(jsonType: string | undefined): string {\n\tif (!jsonType) {\n\t\treturn \"dyn\";\n\t}\n\n\tswitch (jsonType) {\n\t\tcase \"integer\":\n\t\t\treturn \"int\";\n\t\tcase \"number\":\n\t\t\treturn \"double\";\n\t\tcase \"boolean\":\n\t\t\treturn \"bool\";\n\t\tcase \"string\":\n\t\t\treturn \"string\";\n\t\tcase \"array\":\n\t\t\treturn \"list\";\n\t\tcase \"object\":\n\t\t\treturn \"map\";\n\t\tdefault:\n\t\t\treturn \"dyn\";\n\t}\n}\n\n/**\n * Recursively build CEL type definitions from a JSON Schema property\n */\nfunction buildCelTypeFromProperty(\n\tprop: Record<string, unknown>,\n\tbaseTypename: string,\n\tfieldName: string,\n\ttypeDefinitions: CelTypeDefinition[],\n): string {\n\tconst propType = typeof prop.type === \"string\" ? prop.type : undefined;\n\n\t// Handle arrays\n\tif (propType === \"array\" && prop.items && typeof prop.items === \"object\") {\n\t\tconst items = prop.items as Record<string, unknown>;\n\t\tconst itemsType =\n\t\t\ttypeof items.type === \"string\" ? items.type : undefined;\n\n\t\t// Array of objects - create nested type\n\t\tif (itemsType === \"object\" && items.properties) {\n\t\t\tconst nestedTypename = `${baseTypename}_${fieldName}_item`;\n\t\t\tconst nestedFields: Record<string, string> = {};\n\n\t\t\tfor (const [nestedKey, nestedProp] of Object.entries(\n\t\t\t\titems.properties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\tif (typeof nestedProp === \"object\" && nestedProp !== null) {\n\t\t\t\t\tnestedFields[nestedKey] = buildCelTypeFromProperty(\n\t\t\t\t\t\tnestedProp as Record<string, unknown>,\n\t\t\t\t\t\tnestedTypename,\n\t\t\t\t\t\tnestedKey,\n\t\t\t\t\t\ttypeDefinitions,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Register the nested type\n\t\t\ttypeDefinitions.push({\n\t\t\t\ttypename: nestedTypename,\n\t\t\t\tfields: nestedFields,\n\t\t\t});\n\n\t\t\treturn `list<${nestedTypename}>`;\n\t\t}\n\n\t\t// Array of primitives\n\t\tconst itemCelType = mapJsonTypeToCel(itemsType);\n\t\treturn `list<${itemCelType}>`;\n\t}\n\n\t// Handle objects - create nested type\n\tif (propType === \"object\" && prop.properties) {\n\t\tconst nestedTypename = `${baseTypename}_${fieldName}`;\n\t\tconst nestedFields: Record<string, string> = {};\n\n\t\tfor (const [nestedKey, nestedProp] of Object.entries(\n\t\t\tprop.properties as Record<string, unknown>,\n\t\t)) {\n\t\t\tif (typeof nestedProp === \"object\" && nestedProp !== null) {\n\t\t\t\tnestedFields[nestedKey] = buildCelTypeFromProperty(\n\t\t\t\t\tnestedProp as Record<string, unknown>,\n\t\t\t\t\tnestedTypename,\n\t\t\t\t\tnestedKey,\n\t\t\t\t\ttypeDefinitions,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Register the nested type\n\t\ttypeDefinitions.push({\n\t\t\ttypename: nestedTypename,\n\t\t\tfields: nestedFields,\n\t\t});\n\n\t\treturn nestedTypename;\n\t}\n\n\t// Handle primitives\n\treturn mapJsonTypeToCel(propType);\n}\n\n/**\n * Convert JSON Schema to CEL type declarations with full recursive type support\n * Returns type definitions and variable declaration for registration with CEL Environment\n */\nexport function convertSchemaToCelDeclarations(\n\tschema: JSONSchema7,\n\tbasePath = \"input\",\n): CelSchemaConversion {\n\tconst typeDefinitions: CelTypeDefinition[] = [];\n\n\t// Base type name (capitalize first letter)\n\tconst baseTypename = basePath.charAt(0).toUpperCase() + basePath.slice(1);\n\n\t// Build fields for the root type\n\tconst rootFields: Record<string, string> = {};\n\n\tif (schema.properties) {\n\t\tfor (const [key, prop] of Object.entries(\n\t\t\tschema.properties as Record<string, unknown>,\n\t\t)) {\n\t\t\tif (typeof prop === \"object\" && prop !== null) {\n\t\t\t\trootFields[key] = buildCelTypeFromProperty(\n\t\t\t\t\tprop as Record<string, unknown>,\n\t\t\t\t\tbaseTypename,\n\t\t\t\t\tkey,\n\t\t\t\t\ttypeDefinitions,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Register the root type\n\ttypeDefinitions.push({\n\t\ttypename: baseTypename,\n\t\tfields: rootFields,\n\t});\n\n\treturn {\n\t\ttypeDefinitions,\n\t\tvariableDeclaration: {\n\t\t\tname: basePath,\n\t\t\ttype: baseTypename,\n\t\t},\n\t};\n}\n\n/**\n * Compare two JSON schemas to check if they are identical\n * Returns true if schemas match, false otherwise\n */\nexport function areSchemasIdentical(schemas: JSONSchema7[]): boolean {\n\tif (schemas.length <= 1) {\n\t\treturn true;\n\t}\n\n\tconst firstSchema = schemas[0];\n\tif (!firstSchema) {\n\t\treturn false;\n\t}\n\n\t// Convert all schemas to type definitions for comparison\n\tconst conversions = schemas.map((schema) =>\n\t\tconvertSchemaToCelDeclarations(schema),\n\t);\n\n\tconst firstConversion = conversions[0];\n\tif (!firstConversion) {\n\t\treturn false;\n\t}\n\n\t// Compare all conversions against the first one\n\tfor (let i = 1; i < conversions.length; i++) {\n\t\tconst currentConversion = conversions[i];\n\t\tif (!currentConversion) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Compare root type fields\n\t\tconst firstRootType = firstConversion.typeDefinitions.find(\n\t\t\t(t) => t.typename === firstConversion.variableDeclaration.type,\n\t\t);\n\t\tconst currentRootType = currentConversion.typeDefinitions.find(\n\t\t\t(t) => t.typename === currentConversion.variableDeclaration.type,\n\t\t);\n\n\t\tif (!firstRootType || !currentRootType) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Compare field names and types\n\t\tconst firstFields = Object.keys(firstRootType.fields).sort();\n\t\tconst currentFields = Object.keys(currentRootType.fields).sort();\n\n\t\tif (firstFields.length !== currentFields.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let j = 0; j < firstFields.length; j++) {\n\t\t\tif (firstFields[j] !== currentFields[j]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tfirstRootType.fields[firstFields[j]] !==\n\t\t\t\tcurrentRootType.fields[currentFields[j]]\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n}\n",
			"type": "registry:lib",
			"target": "lib/workflow/context/schema-introspection.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/lib/workflow/context/variable-resolver.ts",
			"content": "import type { JSONSchema7 } from \"ai\";\nimport {\n\ttype ParsedSchemaProperty,\n\tparseJSONSchema,\n} from \"@/registry/blocks/workflow-01/lib/workflow/context/schema-introspection\";\nimport {\n\ttype FlowEdge,\n\ttype FlowNode,\n\tisNodeOfType,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport type VariableInfo = {\n\tpath: string;\n\ttype: string;\n\tdescription?: string;\n\tchildren?: VariableInfo[];\n};\n\nexport type VariableTag = \"common\" | \"path-specific\";\n\nexport type TaggedVariableInfo = VariableInfo & {\n\ttag: VariableTag;\n\tsourceNodeIds: string[]; // Which nodes provide this variable\n};\n\nexport type InputSource = {\n\tnodeId: string;\n\tnodeName?: string;\n\tschema: JSONSchema7 | null; // null means text output (no structured schema)\n};\n\n/**\n * Get all potential input schemas for a target node\n * Returns an array of input sources, each with their schema\n */\nexport function getPotentialInputSchemas(\n\ttargetNodeId: string,\n\tnodes: FlowNode[],\n\tedges: FlowEdge[],\n): InputSource[] {\n\tconst incomingEdges = edges.filter(\n\t\t(edge) => edge.target === targetNodeId && edge.targetHandle === \"input\",\n\t);\n\n\tif (incomingEdges.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst inputSources: InputSource[] = [];\n\n\tfor (const edge of incomingEdges) {\n\t\tconst sourceNode = nodes.find((node) => node.id === edge.source);\n\n\t\tif (!sourceNode) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet schema: JSONSchema7 | null = null;\n\t\tlet nodeName: string | undefined;\n\n\t\tif (isNodeOfType(sourceNode, \"agent\")) {\n\t\t\tnodeName = sourceNode.data.name;\n\t\t\tconst sourceType = sourceNode.data.sourceType;\n\n\t\t\tif (sourceType.type === \"structured\" && sourceType.schema) {\n\t\t\t\tschema = sourceType.schema;\n\t\t\t}\n\t\t\t// If not structured, schema remains null (text output)\n\t\t} else {\n\t\t\t// For non-agent nodes, assume text output (no structured schema)\n\t\t\tschema = null;\n\t\t}\n\n\t\tinputSources.push({\n\t\t\tnodeId: sourceNode.id,\n\t\t\tnodeName,\n\t\t\tschema,\n\t\t});\n\t}\n\n\treturn inputSources;\n}\n\n/**\n * Build union of variables from all potential input schemas\n * Tags variables as \"common\" (in all schemas) or \"path-specific\" (in some but not all)\n */\nexport function getUnionOfVariables(\n\tnodeId: string,\n\tnodes: FlowNode[],\n\tedges: FlowEdge[],\n): TaggedVariableInfo[] {\n\tconst inputSources = getPotentialInputSchemas(nodeId, nodes, edges);\n\n\tif (inputSources.length === 0) {\n\t\treturn [];\n\t}\n\n\t// Extract variables from each source\n\tconst variablesBySource = inputSources.map((source) => {\n\t\tif (source.schema) {\n\t\t\treturn {\n\t\t\t\tsourceNodeId: source.nodeId,\n\t\t\t\tvariables: extractVariablesFromSchema(source.schema, \"input\"),\n\t\t\t};\n\t\t}\n\t\t// Text output - return basic input variable\n\t\treturn {\n\t\t\tsourceNodeId: source.nodeId,\n\t\t\tvariables: [\n\t\t\t\t{\n\t\t\t\t\tpath: \"input\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tdescription: \"Text output from previous node\",\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t});\n\n\t// Build a map of all unique variable paths\n\tconst variableMap = new Map<\n\t\tstring,\n\t\t{\n\t\t\tvariable: VariableInfo;\n\t\t\tsourceNodeIds: Set<string>;\n\t\t}\n\t>();\n\n\t// Collect all variables and track which sources provide them\n\tfor (const { sourceNodeId, variables } of variablesBySource) {\n\t\tfunction addVariables(vars: VariableInfo[], parentPath?: string) {\n\t\t\tfor (const variable of vars) {\n\t\t\t\tconst fullPath = parentPath\n\t\t\t\t\t? `${parentPath}.${variable.path.split(\".\").pop()}`\n\t\t\t\t\t: variable.path;\n\n\t\t\t\tif (!variableMap.has(fullPath)) {\n\t\t\t\t\tvariableMap.set(fullPath, {\n\t\t\t\t\t\tvariable: { ...variable, path: fullPath },\n\t\t\t\t\t\tsourceNodeIds: new Set(),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tvariableMap.get(fullPath)?.sourceNodeIds.add(sourceNodeId);\n\n\t\t\t\tif (variable.children) {\n\t\t\t\t\taddVariables(variable.children, fullPath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\taddVariables(variables);\n\t}\n\n\t// Convert to tagged variables\n\tconst totalSources = inputSources.length;\n\tconst taggedVariables: TaggedVariableInfo[] = [];\n\n\tfor (const [, { variable, sourceNodeIds }] of variableMap) {\n\t\tconst tag: VariableTag =\n\t\t\tsourceNodeIds.size === totalSources ? \"common\" : \"path-specific\";\n\n\t\ttaggedVariables.push({\n\t\t\t...variable,\n\t\t\ttag,\n\t\t\tsourceNodeIds: Array.from(sourceNodeIds),\n\t\t});\n\t}\n\n\t// Sort: common variables first, then path-specific\n\ttaggedVariables.sort((a, b) => {\n\t\tif (a.tag === \"common\" && b.tag === \"path-specific\") {\n\t\t\treturn -1;\n\t\t}\n\t\tif (a.tag === \"path-specific\" && b.tag === \"common\") {\n\t\t\treturn 1;\n\t\t}\n\t\treturn a.path.localeCompare(b.path);\n\t});\n\n\treturn taggedVariables;\n}\n\nexport function extractVariablesFromSchema(\n\tschema: JSONSchema7,\n\tbasePath: string,\n): VariableInfo[] {\n\tconst parsedProperties = parseJSONSchema(schema);\n\n\treturn convertParsedToVariableInfo(parsedProperties, basePath);\n}\n\nfunction convertParsedToVariableInfo(\n\tproperties: Record<string, ParsedSchemaProperty>,\n\tbasePath: string,\n): VariableInfo[] {\n\tconst variables: VariableInfo[] = [];\n\n\tfor (const [key, parsed] of Object.entries(properties)) {\n\t\tconst path = `${basePath}.${key}`;\n\n\t\tconst variable: VariableInfo = {\n\t\t\tpath,\n\t\t\ttype: parsed.type,\n\t\t\tdescription: parsed.description,\n\t\t};\n\n\t\tif (parsed.type === \"object\" && parsed.properties) {\n\t\t\tvariable.children = convertParsedToVariableInfo(\n\t\t\t\tparsed.properties,\n\t\t\t\tpath,\n\t\t\t);\n\t\t}\n\n\t\tif (parsed.isArray && parsed.properties) {\n\t\t\tvariable.children = convertParsedToVariableInfo(\n\t\t\t\tparsed.properties,\n\t\t\t\t`${path}[0]`,\n\t\t\t);\n\t\t}\n\n\t\tvariables.push(variable);\n\t}\n\n\treturn variables;\n}\n\n/**\n * Build a set of all available variable paths from a VariableInfo array\n */\nexport function buildVariablePathSet(variables: VariableInfo[]): Set<string> {\n\tconst paths = new Set<string>();\n\n\tfunction addPaths(vars: VariableInfo[]) {\n\t\tfor (const variable of vars) {\n\t\t\tpaths.add(variable.path);\n\t\t\tif (variable.children) {\n\t\t\t\taddPaths(variable.children);\n\t\t\t}\n\t\t}\n\t}\n\n\taddPaths(variables);\n\treturn paths;\n}\n",
			"type": "registry:lib",
			"target": "lib/workflow/context/variable-resolver.ts"
		},
		{
			"path": "./src/registry/blocks/workflow-01/hooks/use-workflow.ts",
			"content": "import type { Connection, EdgeChange, NodeChange } from \"@xyflow/react\";\nimport { addEdge, applyEdgeChanges, applyNodeChanges } from \"@xyflow/react\";\nimport { createWithEqualityFn } from \"zustand/traditional\";\nimport { getNodeDefinition } from \"@/registry/blocks/workflow-01/lib/workflow/nodes\";\nimport {\n\tcanConnectHandle,\n\tgetErrorsForEdge,\n\tgetErrorsForNode,\n\tisValidConnection,\n\tvalidateWorkflow as validateWorkflowFn,\n} from \"@/registry/blocks/workflow-01/lib/workflow/validation\";\nimport type {\n\tFlowEdge,\n\tFlowNode,\n\tFlowNodeType,\n\tValidationError,\n} from \"@/registry/blocks/workflow-01/types/workflow\";\nimport { isNodeOfType } from \"@/registry/blocks/workflow-01/types/workflow\";\n\nexport interface WorkflowState {\n\tnodes: FlowNode[];\n\tedges: FlowEdge[];\n\tvalidationState: {\n\t\tvalid: boolean;\n\t\terrors: ValidationError[];\n\t\twarnings: ValidationError[];\n\t\tlastValidated: number | null;\n\t};\n\tonNodesChange: (changes: NodeChange<FlowNode>[]) => void;\n\tonEdgesChange: (changes: EdgeChange<FlowEdge>[]) => void;\n\tonConnect: (connection: Connection) => void;\n\tgetNodeById: (nodeId: string) => FlowNode | null;\n\tgetWorkflowData: () => { nodes: FlowNode[]; edges: FlowEdge[] };\n\tcreateNode: (\n\t\tnodeType: FlowNode[\"type\"],\n\t\tposition: { x: number; y: number },\n\t) => FlowNode;\n\tupdateNode: <T extends FlowNodeType>({\n\t\tid,\n\t\tnodeType,\n\t\tdata,\n\t}: {\n\t\tid: string;\n\t\tnodeType: T;\n\t\tdata: Partial<Extract<FlowNode, { type: T }>[\"data\"]>;\n\t}) => void;\n\n\tdeleteNode: (id: string) => void;\n\n\tinitializeWorkflow: ({\n\t\tnodes,\n\t\tedges,\n\t}: {\n\t\tnodes: FlowNode[];\n\t\tedges: FlowEdge[];\n\t}) => void;\n\n\tresetNodeStatuses: () => void;\n\tvalidateWorkflow: () => void;\n\tcanConnectHandle: (params: {\n\t\tnodeId: string;\n\t\thandleId: string;\n\t\ttype: \"source\" | \"target\";\n\t}) => boolean;\n}\n\nconst useWorkflow = createWithEqualityFn<WorkflowState>((set, get) => ({\n\tnodes: [],\n\tedges: [],\n\tvalidationState: {\n\t\tvalid: true,\n\t\terrors: [],\n\t\twarnings: [],\n\t\tlastValidated: null,\n\t},\n\tinitializeWorkflow: ({ nodes, edges }) => {\n\t\tset({ nodes: nodes, edges });\n\t\tget().validateWorkflow();\n\t},\n\tonNodesChange: (changes) => {\n\t\tconst filteredChanges = changes.filter((change) => {\n\t\t\tif (change.type === \"remove\") {\n\t\t\t\tconst node = get().nodes.find((n) => n.id === change.id);\n\t\t\t\tif (node?.type === \"start\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tset({\n\t\t\tnodes: applyNodeChanges<FlowNode>(filteredChanges, get().nodes),\n\t\t});\n\n\t\t// Only validate on meaningful structural changes\n\t\tconst shouldValidate = changes.some(\n\t\t\t(change) => change.type === \"add\" || change.type === \"remove\",\n\t\t);\n\n\t\tif (shouldValidate) {\n\t\t\tget().validateWorkflow();\n\t\t}\n\t},\n\tonEdgesChange: (changes) => {\n\t\tset({\n\t\t\tedges: applyEdgeChanges(changes, get().edges),\n\t\t});\n\n\t\t// Only validate on structural edge changes\n\t\tconst shouldValidate = changes.some(\n\t\t\t(change) => change.type === \"add\" || change.type === \"remove\",\n\t\t);\n\n\t\tif (shouldValidate) {\n\t\t\tget().validateWorkflow();\n\t\t}\n\t},\n\tonConnect: (connection) => {\n\t\tconst valid = isValidConnection({\n\t\t\tsourceNodeId: connection.source || \"\",\n\t\t\tsourceHandle: connection.sourceHandle ?? null,\n\t\t\ttargetNodeId: connection.target || \"\",\n\t\t\ttargetHandle: connection.targetHandle ?? null,\n\t\t\tnodes: get().nodes,\n\t\t\tedges: get().edges,\n\t\t});\n\n\t\tif (!valid) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newEdge = addEdge({ ...connection, type: \"status\" }, get().edges);\n\n\t\tif (!connection.sourceHandle) {\n\t\t\tthrow new Error(\"Source handle not found\");\n\t\t}\n\n\t\tset({\n\t\t\tedges: newEdge,\n\t\t});\n\t\tget().validateWorkflow();\n\t},\n\tgetNodeById: (nodeId) => {\n\t\tconst node = get().nodes.find((node) => node.id === nodeId);\n\t\treturn node || null;\n\t},\n\tgetWorkflowData: () => ({\n\t\tnodes: get().nodes,\n\t\tedges: get().edges,\n\t}),\n\tcreateNode(nodeType, position) {\n\t\tconst definition = getNodeDefinition(nodeType);\n\t\tif (!definition) {\n\t\t\tthrow new Error(`Unknown node type: ${nodeType}`);\n\t\t}\n\t\tconst newNode = definition.client.create(position);\n\t\tset((state) => ({\n\t\t\tnodes: [...state.nodes, newNode],\n\t\t}));\n\t\tget().validateWorkflow();\n\t\treturn newNode;\n\t},\n\tupdateNode({ id, nodeType, data }) {\n\t\tset((state) => ({\n\t\t\tnodes: state.nodes.map((node) => {\n\t\t\t\tif (node.id === id && isNodeOfType(node, nodeType)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...node,\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t...node.data,\n\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn node;\n\t\t\t}),\n\t\t}));\n\t\tget().validateWorkflow();\n\t},\n\tdeleteNode(id) {\n\t\tconst node = get().nodes.find((n) => n.id === id);\n\t\tif (node?.type === \"start\") {\n\t\t\treturn;\n\t\t}\n\n\t\tset({\n\t\t\tnodes: get().nodes.filter((node) => node.id !== id),\n\t\t\tedges: get().edges.filter(\n\t\t\t\t(edge) => edge.source !== id && edge.target !== id,\n\t\t\t),\n\t\t});\n\t\tget().validateWorkflow();\n\t},\n\tresetNodeStatuses: () => {\n\t\tset((state) => ({\n\t\t\tnodes: state.nodes.map((node) => ({\n\t\t\t\t...node,\n\t\t\t\tdata: {\n\t\t\t\t\t...node.data,\n\t\t\t\t\tstatus: \"idle\",\n\t\t\t\t},\n\t\t\t})) as FlowNode[],\n\t\t}));\n\t},\n\tvalidateWorkflow: () => {\n\t\tconst { nodes, edges } = get();\n\t\tconst result = validateWorkflowFn(nodes, edges);\n\n\t\tconst updatedNodes = nodes.map((node) => {\n\t\t\tconst nodeErrors = getErrorsForNode(node.id, result.errors);\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tdata: {\n\t\t\t\t\t...node.data,\n\t\t\t\t\tvalidationErrors:\n\t\t\t\t\t\tnodeErrors.length > 0 ? nodeErrors : undefined,\n\t\t\t\t},\n\t\t\t} as FlowNode;\n\t\t});\n\n\t\tconst updatedEdges = edges.map((edge) => {\n\t\t\tconst edgeErrors = getErrorsForEdge(edge.id, result.errors);\n\t\t\treturn {\n\t\t\t\t...edge,\n\t\t\t\tdata: {\n\t\t\t\t\t...edge.data,\n\t\t\t\t\tvalidationErrors:\n\t\t\t\t\t\tedgeErrors.length > 0 ? edgeErrors : undefined,\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\n\t\tset({\n\t\t\tnodes: updatedNodes,\n\t\t\tedges: updatedEdges,\n\t\t\tvalidationState: {\n\t\t\t\tvalid: result.valid,\n\t\t\t\terrors: result.errors,\n\t\t\t\twarnings: result.warnings,\n\t\t\t\tlastValidated: Date.now(),\n\t\t\t},\n\t\t});\n\t},\n\tcanConnectHandle: ({\n\t\tnodeId,\n\t\thandleId,\n\t\ttype,\n\t}: {\n\t\tnodeId: string;\n\t\thandleId: string;\n\t\ttype: \"source\" | \"target\";\n\t}) => {\n\t\tconst { nodes, edges } = get();\n\t\treturn canConnectHandle({ nodeId, handleId, type, nodes, edges });\n\t},\n}));\n\nexport { useWorkflow };\n",
			"type": "registry:hook",
			"target": "hooks/workflow/use-workflow.ts"
		}
	],
	"envVars": {
		"OPENAI_API_KEY": ""
	},
	"docs": "Get an OpenAI API key from https://platform.openai.com/ and add it to the environment variables file and run the dev server. \n\nLearn more about how to use the Vercel AI SDK https://ai-sdk.dev/docs/introduction.",
	"categories": ["workflow"]
}
