FlowNode
A FlowNode incorporates a subflow into an enclosing Flow as a single graph component. Its subflow field identifies the Flow definition that the runtime executes when the node runs. The FlowNode defines the input, output, and branch contract through which the enclosing Flow interacts with the subflow.
The subflow's internal nodes and connections remain separate from the enclosing graph. This boundary allows a Flow definition to be reused in different workflows without changing its internal structure.
When the FlowNode executes, the runtime maps its input values to the subflow's input contract and begins the subflow at its StartNode. The subflow executes until it reaches an EndNode, and the resulting values are mapped to the FlowNode outputs.

Description of the illustration FlowNode Nested Subflow Execution
The enclosing Flow interacts with the subflow only through the FlowNode. Its edges do not connect directly to the nodes inside order-lookup-flow.
The two control graphs are separate. Control reaches the FlowNode in the enclosing Flow, and the FlowNode starts the subflow at the subflow's own StartNode. After the subflow reaches its EndNode, the enclosing Flow can continue from the FlowNode.
Subflow Completion and Branch Selection
A subflow can contain multiple EndNode components for different completion paths. The branch_name of the EndNode reached during execution becomes the branch selected by the enclosing FlowNode.
For example:

The FlowNode declares eligible and ineligible in its branches field. Outgoing control-flow edges in the enclosing Flow use the same names in from_branch to describe the possible continuation.
The enclosing Flow connects to the FlowNode, not directly to the EndNodes inside the subflow. Values returned by either EndNode must satisfy the subflow and FlowNode output contracts.
FlowNode Fields
| Field | Requirement | Purpose |
|---|---|---|
component_type | Required | Identifies the component as a FlowNode. |
id | Required | Uniquely identifies the node for references and graph connections. |
name | Required | Provides a human-readable component name. |
subflow | Required | Identifies the Flow executed by the node, directly or through a component reference. |
inputs | Optional | Declares the typed values supplied to the subflow. When the subflow has inputs, the FlowNode must declare a compatible input contract with the same names and number of entries. |
outputs | Optional | Declares the typed values returned from the subflow. When the subflow has outputs, the FlowNode must declare a compatible output contract with the same names and number of entries. |
branches | Optional | Declares the branch names available from the FlowNode. An outgoing control-flow edge can associate each name with a possible next node. |
The enclosing Flow and the subflow remain separate control-flow graphs. Connections in the enclosing Flow refer to the FlowNode, not to nodes inside the subflow. Connections within the subflow refer only to nodes in that subflow.
The runtime applies the following rules to the FlowNode and subflow contracts:
- The
FlowNodeand subflow must declare the same number of inputs. - Every
FlowNodeinput must have a subflow input with the same case-sensitive name. - The
FlowNodeinput type must be compatible with the corresponding subflow input type, so every value accepted through the node can be supplied to the subflow. - The subflow and
FlowNodemust declare the same number of outputs. - Every subflow output must have a
FlowNodeoutput with the same case-sensitive name. - The subflow output type must be compatible with the corresponding
FlowNodeoutput type, so every value produced by the subflow can be returned through the node.
FlowNode Example
A support Flow needs to retrieve the status of an order. An existing order-lookup-flow already defines this workflow with the following public
contract:
| Direction | Name | Type |
|---|---|---|
| Input | order_id | string |
| Output | order_status | string |
The support Flow incorporates this subflow through a FlowNode. The enclosing Flow interacts only with the FlowNode contract and does not refer directly to nodes inside the subflow.

Description of the illustration FlowNode and Subflow Boundary
The FlowNode is defined as follows:
{
"component_type": "FlowNode",
"id": "run-order-lookup",
"name": "run_order_lookup",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": ["next"],
"subflow": {
"$component_ref": "order-lookup-flow"
}
}
Referenced Subflow
The subflow reference resolves to a separate Flow whose id is order-lookup-flow. Its public input and output contracts match the corresponding FlowNode contracts:
{
"component_type": "Flow",
"id": "order-lookup-flow",
"name": "order_lookup_flow",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"start_node": {
"$component_ref": "order-lookup-start"
},
"nodes": [
{"$component_ref": "order-lookup-start"},
{"$component_ref": "lookup-order"},
{"$component_ref": "order-lookup-end"}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "order-lookup-start-to-tool",
"name": "order_lookup_start_to_tool",
"from_node": {
"$component_ref": "order-lookup-start"
},
"from_branch": null,
"to_node": {
"$component_ref": "lookup-order"
}
},
{
"component_type": "ControlFlowEdge",
"id": "order-lookup-tool-to-end",
"name": "order_lookup_tool_to_end",
"from_node": {
"$component_ref": "lookup-order"
},
"from_branch": null,
"to_node": {
"$component_ref": "order-lookup-end"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "order-id-to-lookup-tool",
"name": "order_id_to_lookup_tool",
"source_node": {
"$component_ref": "order-lookup-start"
},
"source_output": "order_id",
"destination_node": {
"$component_ref": "lookup-order"
},
"destination_input": "order_id"
},
{
"component_type": "DataFlowEdge",
"id": "order-status-to-lookup-end",
"name": "order_status_to_lookup_end",
"source_node": {
"$component_ref": "lookup-order"
},
"source_output": "order_status",
"destination_node": {
"$component_ref": "order-lookup-end"
},
"destination_input": "order_status"
}
],
"$referenced_components": {
"order-lookup-start": {
"component_type": "StartNode",
"id": "order-lookup-start",
"name": "order_lookup_start",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_id",
"type": "string"
}
],
"branches": ["next"]
},
"lookup-order": {
"component_type": "ToolNode",
"id": "lookup-order",
"name": "lookup_order",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": ["next"],
"tool": {
"$component_ref": "lookup-orders-tool"
}
},
"order-lookup-end": {
"component_type": "EndNode",
"id": "order-lookup-end",
"name": "order_lookup_end",
"inputs": [
{
"title": "order_status",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": [],
"branch_name": "next"
},
"lookup-orders-tool": {
"component_type": "BuiltinTool",
"id": "lookup-orders-tool",
"name": "lookup_orders",
"executor_name": "Oracle In-DB Agent Executor",
"tool_type": "plsql_exec",
"configuration": {
"schema_name": "APP_SCHEMA",
"package_name": "ORDER_TOOLS",
"procedure_name": "LOOKUP_ORDER"
}
}
}
}
The subflow definition establishes the complete reusable workflow:
idmatches the$component_refin theFlowNode.inputsdeclares theorder_idvalue accepted from theFlowNode.outputsdeclares theorder_statusvalue returned to theFlowNode.start_nodeidentifiesorder-lookup-startas the first node in the subflow.control_flow_connectionsdescribes the possible execution sequence fromStartNodetoToolNodetoEndNode.data_flow_connectionstransfersorder_idto theToolNodeand transfersorder_statusto theEndNode.$referenced_componentscontains the node and Tool definitions resolved by the component references in the subflow.
The StartNode exposes the subflow input as order_id. The ToolNode invokes APP_SCHEMA.ORDER_TOOLS.LOOKUP_ORDER, and the EndNode maps the resulting order_status value to the subflow output contract. Its branch_name value, next, becomes the branch selected by the enclosing FlowNode when the subflow completes.
The fields establish the boundary between the enclosing Flow and the subflow:
inputsdeclares theorder_idvalue supplied to the subflow.outputsdeclares theorder_statusvalue returned from the subflow.branchesdeclares thenextbranch that an outgoing control-flow edge can reference.subflowidentifies the Flow executed by the node. In this example, its$component_refresolves to the Flow whose ID isorder-lookup-flow.
When the FlowNode executes:
- The runtime maps
FlowNode.order_idto theorder_idinput oforder-lookup-flow. - The subflow begins at its own
StartNodeand executes its internal graph. - The subflow reaches an
EndNodewith anorder_statusresult. - The runtime maps the subflow's
order_statusoutput toFlowNode.order_status. - The enclosing Flow can transfer
FlowNode.order_statusto another node through a data-flow edge.
Complete Runnable Agent Spec
The following example executes order-lookup-flow through a FlowNode. It accepts an order_id, invokes a PL/SQL procedure inside the subflow, and returns order_status through the enclosing Flow.
This example does not require an LLM configuration, credential, or network ACL. The application schema must be able to create the example package and execute DBMS_AI_AGENT.
Create the Example Tool
Connect as the application schema and create the following package:
CREATE OR REPLACE PACKAGE ORDER_TOOLS AS
PROCEDURE LOOKUP_ORDER (
ORDER_ID IN VARCHAR2,
ORDER_STATUS OUT VARCHAR2
);
END ORDER_TOOLS;
/
CREATE OR REPLACE PACKAGE BODY ORDER_TOOLS AS
PROCEDURE LOOKUP_ORDER (
ORDER_ID IN VARCHAR2,
ORDER_STATUS OUT VARCHAR2
) IS
BEGIN
IF ORDER_ID = '7812' THEN
ORDER_STATUS := 'OUT_FOR_DELIVERY';
ELSE
ORDER_STATUS := 'PROCESSING';
END IF;
END LOOKUP_ORDER;
END ORDER_TOOLS;
/
Execute the Complete Agent Spec
SET SERVEROUTPUT ON SIZE UNLIMITED
SET DEFINE OFF
DECLARE
L_AGENT_SPEC CLOB := q'~
{
"component_type": "Flow",
"agentspec_version": "25.4.1",
"id": "support-flow",
"name": "support_flow",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"start_node": {
"$component_ref": "support-start"
},
"nodes": [
{
"$component_ref": "support-start"
},
{
"$component_ref": "run-order-lookup"
},
{
"$component_ref": "support-end"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "support-start-to-lookup",
"name": "support_start_to_lookup",
"from_node": {
"$component_ref": "support-start"
},
"to_node": {
"$component_ref": "run-order-lookup"
}
},
{
"component_type": "ControlFlowEdge",
"id": "lookup-to-support-end",
"name": "lookup_to_support_end",
"from_node": {
"$component_ref": "run-order-lookup"
},
"from_branch": "next",
"to_node": {
"$component_ref": "support-end"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "outer-order-id-to-flow-node",
"name": "outer_order_id_to_flow_node",
"source_node": {
"$component_ref": "support-start"
},
"source_output": "order_id",
"destination_node": {
"$component_ref": "run-order-lookup"
},
"destination_input": "order_id"
},
{
"component_type": "DataFlowEdge",
"id": "flow-node-status-to-outer-end",
"name": "flow_node_status_to_outer_end",
"source_node": {
"$component_ref": "run-order-lookup"
},
"source_output": "order_status",
"destination_node": {
"$component_ref": "support-end"
},
"destination_input": "order_status"
}
],
"$referenced_components": {
"support-start": {
"component_type": "StartNode",
"id": "support-start",
"name": "support_start",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_id",
"type": "string"
}
],
"branches": [
"next"
]
},
"run-order-lookup": {
"component_type": "FlowNode",
"id": "run-order-lookup",
"name": "run_order_lookup",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": [
"next"
],
"subflow": {
"$component_ref": "order-lookup-flow"
}
},
"support-end": {
"component_type": "EndNode",
"id": "support-end",
"name": "support_end",
"inputs": [
{
"title": "order_status",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": [],
"branch_name": "next"
},
"order-lookup-flow": {
"component_type": "Flow",
"id": "order-lookup-flow",
"name": "order_lookup_flow",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"start_node": {
"$component_ref": "order-lookup-start"
},
"nodes": [
{
"$component_ref": "order-lookup-start"
},
{
"$component_ref": "lookup-order"
},
{
"$component_ref": "order-lookup-end"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "order-lookup-start-to-tool",
"name": "order_lookup_start_to_tool",
"from_node": {
"$component_ref": "order-lookup-start"
},
"to_node": {
"$component_ref": "lookup-order"
}
},
{
"component_type": "ControlFlowEdge",
"id": "order-lookup-tool-to-end",
"name": "order_lookup_tool_to_end",
"from_node": {
"$component_ref": "lookup-order"
},
"to_node": {
"$component_ref": "order-lookup-end"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "order-id-to-lookup-tool",
"name": "order_id_to_lookup_tool",
"source_node": {
"$component_ref": "order-lookup-start"
},
"source_output": "order_id",
"destination_node": {
"$component_ref": "lookup-order"
},
"destination_input": "order_id"
},
{
"component_type": "DataFlowEdge",
"id": "order-status-to-lookup-end",
"name": "order_status_to_lookup_end",
"source_node": {
"$component_ref": "lookup-order"
},
"source_output": "order_status",
"destination_node": {
"$component_ref": "order-lookup-end"
},
"destination_input": "order_status"
}
],
"$referenced_components": {
"order-lookup-start": {
"component_type": "StartNode",
"id": "order-lookup-start",
"name": "order_lookup_start",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_id",
"type": "string"
}
],
"branches": [
"next"
]
},
"lookup-order": {
"component_type": "ToolNode",
"id": "lookup-order",
"name": "lookup_order",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": [
"next"
],
"tool": {
"$component_ref": "lookup-orders-tool"
}
},
"order-lookup-end": {
"component_type": "EndNode",
"id": "order-lookup-end",
"name": "order_lookup_end",
"inputs": [
{
"title": "order_status",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"branches": [],
"branch_name": "next"
},
"lookup-orders-tool": {
"component_type": "BuiltinTool",
"id": "lookup-orders-tool",
"name": "lookup_orders",
"description": "Return the current status of an order.",
"inputs": [
{
"title": "order_id",
"type": "string"
}
],
"outputs": [
{
"title": "order_status",
"type": "string"
}
],
"requires_confirmation": false,
"executor_name": "Oracle In-DB Agent Executor",
"tool_version": "1.0",
"tool_type": "plsql_exec",
"configuration": {
"package_name": "ORDER_TOOLS",
"procedure_name": "LOOKUP_ORDER"
}
}
}
}
}
}
~';
L_INPUTS CLOB := TO_CLOB (
'[{"name":"order_id","value":"7812"}]'
);
L_OUTPUTS CLOB;
BEGIN
L_OUTPUTS := DBMS_AI_AGENT.EXECUTE_IMMEDIATE (
AGENT_SPEC => L_AGENT_SPEC,
INPUTS => L_INPUTS
);
DBMS_OUTPUT.PUT_LINE (
DBMS_LOB.SUBSTR (L_OUTPUTS, 32767, 1)
);
END;
/
The returned JSON has the following form:
{
"order_status": "OUT_FOR_DELIVERY"
}
In this execution:
- The enclosing
StartNodepublishesorder_id. - The outer data-flow edge supplies the value to
FlowNode.order_id. - The FlowNode maps the value to the
order_idinput oforder-lookup-flow. - The subflow starts at
order-lookup-startand supplies the value tolookup-order. - The ToolNode invokes
ORDER_TOOLS.LOOKUP_ORDER. - The subflow transfers
order_statustoorder-lookup-end. - The subflow output becomes
FlowNode.order_status. - The enclosing Flow transfers that value to
support-endand returns it through itsorder_statusoutput.