import { NodeProps, NodeToolbar, Position } from "@xyflow/react"; import { Edit, Headset, PlusIcon, Trash2Icon, Wrench } from "lucide-react"; import { memo, useEffect, useMemo, useState } from "react"; import { useWorkflow } from "@/app/workflow/[workflowId]/contexts/WorkflowContext"; import { ToolBadges } from "@/components/flow/ToolBadges"; import { ToolSelector } from "@/components/flow/ToolSelector"; import { ExtractionVariable, FlowNodeData } from "@/components/flow/types"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; import { NodeContent } from "./common/NodeContent"; import { NodeEditDialog } from "./common/NodeEditDialog"; import { useNodeHandlers } from "./common/useNodeHandlers"; interface AgentNodeEditFormProps { nodeData: FlowNodeData; prompt: string; setPrompt: (value: string) => void; name: string; setName: (value: string) => void; allowInterrupt: boolean; setAllowInterrupt: (value: boolean) => void; extractionEnabled: boolean; setExtractionEnabled: (value: boolean) => void; extractionPrompt: string; setExtractionPrompt: (value: string) => void; variables: ExtractionVariable[]; setVariables: (vars: ExtractionVariable[]) => void; addGlobalPrompt: boolean; setAddGlobalPrompt: (value: boolean) => void; toolUuids: string[]; setToolUuids: (value: string[]) => void; } interface AgentNodeProps extends NodeProps { data: FlowNodeData; } export const AgentNode = memo(({ data, selected, id }: AgentNodeProps) => { const { open, setOpen, handleSaveNodeData, handleDeleteNode } = useNodeHandlers({ id }); const { saveWorkflow } = useWorkflow(); // Form state const [prompt, setPrompt] = useState(data.prompt); const [name, setName] = useState(data.name); const [allowInterrupt, setAllowInterrupt] = useState(data.allow_interrupt ?? true); // Variable Extraction state const [extractionEnabled, setExtractionEnabled] = useState(data.extraction_enabled ?? false); const [extractionPrompt, setExtractionPrompt] = useState(data.extraction_prompt ?? ""); const [variables, setVariables] = useState(data.extraction_variables ?? []); const [addGlobalPrompt, setAddGlobalPrompt] = useState(data.add_global_prompt ?? true); const [toolUuids, setToolUuids] = useState(data.tool_uuids ?? []); // Compute if form has unsaved changes (only check prompt, name) const isDirty = useMemo(() => { return ( prompt !== (data.prompt ?? "") || name !== (data.name ?? "") ); }, [prompt, name, data]); const handleSave = async () => { handleSaveNodeData({ ...data, prompt, name, allow_interrupt: allowInterrupt, extraction_enabled: extractionEnabled, extraction_prompt: extractionPrompt, extraction_variables: variables, add_global_prompt: addGlobalPrompt, tool_uuids: toolUuids.length > 0 ? toolUuids : undefined, }); setOpen(false); // Save the workflow after updating node data with a small delay to ensure state is updated setTimeout(async () => { await saveWorkflow(); }, 100); }; // Reset form state when dialog opens const handleOpenChange = (newOpen: boolean) => { if (newOpen) { setPrompt(data.prompt); setName(data.name); setAllowInterrupt(data.allow_interrupt ?? true); setExtractionEnabled(data.extraction_enabled ?? false); setExtractionPrompt(data.extraction_prompt ?? ""); setVariables(data.extraction_variables ?? []); setAddGlobalPrompt(data.add_global_prompt ?? true); setToolUuids(data.tool_uuids ?? []); } setOpen(newOpen); }; // Update form state when data changes (e.g., from undo/redo) useEffect(() => { if (open) { setPrompt(data.prompt); setName(data.name); setAllowInterrupt(data.allow_interrupt ?? true); setExtractionEnabled(data.extraction_enabled ?? false); setExtractionPrompt(data.extraction_prompt ?? ""); setVariables(data.extraction_variables ?? []); setAddGlobalPrompt(data.add_global_prompt ?? true); setToolUuids(data.tool_uuids ?? []); } }, [data, open]); return ( <> } nodeType="agent" hasSourceHandle={true} hasTargetHandle={true} onDoubleClick={() => setOpen(true)} nodeId={id} >

{data.prompt || 'No prompt configured'}

{data.tool_uuids && data.tool_uuids.length > 0 && (
Tools:
)}
{open && ( )} ); }); const AgentNodeEditForm = ({ prompt, setPrompt, name, setName, allowInterrupt, setAllowInterrupt, extractionEnabled, setExtractionEnabled, extractionPrompt, setExtractionPrompt, variables, setVariables, addGlobalPrompt, setAddGlobalPrompt, toolUuids, setToolUuids, }: AgentNodeEditFormProps) => { const handleVariableNameChange = (idx: number, value: string) => { const newVars = [...variables]; newVars[idx] = { ...newVars[idx], name: value }; setVariables(newVars); }; const handleVariableTypeChange = (idx: number, value: 'string' | 'number' | 'boolean') => { const newVars = [...variables]; newVars[idx] = { ...newVars[idx], type: value }; setVariables(newVars); }; const handleVariablePromptChange = (idx: number, value: string) => { const newVars = [...variables]; newVars[idx] = { ...newVars[idx], prompt: value }; setVariables(newVars); }; const handleRemoveVariable = (idx: number) => { const newVars = variables.filter((_, i) => i !== idx); setVariables(newVars); }; const handleAddVariable = () => { setVariables([...variables, { name: '', type: 'string', prompt: '' }]); }; return (
setName(e.target.value)} />