import { useEffect } from 'react'; import { Handle, Position, type NodeProps, useUpdateNodeInternals, useEdges } from 'reactflow'; import type { NodeData } from '../../store/flowStore'; import { Loader2, MessageSquare } from 'lucide-react'; import useFlowStore from '../../store/flowStore'; const LLMNode = ({ id, data, selected }: NodeProps) => { const { updateNodeData } = useFlowStore(); const updateNodeInternals = useUpdateNodeInternals(); const edges = useEdges(); // Force update handles when traces change useEffect(() => { updateNodeInternals(id); }, [id, data.outgoingTraces, data.inputs, updateNodeInternals]); // Determine how many input handles to show // We want to ensure there is always at least one empty handle at the bottom // plus all currently connected handles. // Find all edges connected to this node's inputs const connectedHandles = new Set( edges .filter(e => e.target === id) .map(e => e.targetHandle) ); // Logic: // If input-0 is connected, show input-1. // If input-1 is connected, show input-2. // We can just iterate until we find an unconnected one. let handleCount = 1; while (connectedHandles.has(`input-${handleCount - 1}`)) { handleCount++; } // But wait, if we delete an edge to input-0, we still want input-1 to exist if it's connected? // No, usually in this designs, we just render up to max(connected_index) + 1. // Let's get the max index connected let maxConnectedIndex = -1; edges.filter(e => e.target === id).forEach(e => { const idx = parseInt(e.targetHandle?.replace('input-', '') || '0'); if (!isNaN(idx) && idx > maxConnectedIndex) { maxConnectedIndex = idx; } }); const inputsToShow = Math.max(maxConnectedIndex + 2, 1); return (
{data.status === 'loading' ? ( ) : ( )}
{data.label}
{data.model}
{/* Dynamic Inputs */}
{Array.from({ length: inputsToShow }).map((_, i) => { // Find the connected edge to get color const connectedEdge = edges.find(e => e.target === id && e.targetHandle === `input-${i}`); const edgeColor = connectedEdge?.style?.stroke as string; return (
{i}
); })}
{/* Dynamic Outputs (Traces) */}
{/* 1. Outgoing Traces (Pass-through + Self) */} {data.outgoingTraces && data.outgoingTraces.map((trace, i) => (
))} {/* 2. New Branch Generator Handle (Always visible) */}
+ New
{data.status === 'error' && (
Error
)}
); }; export default LLMNode;