|  | @@ -24,6 +24,60 @@ import type { ToolNodeType } from './nodes/tool/types'
 | 
	
		
			
				|  |  |  import { CollectionType } from '@/app/components/tools/types'
 | 
	
		
			
				|  |  |  import { toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const WHITE = 'WHITE'
 | 
	
		
			
				|  |  | +const GRAY = 'GRAY'
 | 
	
		
			
				|  |  | +const BLACK = 'BLACK'
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const isCyclicUtil = (nodeId: string, color: Record<string, string>, adjaList: Record<string, string[]>, stack: string[]) => {
 | 
	
		
			
				|  |  | +  color[nodeId] = GRAY
 | 
	
		
			
				|  |  | +  stack.push(nodeId)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (let i = 0; i < adjaList[nodeId].length; ++i) {
 | 
	
		
			
				|  |  | +    const childId = adjaList[nodeId][i]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (color[childId] === GRAY) {
 | 
	
		
			
				|  |  | +      stack.push(childId)
 | 
	
		
			
				|  |  | +      return true
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (color[childId] === WHITE && isCyclicUtil(childId, color, adjaList, stack))
 | 
	
		
			
				|  |  | +      return true
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  color[nodeId] = BLACK
 | 
	
		
			
				|  |  | +  if (stack.length > 0 && stack[stack.length - 1] === nodeId)
 | 
	
		
			
				|  |  | +    stack.pop()
 | 
	
		
			
				|  |  | +  return false
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const getCycleEdges = (nodes: Node[], edges: Edge[]) => {
 | 
	
		
			
				|  |  | +  const adjaList: Record<string, string[]> = {}
 | 
	
		
			
				|  |  | +  const color: Record<string, string> = {}
 | 
	
		
			
				|  |  | +  const stack: string[] = []
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (const node of nodes) {
 | 
	
		
			
				|  |  | +    color[node.id] = WHITE
 | 
	
		
			
				|  |  | +    adjaList[node.id] = []
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (const edge of edges)
 | 
	
		
			
				|  |  | +    adjaList[edge.source].push(edge.target)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  for (let i = 0; i < nodes.length; i++) {
 | 
	
		
			
				|  |  | +    if (color[nodes[i].id] === WHITE)
 | 
	
		
			
				|  |  | +      isCyclicUtil(nodes[i].id, color, adjaList, stack)
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const cycleEdges = []
 | 
	
		
			
				|  |  | +  if (stack.length > 0) {
 | 
	
		
			
				|  |  | +    const cycleNodes = new Set(stack)
 | 
	
		
			
				|  |  | +    for (const edge of edges) {
 | 
	
		
			
				|  |  | +      if (cycleNodes.has(edge.source) && cycleNodes.has(edge.target))
 | 
	
		
			
				|  |  | +        cycleEdges.push(edge)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return cycleEdges
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  export const initialNodes = (nodes: Node[], edges: Edge[]) => {
 | 
	
		
			
				|  |  |    const firstNode = nodes[0]
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -35,6 +89,7 @@ export const initialNodes = (nodes: Node[], edges: Edge[]) => {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      })
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    return nodes.map((node) => {
 | 
	
		
			
				|  |  |      node.type = 'custom'
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -75,7 +130,11 @@ export const initialEdges = (edges: Edge[], nodes: Node[]) => {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return acc
 | 
	
		
			
				|  |  |    }, {} as Record<string, Node>)
 | 
	
		
			
				|  |  | -  return edges.map((edge) => {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const cycleEdges = getCycleEdges(nodes, edges)
 | 
	
		
			
				|  |  | +  return edges.filter((edge) => {
 | 
	
		
			
				|  |  | +    return !cycleEdges.find(cycEdge => cycEdge.source === edge.source && cycEdge.target === edge.target)
 | 
	
		
			
				|  |  | +  }).map((edge) => {
 | 
	
		
			
				|  |  |      edge.type = 'custom'
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (!edge.sourceHandle)
 |