How to Use Variables for Shared State in Flows#

python-icon Download Python Script

Python script/notebook for this guide.

Variable how-to script

Prerequisites

This guide assumes familiarity with Flows

When building Flows, you may need a way to preserve information as it moves from one step to another. WayFlow provides this through Variable, which serves as the flow’s state — a place where values can be stored, accessed, and updated throughout execution.

Why to use Variable?

  • Shared state: Holds data that multiple steps can share.

  • Intermediate results: Store partial results and reuse them later.

  • Simpler data flow: Avoid passing outputs between every step, persist them as state using Variable.

This guide will show you how to:

In this guide, you will see a simple example including defining a Variable that stores a list of user feedback, using VariableWriteStep to insert new feedback into the list, and using VariableReadStep to read all collected feedback.

Define a Variable#

To define a variable, you need to define it with a name, type and optionally, a default value. The type of variable determines the kind of data it can hold and is defined using Property. In this case, our feedback_variable has the type of ListProperty and the item_type of StringProperty.

1from wayflowcore.variable import Variable
2from wayflowcore.property import ListProperty, StringProperty
3
4feedback_variable = Variable(
5    name="user_feedback",
6    type=ListProperty(item_type=StringProperty()),
7    description="list of user feedback",
8    default_value=[],
9)

API Reference: Variable | Property

Define Flow Steps#

We will define a simple flow including the following steps.

 1from wayflowcore.steps import StartStep, OutputMessageStep, VariableReadStep, VariableWriteStep
 2from wayflowcore.property import StringProperty
 3
 4FEEDBACK_1 = "feedback_1"
 5FEEDBACK_2 = "feedback_2"
 6
 7start_step = StartStep(
 8    name="start_step",
 9    input_descriptors={StringProperty(FEEDBACK_1), StringProperty(FEEDBACK_2)},
10)
11
12write_feedback_1 = VariableWriteStep(
13    name="write_step_1",
14    variable=feedback_variable,
15    operation="insert",
16)
17
18write_feedback_2 = VariableWriteStep(
19    name="write_step_2",
20    variable=feedback_variable,
21    operation="insert",
22)
23
24read_feedback = VariableReadStep(variable=feedback_variable, name="read_step")
25
26output_step = OutputMessageStep("Collected feedback: {{ feedback }}", name="output_step")

For simplicity, we pass initial feedback to the start_step, which then routes values to write_feedback_1 and write_feedback_2. In practice, those inputs could come from other steps (e.g. ToolExecutionStep).

The VariableWriteStep requires the variable that it writes to. It also accepts the following options of write operation:

  • VariableWriteOperation.OVERWRITE (or 'overwrite') works on any type of variable to replace its value with the incoming value.

  • VariableWriteOperation.MERGE (or 'merge') updates a Variable of type dict (resp. list),

  • VariableWriteOperation.INSERT (or 'insert') operation can be used to append a single element at the end of a list.

Here, we choose insert as we want to append new user feedback to the our list.

Define a Flow with Variable#

Now we connect everything into a flow: two write steps add feedback, and a read step collects it all for output.

 1from wayflowcore.controlconnection import ControlFlowEdge
 2from wayflowcore.dataconnection import DataFlowEdge
 3from wayflowcore.flow import Flow
 4
 5flow = Flow(
 6    begin_step=start_step,
 7    control_flow_edges=[
 8        ControlFlowEdge(start_step, write_feedback_1),
 9        ControlFlowEdge(write_feedback_1, write_feedback_2),
10        ControlFlowEdge(write_feedback_2, read_feedback),
11        ControlFlowEdge(read_feedback, output_step),
12        ControlFlowEdge(output_step, None),
13    ],
14    data_flow_edges=[
15        DataFlowEdge(start_step, FEEDBACK_1, write_feedback_1, VariableWriteStep.VALUE),
16        DataFlowEdge(start_step, FEEDBACK_2, write_feedback_2, VariableWriteStep.VALUE),
17        DataFlowEdge(read_feedback, VariableReadStep.VALUE, output_step, "feedback"),
18    ],
19    variables=[feedback_variable],
20)

The VariableWriteStep has a single input descriptor VariableWriteStep.VALUE - the value to write to the variable it holds. Similarly, the VariableReadStep has a single output descriptor VariableReadStep.VALUE- the value it reads from the variable it holds.

Remember to include your defined variables in the Flow’s variables parameter.

Execute the Flow#

Finally, run the flow:

 1conv = flow.start_conversation(
 2    inputs={
 3        FEEDBACK_1: "Very good!",
 4        FEEDBACK_2: "Need to improve!",
 5    }
 6)
 7conv.execute()
 8
 9result = conv.get_last_message().content
10print(result)
11# >>> Collected feedback: ["Very good!", "Need to improve!"]

Agent Spec Exporting/Loading#

You can export the assistant configuration to its Agent Spec configuration using the AgentSpecExporter.

from wayflowcore.agentspec import AgentSpecExporter

serialized_assistant = AgentSpecExporter().to_yaml(flow)

Here is what the Agent Spec representation will look like ↓

Click here to see the AgentSpec assistant configuration.
component_type: Flow
id: 5b86a3b4-22b1-442a-91f9-569a938d4789
name: flow_96bb6cb7
description: ''
metadata:
  __metadata_info__: {}
inputs:
- type: string
  title: feedback_2
- type: string
  title: feedback_1
outputs:
- description: list of user feedback
  type: array
  items:
    type: string
  title: value
  default: []
- description: the message added to the messages list
  type: string
  title: output_message
start_node:
  $component_ref: cfcab079-4674-4a0a-bc7c-f1128e852ca0
nodes:
- $component_ref: cfcab079-4674-4a0a-bc7c-f1128e852ca0
- $component_ref: ded88ecb-17c9-4578-ae45-5c80b01c34ad
- $component_ref: febaa510-2875-444a-ae51-ea39fbc708f7
- $component_ref: f592ae1a-682f-45e0-849f-579eeb803e04
- $component_ref: a6751ff9-5940-4ff0-90b4-12c7a15b8b87
- $component_ref: 83ea975c-1b64-46f2-9dfb-a12ee1ee8d90
state:
- description: list of user feedback
  type: array
  items:
    type: string
  title: user_feedback
  default: []
control_flow_connections:
- component_type: ControlFlowEdge
  id: 9340d618-bd88-415b-9f19-b4fed93f5896
  name: step_1a0d93db_to_step_709c5a35_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: cfcab079-4674-4a0a-bc7c-f1128e852ca0
  from_branch: null
  to_node:
    $component_ref: ded88ecb-17c9-4578-ae45-5c80b01c34ad
- component_type: ControlFlowEdge
  id: eca38c7f-f5cb-4e86-86fc-80d0810e2b14
  name: step_709c5a35_to_step_15af65a5_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: ded88ecb-17c9-4578-ae45-5c80b01c34ad
  from_branch: null
  to_node:
    $component_ref: febaa510-2875-444a-ae51-ea39fbc708f7
- component_type: ControlFlowEdge
  id: 135cc8b2-b2a1-480c-ac28-2b9226658efd
  name: step_15af65a5_to_step_a8581940_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: febaa510-2875-444a-ae51-ea39fbc708f7
  from_branch: null
  to_node:
    $component_ref: f592ae1a-682f-45e0-849f-579eeb803e04
- component_type: ControlFlowEdge
  id: e8c3990a-45e2-456a-bf40-758efdccb318
  name: step_a8581940_to_step_284a4a1d_control_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  from_node:
    $component_ref: f592ae1a-682f-45e0-849f-579eeb803e04
  from_branch: null
  to_node:
    $component_ref: a6751ff9-5940-4ff0-90b4-12c7a15b8b87
- component_type: ControlFlowEdge
  id: 5315ad19-52b1-44f1-bee8-f296e93d4b67
  name: step_284a4a1d_to_None End node_control_flow_edge
  description: null
  metadata: {}
  from_node:
    $component_ref: a6751ff9-5940-4ff0-90b4-12c7a15b8b87
  from_branch: null
  to_node:
    $component_ref: 83ea975c-1b64-46f2-9dfb-a12ee1ee8d90
data_flow_connections:
- component_type: DataFlowEdge
  id: cb51c4b1-0aab-4928-9d19-6bc098de4354
  name: step_1a0d93db_feedback_1_to_step_709c5a35_value_data_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  source_node:
    $component_ref: cfcab079-4674-4a0a-bc7c-f1128e852ca0
  source_output: feedback_1
  destination_node:
    $component_ref: ded88ecb-17c9-4578-ae45-5c80b01c34ad
  destination_input: value
- component_type: DataFlowEdge
  id: 9a794227-085d-4c79-b1f5-cf0d66e048b9
  name: step_1a0d93db_feedback_2_to_step_15af65a5_value_data_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  source_node:
    $component_ref: cfcab079-4674-4a0a-bc7c-f1128e852ca0
  source_output: feedback_2
  destination_node:
    $component_ref: febaa510-2875-444a-ae51-ea39fbc708f7
  destination_input: value
- component_type: DataFlowEdge
  id: f6ea2e6d-d1c8-411a-ae78-13abba142591
  name: step_a8581940_value_to_step_284a4a1d_feedback_data_flow_edge
  description: null
  metadata:
    __metadata_info__: {}
  source_node:
    $component_ref: f592ae1a-682f-45e0-849f-579eeb803e04
  source_output: value
  destination_node:
    $component_ref: a6751ff9-5940-4ff0-90b4-12c7a15b8b87
  destination_input: feedback
- component_type: DataFlowEdge
  id: 8db068f7-f246-4e8a-bf84-9f6b141aca54
  name: step_a8581940_value_to_None End node_value_data_flow_edge
  description: null
  metadata: {}
  source_node:
    $component_ref: f592ae1a-682f-45e0-849f-579eeb803e04
  source_output: value
  destination_node:
    $component_ref: 83ea975c-1b64-46f2-9dfb-a12ee1ee8d90
  destination_input: value
- component_type: DataFlowEdge
  id: 6c3ea770-a8b9-4bfb-95e7-aee1007d0195
  name: step_284a4a1d_output_message_to_None End node_output_message_data_flow_edge
  description: null
  metadata: {}
  source_node:
    $component_ref: a6751ff9-5940-4ff0-90b4-12c7a15b8b87
  source_output: output_message
  destination_node:
    $component_ref: 83ea975c-1b64-46f2-9dfb-a12ee1ee8d90
  destination_input: output_message
$referenced_components:
  cfcab079-4674-4a0a-bc7c-f1128e852ca0:
    component_type: StartNode
    id: cfcab079-4674-4a0a-bc7c-f1128e852ca0
    name: step_1a0d93db
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - type: string
      title: feedback_2
    - type: string
      title: feedback_1
    outputs:
    - type: string
      title: feedback_2
    - type: string
      title: feedback_1
    branches:
    - next
  ded88ecb-17c9-4578-ae45-5c80b01c34ad:
    component_type: PluginWriteVariableNode
    id: ded88ecb-17c9-4578-ae45-5c80b01c34ad
    name: step_709c5a35
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - description: list of user feedback (single element)
      type: string
      title: value
    outputs: []
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    variable:
      description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    operation: insert
    component_plugin_name: NodesPlugin
    component_plugin_version: 25.3.0.dev2
  febaa510-2875-444a-ae51-ea39fbc708f7:
    component_type: PluginWriteVariableNode
    id: febaa510-2875-444a-ae51-ea39fbc708f7
    name: step_15af65a5
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - description: list of user feedback (single element)
      type: string
      title: value
    outputs: []
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    variable:
      description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    operation: insert
    component_plugin_name: NodesPlugin
    component_plugin_version: 25.3.0.dev2
  f592ae1a-682f-45e0-849f-579eeb803e04:
    component_type: PluginReadVariableNode
    id: f592ae1a-682f-45e0-849f-579eeb803e04
    name: step_a8581940
    description: ''
    metadata:
      __metadata_info__: {}
    inputs: []
    outputs:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: value
      default: []
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    variable:
      description: list of user feedback
      type: array
      items:
        type: string
      title: user_feedback
      default: []
    component_plugin_name: NodesPlugin
    component_plugin_version: 25.3.0.dev2
  a6751ff9-5940-4ff0-90b4-12c7a15b8b87:
    component_type: PluginOutputMessageNode
    id: a6751ff9-5940-4ff0-90b4-12c7a15b8b87
    name: step_284a4a1d
    description: ''
    metadata:
      __metadata_info__: {}
    inputs:
    - description: '"feedback" input variable for the template'
      type: string
      title: feedback
    outputs:
    - description: the message added to the messages list
      type: string
      title: output_message
    branches:
    - next
    input_mapping: {}
    output_mapping: {}
    message_template: 'Collected feedback: {{ feedback }}'
    message_type: AGENT
    rephrase: false
    llm_config: null
    component_plugin_name: NodesPlugin
    component_plugin_version: 25.3.0.dev2
  83ea975c-1b64-46f2-9dfb-a12ee1ee8d90:
    component_type: EndNode
    id: 83ea975c-1b64-46f2-9dfb-a12ee1ee8d90
    name: None End node
    description: End node representing all transitions to None in the WayFlow flow
    metadata: {}
    inputs:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: value
      default: []
    - description: the message added to the messages list
      type: string
      title: output_message
    outputs:
    - description: list of user feedback
      type: array
      items:
        type: string
      title: value
      default: []
    - description: the message added to the messages list
      type: string
      title: output_message
    branches: []
    branch_name: next

You can then load the configuration back to an assistant using the AgentSpecLoader.

from wayflowcore.agentspec import AgentSpecLoader

assistant: Flow = AgentSpecLoader().load_yaml(serialized_assistant)

Note

This guide uses the following extension/plugin Agent Spec components:

  • PluginReadVariableNode

  • PluginWriteVariableNode

See the list of available Agent Spec extension/plugin components in the API Reference

Next steps#

Now that you have learned how to use Variables in Flows, you may proceed to FlowContextProvider to learn how to provide context for flow execution.

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# Code Example - How to Use Variables for Shared State in Flows
  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_variable.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## Define a Variable
 32
 33# %%
 34from wayflowcore.variable import Variable
 35from wayflowcore.property import ListProperty, StringProperty
 36
 37feedback_variable = Variable(
 38    name="user_feedback",
 39    type=ListProperty(item_type=StringProperty()),
 40    description="list of user feedback",
 41    default_value=[],
 42)
 43
 44
 45# %%[markdown]
 46## Define Flow Steps
 47
 48# %%
 49from wayflowcore.steps import StartStep, OutputMessageStep, VariableReadStep, VariableWriteStep
 50from wayflowcore.property import StringProperty
 51
 52FEEDBACK_1 = "feedback_1"
 53FEEDBACK_2 = "feedback_2"
 54
 55start_step = StartStep(
 56    name="start_step",
 57    input_descriptors={StringProperty(FEEDBACK_1), StringProperty(FEEDBACK_2)},
 58)
 59
 60write_feedback_1 = VariableWriteStep(
 61    name="write_step_1",
 62    variable=feedback_variable,
 63    operation="insert",
 64)
 65
 66write_feedback_2 = VariableWriteStep(
 67    name="write_step_2",
 68    variable=feedback_variable,
 69    operation="insert",
 70)
 71
 72read_feedback = VariableReadStep(variable=feedback_variable, name="read_step")
 73
 74output_step = OutputMessageStep("Collected feedback: {{ feedback }}", name="output_step")
 75
 76
 77# %%[markdown]
 78## Define a Flow with variable
 79
 80# %%
 81from wayflowcore.controlconnection import ControlFlowEdge
 82from wayflowcore.dataconnection import DataFlowEdge
 83from wayflowcore.flow import Flow
 84
 85flow = Flow(
 86    begin_step=start_step,
 87    control_flow_edges=[
 88        ControlFlowEdge(start_step, write_feedback_1),
 89        ControlFlowEdge(write_feedback_1, write_feedback_2),
 90        ControlFlowEdge(write_feedback_2, read_feedback),
 91        ControlFlowEdge(read_feedback, output_step),
 92        ControlFlowEdge(output_step, None),
 93    ],
 94    data_flow_edges=[
 95        DataFlowEdge(start_step, FEEDBACK_1, write_feedback_1, VariableWriteStep.VALUE),
 96        DataFlowEdge(start_step, FEEDBACK_2, write_feedback_2, VariableWriteStep.VALUE),
 97        DataFlowEdge(read_feedback, VariableReadStep.VALUE, output_step, "feedback"),
 98    ],
 99    variables=[feedback_variable],
100)
101
102
103# %%[markdown]
104## Execute flow
105
106# %%
107conv = flow.start_conversation(
108    inputs={
109        FEEDBACK_1: "Very good!",
110        FEEDBACK_2: "Need to improve!",
111    }
112)
113conv.execute()
114
115result = conv.get_last_message().content
116print(result)
117# >>> Collected feedback: ["Very good!", "Need to improve!"]
118
119
120# %%[markdown]
121## Export config to Agent Spec
122
123# %%
124from wayflowcore.agentspec import AgentSpecExporter
125
126serialized_assistant = AgentSpecExporter().to_yaml(flow)
127
128
129# %%[markdown]
130## Load Agent Spec config
131
132# %%
133from wayflowcore.agentspec import AgentSpecLoader
134
135assistant: Flow = AgentSpecLoader().load_yaml(serialized_assistant)