From 707b7fd8bc47df8a8aa41dc0735a808cd4031e8d Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Wed, 5 Feb 2025 12:44:02 -0800 Subject: [PATCH] Added router block; fixed hidden rendering on workflow block --- .../components/sub-block/sub-block.tsx | 4 - .../workflow-block/workflow-block.tsx | 5 +- blocks/blocks/router.ts | 104 ++++++++++++++++++ blocks/index.ts | 3 + components/icons.tsx | 16 +++ 5 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 blocks/blocks/router.ts diff --git a/app/w/[id]/components/workflow-block/components/sub-block/sub-block.tsx b/app/w/[id]/components/workflow-block/components/sub-block/sub-block.tsx index e3e06034fc..adb74f6fd8 100644 --- a/app/w/[id]/components/workflow-block/components/sub-block/sub-block.tsx +++ b/app/w/[id]/components/workflow-block/components/sub-block/sub-block.tsx @@ -17,10 +17,6 @@ interface SubBlockProps { } export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) { - if (config.hidden) { - return null - } - const handleMouseDown = (e: React.MouseEvent) => { e.stopPropagation() } diff --git a/app/w/[id]/components/workflow-block/workflow-block.tsx b/app/w/[id]/components/workflow-block/workflow-block.tsx index 803b93c595..0163759626 100644 --- a/app/w/[id]/components/workflow-block/workflow-block.tsx +++ b/app/w/[id]/components/workflow-block/workflow-block.tsx @@ -89,11 +89,14 @@ export function WorkflowBlock({ id, type, config, name, selected }: WorkflowBloc }, [workflow.subBlocks, id, updateNodeInternals]) function groupSubBlocks(subBlocks: SubBlockConfig[]) { + // Filter out hidden subblocks + const visibleSubBlocks = subBlocks.filter(block => !block.hidden) + const rows: SubBlockConfig[][] = [] let currentRow: SubBlockConfig[] = [] let currentRowWidth = 0 - subBlocks.forEach((block) => { + visibleSubBlocks.forEach((block) => { const blockWidth = block.layout === 'half' ? 0.5 : 1 if (currentRowWidth + blockWidth > 1) { rows.push([...currentRow]) diff --git a/blocks/blocks/router.ts b/blocks/blocks/router.ts new file mode 100644 index 0000000000..00af11b0a9 --- /dev/null +++ b/blocks/blocks/router.ts @@ -0,0 +1,104 @@ +import { ConnectIcon } from '@/components/icons' +import { CodeExecutionOutput } from '@/tools/function/execute' +import { BlockConfig } from '../types' +import { MODEL_TOOLS, ModelType } from '../consts' + +const routerPrompt = ( + prompt: string +) => `You are an intelligent routing agent responsible for directing workflow requests to the most appropriate block. Your task is to analyze the input and determine the single most suitable destination based on the request. + +Key Instructions: +1. You MUST choose exactly ONE destination from the IDs of the blocks in the workflow. The destination must be a valid block id. + +2. Analysis Framework: + - Carefully evaluate the intent and requirements of the request + - Consider the primary action needed + - Match the core functionality with the most appropriate destination + +Routing Request: ${prompt} + +Response Format: +Return ONLY the destination id as a single word, lowercase, no punctuation or explanation. +Example: "2acd9007-27e8-4510-a487-73d3b825e7c1"` + +export const RouterBlock: BlockConfig = { + type: 'router', + toolbar: { + title: 'Router', + description: 'Add a router', + bgColor: '#28C43F', + icon: ConnectIcon, + category: 'blocks', + }, + tools: { + access: [ + 'openai_chat', + 'anthropic_chat', + 'google_chat', + 'xai_chat', + 'deepseek_chat', + 'deepseek_reasoner', + ], + config: { + tool: (params: Record) => { + const model = params.model || 'gpt-4o' + if (!model) { + throw new Error('No model selected') + } + const tool = MODEL_TOOLS[model as ModelType] + if (!tool) { + throw new Error(`Invalid model selected: ${model}`) + } + return tool + }, + }, + }, + workflow: { + inputs: { + code: { type: 'string', required: true }, + }, + outputs: { + response: { + type: { + result: 'any', + stdout: 'string', + }, + }, + }, + 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: 'full', + 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 routerPrompt(params.prompt || '') + }, + }, + ], + }, +} diff --git a/blocks/index.ts b/blocks/index.ts index 8c787f3ca0..04dc2dae66 100644 --- a/blocks/index.ts +++ b/blocks/index.ts @@ -7,6 +7,7 @@ import { FirecrawlScrapeBlock } from './blocks/firecrawl' import { FunctionBlock } from './blocks/function' import { GitHubBlock } from './blocks/github' import { JinaBlock } from './blocks/jina' +import { RouterBlock } from './blocks/router' import { SerperBlock } from './blocks/serper' import { SlackMessageBlock } from './blocks/slack' import { TavilyExtractBlock, TavilySearchBlock } from './blocks/tavily' @@ -28,6 +29,7 @@ export { SerperBlock, TavilySearchBlock, TavilyExtractBlock, + RouterBlock, } // Registry of all block configurations @@ -45,6 +47,7 @@ const blocks: Record = { serper_search: SerperBlock, tavily_search: TavilySearchBlock, tavily_extract: TavilyExtractBlock, + router: RouterBlock, } // Build a reverse mapping of tools to block types diff --git a/components/icons.tsx b/components/icons.tsx index dc311706e6..0fc2ddd896 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -1109,3 +1109,19 @@ export const TavilyIcon = (props: SVGProps) => ( /> ) + +export const ConnectIcon = (props: SVGProps) => ( + + + +); \ No newline at end of file