From d5e5f01359ea5d027ce19e699ea6ad725666170a Mon Sep 17 00:00:00 2001 From: shatfield4 Date: Mon, 27 Jan 2025 18:03:26 -0800 Subject: [PATCH 01/33] wip agent builder --- frontend/src/App.jsx | 5 + .../src/pages/Admin/AgentBuilder/index.jsx | 519 ++++++++++++++++++ .../Admin/AgentBuilder/nodes/ApiCallNode.jsx | 17 + .../Admin/AgentBuilder/nodes/BaseNode.jsx | 21 + .../Admin/AgentBuilder/nodes/CodeNode.jsx | 17 + .../Admin/AgentBuilder/nodes/FileNode.jsx | 17 + .../Admin/AgentBuilder/nodes/WebsiteNode.jsx | 17 + 7 files changed, 613 insertions(+) create mode 100644 frontend/src/pages/Admin/AgentBuilder/index.jsx create mode 100644 frontend/src/pages/Admin/AgentBuilder/nodes/ApiCallNode.jsx create mode 100644 frontend/src/pages/Admin/AgentBuilder/nodes/BaseNode.jsx create mode 100644 frontend/src/pages/Admin/AgentBuilder/nodes/CodeNode.jsx create mode 100644 frontend/src/pages/Admin/AgentBuilder/nodes/FileNode.jsx create mode 100644 frontend/src/pages/Admin/AgentBuilder/nodes/WebsiteNode.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index af84603cb8e..180e1d3f534 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -67,6 +67,7 @@ const ExperimentalFeatures = lazy( const LiveDocumentSyncManage = lazy( () => import("@/pages/Admin/ExperimentalFeatures/Features/LiveSync/manage") ); +const AgentBuilder = lazy(() => import("@/pages/Admin/AgentBuilder")); const CommunityHubTrending = lazy( () => import("@/pages/GeneralSettings/CommunityHub/Trending") @@ -143,6 +144,10 @@ export default function App() { path="/settings/agents" element={} /> + } + /> } diff --git a/frontend/src/pages/Admin/AgentBuilder/index.jsx b/frontend/src/pages/Admin/AgentBuilder/index.jsx new file mode 100644 index 00000000000..38d86336f28 --- /dev/null +++ b/frontend/src/pages/Admin/AgentBuilder/index.jsx @@ -0,0 +1,519 @@ +import React, { useState } from 'react'; +import { Plus, X, Globe, Browser, File, Code, CaretDown, CaretUp } from "@phosphor-icons/react"; + +const BLOCK_TYPES = { + START: 'start', + API_CALL: 'apiCall', + WEBSITE: 'website', + FILE: 'file', + CODE: 'code', +}; + +const BLOCK_INFO = { + [BLOCK_TYPES.START]: { + label: 'Agent Start', + icon: , + description: 'Configure agent variables and settings', + getSummary: (config) => { + const varCount = config.variables?.filter(v => v.name)?.length || 0; + return `${varCount} variable${varCount !== 1 ? 's' : ''} defined`; + } + }, + [BLOCK_TYPES.API_CALL]: { + label: 'API Call', + icon: , + description: 'Make an HTTP request', + defaultConfig: { + url: '', + method: 'GET', + headers: {}, + body: '', + responseVariable: '', + }, + getSummary: (config) => `${config.method || 'GET'} ${config.url || '(no URL)'}` + }, + [BLOCK_TYPES.WEBSITE]: { + label: 'Open Website', + icon: , + description: 'Navigate to a URL', + defaultConfig: { + url: '', + selector: '', + action: 'read', + value: '', + resultVariable: '', + }, + getSummary: (config) => `${config.action || 'read'} from ${config.url || '(no URL)'}` + }, + [BLOCK_TYPES.FILE]: { + label: 'Open File', + icon: , + description: 'Read or write to a file', + defaultConfig: { + path: '', + operation: 'read', + content: '', + resultVariable: '', + }, + getSummary: (config) => `${config.operation || 'read'} ${config.path || '(no path)'}` + }, + [BLOCK_TYPES.CODE]: { + label: 'Code Execution', + icon: , + description: 'Execute code snippets', + defaultConfig: { + language: 'javascript', + code: '', + resultVariable: '', + }, + getSummary: (config) => `Run ${config.language || 'javascript'} code` + }, +}; + +export default function AgentBuilder() { + const [agentName, setAgentName] = useState(''); + const [agentDescription, setAgentDescription] = useState(''); + const [blocks, setBlocks] = useState([ + { + id: 'start', + type: BLOCK_TYPES.START, + config: { + variables: [{ name: '', value: '' }], + }, + isExpanded: true, + }, + ]); + const [selectedBlock, setSelectedBlock] = useState('start'); + const [showBlockMenu, setShowBlockMenu] = useState(false); + + const addBlock = (type) => { + const newBlock = { + id: `block_${blocks.length}`, + type, + config: { ...BLOCK_INFO[type].defaultConfig }, + isExpanded: true, + }; + setBlocks([...blocks, newBlock]); + setShowBlockMenu(false); + }; + + const updateBlockConfig = (blockId, config) => { + setBlocks(blocks.map(block => + block.id === blockId ? { ...block, config: { ...block.config, ...config } } : block + )); + }; + + const removeBlock = (blockId) => { + if (blockId === 'start') return; + setBlocks(blocks.filter(block => block.id !== blockId)); + if (selectedBlock === blockId) { + setSelectedBlock('start'); + } + }; + + const generateJson = () => { + const json = { + name: agentName, + description: agentDescription, + steps: blocks.map(block => ({ + type: block.type, + config: block.config, + })), + }; + console.log(json); + }; + + // Get all available variables from the start block + const getAvailableVariables = () => { + const startBlock = blocks.find(b => b.type === BLOCK_TYPES.START); + return startBlock?.config?.variables?.filter(v => v.name) || []; + }; + + const renderVariableSelect = (value, onChange, placeholder = "Select variable") => ( + +); + + const renderBlockConfig = (block) => { + switch (block.type) { + case BLOCK_TYPES.START: + return ( +
+

Variables

+ {block.config.variables.map((variable, index) => ( +
+ { + const newVars = [...block.config.variables]; + newVars[index].name = e.target.value; + updateBlockConfig(block.id, { variables: newVars }); + }} + className="flex-1 p-2 rounded bg-theme-bg-primary border border-theme-sidebar-border text-theme-text-primary" + /> + { + const newVars = [...block.config.variables]; + newVars[index].value = e.target.value; + updateBlockConfig(block.id, { variables: newVars }); + }} + className="flex-1 p-2 rounded bg-theme-bg-primary border border-theme-sidebar-border text-theme-text-primary" + /> + {index === block.config.variables.length - 1 && ( + + )} +
+ ))} +
+ ); + case BLOCK_TYPES.API_CALL: + return ( +
+
+ + updateBlockConfig(block.id, { url: e.target.value })} + className="w-full p-2 rounded bg-theme-bg-primary border border-theme-sidebar-border text-theme-text-primary" + /> +
+
+ + +
+
+ + {renderVariableSelect( + block.config.responseVariable, + (value) => updateBlockConfig(block.id, { responseVariable: value }), + "Select or create variable" + )} +
+
+ ); + case BLOCK_TYPES.WEBSITE: + return ( +
+
+ + updateBlockConfig(block.id, { url: e.target.value })} + className="w-full p-2 rounded bg-theme-bg-primary border border-theme-sidebar-border text-theme-text-primary" + /> +
+
+ + +
+
+ + updateBlockConfig(block.id, { selector: e.target.value })} + className="w-full p-2 rounded bg-theme-bg-primary border border-theme-sidebar-border text-theme-text-primary" + /> +
+
+ + {renderVariableSelect( + block.config.resultVariable, + (value) => updateBlockConfig(block.id, { resultVariable: value }), + "Select or create variable" + )} +
+
+ ); + case BLOCK_TYPES.FILE: + return ( +
+
+ + +
+
+ + updateBlockConfig(block.id, { path: e.target.value })} + className="w-full p-2 rounded bg-theme-bg-primary border border-theme-sidebar-border text-theme-text-primary" + /> +
+ {block.config.operation !== 'read' && ( +
+ +