MapNode

A MapNode runs the same subflow once for each item in an input collection and combines selected outputs from those executions into declared MapNode outputs. For each item in the collection, the runtime:

1. Extracts the item from the collection supplied to the MapNode.
2. Supplies that item to the corresponding input of the subflow.
3. Executes the subflow from its StartNode until it reaches an EndNode.
4. Reads each subflow output named in reducers.

After all iterations complete, each reducer combines the corresponding subflow outputs. The resulting values become the outputs of the MapNode. For example, a MapNode can receive an array of order IDs, execute an order-lookup subflow once for each ID, and append the returned order statuses into a single array.

The collection item type must be compatible with the corresponding subflow input. If the MapNode receives an array of strings, each item is a string and the subflow input must accept a string.

MapNode input and output names describe how the collection boundary corresponds to the subflow contract. An input named iterated_order_id supplies each collection item to the subflow input named order_id, while an output named collected_order_status contains the reduced values from the subflow output named order_status. The suffixes are case-sensitive and must match the corresponding subflow names. Reducer entries use the unprefixed subflow output name, such as order_status.

MapNode Fields

FieldRequirementPurpose
component_typeRequiredIdentifies the component as a MapNode.
idRequiredUniquely identifies the MapNode within its component scope.
nameRequiredProvides a human-readable name for the node.
subflowRequiredDefines or references the Flow executed once for each collection item.
inputsOptionalDeclares the collections processed by the node. Each collection's item specification must be compatible with the corresponding subflow input.
outputsOptionalDeclares the values produced after the configured reducers combine the subflow outputs.
branchesOptionalDeclares the control branches that can continue after the MapNode completes.
reducersOptionalMaps subflow output names to the reduction operations that produce the MapNode outputs. A subflow output without an explicit reducer uses append.

Reducer Behavior

ReducerResult
appendCollect each order status into an array.
sumAdd compatible numeric child values.
averageCompute the mean of compatible numeric values.
minKeep the smallest compatible value.
maxKeep the largest compatible value.

A MapNode can apply different reducers to multiple subflow outputs. For example, it can apply append to an order_status output and sum to a numeric order_amount output. Each reducer independently combines the values produced for its named subflow output. A reducer must name an output the child flow actually publishes, and its result must satisfy the MapNode output contract. For strings or structured results that must be preserved individually, append is usually the natural choice.

MapNode Example

An order-support Flow receives an array of order IDs and returns the status of each order. An existing order-lookup-flow accepts one order_id and returns one order_status:

DirectionNameType
Inputorder_idstring
Outputorder_statusstring

The MapNode executes this subflow once for each value in the order_ids array. The enclosing Flow interacts with the repeated work through the MapNode collection contracts.

Description of the illustration MapNode Repeated Subflow Execution and Reduction

Control Flow

The enclosing Flow treats the MapNode as one graph component. Each collection item causes a separate execution of the subflow's internal control graph.

Data Flow

The fields describe the collection boundary:

  • inputs declares iterated_order_id, the array supplied by the enclosing Flow. Its items declaration matches the order_id input of the subflow.
  • outputs declares collected_order_status, the array produced after the subflow executions complete. Its items declaration matches the order_status output of the subflow.
  • branches declares the next branch that can continue after the MapNode completes.
  • subflow identifies the Flow executed for each item.
  • reducers applies append to the order_status value returned by each subflow execution.

Referenced Subflow

The subflow reference resolves to the Flow whose id is order-lookup-flow. The subflow processes one order at a time:

{
  "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 contract contains scalar values because each execution handles one order. The MapNode contract contains arrays because it receives all order IDs and returns the combined statuses.

During execution:

  1. A data-flow edge transfers StartNode.order_ids to MapNode.iterated_order_id.
  2. The runtime takes one item from iterated_order_id and supplies it as order-lookup-flow.order_id.
  3. The subflow begins at order-lookup-start, invokes the order-lookup tool, and reaches order-lookup-end with one order_status.
  4. The runtime repeats the subflow execution for the remaining order IDs.
  5. The append reducer collects the order_status value from each execution into MapNode.collected_order_status.
  6. A data-flow edge transfers the collected array to EndNode.order_statuses, and the next branch identifies the possible control-flow continuation after the MapNode completes.

The subflow does not receive the complete collection and does not combine the results. It defines only the operation for one order. The MapNode owns the collection iteration and reduction behavior.

Complete Runnable Agent Spec

The following example accepts an array of three order IDs. The MapNode executes order-lookup-flow once for each ID and uses the append reducer to return an array of order statuses. 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
    CASE ORDER_ID
      WHEN '7812' THEN
        ORDER_STATUS := 'SHIPPED';
      WHEN '7930' THEN
        ORDER_STATUS := 'PROCESSING';
      WHEN '8041' THEN
        ORDER_STATUS := 'DELIVERED';
      ELSE
        ORDER_STATUS := 'UNKNOWN';
    END CASE;
  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": "map-node-example-flow",
  "name": "map_node_example_flow",
  "inputs": [
    {
      "title": "order_ids",
      "type": "array",
      "items": {
        "title": "order_id",
        "type": "string"
      }
    }
  ],
  "outputs": [
    {
      "title": "order_statuses",
      "type": "array",
      "items": {
        "title": "order_status",
        "type": "string"
      }
    }
  ],
  "start_node": {
    "$component_ref": "start"
  },
  "nodes": [
    {
      "$component_ref": "start"
    },
    {
      "$component_ref": "lookup-orders"
    },
    {
      "$component_ref": "end"
    }
  ],
  "control_flow_connections": [
    {
      "component_type": "ControlFlowEdge",
      "id": "start-to-map",
      "name": "start_to_map",
      "from_node": {
        "$component_ref": "start"
      },
      "to_node": {
        "$component_ref": "lookup-orders"
      }
    },
    {
      "component_type": "ControlFlowEdge",
      "id": "map-to-end",
      "name": "map_to_end",
      "from_node": {
        "$component_ref": "lookup-orders"
      },
      "from_branch": "next",
      "to_node": {
        "$component_ref": "end"
      }
    }
  ],
  "data_flow_connections": [
    {
      "component_type": "DataFlowEdge",
      "id": "order-ids-to-map",
      "name": "order_ids_to_map",
      "source_node": {
        "$component_ref": "start"
      },
      "source_output": "order_ids",
      "destination_node": {
        "$component_ref": "lookup-orders"
      },
      "destination_input": "iterated_order_id"
    },
    {
      "component_type": "DataFlowEdge",
      "id": "collected-status-to-end",
      "name": "collected_status_to_end",
      "source_node": {
        "$component_ref": "lookup-orders"
      },
      "source_output": "collected_order_status",
      "destination_node": {
        "$component_ref": "end"
      },
      "destination_input": "order_statuses"
    }
  ],
  "$referenced_components": {
    "start": {
      "component_type": "StartNode",
      "id": "start",
      "name": "start",
      "inputs": [
        {
          "title": "order_ids",
          "type": "array",
          "items": {
            "title": "order_id",
            "type": "string"
          }
        }
      ],
      "outputs": [
        {
          "title": "order_ids",
          "type": "array",
          "items": {
            "title": "order_id",
            "type": "string"
          }
        }
      ],
      "branches": [
        "next"
      ]
    },
    "lookup-orders": {
      "component_type": "MapNode",
      "id": "lookup-orders",
      "name": "lookup_orders",
      "inputs": [
        {
          "title": "iterated_order_id",
          "type": "array",
          "items": {
            "title": "order_id",
            "type": "string"
          }
        }
      ],
      "outputs": [
        {
          "title": "collected_order_status",
          "type": "array",
          "items": {
            "title": "order_status",
            "type": "string"
          }
        }
      ],
      "branches": [
        "next"
      ],
      "subflow": {
        "$component_ref": "order-lookup-flow"
      },
      "reducers": {
        "order_status": "append"
      }
    },
    "end": {
      "component_type": "EndNode",
      "id": "end",
      "name": "end",
      "inputs": [
        {
          "title": "order_statuses",
          "type": "array",
          "items": {
            "title": "order_status",
            "type": "string"
          }
        }
      ],
      "outputs": [
        {
          "title": "order_statuses",
          "type": "array",
          "items": {
            "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_ids","value":["7812","7930","8041"]}]'
  );
  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_statuses": [
    "SHIPPED",
    "PROCESSING",
    "DELIVERED"
  ]
}

In this execution:

  1. The enclosing StartNode publishes the order_ids array.
  2. The outer data-flow edge supplies the array to
    MapNode.iterated_order_id.
  3. The MapNode extracts one ID and maps it to the order_id input of
    order-lookup-flow.
  4. The subflow invokes ORDER_TOOLS.LOOKUP_ORDER and returns one
    order_status.
  5. The MapNode repeats the subflow for the remaining IDs.
  6. The append reducer combines the per-item order_status values into
    MapNode.collected_order_status.
  7. The enclosing Flow maps the collected array to EndNode.order_statuses
    and returns it through the Flow output contract.