From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001
From: wwf <yearningwang@iqtogether.com>
Date: 星期三, 04 六月 2025 15:17:49 +0800
Subject: [PATCH] 初始化

---
 app/components/workflow/nodes/_base/components/variable/utils.ts |  394 ++++----------------------------------------------------
 1 files changed, 29 insertions(+), 365 deletions(-)

diff --git a/app/components/workflow/nodes/_base/components/variable/utils.ts b/app/components/workflow/nodes/_base/components/variable/utils.ts
index 428c204..24c2b73 100644
--- a/app/components/workflow/nodes/_base/components/variable/utils.ts
+++ b/app/components/workflow/nodes/_base/components/variable/utils.ts
@@ -3,7 +3,7 @@
 import type { CodeNodeType } from '../../../code/types'
 import type { EndNodeType } from '../../../end/types'
 import type { AnswerNodeType } from '../../../answer/types'
-import { type LLMNodeType, type StructuredOutput, Type } from '../../../llm/types'
+import type { LLMNodeType } from '../../../llm/types'
 import type { KnowledgeRetrievalNodeType } from '../../../knowledge-retrieval/types'
 import type { IfElseNodeType } from '../../../if-else/types'
 import type { TemplateTransformNodeType } from '../../../template-transform/types'
@@ -13,16 +13,13 @@
 import type { ToolNodeType } from '../../../tool/types'
 import type { ParameterExtractorNodeType } from '../../../parameter-extractor/types'
 import type { IterationNodeType } from '../../../iteration/types'
-import type { LoopNodeType } from '../../../loop/types'
 import type { ListFilterNodeType } from '../../../list-operator/types'
-import { OUTPUT_FILE_SUB_VARIABLES } from '../../../constants'
+import { OUTPUT_FILE_SUB_VARIABLES } from '../../../if-else/default'
 import type { DocExtractorNodeType } from '../../../document-extractor/types'
 import { BlockEnum, InputVarType, VarType } from '@/app/components/workflow/types'
 import type { StartNodeType } from '@/app/components/workflow/nodes/start/types'
 import type { ConversationVariable, EnvironmentVariable, Node, NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
 import type { VariableAssignerNodeType } from '@/app/components/workflow/nodes/variable-assigner/types'
-import type { Field as StructField } from '@/app/components/workflow/nodes/llm/types'
-
 import {
   HTTP_REQUEST_OUTPUT_STRUCT,
   KNOWLEDGE_RETRIEVAL_OUTPUT_STRUCT,
@@ -35,7 +32,6 @@
 } from '@/app/components/workflow/constants'
 import type { PromptItem } from '@/models/debug'
 import { VAR_REGEX } from '@/config'
-import type { AgentNodeType } from '../../../agent/types'
 
 export const isSystemVar = (valueSelector: ValueSelector) => {
   return valueSelector[0] === 'sys' || valueSelector[1] === 'sys'
@@ -57,110 +53,21 @@
   } as any)[type] || VarType.string
 }
 
-const structTypeToVarType = (type: Type, isArray?: boolean): VarType => {
-  if (isArray) {
-    return ({
-      [Type.string]: VarType.arrayString,
-      [Type.number]: VarType.arrayNumber,
-      [Type.object]: VarType.arrayObject,
-    } as any)[type] || VarType.string
-  }
-  return ({
-    [Type.string]: VarType.string,
-    [Type.number]: VarType.number,
-    [Type.boolean]: VarType.boolean,
-    [Type.object]: VarType.object,
-    [Type.array]: VarType.array,
-  } as any)[type] || VarType.string
-}
-
-export const varTypeToStructType = (type: VarType): Type => {
-  return ({
-    [VarType.string]: Type.string,
-    [VarType.number]: Type.number,
-    [VarType.boolean]: Type.boolean,
-    [VarType.object]: Type.object,
-    [VarType.array]: Type.array,
-  } as any)[type] || Type.string
-}
-
-const findExceptVarInStructuredProperties = (properties: Record<string, StructField>, filterVar: (payload: Var, selector: ValueSelector) => boolean): Record<string, StructField> => {
-  const res = produce(properties, (draft) => {
-    Object.keys(properties).forEach((key) => {
-      const item = properties[key]
-      const isObj = item.type === Type.object
-      const isArray = item.type === Type.array
-      const arrayType = item.items?.type
-
-      if (!isObj && !filterVar({
-        variable: key,
-        type: structTypeToVarType(isArray ? arrayType! : item.type, isArray),
-      }, [key])) {
-        delete properties[key]
-        return
-      }
-      if (item.type === Type.object && item.properties)
-        item.properties = findExceptVarInStructuredProperties(item.properties, filterVar)
-    })
-    return draft
-  })
-  return res
-}
-
-const findExceptVarInStructuredOutput = (structuredOutput: StructuredOutput, filterVar: (payload: Var, selector: ValueSelector) => boolean): StructuredOutput => {
-  const res = produce(structuredOutput, (draft) => {
-    const properties = draft.schema.properties
-    Object.keys(properties).forEach((key) => {
-      const item = properties[key]
-      const isObj = item.type === Type.object
-      const isArray = item.type === Type.array
-      const arrayType = item.items?.type
-      if (!isObj && !filterVar({
-        variable: key,
-        type: structTypeToVarType(isArray ? arrayType! : item.type, isArray),
-      }, [key])) {
-        delete properties[key]
-        return
-      }
-      if (item.type === Type.object && item.properties)
-        item.properties = findExceptVarInStructuredProperties(item.properties, filterVar)
-    })
-    return draft
-  })
-  return res
-}
-
 const findExceptVarInObject = (obj: any, filterVar: (payload: Var, selector: ValueSelector) => boolean, value_selector: ValueSelector, isFile?: boolean): Var => {
   const { children } = obj
-  const isStructuredOutput = !!(children as StructuredOutput)?.schema?.properties
-
-  let childrenResult: Var[] | StructuredOutput | undefined
-
-  if (isStructuredOutput) {
-    childrenResult = findExceptVarInStructuredOutput(children, filterVar)
-  }
- else if (Array.isArray(children)) {
-    childrenResult = children.filter((item: Var) => {
-      const { children: itemChildren } = item
-      const currSelector = [...value_selector, item.variable]
-
-      if (!itemChildren)
-        return filterVar(item, currSelector)
-
-      const filteredObj = findExceptVarInObject(item, filterVar, currSelector, false) // File doesn't contain file children
-      return filteredObj.children && (filteredObj.children as Var[])?.length > 0
-    })
-  }
- else {
-    childrenResult = []
-  }
-
   const res: Var = {
     variable: obj.variable,
     type: isFile ? VarType.file : VarType.object,
-    children: childrenResult,
-  }
+    children: children.filter((item: Var) => {
+      const { children } = item
+      const currSelector = [...value_selector, item.variable]
+      if (!children)
+        return filterVar(item, currSelector)
 
+      const obj = findExceptVarInObject(item, filterVar, currSelector, false) // File doesn't contains file children
+      return obj.children && obj.children?.length > 0
+    }),
+  }
   return res
 }
 
@@ -230,17 +137,10 @@
     }
 
     case BlockEnum.LLM: {
-      res.vars = [...LLM_OUTPUT_STRUCT]
-      if (data.structured_output_enabled && data.structured_output?.schema?.properties && Object.keys(data.structured_output.schema.properties).length > 0) {
-        res.vars.push({
-          variable: 'structured_output',
-          type: VarType.object,
-          children: data.structured_output,
-        })
-      }
-
+      res.vars = LLM_OUTPUT_STRUCT
       break
     }
+
     case BlockEnum.KnowledgeRetrieval: {
       res.vars = KNOWLEDGE_RETRIEVAL_OUTPUT_STRUCT
       break
@@ -305,7 +205,6 @@
       break
     }
 
-    // eslint-disable-next-line sonarjs/no-duplicated-branches
     case BlockEnum.VariableAggregator: {
       const {
         output_type,
@@ -336,36 +235,7 @@
     }
 
     case BlockEnum.Tool: {
-      const {
-        output_schema,
-      } = data as ToolNodeType
-      if (!output_schema) {
-        res.vars = TOOL_OUTPUT_STRUCT
-      }
-      else {
-        const outputSchema: any[] = []
-        Object.keys(output_schema.properties).forEach((outputKey) => {
-          const output = output_schema.properties[outputKey]
-          const dataType = output.type
-          outputSchema.push({
-            variable: outputKey,
-            type: dataType === 'array'
-              ? `array[${output.items?.type.slice(0, 1).toLocaleLowerCase()}${output.items?.type.slice(1)}]`
-              : `${output.type.slice(0, 1).toLocaleLowerCase()}${output.type.slice(1)}`,
-            description: output.description,
-            children: output.type === 'object' ? {
-              schema: {
-                type: 'object',
-                properties: output.properties,
-              },
-            } : undefined,
-          })
-        })
-        res.vars = [
-          ...TOOL_OUTPUT_STRUCT,
-          ...outputSchema,
-        ]
-      }
+      res.vars = TOOL_OUTPUT_STRUCT
       break
     }
 
@@ -389,21 +259,6 @@
           type: (data as IterationNodeType).output_type || VarType.arrayString,
         },
       ]
-      break
-    }
-
-    case BlockEnum.Loop: {
-      const { loop_variables } = data as LoopNodeType
-      res.isLoop = true
-      res.vars = loop_variables?.map((v) => {
-        return {
-          variable: v.label,
-          type: v.var_type,
-          isLoopVariable: true,
-          nodeId: res.nodeId,
-        }
-      }) || []
-
       break
     }
 
@@ -434,25 +289,6 @@
           variable: 'last_record',
           type: (data as ListFilterNodeType).item_var_type,
         },
-      ]
-      break
-    }
-
-    case BlockEnum.Agent: {
-      const payload = data as AgentNodeType
-      const outputs: Var[] = []
-      Object.keys(payload.output_schema?.properties || {}).forEach((outputKey) => {
-        const output = payload.output_schema.properties[outputKey]
-        outputs.push({
-          variable: outputKey,
-          type: output.type === 'array'
-            ? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` as VarType
-            : `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}` as VarType,
-        })
-      })
-      res.vars = [
-        ...outputs,
-        ...TOOL_OUTPUT_STRUCT,
       ]
       break
     }
@@ -501,7 +337,7 @@
   res.vars = res.vars.filter((v) => {
     const isCurrentMatched = filterVar(v, (() => {
       const variableArr = v.variable.split('.')
-      const [first] = variableArr
+      const [first, ..._other] = variableArr
       if (first === 'sys' || first === 'env' || first === 'conversation')
         return variableArr
 
@@ -526,7 +362,7 @@
       return false
 
     const obj = findExceptVarInObject(isFile ? { ...v, children } : v, filterVar, selector, isFile)
-    return obj?.children && ((obj?.children as Var[]).length > 0 || Object.keys((obj?.children as StructuredOutput)?.schema?.properties || {}).length > 0)
+    return obj?.children && obj?.children.length > 0
   }).map((v) => {
     const isFile = v.type === VarType.file
 
@@ -577,20 +413,8 @@
       chatVarList: conversationVariables,
     },
   }
-  // Sort nodes in reverse chronological order (most recent first)
-  const sortedNodes = [...nodes].sort((a, b) => {
-    if (a.data.type === BlockEnum.Start) return 1
-    if (b.data.type === BlockEnum.Start) return -1
-    if (a.data.type === 'env') return 1
-    if (b.data.type === 'env') return -1
-    if (a.data.type === 'conversation') return 1
-    if (b.data.type === 'conversation') return -1
-    // sort nodes by x position
-    return (b.position?.x || 0) - (a.position?.x || 0)
-  })
-
   const res = [
-    ...sortedNodes.filter(node => SUPPORT_OUTPUT_VARS_NODE.includes(node?.data?.type)),
+    ...nodes.filter(node => SUPPORT_OUTPUT_VARS_NODE.includes(node.data.type)),
     ...(environmentVariables.length > 0 ? [ENV_NODE] : []),
     ...((isChatMode && conversationVariables.length > 0) ? [CHAT_VAR_NODE] : []),
   ].map((node) => {
@@ -608,57 +432,6 @@
 }: {
   valueSelector: ValueSelector
   beforeNodesOutputVars: NodeOutPutVar[]
-}): VarType => {
-  const outputVarNodeId = valueSelector[0]
-  const isSystem = isSystemVar(valueSelector)
-
-  const targetVar = isSystem ? beforeNodesOutputVars.find(v => v.isStartNode) : beforeNodesOutputVars.find(v => v.nodeId === outputVarNodeId)
-
-  if (!targetVar)
-    return VarType.string
-
-  let arrayType: VarType = VarType.string
-
-  let curr: any = targetVar.vars
-  if (isSystem) {
-    arrayType = curr.find((v: any) => v.variable === (valueSelector).join('.'))?.type
-  }
-  else {
-    for (let i = 1; i < valueSelector.length; i++) {
-      const key = valueSelector[i]
-      const isLast = i === valueSelector.length - 1
-      curr = Array.isArray(curr) ? curr.find(v => v.variable === key) : []
-
-      if (isLast)
-      arrayType = curr?.type
-      else if (curr?.type === VarType.object || curr?.type === VarType.file)
-      curr = curr.children || []
-    }
-  }
-
-  switch (arrayType as VarType) {
-    case VarType.arrayString:
-      return VarType.string
-    case VarType.arrayNumber:
-      return VarType.number
-    case VarType.arrayObject:
-      return VarType.object
-    case VarType.array:
-      return VarType.any
-    case VarType.arrayFile:
-      return VarType.file
-    default:
-      return VarType.string
-  }
-}
-
-const getLoopItemType = ({
-  valueSelector,
-  beforeNodesOutputVars,
-}: {
-  valueSelector: ValueSelector
-  beforeNodesOutputVars: NodeOutPutVar[]
-
 }): VarType => {
   const outputVarNodeId = valueSelector[0]
   const isSystem = isSystemVar(valueSelector)
@@ -707,17 +480,16 @@
   parentNode,
   valueSelector,
   isIterationItem,
-  isLoopItem,
   availableNodes,
   isChatMode,
   isConstant,
   environmentVariables = [],
   conversationVariables = [],
-}: {
+}:
+{
   valueSelector: ValueSelector
   parentNode?: Node | null
   isIterationItem?: boolean
-  isLoopItem?: boolean
   availableNodes: any[]
   isChatMode: boolean
   isConstant?: boolean
@@ -753,31 +525,11 @@
     if (valueSelector[1] === 'index')
       return VarType.number
   }
-
-  const isLoopInnerVar = parentNode?.data.type === BlockEnum.Loop
-  if (isLoopItem) {
-    return getLoopItemType({
-      valueSelector,
-      beforeNodesOutputVars,
-    })
-  }
-  if (isLoopInnerVar) {
-    if (valueSelector[1] === 'item') {
-      const itemType = getLoopItemType({
-        valueSelector: (parentNode?.data as any).iterator_selector || [],
-        beforeNodesOutputVars,
-      })
-      return itemType
-    }
-    if (valueSelector[1] === 'index')
-      return VarType.number
-  }
-
   const isSystem = isSystemVar(valueSelector)
   const isEnv = isENV(valueSelector)
   const isChatVar = isConversationVar(valueSelector)
   const startNode = availableNodes.find((node: any) => {
-    return node?.data.type === BlockEnum.Start
+    return node.data.type === BlockEnum.Start
   })
 
   const targetVarNodeId = isSystem ? startNode?.id : valueSelector[0]
@@ -788,33 +540,10 @@
 
   let type: VarType = VarType.string
   let curr: any = targetVar.vars
-
   if (isSystem || isEnv || isChatVar) {
     return curr.find((v: any) => v.variable === (valueSelector as ValueSelector).join('.'))?.type
   }
   else {
-    const targetVar = curr.find((v: any) => v.variable === valueSelector[1])
-    if (!targetVar)
-      return VarType.string
-
-    const isStructuredOutputVar = !!targetVar.children?.schema?.properties
-    if (isStructuredOutputVar) {
-      if (valueSelector.length === 2) { // root
-        return VarType.object
-      }
-      let currProperties = targetVar.children.schema;
-      (valueSelector as ValueSelector).slice(2).forEach((key, i) => {
-        const isLast = i === valueSelector.length - 3
-        if (!currProperties)
-          return
-
-        currProperties = currProperties.properties[key]
-        if (isLast)
-          type = structTypeToVarType(currProperties?.type)
-      })
-      return type
-    }
-
     (valueSelector as ValueSelector).slice(1).forEach((key, i) => {
       const isLast = i === valueSelector.length - 2
       if (Array.isArray(curr))
@@ -897,9 +626,6 @@
         },
       ],
     }
-    const iterationIndex = beforeNodesOutputVars.findIndex(v => v.nodeId === iterationNode?.id)
-    if (iterationIndex > -1)
-      beforeNodesOutputVars.splice(iterationIndex, 1)
     beforeNodesOutputVars.unshift(iterationVar)
   }
   return beforeNodesOutputVars
@@ -954,7 +680,7 @@
       break
     }
     case BlockEnum.LLM: {
-      const payload = data as LLMNodeType
+      const payload = (data as LLMNodeType)
       const isChatModel = payload.model?.mode === 'chat'
       let prompts: string[] = []
       if (isChatModel) {
@@ -992,19 +718,19 @@
       break
     }
     case BlockEnum.QuestionClassifier: {
-      const payload = data as QuestionClassifierNodeType
+      const payload = (data as QuestionClassifierNodeType)
       res = [payload.query_variable_selector]
       const varInInstructions = matchNotSystemVars([payload.instruction || ''])
       res.push(...varInInstructions)
       break
     }
     case BlockEnum.HttpRequest: {
-      const payload = data as HttpNodeType
+      const payload = (data as HttpNodeType)
       res = matchNotSystemVars([payload.url, payload.headers, payload.params, typeof payload.body.data === 'string' ? payload.body.data : payload.body.data.map(d => d.value).join('')])
       break
     }
     case BlockEnum.Tool: {
-      const payload = data as ToolNodeType
+      const payload = (data as ToolNodeType)
       const mixVars = matchNotSystemVars(Object.keys(payload.tool_parameters)?.filter(key => payload.tool_parameters[key].type === ToolVarType.mixed).map(key => payload.tool_parameters[key].value) as string[])
       const vars = Object.keys(payload.tool_parameters).filter(key => payload.tool_parameters[key].type === ToolVarType.variable).map(key => payload.tool_parameters[key].value as string) || []
       res = [...(mixVars as ValueSelector[]), ...(vars as any)]
@@ -1022,7 +748,7 @@
     }
 
     case BlockEnum.ParameterExtractor: {
-      const payload = data as ParameterExtractorNodeType
+      const payload = (data as ParameterExtractorNodeType)
       res = [payload.query]
       const varInInstructions = matchNotSystemVars([payload.instruction || ''])
       res.push(...varInInstructions)
@@ -1034,31 +760,8 @@
       break
     }
 
-    case BlockEnum.Loop: {
-      const payload = data as LoopNodeType
-      res = payload.break_conditions?.map((c) => {
-        return c.variable_selector || []
-      }) || []
-      break
-    }
-
     case BlockEnum.ListFilter: {
       res = [(data as ListFilterNodeType).variable]
-      break
-    }
-
-    case BlockEnum.Agent: {
-      const payload = data as AgentNodeType
-      const valueSelectors: ValueSelector[] = []
-      if (!payload.agent_parameters)
-        break
-
-      Object.keys(payload.agent_parameters || {}).forEach((key) => {
-        const { value } = payload.agent_parameters![key]
-        if (typeof value === 'string')
-          valueSelectors.push(...matchNotSystemVars([value]))
-      })
-      res = valueSelectors
       break
     }
   }
@@ -1072,7 +775,7 @@
   let res: string | string[] = ''
   switch (type) {
     case BlockEnum.LLM: {
-      const payload = data as LLMNodeType
+      const payload = (data as LLMNodeType)
       res = [`#${valueSelector.join('.')}#`]
       if (payload.context?.variable_selector.join('.') === valueSelector.join('.'))
         res.push('#context#')
@@ -1294,7 +997,6 @@
         }
         break
       }
-      // eslint-disable-next-line sonarjs/no-duplicated-branches
       case BlockEnum.VariableAggregator: {
         const payload = data as VariableAssignerNodeType
         if (payload.variables) {
@@ -1320,17 +1022,6 @@
 
         break
       }
-      case BlockEnum.Loop: {
-        const payload = data as LoopNodeType
-        if (payload.break_conditions) {
-          payload.break_conditions = payload.break_conditions.map((c) => {
-            if (c.variable_selector?.join('.') === oldVarSelector.join('.'))
-              c.variable_selector = newVarSelector
-            return c
-          })
-        }
-        break
-      }
       case BlockEnum.ListFilter: {
         const payload = data as ListFilterNodeType
         if (payload.variable.join('.') === oldVarSelector.join('.'))
@@ -1341,28 +1032,15 @@
   })
   return newNode
 }
-
 const varToValueSelectorList = (v: Var, parentValueSelector: ValueSelector, res: ValueSelector[]) => {
   if (!v.variable)
     return
 
   res.push([...parentValueSelector, v.variable])
-  const isStructuredOutput = !!(v.children as StructuredOutput)?.schema?.properties
 
-  if ((v.children as Var[])?.length > 0) {
-    (v.children as Var[]).forEach((child) => {
+  if (v.children && v.children.length > 0) {
+    v.children.forEach((child) => {
       varToValueSelectorList(child, [...parentValueSelector, v.variable], res)
-    })
-  }
-  if (isStructuredOutput) {
-    Object.keys((v.children as StructuredOutput)?.schema?.properties || {}).forEach((key) => {
-      const type = (v.children as StructuredOutput)?.schema?.properties[key].type
-      const isArray = type === Type.array
-      const arrayType = (v.children as StructuredOutput)?.schema?.properties[key].items?.type
-      varToValueSelectorList({
-        variable: key,
-        type: structTypeToVarType(isArray ? arrayType! : type, isArray),
-      }, [...parentValueSelector, v.variable], res)
     })
   }
 }
@@ -1398,16 +1076,7 @@
     }
 
     case BlockEnum.LLM: {
-      const vars = [...LLM_OUTPUT_STRUCT]
-      const llmNodeData = data as LLMNodeType
-      if (llmNodeData.structured_output_enabled && llmNodeData.structured_output?.schema?.properties && Object.keys(llmNodeData.structured_output.schema.properties).length > 0) {
-        vars.push({
-          variable: 'structured_output',
-          type: VarType.object,
-          children: llmNodeData.structured_output,
-        })
-      }
-      varsToValueSelectorList(vars, [id], res)
+      varsToValueSelectorList(LLM_OUTPUT_STRUCT, [id], res)
       break
     }
 
@@ -1470,11 +1139,6 @@
     }
 
     case BlockEnum.Iteration: {
-      res.push([id, 'output'])
-      break
-    }
-
-    case BlockEnum.Loop: {
       res.push([id, 'output'])
       break
     }

--
Gitblit v1.8.0