Basic Components
Components are the building blocks of MASFactory workflows. They include Node components, Edge components, and MessageFormatter components.
Node: the abstract computation unit on aGraph;Graph,Agent, control components, and others are all derived fromNodeEdge: connects two nodes for flow control and automatic message forwardingMessageFormatter: defines how model output is parsed into adict, and how adictis rendered back into prompt text
Node Components
Node components do not appear directly in MASFactory workflows, but appear as their derived classes, such as Graph, Agent, Switch, etc. They undertake core functions such as sub-workflows, computation, and control. All components introduced below are Node class components.
Top-level Components:
Top-level components refer to objects that can be directly instantiated and run independently by users. They are the outermost nodes that neither belong to any Graph nor serve as Node or subgraphs of other Graph. MASFactory provides two types of top-level components: SingleAgent and RootGraph.
RootGraph
Top-level executable workflow container. Can be directly instantiated by users, serving as a "canvas" to host nodes and edges, organize the overall DAG, and responsible for one-time execution and result output. Main methods:
- Constructor parameters:
name,attributes?
Wherenameis the name of RootGraph;attributesare node variables of RootGraph, accessible to all subgraphs and nodes.
Node Variables
For detailed introduction to node variables, please refer to: Concepts-Node Variables
- Related methods:
Method Description
RootGraphis derived fromGraph, so the methodscreate_node,create_edge,edge_from_entryandedge_to_exitbelow are actually inherited fromGraph.
At the same time, bothRootGraphandGraphare subclasses ofNode, where thebuildmethod is declared inNodeand has different implementations in all its subclasses.create_node: Parameters includecls,*args,**kwargs; returnsNode.
Create a node onRootGraph(such asAgent,DynamicAgent,AgentSwitch,LogicSwitch,Graph,Loop,CustomNode, etc.). Whereclsmust be aNodesubclass (SingleAgentandRootGraphare prohibited as intra-graph nodes). Other parameters are passed as-is to the corresponding constructor, returning the node instance.create_edge: Parameters includesender,receiver,keys?; returnsEdge.
Create a directed edge between two nodes in the current graph. Wherekeysdefine fields to be passed and their natural language descriptions. Internal validation includes loop and duplicate-edge checking; created edges are automatically registered to both endpoint nodes and graph.edge_from_entry: Parameters includereceiver,keys?; returnsEdge.
Create a directed edge from graph entry to nodereceiverin the graph.edge_to_exit: Parameters includesender,keys?; returnsEdge.
Create a directed edge from nodesenderin the graph to graph exit.build: No parameters.
Recursively buildRootGraph, its subgraphs, and its nodes. For declarative graphs, this is also wherenodes=[...]/edges=[...]are materialized into real nodes and edges. Must execute this method before callinginvoke.invoke: Parameters includeinput,attributes?; returns(dict, dict).
Start workflow execution. Whereinputformat needs to match entry edgekeys; returns(output_dict, attributes_dict).
Graph Constraints (recommended practice)
To avoid deadlocks or unexpected early exits at runtime, follow these constraints when possible:
- Avoid dangling or unreachable nodes whenever possible; the framework does not uniformly reject isolated-node structures during
build(); - When creating edges connected to
entryandexit, you must useedge_from_entryoredge_to_exit, notcreate_edge; - The
receiverandsenderpassed tocreate_edgemust beNodeobjects created by the current graph'screate_nodemethod; NodeandEdgedefinitions must not create illegal cycles. If you need loop behavior, use theLoopcomponent.
- Example reference: Create a linear workflow
SingleAgent
Single agent component. An Agent component that can be used independently without relying on any Graph, users can directly instantiate and use it.
Suitable for quick Q&A, simple tool calls, scripted batch processing and other tasks that do not require complete workflow orchestration.
- Constructor parameters:
name,model,instructions,prompt_template?,tools?,memories?,model_settings?,role_name?
Parameter meanings refer to Agent. - Related methods:
invoke: Parameters includeinput(dict); returnsdict.SingleAgentusesdictfor both input and output (parsed/rendered by the configuredMessageFormatter).
- Example: Create a single agent workflow
Subgraph Components
Subgraph components cannot be directly instantiated by users, but are created through the create_node interface of other Graph instances. The resulting subgraph objects also have create_node and create_edge interfaces and can have their own internal Node. Subgraphs connect with other Node at the same level through the parent graph's create_edge interface, thus forming DAG structure.
Graph
Sub-workflow node supporting reuse and nesting.
- Constructor parameters:
name,pull_keys?,push_keys?,attributes?
Wherenameis the graph name for identification in logs;pull_keys,push_keysandattributesare all node variable control logic.pull_keyscontrols extracting corresponding fields from node variables in parent graph;push_keyscontrols updating corresponding fields in parent graph;attributesare node variable fields that this node carries. Related introduction reference: Concepts-Node Variables. - Features: Built-in
Entry/Exit, serving as "stages" that host multiple nodes; inheritsBaseGraph's node/edge management and performs baseline checks such as duplicate-edge and illegal-cycle validation during edge creation. - Related methods:
edge_from_entry,edge_to_exit,create_nodeandcreate_edge, specific introduction reference: RootGraph. - Application scenarios: Divide complex processes into several sub-stages for easy reuse and debugging.
Loop
Loop subgraph, encapsulating iteration control and optional LLM termination judgment functionality.
- Constructor parameters:
name,max_iterations,model?,terminate_condition_prompt?,terminate_condition_function?,pull_keys?,push_keys?,attributes?,initial_messages?max_iterations: Controls maximum loop count.modelandterminate_condition_prompt: Used to set up model and logic for using LLM to determine termination conditions.terminate_condition_function: Recommended Python termination callback (Truemeans terminate).pull_keys,push_keysandattributes: Control node variable logic, detailed reference: Concepts-Node Variables.
- Features: Contains an internal
Controllernode that checksmax_iterationscondition andterminate_condition_promptcondition at the beginning of each loop;TerminateNodesupports early exit within loop body. - Related methods:
create_nodeandcreate_edge: Usage same as: RootGraph.edge_from_controller: Parameters includereceiver,keysetc.; returnsEdge(start each iteration from controller).edge_to_controller: Parameters includesender,keysetc.; returnsEdge(result flows back to controller forming next round input).edge_to_terminate_node: Parameters includesender,keysetc.; returnsEdge(trigger forced termination within loop body).
- Termination conditions: Terminate when reaching
max_iterationsor when LLM determinesterminate_condition_promptis satisfied. - Force exit loop: Immediately exit when
terminate_nodereceives any message. - Example: Loop example
Loop Constraints
Loopmust form a loop path centered onController, and no other loops are allowed except this loop.Controlleronly makes loop exit judgment at the beginning of each iteration. If you need to exit the loop midway, please useTerminateNodenode to exit the loop.- Edges connected to
Controllernode andTerminateNodenode must be created throughedge_from_controller,edge_to_controllerandedge_to_terminate_nodeinterfaces, cannot be created throughcreate_edgeinterface. - When
TerminateNodereceives a message, it will immediately trigger the exit mechanism (equivalent tobreaklogic in programming languages to exit loops). - The
keysonedge_from_controller,edge_to_controller,edge_to_terminate_nodeandLoop'sin_edgesandout_edgesmust be the same to avoid errors.
Agent Components
Agent
Standard agent node.
Constructor parameters:
name,model,instructions,prompt_template?,formatters?,tools?,memories?,retrievers?,pull_keys?,push_keys?,model_settings?,role_name?,hide_unused_fields?name: Node name for identifying current Agent;model: Large model called by Agent, receives aModelobject, adapted for mainstream LLM APIs. Detailed reference: Model Adapters;instructions: Instruction information sent to Agent. Receives a string or string list; when it's a list, it will be joined with newline characters into complete instructions. Supports using{replacement_field}to embed fields fromin_edgeskeys, fields from node variablesattributes,role_nameinto instructions;prompt_template: Agent's prompt template (corresponding to user prompt). Supportsstrorlist[str]; when it's a list, it will be joined with newline characters; can be used in combination withinstructions; defaults toNone;formatters: Message formatter(s) that define the LLM I/O protocol. Pass a single formatter (used for both in/out) or a list of two formatters[in, out]. Defaults to “paragraph-style input + JSON output”.tools: List of tool functions available for Agent to call. Function names, parameter names, return value types and docstrings will be automatically added to LLM context by MASFactory, automatically call corresponding tools based on LLM call results, and return results to LLM;memories: Memory adapters (write + read). Except forHistoryMemory, memories act as context sources viaget_blocks(...)(injected intoCONTEXT), and Agents willinsert(...)after each step.retrievers: Read-only RAG / external context sources injected viaget_blocks(...). MCP sources can also be plugged in here.model_settings: Additional settings passed to underlying model interface (refer to OpenAI Chat Completions Legacy interface). Supports:temperature(float, range [0.0, 2.0]),top_p(float, range [0.0, 1.0]),max_tokens(positive integer),stop(stop words,strorlist[str]). Unlisted keys will be passed as-is to model adapter (if model supports). Example:{"temperature": 0.7, "top_p": 0.95, "max_tokens": 512, "stop": ["</end>"]};
role_name: Agent's role name. Can use{role_name}to insert it into instructions. Ifrole_nameis not set,role_namedirectly uses the value ofname.hide_unused_fields: IfTrue, input fields not consumed by template placeholders will not be appended into the user payload.
Features:
- Model adaptation: Adapts mainstream model API interfaces.
- Automatic tool calling: When LLM returns tool calls, automatically execute corresponding tools, backfill results and request LLM again until final content is returned.
- Context injection (RAG/Memory/MCP): Providers emit
ContextBlocks which are injected into the user payload as aCONTEXTfield during Observe. Supports passive (auto-inject) and active (on-demand via tools) modes. - System instructions and user templates:
instructionssupportsstrorlistwith placeholders (like{role_name}, incoming edgekeys, node variables); can useprompt_templateto modify input fromin_edges. - Structured output constraints: Automatically generate JSON field constraint prompts based on outgoing edge
output_keysto guide model strict output. - Node variable support: Follows
Node'spull_keys,push_keysandattributesrules;Agentdefaultspull_keysandpush_keysto empty dictionaries.
Related methods:
build(): MarkAgentas executable (usually called uniformly byGraph).add_memory(memory: Memory): Add a memory adapter (used forget_blocksinjection and step-timeinsert).add_retriever(retriever: Retrieval): Add a retrieval/context source (used forget_blocksinjection and/or active retrieval tools).
Example: Agent example
Deep dive
- Observe/Think/Act runtime:
/guide/agent_runtime - Context adapters (RAG/Memory/MCP):
/guide/context_adapters
DynamicAgent
Dynamic agent node.DynamicAgent is similar to Agent, except its instructions are not fixed at coding time. Instead, they are read from input messages at runtime.
At runtime, DynamicAgent reads the field named by instruction_key (default: "instructions") from the input payload, uses that value to override the instructions for the current execution, then removes that field from the input before continuing. Therefore, when using DynamicAgent, make sure upstream nodes or incoming edges provide that field; otherwise the current implementation raises KeyError.
- Constructor parameters:
name,model,default_instructions,instruction_key?,prompt_template?,tools?,memories?,retrievers?,pull_keys?,push_keys?,model_settings?,role_name?default_instructions: Default instructions used at initialization. In practice, runtime behavior is usually driven by the field referenced byinstruction_key;instruction_key: Key name in the incoming message used to dynamically override instructions. Default is"instructions"; if this key exists in the input, its value is used as the instructions for the current execution;name,model,tools,memories,retrievers,pull_keys,push_keys,model_settings,prompt_template: Same as Agent;
- Usage example: DynamicAgent example
Conditional Branch Components
Branch components are similar to if branches in programming languages, deciding the direction of the next path based on current state and conditions. MASFactory provides two branch components: logic branch component LogicSwitch based on callback functions and semantic branch component AgentSwitch based on Agent semantic judgment.
LogicSwitch
Conditional routing component based on callback functions, using condition_binding(callback, out_edge) to bind branch conditions.
- Constructor parameters:
name,pull_keys?,push_keys? (meaning same asAgent) - Related methods:
condition_binding(callback, out_edge): Bind anout_edgewith condition callback function.callback(message, attributes) -> bool: wheremessageis the aggregated message from incoming edges (dict), andattributesis the node-variable dict. When it returnsTrue, the message is forwarded to thatout_edgeand the target node connected by that edge is added to the execution queue.
LogicSwitch and AgentSwitch
LogicSwitchwill pass the messagemessagefromin_edgesand node variablesattributesinherited from parent graph into callback functions corresponding to all out_edges, and decide whether to put target nodes connected by thoseout_edgesinto the execution queue based on the return values of callback functions.LogicSwitchsupports "multi-path matching", that is, if multipleout_edgecorresponding condition functions returnTrue, nodes on these paths are all put into the execution queue.AgentSwitchhas similar processing logic toLogicSwitch. The difference is thatLogicSwitchuses callback functions for condition judgment, whileAgentSwitchuses LLM for condition judgment based on condition semantics.
Situations to Avoid
- If an
out_edgeis not bound with condition callback function or condition semantics, the target node corresponding to this edge will never be added to the execution queue. This situation should be avoided in development. - If all conditions bound to all
out_edgeevaluate toFalsein a certain execution, the switch will close all outgoing edges and forward nothing. If the execution queue becomes empty, the workflow ends early. To avoid surprises, add a default/fallback branch (e.g., a predicate that always returnsTrue) or handle the “no match” case explicitly.
- Usage example: Logic branch example
AgentSwitch
LLM-based semantic routing component, using condition_binding(prompt, out_edge) to bind routing semantics.
- Constructor parameters:
name,model,pull_keys?,push_keys? (meaning same asAgent) - Related methods:
condition_binding(prompt, out_edge): Bind semantic judgment promptpromptfor a certain outgoing edge.AgentSwitchwill combine incoming edge messages with each outgoing edge'spromptone by one, callmodelfor judgment (supports multiple outgoing edges hitting simultaneously).
- Usage example: Semantic branch example
Custom Nodes
CustomNode
Node that customizes runtime behavior with a callback function, convenient for integrating external computation or rule-based logic. Supports setting the handler at initialization time or later through set_forward.
Constructor parameters:
name,forward?,memories?,tools?,retrievers?,pull_keys?,push_keys?forward: Custom runtime callback, must returndict; ifforwardisNone, this node passes input through as-is (input is alsodict);memories,tools,retrievers: Available memory / tool / retriever lists for the current node (as optional callback parameters);pull_keys,push_keys: Same meaning asNode(node variables).
Related methods:
set_forward(forward_callback): Set callback function.
Callback function:
- Callback parameter forms (automatically matched by parameter count, up to
self):forward(input);forward(input, attributes);forward(input, attributes, memories);forward(input, attributes, memories, tools);forward(input, attributes, memories, tools, retrievers);forward(input, attributes, memories, tools, retrievers, self);
- Return value: Callback return value is automatically sent to downstream nodes through all outgoing edges (return type must be
dict).
- Callback parameter forms (automatically matched by parameter count, up to
Usage example: CustomNode example