diff --git a/app/w/[id]/components/workflow-block/components/sub-block/components/tool-input.tsx b/app/w/[id]/components/workflow-block/components/sub-block/components/tool-input.tsx
index 90eed2838b..44e51f4c2d 100644
--- a/app/w/[id]/components/workflow-block/components/sub-block/components/tool-input.tsx
+++ b/app/w/[id]/components/workflow-block/components/sub-block/components/tool-input.tsx
@@ -39,7 +39,7 @@ interface ToolParam {
// Assumes the first tool in the access array is the tool to be used
// TODO: Switch to getting tools instead of tool blocks once we switch to providers
const getToolIdFromBlock = (blockType: string): string | undefined => {
- const block = getAllBlocks().find((block) => block.type === blockType)
+ const block = getAllBlocks().find((block) => block.id === blockType)
return block?.tools.access[0]
}
@@ -62,7 +62,7 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
const [open, setOpen] = useState(false)
const isWide = useWorkflowStore((state) => state.blocks[blockId]?.isWide)
- const toolBlocks = getAllBlocks().filter((block) => block.toolbar.category === 'tools')
+ const toolBlocks = getAllBlocks().filter((block) => block.category === 'tools')
const selectedTools: StoredTool[] =
Array.isArray(value) && value.length > 0 && typeof value[0] === 'object'
@@ -71,15 +71,15 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
const handleSelectTool = (toolBlock: (typeof toolBlocks)[0]) => {
// Check if tool already exists
- if (selectedTools.some((tool) => tool.type === toolBlock.type)) {
+ if (selectedTools.some((tool) => tool.type === toolBlock.id)) {
setOpen(false)
return
}
- const toolId = getToolIdFromBlock(toolBlock.type)
+ const toolId = getToolIdFromBlock(toolBlock.id)
const newTool: StoredTool = {
- type: toolBlock.type,
- title: toolBlock.toolbar.title,
+ type: toolBlock.id,
+ title: toolBlock.name,
params: {},
isExpanded: true,
}
@@ -135,12 +135,6 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
return
}
- // Helper function to get the icon component for a tool type
- const getToolIcon = (type: string) => {
- const toolBlock = toolBlocks.find((block) => block.type === type)
- return toolBlock?.toolbar.icon
- }
-
return (
{selectedTools.length === 0 ? (
@@ -161,17 +155,17 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
{toolBlocks.map((block) => (
handleSelectTool(block)}
className="flex items-center gap-2 cursor-pointer"
>
-
+
- {block.toolbar.title}
+ {block.name}
))}
@@ -182,7 +176,7 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
) : (
{selectedTools.map((tool) => {
- const toolBlock = toolBlocks.find((block) => block.type === tool.type)
+ const toolBlock = toolBlocks.find((block) => block.id === tool.type)
const toolId = getToolIdFromBlock(tool.type)
const requiredParams = toolId ? getRequiredToolParams(toolId) : []
@@ -199,12 +193,9 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
@@ -278,17 +269,17 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
{toolBlocks.map((block) => (
handleSelectTool(block)}
className="flex items-center gap-2 cursor-pointer"
>
-
+
- {block.toolbar.title}
+ {block.name}
))}
diff --git a/app/w/[id]/components/workflow-block/workflow-block.tsx b/app/w/[id]/components/workflow-block/workflow-block.tsx
index bc1228033f..1098147857 100644
--- a/app/w/[id]/components/workflow-block/workflow-block.tsx
+++ b/app/w/[id]/components/workflow-block/workflow-block.tsx
@@ -21,7 +21,6 @@ interface WorkflowBlockProps {
// Combine both interfaces into a single component
export function WorkflowBlock({ id, data, selected }: NodeProps
) {
const { type, config, name } = data
- const { toolbar, workflow } = config
// State management
const [isConnecting, setIsConnecting] = useState(false)
@@ -146,7 +145,7 @@ export function WorkflowBlock({ id, data, selected }: NodeProps {
@@ -209,9 +208,9 @@ export function WorkflowBlock({ id, data, selected }: NodeProps
-
+
{isEditing ? (
b.type === data.type).length + 1
+ const name = `${blockConfig.name} ${
+ Object.values(blocks).filter((b) => b.id === data.type).length + 1
}`
addBlock(id, data.type, name, position)
diff --git a/app/w/components/console/components/console-entry/console-entry.tsx b/app/w/components/console/components/console-entry/console-entry.tsx
index e129875a4d..2a8989c659 100644
--- a/app/w/components/console/components/console-entry/console-entry.tsx
+++ b/app/w/components/console/components/console-entry/console-entry.tsx
@@ -26,7 +26,7 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
return getBlock(entry.blockType)
}, [entry.blockType])
- const BlockIcon = blockConfig?.toolbar.icon
+ const BlockIcon = blockConfig?.icon
const statusIcon = entry.error ? (
diff --git a/app/w/components/console/components/json-view/json-view.tsx b/app/w/components/console/components/json-view/json-view.tsx
index 2cc05c46fe..98891dd556 100644
--- a/app/w/components/console/components/json-view/json-view.tsx
+++ b/app/w/components/console/components/json-view/json-view.tsx
@@ -1,5 +1,4 @@
import { useEffect, useState } from 'react'
-import { ChevronDown, ChevronRight } from 'lucide-react'
import { Button } from '@/components/ui/button'
interface JSONViewProps {
diff --git a/app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx b/app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx
index e35725c0aa..66e8c9c9fe 100644
--- a/app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx
+++ b/app/w/components/toolbar/components/toolbar-block/toolbar-block.tsx
@@ -6,7 +6,7 @@ export type ToolbarBlockProps = {
export function ToolbarBlock({ config }: ToolbarBlockProps) {
const handleDragStart = (e: React.DragEvent) => {
- e.dataTransfer.setData('application/json', JSON.stringify({ type: config.type }))
+ e.dataTransfer.setData('application/json', JSON.stringify({ type: config.id }))
e.dataTransfer.effectAllowed = 'move'
}
@@ -18,17 +18,17 @@ export function ToolbarBlock({ config }: ToolbarBlockProps) {
>
-
-
{config.toolbar.title}
-
{config.toolbar.description}
+
{config.name}
+
{config.description}
)
diff --git a/app/w/components/toolbar/toolbar.tsx b/app/w/components/toolbar/toolbar.tsx
index 57048f7fec..af2b618ff4 100644
--- a/app/w/components/toolbar/toolbar.tsx
+++ b/app/w/components/toolbar/toolbar.tsx
@@ -23,8 +23,7 @@ export function Toolbar() {
const query = searchQuery.toLowerCase()
return getAllBlocks().filter(
(block) =>
- block.toolbar.title.toLowerCase().includes(query) ||
- block.toolbar.description.toLowerCase().includes(query)
+ block.name.toLowerCase().includes(query) || block.description.toLowerCase().includes(query)
)
}, [searchQuery, activeTab])
@@ -70,7 +69,7 @@ export function Toolbar() {
{blocks.map((block) => (
-
+
))}
diff --git a/app/w/hooks/use-workflow-execution.ts b/app/w/hooks/use-workflow-execution.ts
index 632c4313a8..2a14cea56c 100644
--- a/app/w/hooks/use-workflow-execution.ts
+++ b/app/w/hooks/use-workflow-execution.ts
@@ -67,7 +67,7 @@ export function useWorkflowExecution() {
endedAt: log.endedAt,
workflowId: activeWorkflowId,
timestamp: log.startedAt,
- blockName: log.blockTitle,
+ blockName: log.blockName,
blockType: log.blockType,
})
})
@@ -76,7 +76,7 @@ export function useWorkflowExecution() {
if (result.logs) {
console.group('Detailed Block Logs')
result.logs.forEach((log) => {
- console.log(`Block ${log.blockTitle}: Success=${log.success}`, {
+ console.log(`Block ${log.blockName}: Success=${log.success}`, {
output: log.output,
error: log.error,
durationMs: log.durationMs,
diff --git a/blocks/blocks/agent.ts b/blocks/blocks/agent.ts
index 85bf15bc35..2e220393bf 100644
--- a/blocks/blocks/agent.ts
+++ b/blocks/blocks/agent.ts
@@ -23,14 +23,64 @@ interface AgentResponse extends ToolResponse {
}
export const AgentBlock: BlockConfig
= {
- type: 'agent',
- toolbar: {
- title: 'Agent',
- description: 'Build an agent',
- bgColor: '#7F2FFF',
- icon: AgentIcon,
- category: 'blocks',
- },
+ id: 'agent',
+ name: 'Agent',
+ description: 'Build an agent',
+ category: 'blocks',
+ bgColor: '#7F2FFF',
+ icon: AgentIcon,
+ subBlocks: [
+ {
+ id: 'systemPrompt',
+ title: 'System Prompt',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter system prompt...',
+ },
+ {
+ id: 'context',
+ title: 'User Prompt',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter context or user message...',
+ },
+ {
+ id: 'model',
+ title: 'Model',
+ type: 'dropdown',
+ layout: 'half',
+ options: Object.keys(MODEL_TOOLS),
+ },
+ {
+ id: 'temperature',
+ title: 'Temperature',
+ type: 'slider',
+ layout: 'half',
+ min: 0,
+ max: 2,
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your API key',
+ password: true,
+ connectionDroppable: false,
+ },
+ {
+ id: 'tools',
+ title: 'Tools',
+ type: 'tool-input',
+ layout: 'full',
+ },
+ {
+ id: 'responseFormat',
+ title: 'Response Format',
+ type: 'code',
+ layout: 'full',
+ },
+ ],
tools: {
access: [
'openai_chat',
@@ -54,165 +104,97 @@ export const AgentBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- systemPrompt: { type: 'string', required: true },
- context: { type: 'string', required: false },
- model: { type: 'string', required: true },
- apiKey: { type: 'string', required: true },
- responseFormat: {
- type: 'json',
- required: false,
- description:
- 'Define the expected response format. If not provided, returns plain text content.',
- schema: {
- type: 'object',
- properties: {
- fields: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- description: 'Name of the field',
- },
- type: {
- type: 'string',
- enum: ['string', 'number', 'boolean', 'array', 'object'],
- description: 'Type of the field',
- },
- isArray: {
- type: 'boolean',
- description: 'Whether this field contains multiple values',
- },
- items: {
- type: 'object',
- description: 'Schema for array items (required when isArray is true)',
+ inputs: {
+ systemPrompt: { type: 'string', required: true },
+ context: { type: 'string', required: false },
+ model: { type: 'string', required: true },
+ apiKey: { type: 'string', required: true },
+ responseFormat: {
+ type: 'json',
+ required: false,
+ description:
+ 'Define the expected response format. If not provided, returns plain text content.',
+ schema: {
+ type: 'object',
+ properties: {
+ fields: {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ name: {
+ type: 'string',
+ description: 'Name of the field',
+ },
+ type: {
+ type: 'string',
+ enum: ['string', 'number', 'boolean', 'array', 'object'],
+ description: 'Type of the field',
+ },
+ isArray: {
+ type: 'boolean',
+ description: 'Whether this field contains multiple values',
+ },
+ items: {
+ type: 'object',
+ description: 'Schema for array items (required when isArray is true)',
+ properties: {
+ type: {
+ type: 'string',
+ enum: ['string', 'number', 'boolean', 'object'],
+ },
properties: {
- type: {
- type: 'string',
- enum: ['string', 'number', 'boolean', 'object'],
- },
- properties: {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- name: { type: 'string' },
- type: {
- type: 'string',
- enum: ['string', 'number', 'boolean'],
- },
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ name: { type: 'string' },
+ type: {
+ type: 'string',
+ enum: ['string', 'number', 'boolean'],
},
- required: ['name', 'type'],
},
+ required: ['name', 'type'],
},
},
},
- description: {
- type: 'string',
- description: 'Description of what this field represents',
- },
},
- required: ['name', 'type'],
- additionalProperties: false,
+ description: {
+ type: 'string',
+ description: 'Description of what this field represents',
+ },
},
+ required: ['name', 'type'],
+ additionalProperties: false,
},
},
- required: ['fields'],
},
+ required: ['fields'],
},
- temperature: { type: 'number', required: false },
- tools: { type: 'json', required: false },
},
- outputs: {
- response: {
- type: {
- content: 'string',
- model: 'string',
- tokens: 'any',
- toolCalls: 'any',
- },
- dependsOn: {
- subBlockId: 'responseFormat',
- condition: {
- whenEmpty: {
- content: 'string',
- model: 'string',
- tokens: 'any',
- toolCalls: 'any',
- },
- whenFilled: 'json',
+ temperature: { type: 'number', required: false },
+ tools: { type: 'json', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ model: 'string',
+ tokens: 'any',
+ toolCalls: 'any',
+ },
+ dependsOn: {
+ subBlockId: 'responseFormat',
+ condition: {
+ whenEmpty: {
+ content: 'string',
+ model: 'string',
+ tokens: 'any',
+ toolCalls: 'any',
},
+ whenFilled: 'json',
},
},
},
- subBlocks: [
- {
- id: 'systemPrompt',
- title: 'System Prompt',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter system prompt...',
- },
- {
- id: 'context',
- title: 'User Prompt',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter context or user message...',
- },
- {
- id: 'model',
- title: 'Model',
- type: 'dropdown',
- layout: 'half',
- options: Object.keys(MODEL_TOOLS),
- },
- {
- id: 'temperature',
- title: 'Temperature',
- type: 'slider',
- layout: 'half',
- min: 0,
- max: 2,
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your API key',
- password: true,
- connectionDroppable: false,
- },
- {
- id: 'tools',
- title: 'Tools',
- type: 'tool-input',
- layout: 'full',
- },
- {
- id: 'responseFormat',
- title: 'Response Format',
- type: 'code',
- layout: 'full',
- placeholder: `{
- "fields": [
- {
- "name": "sentiment",
- "type": "string",
- "description": "The sentiment of the text (positive, negative, neutral)"
- },
- {
- "name": "score",
- "type": "number",
- "description": "Confidence score between 0 and 1"
- }
- ]
-}`,
- },
- ],
},
}
diff --git a/blocks/blocks/api.ts b/blocks/blocks/api.ts
index 917a39f35b..fa99674578 100644
--- a/blocks/blocks/api.ts
+++ b/blocks/blocks/api.ts
@@ -3,61 +3,57 @@ import { RequestResponse } from '@/tools/http/request'
import { BlockConfig } from '../types'
export const ApiBlock: BlockConfig = {
- type: 'api',
- toolbar: {
- title: 'API',
- description: 'Use any API',
- bgColor: '#2F55FF',
- icon: ApiIcon,
- category: 'blocks',
- },
+ id: 'api',
+ name: 'API',
+ description: 'Use any API',
+ category: 'blocks',
+ bgColor: '#2F55FF',
+ icon: ApiIcon,
+ subBlocks: [
+ {
+ id: 'url',
+ title: 'URL',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter URL',
+ },
+ {
+ id: 'method',
+ title: 'Method',
+ type: 'dropdown',
+ layout: 'half',
+ options: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
+ },
+ {
+ id: 'headers',
+ title: 'Headers',
+ type: 'table',
+ layout: 'full',
+ columns: ['Key', 'Value'],
+ },
+ {
+ id: 'body',
+ title: 'Body',
+ type: 'code',
+ layout: 'full',
+ },
+ ],
tools: {
access: ['http_request'],
},
- workflow: {
- inputs: {
- url: { type: 'string', required: true },
- method: { type: 'string', required: true },
- headers: { type: 'json', required: false },
- body: { type: 'json', required: false },
- },
- outputs: {
- response: {
- type: {
- data: 'any',
- status: 'number',
- headers: 'json',
- },
+ inputs: {
+ url: { type: 'string', required: true },
+ method: { type: 'string', required: true },
+ headers: { type: 'json', required: false },
+ body: { type: 'json', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ data: 'any',
+ status: 'number',
+ headers: 'json',
},
},
- subBlocks: [
- {
- id: 'url',
- title: 'URL',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter URL',
- },
- {
- id: 'method',
- title: 'Method',
- type: 'dropdown',
- layout: 'half',
- options: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
- },
- {
- id: 'headers',
- title: 'Headers',
- type: 'table',
- layout: 'full',
- columns: ['Key', 'Value'],
- },
- {
- id: 'body',
- title: 'Body',
- type: 'code',
- layout: 'full',
- },
- ],
},
}
diff --git a/blocks/blocks/condition.ts b/blocks/blocks/condition.ts
index e4d17f376f..b34d17e88d 100644
--- a/blocks/blocks/condition.ts
+++ b/blocks/blocks/condition.ts
@@ -3,36 +3,33 @@ import { CodeExecutionOutput } from '@/tools/function/execute'
import { BlockConfig } from '../types'
export const ConditionBlock: BlockConfig = {
- type: 'condition',
- toolbar: {
- title: 'Condition',
- description: 'Add a condition',
- bgColor: '#FF972F',
- icon: ConditionalIcon,
- category: 'blocks',
- },
+ id: 'condition',
+ name: 'Condition',
+ description: 'Add a condition',
+ longDescription: 'Add a condition to the workflow',
+ bgColor: '#FF972F',
+ icon: ConditionalIcon,
+ category: 'blocks',
+ subBlocks: [
+ {
+ id: 'conditions',
+ type: 'condition-input',
+ layout: 'full',
+ },
+ ],
tools: {
access: ['function_execute'],
},
- workflow: {
- inputs: {
- code: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- result: 'any',
- stdout: 'string',
- executionTime: 'number',
- },
+ inputs: {
+ code: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ result: 'any',
+ stdout: 'string',
+ executionTime: 'number',
},
},
- subBlocks: [
- {
- id: 'conditions',
- type: 'condition-input',
- layout: 'full',
- },
- ],
},
}
diff --git a/blocks/blocks/crewai.ts b/blocks/blocks/crewai.ts
index 74fa3f59c3..58b2cef27f 100644
--- a/blocks/blocks/crewai.ts
+++ b/blocks/blocks/crewai.ts
@@ -3,63 +3,59 @@ import { VisionResponse } from '@/tools/crewai/vision'
import { BlockConfig } from '../types'
export const CrewAIVisionBlock: BlockConfig = {
- type: 'crewai_vision',
- toolbar: {
- title: 'CrewAI Vision Tool',
- description: 'Analyze images with vision models',
- bgColor: '#FF5A50',
- icon: CrewAIIcon,
- category: 'tools',
- },
+ id: 'crewai_vision',
+ name: 'CrewAI Vision',
+ description: 'Analyze images with vision models',
+ category: 'tools',
+ bgColor: '#FF5A50',
+ icon: CrewAIIcon,
+ subBlocks: [
+ {
+ id: 'imageUrl',
+ title: 'Image URL',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter publicly accessible image URL',
+ },
+ {
+ id: 'model',
+ title: 'Vision Model',
+ type: 'dropdown',
+ layout: 'half',
+ options: ['gpt-4o', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229'],
+ },
+ {
+ id: 'prompt',
+ title: 'Prompt',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter prompt for image analysis (optional)',
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your API key',
+ password: true,
+ },
+ ],
tools: {
access: ['crewai_vision'],
},
- workflow: {
- inputs: {
- apiKey: { type: 'string', required: true },
- imageUrl: { type: 'string', required: true },
- model: { type: 'string', required: false },
- prompt: { type: 'string', required: false },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- model: 'any',
- tokens: 'any',
- },
+ inputs: {
+ apiKey: { type: 'string', required: true },
+ imageUrl: { type: 'string', required: true },
+ model: { type: 'string', required: false },
+ prompt: { type: 'string', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ model: 'any',
+ tokens: 'any',
},
},
- subBlocks: [
- {
- id: 'imageUrl',
- title: 'Image URL',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter publicly accessible image URL',
- },
- {
- id: 'model',
- title: 'Vision Model',
- type: 'dropdown',
- layout: 'half',
- options: ['gpt-4o', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229'],
- },
- {
- id: 'prompt',
- title: 'Prompt',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter prompt for image analysis (optional)',
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your API key',
- password: true,
- },
- ],
},
}
diff --git a/blocks/blocks/evaluator.ts b/blocks/blocks/evaluator.ts
index b97f7c20ca..3fa655b577 100644
--- a/blocks/blocks/evaluator.ts
+++ b/blocks/blocks/evaluator.ts
@@ -56,14 +56,60 @@ const generateResponseFormat = (metrics: Metric[]) => ({
})
export const EvaluatorBlock: BlockConfig = {
- type: 'evaluator',
- toolbar: {
- title: 'Evaluator',
- description: 'Evaluate content',
- bgColor: '#2FA1FF',
- icon: ChartBarIcon,
- category: 'blocks',
- },
+ id: 'evaluator',
+ name: 'Evaluator',
+ description: 'Evaluate content',
+ category: 'blocks',
+ bgColor: '#2FA1FF',
+ icon: ChartBarIcon,
+ subBlocks: [
+ {
+ id: 'metrics',
+ title: 'Evaluation Metrics',
+ type: 'eval-input',
+ layout: 'full',
+ },
+ {
+ id: 'content',
+ title: 'Content',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter the content to evaluate',
+ },
+ {
+ id: 'model',
+ title: 'Model',
+ type: 'dropdown',
+ layout: 'half',
+ options: Object.keys(MODEL_TOOLS),
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your API key',
+ password: true,
+ connectionDroppable: false,
+ },
+ {
+ id: 'systemPrompt',
+ title: 'System Prompt',
+ type: 'code',
+ layout: 'full',
+ hidden: true,
+ value: (params: Record) => {
+ const metrics = params.metrics || []
+ const content = params.content || ''
+ const responseFormat = generateResponseFormat(metrics)
+
+ return JSON.stringify({
+ systemPrompt: generateEvaluatorPrompt(metrics, content),
+ responseFormat,
+ })
+ },
+ },
+ ],
tools: {
access: [
'openai_chat',
@@ -87,116 +133,66 @@ export const EvaluatorBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- metrics: {
- type: 'json' as ParamType,
- required: true,
- description: 'Array of metrics to evaluate against',
- schema: {
- type: 'array',
- properties: {},
- items: {
- type: 'object',
- properties: {
- name: {
- type: 'string',
- description: 'Name of the metric',
- },
- description: {
- type: 'string',
- description: 'Description of what this metric measures',
- },
- range: {
- type: 'object',
- properties: {
- min: {
- type: 'number',
- description: 'Minimum possible score',
- },
- max: {
- type: 'number',
- description: 'Maximum possible score',
- },
+ inputs: {
+ metrics: {
+ type: 'json' as ParamType,
+ required: true,
+ description: 'Array of metrics to evaluate against',
+ schema: {
+ type: 'array',
+ properties: {},
+ items: {
+ type: 'object',
+ properties: {
+ name: {
+ type: 'string',
+ description: 'Name of the metric',
+ },
+ description: {
+ type: 'string',
+ description: 'Description of what this metric measures',
+ },
+ range: {
+ type: 'object',
+ properties: {
+ min: {
+ type: 'number',
+ description: 'Minimum possible score',
+ },
+ max: {
+ type: 'number',
+ description: 'Maximum possible score',
},
- required: ['min', 'max'],
},
+ required: ['min', 'max'],
},
- required: ['name', 'description', 'range'],
- },
- },
- },
- model: { type: 'string' as ParamType, required: true },
- apiKey: { type: 'string' as ParamType, required: true },
- content: { type: 'string' as ParamType, required: true },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- model: 'string',
- tokens: 'any',
- },
- dependsOn: {
- subBlockId: 'metrics',
- condition: {
- whenEmpty: {
- content: 'string',
- model: 'string',
- tokens: 'any',
- },
- whenFilled: 'json',
},
+ required: ['name', 'description', 'range'],
},
},
},
- subBlocks: [
- {
- id: 'metrics',
- title: 'Evaluation Metrics',
- type: 'eval-input',
- layout: 'full',
+ model: { type: 'string' as ParamType, required: true },
+ apiKey: { type: 'string' as ParamType, required: true },
+ content: { type: 'string' as ParamType, required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ model: 'string',
+ tokens: 'any',
},
- {
- id: 'content',
- title: 'Content',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter the content to evaluate',
- },
- {
- id: 'model',
- title: 'Model',
- type: 'dropdown',
- layout: 'half',
- options: Object.keys(MODEL_TOOLS),
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your API key',
- password: true,
- connectionDroppable: false,
- },
- {
- id: 'systemPrompt',
- title: 'System Prompt',
- type: 'code',
- layout: 'full',
- hidden: true,
- value: (params: Record) => {
- const metrics = params.metrics || []
- const content = params.content || ''
- const responseFormat = generateResponseFormat(metrics)
-
- return JSON.stringify({
- systemPrompt: generateEvaluatorPrompt(metrics, content),
- responseFormat,
- })
+ dependsOn: {
+ subBlockId: 'metrics',
+ condition: {
+ whenEmpty: {
+ content: 'string',
+ model: 'string',
+ tokens: 'any',
+ },
+ whenFilled: 'json',
},
},
- ],
+ },
},
}
diff --git a/blocks/blocks/firecrawl.ts b/blocks/blocks/firecrawl.ts
index 8ae57722a0..83a5e5a705 100644
--- a/blocks/blocks/firecrawl.ts
+++ b/blocks/blocks/firecrawl.ts
@@ -2,55 +2,51 @@ import { FirecrawlIcon } from '@/components/icons'
import { ScrapeResponse } from '@/tools/firecrawl/scrape'
import { BlockConfig } from '../types'
-export const FirecrawlScrapeBlock: BlockConfig = {
- type: 'firecrawl_scrape',
- toolbar: {
- title: 'Firecrawl Scraper',
- description: 'Scrape website content',
- bgColor: '#181C1E',
- icon: FirecrawlIcon,
- category: 'tools',
- },
+export const FirecrawlBlock: BlockConfig = {
+ id: 'firecrawl',
+ name: 'Firecrawl',
+ description: 'Scrape website content',
+ category: 'tools',
+ bgColor: '#181C1E',
+ icon: FirecrawlIcon,
+ subBlocks: [
+ {
+ id: 'url',
+ title: 'Website URL',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter the webpage URL to scrape',
+ },
+ {
+ id: 'onlyMainContent',
+ title: 'Only Main Content',
+ type: 'switch',
+ layout: 'half',
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your Firecrawl API key',
+ password: true,
+ },
+ ],
tools: {
access: ['firecrawl_scrape'],
},
- workflow: {
- inputs: {
- apiKey: { type: 'string', required: true },
- url: { type: 'string', required: true },
- scrapeOptions: { type: 'json', required: false },
- },
- outputs: {
- response: {
- type: {
- markdown: 'string',
- html: 'any',
- metadata: 'json',
- },
+ inputs: {
+ apiKey: { type: 'string', required: true },
+ url: { type: 'string', required: true },
+ scrapeOptions: { type: 'json', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ markdown: 'string',
+ html: 'any',
+ metadata: 'json',
},
},
- subBlocks: [
- {
- id: 'url',
- title: 'Website URL',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter the webpage URL to scrape',
- },
- {
- id: 'onlyMainContent',
- title: 'Only Main Content',
- type: 'switch',
- layout: 'half',
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your Firecrawl API key',
- password: true,
- },
- ],
},
}
diff --git a/blocks/blocks/function.ts b/blocks/blocks/function.ts
index 5f8bb987ae..550a686c3f 100644
--- a/blocks/blocks/function.ts
+++ b/blocks/blocks/function.ts
@@ -3,38 +3,34 @@ import { CodeExecutionOutput } from '@/tools/function/execute'
import { BlockConfig } from '../types'
export const FunctionBlock: BlockConfig = {
- type: 'function',
- toolbar: {
- title: 'Function',
- description: 'Run custom logic',
- bgColor: '#FF402F',
- icon: CodeIcon,
- category: 'blocks',
- },
+ id: 'function',
+ name: 'Function',
+ description: 'Run custom logic',
+ category: 'blocks',
+ bgColor: '#FF402F',
+ icon: CodeIcon,
+ subBlocks: [
+ {
+ id: 'code',
+ type: 'code',
+ layout: 'full',
+ },
+ ],
tools: {
access: ['function_execute'],
},
- workflow: {
- inputs: {
- code: { type: 'string', required: true },
- timeout: { type: 'number', required: false },
- memoryLimit: { type: 'number', required: false },
- },
- outputs: {
- response: {
- type: {
- result: 'any',
- stdout: 'string',
- executionTime: 'number',
- },
+ inputs: {
+ code: { type: 'string', required: true },
+ timeout: { type: 'number', required: false },
+ memoryLimit: { type: 'number', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ result: 'any',
+ stdout: 'string',
+ executionTime: 'number',
},
},
- subBlocks: [
- {
- id: 'code',
- type: 'code',
- layout: 'full',
- },
- ],
},
}
diff --git a/blocks/blocks/github.ts b/blocks/blocks/github.ts
index e70bb641e4..d40a6ec05c 100644
--- a/blocks/blocks/github.ts
+++ b/blocks/blocks/github.ts
@@ -3,57 +3,53 @@ import { GithubIcon } from '../../components/icons'
import { BlockConfig } from '../types'
export const GitHubBlock: BlockConfig = {
- type: 'github_repo_info',
- toolbar: {
- title: 'GitHub Repository',
- description: 'Fetch GitHub repository',
- bgColor: '#181C1E',
- icon: GithubIcon,
- category: 'tools',
- },
+ id: 'github',
+ name: 'GitHub',
+ description: 'Fetch GitHub repository',
+ category: 'tools',
+ bgColor: '#181C1E',
+ icon: GithubIcon,
+ subBlocks: [
+ {
+ id: 'owner',
+ title: 'Repository Owner',
+ type: 'short-input',
+ layout: 'half',
+ placeholder: 'e.g., microsoft',
+ },
+ {
+ id: 'repo',
+ title: 'Repository Name',
+ type: 'short-input',
+ layout: 'half',
+ placeholder: 'e.g., vscode',
+ },
+ {
+ id: 'apiKey',
+ title: 'GitHub Token',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter GitHub Token',
+ password: true,
+ },
+ ],
tools: {
access: ['github_repoinfo'],
},
- workflow: {
- inputs: {
- owner: { type: 'string', required: true },
- repo: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- name: 'string',
- description: 'string',
- stars: 'number',
- forks: 'number',
- openIssues: 'number',
- language: 'string',
- },
+ inputs: {
+ owner: { type: 'string', required: true },
+ repo: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ name: 'string',
+ description: 'string',
+ stars: 'number',
+ forks: 'number',
+ openIssues: 'number',
+ language: 'string',
},
},
- subBlocks: [
- {
- id: 'owner',
- title: 'Repository Owner',
- type: 'short-input',
- layout: 'half',
- placeholder: 'e.g., microsoft',
- },
- {
- id: 'repo',
- title: 'Repository Name',
- type: 'short-input',
- layout: 'half',
- placeholder: 'e.g., vscode',
- },
- {
- id: 'apiKey',
- title: 'GitHub Token',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter GitHub Token',
- password: true,
- },
- ],
},
}
diff --git a/blocks/blocks/gmail.ts b/blocks/blocks/gmail.ts
index 16970f55c5..601e437e4c 100644
--- a/blocks/blocks/gmail.ts
+++ b/blocks/blocks/gmail.ts
@@ -3,14 +3,86 @@ import { GmailToolResponse } from '@/tools/gmail/types'
import { BlockConfig } from '../types'
export const GmailBlock: BlockConfig = {
- type: 'gmail_block',
- toolbar: {
- title: 'Gmail',
- description: 'Send, read, and search Gmail messages',
- bgColor: '#F14537',
- icon: GmailIcon,
- category: 'tools',
- },
+ id: 'gmail',
+ name: 'Gmail',
+ description: 'Send, read, and search Gmail messages',
+ category: 'tools',
+ bgColor: '#F14537',
+ icon: GmailIcon,
+ subBlocks: [
+ // Operation selector
+ {
+ id: 'operation',
+ title: 'Operation',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'Send Email', id: 'send_gmail' },
+ { label: 'Read Email', id: 'read_gmail' },
+ { label: 'Search Emails', id: 'search_gmail' },
+ ],
+ },
+ // OAuth Token
+ {
+ id: 'accessToken',
+ title: 'Access Token',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter Gmail OAuth token',
+ password: true,
+ },
+ // Send Email Fields
+ {
+ id: 'to',
+ title: 'To',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Recipient email address',
+ condition: { field: 'operation', value: 'send_gmail' },
+ },
+ {
+ id: 'subject',
+ title: 'Subject',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Email subject',
+ condition: { field: 'operation', value: 'send_gmail' },
+ },
+ {
+ id: 'body',
+ title: 'Body',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Email content',
+ condition: { field: 'operation', value: 'send_gmail' },
+ },
+ // Read Email Fields
+ {
+ id: 'messageId',
+ title: 'Message ID',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter message ID to read',
+ condition: { field: 'operation', value: 'read_gmail' },
+ },
+ // Search Fields
+ {
+ id: 'query',
+ title: 'Search Query',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter search terms',
+ condition: { field: 'operation', value: 'search_gmail' },
+ },
+ {
+ id: 'maxResults',
+ title: 'Max Results',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Maximum number of results (default: 10)',
+ condition: { field: 'operation', value: 'search_gmail' },
+ },
+ ],
tools: {
access: ['gmail_send', 'gmail_read', 'gmail_search'],
config: {
@@ -28,101 +100,25 @@ export const GmailBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- operation: { type: 'string', required: true },
- accessToken: { type: 'string', required: true },
- // Send operation inputs
- to: { type: 'string', required: false },
- subject: { type: 'string', required: false },
- body: { type: 'string', required: false },
- // Read operation inputs
- messageId: { type: 'string', required: false },
- // Search operation inputs
- query: { type: 'string', required: false },
- maxResults: { type: 'number', required: false },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- metadata: 'json',
- },
+ inputs: {
+ operation: { type: 'string', required: true },
+ accessToken: { type: 'string', required: true },
+ // Send operation inputs
+ to: { type: 'string', required: false },
+ subject: { type: 'string', required: false },
+ body: { type: 'string', required: false },
+ // Read operation inputs
+ messageId: { type: 'string', required: false },
+ // Search operation inputs
+ query: { type: 'string', required: false },
+ maxResults: { type: 'number', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ metadata: 'json',
},
},
- subBlocks: [
- // Operation selector
- {
- id: 'operation',
- title: 'Operation',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'Send Email', id: 'send_gmail' },
- { label: 'Read Email', id: 'read_gmail' },
- { label: 'Search Emails', id: 'search_gmail' },
- ],
- },
- // OAuth Token
- {
- id: 'accessToken',
- title: 'Access Token',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter Gmail OAuth token',
- password: true,
- },
- // Send Email Fields
- {
- id: 'to',
- title: 'To',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Recipient email address',
- condition: { field: 'operation', value: 'send_gmail' },
- },
- {
- id: 'subject',
- title: 'Subject',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Email subject',
- condition: { field: 'operation', value: 'send_gmail' },
- },
- {
- id: 'body',
- title: 'Body',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Email content',
- condition: { field: 'operation', value: 'send_gmail' },
- },
- // Read Email Fields
- {
- id: 'messageId',
- title: 'Message ID',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter message ID to read',
- condition: { field: 'operation', value: 'read_gmail' },
- },
- // Search Fields
- {
- id: 'query',
- title: 'Search Query',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter search terms',
- condition: { field: 'operation', value: 'search_gmail' },
- },
- {
- id: 'maxResults',
- title: 'Max Results',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Maximum number of results (default: 10)',
- condition: { field: 'operation', value: 'search_gmail' },
- },
- ],
},
}
diff --git a/blocks/blocks/jina.ts b/blocks/blocks/jina.ts
index 26cc0c3533..5b4ca1ccc9 100644
--- a/blocks/blocks/jina.ts
+++ b/blocks/blocks/jina.ts
@@ -3,59 +3,55 @@ import { ReadUrlResponse } from '@/tools/jina/reader'
import { BlockConfig } from '../types'
export const JinaBlock: BlockConfig = {
- type: 'jina_reader',
- toolbar: {
- title: 'Jina Reader',
- description: 'Convert website content into text',
- bgColor: '#333333',
- icon: JinaAIIcon,
- category: 'tools',
- },
+ id: 'jina',
+ name: 'Jina',
+ description: 'Convert website content into text',
+ category: 'tools',
+ bgColor: '#333333',
+ icon: JinaAIIcon,
+ subBlocks: [
+ {
+ id: 'url',
+ title: 'URL',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter URL to extract content from',
+ },
+ {
+ id: 'options',
+ title: 'Options',
+ type: 'checkbox-list',
+ layout: 'full',
+ options: [
+ { id: 'useReaderLMv2', label: 'Use Reader LM v2' },
+ { id: 'gatherLinks', label: 'Gather Links' },
+ { id: 'jsonResponse', label: 'JSON Response' },
+ ],
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your Jina API key',
+ password: true,
+ },
+ ],
tools: {
access: ['jina_readurl'],
},
- workflow: {
- inputs: {
- url: { type: 'string', required: true },
- useReaderLMv2: { type: 'boolean', required: false },
- gatherLinks: { type: 'boolean', required: false },
- jsonResponse: { type: 'boolean', required: false },
- apiKey: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- },
+ inputs: {
+ url: { type: 'string', required: true },
+ useReaderLMv2: { type: 'boolean', required: false },
+ gatherLinks: { type: 'boolean', required: false },
+ jsonResponse: { type: 'boolean', required: false },
+ apiKey: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
},
},
- subBlocks: [
- {
- id: 'url',
- title: 'URL',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter URL to extract content from',
- },
- {
- id: 'options',
- title: 'Options',
- type: 'checkbox-list',
- layout: 'full',
- options: [
- { id: 'useReaderLMv2', label: 'Use Reader LM v2' },
- { id: 'gatherLinks', label: 'Gather Links' },
- { id: 'jsonResponse', label: 'JSON Response' },
- ],
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your Jina API key',
- password: true,
- },
- ],
},
}
diff --git a/blocks/blocks/notion.ts b/blocks/blocks/notion.ts
index b2152a29e9..22878b4608 100644
--- a/blocks/blocks/notion.ts
+++ b/blocks/blocks/notion.ts
@@ -3,14 +3,47 @@ import { NotionResponse } from '@/tools/notion/read'
import { BlockConfig } from '../types'
export const NotionBlock: BlockConfig = {
- type: 'notion_reader',
- toolbar: {
- title: 'Notion',
- description: 'Read and write to Notion pages and databases',
- bgColor: '#000000',
- icon: NotionIcon,
- category: 'tools',
- },
+ id: 'notion',
+ name: 'Notion',
+ description: 'Read and write to Notion pages and databases',
+ category: 'tools',
+ bgColor: '#000000',
+ icon: NotionIcon,
+ subBlocks: [
+ {
+ id: 'operation',
+ title: 'Operation',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'Read Page', id: 'read_notion' },
+ { label: 'Write Page', id: 'write_notion' },
+ ],
+ },
+ {
+ id: 'pageId',
+ title: 'Page ID',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter Notion page ID',
+ },
+ {
+ id: 'content',
+ title: 'Content',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter content to write (for write operation)',
+ condition: { field: 'operation', value: 'write_notion' },
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your Notion API key',
+ password: true,
+ },
+ ],
tools: {
access: ['notion_read', 'notion_write'],
config: {
@@ -19,55 +52,18 @@ export const NotionBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- pageId: { type: 'string', required: true },
- operation: { type: 'string', required: true },
- content: { type: 'string', required: false },
- apiKey: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- metadata: 'any',
- },
+ inputs: {
+ pageId: { type: 'string', required: true },
+ operation: { type: 'string', required: true },
+ content: { type: 'string', required: false },
+ apiKey: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ metadata: 'any',
},
},
- subBlocks: [
- {
- id: 'operation',
- title: 'Operation',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'Read Page', id: 'read_notion' },
- { label: 'Write Page', id: 'write_notion' },
- ],
- },
- {
- id: 'pageId',
- title: 'Page ID',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter Notion page ID',
- },
- {
- id: 'content',
- title: 'Content',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter content to write (for write operation)',
- condition: { field: 'operation', value: 'write_notion' },
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your Notion API key',
- password: true,
- },
- ],
},
}
diff --git a/blocks/blocks/router.ts b/blocks/blocks/router.ts
index 387e96ced3..e0900b1ee8 100644
--- a/blocks/blocks/router.ts
+++ b/blocks/blocks/router.ts
@@ -86,14 +86,47 @@ Remember: Your response must be ONLY the block ID - no additional text, formatti
}
export const RouterBlock: BlockConfig = {
- type: 'router',
- toolbar: {
- title: 'Router',
- description: 'Route workflow',
- bgColor: '#28C43F',
- icon: ConnectIcon,
- category: 'blocks',
- },
+ id: 'router',
+ name: 'Router',
+ description: 'Route workflow',
+ category: 'blocks',
+ bgColor: '#28C43F',
+ icon: ConnectIcon,
+ subBlocks: [
+ {
+ id: 'prompt',
+ title: 'Prompt',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Route to the correct block based on the input...',
+ },
+ {
+ id: 'model',
+ title: 'Model',
+ type: 'dropdown',
+ layout: 'half',
+ options: Object.keys(MODEL_TOOLS),
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your API key',
+ password: true,
+ connectionDroppable: false,
+ },
+ {
+ id: 'systemPrompt',
+ title: 'System Prompt',
+ type: 'code',
+ layout: 'full',
+ hidden: true,
+ value: (params: Record) => {
+ return generateRouterPrompt(params.prompt || '')
+ },
+ },
+ ],
tools: {
access: [
'openai_chat',
@@ -117,56 +150,19 @@ export const RouterBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- prompt: { type: 'string', required: true },
- model: { type: 'string', required: true },
- apiKey: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- model: 'string',
- tokens: 'any',
- selectedPath: 'json',
- },
+ inputs: {
+ prompt: { type: 'string', required: true },
+ model: { type: 'string', required: true },
+ apiKey: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ model: 'string',
+ tokens: 'any',
+ selectedPath: 'json',
},
},
- subBlocks: [
- {
- id: 'prompt',
- title: 'Prompt',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Route to the correct block based on the input...',
- },
- {
- id: 'model',
- title: 'Model',
- type: 'dropdown',
- layout: 'half',
- options: Object.keys(MODEL_TOOLS),
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your API key',
- password: true,
- connectionDroppable: false,
- },
- {
- id: 'systemPrompt',
- title: 'System Prompt',
- type: 'code',
- layout: 'full',
- hidden: true,
- value: (params: Record) => {
- return generateRouterPrompt(params.prompt || '')
- },
- },
- ],
},
}
diff --git a/blocks/blocks/serper.ts b/blocks/blocks/serper.ts
index 4532416030..c684bc2cc4 100644
--- a/blocks/blocks/serper.ts
+++ b/blocks/blocks/serper.ts
@@ -3,77 +3,73 @@ import { SearchResponse } from '@/tools/serper/search'
import { BlockConfig } from '../types'
export const SerperBlock: BlockConfig = {
- type: 'serper_search',
- toolbar: {
- title: 'Serper Search',
- description: 'Search the web using Serper',
- bgColor: '#2B3543',
- icon: SerperIcon,
- category: 'tools',
- },
+ id: 'serper',
+ name: 'Serper',
+ description: 'Search the web using Serper',
+ category: 'tools',
+ bgColor: '#2B3543',
+ icon: SerperIcon,
+ subBlocks: [
+ {
+ id: 'query',
+ title: 'Search Query',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your search query...',
+ },
+ {
+ id: 'type',
+ title: 'Search Type',
+ type: 'dropdown',
+ layout: 'half',
+ options: ['search', 'news', 'places', 'images'],
+ },
+ {
+ id: 'num',
+ title: 'Number of Results',
+ type: 'dropdown',
+ layout: 'half',
+ options: ['10', '20', '30', '40', '50', '100'],
+ },
+ {
+ id: 'gl',
+ title: 'Country',
+ type: 'dropdown',
+ layout: 'half',
+ options: ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'ES', 'IT', 'JP', 'KR'],
+ },
+ {
+ id: 'hl',
+ title: 'Language',
+ type: 'dropdown',
+ layout: 'half',
+ options: ['en', 'es', 'fr', 'de', 'it', 'pt', 'ja', 'ko', 'zh'],
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your Serper API key',
+ password: true,
+ },
+ ],
tools: {
access: ['serper_search'],
},
- workflow: {
- inputs: {
- query: { type: 'string', required: true },
- apiKey: { type: 'string', required: true },
- num: { type: 'number', required: false },
- gl: { type: 'string', required: false },
- hl: { type: 'string', required: false },
- type: { type: 'string', required: false },
- },
- outputs: {
- response: {
- type: {
- searchResults: 'json',
- },
+ inputs: {
+ query: { type: 'string', required: true },
+ apiKey: { type: 'string', required: true },
+ num: { type: 'number', required: false },
+ gl: { type: 'string', required: false },
+ hl: { type: 'string', required: false },
+ type: { type: 'string', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ searchResults: 'json',
},
},
- subBlocks: [
- {
- id: 'query',
- title: 'Search Query',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your search query...',
- },
- {
- id: 'type',
- title: 'Search Type',
- type: 'dropdown',
- layout: 'half',
- options: ['search', 'news', 'places', 'images'],
- },
- {
- id: 'num',
- title: 'Number of Results',
- type: 'dropdown',
- layout: 'half',
- options: ['10', '20', '30', '40', '50', '100'],
- },
- {
- id: 'gl',
- title: 'Country',
- type: 'dropdown',
- layout: 'half',
- options: ['US', 'GB', 'CA', 'AU', 'DE', 'FR', 'ES', 'IT', 'JP', 'KR'],
- },
- {
- id: 'hl',
- title: 'Language',
- type: 'dropdown',
- layout: 'half',
- options: ['en', 'es', 'fr', 'de', 'it', 'pt', 'ja', 'ko', 'zh'],
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your Serper API key',
- password: true,
- },
- ],
},
}
diff --git a/blocks/blocks/slack.ts b/blocks/blocks/slack.ts
index 9cb7201f9a..948cc2aa86 100644
--- a/blocks/blocks/slack.ts
+++ b/blocks/blocks/slack.ts
@@ -2,56 +2,52 @@ import { SlackIcon } from '@/components/icons'
import { SlackMessageResponse } from '@/tools/slack/message'
import { BlockConfig } from '../types'
-export const SlackMessageBlock: BlockConfig = {
- type: 'slack_message',
- toolbar: {
- title: 'Slack Message',
- description: 'Send a message to Slack',
- bgColor: '#611f69',
- icon: SlackIcon,
- category: 'tools',
- },
+export const SlackBlock: BlockConfig = {
+ id: 'slack',
+ name: 'Slack',
+ description: 'Send a message to Slack',
+ category: 'tools',
+ bgColor: '#611f69',
+ icon: SlackIcon,
+ subBlocks: [
+ {
+ id: 'channel',
+ title: 'Channel',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter Slack channel (e.g., #general)',
+ },
+ {
+ id: 'text',
+ title: 'Message',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter your alert message',
+ },
+ {
+ id: 'apiKey',
+ title: 'OAuth Token',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your Slack OAuth token',
+ password: true,
+ connectionDroppable: false,
+ },
+ ],
tools: {
access: ['slack_message'],
},
- workflow: {
- inputs: {
- apiKey: { type: 'string', required: true },
- channel: { type: 'string', required: true },
- text: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- ts: 'string',
- channel: 'string',
- },
+ inputs: {
+ apiKey: { type: 'string', required: true },
+ channel: { type: 'string', required: true },
+ text: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ ts: 'string',
+ channel: 'string',
},
},
- subBlocks: [
- {
- id: 'channel',
- title: 'Channel',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter Slack channel (e.g., #general)',
- },
- {
- id: 'text',
- title: 'Message',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter your alert message',
- },
- {
- id: 'apiKey',
- title: 'OAuth Token',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your Slack OAuth token',
- password: true,
- connectionDroppable: false,
- },
- ],
},
}
diff --git a/blocks/blocks/starter.ts b/blocks/blocks/starter.ts
index 6760343c3c..4b97041a48 100644
--- a/blocks/blocks/starter.ts
+++ b/blocks/blocks/starter.ts
@@ -2,251 +2,247 @@ import { StartIcon } from '@/components/icons'
import { BlockConfig } from '../types'
export const StarterBlock: BlockConfig = {
- type: 'starter',
- toolbar: {
- title: 'Starter',
- description: 'Start workflow',
- bgColor: '#2FB3FF',
- icon: StartIcon,
- category: 'blocks',
- },
+ id: 'starter',
+ name: 'Starter',
+ description: 'Start workflow',
+ category: 'blocks',
+ bgColor: '#2FB3FF',
+ icon: StartIcon,
+ subBlocks: [
+ // Main trigger selector
+ {
+ id: 'startWorkflow',
+ title: 'Start Workflow',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'Run manually', id: 'manual' },
+ { label: 'On webhook call', id: 'webhook' },
+ { label: 'On schedule', id: 'schedule' },
+ ],
+ value: () => 'manual',
+ },
+ // Webhook configuration
+ {
+ id: 'webhookPath',
+ title: 'Webhook Path',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter webhook path (e.g., /my-webhook)',
+ condition: { field: 'startWorkflow', value: 'webhook' },
+ },
+ {
+ id: 'webhookSecret',
+ title: 'Webhook Secret',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter a secret key for webhook security',
+ password: true,
+ condition: { field: 'startWorkflow', value: 'webhook' },
+ },
+ // Schedule configuration
+ {
+ id: 'scheduleType',
+ title: 'Frequency',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'Every X Minutes', id: 'minutes' },
+ { label: 'Hourly', id: 'hourly' },
+ { label: 'Daily', id: 'daily' },
+ { label: 'Weekly', id: 'weekly' },
+ { label: 'Monthly', id: 'monthly' },
+ { label: 'Custom Cron', id: 'custom' },
+ ],
+ value: () => 'daily',
+ condition: { field: 'startWorkflow', value: 'schedule' },
+ },
+ // Minutes schedule options
+ {
+ id: 'minutesInterval',
+ title: 'Run Every',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '15 minutes',
+ condition: {
+ field: 'scheduleType',
+ value: 'minutes',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ {
+ id: 'minutesStartingAt',
+ title: 'Starting At',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '09:00',
+ condition: {
+ field: 'scheduleType',
+ value: 'minutes',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ // Hourly schedule options
+ {
+ id: 'hourlyMinute',
+ title: 'Start at Minute',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '00',
+ condition: {
+ field: 'scheduleType',
+ value: 'hourly',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ // Daily schedule options
+ {
+ id: 'dailyTime',
+ title: 'Time',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '09:00',
+ condition: {
+ field: 'scheduleType',
+ value: 'daily',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ // Weekly schedule options
+ {
+ id: 'weeklyDay',
+ title: 'Day of Week',
+ type: 'dropdown',
+ layout: 'half',
+ options: [
+ { label: 'Monday', id: 'MON' },
+ { label: 'Tuesday', id: 'TUE' },
+ { label: 'Wednesday', id: 'WED' },
+ { label: 'Thursday', id: 'THU' },
+ { label: 'Friday', id: 'FRI' },
+ { label: 'Saturday', id: 'SAT' },
+ { label: 'Sunday', id: 'SUN' },
+ ],
+ value: () => 'MON',
+ condition: {
+ field: 'scheduleType',
+ value: 'weekly',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ {
+ id: 'weeklyDayTime',
+ title: 'Time',
+ type: 'short-input',
+ layout: 'half',
+ placeholder: '09:00',
+ condition: {
+ field: 'scheduleType',
+ value: 'weekly',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ // Monthly schedule options
+ {
+ id: 'monthlyDay',
+ title: 'Day of Month',
+ type: 'short-input',
+ layout: 'half',
+ placeholder: '1',
+ condition: {
+ field: 'scheduleType',
+ value: 'monthly',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ {
+ id: 'monthlyTime',
+ title: 'Time',
+ type: 'short-input',
+ layout: 'half',
+ placeholder: '09:00',
+ condition: {
+ field: 'scheduleType',
+ value: 'monthly',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ // Custom cron options
+ {
+ id: 'cronExpression',
+ title: 'Cron Expression',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '*/15 * * * *',
+ condition: {
+ field: 'scheduleType',
+ value: 'custom',
+ and: {
+ field: 'startWorkflow',
+ value: 'schedule',
+ },
+ },
+ },
+ // Timezone configuration (for all schedule types)
+ {
+ id: 'timezone',
+ title: 'Timezone',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'UTC', id: 'UTC' },
+ { label: 'US Eastern (UTC-4)', id: 'America/New_York' },
+ { label: 'US Central (UTC-5)', id: 'America/Chicago' },
+ { label: 'US Mountain (UTC-6)', id: 'America/Denver' },
+ { label: 'US Pacific (UTC-7)', id: 'America/Los_Angeles' },
+ { label: 'London (UTC+1)', id: 'Europe/London' },
+ { label: 'Paris (UTC+2)', id: 'Europe/Paris' },
+ { label: 'Singapore (UTC+8)', id: 'Asia/Singapore' },
+ { label: 'Tokyo (UTC+9)', id: 'Asia/Tokyo' },
+ { label: 'Sydney (UTC+10)', id: 'Australia/Sydney' },
+ ],
+ value: () => 'UTC',
+ condition: { field: 'startWorkflow', value: 'schedule' },
+ },
+ ],
tools: {
access: [],
},
- workflow: {
- inputs: {
- code: { type: 'string', required: true },
- executionMode: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- result: 'any',
- stdout: 'string',
- executionTime: 'number',
- },
+ inputs: {
+ code: { type: 'string', required: true },
+ executionMode: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ result: 'any',
+ stdout: 'string',
+ executionTime: 'number',
},
},
- subBlocks: [
- // Main trigger selector
- {
- id: 'startWorkflow',
- title: 'Start Workflow',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'Run manually', id: 'manual' },
- { label: 'On webhook call', id: 'webhook' },
- { label: 'On schedule', id: 'schedule' },
- ],
- value: () => 'manual',
- },
- // Webhook configuration
- {
- id: 'webhookPath',
- title: 'Webhook Path',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter webhook path (e.g., /my-webhook)',
- condition: { field: 'startWorkflow', value: 'webhook' },
- },
- {
- id: 'webhookSecret',
- title: 'Webhook Secret',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter a secret key for webhook security',
- password: true,
- condition: { field: 'startWorkflow', value: 'webhook' },
- },
- // Schedule configuration
- {
- id: 'scheduleType',
- title: 'Frequency',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'Every X Minutes', id: 'minutes' },
- { label: 'Hourly', id: 'hourly' },
- { label: 'Daily', id: 'daily' },
- { label: 'Weekly', id: 'weekly' },
- { label: 'Monthly', id: 'monthly' },
- { label: 'Custom Cron', id: 'custom' },
- ],
- value: () => 'daily',
- condition: { field: 'startWorkflow', value: 'schedule' },
- },
- // Minutes schedule options
- {
- id: 'minutesInterval',
- title: 'Run Every',
- type: 'short-input',
- layout: 'full',
- placeholder: '15 minutes',
- condition: {
- field: 'scheduleType',
- value: 'minutes',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- {
- id: 'minutesStartingAt',
- title: 'Starting At',
- type: 'short-input',
- layout: 'full',
- placeholder: '09:00',
- condition: {
- field: 'scheduleType',
- value: 'minutes',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- // Hourly schedule options
- {
- id: 'hourlyMinute',
- title: 'Start at Minute',
- type: 'short-input',
- layout: 'full',
- placeholder: '00',
- condition: {
- field: 'scheduleType',
- value: 'hourly',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- // Daily schedule options
- {
- id: 'dailyTime',
- title: 'Time',
- type: 'short-input',
- layout: 'full',
- placeholder: '09:00',
- condition: {
- field: 'scheduleType',
- value: 'daily',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- // Weekly schedule options
- {
- id: 'weeklyDay',
- title: 'Day of Week',
- type: 'dropdown',
- layout: 'half',
- options: [
- { label: 'Monday', id: 'MON' },
- { label: 'Tuesday', id: 'TUE' },
- { label: 'Wednesday', id: 'WED' },
- { label: 'Thursday', id: 'THU' },
- { label: 'Friday', id: 'FRI' },
- { label: 'Saturday', id: 'SAT' },
- { label: 'Sunday', id: 'SUN' },
- ],
- value: () => 'MON',
- condition: {
- field: 'scheduleType',
- value: 'weekly',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- {
- id: 'weeklyDayTime',
- title: 'Time',
- type: 'short-input',
- layout: 'half',
- placeholder: '09:00',
- condition: {
- field: 'scheduleType',
- value: 'weekly',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- // Monthly schedule options
- {
- id: 'monthlyDay',
- title: 'Day of Month',
- type: 'short-input',
- layout: 'half',
- placeholder: '1',
- condition: {
- field: 'scheduleType',
- value: 'monthly',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- {
- id: 'monthlyTime',
- title: 'Time',
- type: 'short-input',
- layout: 'half',
- placeholder: '09:00',
- condition: {
- field: 'scheduleType',
- value: 'monthly',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- // Custom cron options
- {
- id: 'cronExpression',
- title: 'Cron Expression',
- type: 'short-input',
- layout: 'full',
- placeholder: '*/15 * * * *',
- condition: {
- field: 'scheduleType',
- value: 'custom',
- and: {
- field: 'startWorkflow',
- value: 'schedule',
- },
- },
- },
- // Timezone configuration (for all schedule types)
- {
- id: 'timezone',
- title: 'Timezone',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'UTC', id: 'UTC' },
- { label: 'US Eastern (UTC-4)', id: 'America/New_York' },
- { label: 'US Central (UTC-5)', id: 'America/Chicago' },
- { label: 'US Mountain (UTC-6)', id: 'America/Denver' },
- { label: 'US Pacific (UTC-7)', id: 'America/Los_Angeles' },
- { label: 'London (UTC+1)', id: 'Europe/London' },
- { label: 'Paris (UTC+2)', id: 'Europe/Paris' },
- { label: 'Singapore (UTC+8)', id: 'Asia/Singapore' },
- { label: 'Tokyo (UTC+9)', id: 'Asia/Tokyo' },
- { label: 'Sydney (UTC+10)', id: 'Australia/Sydney' },
- ],
- value: () => 'UTC',
- condition: { field: 'startWorkflow', value: 'schedule' },
- },
- ],
},
}
diff --git a/blocks/blocks/tavily.ts b/blocks/blocks/tavily.ts
index 05aa289ba9..25544e5727 100644
--- a/blocks/blocks/tavily.ts
+++ b/blocks/blocks/tavily.ts
@@ -5,14 +5,70 @@ import { BlockConfig } from '../types'
type TavilyResponse = TavilySearchResponse | TavilyExtractResponse
export const TavilyBlock: BlockConfig = {
- type: 'tavily_block',
- toolbar: {
- title: 'Tavily',
- description: 'Search and extract information using Tavily AI',
- bgColor: '#0066FF',
- icon: TavilyIcon,
- category: 'tools',
- },
+ id: 'tavily',
+ name: 'Tavily',
+ description: 'Search and extract information using Tavily AI',
+ category: 'tools',
+ bgColor: '#0066FF',
+ icon: TavilyIcon,
+ subBlocks: [
+ // Operation selector
+ {
+ id: 'operation',
+ title: 'Operation',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'Search', id: 'tavily_search' },
+ { label: 'Extract Content', id: 'tavily_extract' },
+ ],
+ value: () => 'tavily_search',
+ },
+ // API Key (common)
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your Tavily API key',
+ password: true,
+ },
+ // Search operation inputs
+ {
+ id: 'query',
+ title: 'Search Query',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter your search query...',
+ condition: { field: 'operation', value: 'tavily_search' },
+ },
+ {
+ id: 'maxResults',
+ title: 'Max Results',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '5',
+ condition: { field: 'operation', value: 'tavily_search' },
+ },
+ // Extract operation inputs
+ {
+ id: 'urls',
+ title: 'URL',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter URL to extract content from...',
+ condition: { field: 'operation', value: 'tavily_extract' },
+ },
+ {
+ id: 'extract_depth',
+ title: 'Extract Depth',
+ type: 'dropdown',
+ layout: 'full',
+ options: ['basic', 'advanced'],
+ value: () => 'basic',
+ condition: { field: 'operation', value: 'tavily_extract' },
+ },
+ ],
tools: {
access: ['tavily_search', 'tavily_extract'],
config: {
@@ -28,86 +84,26 @@ export const TavilyBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- operation: { type: 'string', required: true },
- apiKey: { type: 'string', required: true },
- // Search operation
- query: { type: 'string', required: false },
- maxResults: { type: 'number', required: false },
- // Extract operation
- urls: { type: 'string', required: false },
- extract_depth: { type: 'string', required: false },
- },
- outputs: {
- response: {
- type: {
- results: 'json',
- answer: 'any',
- query: 'string',
- content: 'string',
- title: 'string',
- url: 'string',
- },
+ inputs: {
+ operation: { type: 'string', required: true },
+ apiKey: { type: 'string', required: true },
+ // Search operation
+ query: { type: 'string', required: false },
+ maxResults: { type: 'number', required: false },
+ // Extract operation
+ urls: { type: 'string', required: false },
+ extract_depth: { type: 'string', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ results: 'json',
+ answer: 'any',
+ query: 'string',
+ content: 'string',
+ title: 'string',
+ url: 'string',
},
},
- subBlocks: [
- // Operation selector
- {
- id: 'operation',
- title: 'Operation',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'Search', id: 'tavily_search' },
- { label: 'Extract Content', id: 'tavily_extract' },
- ],
- value: () => 'tavily_search',
- },
- // API Key (common)
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your Tavily API key',
- password: true,
- },
- // Search operation inputs
- {
- id: 'query',
- title: 'Search Query',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter your search query...',
- condition: { field: 'operation', value: 'tavily_search' },
- },
- {
- id: 'maxResults',
- title: 'Max Results',
- type: 'short-input',
- layout: 'full',
- placeholder: '5',
- condition: { field: 'operation', value: 'tavily_search' },
- },
- // Extract operation inputs
- {
- id: 'urls',
- title: 'URL',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter URL to extract content from...',
- condition: { field: 'operation', value: 'tavily_extract' },
- },
- {
- id: 'extract_depth',
- title: 'Extract Depth',
- type: 'dropdown',
- layout: 'full',
- options: ['basic', 'advanced'],
- value: () => 'basic',
- condition: { field: 'operation', value: 'tavily_extract' },
- },
- ],
},
}
diff --git a/blocks/blocks/translate.ts b/blocks/blocks/translate.ts
index f1eb3f62f8..f848020994 100644
--- a/blocks/blocks/translate.ts
+++ b/blocks/blocks/translate.ts
@@ -15,14 +15,54 @@ const getTranslationPrompt = (
Only return the translated text without any explanations or notes. The translation should be natural and fluent in ${targetLanguage || 'English'}.`
export const TranslateBlock: BlockConfig = {
- type: 'translate',
- toolbar: {
- title: 'Translate',
- description: 'Translate text to any language',
- bgColor: '#FF4B4B',
- icon: TranslateIcon,
- category: 'tools',
- },
+ id: 'translate',
+ name: 'Translate',
+ description: 'Translate text to any language',
+ category: 'tools',
+ bgColor: '#FF4B4B',
+ icon: TranslateIcon,
+ subBlocks: [
+ {
+ id: 'context',
+ title: 'Text to Translate',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter the text you want to translate',
+ },
+ {
+ id: 'targetLanguage',
+ title: 'Translate To',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter language (e.g. Spanish, French, etc.)',
+ },
+ {
+ id: 'model',
+ title: 'Model',
+ type: 'dropdown',
+ layout: 'half',
+ options: Object.keys(MODEL_TOOLS),
+ },
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your API key',
+ password: true,
+ connectionDroppable: false,
+ },
+ {
+ id: 'systemPrompt',
+ title: 'System Prompt',
+ type: 'code',
+ layout: 'full',
+ hidden: true,
+ value: (params: Record) => {
+ return getTranslationPrompt(params.targetLanguage || 'English')
+ },
+ },
+ ],
tools: {
access: ['openai_chat', 'anthropic_chat', 'google_chat'],
config: {
@@ -43,63 +83,19 @@ export const TranslateBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- context: { type: 'string', required: true },
- targetLanguage: { type: 'string', required: true },
- apiKey: { type: 'string', required: true },
- systemPrompt: { type: 'string', required: true },
- },
- outputs: {
- response: {
- type: {
- content: 'string',
- model: 'string',
- tokens: 'any',
- },
+ inputs: {
+ context: { type: 'string', required: true },
+ targetLanguage: { type: 'string', required: true },
+ apiKey: { type: 'string', required: true },
+ systemPrompt: { type: 'string', required: true },
+ },
+ outputs: {
+ response: {
+ type: {
+ content: 'string',
+ model: 'string',
+ tokens: 'any',
},
},
- subBlocks: [
- {
- id: 'context',
- title: 'Text to Translate',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter the text you want to translate',
- },
- {
- id: 'targetLanguage',
- title: 'Translate To',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter language (e.g. Spanish, French, etc.)',
- },
- {
- id: 'model',
- title: 'Model',
- type: 'dropdown',
- layout: 'half',
- options: Object.keys(MODEL_TOOLS),
- },
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your API key',
- password: true,
- connectionDroppable: false,
- },
- {
- id: 'systemPrompt',
- title: 'System Prompt',
- type: 'code',
- layout: 'full',
- hidden: true,
- value: (params: Record) => {
- return getTranslationPrompt(params.targetLanguage || 'English')
- },
- },
- ],
},
}
diff --git a/blocks/blocks/x.ts b/blocks/blocks/x.ts
index 6c4dd1244e..a4ab0fce22 100644
--- a/blocks/blocks/x.ts
+++ b/blocks/blocks/x.ts
@@ -5,14 +5,140 @@ import { BlockConfig } from '../types'
type XResponse = XWriteResponse | XReadResponse | XSearchResponse | XUserResponse
export const XBlock: BlockConfig = {
- type: 'x_block',
- toolbar: {
- title: 'X',
- description: 'Interact with X',
- bgColor: '#000000', // X's black color
- icon: xIcon,
- category: 'tools',
- },
+ id: 'x',
+ name: 'X',
+ description: 'Interact with X',
+ category: 'tools',
+ bgColor: '#000000', // X's black color
+ icon: xIcon,
+ subBlocks: [
+ // Operation selector
+ {
+ id: 'operation',
+ title: 'Operation',
+ type: 'dropdown',
+ layout: 'full',
+ options: [
+ { label: 'Post a New Tweet', id: 'x_write' },
+ { label: 'Get Tweet Details', id: 'x_read' },
+ { label: 'Search Tweets', id: 'x_search' },
+ { label: 'Get User Profile', id: 'x_user' },
+ ],
+ value: () => 'x_write',
+ },
+ // API Key (common)
+ {
+ id: 'apiKey',
+ title: 'API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter your X Bearer token',
+ password: true,
+ },
+ // Write operation inputs
+ {
+ id: 'text',
+ title: 'Tweet Text',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: "What's happening?",
+ condition: { field: 'operation', value: 'x_write' },
+ },
+ {
+ id: 'replyTo',
+ title: 'Reply To (Tweet ID)',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter tweet ID to reply to',
+ condition: { field: 'operation', value: 'x_write' },
+ },
+ {
+ id: 'mediaIds',
+ title: 'Media IDs',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter comma-separated media IDs',
+ condition: { field: 'operation', value: 'x_write' },
+ },
+ // Read operation inputs
+ {
+ id: 'tweetId',
+ title: 'Tweet ID',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter tweet ID to read',
+ condition: { field: 'operation', value: 'x_read' },
+ },
+ {
+ id: 'includeReplies',
+ title: 'Include Replies',
+ type: 'dropdown',
+ layout: 'full',
+ options: ['true', 'false'],
+ value: () => 'false',
+ condition: { field: 'operation', value: 'x_read' },
+ },
+ // Search operation inputs
+ {
+ id: 'query',
+ title: 'Search Query',
+ type: 'long-input',
+ layout: 'full',
+ placeholder: 'Enter search terms (supports X search operators)',
+ condition: { field: 'operation', value: 'x_search' },
+ },
+ {
+ id: 'maxResults',
+ title: 'Max Results',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: '10',
+ condition: { field: 'operation', value: 'x_search' },
+ },
+ {
+ id: 'sortOrder',
+ title: 'Sort Order',
+ type: 'dropdown',
+ layout: 'full',
+ options: ['recency', 'relevancy'],
+ value: () => 'recency',
+ condition: { field: 'operation', value: 'x_search' },
+ },
+ {
+ id: 'startTime',
+ title: 'Start Time',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
+ condition: { field: 'operation', value: 'x_search' },
+ },
+ {
+ id: 'endTime',
+ title: 'End Time',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
+ condition: { field: 'operation', value: 'x_search' },
+ },
+ // User operation inputs
+ {
+ id: 'username',
+ title: 'Username',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter username (without @)',
+ condition: { field: 'operation', value: 'x_user' },
+ },
+ {
+ id: 'includeRecentTweets',
+ title: 'Include Recent Tweets',
+ type: 'dropdown',
+ layout: 'full',
+ options: ['true', 'false'],
+ value: () => 'false',
+ condition: { field: 'operation', value: 'x_user' },
+ },
+ ],
tools: {
access: ['x_write', 'x_read', 'x_search', 'x_user'],
config: {
@@ -32,169 +158,39 @@ export const XBlock: BlockConfig = {
},
},
},
- workflow: {
- inputs: {
- operation: { type: 'string', required: true },
- apiKey: { type: 'string', required: true },
- // Write operation
- text: { type: 'string', required: false },
- replyTo: { type: 'string', required: false },
- mediaIds: { type: 'string', required: false },
- poll: { type: 'json', required: false },
- // Read operation
- tweetId: { type: 'string', required: false },
- includeReplies: { type: 'boolean', required: false },
- // Search operation
- query: { type: 'string', required: false },
- maxResults: { type: 'number', required: false },
- startTime: { type: 'string', required: false },
- endTime: { type: 'string', required: false },
- sortOrder: { type: 'string', required: false },
- // User operation
- username: { type: 'string', required: false },
- includeRecentTweets: { type: 'boolean', required: false },
- },
- outputs: {
- response: {
- type: {
- tweet: 'json',
- replies: 'any',
- context: 'any',
- tweets: 'json',
- includes: 'any',
- meta: 'json',
- user: 'json',
- recentTweets: 'any',
- },
+ inputs: {
+ operation: { type: 'string', required: true },
+ apiKey: { type: 'string', required: true },
+ // Write operation
+ text: { type: 'string', required: false },
+ replyTo: { type: 'string', required: false },
+ mediaIds: { type: 'string', required: false },
+ poll: { type: 'json', required: false },
+ // Read operation
+ tweetId: { type: 'string', required: false },
+ includeReplies: { type: 'boolean', required: false },
+ // Search operation
+ query: { type: 'string', required: false },
+ maxResults: { type: 'number', required: false },
+ startTime: { type: 'string', required: false },
+ endTime: { type: 'string', required: false },
+ sortOrder: { type: 'string', required: false },
+ // User operation
+ username: { type: 'string', required: false },
+ includeRecentTweets: { type: 'boolean', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ tweet: 'json',
+ replies: 'any',
+ context: 'any',
+ tweets: 'json',
+ includes: 'any',
+ meta: 'json',
+ user: 'json',
+ recentTweets: 'any',
},
},
- subBlocks: [
- // Operation selector
- {
- id: 'operation',
- title: 'Operation',
- type: 'dropdown',
- layout: 'full',
- options: [
- { label: 'Post a New Tweet', id: 'x_write' },
- { label: 'Get Tweet Details', id: 'x_read' },
- { label: 'Search Tweets', id: 'x_search' },
- { label: 'Get User Profile', id: 'x_user' },
- ],
- value: () => 'x_write',
- },
- // API Key (common)
- {
- id: 'apiKey',
- title: 'API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter your X Bearer token',
- password: true,
- },
- // Write operation inputs
- {
- id: 'text',
- title: 'Tweet Text',
- type: 'long-input',
- layout: 'full',
- placeholder: "What's happening?",
- condition: { field: 'operation', value: 'x_write' },
- },
- {
- id: 'replyTo',
- title: 'Reply To (Tweet ID)',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter tweet ID to reply to',
- condition: { field: 'operation', value: 'x_write' },
- },
- {
- id: 'mediaIds',
- title: 'Media IDs',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter comma-separated media IDs',
- condition: { field: 'operation', value: 'x_write' },
- },
- // Read operation inputs
- {
- id: 'tweetId',
- title: 'Tweet ID',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter tweet ID to read',
- condition: { field: 'operation', value: 'x_read' },
- },
- {
- id: 'includeReplies',
- title: 'Include Replies',
- type: 'dropdown',
- layout: 'full',
- options: ['true', 'false'],
- value: () => 'false',
- condition: { field: 'operation', value: 'x_read' },
- },
- // Search operation inputs
- {
- id: 'query',
- title: 'Search Query',
- type: 'long-input',
- layout: 'full',
- placeholder: 'Enter search terms (supports X search operators)',
- condition: { field: 'operation', value: 'x_search' },
- },
- {
- id: 'maxResults',
- title: 'Max Results',
- type: 'short-input',
- layout: 'full',
- placeholder: '10',
- condition: { field: 'operation', value: 'x_search' },
- },
- {
- id: 'sortOrder',
- title: 'Sort Order',
- type: 'dropdown',
- layout: 'full',
- options: ['recency', 'relevancy'],
- value: () => 'recency',
- condition: { field: 'operation', value: 'x_search' },
- },
- {
- id: 'startTime',
- title: 'Start Time',
- type: 'short-input',
- layout: 'full',
- placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
- condition: { field: 'operation', value: 'x_search' },
- },
- {
- id: 'endTime',
- title: 'End Time',
- type: 'short-input',
- layout: 'full',
- placeholder: 'YYYY-MM-DDTHH:mm:ssZ',
- condition: { field: 'operation', value: 'x_search' },
- },
- // User operation inputs
- {
- id: 'username',
- title: 'Username',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter username (without @)',
- condition: { field: 'operation', value: 'x_user' },
- },
- {
- id: 'includeRecentTweets',
- title: 'Include Recent Tweets',
- type: 'dropdown',
- layout: 'full',
- options: ['true', 'false'],
- value: () => 'false',
- condition: { field: 'operation', value: 'x_user' },
- },
- ],
},
}
diff --git a/blocks/blocks/youtube.ts b/blocks/blocks/youtube.ts
index 461b2e05d0..6a36667bc9 100644
--- a/blocks/blocks/youtube.ts
+++ b/blocks/blocks/youtube.ts
@@ -2,56 +2,52 @@ import { YouTubeIcon } from '@/components/icons'
import { YouTubeSearchResponse } from '@/tools/youtube/search'
import { BlockConfig } from '../types'
-export const YouTubeSearchBlock: BlockConfig = {
- type: 'youtube_search',
- toolbar: {
- title: 'YouTube Search',
- description: 'Search for videos on YouTube',
- bgColor: '#FF0000',
- icon: YouTubeIcon,
- category: 'tools',
- },
+export const YouTubeBlock: BlockConfig = {
+ id: 'youtube',
+ name: 'YouTube',
+ description: 'Search for videos on YouTube',
+ category: 'tools',
+ bgColor: '#FF0000',
+ icon: YouTubeIcon,
+ subBlocks: [
+ {
+ id: 'query',
+ title: 'Search Query',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter search query',
+ },
+ {
+ id: 'apiKey',
+ title: 'YouTube API Key',
+ type: 'short-input',
+ layout: 'full',
+ placeholder: 'Enter YouTube API Key',
+ password: true,
+ },
+ {
+ id: 'maxResults',
+ title: 'Max Results',
+ type: 'slider',
+ layout: 'half',
+ min: 0,
+ max: 20,
+ },
+ ],
tools: {
access: ['youtube_search'],
},
- workflow: {
- inputs: {
- apiKey: { type: 'string', required: true },
- query: { type: 'string', required: true },
- maxResults: { type: 'number', required: false },
- },
- outputs: {
- response: {
- type: {
- items: 'json',
- totalResults: 'number',
- },
+ inputs: {
+ apiKey: { type: 'string', required: true },
+ query: { type: 'string', required: true },
+ maxResults: { type: 'number', required: false },
+ },
+ outputs: {
+ response: {
+ type: {
+ items: 'json',
+ totalResults: 'number',
},
},
- subBlocks: [
- {
- id: 'query',
- title: 'Search Query',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter search query',
- },
- {
- id: 'apiKey',
- title: 'YouTube API Key',
- type: 'short-input',
- layout: 'full',
- placeholder: 'Enter YouTube API Key',
- password: true,
- },
- {
- id: 'maxResults',
- title: 'Max Results',
- type: 'slider',
- layout: 'half',
- min: 0,
- max: 20,
- },
- ],
},
}
diff --git a/blocks/index.ts b/blocks/index.ts
index fa965bb243..f79f31b889 100644
--- a/blocks/index.ts
+++ b/blocks/index.ts
@@ -4,7 +4,7 @@ import { ApiBlock } from './blocks/api'
import { ConditionBlock } from './blocks/condition'
import { CrewAIVisionBlock } from './blocks/crewai'
import { EvaluatorBlock } from './blocks/evaluator'
-import { FirecrawlScrapeBlock } from './blocks/firecrawl'
+import { FirecrawlBlock } from './blocks/firecrawl'
import { FunctionBlock } from './blocks/function'
import { GitHubBlock } from './blocks/github'
import { GmailBlock } from './blocks/gmail'
@@ -12,12 +12,12 @@ import { JinaBlock } from './blocks/jina'
import { NotionBlock } from './blocks/notion'
import { RouterBlock } from './blocks/router'
import { SerperBlock } from './blocks/serper'
-import { SlackMessageBlock } from './blocks/slack'
+import { SlackBlock } from './blocks/slack'
import { StarterBlock } from './blocks/starter'
import { TavilyBlock } from './blocks/tavily'
import { TranslateBlock } from './blocks/translate'
import { XBlock } from './blocks/x'
-import { YouTubeSearchBlock } from './blocks/youtube'
+import { YouTubeBlock } from './blocks/youtube'
import { BlockConfig } from './types'
// Export blocks for ease of use
@@ -26,17 +26,17 @@ export {
ApiBlock,
FunctionBlock,
CrewAIVisionBlock,
- FirecrawlScrapeBlock,
+ FirecrawlBlock,
JinaBlock,
TranslateBlock,
- SlackMessageBlock,
+ SlackBlock,
GitHubBlock,
ConditionBlock,
SerperBlock,
TavilyBlock,
RouterBlock,
EvaluatorBlock,
- YouTubeSearchBlock,
+ YouTubeBlock,
NotionBlock,
GmailBlock,
XBlock,
@@ -53,27 +53,27 @@ const blocks: Record = {
router: RouterBlock,
evaluator: EvaluatorBlock,
crewai_vision: CrewAIVisionBlock,
- firecrawl_scrape: FirecrawlScrapeBlock,
- jina_reader: JinaBlock,
+ firecrawl: FirecrawlBlock,
+ jina: JinaBlock,
translate: TranslateBlock,
- slack_message: SlackMessageBlock,
- github_repo_info: GitHubBlock,
- serper_search: SerperBlock,
- tavily_block: TavilyBlock,
- youtube_search: YouTubeSearchBlock,
- notion_reader: NotionBlock,
- gmail_block: GmailBlock,
- x_block: XBlock,
+ slack: SlackBlock,
+ github: GitHubBlock,
+ serper: SerperBlock,
+ tavily: TavilyBlock,
+ youtube: YouTubeBlock,
+ notion: NotionBlock,
+ gmail: GmailBlock,
+ x: XBlock,
}
// Helper functions
-export const getBlock = (type: string): BlockConfig | undefined => blocks[type]
+export const getBlock = (id: string): BlockConfig | undefined => blocks[id]
export const getBlocksByCategory = (category: 'blocks' | 'tools'): BlockConfig[] =>
- Object.values(blocks).filter((block) => block.toolbar.category === category)
+ Object.values(blocks).filter((block) => block.category === category)
-export const getAllBlockTypes = (): string[] => Object.keys(blocks)
+export const getAllBlockIds = (): string[] => Object.keys(blocks)
-export const isValidBlockType = (type: string): type is string => type in blocks
+export const isValidBlockId = (id: string): id is string => id in blocks
export const getAllBlocks = (): BlockConfig[] => Object.values(blocks)
diff --git a/blocks/types.ts b/blocks/types.ts
index 9efe6407a9..93eca3edcd 100644
--- a/blocks/types.ts
+++ b/blocks/types.ts
@@ -2,30 +2,35 @@ import type { SVGProps } from 'react'
import type { JSX } from 'react'
import { ToolResponse } from '@/tools/types'
-// Basic type definitions for block components
+// Basic types
export type BlockIcon = (props: SVGProps) => JSX.Element
-export type BlockCategory = 'blocks' | 'tools'
export type ParamType = 'string' | 'number' | 'boolean' | 'json'
export type PrimitiveValueType = 'string' | 'number' | 'boolean' | 'json' | 'any'
-// Sub-block configuration types
+// Block classification
+export type BlockCategory = 'blocks' | 'tools'
+
+// SubBlock types
export type SubBlockType =
- | 'short-input'
- | 'long-input'
- | 'dropdown'
- | 'slider'
- | 'table'
- | 'code'
- | 'switch'
- | 'tool-input'
- | 'checkbox-list'
- | 'condition-input'
- | 'eval-input'
+ | 'short-input' // Single line input
+ | 'long-input' // Multi-line input
+ | 'dropdown' // Select menu
+ | 'slider' // Range input
+ | 'table' // Grid layout
+ | 'code' // Code editor
+ | 'switch' // Toggle button
+ | 'tool-input' // Tool configuration
+ | 'checkbox-list' // Multiple selection
+ | 'condition-input' // Conditional logic
+ | 'eval-input' // Evaluation input
+
+// Component width setting
export type SubBlockLayout = 'full' | 'half'
-// Tool output type utilities
+// Tool result extraction
export type ExtractToolOutput = T extends ToolResponse ? T['output'] : never
+// Convert tool output to types
export type ToolOutputToValueType =
T extends Record
? {
@@ -41,11 +46,12 @@ export type ToolOutputToValueType =
}
: never
-// Block configuration interfaces and types
+// Block output definition
export type BlockOutput =
| PrimitiveValueType
| { [key: string]: PrimitiveValueType | Record }
+// Parameter validation rules
export interface ParamConfig {
type: ParamType
required: boolean
@@ -64,6 +70,7 @@ export interface ParamConfig {
}
}
+// SubBlock configuration
export interface SubBlockConfig {
id: string
title?: string
@@ -88,39 +95,38 @@ export interface SubBlockConfig {
}
}
+// Main block definition
export interface BlockConfig {
- type: string
- toolbar: {
- title: string
- description: string
- bgColor: string
- icon: BlockIcon
- category: BlockCategory
- }
+ id: string
+ name: string
+ description: string
+ category: BlockCategory
+ longDescription?: string
+ bgColor: string
+ icon: BlockIcon
+ subBlocks: SubBlockConfig[]
tools: {
access: string[]
config?: {
tool: (params: Record) => string
}
}
- workflow: {
- subBlocks: SubBlockConfig[]
- inputs: Record
- outputs: {
- response: {
- type: ToolOutputToValueType>
- dependsOn?: {
- subBlockId: string
- condition: {
- whenEmpty: ToolOutputToValueType>
- whenFilled: 'json'
- }
+ inputs: Record
+ outputs: {
+ response: {
+ type: ToolOutputToValueType>
+ dependsOn?: {
+ subBlockId: string
+ condition: {
+ whenEmpty: ToolOutputToValueType>
+ whenFilled: 'json'
}
}
}
}
}
+// Output configuration rules
export interface OutputConfig {
type: BlockOutput
dependsOn?: {
diff --git a/executor/index.ts b/executor/index.ts
index 3414481840..5140bffbcf 100644
--- a/executor/index.ts
+++ b/executor/index.ts
@@ -270,7 +270,7 @@ export class Executor {
context.blockStates.set(blockId, result)
lastOutput = result
- if (block.metadata?.type === 'router') {
+ if (block.metadata?.id === 'router') {
const routerResult = result as {
response: {
content: string
@@ -280,7 +280,7 @@ export class Executor {
}
}
routerDecisions.set(block.id, routerResult.response.selectedPath.blockId)
- } else if (block.metadata?.type === 'condition') {
+ } else if (block.metadata?.id === 'condition') {
const conditionResult = await this.executeConditionalBlock(block, context)
activeConditionalPaths.set(block.id, conditionResult.selectedConditionId)
}
@@ -324,7 +324,7 @@ export class Executor {
// Check if this was the last block in the loop (e.g., a condition block)
const isLoopComplete = executedLoopBlocks.some((blockId) => {
const block = blocks.find((b) => b.id === blockId)
- return block?.metadata?.type === 'condition'
+ return block?.metadata?.id === 'condition'
})
if (hasLoopConnection) {
@@ -374,7 +374,7 @@ export class Executor {
context: ExecutionContext
): Promise {
if (block.enabled === false) {
- throw new Error(`Cannot execute disabled block: ${block.metadata?.title || block.id}`)
+ throw new Error(`Cannot execute disabled block: ${block.metadata?.name || block.id}`)
}
const blockLog = this.startBlockLog(block)
@@ -383,7 +383,7 @@ export class Executor {
let output: BlockOutput
// Execute block based on its type.
- if (block.metadata?.type === 'router') {
+ if (block.metadata?.id === 'router') {
const routerOutput = await this.executeRouterBlock(block, context)
output = {
response: {
@@ -393,10 +393,10 @@ export class Executor {
selectedPath: routerOutput.selectedPath,
},
}
- } else if (block.metadata?.type === 'evaluator') {
+ } else if (block.metadata?.id === 'evaluator') {
const evaluatorOutput = await this.executeEvaluatorBlock(block, context)
output = evaluatorOutput
- } else if (block.metadata?.type === 'condition') {
+ } else if (block.metadata?.id === 'condition') {
const conditionResult = await this.executeConditionalBlock(block, context)
output = {
response: {
@@ -409,7 +409,7 @@ export class Executor {
},
},
}
- } else if (block.metadata?.type === 'agent') {
+ } else if (block.metadata?.id === 'agent') {
// Agent block: use a provider request.
let responseFormat: any = undefined
if (inputs.responseFormat) {
@@ -431,7 +431,7 @@ export class Executor {
const formattedTools = Array.isArray(inputs.tools)
? inputs.tools
.map((tool: any) => {
- const blockFound = getAllBlocks().find((b: BlockConfig) => b.type === tool.type)
+ const blockFound = getAllBlocks().find((b: BlockConfig) => b.id === tool.type)
const toolId = blockFound?.tools.access[0]
if (!toolId) return null
@@ -580,8 +580,8 @@ export class Executor {
}
return {
id: targetBlock.id,
- type: targetBlock.metadata?.type,
- title: targetBlock.metadata?.title,
+ type: targetBlock.metadata?.id,
+ title: targetBlock.metadata?.name,
description: targetBlock.metadata?.description,
subBlocks: targetBlock.config.params,
currentState: context.blockStates.get(targetBlock.id),
@@ -729,7 +729,7 @@ export class Executor {
for (const conn of connections) {
// Don't follow connections from other routers
const sourceBlock = this.workflow.blocks.find((b) => b.id === conn.source)
- if (sourceBlock?.metadata?.type !== 'router') {
+ if (sourceBlock?.metadata?.id !== 'router') {
queue.push(conn.target)
}
}
@@ -784,8 +784,8 @@ export class Executor {
if (!sourceBlock) {
throw new Error(`Source block ${sourceBlockId} not found`)
}
- const sourceKey = sourceBlock.metadata?.title
- ? sourceBlock.metadata.title.toLowerCase().replace(/\s+/g, '')
+ const sourceKey = sourceBlock.metadata?.name
+ ? sourceBlock.metadata.name.toLowerCase().replace(/\s+/g, '')
: 'source'
const outgoingConnections = this.workflow.connections.filter((conn) => conn.source === block.id)
@@ -874,8 +874,8 @@ export class Executor {
result: conditionMet,
selectedPath: {
blockId: targetBlock.id,
- blockType: targetBlock.metadata?.type || '',
- blockTitle: targetBlock.metadata?.title || '',
+ blockType: targetBlock.metadata?.id || '',
+ blockTitle: targetBlock.metadata?.name || '',
},
selectedConditionId: selectedCondition.id,
},
@@ -892,8 +892,8 @@ export class Executor {
sourceOutput: sourceBlockState,
selectedPath: {
blockId: targetBlock.id,
- blockType: targetBlock.metadata?.type || '',
- blockTitle: targetBlock.metadata?.title || '',
+ blockType: targetBlock.metadata?.id || '',
+ blockTitle: targetBlock.metadata?.name || '',
},
}
}
@@ -918,7 +918,7 @@ export class Executor {
const blockById = new Map(this.workflow.blocks.map((b) => [b.id, b]))
const blockByName = new Map(
this.workflow.blocks.map((b) => [
- b.metadata?.title?.toLowerCase().replace(/\s+/g, '') || '',
+ b.metadata?.name?.toLowerCase().replace(/\s+/g, '') || '',
b,
])
)
@@ -932,8 +932,8 @@ export class Executor {
blockById,
blockByName,
context.blockStates,
- block.metadata?.title || '',
- block.metadata?.type || ''
+ block.metadata?.name || '',
+ block.metadata?.id || ''
)
// Resolve environment variables
@@ -961,8 +961,8 @@ export class Executor {
private startBlockLog(block: SerializedBlock): BlockLog {
return {
blockId: block.id,
- blockTitle: block.metadata?.title || '',
- blockType: block.metadata?.type || '',
+ blockName: block.metadata?.name || '',
+ blockType: block.metadata?.id || '',
startedAt: new Date().toISOString(),
endedAt: '',
durationMs: 0,
@@ -986,7 +986,7 @@ export class Executor {
) {
const sourceBlock = blocks.find((b) => b.id === conn.source)
- if (sourceBlock?.metadata?.type === 'router') {
+ if (sourceBlock?.metadata?.id === 'router') {
const chosenPath = routerDecisions?.get(sourceBlock.id)
if (conn.target === chosenPath) {
diff --git a/executor/types.ts b/executor/types.ts
index c0103d00ff..93bea0504a 100644
--- a/executor/types.ts
+++ b/executor/types.ts
@@ -5,7 +5,7 @@ import { BlockOutput } from '@/blocks/types'
*/
export interface BlockLog {
blockId: string
- blockTitle?: string
+ blockName?: string
blockType?: string
startedAt: string
endedAt: string
diff --git a/serializer/index.ts b/serializer/index.ts
index a788c283b9..bd64aa7d04 100644
--- a/serializer/index.ts
+++ b/serializer/index.ts
@@ -38,8 +38,8 @@ export class Serializer {
// Get inputs from block config
const inputs: Record = {}
- if (blockConfig.workflow.inputs) {
- Object.entries(blockConfig.workflow.inputs).forEach(([key, config]) => {
+ if (blockConfig.inputs) {
+ Object.entries(blockConfig.inputs).forEach(([key, config]) => {
inputs[key] = config.type
})
}
@@ -62,11 +62,11 @@ export class Serializer {
: {}),
},
metadata: {
- title: block.name,
- description: blockConfig.toolbar.description,
- category: blockConfig.toolbar.category,
- color: blockConfig.toolbar.bgColor,
- type: block.type,
+ id: block.type,
+ name: block.name,
+ description: blockConfig.description,
+ category: blockConfig.category,
+ color: blockConfig.bgColor,
},
enabled: block.enabled,
}
@@ -86,7 +86,7 @@ export class Serializer {
})
// Then check for any subBlocks with default values
- blockConfig.workflow.subBlocks.forEach((subBlockConfig) => {
+ blockConfig.subBlocks.forEach((subBlockConfig) => {
const id = subBlockConfig.id
if (params[id] === null && subBlockConfig.value) {
// If the value is null and there's a default value function, use it
@@ -125,9 +125,9 @@ export class Serializer {
}
private deserializeBlock(serializedBlock: SerializedBlock): BlockState {
- const blockType = serializedBlock.metadata?.type
+ const blockType = serializedBlock.metadata?.id
if (!blockType) {
- throw new Error(`Invalid block type: ${serializedBlock.metadata?.type}`)
+ throw new Error(`Invalid block type: ${serializedBlock.metadata?.id}`)
}
const blockConfig = getBlock(blockType)
@@ -136,7 +136,7 @@ export class Serializer {
}
const subBlocks: Record = {}
- blockConfig.workflow.subBlocks.forEach((subBlock) => {
+ blockConfig.subBlocks.forEach((subBlock) => {
subBlocks[subBlock.id] = {
id: subBlock.id,
type: subBlock.type,
@@ -147,7 +147,7 @@ export class Serializer {
return {
id: serializedBlock.id,
type: blockType,
- name: serializedBlock.metadata?.title || blockConfig.toolbar.title,
+ name: serializedBlock.metadata?.name || blockConfig.name,
position: serializedBlock.position,
subBlocks,
outputs: serializedBlock.outputs,
diff --git a/serializer/types.ts b/serializer/types.ts
index a33efb60df..ea52cce5af 100644
--- a/serializer/types.ts
+++ b/serializer/types.ts
@@ -29,12 +29,12 @@ export interface SerializedBlock {
inputs: Record
outputs: Record
metadata?: {
- title?: string
+ id: string
+ name?: string
description?: string
category?: string
icon?: string
color?: string
- type: string
}
enabled: boolean
}
diff --git a/stores/workflow/store.ts b/stores/workflow/store.ts
index d39efc30dc..52b4d701d6 100644
--- a/stores/workflow/store.ts
+++ b/stores/workflow/store.ts
@@ -104,7 +104,7 @@ export const useWorkflowStore = create()(
if (!blockConfig) return
const subBlocks: Record = {}
- blockConfig.workflow.subBlocks.forEach((subBlock) => {
+ blockConfig.subBlocks.forEach((subBlock) => {
const subBlockId = subBlock.id
subBlocks[subBlockId] = {
id: subBlockId,
@@ -113,7 +113,7 @@ export const useWorkflowStore = create()(
}
})
- const outputs = resolveOutputType(blockConfig.workflow.outputs, subBlocks)
+ const outputs = resolveOutputType(blockConfig.outputs, subBlocks)
const newState = {
blocks: {