diff --git a/web/app/components/sub-graph/components/sub-graph-main.tsx b/web/app/components/sub-graph/components/sub-graph-main.tsx index c8768a712f..295e8e065c 100644 --- a/web/app/components/sub-graph/components/sub-graph-main.tsx +++ b/web/app/components/sub-graph/components/sub-graph-main.tsx @@ -6,7 +6,7 @@ import type { NestedNodeConfig } from '@/app/components/workflow/nodes/_base/typ import type { Edge, Node } from '@/app/components/workflow/types' import { useCallback, useMemo } from 'react' import { useStoreApi } from 'reactflow' -import { WorkflowWithInnerContext } from '@/app/components/workflow' +import { InteractionMode, WorkflowWithInnerContext } from '@/app/components/workflow' import { useSetWorkflowVarsWithValue } from '@/app/components/workflow/hooks/use-fetch-workflow-inspect-vars' import { useInspectVarsCrudCommon } from '@/app/components/workflow/hooks/use-inspect-vars-crud-common' import { BlockEnum } from '@/app/components/workflow/types' @@ -96,7 +96,7 @@ const SubGraphMain: FC = (props) => { }, [selectableNodeTypes, variant]) const hooksStore = useMemo(() => ({ - interactionMode: 'subgraph', + interactionMode: InteractionMode.Subgraph, subGraphSelectableNodeTypes: resolvedSelectableTypes, availableNodesMetaData, configsMap, @@ -135,7 +135,7 @@ const SubGraphMain: FC = (props) => { hooksStore={hooksStore as any} allowSelectionWhenReadOnly canvasReadOnly - interactionMode="subgraph" + interactionMode={InteractionMode.Subgraph} > {subGraphChildren} diff --git a/web/app/components/workflow/hooks/use-nodes-available-var-list.ts b/web/app/components/workflow/hooks/use-nodes-available-var-list.ts index cb04b43002..18613a8652 100644 --- a/web/app/components/workflow/hooks/use-nodes-available-var-list.ts +++ b/web/app/components/workflow/hooks/use-nodes-available-var-list.ts @@ -1,10 +1,12 @@ import type { Node, NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' import { useCallback } from 'react' +import { useShallow } from 'zustand/react/shallow' import { useIsChatMode, useWorkflow, useWorkflowVariables, } from '@/app/components/workflow/hooks' +import { useStore } from '@/app/components/workflow/store' import { BlockEnum } from '@/app/components/workflow/types' type Params = { @@ -15,6 +17,20 @@ type Params = { passedInAvailableNodes?: Node[] } +const mergeAvailableNodes = (baseNodes: Node[], extraNodes: Node[]) => { + if (!extraNodes.length) + return baseNodes + const merged = new Map() + baseNodes.forEach((node) => { + merged.set(node.id, node) + }) + extraNodes.forEach((node) => { + if (!merged.has(node.id)) + merged.set(node.id, node) + }) + return Array.from(merged.values()) +} + const getNodeInfo = (nodeId: string, nodes: Node[]) => { const allNodes = nodes const node = allNodes.find(n => n.id === nodeId) @@ -44,12 +60,14 @@ const useNodesAvailableVarList = (nodes: Node[], { const { getTreeLeafNodes, getBeforeNodesInSameBranchIncludeParent } = useWorkflow() const { getNodeAvailableVars } = useWorkflowVariables() const isChatMode = useIsChatMode() + const parentAvailableNodes = useStore(useShallow(s => s.parentAvailableNodes)) || [] const nodeAvailabilityMap: { [key: string ]: { availableVars: NodeOutPutVar[], availableNodes: Node[] } } = {} nodes.forEach((node) => { const nodeId = node.id - const availableNodes = passedInAvailableNodes || (onlyLeafNodeVar ? getTreeLeafNodes(nodeId) : getBeforeNodesInSameBranchIncludeParent(nodeId)) + const baseAvailableNodes = passedInAvailableNodes || (onlyLeafNodeVar ? getTreeLeafNodes(nodeId) : getBeforeNodesInSameBranchIncludeParent(nodeId)) + const availableNodes = mergeAvailableNodes(baseAvailableNodes, parentAvailableNodes) if (node.data.type === BlockEnum.Loop) availableNodes.push(node) @@ -79,6 +97,7 @@ export const useGetNodesAvailableVarList = () => { const { getTreeLeafNodes, getBeforeNodesInSameBranchIncludeParent } = useWorkflow() const { getNodeAvailableVars } = useWorkflowVariables() const isChatMode = useIsChatMode() + const parentAvailableNodes = useStore(useShallow(s => s.parentAvailableNodes)) || [] const getNodesAvailableVarList = useCallback((nodes: Node[], { onlyLeafNodeVar, filterVar, @@ -93,7 +112,8 @@ export const useGetNodesAvailableVarList = () => { nodes.forEach((node) => { const nodeId = node.id - const availableNodes = passedInAvailableNodes || (onlyLeafNodeVar ? getTreeLeafNodes(nodeId) : getBeforeNodesInSameBranchIncludeParent(nodeId)) + const baseAvailableNodes = passedInAvailableNodes || (onlyLeafNodeVar ? getTreeLeafNodes(nodeId) : getBeforeNodesInSameBranchIncludeParent(nodeId)) + const availableNodes = mergeAvailableNodes(baseAvailableNodes, parentAvailableNodes) if (node.data.type === BlockEnum.Loop) availableNodes.push(node) @@ -117,7 +137,7 @@ export const useGetNodesAvailableVarList = () => { nodeAvailabilityMap[nodeId] = result }) return nodeAvailabilityMap - }, [getTreeLeafNodes, getBeforeNodesInSameBranchIncludeParent, getNodeAvailableVars, isChatMode]) + }, [getTreeLeafNodes, getBeforeNodesInSameBranchIncludeParent, getNodeAvailableVars, isChatMode, parentAvailableNodes]) return { getNodesAvailableVarList, } diff --git a/web/app/components/workflow/index.tsx b/web/app/components/workflow/index.tsx index 6436e5cf26..8b3fc14b82 100644 --- a/web/app/components/workflow/index.tsx +++ b/web/app/components/workflow/index.tsx @@ -134,6 +134,11 @@ const edgeTypes = { [CUSTOM_EDGE]: CustomEdge, } +export enum InteractionMode { + Default = 'default', + Subgraph = 'subgraph', +} + export type WorkflowProps = { nodes: Node[] edges: Edge[] @@ -142,7 +147,7 @@ export type WorkflowProps = { onWorkflowDataUpdate?: (v: any) => void allowSelectionWhenReadOnly?: boolean canvasReadOnly?: boolean - interactionMode?: 'default' | 'subgraph' + interactionMode?: InteractionMode } export const Workflow: FC = memo(({ nodes: originalNodes, @@ -223,7 +228,7 @@ export const Workflow: FC = memo(({ const store = useStoreApi() eventEmitter?.useSubscription((v: any) => { if (v.type === WORKFLOW_DATA_UPDATE) { - if (interactionMode === 'subgraph') + if (interactionMode === InteractionMode.Subgraph) return setNodes(v.payload.nodes) store.getState().setNodes(v.payload.nodes) diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx index bca8b79c14..d4455da743 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx @@ -270,8 +270,9 @@ const VarReferencePicker: FC = ({ }, [onChange, varKindType]) const handleVariableJump = useCallback((nodeId: string) => { - const currentNodeIndex = availableNodes.findIndex(node => node.id === nodeId) - const currentNode = availableNodes[currentNodeIndex] + const currentNode = nodes.find(node => node.id === nodeId) + if (!currentNode) + return const workflowContainer = document.getElementById('workflow-container') const { @@ -289,7 +290,7 @@ const VarReferencePicker: FC = ({ y: (clientHeight - currentNode.height! * zoom) / 2 - position.y * zoom, zoom: transform[2], }) - }, [availableNodes, reactflow, store]) + }, [nodes, reactflow, store]) const type = getCurrentVariableType({ parentNode: (isInIteration ? iterationNode : loopNode) as any, diff --git a/web/app/components/workflow/nodes/_base/hooks/use-available-var-list.ts b/web/app/components/workflow/nodes/_base/hooks/use-available-var-list.ts index e687813b69..861f99bf11 100644 --- a/web/app/components/workflow/nodes/_base/hooks/use-available-var-list.ts +++ b/web/app/components/workflow/nodes/_base/hooks/use-available-var-list.ts @@ -1,4 +1,6 @@ import type { Node, NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types' +import { useMemo } from 'react' +import { useShallow } from 'zustand/react/shallow' import { useIsChatMode, useWorkflow, @@ -31,7 +33,23 @@ const useAvailableVarList = (nodeId: string, { const { getTreeLeafNodes, getNodeById, getBeforeNodesInSameBranchIncludeParent } = useWorkflow() const { getNodeAvailableVars } = useWorkflowVariables() const isChatMode = useIsChatMode() - const availableNodes = passedInAvailableNodes || (onlyLeafNodeVar ? getTreeLeafNodes(nodeId) : getBeforeNodesInSameBranchIncludeParent(nodeId)) + const baseAvailableNodes = useMemo(() => { + return passedInAvailableNodes || (onlyLeafNodeVar ? getTreeLeafNodes(nodeId) : getBeforeNodesInSameBranchIncludeParent(nodeId)) + }, [passedInAvailableNodes, onlyLeafNodeVar, nodeId, getTreeLeafNodes, getBeforeNodesInSameBranchIncludeParent]) + const parentAvailableNodes = useWorkflowStore(useShallow(s => s.parentAvailableNodes)) || [] + const availableNodes = useMemo(() => { + if (!parentAvailableNodes.length) + return baseAvailableNodes + const merged = new Map() + baseAvailableNodes.forEach((node) => { + merged.set(node.id, node) + }) + parentAvailableNodes.forEach((node) => { + if (!merged.has(node.id)) + merged.set(node.id, node) + }) + return Array.from(merged.values()) + }, [baseAvailableNodes, parentAvailableNodes]) const { parentNode: iterationNode, } = useNodeInfo(nodeId) @@ -71,10 +89,12 @@ const useAvailableVarList = (nodeId: string, { hideEnv, hideChatVar, }), ...dataSourceRagVars] - const availableNodesWithParent = [ - ...availableNodes, - ...(isDataSourceNode ? [currNode] : []), - ] + const availableNodesWithParent = useMemo(() => { + return [ + ...availableNodes, + ...(isDataSourceNode ? [currNode] : []), + ] + }, [availableNodes, currNode, isDataSourceNode]) const llmNodeIds = new Set( availableNodesWithParent .filter(node => node?.data.type === BlockEnum.LLM) diff --git a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts index d2d7b6b6d9..e98017f794 100644 --- a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts +++ b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts @@ -1,4 +1,4 @@ -import type { CommonNodeType, InputVar, TriggerNodeType, ValueSelector, Var, Variable } from '@/app/components/workflow/types' +import type { CommonNodeType, InputVar, Node, TriggerNodeType, ValueSelector, Var, Variable } from '@/app/components/workflow/types' import type { FlowType } from '@/types/common' import type { NodeRunResult, NodeTracing } from '@/types/workflow' import { unionBy } from 'es-toolkit/compat' @@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next' import { useStoreApi, } from 'reactflow' +import { useShallow } from 'zustand/react/shallow' import { trackEvent } from '@/app/components/base/amplitude' import { getInputVars as doGetInputVars } from '@/app/components/base/prompt-editor/constants' import Toast from '@/app/components/base/toast' @@ -150,9 +151,24 @@ const useOneStepRun = ({ const isIteration = data.type === BlockEnum.Iteration const isLoop = data.type === BlockEnum.Loop const isStartNode = data.type === BlockEnum.Start + const parentAvailableNodes = useStore(useShallow(s => s.parentAvailableNodes)) || [] - const availableNodes = getBeforeNodesInSameBranch(id) - const availableNodesIncludeParent = getBeforeNodesInSameBranchIncludeParent(id) + const mergeAvailableNodes = (baseNodes: Node[]) => { + if (!parentAvailableNodes.length) + return baseNodes + const merged = new Map() + baseNodes.forEach((node) => { + merged.set(node.id, node) + }) + parentAvailableNodes.forEach((node) => { + if (!merged.has(node.id)) + merged.set(node.id, node) + }) + return Array.from(merged.values()) + } + + const availableNodes = mergeAvailableNodes(getBeforeNodesInSameBranch(id)) + const availableNodesIncludeParent = mergeAvailableNodes(getBeforeNodesInSameBranchIncludeParent(id)) const workflowStore = useWorkflowStore() const { schemaTypeDefinitions } = useMatchSchemaType() diff --git a/web/app/components/workflow/nodes/iteration/use-single-run-form-params.ts b/web/app/components/workflow/nodes/iteration/use-single-run-form-params.ts index fd53a603a5..634bad2ad9 100644 --- a/web/app/components/workflow/nodes/iteration/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/iteration/use-single-run-form-params.ts @@ -1,10 +1,12 @@ import type { RefObject } from 'react' import type { IterationNodeType } from './types' -import type { InputVar, ValueSelector, Variable } from '@/app/components/workflow/types' +import type { InputVar, Node, ValueSelector, Variable } from '@/app/components/workflow/types' import type { NodeTracing } from '@/types/workflow' import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' +import { useShallow } from 'zustand/react/shallow' import formatTracing from '@/app/components/workflow/run/utils/format-log' +import { useStore } from '@/app/components/workflow/store' import { InputVarType, VarType } from '@/app/components/workflow/types' import { VALUE_SELECTOR_DELIMITER as DELIMITER } from '@/config' import { useIsNodeInIteration, useWorkflow } from '../../hooks' @@ -34,8 +36,22 @@ const useSingleRunFormParams = ({ const { isNodeInIteration } = useIsNodeInIteration(id) const { getIterationNodeChildren, getBeforeNodesInSameBranch } = useWorkflow() + const parentAvailableNodes = useStore(useShallow(s => s.parentAvailableNodes)) || [] const iterationChildrenNodes = getIterationNodeChildren(id) - const beforeNodes = getBeforeNodesInSameBranch(id) + const beforeNodes = (() => { + const baseBeforeNodes = getBeforeNodesInSameBranch(id) + if (!parentAvailableNodes.length) + return baseBeforeNodes + const merged = new Map() + baseBeforeNodes.forEach((node) => { + merged.set(node.id, node) + }) + parentAvailableNodes.forEach((node) => { + if (!merged.has(node.id)) + merged.set(node.id, node) + }) + return Array.from(merged.values()) + })() const canChooseVarNodes = [...beforeNodes, ...iterationChildrenNodes] const iteratorInputKey = `${id}.input_selector` diff --git a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx index 7866d5ffae..bffe7312e5 100644 --- a/web/app/components/workflow/nodes/llm/components/config-prompt.tsx +++ b/web/app/components/workflow/nodes/llm/components/config-prompt.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import type { ModelConfig, Node, NodeOutPutVar, PromptItem, PromptMessageContext, PromptTemplateItem, ValueSelector, Var, Variable } from '../../../types' +import type { ModelConfig, NodeOutPutVar, PromptItem, PromptMessageContext, PromptTemplateItem, ValueSelector, Var, Variable } from '../../../types' import { produce } from 'immer' import * as React from 'react' import { useCallback, useMemo, useRef, useState } from 'react' @@ -18,7 +18,7 @@ import AddButton from '@/app/components/workflow/nodes/_base/components/add-butt import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars' import { cn } from '@/utils/classnames' -import { useStore, useWorkflowStore } from '../../../store' +import { useWorkflowStore } from '../../../store' import { BlockEnum, EditionType, isPromptMessageContext, PromptRole, VarType } from '../../../types' import useAvailableVarList from '../../_base/hooks/use-available-var-list' import ConfigContextItem from './config-context-item' @@ -88,39 +88,9 @@ const ConfigPrompt: FC = ({ onlyLeafNodeVar: false, filterVar, }) - const parentAvailableVars = useStore(state => state.parentAvailableVars) || [] - const parentAvailableNodes = useStore(state => state.parentAvailableNodes) || [] - - const mergedAvailableVars = useMemo(() => { - if (!parentAvailableVars.length) - return availableVars - const merged = new Map() - availableVars.forEach((item) => { - merged.set(item.nodeId, item) - }) - parentAvailableVars.forEach((item) => { - if (!merged.has(item.nodeId)) - merged.set(item.nodeId, item) - }) - return Array.from(merged.values()) - }, [availableVars, parentAvailableVars]) - - const mergedAvailableNodesWithParent = useMemo(() => { - if (!parentAvailableNodes.length) - return availableNodesWithParent - const merged = new Map() - availableNodesWithParent.forEach((node) => { - merged.set(node.id, node) - }) - parentAvailableNodes.forEach((node) => { - if (!merged.has(node.id)) - merged.set(node.id, node) - }) - return Array.from(merged.values()) - }, [availableNodesWithParent, parentAvailableNodes]) const contextVarOptions = useMemo(() => { - return mergedAvailableNodesWithParent + return availableNodesWithParent .filter(node => node.data.type === BlockEnum.Agent || node.data.type === BlockEnum.LLM) .map(node => ({ nodeId: node.id, @@ -133,7 +103,7 @@ const ConfigPrompt: FC = ({ }, ], })) - }, [mergedAvailableNodesWithParent]) + }, [availableNodesWithParent]) const handleChatModePromptChange = useCallback((index: number) => { return (prompt: string) => { @@ -315,7 +285,7 @@ const ConfigPrompt: FC = ({ readOnly={readOnly} payload={item} contextVars={contextVarOptions} - availableNodes={mergedAvailableNodesWithParent} + availableNodes={availableNodesWithParent} onChange={handleContextChange(index)} onRemove={handleRemove(index)} /> @@ -354,8 +324,8 @@ const ConfigPrompt: FC = ({ onRemove={handleRemove(index)} isShowContext={isShowContext} hasSetBlockStatus={hasSetBlockStatus} - availableVars={mergedAvailableVars} - availableNodes={mergedAvailableNodesWithParent} + availableVars={availableVars} + availableNodes={availableNodesWithParent} varList={varList} handleAddVariable={handleAddVariable} modelConfig={modelConfig} @@ -425,8 +395,8 @@ const ConfigPrompt: FC = ({ isChatApp={isChatApp} isShowContext={isShowContext} hasSetBlockStatus={hasSetBlockStatus} - nodesOutputVars={mergedAvailableVars} - availableNodes={mergedAvailableNodesWithParent} + nodesOutputVars={availableVars} + availableNodes={availableNodesWithParent} isSupportPromptGenerator isSupportJinja editionType={(payload as PromptItem).edition_type} diff --git a/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts b/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts index c4123b0e30..482e3055ed 100644 --- a/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts @@ -1,9 +1,11 @@ -import type { InputVar, ValueSelector, Variable } from '../../types' +import type { InputVar, Node, ValueSelector, Variable } from '../../types' import type { CaseItem, Condition, LoopNodeType } from './types' import type { NodeTracing } from '@/types/workflow' import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' +import { useShallow } from 'zustand/react/shallow' import formatTracing from '@/app/components/workflow/run/utils/format-log' +import { useStore } from '@/app/components/workflow/store' import { ValueType } from '@/app/components/workflow/types' import { VALUE_SELECTOR_DELIMITER as DELIMITER } from '@/config' import { useIsNodeInLoop, useWorkflow } from '../../hooks' @@ -35,8 +37,22 @@ const useSingleRunFormParams = ({ const { isNodeInLoop } = useIsNodeInLoop(id) const { getLoopNodeChildren, getBeforeNodesInSameBranch } = useWorkflow() + const parentAvailableNodes = useStore(useShallow(s => s.parentAvailableNodes)) || [] const loopChildrenNodes = getLoopNodeChildren(id) - const beforeNodes = getBeforeNodesInSameBranch(id) + const beforeNodes = (() => { + const baseBeforeNodes = getBeforeNodesInSameBranch(id) + if (!parentAvailableNodes.length) + return baseBeforeNodes + const merged = new Map() + baseBeforeNodes.forEach((node) => { + merged.set(node.id, node) + }) + parentAvailableNodes.forEach((node) => { + if (!merged.has(node.id)) + merged.set(node.id, node) + }) + return Array.from(merged.values()) + })() const canChooseVarNodes = [...beforeNodes, ...loopChildrenNodes] const { usedOutVars, allVarObject } = (() => { diff --git a/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx b/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx index a451b92d1d..59a562fec1 100644 --- a/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx +++ b/web/app/components/workflow/nodes/tool/components/context-generate-modal/components/right-panel.tsx @@ -1,6 +1,6 @@ import type { PointerEvent, RefObject } from 'react' import type { ContextGenerateResponse } from '@/service/debug' -import { RiArrowDownSLine, RiCheckLine, RiCloseLine } from '@remixicon/react' +import { RiArrowDownSLine, RiCheckLine, RiCloseLine, RiPlayLargeLine } from '@remixicon/react' import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' @@ -178,6 +178,7 @@ const RightPanel = ({ onClick={onRun} disabled={!canRun || isGenerating} > + {t('nodes.tool.contextGenerate.run', { ns: 'workflow' })} )} diff --git a/web/app/components/workflow/nodes/tool/components/sub-graph-modal/index.tsx b/web/app/components/workflow/nodes/tool/components/sub-graph-modal/index.tsx index 7d5cab1f1f..5ff96a01a2 100644 --- a/web/app/components/workflow/nodes/tool/components/sub-graph-modal/index.tsx +++ b/web/app/components/workflow/nodes/tool/components/sub-graph-modal/index.tsx @@ -18,7 +18,7 @@ import { useIsChatMode, useNodesSyncDraft, useWorkflow, useWorkflowVariables } f import { useHooksStore } from '@/app/components/workflow/hooks-store' import { VarKindType } from '@/app/components/workflow/nodes/_base/types' import { useStore as useWorkflowStore } from '@/app/components/workflow/store' -import { BlockEnum, EditionType, isPromptMessageContext, PromptRole, VarType } from '@/app/components/workflow/types' +import { EditionType, isPromptMessageContext, PromptRole, VarType } from '@/app/components/workflow/types' import SubGraphCanvas from './sub-graph-canvas' const SubGraphModal: FC = (props) => { @@ -64,17 +64,11 @@ const SubGraphModal: FC = (props) => { return getBeforeNodesInSameBranch(toolNodeId, workflowNodes, workflowEdges) }, [getBeforeNodesInSameBranch, isOpen, toolNodeId, workflowEdges, workflowNodes]) - const parentContextNodes = useMemo(() => { - if (!parentBeforeNodes.length || !isAgentVariant) - return [] - return parentBeforeNodes.filter(node => node.data.type === BlockEnum.Agent || node.data.type === BlockEnum.LLM) - }, [isAgentVariant, parentBeforeNodes]) - const parentAvailableNodes = useMemo(() => { if (!isOpen) return [] - return isAgentVariant ? parentContextNodes : parentBeforeNodes - }, [isAgentVariant, isOpen, parentBeforeNodes, parentContextNodes]) + return parentBeforeNodes + }, [isOpen, parentBeforeNodes]) const parentAvailableVars = useMemo(() => { if (!parentAvailableNodes.length)