How to Connect Assistants to Your Data#
Agents rely on access to relevant data to function effectively. Without a steady stream of high-quality data, AI models are unable to learn, reason, or make informed decisions. Connecting an Agent or Flow to data sources is therefore a critical step in developing functional AI systems. This connection enables agents to perceive their environment, update their knowledge or the underlying data source, and adapt to changing conditions.
In this tutorial, you will:
Define Entities that an Agent or Flow can access and manipulate.
Populate a Datastore with entities for development and testing.
Use Datastores in Flows and Agents to create two types of inventory management assistants.
To ensure reproducibility of this tutorial, you will use an in-memory data source.
Concepts shown in this guide#
Entities to model data
Datastore and InMemoryDatastore to manipulate collections of data
Steps to use datastores in Agents and Flows (DatastoreListStep, DatastoreCreateStep, DatastoreUpdateStep, DatastoreDeleteStep)
Note
The InMemoryDatastore is mainly suitable for testing and development, or other use-cases where data persistence across assistants and conversations is not a requirement. For production use-cases, the OracleDatabaseDatastore provides a robust and scalable persistence layer in Oracle Database.
Note that there are a few key differences between an in-memory and a database Datastore
:
- With database Datastores, all tables relevant to the assistant must already be created in the database prior to connecting to it.
- You may choose to only model a subset of the tables available in the database via the Entity construct.
- Database Datastores offer an additional query
method (and the corresponding DatastoreQueryStep),
that enables flexible execution of SQL queries that cannot be modelled by the list
operation on the in-memory datastore
Datastores in Flows#
In this section, you will build a simple Flow that performs operations on an inventory database based on user input. This Flow helps users keep product descriptions up to date by leveraging an LLM for the creative writing component.
Step 1. Add imports and LLM configuration#
Import the required packages:
1from textwrap import dedent
2
3from wayflowcore.controlconnection import ControlFlowEdge
4from wayflowcore.dataconnection import DataFlowEdge
5from wayflowcore.datastore import Entity, InMemoryDatastore
6from wayflowcore.datastore.entity import nullable
7from wayflowcore.flow import Flow
8from wayflowcore.property import (
9 AnyProperty,
10 DictProperty,
11 FloatProperty,
12 IntegerProperty,
13 ObjectProperty,
14 StringProperty,
15)
16from wayflowcore.steps import InputMessageStep, OutputMessageStep, PromptExecutionStep
17from wayflowcore.steps.datastoresteps import (
18 DatastoreCreateStep,
19 DatastoreDeleteStep,
20 DatastoreListStep,
21 DatastoreUpdateStep,
22)
In this assistant, you need to use an LLM. WayFlow supports several LLM API providers. Select an LLM from the options below:
from wayflowcore.models import OCIGenAIModel
if __name__ == "__main__":
llm = OCIGenAIModel(
model_id="provider.model-id",
service_endpoint="https://url-to-service-endpoint.com",
compartment_id="compartment-id",
auth_type="API_KEY",
)
from wayflowcore.models import VllmModel
llm = VllmModel(
model_id="model-id",
host_port="VLLM_HOST_PORT",
)
from wayflowcore.models import OllamaModel
llm = OllamaModel(
model_id="model-id",
)
Important
API keys should not be stored anywhere in the code. Use environment variables and/or tools such as python-dotenv.
Step 2. Define data#
Start by defining the schema for your data using the Entity construct. In this example, you will manage products in an inventory, so a single collection is sufficient. Datastores also support managing multiple collections at the same time if needed.
1product = Entity(
2 properties={
3 "ID": IntegerProperty(description="Unique product identifier"),
4 # Descriptions can be helpful if an LLM needs to fill these fields,
5 # or generally disambiguate non-obvious property names
6 "title": StringProperty(description="Brief summary of the product"),
7 "description": StringProperty(),
8 "price": FloatProperty(default_value=0.1),
9 # Use nullable to define optional properties
10 "category": nullable(StringProperty()),
11 },
12)
Next, create an InMemoryDataStore. For simplicity, you will use dummy data:
1datastore = InMemoryDatastore(schema={"products": product})
2
3dummy_data = [
4 {
5 "ID": 0,
6 "title": "Broccoli",
7 "description": "Healty and delicious cruciferous vegetable!",
8 "price": 1.5,
9 "category": "Produce",
10 },
11 {
12 "ID": 1,
13 "title": "Oranges",
14 "description": "Vitamin C-filled citrus fruits",
15 "price": 1.8,
16 "category": "Produce",
17 },
18 {
19 "ID": 2,
20 "title": "Shampoo",
21 "description": "Shiny smooth hair in just 10 applications!",
22 "price": 4.5,
23 "category": "Personal hygene",
24 },
25 {
26 "ID": 3,
27 "title": "Crushed ice",
28 "description": "Cool any drink in seconds!",
29 "price": 4.5,
30 },
31]
32
33# Create supports both bulk-creation, as well as single element creation
34datastore.create(collection_name="products", entities=dummy_data[:-1])
35datastore.create(collection_name="products", entities=dummy_data[-1])
Step 3. Create datastore steps#
Now that the Datastore is set up, create steps to perform different operations in the flow. In this case, the assistant only needs to retrieve the current description of products and update it. See the list of all available Datastore steps for more details.
1datastore_list_step = DatastoreListStep(
2 datastore,
3 name="product_list_step",
4 collection_name="products",
5 where={"title": "{{user_requested_product}}"},
6 limit=1,
7 unpack_single_entity_from_list=True,
8)
9
10datastore_update_step = DatastoreUpdateStep(
11 datastore,
12 name="product_update_step",
13 collection_name="products",
14 where={"title": "{{user_requested_product}}"}
15)
Key points:
Use
where
to filter which product to list and update. Configure it with a variable so that the user can dynamically choose the product title.In the
DatastoreListStep
,limit
andunpack_single_entity_from_list
are used to assume that product titles are unique, making the output concise and easy to handle.
The input to the DatastoreListStep
is the title of the product to retrieve, and the output is a single object containing the corresponding product data.
The input to the DatastoreUpdateStep
includes both the title of the product to update and the updates to apply, in the form of a dictionary containing the properties and the corresponding values.
The output will be the new properties that were updated.
Step 4. Create the Flow#
Now define the Flow for this assistant.
After the user enters which product they want to update, and how the description should be updated, the datastore is queried to find the matching product. The LLM is prompted with the product details and the user’s instructions. The output is used to update the data, and the new result is returned back to the user.
Click to see the rest of the code
1# We create the steps needed by our flow
2USER_INPUT_STEP = "user_product_input_step"
3USER_TASK_INPUT_STEP = "user_task_input_step"
4LLM_REWRITE_STEP = "llm_rewrite_step"
5USER_OUTPUT_STEP = "user_output_step"
6
7user_input_message_template = dedent(
8 """I am an inventory Assistant, designed to help you keep product descriptions up-to-date.
9 What product would you like to update? Please provide its title.
10 """
11)
12
13user_task_message_template = "How would you like to update the description? I will help you rewrite it according to your instructions"
14
15rewrite_description_prompt_template = dedent(
16 """You are an inventory assistant.
17
18 Your task:
19 - Based on the product details given below, rewrite the description according to the user's request
20 Important:
21 - Be helpful and concise in your messages
22 - Only provide the new description as an output, and nothing else
23
24 Here is the User's request:
25 - {{ user_request }}
26
27 Here is the product description:
28 - {{ product }}
29 """
30)
31
32user_input_step = InputMessageStep(
33 name=USER_INPUT_STEP,
34 message_template=user_input_message_template,
35)
36
37user_task_input_step = InputMessageStep(
38 name=USER_TASK_INPUT_STEP,
39 message_template=user_task_message_template,
40)
41
42llm_rewrite_step = PromptExecutionStep(
43 name=LLM_REWRITE_STEP,
44 prompt_template=rewrite_description_prompt_template,
45 llm=llm,
46 input_descriptors=[
47 DictProperty("product", key_type=StringProperty(), value_type=AnyProperty())
48 ],
49 output_descriptors=[
50 ObjectProperty(
51 name=PromptExecutionStep.OUTPUT, properties={"description": StringProperty()}
52 )
53 ],
54)
55
56user_output_step = OutputMessageStep(
57 name=USER_OUTPUT_STEP,
58 message_template="The product has been updated with the following description: {{ answer['description'] }}",
59)
60
61assistant = Flow(
62 begin_step=user_input_step,
63 control_flow_edges=[
64 ControlFlowEdge(source_step=user_input_step, destination_step=user_task_input_step),
65 ControlFlowEdge(source_step=user_task_input_step, destination_step=datastore_list_step),
66 ControlFlowEdge(source_step=datastore_list_step, destination_step=llm_rewrite_step),
67 ControlFlowEdge(source_step=llm_rewrite_step, destination_step=datastore_update_step),
68 ControlFlowEdge(source_step=datastore_update_step, destination_step=user_output_step),
69 ControlFlowEdge(source_step=user_output_step, destination_step=None),
70 ],
71 data_flow_edges=[
72 # The first title given by the user is mapped to the datastore steps for listing and updating
73 DataFlowEdge(
74 user_input_step,
75 InputMessageStep.USER_PROVIDED_INPUT,
76 datastore_list_step,
77 "user_requested_product",
78 ),
79 DataFlowEdge(
80 user_input_step,
81 InputMessageStep.USER_PROVIDED_INPUT,
82 datastore_update_step,
83 "user_requested_product",
84 ),
85 # The task and product detail are given to the LLM in the prompt execution step
86 DataFlowEdge(
87 user_task_input_step,
88 InputMessageStep.USER_PROVIDED_INPUT,
89 llm_rewrite_step,
90 "user_request",
91 ),
92 DataFlowEdge(datastore_list_step, DatastoreListStep.ENTITIES, llm_rewrite_step, "product"),
93 # The generated update is applied on the datastore, and echoed back to the user
94 DataFlowEdge(
95 llm_rewrite_step,
96 PromptExecutionStep.OUTPUT,
97 datastore_update_step,
98 DatastoreUpdateStep.UPDATE,
99 ),
100 DataFlowEdge(llm_rewrite_step, PromptExecutionStep.OUTPUT, user_output_step, "answer"),
101 ],
102)
Note the use of structured generation in the PromptExecutionStep
(via the output_descriptors
parameter).
This ensures that the LLM generates exactly the structure expected by the DatastoreUpdateStep
.
Finally, verify that the Flow works:
1conversation = assistant.start_conversation()
2conversation.execute()
3conversation.append_user_message("Broccoli")
4
5conversation.execute()
6conversation.append_user_message(
7 "Shoppers don't know what 'cruciferous' means, we should find a catchier description."
8)
9
10conversation.execute()
11print(conversation.get_last_message().content)
Datastores in Agents#
This section assumes you have completed the previous steps on using datastores in Flows.
The Flow you built earlier is quite helpful and reliable because it performs a single, specialized task.
Next, you will see how to define an Agent for inventory management when the task is not defined in advance.
This Agent will be able to interpret the user’s requests and autonomously decide which actions on the Datastore
are required to fulfill each task.
Step 1. Add imports and LLM configuration#
Add the additional imports needed to use Agents:
1from wayflowcore.agent import Agent
Step 2. Create Datastore Flows for an Agent#
To use the Datastore
in an agent, create flows for the different operations you want the agent to perform.
In the simplest setup, you can define one flow per basic Datastore
operation.
The agent will then determine the correct sequence of actions to achieve the user’s goal.
Define flows for:
1AGENT_PROMPT = dedent(
2 """
3 You are an inventory assistant. Your task is to help the user with their requests by using the available tools.
4 If you are unsure about the action to take, or you don't have the right tool, simply tell the user so and follow their guidance.
5 """
6)
7
8create_product_flow = Flow.from_steps(
9 [DatastoreCreateStep(datastore, "products")],
10 name="Create product",
11 description="Creates a new product in the data source",
12)
13list_products_flow = Flow.from_steps(
14 [DatastoreListStep(datastore, "products")],
15 name="List all products",
16 description="Lists all products in the data source.",
17)
18list_one_product_flow = Flow.from_steps(
19 [datastore_list_step],
20 name="List single product",
21 description="Lists a single product in the data source by its title.",
22)
23update_product_flow = Flow.from_steps(
24 [datastore_update_step],
25 name="Update product",
26 description="Updates a product in the data source by its title.",
27)
28delete_product_flow = Flow.from_steps(
29 [DatastoreDeleteStep(datastore, "products", where={"title": "{{product_title}}"})],
30 name="Delete product",
31 description="Delete a product in the data source by its title.",
32)
Notice the provided descriptions for the flows to help the agent understand the objective of each operation.
Additionally, you can incorporate more complex behaviors into these flows. For example, you could ask for user confirmation before deleting entities, or you could provide the user with an overview, and an editing option of the updates made by the agent before they are applied.
Step 3. Create the Agent#
Finally, create the inventory management agent by combining the LLM, the datastore flows, and a custom instruction:
1AGENT_PROMPT = dedent(
2 """
3 You are an inventory assistant. Your task is to help the user with their requests by using the available tools.
4 If you are unsure about the action to take, or you don't have the right tool, simply tell the user so and follow their guidance.
5 """
6)
7
8create_product_flow = Flow.from_steps(
9 [DatastoreCreateStep(datastore, "products")],
10 name="Create product",
11 description="Creates a new product in the data source",
12)
13list_products_flow = Flow.from_steps(
14 [DatastoreListStep(datastore, "products")],
15 name="List all products",
16 description="Lists all products in the data source.",
17)
18list_one_product_flow = Flow.from_steps(
19 [datastore_list_step],
20 name="List single product",
21 description="Lists a single product in the data source by its title.",
22)
23update_product_flow = Flow.from_steps(
24 [datastore_update_step],
25 name="Update product",
26 description="Updates a product in the data source by its title.",
27)
28delete_product_flow = Flow.from_steps(
29 [DatastoreDeleteStep(datastore, "products", where={"title": "{{product_title}}"})],
30 name="Delete product",
31 description="Delete a product in the data source by its title.",
32)
This agent can now respond to the user and perform actions on the data on their behalf.
Refer to the WayFlow Agents Tutorial to see how to run this Agent.
Agent Spec Exporting/Loading#
You can export the assistant configuration to its Agent Spec configuration using the AgentSpecExporter
.
from wayflowcore.agentspec import AgentSpecExporter
serialized_agent = AgentSpecExporter().to_json(agent)
Here is what the Agent Spec representation will look like ↓
Click here to see the assistant configuration.
{
"component_type": "ExtendedAgent",
"id": "99f1d854-0f10-473a-ad2a-3558b8977244",
"name": "agent_d18c1f13__auto",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [],
"outputs": [],
"llm_config": {
"component_type": "VllmConfig",
"id": "b10b47da-03bc-4bb3-a024-b2d8330a5be8",
"name": "LLAMA_MODEL_ID",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"default_generation_parameters": null,
"url": "LLAMA_API_URL",
"model_id": "LLAMA_MODEL_ID"
},
"system_prompt": "\nYou are an inventory assistant. Your task is to help the user with their requests by using the available tools.\nIf you are unsure about the action to take, or you don't have the right tool, simply tell the user so and follow their guidance.\n",
"tools": [],
"toolboxes": [],
"context_providers": null,
"can_finish_conversation": false,
"max_iterations": 10,
"initial_message": "Hi! How can I help you?",
"caller_input_mode": "always",
"agents": [],
"flows": [
{
"component_type": "Flow",
"id": "96d3782c-552c-429c-bd7e-4f4af61ff713",
"name": "Create product",
"description": "Creates a new product in the data source",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entity"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "created_entity"
}
],
"start_node": {
"$component_ref": "79b6331a-5543-4310-8d8b-1d9f1337b025"
},
"nodes": [
{
"$component_ref": "331ca41a-8738-4751-a87e-5cc48b8a3e23"
},
{
"$component_ref": "79b6331a-5543-4310-8d8b-1d9f1337b025"
},
{
"$component_ref": "ae2f0460-cba8-499e-a993-62b946e56d40"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "fe4ef560-e504-4dc8-a298-7dbb3c067a6f",
"name": "__StartStep___to_step_0_control_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"from_node": {
"$component_ref": "79b6331a-5543-4310-8d8b-1d9f1337b025"
},
"from_branch": null,
"to_node": {
"$component_ref": "331ca41a-8738-4751-a87e-5cc48b8a3e23"
}
},
{
"component_type": "ControlFlowEdge",
"id": "a16d091c-0d0c-4d29-9104-7761bdbb4cd3",
"name": "step_0_to_None End node_control_flow_edge",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "331ca41a-8738-4751-a87e-5cc48b8a3e23"
},
"from_branch": null,
"to_node": {
"$component_ref": "ae2f0460-cba8-499e-a993-62b946e56d40"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "58dbd841-e0a5-4c87-ac0c-08a34625323b",
"name": "__StartStep___entity_to_step_0_entity_data_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"source_node": {
"$component_ref": "79b6331a-5543-4310-8d8b-1d9f1337b025"
},
"source_output": "entity",
"destination_node": {
"$component_ref": "331ca41a-8738-4751-a87e-5cc48b8a3e23"
},
"destination_input": "entity"
},
{
"component_type": "DataFlowEdge",
"id": "92415266-d5a4-40ca-b8e6-57e01ec002a5",
"name": "step_0_created_entity_to_None End node_created_entity_data_flow_edge",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "331ca41a-8738-4751-a87e-5cc48b8a3e23"
},
"source_output": "created_entity",
"destination_node": {
"$component_ref": "ae2f0460-cba8-499e-a993-62b946e56d40"
},
"destination_input": "created_entity"
}
],
"$referenced_components": {
"331ca41a-8738-4751-a87e-5cc48b8a3e23": {
"component_type": "PluginDatastoreCreateNode",
"id": "331ca41a-8738-4751-a87e-5cc48b8a3e23",
"name": "step_0",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entity"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "created_entity"
}
],
"branches": [
"next"
],
"input_mapping": {},
"output_mapping": {},
"datastore": {
"$component_ref": "4f8e1008-2f20-456c-9250-679146e88192"
},
"collection_name": "products",
"ENTITY": "entity",
"CREATED_ENTITY": "created_entity",
"component_plugin_name": "DatastorePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"79b6331a-5543-4310-8d8b-1d9f1337b025": {
"component_type": "StartNode",
"id": "79b6331a-5543-4310-8d8b-1d9f1337b025",
"name": "__StartStep__",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entity"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entity"
}
],
"branches": [
"next"
]
},
"ae2f0460-cba8-499e-a993-62b946e56d40": {
"component_type": "EndNode",
"id": "ae2f0460-cba8-499e-a993-62b946e56d40",
"name": "None End node",
"description": "End node representing all transitions to None in the WayFlow flow",
"metadata": {},
"inputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "created_entity"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "created_entity"
}
],
"branches": [],
"branch_name": "next"
}
}
},
{
"component_type": "Flow",
"id": "ba1cd504-bef6-4af3-9498-cbf6e50a0bca",
"name": "List all products",
"description": "Lists all products in the data source.",
"metadata": {
"__metadata_info__": {}
},
"inputs": [],
"outputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"start_node": {
"$component_ref": "bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff"
},
"nodes": [
{
"$component_ref": "0c924103-23f5-4698-b69e-c553250186ab"
},
{
"$component_ref": "bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff"
},
{
"$component_ref": "098f2832-4672-44eb-a060-ea9514ceefc5"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "a0392cfe-bed3-44cb-84c0-20a30f1cbe18",
"name": "__StartStep___to_step_0_control_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"from_node": {
"$component_ref": "bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff"
},
"from_branch": null,
"to_node": {
"$component_ref": "0c924103-23f5-4698-b69e-c553250186ab"
}
},
{
"component_type": "ControlFlowEdge",
"id": "3290795e-59ca-46f8-8a96-5a265d707c13",
"name": "step_0_to_None End node_control_flow_edge",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "0c924103-23f5-4698-b69e-c553250186ab"
},
"from_branch": null,
"to_node": {
"$component_ref": "098f2832-4672-44eb-a060-ea9514ceefc5"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "308b92b6-70f4-4e9c-b41e-1563bc449a24",
"name": "step_0_entities_to_None End node_entities_data_flow_edge",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "0c924103-23f5-4698-b69e-c553250186ab"
},
"source_output": "entities",
"destination_node": {
"$component_ref": "098f2832-4672-44eb-a060-ea9514ceefc5"
},
"destination_input": "entities"
}
],
"$referenced_components": {
"098f2832-4672-44eb-a060-ea9514ceefc5": {
"component_type": "EndNode",
"id": "098f2832-4672-44eb-a060-ea9514ceefc5",
"name": "None End node",
"description": "End node representing all transitions to None in the WayFlow flow",
"metadata": {},
"inputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"outputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"branches": [],
"branch_name": "next"
},
"0c924103-23f5-4698-b69e-c553250186ab": {
"component_type": "PluginDatastoreListNode",
"id": "0c924103-23f5-4698-b69e-c553250186ab",
"name": "step_0",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [],
"outputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"branches": [
"next"
],
"input_mapping": {},
"output_mapping": {},
"datastore": {
"$component_ref": "4f8e1008-2f20-456c-9250-679146e88192"
},
"collection_name": "products",
"where": null,
"limit": null,
"unpack_single_entity_from_list": false,
"ENTITIES": "entities",
"component_plugin_name": "DatastorePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff": {
"component_type": "StartNode",
"id": "bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff",
"name": "__StartStep__",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [],
"outputs": [],
"branches": [
"next"
]
}
}
},
{
"component_type": "Flow",
"id": "bad00138-48b3-4e7c-84a9-51bd385a38a2",
"name": "List single product",
"description": "Lists a single product in the data source by its title.",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entities"
}
],
"start_node": {
"$component_ref": "76d19c9a-241f-4a4d-bbac-2bcbd3359498"
},
"nodes": [
{
"$component_ref": "d1b1f436-b91f-435c-867c-ecf9b5b187a1"
},
{
"$component_ref": "76d19c9a-241f-4a4d-bbac-2bcbd3359498"
},
{
"$component_ref": "aa8090d6-2220-40ad-ab16-6adb1bdead7b"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "e37ae190-e7f6-4090-8091-c5eddadf7a9d",
"name": "__StartStep___to_product_list_step_control_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"from_node": {
"$component_ref": "76d19c9a-241f-4a4d-bbac-2bcbd3359498"
},
"from_branch": null,
"to_node": {
"$component_ref": "d1b1f436-b91f-435c-867c-ecf9b5b187a1"
}
},
{
"component_type": "ControlFlowEdge",
"id": "80680849-e51b-435d-aee6-cdb7e6571ee7",
"name": "product_list_step_to_None End node_control_flow_edge",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "d1b1f436-b91f-435c-867c-ecf9b5b187a1"
},
"from_branch": null,
"to_node": {
"$component_ref": "aa8090d6-2220-40ad-ab16-6adb1bdead7b"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "dab6eb95-057c-4adc-85dd-2a40e14713eb",
"name": "__StartStep___user_requested_product_to_product_list_step_user_requested_product_data_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"source_node": {
"$component_ref": "76d19c9a-241f-4a4d-bbac-2bcbd3359498"
},
"source_output": "user_requested_product",
"destination_node": {
"$component_ref": "d1b1f436-b91f-435c-867c-ecf9b5b187a1"
},
"destination_input": "user_requested_product"
},
{
"component_type": "DataFlowEdge",
"id": "82d0a256-6c3d-45a8-a6bf-c1c949069927",
"name": "product_list_step_entities_to_None End node_entities_data_flow_edge",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "d1b1f436-b91f-435c-867c-ecf9b5b187a1"
},
"source_output": "entities",
"destination_node": {
"$component_ref": "aa8090d6-2220-40ad-ab16-6adb1bdead7b"
},
"destination_input": "entities"
}
],
"$referenced_components": {
"d1b1f436-b91f-435c-867c-ecf9b5b187a1": {
"component_type": "PluginDatastoreListNode",
"id": "d1b1f436-b91f-435c-867c-ecf9b5b187a1",
"name": "product_list_step",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entities"
}
],
"branches": [
"next"
],
"input_mapping": {},
"output_mapping": {},
"datastore": {
"$component_ref": "4f8e1008-2f20-456c-9250-679146e88192"
},
"collection_name": "products",
"where": {
"title": "{{user_requested_product}}"
},
"limit": 1,
"unpack_single_entity_from_list": true,
"ENTITIES": "entities",
"component_plugin_name": "DatastorePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"76d19c9a-241f-4a4d-bbac-2bcbd3359498": {
"component_type": "StartNode",
"id": "76d19c9a-241f-4a4d-bbac-2bcbd3359498",
"name": "__StartStep__",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
}
],
"outputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
}
],
"branches": [
"next"
]
},
"aa8090d6-2220-40ad-ab16-6adb1bdead7b": {
"component_type": "EndNode",
"id": "aa8090d6-2220-40ad-ab16-6adb1bdead7b",
"name": "None End node",
"description": "End node representing all transitions to None in the WayFlow flow",
"metadata": {},
"inputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entities"
}
],
"outputs": [
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "entities"
}
],
"branches": [],
"branch_name": "next"
}
}
},
{
"component_type": "Flow",
"id": "a3047067-dea3-4cc9-a922-c26d35d97c48",
"name": "Update product",
"description": "Updates a product in the data source by its title.",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
},
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "update"
}
],
"outputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"start_node": {
"$component_ref": "8c74a4c5-fdf0-447e-956f-59498da1dc09"
},
"nodes": [
{
"$component_ref": "487a708b-0553-4bb5-b015-948d2a97ede6"
},
{
"$component_ref": "8c74a4c5-fdf0-447e-956f-59498da1dc09"
},
{
"$component_ref": "9074c861-1cf4-4bd9-88dd-3fe209b2c218"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "64436400-797d-4d35-92df-78fc557006f2",
"name": "__StartStep___to_product_update_step_control_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"from_node": {
"$component_ref": "8c74a4c5-fdf0-447e-956f-59498da1dc09"
},
"from_branch": null,
"to_node": {
"$component_ref": "487a708b-0553-4bb5-b015-948d2a97ede6"
}
},
{
"component_type": "ControlFlowEdge",
"id": "5e55b5d7-7bf8-435a-9044-f05f1b377671",
"name": "product_update_step_to_None End node_control_flow_edge",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "487a708b-0553-4bb5-b015-948d2a97ede6"
},
"from_branch": null,
"to_node": {
"$component_ref": "9074c861-1cf4-4bd9-88dd-3fe209b2c218"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "43c29773-0a4b-4145-9c0d-ad5238410e9d",
"name": "__StartStep___user_requested_product_to_product_update_step_user_requested_product_data_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"source_node": {
"$component_ref": "8c74a4c5-fdf0-447e-956f-59498da1dc09"
},
"source_output": "user_requested_product",
"destination_node": {
"$component_ref": "487a708b-0553-4bb5-b015-948d2a97ede6"
},
"destination_input": "user_requested_product"
},
{
"component_type": "DataFlowEdge",
"id": "8e5f0ea8-8ea1-42ba-bdba-95a74082c908",
"name": "__StartStep___update_to_product_update_step_update_data_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"source_node": {
"$component_ref": "8c74a4c5-fdf0-447e-956f-59498da1dc09"
},
"source_output": "update",
"destination_node": {
"$component_ref": "487a708b-0553-4bb5-b015-948d2a97ede6"
},
"destination_input": "update"
},
{
"component_type": "DataFlowEdge",
"id": "1bd34870-1e52-4896-bfaf-5a71006da687",
"name": "product_update_step_entities_to_None End node_entities_data_flow_edge",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "487a708b-0553-4bb5-b015-948d2a97ede6"
},
"source_output": "entities",
"destination_node": {
"$component_ref": "9074c861-1cf4-4bd9-88dd-3fe209b2c218"
},
"destination_input": "entities"
}
],
"$referenced_components": {
"487a708b-0553-4bb5-b015-948d2a97ede6": {
"component_type": "PluginDatastoreUpdateNode",
"id": "487a708b-0553-4bb5-b015-948d2a97ede6",
"name": "product_update_step",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
},
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "update"
}
],
"outputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"branches": [
"next"
],
"input_mapping": {},
"output_mapping": {},
"datastore": {
"$component_ref": "4f8e1008-2f20-456c-9250-679146e88192"
},
"collection_name": "products",
"where": {
"title": "{{user_requested_product}}"
},
"ENTITIES": "entities",
"UPDATE": "update",
"component_plugin_name": "DatastorePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"8c74a4c5-fdf0-447e-956f-59498da1dc09": {
"component_type": "StartNode",
"id": "8c74a4c5-fdf0-447e-956f-59498da1dc09",
"name": "__StartStep__",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
},
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "update"
}
],
"outputs": [
{
"description": "\"user_requested_product\" input variable for the template",
"type": "string",
"title": "user_requested_product"
},
{
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
},
"title": "update"
}
],
"branches": [
"next"
]
},
"9074c861-1cf4-4bd9-88dd-3fe209b2c218": {
"component_type": "EndNode",
"id": "9074c861-1cf4-4bd9-88dd-3fe209b2c218",
"name": "None End node",
"description": "End node representing all transitions to None in the WayFlow flow",
"metadata": {},
"inputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"outputs": [
{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {},
"key_type": {
"type": "string"
}
},
"title": "entities"
}
],
"branches": [],
"branch_name": "next"
}
}
},
{
"component_type": "Flow",
"id": "ebae9461-df3a-4544-9cfd-dd2a2e13e34e",
"name": "Delete product",
"description": "Delete a product in the data source by its title.",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"product_title\" input variable for the template",
"type": "string",
"title": "product_title"
}
],
"outputs": [],
"start_node": {
"$component_ref": "13d561e4-1c49-4808-974c-d82311479998"
},
"nodes": [
{
"$component_ref": "9cd4c282-5290-477d-b9c1-f069a599aa68"
},
{
"$component_ref": "13d561e4-1c49-4808-974c-d82311479998"
},
{
"$component_ref": "49384f2b-1825-4c6b-a876-86e8803b0014"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "7b91ecf7-f24e-4ff3-8df4-f6769847e7a4",
"name": "__StartStep___to_step_0_control_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"from_node": {
"$component_ref": "13d561e4-1c49-4808-974c-d82311479998"
},
"from_branch": null,
"to_node": {
"$component_ref": "9cd4c282-5290-477d-b9c1-f069a599aa68"
}
},
{
"component_type": "ControlFlowEdge",
"id": "e666dfe3-6041-4141-b21b-afedfa74f3ab",
"name": "step_0_to_None End node_control_flow_edge",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "9cd4c282-5290-477d-b9c1-f069a599aa68"
},
"from_branch": null,
"to_node": {
"$component_ref": "49384f2b-1825-4c6b-a876-86e8803b0014"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "a731fb73-ad3b-4a22-9f0b-35e9f1d63131",
"name": "__StartStep___product_title_to_step_0_product_title_data_flow_edge",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"source_node": {
"$component_ref": "13d561e4-1c49-4808-974c-d82311479998"
},
"source_output": "product_title",
"destination_node": {
"$component_ref": "9cd4c282-5290-477d-b9c1-f069a599aa68"
},
"destination_input": "product_title"
}
],
"$referenced_components": {
"9cd4c282-5290-477d-b9c1-f069a599aa68": {
"component_type": "PluginDatastoreDeleteNode",
"id": "9cd4c282-5290-477d-b9c1-f069a599aa68",
"name": "step_0",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"product_title\" input variable for the template",
"type": "string",
"title": "product_title"
}
],
"outputs": [],
"branches": [
"next"
],
"input_mapping": {},
"output_mapping": {},
"datastore": {
"$component_ref": "4f8e1008-2f20-456c-9250-679146e88192"
},
"collection_name": "products",
"where": {
"title": "{{product_title}}"
},
"component_plugin_name": "DatastorePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"13d561e4-1c49-4808-974c-d82311479998": {
"component_type": "StartNode",
"id": "13d561e4-1c49-4808-974c-d82311479998",
"name": "__StartStep__",
"description": "",
"metadata": {
"__metadata_info__": {}
},
"inputs": [
{
"description": "\"product_title\" input variable for the template",
"type": "string",
"title": "product_title"
}
],
"outputs": [
{
"description": "\"product_title\" input variable for the template",
"type": "string",
"title": "product_title"
}
],
"branches": [
"next"
]
},
"49384f2b-1825-4c6b-a876-86e8803b0014": {
"component_type": "EndNode",
"id": "49384f2b-1825-4c6b-a876-86e8803b0014",
"name": "None End node",
"description": "End node representing all transitions to None in the WayFlow flow",
"metadata": {},
"inputs": [],
"outputs": [],
"branches": [],
"branch_name": "next"
}
}
}
],
"agent_template": {
"component_type": "PluginPromptTemplate",
"id": "ea261004-a6d8-4380-af2a-4e5adbaf7b9c",
"name": "",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"messages": [
{
"role": "system",
"contents": [
{
"type": "text",
"content": "{%- if __TOOLS__ -%}\nEnvironment: ipython\nCutting Knowledge Date: December 2023\n\nYou are a helpful assistant with tool calling capabilities. Only reply with a tool call if the function exists in the library provided by the user. If it doesn't exist, just reply directly in natural language. When you receive a tool call response, use the output to format an answer to the original user question.\n\nYou have access to the following functions. To call a function, please respond with JSON for a function call.\nRespond in the format {\"name\": function name, \"parameters\": dictionary of argument name and its value}.\nDo not use variables.\n\n[{% for tool in __TOOLS__%}{{tool.to_openai_format() | tojson}}{{', ' if not loop.last}}{% endfor %}]\n{%- endif -%}\n"
}
],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T15:58:42.673848+00:00",
"time_updated": "2025-09-02T15:58:42.673852+00:00"
},
{
"role": "system",
"contents": [
{
"type": "text",
"content": "{%- if custom_instruction -%}Additional instructions:\n{{custom_instruction}}{%- endif -%}"
}
],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T15:58:42.673915+00:00",
"time_updated": "2025-09-02T15:58:42.673916+00:00"
},
{
"role": "user",
"contents": [],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T15:58:42.660189+00:00",
"time_updated": "2025-09-02T15:58:42.660446+00:00"
},
{
"role": "system",
"contents": [
{
"type": "text",
"content": "{% if __PLAN__ %}The current plan you should follow is the following: \n{{__PLAN__}}{% endif %}"
}
],
"tool_requests": null,
"tool_result": null,
"display_only": false,
"sender": null,
"recipients": [],
"time_created": "2025-09-02T15:58:42.673985+00:00",
"time_updated": "2025-09-02T15:58:42.673986+00:00"
}
],
"output_parser": {
"component_type": "PluginJsonToolOutputParser",
"id": "8d8b00f0-2c13-4e0f-894c-a46ad91eccbc",
"name": "jsontool_outputparser",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"tools": null,
"component_plugin_name": "OutputParserPlugin",
"component_plugin_version": "25.4.0.dev0"
},
"inputs": [
{
"description": "\"__TOOLS__\" input variable for the template",
"title": "__TOOLS__"
},
{
"description": "\"custom_instruction\" input variable for the template",
"type": "string",
"title": "custom_instruction"
},
{
"description": "\"__PLAN__\" input variable for the template",
"type": "string",
"title": "__PLAN__",
"default": ""
},
{
"type": "array",
"items": {},
"title": "__CHAT_HISTORY__"
}
],
"pre_rendering_transforms": null,
"post_rendering_transforms": [
{
"component_type": "PluginRemoveEmptyNonUserMessageTransform",
"id": "f964b648-4850-43ca-983b-6bf05ec6fe59",
"name": "removeemptynonusermessage_messagetransform",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"component_plugin_name": "MessageTransformPlugin",
"component_plugin_version": "25.4.0.dev0"
},
{
"component_type": "PluginCoalesceSystemMessagesTransform",
"id": "b0c702f1-14a8-4692-b746-490f3cc2a406",
"name": "coalescesystemmessage_messagetransform",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"component_plugin_name": "MessageTransformPlugin",
"component_plugin_version": "25.4.0.dev0"
},
{
"component_type": "PluginLlamaMergeToolRequestAndCallsTransform",
"id": "466f3fef-697b-4e2e-804b-cc9788186b0d",
"name": "llamamergetoolrequestandcalls_messagetransform",
"description": null,
"metadata": {
"__metadata_info__": {}
},
"component_plugin_name": "MessageTransformPlugin",
"component_plugin_version": "25.4.0.dev0"
}
],
"tools": null,
"native_tool_calling": false,
"response_format": null,
"native_structured_generation": true,
"generation_config": null,
"component_plugin_name": "PromptTemplatePlugin",
"component_plugin_version": "25.4.0.dev0"
},
"component_plugin_name": "AgentPlugin",
"component_plugin_version": "25.4.0.dev0",
"$referenced_components": {
"4f8e1008-2f20-456c-9250-679146e88192": {
"component_type": "PluginInMemoryDatastore",
"id": "4f8e1008-2f20-456c-9250-679146e88192",
"name": "PluginInMemoryDatastore",
"description": null,
"metadata": {},
"datastore_schema": {
"products": {
"description": "",
"title": "",
"properties": {
"description": {
"type": "string"
},
"ID": {
"description": "Unique product identifier",
"type": "integer"
},
"title": {
"description": "Brief summary of the product",
"type": "string"
},
"price": {
"type": "number",
"default": 0.1
},
"category": {
"anyOf": [
{
"type": "null"
},
{
"type": "string"
}
],
"default": null
}
}
}
},
"component_plugin_name": "DatastorePlugin",
"component_plugin_version": "25.4.0.dev0"
}
},
"agentspec_version": "25.4.1"
}
component_type: ExtendedAgent
id: 99f1d854-0f10-473a-ad2a-3558b8977244
name: agent_d18c1f13__auto
description: ''
metadata:
__metadata_info__: {}
inputs: []
outputs: []
llm_config:
component_type: VllmConfig
id: b10b47da-03bc-4bb3-a024-b2d8330a5be8
name: LLAMA_MODEL_ID
description: null
metadata:
__metadata_info__: {}
default_generation_parameters: null
url: LLAMA_API_URL
model_id: LLAMA_MODEL_ID
system_prompt: '
You are an inventory assistant. Your task is to help the user with their requests
by using the available tools.
If you are unsure about the action to take, or you don''t have the right tool, simply
tell the user so and follow their guidance.
'
tools: []
toolboxes: []
context_providers: null
can_finish_conversation: false
max_iterations: 10
initial_message: Hi! How can I help you?
caller_input_mode: always
agents: []
flows:
- component_type: Flow
id: 96d3782c-552c-429c-bd7e-4f4af61ff713
name: Create product
description: Creates a new product in the data source
metadata:
__metadata_info__: {}
inputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entity
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: created_entity
start_node:
$component_ref: 79b6331a-5543-4310-8d8b-1d9f1337b025
nodes:
- $component_ref: 331ca41a-8738-4751-a87e-5cc48b8a3e23
- $component_ref: 79b6331a-5543-4310-8d8b-1d9f1337b025
- $component_ref: ae2f0460-cba8-499e-a993-62b946e56d40
control_flow_connections:
- component_type: ControlFlowEdge
id: fe4ef560-e504-4dc8-a298-7dbb3c067a6f
name: __StartStep___to_step_0_control_flow_edge
description: null
metadata:
__metadata_info__: {}
from_node:
$component_ref: 79b6331a-5543-4310-8d8b-1d9f1337b025
from_branch: null
to_node:
$component_ref: 331ca41a-8738-4751-a87e-5cc48b8a3e23
- component_type: ControlFlowEdge
id: a16d091c-0d0c-4d29-9104-7761bdbb4cd3
name: step_0_to_None End node_control_flow_edge
description: null
metadata: {}
from_node:
$component_ref: 331ca41a-8738-4751-a87e-5cc48b8a3e23
from_branch: null
to_node:
$component_ref: ae2f0460-cba8-499e-a993-62b946e56d40
data_flow_connections:
- component_type: DataFlowEdge
id: 58dbd841-e0a5-4c87-ac0c-08a34625323b
name: __StartStep___entity_to_step_0_entity_data_flow_edge
description: null
metadata:
__metadata_info__: {}
source_node:
$component_ref: 79b6331a-5543-4310-8d8b-1d9f1337b025
source_output: entity
destination_node:
$component_ref: 331ca41a-8738-4751-a87e-5cc48b8a3e23
destination_input: entity
- component_type: DataFlowEdge
id: 92415266-d5a4-40ca-b8e6-57e01ec002a5
name: step_0_created_entity_to_None End node_created_entity_data_flow_edge
description: null
metadata: {}
source_node:
$component_ref: 331ca41a-8738-4751-a87e-5cc48b8a3e23
source_output: created_entity
destination_node:
$component_ref: ae2f0460-cba8-499e-a993-62b946e56d40
destination_input: created_entity
$referenced_components:
331ca41a-8738-4751-a87e-5cc48b8a3e23:
component_type: PluginDatastoreCreateNode
id: 331ca41a-8738-4751-a87e-5cc48b8a3e23
name: step_0
description: ''
metadata:
__metadata_info__: {}
inputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entity
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: created_entity
branches:
- next
input_mapping: {}
output_mapping: {}
datastore:
$component_ref: 4f8e1008-2f20-456c-9250-679146e88192
collection_name: products
ENTITY: entity
CREATED_ENTITY: created_entity
component_plugin_name: DatastorePlugin
component_plugin_version: 25.4.0.dev0
79b6331a-5543-4310-8d8b-1d9f1337b025:
component_type: StartNode
id: 79b6331a-5543-4310-8d8b-1d9f1337b025
name: __StartStep__
description: ''
metadata:
__metadata_info__: {}
inputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entity
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entity
branches:
- next
ae2f0460-cba8-499e-a993-62b946e56d40:
component_type: EndNode
id: ae2f0460-cba8-499e-a993-62b946e56d40
name: None End node
description: End node representing all transitions to None in the WayFlow flow
metadata: {}
inputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: created_entity
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: created_entity
branches: []
branch_name: next
- component_type: Flow
id: ba1cd504-bef6-4af3-9498-cbf6e50a0bca
name: List all products
description: Lists all products in the data source.
metadata:
__metadata_info__: {}
inputs: []
outputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
start_node:
$component_ref: bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff
nodes:
- $component_ref: 0c924103-23f5-4698-b69e-c553250186ab
- $component_ref: bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff
- $component_ref: 098f2832-4672-44eb-a060-ea9514ceefc5
control_flow_connections:
- component_type: ControlFlowEdge
id: a0392cfe-bed3-44cb-84c0-20a30f1cbe18
name: __StartStep___to_step_0_control_flow_edge
description: null
metadata:
__metadata_info__: {}
from_node:
$component_ref: bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff
from_branch: null
to_node:
$component_ref: 0c924103-23f5-4698-b69e-c553250186ab
- component_type: ControlFlowEdge
id: 3290795e-59ca-46f8-8a96-5a265d707c13
name: step_0_to_None End node_control_flow_edge
description: null
metadata: {}
from_node:
$component_ref: 0c924103-23f5-4698-b69e-c553250186ab
from_branch: null
to_node:
$component_ref: 098f2832-4672-44eb-a060-ea9514ceefc5
data_flow_connections:
- component_type: DataFlowEdge
id: 308b92b6-70f4-4e9c-b41e-1563bc449a24
name: step_0_entities_to_None End node_entities_data_flow_edge
description: null
metadata: {}
source_node:
$component_ref: 0c924103-23f5-4698-b69e-c553250186ab
source_output: entities
destination_node:
$component_ref: 098f2832-4672-44eb-a060-ea9514ceefc5
destination_input: entities
$referenced_components:
098f2832-4672-44eb-a060-ea9514ceefc5:
component_type: EndNode
id: 098f2832-4672-44eb-a060-ea9514ceefc5
name: None End node
description: End node representing all transitions to None in the WayFlow flow
metadata: {}
inputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
outputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
branches: []
branch_name: next
0c924103-23f5-4698-b69e-c553250186ab:
component_type: PluginDatastoreListNode
id: 0c924103-23f5-4698-b69e-c553250186ab
name: step_0
description: ''
metadata:
__metadata_info__: {}
inputs: []
outputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
branches:
- next
input_mapping: {}
output_mapping: {}
datastore:
$component_ref: 4f8e1008-2f20-456c-9250-679146e88192
collection_name: products
where: null
limit: null
unpack_single_entity_from_list: false
ENTITIES: entities
component_plugin_name: DatastorePlugin
component_plugin_version: 25.4.0.dev0
bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff:
component_type: StartNode
id: bb1b722a-0aae-4e09-b2a4-cbcdb93b2cff
name: __StartStep__
description: ''
metadata:
__metadata_info__: {}
inputs: []
outputs: []
branches:
- next
- component_type: Flow
id: bad00138-48b3-4e7c-84a9-51bd385a38a2
name: List single product
description: Lists a single product in the data source by its title.
metadata:
__metadata_info__: {}
inputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entities
start_node:
$component_ref: 76d19c9a-241f-4a4d-bbac-2bcbd3359498
nodes:
- $component_ref: d1b1f436-b91f-435c-867c-ecf9b5b187a1
- $component_ref: 76d19c9a-241f-4a4d-bbac-2bcbd3359498
- $component_ref: aa8090d6-2220-40ad-ab16-6adb1bdead7b
control_flow_connections:
- component_type: ControlFlowEdge
id: e37ae190-e7f6-4090-8091-c5eddadf7a9d
name: __StartStep___to_product_list_step_control_flow_edge
description: null
metadata:
__metadata_info__: {}
from_node:
$component_ref: 76d19c9a-241f-4a4d-bbac-2bcbd3359498
from_branch: null
to_node:
$component_ref: d1b1f436-b91f-435c-867c-ecf9b5b187a1
- component_type: ControlFlowEdge
id: 80680849-e51b-435d-aee6-cdb7e6571ee7
name: product_list_step_to_None End node_control_flow_edge
description: null
metadata: {}
from_node:
$component_ref: d1b1f436-b91f-435c-867c-ecf9b5b187a1
from_branch: null
to_node:
$component_ref: aa8090d6-2220-40ad-ab16-6adb1bdead7b
data_flow_connections:
- component_type: DataFlowEdge
id: dab6eb95-057c-4adc-85dd-2a40e14713eb
name: __StartStep___user_requested_product_to_product_list_step_user_requested_product_data_flow_edge
description: null
metadata:
__metadata_info__: {}
source_node:
$component_ref: 76d19c9a-241f-4a4d-bbac-2bcbd3359498
source_output: user_requested_product
destination_node:
$component_ref: d1b1f436-b91f-435c-867c-ecf9b5b187a1
destination_input: user_requested_product
- component_type: DataFlowEdge
id: 82d0a256-6c3d-45a8-a6bf-c1c949069927
name: product_list_step_entities_to_None End node_entities_data_flow_edge
description: null
metadata: {}
source_node:
$component_ref: d1b1f436-b91f-435c-867c-ecf9b5b187a1
source_output: entities
destination_node:
$component_ref: aa8090d6-2220-40ad-ab16-6adb1bdead7b
destination_input: entities
$referenced_components:
d1b1f436-b91f-435c-867c-ecf9b5b187a1:
component_type: PluginDatastoreListNode
id: d1b1f436-b91f-435c-867c-ecf9b5b187a1
name: product_list_step
description: ''
metadata:
__metadata_info__: {}
inputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entities
branches:
- next
input_mapping: {}
output_mapping: {}
datastore:
$component_ref: 4f8e1008-2f20-456c-9250-679146e88192
collection_name: products
where:
title: '{{user_requested_product}}'
limit: 1
unpack_single_entity_from_list: true
ENTITIES: entities
component_plugin_name: DatastorePlugin
component_plugin_version: 25.4.0.dev0
76d19c9a-241f-4a4d-bbac-2bcbd3359498:
component_type: StartNode
id: 76d19c9a-241f-4a4d-bbac-2bcbd3359498
name: __StartStep__
description: ''
metadata:
__metadata_info__: {}
inputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
outputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
branches:
- next
aa8090d6-2220-40ad-ab16-6adb1bdead7b:
component_type: EndNode
id: aa8090d6-2220-40ad-ab16-6adb1bdead7b
name: None End node
description: End node representing all transitions to None in the WayFlow flow
metadata: {}
inputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entities
outputs:
- type: object
additionalProperties: {}
key_type:
type: string
title: entities
branches: []
branch_name: next
- component_type: Flow
id: a3047067-dea3-4cc9-a922-c26d35d97c48
name: Update product
description: Updates a product in the data source by its title.
metadata:
__metadata_info__: {}
inputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
- type: object
additionalProperties: {}
key_type:
type: string
title: update
outputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
start_node:
$component_ref: 8c74a4c5-fdf0-447e-956f-59498da1dc09
nodes:
- $component_ref: 487a708b-0553-4bb5-b015-948d2a97ede6
- $component_ref: 8c74a4c5-fdf0-447e-956f-59498da1dc09
- $component_ref: 9074c861-1cf4-4bd9-88dd-3fe209b2c218
control_flow_connections:
- component_type: ControlFlowEdge
id: 64436400-797d-4d35-92df-78fc557006f2
name: __StartStep___to_product_update_step_control_flow_edge
description: null
metadata:
__metadata_info__: {}
from_node:
$component_ref: 8c74a4c5-fdf0-447e-956f-59498da1dc09
from_branch: null
to_node:
$component_ref: 487a708b-0553-4bb5-b015-948d2a97ede6
- component_type: ControlFlowEdge
id: 5e55b5d7-7bf8-435a-9044-f05f1b377671
name: product_update_step_to_None End node_control_flow_edge
description: null
metadata: {}
from_node:
$component_ref: 487a708b-0553-4bb5-b015-948d2a97ede6
from_branch: null
to_node:
$component_ref: 9074c861-1cf4-4bd9-88dd-3fe209b2c218
data_flow_connections:
- component_type: DataFlowEdge
id: 43c29773-0a4b-4145-9c0d-ad5238410e9d
name: __StartStep___user_requested_product_to_product_update_step_user_requested_product_data_flow_edge
description: null
metadata:
__metadata_info__: {}
source_node:
$component_ref: 8c74a4c5-fdf0-447e-956f-59498da1dc09
source_output: user_requested_product
destination_node:
$component_ref: 487a708b-0553-4bb5-b015-948d2a97ede6
destination_input: user_requested_product
- component_type: DataFlowEdge
id: 8e5f0ea8-8ea1-42ba-bdba-95a74082c908
name: __StartStep___update_to_product_update_step_update_data_flow_edge
description: null
metadata:
__metadata_info__: {}
source_node:
$component_ref: 8c74a4c5-fdf0-447e-956f-59498da1dc09
source_output: update
destination_node:
$component_ref: 487a708b-0553-4bb5-b015-948d2a97ede6
destination_input: update
- component_type: DataFlowEdge
id: 1bd34870-1e52-4896-bfaf-5a71006da687
name: product_update_step_entities_to_None End node_entities_data_flow_edge
description: null
metadata: {}
source_node:
$component_ref: 487a708b-0553-4bb5-b015-948d2a97ede6
source_output: entities
destination_node:
$component_ref: 9074c861-1cf4-4bd9-88dd-3fe209b2c218
destination_input: entities
$referenced_components:
487a708b-0553-4bb5-b015-948d2a97ede6:
component_type: PluginDatastoreUpdateNode
id: 487a708b-0553-4bb5-b015-948d2a97ede6
name: product_update_step
description: ''
metadata:
__metadata_info__: {}
inputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
- type: object
additionalProperties: {}
key_type:
type: string
title: update
outputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
branches:
- next
input_mapping: {}
output_mapping: {}
datastore:
$component_ref: 4f8e1008-2f20-456c-9250-679146e88192
collection_name: products
where:
title: '{{user_requested_product}}'
ENTITIES: entities
UPDATE: update
component_plugin_name: DatastorePlugin
component_plugin_version: 25.4.0.dev0
8c74a4c5-fdf0-447e-956f-59498da1dc09:
component_type: StartNode
id: 8c74a4c5-fdf0-447e-956f-59498da1dc09
name: __StartStep__
description: ''
metadata:
__metadata_info__: {}
inputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
- type: object
additionalProperties: {}
key_type:
type: string
title: update
outputs:
- description: '"user_requested_product" input variable for the template'
type: string
title: user_requested_product
- type: object
additionalProperties: {}
key_type:
type: string
title: update
branches:
- next
9074c861-1cf4-4bd9-88dd-3fe209b2c218:
component_type: EndNode
id: 9074c861-1cf4-4bd9-88dd-3fe209b2c218
name: None End node
description: End node representing all transitions to None in the WayFlow flow
metadata: {}
inputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
outputs:
- type: array
items:
type: object
additionalProperties: {}
key_type:
type: string
title: entities
branches: []
branch_name: next
- component_type: Flow
id: ebae9461-df3a-4544-9cfd-dd2a2e13e34e
name: Delete product
description: Delete a product in the data source by its title.
metadata:
__metadata_info__: {}
inputs:
- description: '"product_title" input variable for the template'
type: string
title: product_title
outputs: []
start_node:
$component_ref: 13d561e4-1c49-4808-974c-d82311479998
nodes:
- $component_ref: 9cd4c282-5290-477d-b9c1-f069a599aa68
- $component_ref: 13d561e4-1c49-4808-974c-d82311479998
- $component_ref: 49384f2b-1825-4c6b-a876-86e8803b0014
control_flow_connections:
- component_type: ControlFlowEdge
id: 7b91ecf7-f24e-4ff3-8df4-f6769847e7a4
name: __StartStep___to_step_0_control_flow_edge
description: null
metadata:
__metadata_info__: {}
from_node:
$component_ref: 13d561e4-1c49-4808-974c-d82311479998
from_branch: null
to_node:
$component_ref: 9cd4c282-5290-477d-b9c1-f069a599aa68
- component_type: ControlFlowEdge
id: e666dfe3-6041-4141-b21b-afedfa74f3ab
name: step_0_to_None End node_control_flow_edge
description: null
metadata: {}
from_node:
$component_ref: 9cd4c282-5290-477d-b9c1-f069a599aa68
from_branch: null
to_node:
$component_ref: 49384f2b-1825-4c6b-a876-86e8803b0014
data_flow_connections:
- component_type: DataFlowEdge
id: a731fb73-ad3b-4a22-9f0b-35e9f1d63131
name: __StartStep___product_title_to_step_0_product_title_data_flow_edge
description: null
metadata:
__metadata_info__: {}
source_node:
$component_ref: 13d561e4-1c49-4808-974c-d82311479998
source_output: product_title
destination_node:
$component_ref: 9cd4c282-5290-477d-b9c1-f069a599aa68
destination_input: product_title
$referenced_components:
9cd4c282-5290-477d-b9c1-f069a599aa68:
component_type: PluginDatastoreDeleteNode
id: 9cd4c282-5290-477d-b9c1-f069a599aa68
name: step_0
description: ''
metadata:
__metadata_info__: {}
inputs:
- description: '"product_title" input variable for the template'
type: string
title: product_title
outputs: []
branches:
- next
input_mapping: {}
output_mapping: {}
datastore:
$component_ref: 4f8e1008-2f20-456c-9250-679146e88192
collection_name: products
where:
title: '{{product_title}}'
component_plugin_name: DatastorePlugin
component_plugin_version: 25.4.0.dev0
13d561e4-1c49-4808-974c-d82311479998:
component_type: StartNode
id: 13d561e4-1c49-4808-974c-d82311479998
name: __StartStep__
description: ''
metadata:
__metadata_info__: {}
inputs:
- description: '"product_title" input variable for the template'
type: string
title: product_title
outputs:
- description: '"product_title" input variable for the template'
type: string
title: product_title
branches:
- next
49384f2b-1825-4c6b-a876-86e8803b0014:
component_type: EndNode
id: 49384f2b-1825-4c6b-a876-86e8803b0014
name: None End node
description: End node representing all transitions to None in the WayFlow flow
metadata: {}
inputs: []
outputs: []
branches: []
branch_name: next
agent_template:
component_type: PluginPromptTemplate
id: ea261004-a6d8-4380-af2a-4e5adbaf7b9c
name: ''
description: null
metadata:
__metadata_info__: {}
messages:
- role: system
contents:
- type: text
content: '{%- if __TOOLS__ -%}
Environment: ipython
Cutting Knowledge Date: December 2023
You are a helpful assistant with tool calling capabilities. Only reply with
a tool call if the function exists in the library provided by the user. If
it doesn''t exist, just reply directly in natural language. When you receive
a tool call response, use the output to format an answer to the original user
question.
You have access to the following functions. To call a function, please respond
with JSON for a function call.
Respond in the format {"name": function name, "parameters": dictionary of
argument name and its value}.
Do not use variables.
[{% for tool in __TOOLS__%}{{tool.to_openai_format() | tojson}}{{'', '' if
not loop.last}}{% endfor %}]
{%- endif -%}
'
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T15:58:42.673848+00:00'
time_updated: '2025-09-02T15:58:42.673852+00:00'
- role: system
contents:
- type: text
content: '{%- if custom_instruction -%}Additional instructions:
{{custom_instruction}}{%- endif -%}'
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T15:58:42.673915+00:00'
time_updated: '2025-09-02T15:58:42.673916+00:00'
- role: user
contents: []
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T15:58:42.660189+00:00'
time_updated: '2025-09-02T15:58:42.660446+00:00'
- role: system
contents:
- type: text
content: "{% if __PLAN__ %}The current plan you should follow is the following:\
\ \n{{__PLAN__}}{% endif %}"
tool_requests: null
tool_result: null
display_only: false
sender: null
recipients: []
time_created: '2025-09-02T15:58:42.673985+00:00'
time_updated: '2025-09-02T15:58:42.673986+00:00'
output_parser:
component_type: PluginJsonToolOutputParser
id: 8d8b00f0-2c13-4e0f-894c-a46ad91eccbc
name: jsontool_outputparser
description: null
metadata:
__metadata_info__: {}
tools: null
component_plugin_name: OutputParserPlugin
component_plugin_version: 25.4.0.dev0
inputs:
- description: '"__TOOLS__" input variable for the template'
title: __TOOLS__
- description: '"custom_instruction" input variable for the template'
type: string
title: custom_instruction
- description: '"__PLAN__" input variable for the template'
type: string
title: __PLAN__
default: ''
- type: array
items: {}
title: __CHAT_HISTORY__
pre_rendering_transforms: null
post_rendering_transforms:
- component_type: PluginRemoveEmptyNonUserMessageTransform
id: f964b648-4850-43ca-983b-6bf05ec6fe59
name: removeemptynonusermessage_messagetransform
description: null
metadata:
__metadata_info__: {}
component_plugin_name: MessageTransformPlugin
component_plugin_version: 25.4.0.dev0
- component_type: PluginCoalesceSystemMessagesTransform
id: b0c702f1-14a8-4692-b746-490f3cc2a406
name: coalescesystemmessage_messagetransform
description: null
metadata:
__metadata_info__: {}
component_plugin_name: MessageTransformPlugin
component_plugin_version: 25.4.0.dev0
- component_type: PluginLlamaMergeToolRequestAndCallsTransform
id: 466f3fef-697b-4e2e-804b-cc9788186b0d
name: llamamergetoolrequestandcalls_messagetransform
description: null
metadata:
__metadata_info__: {}
component_plugin_name: MessageTransformPlugin
component_plugin_version: 25.4.0.dev0
tools: null
native_tool_calling: false
response_format: null
native_structured_generation: true
generation_config: null
component_plugin_name: PromptTemplatePlugin
component_plugin_version: 25.4.0.dev0
component_plugin_name: AgentPlugin
component_plugin_version: 25.4.0.dev0
$referenced_components:
4f8e1008-2f20-456c-9250-679146e88192:
component_type: PluginInMemoryDatastore
id: 4f8e1008-2f20-456c-9250-679146e88192
name: PluginInMemoryDatastore
description: null
metadata: {}
datastore_schema:
products:
description: ''
title: ''
properties:
description:
type: string
ID:
description: Unique product identifier
type: integer
title:
description: Brief summary of the product
type: string
price:
type: number
default: 0.1
category:
anyOf:
- type: 'null'
- type: string
default: null
component_plugin_name: DatastorePlugin
component_plugin_version: 25.4.0.dev0
agentspec_version: 25.4.1
You can then load the configuration back to an assistant using the AgentSpecLoader
.
from wayflowcore.agentspec import AgentSpecLoader
agent = AgentSpecLoader().load_json(serialized_agent)
Note
This guide uses the following extension/plugin Agent Spec components:
PluginPromptTemplate
PluginDatastoreCreateNode
PluginDatastoreUpdateNode
PluginDatastoreListNode
PluginDatastoreDeleteNode
PluginJsonToolOutputParser
PluginRemoveEmptyNonUserMessageTransform
PluginCoalesceSystemMessagesTransform
PluginLlamaMergeToolRequestAndCallsTransform
PluginInMemoryDatastore
ExtendedAgent
See the list of available Agent Spec extension/plugin components in the API Reference
Next steps#
Having learned how to connect WayFlow assistants to data sources, you may now proceed to:
Full code#
Click on the card at the top of this page to download the full code for this guide or copy the code below.
1# Copyright © 2025 Oracle and/or its affiliates.
2#
3# This software is under the Universal Permissive License
4# %%[markdown]
5# WayFlow Code Example - How to Connect to Your Data
6# --------------------------------------------------
7
8# How to use:
9# Create a new Python virtual environment and install the latest WayFlow version.
10# ```bash
11# python -m venv venv-wayflowcore
12# source venv-wayflowcore/bin/activate
13# pip install --upgrade pip
14# pip install "wayflowcore==26.1"
15# ```
16
17# You can now run the script
18# 1. As a Python file:
19# ```bash
20# python howto_datastores.py
21# ```
22# 2. As a Notebook (in VSCode):
23# When viewing the file,
24# - press the keys Ctrl + Enter to run the selected cell
25# - or Shift + Enter to run the selected cell and move to the cell below# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl) or Apache License
26# 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0), at your option.
27
28
29
30# %%[markdown]
31## Imports
32
33# %%
34from textwrap import dedent
35
36from wayflowcore.controlconnection import ControlFlowEdge
37from wayflowcore.dataconnection import DataFlowEdge
38from wayflowcore.datastore import Entity, InMemoryDatastore
39from wayflowcore.datastore.entity import nullable
40from wayflowcore.flow import Flow
41from wayflowcore.property import (
42 AnyProperty,
43 DictProperty,
44 FloatProperty,
45 IntegerProperty,
46 ObjectProperty,
47 StringProperty,
48)
49from wayflowcore.steps import InputMessageStep, OutputMessageStep, PromptExecutionStep
50from wayflowcore.steps.datastoresteps import (
51 DatastoreCreateStep,
52 DatastoreDeleteStep,
53 DatastoreListStep,
54 DatastoreUpdateStep,
55)
56
57# %%[markdown]
58## Define the llm
59
60# %%
61from wayflowcore.models import VllmModel
62
63llm = VllmModel(
64 model_id="LLAMA_MODEL_ID",
65 host_port="LLAMA_API_URL",
66)
67
68# %%[markdown]
69## Create entities
70
71# %%
72product = Entity(
73 properties={
74 "ID": IntegerProperty(description="Unique product identifier"),
75 # Descriptions can be helpful if an LLM needs to fill these fields,
76 # or generally disambiguate non-obvious property names
77 "title": StringProperty(description="Brief summary of the product"),
78 "description": StringProperty(),
79 "price": FloatProperty(default_value=0.1),
80 # Use nullable to define optional properties
81 "category": nullable(StringProperty()),
82 },
83)
84
85# %%[markdown]
86## Create datastore
87
88# %%
89datastore = InMemoryDatastore(schema={"products": product})
90
91dummy_data = [
92 {
93 "ID": 0,
94 "title": "Broccoli",
95 "description": "Healty and delicious cruciferous vegetable!",
96 "price": 1.5,
97 "category": "Produce",
98 },
99 {
100 "ID": 1,
101 "title": "Oranges",
102 "description": "Vitamin C-filled citrus fruits",
103 "price": 1.8,
104 "category": "Produce",
105 },
106 {
107 "ID": 2,
108 "title": "Shampoo",
109 "description": "Shiny smooth hair in just 10 applications!",
110 "price": 4.5,
111 "category": "Personal hygene",
112 },
113 {
114 "ID": 3,
115 "title": "Crushed ice",
116 "description": "Cool any drink in seconds!",
117 "price": 4.5,
118 },
119]
120
121# Create supports both bulk-creation, as well as single element creation
122datastore.create(collection_name="products", entities=dummy_data[:-1])
123datastore.create(collection_name="products", entities=dummy_data[-1])
124
125# %%[markdown]
126## Create Datastore step
127
128# %%
129datastore_list_step = DatastoreListStep(
130 datastore,
131 name="product_list_step",
132 collection_name="products",
133 where={"title": "{{user_requested_product}}"},
134 limit=1,
135 unpack_single_entity_from_list=True,
136)
137
138datastore_update_step = DatastoreUpdateStep(
139 datastore,
140 name="product_update_step",
141 collection_name="products",
142 where={"title": "{{user_requested_product}}"}
143)
144
145# %%[markdown]
146## Create flow
147
148# %%
149# We create the steps needed by our flow
150USER_INPUT_STEP = "user_product_input_step"
151USER_TASK_INPUT_STEP = "user_task_input_step"
152LLM_REWRITE_STEP = "llm_rewrite_step"
153USER_OUTPUT_STEP = "user_output_step"
154
155user_input_message_template = dedent(
156 """I am an inventory Assistant, designed to help you keep product descriptions up-to-date.
157 What product would you like to update? Please provide its title.
158 """
159)
160
161user_task_message_template = "How would you like to update the description? I will help you rewrite it according to your instructions"
162
163rewrite_description_prompt_template = dedent(
164 """You are an inventory assistant.
165
166 Your task:
167 - Based on the product details given below, rewrite the description according to the user's request
168 Important:
169 - Be helpful and concise in your messages
170 - Only provide the new description as an output, and nothing else
171
172 Here is the User's request:
173 - {{ user_request }}
174
175 Here is the product description:
176 - {{ product }}
177 """
178)
179
180user_input_step = InputMessageStep(
181 name=USER_INPUT_STEP,
182 message_template=user_input_message_template,
183)
184
185user_task_input_step = InputMessageStep(
186 name=USER_TASK_INPUT_STEP,
187 message_template=user_task_message_template,
188)
189
190llm_rewrite_step = PromptExecutionStep(
191 name=LLM_REWRITE_STEP,
192 prompt_template=rewrite_description_prompt_template,
193 llm=llm,
194 input_descriptors=[
195 DictProperty("product", key_type=StringProperty(), value_type=AnyProperty())
196 ],
197 output_descriptors=[
198 ObjectProperty(
199 name=PromptExecutionStep.OUTPUT, properties={"description": StringProperty()}
200 )
201 ],
202)
203
204user_output_step = OutputMessageStep(
205 name=USER_OUTPUT_STEP,
206 message_template="The product has been updated with the following description: {{ answer['description'] }}",
207)
208
209assistant = Flow(
210 begin_step=user_input_step,
211 control_flow_edges=[
212 ControlFlowEdge(source_step=user_input_step, destination_step=user_task_input_step),
213 ControlFlowEdge(source_step=user_task_input_step, destination_step=datastore_list_step),
214 ControlFlowEdge(source_step=datastore_list_step, destination_step=llm_rewrite_step),
215 ControlFlowEdge(source_step=llm_rewrite_step, destination_step=datastore_update_step),
216 ControlFlowEdge(source_step=datastore_update_step, destination_step=user_output_step),
217 ControlFlowEdge(source_step=user_output_step, destination_step=None),
218 ],
219 data_flow_edges=[
220 # The first title given by the user is mapped to the datastore steps for listing and updating
221 DataFlowEdge(
222 user_input_step,
223 InputMessageStep.USER_PROVIDED_INPUT,
224 datastore_list_step,
225 "user_requested_product",
226 ),
227 DataFlowEdge(
228 user_input_step,
229 InputMessageStep.USER_PROVIDED_INPUT,
230 datastore_update_step,
231 "user_requested_product",
232 ),
233 # The task and product detail are given to the LLM in the prompt execution step
234 DataFlowEdge(
235 user_task_input_step,
236 InputMessageStep.USER_PROVIDED_INPUT,
237 llm_rewrite_step,
238 "user_request",
239 ),
240 DataFlowEdge(datastore_list_step, DatastoreListStep.ENTITIES, llm_rewrite_step, "product"),
241 # The generated update is applied on the datastore, and echoed back to the user
242 DataFlowEdge(
243 llm_rewrite_step,
244 PromptExecutionStep.OUTPUT,
245 datastore_update_step,
246 DatastoreUpdateStep.UPDATE,
247 ),
248 DataFlowEdge(llm_rewrite_step, PromptExecutionStep.OUTPUT, user_output_step, "answer"),
249 ],
250)
251
252# %%[markdown]
253## Execute flow
254
255# %%
256conversation = assistant.start_conversation()
257conversation.execute()
258conversation.append_user_message("Broccoli")
259
260conversation.execute()
261conversation.append_user_message(
262 "Shoppers don't know what 'cruciferous' means, we should find a catchier description."
263)
264
265conversation.execute()
266print(conversation.get_last_message().content)
267
268# %%[markdown]
269## Import agents
270
271# %%
272from wayflowcore.agent import Agent
273
274# %%[markdown]
275## Create agent flows
276
277# %%
278AGENT_PROMPT = dedent(
279 """
280 You are an inventory assistant. Your task is to help the user with their requests by using the available tools.
281 If you are unsure about the action to take, or you don't have the right tool, simply tell the user so and follow their guidance.
282 """
283)
284
285create_product_flow = Flow.from_steps(
286 [DatastoreCreateStep(datastore, "products")],
287 name="Create product",
288 description="Creates a new product in the data source",
289)
290list_products_flow = Flow.from_steps(
291 [DatastoreListStep(datastore, "products")],
292 name="List all products",
293 description="Lists all products in the data source.",
294)
295list_one_product_flow = Flow.from_steps(
296 [datastore_list_step],
297 name="List single product",
298 description="Lists a single product in the data source by its title.",
299)
300update_product_flow = Flow.from_steps(
301 [datastore_update_step],
302 name="Update product",
303 description="Updates a product in the data source by its title.",
304)
305delete_product_flow = Flow.from_steps(
306 [DatastoreDeleteStep(datastore, "products", where={"title": "{{product_title}}"})],
307 name="Delete product",
308 description="Delete a product in the data source by its title.",
309)
310
311# %%[markdown]
312## Create agent
313
314# %%
315agent = Agent(
316 llm=llm,
317 flows=[
318 create_product_flow,
319 list_products_flow,
320 list_one_product_flow,
321 update_product_flow,
322 delete_product_flow,
323 ],
324 custom_instruction=AGENT_PROMPT,
325)
326
327# %%[markdown]
328## Export config to Agent Spec
329
330# %%
331from wayflowcore.agentspec import AgentSpecExporter
332
333serialized_agent = AgentSpecExporter().to_json(agent)
334
335# %%[markdown]
336## Load Agent Spec config
337
338# %%
339from wayflowcore.agentspec import AgentSpecLoader
340
341agent = AgentSpecLoader().load_json(serialized_agent)