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