How to Run Multiple Flows in Parallel#
Parallelism is a fundamental concept in computing that enables tasks to be processed concurrently, significantly enhancing system efficiency, scalability, and overall performance.
Agent Spec supports the execution of multiple Flows in parallel, using the ParallelFlowNode. This guide will show you how to:
use ParallelFlowNode to run several tasks in parallel
use LlmNode to summarize the outcome of the parallel tasks
To follow this guide, you need an LLM. Agent Spec supports several LLM API providers. Select an LLM from the options below:
from pyagentspec.llms import OciGenAiConfig
from pyagentspec.llms.ociclientconfig import OciClientConfigWithApiKey
client_config = OciClientConfigWithApiKey(
name="Oci Client Config",
service_endpoint="https://url-to-service-endpoint.com",
auth_profile="DEFAULT",
auth_file_location="~/.oci/config"
)
llm_config = OciGenAiConfig(
name="Oci GenAI Config",
model_id="provider.model-id",
compartment_id="compartment-id",
client_config=client_config,
)
from pyagentspec.llms import VllmConfig
llm_config = VllmConfig(
name="Llama 3.1 8B instruct",
url="VLLM_URL",
model_id="model-id",
)
from pyagentspec.llms import OllamaConfig
llm_config = OllamaConfig(
name="Ollama Config",
model_id="model-id",
)
Basic implementation#
In this guide, we will create a Flow that generates a marketing message for a user.
Taking the username that identifies the user as input, we will take advantage of the ParallelFlowNode
to concurrently retrieve information about the user and the context, so that we can finally generate a
personalized marketing welcome message.
We first define the following server tools that retrieve the desired information:
One tool that retrieves the current time;
One tool that retrieves the user information, like name and date of birth;
One tool that gathers the user’s purchase history;
One tool that looks for the current list of items on sale, which could be recommended to the user.
Warning
In ParallelFlowNode subflows, it’s important to avoid calls to ClientTools, as they would require
to temporarily pause the execution to wait for client’s response. This is an operation that, based on
the runtime implementation, might require to interrupt the execution of the flow, with undesired side
effects on the final outcome.
from pyagentspec.property import DictProperty, ListProperty, StringProperty
from pyagentspec.tools import ServerTool
username_property = StringProperty(title="username")
user_info_property = DictProperty(title="user_info", value_type=StringProperty())
get_user_information_tool = ServerTool(
name="get_user_information",
description="Retrieve information about a user",
inputs=[username_property],
outputs=[user_info_property],
)
current_time_property = StringProperty(title="current_time")
get_current_time_tool = ServerTool(
name="get_current_time",
description="Return current time",
inputs=[],
outputs=[current_time_property],
)
user_purchases_property = ListProperty(title="user_purchases", item_type=DictProperty(value_type=StringProperty()))
get_user_last_purchases_tool = ServerTool(
name="get_user_last_purchases",
description="Retrieve the list of purchases made by a user",
inputs=[username_property],
outputs=[user_purchases_property],
)
items_on_sale_property = ListProperty(title="items_on_sale", item_type=DictProperty(value_type=StringProperty()))
get_items_on_sale_tool = ServerTool(
name="get_items_on_sale",
description="Retrieve the list of items currently on sale",
inputs=[],
outputs=[items_on_sale_property],
)
These tools simply gather information, therefore they can be easily parallelized.
We create the flows that wrap the tools we just created, and we collect them all in a ParallelFlowNode
for parallel execution. For simplicity, to create the subflows we use a helper that takes a single node
and creates a flow containing only that node, and exposing its inputs and outputs.
from pyagentspec.flows.flow import Flow
from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge
from pyagentspec.flows.node import Node
from pyagentspec.flows.nodes import ParallelFlowNode, ToolNode, StartNode, EndNode
def create_one_node_flow(node: Node) -> Flow:
"""Create a flow that wraps the given node, having the same inputs and outputs"""
flow_name = node.name + "_flow"
start_node = StartNode(name=flow_name + "_start", inputs=node.inputs)
end_node = EndNode(name=flow_name + "_end", outputs=node.outputs)
return Flow(
name=flow_name,
start_node=start_node,
nodes=[start_node, end_node, node],
control_flow_connections=[
ControlFlowEdge(name="c1", from_node=start_node, to_node=node),
ControlFlowEdge(name="c2", from_node=node, to_node=end_node),
],
data_flow_connections=[
DataFlowEdge(
name=f"din_{input_property.title}",
source_node=start_node, source_output=input_property.title,
destination_node=node, destination_input=input_property.title,
)
for input_property in node.inputs
] + [
DataFlowEdge(
name=f"dout_{output_property.title}",
source_node=node, source_output=output_property.title,
destination_node=end_node, destination_input=output_property.title,
)
for output_property in node.outputs
]
)
get_current_time_flow = create_one_node_flow(
ToolNode(name="get_current_time_step", tool=get_current_time_tool)
)
get_user_information_flow = create_one_node_flow(
ToolNode(name="get_user_information_step", tool=get_user_information_tool)
)
get_user_last_purchases_flow = create_one_node_flow(
ToolNode(name="get_user_last_purchases_step", tool=get_user_last_purchases_tool)
)
get_items_on_sale_flow = create_one_node_flow(
ToolNode(name="get_items_on_sale_steo", tool=get_items_on_sale_tool)
)
parallel_flow_node = ParallelFlowNode(
name="parallel_flow_node",
subflows=[
get_current_time_flow,
get_user_information_flow,
get_user_last_purchases_flow,
get_items_on_sale_flow,
],
)
The ParallelFlowNode we created will expose all the outputs that the different inner flows generate.
We use this information to ask an LLM to generate a personalized welcome message for the user, which should also
have a marketing purpose.
from pyagentspec.llms import VllmConfig
from pyagentspec.flows.nodes import OutputMessageNode, LlmNode
llm_config = VllmConfig(
name="vllm-llama-4-maverick",
model_id="llama-4-maverick",
url="http://url.to.my.vllm.server/llama4mav",
)
prompt = """# Instructions
You are a marketing expert. You have to write a welcome message for a user.
The message must contain:
- A first sentence of greetings, including user's name, and personalized in case it's user's birthday
- A proposal containing something to buy
The purchase proposal must be:
- aligned with user's purchase history
- part of the list of items on sale
# User information
{{user_info}}
Note that the current time to check the birthday is: {{current_time}}
The list of items purchased by the user is:
{{user_purchases}}
# Items on sale
{{items_on_sale}}
Please write the welcome message for the user.
Do not give me the instructions to do it, I want only the final message to send.
"""
prepare_marketing_message_node = LlmNode(
name="prepare_marketing_message_node", prompt_template=prompt, llm_config=llm_config
)
output_message_node = OutputMessageNode(name="output_message_node", message="{{output}}")
Now that we have all the steps that compose our flow, we just put everything together to create it, and we execute it to generate our personalized message.
from pyagentspec.flows.flow import Flow
start_node = StartNode(name="start_node", inputs=[username_property])
end_node = EndNode(name="end_node")
flow = Flow(
name="marketing_message_flow",
start_node=start_node,
nodes=[parallel_flow_node, prepare_marketing_message_node, output_message_node, start_node, end_node],
control_flow_connections=[
ControlFlowEdge(name="cfe1", from_node=start_node, to_node=parallel_flow_node),
ControlFlowEdge(name="cfe2", from_node=parallel_flow_node, to_node=prepare_marketing_message_node),
ControlFlowEdge(name="cfe3", from_node=prepare_marketing_message_node, to_node=output_message_node),
ControlFlowEdge(name="cfe4", from_node=output_message_node, to_node=end_node),
],
data_flow_connections=[
DataFlowEdge(
name="dfe_username",
source_node=start_node, source_output="username",
destination_node=parallel_flow_node, destination_input="username",
)
] + [
DataFlowEdge(
name="dfe_" + property_.title,
source_node=parallel_flow_node, source_output=property_.title,
destination_node=prepare_marketing_message_node, destination_input=property_.title,
)
for property_ in [current_time_property, user_info_property, user_purchases_property, items_on_sale_property]
]
)
Notes about parallelization#
Not all sub-flows can be executed in parallel.
Agent Spec does not forbid specific configurations for ParallelFlowNode subflows, but there are several
precautions to take when parallelization is enabled, especially when sub-flows are supposed to access mutable
shared resources (e.g., the conversation), or interrupt the normal execution of the flow (e.g., client tools).
For more information about parallel execution support in Agent Spec, please check the language specification. For guidelines about secure implementation of concurrent execution, instead, check our security guidelines.
Export the Agent Spec configuration#
The Agent Spec configuration is generated in JSON format. These configurations can be loaded and executed in Agent Spec-compatible systems such as the WayFlow runtime. See, for example, How to Execute Agent Spec Configurations with WayFlow.
from pyagentspec.serialization import AgentSpecSerializer
serialized_flow = AgentSpecSerializer().to_json(flow)
API Reference: AgentSpecSerializer
Here is what the Agent Spec representation will look like ↓
Click here to see the assistant configuration.
{
"component_type": "Flow",
"id": "61d93ff3-a5c2-42e1-a9a3-d913014a8d47",
"name": "marketing_message_flow",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [],
"start_node": {
"$component_ref": "276f6084-b26d-4ee2-8cf1-238f3032654e"
},
"nodes": [
{
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
{
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
},
{
"$component_ref": "7e31a16a-357c-4121-b00e-549cb36b550b"
},
{
"$component_ref": "276f6084-b26d-4ee2-8cf1-238f3032654e"
},
{
"$component_ref": "cc8603e1-1c15-4a1d-9674-68a202049fd6"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "4bb948ac-b7b0-4383-af68-d212a836d468",
"name": "cfe1",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "276f6084-b26d-4ee2-8cf1-238f3032654e"
},
"from_branch": null,
"to_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
}
},
{
"component_type": "ControlFlowEdge",
"id": "ab9eb713-3ad8-4e6d-8afe-87af8b40121f",
"name": "cfe2",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
"from_branch": null,
"to_node": {
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
}
},
{
"component_type": "ControlFlowEdge",
"id": "73f33011-058b-4d63-a02a-c4e3f1b8fb30",
"name": "cfe3",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
},
"from_branch": null,
"to_node": {
"$component_ref": "7e31a16a-357c-4121-b00e-549cb36b550b"
}
},
{
"component_type": "ControlFlowEdge",
"id": "79c742e8-6f06-4391-baae-49b555d74908",
"name": "cfe4",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "7e31a16a-357c-4121-b00e-549cb36b550b"
},
"from_branch": null,
"to_node": {
"$component_ref": "cc8603e1-1c15-4a1d-9674-68a202049fd6"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "83c62b8a-56cd-46c0-9c92-5e6d90246361",
"name": "dfe_username",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "276f6084-b26d-4ee2-8cf1-238f3032654e"
},
"source_output": "username",
"destination_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
"destination_input": "username"
},
{
"component_type": "DataFlowEdge",
"id": "b0c1ad2d-0e11-40f3-8c84-4601bcf556cb",
"name": "dfe_current_time",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
"source_output": "current_time",
"destination_node": {
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
},
"destination_input": "current_time"
},
{
"component_type": "DataFlowEdge",
"id": "7933dfd3-7a12-4fcf-aac4-2510a5fce982",
"name": "dfe_user_info",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
"source_output": "user_info",
"destination_node": {
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
},
"destination_input": "user_info"
},
{
"component_type": "DataFlowEdge",
"id": "03b5a2b2-9359-4ad9-ba02-0d6281dd83f5",
"name": "dfe_user_purchases",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
"source_output": "user_purchases",
"destination_node": {
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
},
"destination_input": "user_purchases"
},
{
"component_type": "DataFlowEdge",
"id": "db2d9275-7937-4d1e-b1c1-417586886c10",
"name": "dfe_items_on_sale",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "1954fcef-a669-417a-a1be-9bd5d138bf2a"
},
"source_output": "items_on_sale",
"destination_node": {
"$component_ref": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7"
},
"destination_input": "items_on_sale"
}
],
"$referenced_components": {
"1954fcef-a669-417a-a1be-9bd5d138bf2a": {
"component_type": "ParallelFlowNode",
"id": "1954fcef-a669-417a-a1be-9bd5d138bf2a",
"name": "parallel_flow_node",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "current_time",
"type": "string"
},
{
"title": "user_info",
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
{
"title": "user_purchases",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
},
{
"title": "items_on_sale",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"branches": [
"next"
],
"subflows": [
{
"component_type": "Flow",
"id": "9c2736c2-9716-4c69-935a-b341adb0056c",
"name": "get_current_time_step_flow",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "current_time",
"type": "string"
}
],
"start_node": {
"$component_ref": "6e2a3922-9993-4f66-b6b3-570c2821518e"
},
"nodes": [
{
"$component_ref": "6e2a3922-9993-4f66-b6b3-570c2821518e"
},
{
"$component_ref": "cde5f5ec-c028-43b7-9d66-23e37f59403e"
},
{
"$component_ref": "982f992c-76dd-4901-b810-aab2d1f610bd"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "47fbf5c0-2ba4-4f68-883f-1a0c205524d3",
"name": "c1",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "6e2a3922-9993-4f66-b6b3-570c2821518e"
},
"from_branch": null,
"to_node": {
"$component_ref": "982f992c-76dd-4901-b810-aab2d1f610bd"
}
},
{
"component_type": "ControlFlowEdge",
"id": "63dac3bd-cbfb-47bc-82d9-c9fc18cb086f",
"name": "c2",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "982f992c-76dd-4901-b810-aab2d1f610bd"
},
"from_branch": null,
"to_node": {
"$component_ref": "cde5f5ec-c028-43b7-9d66-23e37f59403e"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "453e3bfe-0b46-4cd3-b38d-85cf5ac13efb",
"name": "dout_current_time",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "982f992c-76dd-4901-b810-aab2d1f610bd"
},
"source_output": "current_time",
"destination_node": {
"$component_ref": "cde5f5ec-c028-43b7-9d66-23e37f59403e"
},
"destination_input": "current_time"
}
],
"$referenced_components": {
"6e2a3922-9993-4f66-b6b3-570c2821518e": {
"component_type": "StartNode",
"id": "6e2a3922-9993-4f66-b6b3-570c2821518e",
"name": "get_current_time_step_flow_start",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [],
"branches": [
"next"
]
},
"cde5f5ec-c028-43b7-9d66-23e37f59403e": {
"component_type": "EndNode",
"id": "cde5f5ec-c028-43b7-9d66-23e37f59403e",
"name": "get_current_time_step_flow_start",
"description": null,
"metadata": {},
"inputs": [
{
"title": "current_time",
"type": "string"
}
],
"outputs": [
{
"title": "current_time",
"type": "string"
}
],
"branches": [],
"branch_name": "next"
},
"982f992c-76dd-4901-b810-aab2d1f610bd": {
"component_type": "ToolNode",
"id": "982f992c-76dd-4901-b810-aab2d1f610bd",
"name": "get_current_time_step",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "current_time",
"type": "string"
}
],
"branches": [
"next"
],
"tool": {
"component_type": "ServerTool",
"id": "d5540249-4d2f-4f99-a807-14088ff9e14c",
"name": "get_current_time",
"description": "Return current time",
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "current_time",
"type": "string"
}
]
}
}
}
},
{
"component_type": "Flow",
"id": "241296a7-0a4a-45d6-93e8-88b77f0ecd9e",
"name": "get_user_information_step_flow",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "user_info",
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
}
],
"start_node": {
"$component_ref": "3dc5d3eb-d366-4de7-8afe-3d2d160c7dec"
},
"nodes": [
{
"$component_ref": "3dc5d3eb-d366-4de7-8afe-3d2d160c7dec"
},
{
"$component_ref": "429967e3-5a64-4749-be07-57cc54afd39e"
},
{
"$component_ref": "141c49b0-026c-4379-b3a8-24dafe756278"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "3fd8d404-e67c-491a-b3e8-31771f1da442",
"name": "c1",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "3dc5d3eb-d366-4de7-8afe-3d2d160c7dec"
},
"from_branch": null,
"to_node": {
"$component_ref": "141c49b0-026c-4379-b3a8-24dafe756278"
}
},
{
"component_type": "ControlFlowEdge",
"id": "d068501a-964e-4035-8f98-34d7b8350d43",
"name": "c2",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "141c49b0-026c-4379-b3a8-24dafe756278"
},
"from_branch": null,
"to_node": {
"$component_ref": "429967e3-5a64-4749-be07-57cc54afd39e"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "b756b473-e40e-4a97-b25a-bcd457b95242",
"name": "din_username",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "3dc5d3eb-d366-4de7-8afe-3d2d160c7dec"
},
"source_output": "username",
"destination_node": {
"$component_ref": "141c49b0-026c-4379-b3a8-24dafe756278"
},
"destination_input": "username"
},
{
"component_type": "DataFlowEdge",
"id": "37827be0-ab14-439f-8251-832cb18128e0",
"name": "dout_user_info",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "141c49b0-026c-4379-b3a8-24dafe756278"
},
"source_output": "user_info",
"destination_node": {
"$component_ref": "429967e3-5a64-4749-be07-57cc54afd39e"
},
"destination_input": "user_info"
}
],
"$referenced_components": {
"3dc5d3eb-d366-4de7-8afe-3d2d160c7dec": {
"component_type": "StartNode",
"id": "3dc5d3eb-d366-4de7-8afe-3d2d160c7dec",
"name": "get_user_information_step_flow_start",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "username",
"type": "string"
}
],
"branches": [
"next"
]
},
"429967e3-5a64-4749-be07-57cc54afd39e": {
"component_type": "EndNode",
"id": "429967e3-5a64-4749-be07-57cc54afd39e",
"name": "get_user_information_step_flow_start",
"description": null,
"metadata": {},
"inputs": [
{
"title": "user_info",
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
}
],
"outputs": [
{
"title": "user_info",
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
}
],
"branches": [],
"branch_name": "next"
},
"141c49b0-026c-4379-b3a8-24dafe756278": {
"component_type": "ToolNode",
"id": "141c49b0-026c-4379-b3a8-24dafe756278",
"name": "get_user_information_step",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "user_info",
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
}
],
"branches": [
"next"
],
"tool": {
"component_type": "ServerTool",
"id": "2ab1ea62-0c8b-46ed-85ba-2d6dbbd65761",
"name": "get_user_information",
"description": "Retrieve information about a user",
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "user_info",
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
}
]
}
}
}
},
{
"component_type": "Flow",
"id": "d384b947-2c6c-4669-b4f1-92c2d515891e",
"name": "get_user_last_purchases_step_flow",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "user_purchases",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"start_node": {
"$component_ref": "0bc49848-2a50-4b01-8b88-68794a3a5cad"
},
"nodes": [
{
"$component_ref": "0bc49848-2a50-4b01-8b88-68794a3a5cad"
},
{
"$component_ref": "205dff1d-9af0-4a44-937e-4ef950fbc436"
},
{
"$component_ref": "82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "9c1644a5-91e5-4124-97f2-e3e0a111b2b7",
"name": "c1",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "0bc49848-2a50-4b01-8b88-68794a3a5cad"
},
"from_branch": null,
"to_node": {
"$component_ref": "82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780"
}
},
{
"component_type": "ControlFlowEdge",
"id": "ae0ff36d-b08e-496e-9dec-08e443ba8d92",
"name": "c2",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780"
},
"from_branch": null,
"to_node": {
"$component_ref": "205dff1d-9af0-4a44-937e-4ef950fbc436"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "5f538977-456f-48e8-9c6d-04571895aa1d",
"name": "din_username",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "0bc49848-2a50-4b01-8b88-68794a3a5cad"
},
"source_output": "username",
"destination_node": {
"$component_ref": "82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780"
},
"destination_input": "username"
},
{
"component_type": "DataFlowEdge",
"id": "2e320aee-73dd-43f3-b3f1-623d41ad1fa8",
"name": "dout_user_purchases",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780"
},
"source_output": "user_purchases",
"destination_node": {
"$component_ref": "205dff1d-9af0-4a44-937e-4ef950fbc436"
},
"destination_input": "user_purchases"
}
],
"$referenced_components": {
"0bc49848-2a50-4b01-8b88-68794a3a5cad": {
"component_type": "StartNode",
"id": "0bc49848-2a50-4b01-8b88-68794a3a5cad",
"name": "get_user_last_purchases_step_flow_start",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "username",
"type": "string"
}
],
"branches": [
"next"
]
},
"205dff1d-9af0-4a44-937e-4ef950fbc436": {
"component_type": "EndNode",
"id": "205dff1d-9af0-4a44-937e-4ef950fbc436",
"name": "get_user_last_purchases_step_flow_start",
"description": null,
"metadata": {},
"inputs": [
{
"title": "user_purchases",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"outputs": [
{
"title": "user_purchases",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"branches": [],
"branch_name": "next"
},
"82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780": {
"component_type": "ToolNode",
"id": "82e6d2c4-44b0-42f7-8cc8-ba54eb3c4780",
"name": "get_user_last_purchases_step",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "user_purchases",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"branches": [
"next"
],
"tool": {
"component_type": "ServerTool",
"id": "86f046df-a9b6-49ac-b73b-998d02ead1a3",
"name": "get_user_last_purchases",
"description": "Retrieve the list of purchases made by a user",
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "user_purchases",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
]
}
}
}
},
{
"component_type": "Flow",
"id": "8d7b7b24-58e7-4335-8a1f-f91587dee241",
"name": "get_items_on_sale_steo_flow",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "items_on_sale",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"start_node": {
"$component_ref": "9c97adb1-2c15-4f69-9a30-c7b46f4a598d"
},
"nodes": [
{
"$component_ref": "9c97adb1-2c15-4f69-9a30-c7b46f4a598d"
},
{
"$component_ref": "e099a667-cf9d-402c-b07c-894502f28fb7"
},
{
"$component_ref": "2e535a6e-ae5a-445b-8bda-d75b9adb7534"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "9c48f961-1541-4bf0-b571-7f19e1610a42",
"name": "c1",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "9c97adb1-2c15-4f69-9a30-c7b46f4a598d"
},
"from_branch": null,
"to_node": {
"$component_ref": "2e535a6e-ae5a-445b-8bda-d75b9adb7534"
}
},
{
"component_type": "ControlFlowEdge",
"id": "6f0954d1-8d9f-498c-bcb0-167f5f15488e",
"name": "c2",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "2e535a6e-ae5a-445b-8bda-d75b9adb7534"
},
"from_branch": null,
"to_node": {
"$component_ref": "e099a667-cf9d-402c-b07c-894502f28fb7"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "bf4a0a50-d3a6-4ebf-bc0c-53b7d5f1eb6a",
"name": "dout_items_on_sale",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "2e535a6e-ae5a-445b-8bda-d75b9adb7534"
},
"source_output": "items_on_sale",
"destination_node": {
"$component_ref": "e099a667-cf9d-402c-b07c-894502f28fb7"
},
"destination_input": "items_on_sale"
}
],
"$referenced_components": {
"9c97adb1-2c15-4f69-9a30-c7b46f4a598d": {
"component_type": "StartNode",
"id": "9c97adb1-2c15-4f69-9a30-c7b46f4a598d",
"name": "get_items_on_sale_steo_flow_start",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [],
"branches": [
"next"
]
},
"e099a667-cf9d-402c-b07c-894502f28fb7": {
"component_type": "EndNode",
"id": "e099a667-cf9d-402c-b07c-894502f28fb7",
"name": "get_items_on_sale_steo_flow_start",
"description": null,
"metadata": {},
"inputs": [
{
"title": "items_on_sale",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"outputs": [
{
"title": "items_on_sale",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"branches": [],
"branch_name": "next"
},
"2e535a6e-ae5a-445b-8bda-d75b9adb7534": {
"component_type": "ToolNode",
"id": "2e535a6e-ae5a-445b-8bda-d75b9adb7534",
"name": "get_items_on_sale_steo",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "items_on_sale",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
],
"branches": [
"next"
],
"tool": {
"component_type": "ServerTool",
"id": "fa406981-3775-4415-a147-c68ee85102bb",
"name": "get_items_on_sale",
"description": "Retrieve the list of items currently on sale",
"metadata": {},
"inputs": [],
"outputs": [
{
"title": "items_on_sale",
"items": {
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
"type": "array"
}
]
}
}
}
}
]
},
"db1adb9a-9ce9-4af5-bc4d-878acec77bd7": {
"component_type": "LlmNode",
"id": "db1adb9a-9ce9-4af5-bc4d-878acec77bd7",
"name": "prepare_marketing_message_node",
"description": null,
"metadata": {},
"inputs": [
{
"title": "user_purchases",
"type": "string"
},
{
"title": "items_on_sale",
"type": "string"
},
{
"title": "current_time",
"type": "string"
},
{
"title": "user_info",
"type": "string"
}
],
"outputs": [
{
"description": "Raw text generated by the LLM",
"title": "generated_text",
"type": "string"
}
],
"branches": [
"next"
],
"llm_config": {
"component_type": "VllmConfig",
"id": "5d2b8499-3d7a-494b-9e12-b61daf36a3f7",
"name": "vllm-llama-4-maverick",
"description": null,
"metadata": {},
"default_generation_parameters": null,
"url": "http://url.to.my.vllm.server/llama4mav",
"model_id": "llama-4-maverick"
},
"prompt_template": "# Instructions\n\nYou are a marketing expert. You have to write a welcome message for a user.\n\nThe message must contain:\n- A first sentence of greetings, including user's name, and personalized in case it's user's birthday\n- A proposal containing something to buy\n\nThe purchase proposal must be:\n- aligned with user's purchase history\n- part of the list of items on sale\n\n# User information\n\n{{user_info}}\n\nNote that the current time to check the birthday is: {{current_time}}\n\nThe list of items purchased by the user is:\n{{user_purchases}}\n\n# Items on sale\n\n{{items_on_sale}}\n\nPlease write the welcome message for the user.\nDo not give me the instructions to do it, I want only the final message to send. \n"
},
"7e31a16a-357c-4121-b00e-549cb36b550b": {
"component_type": "OutputMessageNode",
"id": "7e31a16a-357c-4121-b00e-549cb36b550b",
"name": "output_message_node",
"description": null,
"metadata": {},
"inputs": [
{
"title": "output",
"type": "string"
}
],
"outputs": [],
"branches": [
"next"
],
"message": "{{output}}"
},
"276f6084-b26d-4ee2-8cf1-238f3032654e": {
"component_type": "StartNode",
"id": "276f6084-b26d-4ee2-8cf1-238f3032654e",
"name": "start_node",
"description": null,
"metadata": {},
"inputs": [
{
"title": "username",
"type": "string"
}
],
"outputs": [
{
"title": "username",
"type": "string"
}
],
"branches": [
"next"
]
},
"cc8603e1-1c15-4a1d-9674-68a202049fd6": {
"component_type": "EndNode",
"id": "cc8603e1-1c15-4a1d-9674-68a202049fd6",
"name": "end_node",
"description": null,
"metadata": {},
"inputs": [],
"outputs": [],
"branches": [],
"branch_name": "next"
}
},
"agentspec_version": "25.4.2"
}
component_type: Flow
id: 6861b3dc-f43c-4fda-a810-d46d927a97fc
name: marketing_message_flow
description: null
metadata: {}
inputs:
- title: username
type: string
outputs: []
start_node:
$component_ref: c70fc4da-5944-465d-95ff-43a566fd869d
nodes:
- $component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
- $component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
- $component_ref: b787c7ef-3825-45b4-9673-f4aa3d0fa3da
- $component_ref: c70fc4da-5944-465d-95ff-43a566fd869d
- $component_ref: af549944-223d-4040-847d-5144d0e2299e
control_flow_connections:
- component_type: ControlFlowEdge
id: 1bc34625-c3ed-4666-b940-1843005a031d
name: cfe1
description: null
metadata: {}
from_node:
$component_ref: c70fc4da-5944-465d-95ff-43a566fd869d
from_branch: null
to_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
- component_type: ControlFlowEdge
id: 5565d070-0023-4654-8981-55c84862113e
name: cfe2
description: null
metadata: {}
from_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
from_branch: null
to_node:
$component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
- component_type: ControlFlowEdge
id: 4c76ad90-9d79-4c22-9a37-da82bd62828f
name: cfe3
description: null
metadata: {}
from_node:
$component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
from_branch: null
to_node:
$component_ref: b787c7ef-3825-45b4-9673-f4aa3d0fa3da
- component_type: ControlFlowEdge
id: 387f6cfd-8a48-45d2-9737-d2cc865ef374
name: cfe4
description: null
metadata: {}
from_node:
$component_ref: b787c7ef-3825-45b4-9673-f4aa3d0fa3da
from_branch: null
to_node:
$component_ref: af549944-223d-4040-847d-5144d0e2299e
data_flow_connections:
- component_type: DataFlowEdge
id: b3d3e994-c69b-4e0e-81f6-8420f5e8d557
name: dfe_username
description: null
metadata: {}
source_node:
$component_ref: c70fc4da-5944-465d-95ff-43a566fd869d
source_output: username
destination_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
destination_input: username
- component_type: DataFlowEdge
id: 2144ad10-c436-418b-9726-a1c50e53e9ab
name: dfe_current_time
description: null
metadata: {}
source_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
source_output: current_time
destination_node:
$component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
destination_input: current_time
- component_type: DataFlowEdge
id: baffc53e-b41d-442c-bf9f-c9dc63ca58e2
name: dfe_user_info
description: null
metadata: {}
source_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
source_output: user_info
destination_node:
$component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
destination_input: user_info
- component_type: DataFlowEdge
id: f6fe93f1-7f9c-4c63-b21e-642571bffa8d
name: dfe_user_purchases
description: null
metadata: {}
source_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
source_output: user_purchases
destination_node:
$component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
destination_input: user_purchases
- component_type: DataFlowEdge
id: 87853542-222c-44bd-bb72-617b3b703ddd
name: dfe_items_on_sale
description: null
metadata: {}
source_node:
$component_ref: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
source_output: items_on_sale
destination_node:
$component_ref: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
destination_input: items_on_sale
$referenced_components:
c70fc4da-5944-465d-95ff-43a566fd869d:
component_type: StartNode
id: c70fc4da-5944-465d-95ff-43a566fd869d
name: start_node
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: username
type: string
branches:
- next
35c9387c-b8f3-4657-ab07-cb0c52cbb064:
component_type: ParallelFlowNode
id: 35c9387c-b8f3-4657-ab07-cb0c52cbb064
name: parallel_flow_node
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: current_time
type: string
- title: user_info
additionalProperties:
type: string
properties: {}
type: object
- title: user_purchases
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
- title: items_on_sale
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
branches:
- next
subflows:
- component_type: Flow
id: 282874ac-6d5f-471a-9f04-d0cc00c07145
name: get_current_time_step_flow
description: null
metadata: {}
inputs: []
outputs:
- title: current_time
type: string
start_node:
$component_ref: d26092d8-2894-45bf-8eea-2e4348f0eb36
nodes:
- $component_ref: d26092d8-2894-45bf-8eea-2e4348f0eb36
- $component_ref: e1a65898-83f7-42cd-907f-5e790ec39f05
- $component_ref: de6ee72d-89f6-4d43-a400-f755af144c5b
control_flow_connections:
- component_type: ControlFlowEdge
id: 7cdca1f7-ffeb-4363-a027-810c411fade9
name: c1
description: null
metadata: {}
from_node:
$component_ref: d26092d8-2894-45bf-8eea-2e4348f0eb36
from_branch: null
to_node:
$component_ref: de6ee72d-89f6-4d43-a400-f755af144c5b
- component_type: ControlFlowEdge
id: 8e3b006b-ad21-4a8f-89ae-2e225e5a957c
name: c2
description: null
metadata: {}
from_node:
$component_ref: de6ee72d-89f6-4d43-a400-f755af144c5b
from_branch: null
to_node:
$component_ref: e1a65898-83f7-42cd-907f-5e790ec39f05
data_flow_connections:
- component_type: DataFlowEdge
id: fa57815c-8719-44e8-adda-b85bf17ed61c
name: dout_current_time
description: null
metadata: {}
source_node:
$component_ref: de6ee72d-89f6-4d43-a400-f755af144c5b
source_output: current_time
destination_node:
$component_ref: e1a65898-83f7-42cd-907f-5e790ec39f05
destination_input: current_time
$referenced_components:
d26092d8-2894-45bf-8eea-2e4348f0eb36:
component_type: StartNode
id: d26092d8-2894-45bf-8eea-2e4348f0eb36
name: get_current_time_step_flow_start
description: null
metadata: {}
inputs: []
outputs: []
branches:
- next
de6ee72d-89f6-4d43-a400-f755af144c5b:
component_type: ToolNode
id: de6ee72d-89f6-4d43-a400-f755af144c5b
name: get_current_time_step
description: null
metadata: {}
inputs: []
outputs:
- title: current_time
type: string
branches:
- next
tool:
component_type: ServerTool
id: a94b12bb-1d7e-41c4-955b-7db0c8754256
name: get_current_time
description: Return current time
metadata: {}
inputs: []
outputs:
- title: current_time
type: string
e1a65898-83f7-42cd-907f-5e790ec39f05:
component_type: EndNode
id: e1a65898-83f7-42cd-907f-5e790ec39f05
name: get_current_time_step_flow_start
description: null
metadata: {}
inputs:
- title: current_time
type: string
outputs:
- title: current_time
type: string
branches: []
branch_name: next
- component_type: Flow
id: ed508681-fa46-4d65-9fde-6da51f84fae7
name: get_user_information_step_flow
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: user_info
additionalProperties:
type: string
properties: {}
type: object
start_node:
$component_ref: f7c961d9-0b97-4a9a-ae1b-6be99d84288c
nodes:
- $component_ref: f7c961d9-0b97-4a9a-ae1b-6be99d84288c
- $component_ref: d2f33b8f-eb0f-4952-94ed-5eb84c8381f6
- $component_ref: af34f4fa-cb16-4296-b600-a2464df0e820
control_flow_connections:
- component_type: ControlFlowEdge
id: 7fc31ca2-a583-4133-91e6-a0f13674f6aa
name: c1
description: null
metadata: {}
from_node:
$component_ref: f7c961d9-0b97-4a9a-ae1b-6be99d84288c
from_branch: null
to_node:
$component_ref: af34f4fa-cb16-4296-b600-a2464df0e820
- component_type: ControlFlowEdge
id: 48c3736e-58c7-4164-9220-aed924a1d44b
name: c2
description: null
metadata: {}
from_node:
$component_ref: af34f4fa-cb16-4296-b600-a2464df0e820
from_branch: null
to_node:
$component_ref: d2f33b8f-eb0f-4952-94ed-5eb84c8381f6
data_flow_connections:
- component_type: DataFlowEdge
id: 9791f68b-bfa5-45b2-b39a-022aafba8e84
name: din_username
description: null
metadata: {}
source_node:
$component_ref: f7c961d9-0b97-4a9a-ae1b-6be99d84288c
source_output: username
destination_node:
$component_ref: af34f4fa-cb16-4296-b600-a2464df0e820
destination_input: username
- component_type: DataFlowEdge
id: f4289953-57c8-43e7-8c41-58a93e926c6f
name: dout_user_info
description: null
metadata: {}
source_node:
$component_ref: af34f4fa-cb16-4296-b600-a2464df0e820
source_output: user_info
destination_node:
$component_ref: d2f33b8f-eb0f-4952-94ed-5eb84c8381f6
destination_input: user_info
$referenced_components:
f7c961d9-0b97-4a9a-ae1b-6be99d84288c:
component_type: StartNode
id: f7c961d9-0b97-4a9a-ae1b-6be99d84288c
name: get_user_information_step_flow_start
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: username
type: string
branches:
- next
af34f4fa-cb16-4296-b600-a2464df0e820:
component_type: ToolNode
id: af34f4fa-cb16-4296-b600-a2464df0e820
name: get_user_information_step
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: user_info
additionalProperties:
type: string
properties: {}
type: object
branches:
- next
tool:
component_type: ServerTool
id: d5fd6f3c-6b39-43b8-8829-bfab35cab174
name: get_user_information
description: Retrieve information about a user
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: user_info
additionalProperties:
type: string
properties: {}
type: object
d2f33b8f-eb0f-4952-94ed-5eb84c8381f6:
component_type: EndNode
id: d2f33b8f-eb0f-4952-94ed-5eb84c8381f6
name: get_user_information_step_flow_start
description: null
metadata: {}
inputs:
- title: user_info
additionalProperties:
type: string
properties: {}
type: object
outputs:
- title: user_info
additionalProperties:
type: string
properties: {}
type: object
branches: []
branch_name: next
- component_type: Flow
id: 107cb956-34b6-45b3-819c-8609ff09443a
name: get_user_last_purchases_step_flow
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: user_purchases
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
start_node:
$component_ref: 1215d9f6-06f3-4cbe-8789-8fae2d54e218
nodes:
- $component_ref: 1215d9f6-06f3-4cbe-8789-8fae2d54e218
- $component_ref: 9a691ffe-3c85-41a9-9c80-b6efecb01cb8
- $component_ref: 87d8a6ff-a38f-490d-a029-59495e53df5d
control_flow_connections:
- component_type: ControlFlowEdge
id: 20a98d13-65df-4c4c-b16d-f6da1787151f
name: c1
description: null
metadata: {}
from_node:
$component_ref: 1215d9f6-06f3-4cbe-8789-8fae2d54e218
from_branch: null
to_node:
$component_ref: 87d8a6ff-a38f-490d-a029-59495e53df5d
- component_type: ControlFlowEdge
id: bd9b876f-7ffd-4ee2-976b-1eb740f13a5e
name: c2
description: null
metadata: {}
from_node:
$component_ref: 87d8a6ff-a38f-490d-a029-59495e53df5d
from_branch: null
to_node:
$component_ref: 9a691ffe-3c85-41a9-9c80-b6efecb01cb8
data_flow_connections:
- component_type: DataFlowEdge
id: 0c1818d2-660f-47ac-b520-a84bc61f221f
name: din_username
description: null
metadata: {}
source_node:
$component_ref: 1215d9f6-06f3-4cbe-8789-8fae2d54e218
source_output: username
destination_node:
$component_ref: 87d8a6ff-a38f-490d-a029-59495e53df5d
destination_input: username
- component_type: DataFlowEdge
id: 0039f6a6-faf6-40a8-b2d3-3041b03eb3b1
name: dout_user_purchases
description: null
metadata: {}
source_node:
$component_ref: 87d8a6ff-a38f-490d-a029-59495e53df5d
source_output: user_purchases
destination_node:
$component_ref: 9a691ffe-3c85-41a9-9c80-b6efecb01cb8
destination_input: user_purchases
$referenced_components:
1215d9f6-06f3-4cbe-8789-8fae2d54e218:
component_type: StartNode
id: 1215d9f6-06f3-4cbe-8789-8fae2d54e218
name: get_user_last_purchases_step_flow_start
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: username
type: string
branches:
- next
87d8a6ff-a38f-490d-a029-59495e53df5d:
component_type: ToolNode
id: 87d8a6ff-a38f-490d-a029-59495e53df5d
name: get_user_last_purchases_step
description: null
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: user_purchases
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
branches:
- next
tool:
component_type: ServerTool
id: 380dd9d1-072a-45c4-8a61-2ba4413b4496
name: get_user_last_purchases
description: Retrieve the list of purchases made by a user
metadata: {}
inputs:
- title: username
type: string
outputs:
- title: user_purchases
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
9a691ffe-3c85-41a9-9c80-b6efecb01cb8:
component_type: EndNode
id: 9a691ffe-3c85-41a9-9c80-b6efecb01cb8
name: get_user_last_purchases_step_flow_start
description: null
metadata: {}
inputs:
- title: user_purchases
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
outputs:
- title: user_purchases
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
branches: []
branch_name: next
- component_type: Flow
id: dfeb70dc-6b50-4f23-a030-2ca7ccb6c9a1
name: get_items_on_sale_steo_flow
description: null
metadata: {}
inputs: []
outputs:
- title: items_on_sale
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
start_node:
$component_ref: b3a7dcd4-0c27-4d3e-9c24-6abcf80ede14
nodes:
- $component_ref: b3a7dcd4-0c27-4d3e-9c24-6abcf80ede14
- $component_ref: 5d530823-b8a1-4c19-9221-d95b6b12f7ff
- $component_ref: 126d5e3d-b214-48e1-8bca-ab5c0b518892
control_flow_connections:
- component_type: ControlFlowEdge
id: 2bcc26b9-208f-47ee-81ff-87069794b06a
name: c1
description: null
metadata: {}
from_node:
$component_ref: b3a7dcd4-0c27-4d3e-9c24-6abcf80ede14
from_branch: null
to_node:
$component_ref: 126d5e3d-b214-48e1-8bca-ab5c0b518892
- component_type: ControlFlowEdge
id: 59e0f356-3a09-4859-be30-dd204c42fdfd
name: c2
description: null
metadata: {}
from_node:
$component_ref: 126d5e3d-b214-48e1-8bca-ab5c0b518892
from_branch: null
to_node:
$component_ref: 5d530823-b8a1-4c19-9221-d95b6b12f7ff
data_flow_connections:
- component_type: DataFlowEdge
id: c6a4b9ac-9a1f-43b0-883f-990f6d98f3f0
name: dout_items_on_sale
description: null
metadata: {}
source_node:
$component_ref: 126d5e3d-b214-48e1-8bca-ab5c0b518892
source_output: items_on_sale
destination_node:
$component_ref: 5d530823-b8a1-4c19-9221-d95b6b12f7ff
destination_input: items_on_sale
$referenced_components:
b3a7dcd4-0c27-4d3e-9c24-6abcf80ede14:
component_type: StartNode
id: b3a7dcd4-0c27-4d3e-9c24-6abcf80ede14
name: get_items_on_sale_steo_flow_start
description: null
metadata: {}
inputs: []
outputs: []
branches:
- next
126d5e3d-b214-48e1-8bca-ab5c0b518892:
component_type: ToolNode
id: 126d5e3d-b214-48e1-8bca-ab5c0b518892
name: get_items_on_sale_steo
description: null
metadata: {}
inputs: []
outputs:
- title: items_on_sale
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
branches:
- next
tool:
component_type: ServerTool
id: 5057a406-bf9c-400e-bfca-d88f32c8e840
name: get_items_on_sale
description: Retrieve the list of items currently on sale
metadata: {}
inputs: []
outputs:
- title: items_on_sale
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
5d530823-b8a1-4c19-9221-d95b6b12f7ff:
component_type: EndNode
id: 5d530823-b8a1-4c19-9221-d95b6b12f7ff
name: get_items_on_sale_steo_flow_start
description: null
metadata: {}
inputs:
- title: items_on_sale
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
outputs:
- title: items_on_sale
items:
additionalProperties:
type: string
properties: {}
type: object
type: array
branches: []
branch_name: next
42abbbdb-15c9-44f0-97f4-b6246ab5769e:
component_type: LlmNode
id: 42abbbdb-15c9-44f0-97f4-b6246ab5769e
name: prepare_marketing_message_node
description: null
metadata: {}
inputs:
- title: user_info
type: string
- title: current_time
type: string
- title: items_on_sale
type: string
- title: user_purchases
type: string
outputs:
- description: Raw text generated by the LLM
title: generated_text
type: string
branches:
- next
llm_config:
component_type: VllmConfig
id: 0c85bb34-f57c-4aa4-8ec4-a4d4bb3b0bf5
name: vllm-llama-4-maverick
description: null
metadata: {}
default_generation_parameters: null
url: http://url.to.my.vllm.server/llama4mav
model_id: llama-4-maverick
prompt_template: "# Instructions\n\nYou are a marketing expert. You have to write\
\ a welcome message for a user.\n\nThe message must contain:\n- A first sentence\
\ of greetings, including user's name, and personalized in case it's user's\
\ birthday\n- A proposal containing something to buy\n\nThe purchase proposal\
\ must be:\n- aligned with user's purchase history\n- part of the list of items\
\ on sale\n\n# User information\n\n{{user_info}}\n\nNote that the current time\
\ to check the birthday is: {{current_time}}\n\nThe list of items purchased\
\ by the user is:\n{{user_purchases}}\n\n# Items on sale\n\n{{items_on_sale}}\n\
\nPlease write the welcome message for the user.\nDo not give me the instructions\
\ to do it, I want only the final message to send. \n"
b787c7ef-3825-45b4-9673-f4aa3d0fa3da:
component_type: OutputMessageNode
id: b787c7ef-3825-45b4-9673-f4aa3d0fa3da
name: output_message_node
description: null
metadata: {}
inputs:
- title: output
type: string
outputs: []
branches:
- next
message: '{{output}}'
af549944-223d-4040-847d-5144d0e2299e:
component_type: EndNode
id: af549944-223d-4040-847d-5144d0e2299e
name: end_node
description: null
metadata: {}
inputs: []
outputs: []
branches: []
branch_name: next
agentspec_version: 25.4.2
Recap#
This guide covered how to define tasks for parallel execution in Agent Spec.
Below is the complete code from this guide.
1from pyagentspec.property import DictProperty, ListProperty, StringProperty
2from pyagentspec.tools import ServerTool
3
4username_property = StringProperty(title="username")
5user_info_property = DictProperty(title="user_info", value_type=StringProperty())
6get_user_information_tool = ServerTool(
7 name="get_user_information",
8 description="Retrieve information about a user",
9 inputs=[username_property],
10 outputs=[user_info_property],
11)
12
13current_time_property = StringProperty(title="current_time")
14get_current_time_tool = ServerTool(
15 name="get_current_time",
16 description="Return current time",
17 inputs=[],
18 outputs=[current_time_property],
19)
20
21user_purchases_property = ListProperty(title="user_purchases", item_type=DictProperty(value_type=StringProperty()))
22get_user_last_purchases_tool = ServerTool(
23 name="get_user_last_purchases",
24 description="Retrieve the list of purchases made by a user",
25 inputs=[username_property],
26 outputs=[user_purchases_property],
27)
28
29items_on_sale_property = ListProperty(title="items_on_sale", item_type=DictProperty(value_type=StringProperty()))
30get_items_on_sale_tool = ServerTool(
31 name="get_items_on_sale",
32 description="Retrieve the list of items currently on sale",
33 inputs=[],
34 outputs=[items_on_sale_property],
35)
36
37
38from pyagentspec.flows.flow import Flow
39from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge
40from pyagentspec.flows.node import Node
41from pyagentspec.flows.nodes import ParallelFlowNode, ToolNode, StartNode, EndNode
42
43def create_one_node_flow(node: Node) -> Flow:
44 """Create a flow that wraps the given node, having the same inputs and outputs"""
45 flow_name = node.name + "_flow"
46 start_node = StartNode(name=flow_name + "_start", inputs=node.inputs)
47 end_node = EndNode(name=flow_name + "_start", outputs=node.outputs)
48 return Flow(
49 name=flow_name,
50 start_node=start_node,
51 nodes=[start_node, end_node, node],
52 control_flow_connections=[
53 ControlFlowEdge(name="c1", from_node=start_node, to_node=node),
54 ControlFlowEdge(name="c2", from_node=node, to_node=end_node),
55 ],
56 data_flow_connections=[
57 DataFlowEdge(
58 name=f"din_{input_property.title}",
59 source_node=start_node, source_output=input_property.title,
60 destination_node=node, destination_input=input_property.title,
61 )
62 for input_property in node.inputs
63 ] + [
64 DataFlowEdge(
65 name=f"dout_{output_property.title}",
66 source_node=node, source_output=output_property.title,
67 destination_node=end_node, destination_input=output_property.title,
68 )
69 for output_property in node.outputs
70 ]
71 )
72
73get_current_time_flow = create_one_node_flow(
74 ToolNode(name="get_current_time_step", tool=get_current_time_tool)
75)
76get_user_information_flow = create_one_node_flow(
77 ToolNode(name="get_user_information_step", tool=get_user_information_tool)
78)
79get_user_last_purchases_flow = create_one_node_flow(
80 ToolNode(name="get_user_last_purchases_step", tool=get_user_last_purchases_tool)
81)
82get_items_on_sale_flow = create_one_node_flow(
83 ToolNode(name="get_items_on_sale_steo", tool=get_items_on_sale_tool)
84)
85
86parallel_flow_node = ParallelFlowNode(
87 name="parallel_flow_node",
88 subflows=[
89 get_current_time_flow,
90 get_user_information_flow,
91 get_user_last_purchases_flow,
92 get_items_on_sale_flow,
93 ],
94)
95
96
97from pyagentspec.llms import VllmConfig
98from pyagentspec.flows.nodes import OutputMessageNode, LlmNode
99
100llm_config = VllmConfig(
101 name="vllm-llama-4-maverick",
102 model_id="llama-4-maverick",
103 url="http://url.to.my.vllm.server/llama4mav",
104)
105
106prompt = """# Instructions
107
108You are a marketing expert. You have to write a welcome message for a user.
109
110The message must contain:
111- A first sentence of greetings, including user's name, and personalized in case it's user's birthday
112- A proposal containing something to buy
113
114The purchase proposal must be:
115- aligned with user's purchase history
116- part of the list of items on sale
117
118# User information
119
120{{user_info}}
121
122Note that the current time to check the birthday is: {{current_time}}
123
124The list of items purchased by the user is:
125{{user_purchases}}
126
127# Items on sale
128
129{{items_on_sale}}
130
131Please write the welcome message for the user.
132Do not give me the instructions to do it, I want only the final message to send.
133"""
134
135prepare_marketing_message_node = LlmNode(
136 name="prepare_marketing_message_node", prompt_template=prompt, llm_config=llm_config
137)
138output_message_node = OutputMessageNode(name="output_message_node", message="{{output}}")
139
140
141from pyagentspec.flows.flow import Flow
142
143start_node = StartNode(name="start_node", inputs=[username_property])
144end_node = EndNode(name="end_node")
145flow = Flow(
146 name="marketing_message_flow",
147 start_node=start_node,
148 nodes=[parallel_flow_node, prepare_marketing_message_node, output_message_node, start_node, end_node],
149 control_flow_connections=[
150 ControlFlowEdge(name="cfe1", from_node=start_node, to_node=parallel_flow_node),
151 ControlFlowEdge(name="cfe2", from_node=parallel_flow_node, to_node=prepare_marketing_message_node),
152 ControlFlowEdge(name="cfe3", from_node=prepare_marketing_message_node, to_node=output_message_node),
153 ControlFlowEdge(name="cfe4", from_node=output_message_node, to_node=end_node),
154 ],
155 data_flow_connections=[
156 DataFlowEdge(
157 name="dfe_username",
158 source_node=start_node, source_output="username",
159 destination_node=parallel_flow_node, destination_input="username",
160 )
161 ] + [
162 DataFlowEdge(
163 name="dfe_" + property_.title,
164 source_node=parallel_flow_node, source_output=property_.title,
165 destination_node=prepare_marketing_message_node, destination_input=property_.title,
166 )
167 for property_ in [current_time_property, user_info_property, user_purchases_property, items_on_sale_property]
168 ]
169)
170
171from pyagentspec.serialization import AgentSpecSerializer
172
173serialized_flow = AgentSpecSerializer().to_json(flow)
Next steps#
Having learned how to perform generic parallel operations in Agent Spec, you may now proceed to How to Do Map and Reduce Operations in Flows.