utils.ts
Overview
utils.ts is a utility module designed to support the construction, manipulation, and management of nodes, edges, and operator parameters within a graph-based flow system, likely related to a RAG (Retrieval-Augmented Generation) or agent workflow application. The file provides helper functions to:
Build DSL components from graph nodes and edges
Process and clean operator parameters
Handle agent-specific constructs such as sub-agents and exception paths
Convert between different data representations (lists, objects)
Manage node naming, duplication, and positioning
Facilitate form value extraction and manipulation
Support UI-related functionalities like drag handles and drawer width
Manage edge state and mouse interactions
This module interacts primarily with graph data structures (nodes, edges), forms (via Ant Design's FormInstance), and domain-specific interfaces and constants representing operators, node types, and positions.
Detailed Explanations
Imports and Dependencies
Interfaces from agent and flow modules (
IAgentForm,ICategorizeForm, etc.)Utility functions like
removeUselessFieldsFromValuesTypes from @xyflow/react for graph elements (
Edge,Node,XYPosition)Ant Design form utilities (
FormInstance,FormListFieldData)Lodash utilities (
curry,get,intersectionWith, etc.)Constants such as operator names, node handle IDs, and anchor positions
Constants and Curry Functions
removeUselessDataInTheOperator
const removeUselessDataInTheOperator = curry(
(operatorName: string, params: Record<string, unknown>) => {
if (
operatorName === Operator.Generate ||
operatorName === Operator.Categorize
) {
return removeUselessFieldsFromValues(params, '');
}
return params;
},
);
Purpose: Cleans operator parameters by removing unnecessary fields for specific operators (
GenerateandCategorize).Parameters:
operatorName: Name of the operator (string).params: Operator parameters object.
Returns: Cleaned parameters object.
Usage: Used in parameter preparation before building DSL components.
Functions
buildAgentExceptionGoto
function buildAgentExceptionGoto(edges: Edge[], nodeId: string): string[]
Purpose: Finds all target node IDs that an agent node's exception handle points to.
Parameters:
edges: Array of graph edges.nodeId: The agent node's ID.
Returns: Array of target node IDs where exceptions route to.
Usage: Used when building agent operator parameters to handle exception routing.
buildComponentDownstreamOrUpstream
const buildComponentDownstreamOrUpstream = (
edges: Edge[],
nodeId: string,
isBuildDownstream = true,
nodes: Node[],
): string[]
Purpose: Retrieves the IDs of nodes either downstream or upstream related to a given node, with special filtering for agents and tools.
Parameters:
edges: Array of edges.nodeId: Current node ID.isBuildDownstream: Iftrue, build downstream list, else upstream.nodes: Array of all nodes.
Returns: Array of node IDs downstream or upstream.
Details: For agent nodes, excludes certain downstream nodes connected via specific handles (e.g., exception handle, tool operator, sub-agent).
Usage: Builds relationship maps between nodes for DSL construction.
buildAgentTools
function buildAgentTools(edges: Edge[], nodes: Node[], nodeId: string): { params: IAgentForm, name?: string, id?: string }
Purpose: Recursively builds the tool list for an agent node by traversing edges connected to its bottom handle.
Parameters:
edges: Array of edges.nodes: Array of nodes.nodeId: The current agent node ID.
Returns: Object containing:
params: The agent form parameters including an aggregatedtoolsarray.name: Node's name.id: Node's ID.
Usage: Used in building the agent operator's parameters, gathering sub-agent and tool information.
buildCategorize
function buildCategorize(edges: Edge[], nodes: Node[], nodeId: string): ICategorizeForm
Purpose: Builds a categorize operator's parameters, especially reconstructing its
category_descriptionwith linked edges by their handle IDs.Parameters:
edges: Array of edges.nodes: Array of nodes.nodeId: Categorize node ID.
Returns: A cleaned
ICategorizeFormobject.Details: Synchronizes the
tofield in category descriptions with the targets from edges filtered by source handles.Usage: Used during DSL construction of categorize nodes.
buildOperatorParams
const buildOperatorParams = (operatorName: string) => pipe(removeUselessDataInTheOperator(operatorName));
Purpose: A pipeline function to process operator parameters, currently only removing useless data.
Parameters:
operatorName: Name of the operator.
Returns: A function that accepts parameters and returns processed parameters.
Usage: Ensures parameters are cleaned before inclusion in DSL.
isBottomSubAgent
export function isBottomSubAgent(edges: Edge[], nodeId?: string): boolean
Purpose: Determines if the node is a bottom sub-agent by checking incoming edges with the
AgentTophandle.Parameters:
edges: Array of edges.nodeId: Node ID to test.
Returns:
trueif bottom sub-agent, elsefalse.
hasSubAgentOrTool
export function hasSubAgentOrTool(edges: Edge[], nodeId?: string): boolean
Purpose: Checks if the node has outgoing edges with handles indicating sub-agent or tool connections.
Parameters:
edges: Array of edges.nodeId: Node ID.
Returns: Boolean indicating presence of sub-agent or tool downstream.
buildDslComponentsByGraph
export const buildDslComponentsByGraph = (
nodes: RAGFlowNodeType[],
edges: Edge[],
oldDslComponents: DSLComponents,
): DSLComponents
Purpose: Constructs DSL components from graph nodes and edges, processing each node except excluded ones.
Parameters:
nodes: Array of flow nodes.edges: Array of edges.oldDslComponents: Previous DSL components to merge.
Returns: An object mapping node IDs to their DSL component representation.
Details:
Excludes some operators (
Note,Tool) and bottom sub-agents.For agent nodes, builds tools and exception paths.
For categorize nodes, builds categorize parameters.
Builds downstream and upstream node arrays.
Usage: Core function to convert graph model to DSL for execution or storage.
receiveMessageError
export const receiveMessageError = (res: any): boolean
Purpose: Checks if a response indicates an error based on HTTP status or application code.
Parameters:
res: Response object.
Returns:
trueif error detected, elsefalse.
replaceIdWithText
export const replaceIdWithText = (
obj: Record<string, unknown> | unknown[] | unknown,
getNameById: (id?: string) => string | undefined,
): unknown
Purpose: Recursively replaces IDs (strings) in an object or array with corresponding text from a lookup function.
Parameters:
obj: Object or array to process.getNameById: Function that returns a name given an ID.
Returns: New object/array with IDs replaced by text.
Usage: Useful for UI display or serialization.
isEdgeEqual
export const isEdgeEqual = (previous: Edge, current: Edge): boolean
Purpose: Compares two edges for equality based on source, target, and source handle.
Parameters:
previous: Previous edge.current: Current edge.
Returns: Boolean indicating equality.
buildNewPositionMap
export const buildNewPositionMap = (
currentKeys: string[],
previousPositionMap: Record<string, IPosition>,
): { intersectionKeys: string[], newPositionMap: Record<string, IPosition> }
Purpose: Generates a new map of positions for nodes that are newly added, avoiding overlaps by using predefined anchor positions.
Parameters:
currentKeys: Current node IDs.previousPositionMap: Previously stored positions.
Returns: Object with:
intersectionKeys: Node IDs existing both before and now.newPositionMap: Positions assigned to new node IDs.
Usage: Helps preserve node layout consistency.
isKeysEqual
export const isKeysEqual = (currentKeys: string[], previousKeys: string[]): boolean
Purpose: Checks if two arrays of keys are equal, ignoring order.
Parameters:
currentKeys: Current keys array.previousKeys: Previous keys array.
Returns: Boolean.
getOperatorIndex
export const getOperatorIndex = (handleTitle: string): string | undefined
Purpose: Extracts operator index from a handle title string.
Parameters:
handleTitle: Title string containing an index.
Returns: The last word in the string (usually an index).
getOtherFieldValues
export const getOtherFieldValues = (
form: FormInstance,
formListName: string,
field: FormListFieldData,
latestField: string,
): any[]
Purpose: Retrieves values of a specific field from all form list items except the current one.
Parameters:
form: Ant Design form instance.formListName: Name of the form list field (default'items').field: Current field data.latestField: Field key to extract.
Returns: Array of values excluding the current field's value.
Usage: Useful for validation or duplicate checking.
generateSwitchHandleText
export const generateSwitchHandleText = (idx: number): string
Purpose: Generates label text for a switch case handle.
Parameters:
idx: Index number starting from 0.
Returns: String like
"Case 1","Case 2", etc.
getNodeDragHandle
export const getNodeDragHandle = (nodeType?: string): string | undefined
Purpose: Returns a CSS selector for the drag handle of a node based on its type.
Parameters:
nodeType: Node label/type.
Returns: Selector string or
undefined.Usage: For UI drag behavior; notes have custom drag handles.
generateNodeNamesWithIncreasingIndex
export const generateNodeNamesWithIncreasingIndex = (
name: string,
nodes: RAGFlowNodeType[],
): string
Purpose: Generates a new node name with an incremented index suffix, ensuring no conflicts with existing node names.
Parameters:
name: Base name string.nodes: Existing nodes array.
Returns: New unique node name like
"Agent_3".Usage: When adding new nodes programmatically.
duplicateNodeForm
export const duplicateNodeForm = (nodeData?: RAGFlowNodeType['data']): RAGFlowNodeType['data']
Purpose: Creates a deep copy of a node's form data, cleaning fields that reference downstream nodes.
Parameters:
nodeData: Node data including label and form.
Returns: New node data object with cleared downstream references.
Usage: Used when duplicating nodes to avoid duplicate downstream links.
getDrawerWidth
export const getDrawerWidth = (): string | number
Purpose: Returns drawer width for UI, responsive to window size.
Returns:
"40%"if window width > 1278px, else470.
needsSingleStepDebugging
export const needsSingleStepDebugging = (label: string): boolean
Purpose: Checks if a node/operator requires single-step debugging.
Parameters:
label: Operator label.
Returns:
trueif debugging allowed, elsefalse.
getRelativePositionToIterationNode
export function getRelativePositionToIterationNode(
nodes: RAGFlowNodeType[],
position?: XYPosition,
): { parentId: string, position: XYPosition } | undefined
Purpose: Computes a node's position relative to an iteration node to determine parenting.
Parameters:
nodes: Array of nodes.position: Absolute position to translate.
Returns: Object with
parentId(iteration node's ID) and relative position, orundefinedif no iteration node matches.
generateDuplicateNode
export const generateDuplicateNode = (
position?: XYPosition,
label?: string,
)
Purpose: Generates a new node object positioned offset from an existing node, with a unique ID.
Parameters:
position: Original node position.label: Operator label.
Returns: New node object with:
id: Unique string including label and human-readable id.position: Offset by +50 pixels on x and y.dragHandle: Drag handle selector if applicable.
convertToStringArray
export function convertToStringArray(
list?: Array<{ value: string | number | boolean }>,
): Array<string | number | boolean>
Purpose: Converts an array of objects with a
valueproperty to an array of those values.Parameters:
list: Array of objects withvaluekey.
Returns: Array of primitive values.
convertToObjectArray
export function convertToObjectArray(
list: Array<string | number | boolean>,
): Array<{ value: string | number | boolean }>
Purpose: Converts an array of primitive values to an array of objects with
valuekeys.Parameters:
list: Array of primitives.
Returns: Array of objects.
buildCategorizeListFromObject
export const buildCategorizeListFromObject = (
categorizeItem: ICategorizeItemResult,
): ICategorizeItem[]
Purpose: Converts a categorize object with category keys into a sorted list of categorize items suitable for forms.
Parameters:
categorizeItem: Object keyed by category names.
Returns: Sorted array of categorize items.
Details: Converts
examplesfrom string arrays to object arrays.
buildCategorizeObjectFromList
export const buildCategorizeObjectFromList = (
list: Array<ICategorizeItem>,
): ICategorizeItemResult
Purpose: Converts a list of categorize items back into an object keyed by category name.
Parameters:
list: Array of categorize items.
Returns: Object with category keys.
Details: Converts
examplesfrom object arrays to string arrays.
getAgentNodeTools
export function getAgentNodeTools(agentNode?: RAGFlowNodeType): IAgentForm['tools']
Purpose: Retrieves the tools array from an agent node's form.
Parameters:
agentNode: Agent node.
Returns: Tools array or empty array.
getAgentNodeMCP
export function getAgentNodeMCP(agentNode?: RAGFlowNodeType): IAgentForm['mcp']
Purpose: Retrieves the MCP array from an agent node's form.
Parameters:
agentNode: Agent node.
Returns: MCP array or empty array.
mapEdgeMouseEvent
export function mapEdgeMouseEvent(
edges: Edge[],
edgeId: string,
isHovered: boolean,
): Edge[]
Purpose: Updates edge hover state for a given edge ID.
Parameters:
edges: Array of edges.edgeId: Target edge ID.isHovered: Hover state boolean.
Returns: New edges array with updated edge data.
buildBeginQueryWithObject
export function buildBeginQueryWithObject(
inputs: Record<string, BeginQuery>,
values: BeginQuery[],
): Record<string, BeginQuery>
Purpose: Synchronizes an inputs map with an array of values by matching keys.
Parameters:
inputs: Object with keys andBeginQueryvalues.values: Array ofBeginQuerys.
Returns: New inputs object merged from values.
Important Implementation Details and Algorithms
Recursive Agent Tools Construction:
buildAgentToolsrecursively traverses edges connected to an agent node's bottom handle to build nested sub-agent/tool structures.Downstream/Upstream Filtering:
buildComponentDownstreamOrUpstreamfilters edges based on node types and handles, excluding specific operator connections for correctness.Parameter Cleaning with Currying:
removeUselessDataInTheOperatoruses lodash'scurryto create reusable functions tailored to each operator.Name Generation with Gap Detection:
generateNodeNamesWithIncreasingIndexidentifies gaps in existing node indices to generate the next available name with minimal duplicates.Position Map Management: `buildNewPositionMap