use-add-node.ts
Overview
The use-add-node.ts file provides a set of React hooks and utility functions designed to facilitate the creation, positioning, and linking of nodes within a graph-based user interface, specifically for a React Flow diagram environment. It integrates with a custom graph state management store (useGraphStore), manages node initialization parameters, calculates logical node positions to avoid overlap, and handles creation of special node types like Iteration and Tool nodes.
This file is crucial for dynamically adding nodes to a flow graph, initializing node data with default parameters, correctly positioning nodes relative to their parent or siblings, and establishing edges (connections) between nodes. It supports various operator types (e.g., Agent, Tool, Iteration) with specialized behaviors.
Detailed Explanation
Key Concepts
Node: A single element in the flow graph representing an operator or action.
Edge: A connection between two nodes.
Operator: Defines the type or role of a node (e.g., Agent, Tool, Iteration).
Position: Enum indicating the relative position of a node (Right, Left, Bottom).
ReactFlowInstance: Instance of the React Flow library managing the graphical flow.
Functions and Hooks
Helper Function: isBottomSubAgent(type: string, position: Position): boolean
Determines if a node type positioned at the bottom is considered a "sub-agent" or a tool.
Parameters:
type: The operator type of the node.position: The position enum of the node.
Returns: true if the node is an Agent positioned at the bottom or a Tool; otherwise
false.Usage: Used to apply special initialization logic for these node positions.
Hook: useInitializeOperatorParams
Initializes default form parameters for each operator type, leveraging a fetched large language model ID (llmId) for some operators that require it.
Returns:
initializeOperatorParams(operatorName: Operator, position: Position): object
Returns the initial form values for the operator, with special overrides for bottom-positioned sub-agents (adds default description and user prompt).initialFormValuesMap: A memoized mapping from operator types to their initial form values.
Usage Example:
const { initializeOperatorParams } = useInitializeOperatorParams();
const initialParams = initializeOperatorParams(Operator.Agent, Position.Bottom);
Implementation Details:
Uses
useFetchModelIdto dynamically include the current model ID.Uses
i18nextfor translation/localization of default texts.Uses
useMemoanduseCallbackfor performance optimization.
Hook: useGetNodeName
Provides a function to get the localized display name of an operator type.
Returns:
(type: string) => string- a function that returns the translated name.Usage Example:
const getNodeName = useGetNodeName();
const displayName = getNodeName(Operator.Agent); // e.g., "Agent"
Hook: useCalculateNewlyChildPosition
Calculates the position of a new child node relative to a parent node to avoid overlapping existing child nodes.
Returns:
calculateNewlyBackChildPosition(id?: string, sourceHandle?: string): {x: number, y: number}
Calculates a position offset to the right and downward from the parent or sibling nodes.
Implementation Details:
Fetches all edges from the parent node filtered by the
sourceHandle.Finds all child nodes connected via those edges.
Determines the maximum Y position among those children to position the new node below them.
Defaults to an offset position if no children exist.
Hook: useAddChildEdge
Adds a child edge (connection) from a source node to a target node on the graph.
Returns:
addChildEdge(position: Position, edge: Partial<Connection>): void
Details:
Only adds edges for nodes positioned on the right.
Uses
addEdgefrom the graph store to create the edge.Sets the target handle to
NodeHandleId.Endby default.
Hook: useAddToolNode
Handles adding a Tool-type node as a child of an Agent node, ensuring only one Tool node per Agent.
Returns:
addToolNode(newNode: Node<any>, nodeId?: string): boolean
Adds the tool node if no existing tool child node is found for the agent, otherwise returns false.
Behavior:
Positions the Tool node below and slightly left of the agent node.
Adds an edge from the agent node to the tool node with specific handles.
Usage: Used internally when adding Tool nodes.
Hook: useResizeIterationNode
Resizes an Iteration parent node dynamically based on the positions of its child nodes to maintain layout integrity.
Returns:
resizeIterationNode(type: string, position: Position, parentId?: string): void
Behavior:
Checks if the parent node needs expansion to accommodate new child nodes to the right.
Adjusts the width and position of the parent node accordingly.
Usage: Called when adding non-bottom sub-agent nodes inside Iteration nodes.
Hook: useAddNode
The primary hook that exposes functions to add nodes to the graph on the canvas.
Parameters:
reactFlowInstance?: ReactFlowInstance<any, any>- Optional React Flow instance to convert screen coordinates to flow coordinates.
Returns:
addCanvasNode(type: string, params: { nodeId?: string; position: Position; id?: string; isFromConnectionDrag?: boolean }): (event?: CanvasMouseEvent) => string | undefined
Returns a function that adds a node of the specified type at a computed or event-based position.addNoteNode(e: CanvasMouseEvent): void
Convenience function to add a Note node on the canvas, using mouse event coordinates.
Functionality:
Projects mouse coordinates to flow coordinates when adding nodes by user interaction.
Manages special cases for Iteration, Agent (bottom), Tool nodes.
Initializes node data with default parameters.
Adds nodes and edges to the graph store.
Calls
resizeIterationNodeto adjust Iteration nodes dynamically.
Usage Example:
const { addCanvasNode, addNoteNode } = useAddNode(reactFlowInstance);
// Add an Agent node to the right of node "node-1"
const addAgentNode = addCanvasNode(Operator.Agent, { nodeId: "node-1", position: Position.Right });
const newNodeId = addAgentNode();
// Add a Note node at mouse click event
addNoteNode(mouseEvent);
Important Implementation Details
Uses React hooks (
useCallback,useMemo) extensively for memoization and performance.Integrates tightly with a global graph store (
useGraphStore) for node/edge management.Uses
human-idto generate unique, human-readable node IDs.Supports localization with
i18nextto provide translated default texts.Handles special node types like Iteration nodes which require adding children and resizing parents.
Calculates node positions based on existing graph layout to prevent overlap.
Establishes edges with specific source and target handles depending on node types and positions.
Designed to work with React Flow's evolving API, including updated coordinate projection methods.
Interaction With Other Parts of the System
Graph Store (
useGraphStore): Central state management for nodes and edges; this file reads from and writes to this store.Constants & Initial Values: Imports numerous initial form value objects and operator enums from constants files to initialize nodes.
React Flow: Uses React Flow's
ReactFlowInstancefor coordinate transformations and positions nodes accordingly.Localization: Utilizes
i18nextfor translated labels and descriptions.Utility Functions: Uses helper utilities for generating node names and getting drag handles.
Hooks: Depends on other custom hooks such as
useFetchModelIdfor fetching dynamic model IDs.
Visual Diagram
classDiagram
class useAddNode {
+addCanvasNode(type: string, params): (event?) => string | undefined
+addNoteNode(event)
}
class useInitializeOperatorParams {
+initializeOperatorParams(operatorName: Operator, position: Position): object
+initialFormValuesMap: object
}
class useGetNodeName {
+getNodeName(type: string): string
}
class useCalculateNewlyChildPosition {
+calculateNewlyBackChildPosition(id?: string, sourceHandle?: string): {x: number, y: number}
}
class useAddChildEdge {
+addChildEdge(position: Position, edge: Partial<Connection>): void
}
class useAddToolNode {
+addToolNode(newNode: Node, nodeId?: string): boolean
}
class useResizeIterationNode {
+resizeIterationNode(type: string, position: Position, parentId?: string): void
}
useAddNode --> useInitializeOperatorParams : uses
useAddNode --> useGetNodeName : uses
useAddNode --> useCalculateNewlyChildPosition : uses
useAddNode --> useAddChildEdge : uses
useAddNode --> useAddToolNode : uses
useAddNode --> useResizeIterationNode : uses
Summary
The use-add-node.ts module is a comprehensive utility for managing the addition of nodes within a React Flow graph environment. It abstracts the complexity of node initialization, positioning, edge creation, and special node handling, providing an easy-to-use API for higher-level components and features to dynamically build and manipulate flow graphs.
It ensures proper layout, uniqueness, and consistency of nodes, supporting a wide variety of operator types with localized labels and default parameters. Its design promotes modularity and reusability via React hooks and integrates seamlessly with the global graph state and React Flow's rendering engine.