From 77950e48c76f4a3b29d01831d43039caba29888a Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期二, 18 十一月 2025 14:12:42 +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