Memory is a general purpose container that acts more or less like a JSON object.

Saving data to Memory

You can save to Memory:

  • literal values, eg. [1, 2, "foo"], 3, "this is a string"
  • results of an expression, eg. nlu.intent, memory.someArray[0], memory.array.length(), nlu.intent = "blockCard"

The following list contains all of the blocks that are used to save data to Memory:

  • Custom block
  • Integration block
  • Ask block

Custom block

This is the only block that features Memory input fields.

Memory input fields serve as the primary means of saving data to Memory, as well as using Expression language (AEL) to process data.

To save data to Memory, you need to define its key and value.

Key

A key is like a nickname given to some data, which allows you to easily find and use that data later on. It's like assigning a name to something so that you can quickly retrieve it whenever you need it.

It has to be a string with no whitespaces nor special characters except for -, _ or . (although a dot has a special function). For example, if the defined key is birthdate, saved value will be accessible by using such expression: memory.birthdate.

Value

A value is the data you want to assign to the key.

Value can be of any data type, including:

Value can be defined as:

  • a literal value, eg. [1, 2, "foo"], 3, "this is a string" or
  • the result of an expression, eg. nlu.intent, memory.someArray[0], memory.array.length(), nlu.intent = "blockCard"
Example of using Memory input fields and AEL to save data to Memory

Example of using Memory input fields and AEL to save data to Memory

👍

Using dot notation in key to define object's property

Memory acts like a JSON object, so its values can be objects as well. You can use dot notation while defining key to create an object and define one of its properties at once. For example, user.surname would store an object as a Memory value. You could later use memory.user to access the whole object, and memory.user.surname to access the defined property.

Saving multiple Memory values in one Custom block

You can save to Memory as many values as you need in one Custom block. Those values are evaluated one after another, which means that you can use previous ("higher") Memory values when defining the next ones:

`memory.fullName` uses values saved in the same block: `memory.name` and `memory.surname`.

memory.fullName uses values saved in the same block: memory.name and memory.surname.

Note that you can't save the same key twice in the same Custom block. If you want to update previously stored Memory value, use another Custom block.

Integration block

Any time Integration block is being used to send a request to an API, at least two values are being saved to Memory: memory.response and memory.success. You can define more output values with custom names for any Integration. Those values will be saved to Memory as well.

Ask block

With Ask block, you can request a specific variable from the user. If the variable is recognized, it is saved to Memory with current context's name as a prefix, eg. memory.contextName.variableName. This method is not recommended anymore due to lack of flexibility.

Accessing Memory values

Accessing Memory values means printing them out in Responses or using them in AEL expressions.

You can access Memory values with dot notation: memory.someVariable where someVariable is the key.

If the value stored in Memory is an object, you can use either dot notation or bracket notation (memory.someObject["someProperty"]) to access its properties.

To check the whole Memory object, you can use the debugger built into the chat tester or print it out using the expression: {memory}.

Example of saving to and accessing Memory values. `memory.today` is accessed and formatted by `memory.formattedDate`. `memory.formattedDate` is accessed by Response to be printed out to the user.

Example of saving to and accessing Memory values. First, memory.today is defined; then, it is accessed and formatted by memory.formattedDate; in the end, memory.formattedDate is printed out to the user as a part of the Response.

Clearing Memory value

If you want to clear a value saved to Memory, define its value as null.

🚧

Cleared Memory when transferring between flows

Be careful when transferring between flows. The whole Memory is cleared whenever you transfer to another flow - except for the values defined in "Transfer to flow" block.

What Memory can be useful for: examples

The following section provides some examples of how Memory can help with building bots in Automate:

Saving NLU results & user choices for later

Every time you use Request User Input option in a block, the previous NLU results are overwritten. To save them for later, use Memory. You can either save all of the results using nlu.intentsList for intents and nlu.variablesList for entities, or you can save only specific information. Go to NLU API to learn more.

Saving current NLU results to Memory

Saving current NLU results to Memory

As these NLU results will be stored as arrays of objects, you can later access, edit and print them using Arrays and Objects methods.

Saving responses from API integrations for later

Every time you use Integration block to send a request to external API, its response is saved as memory.response, and information about success is saved as memory.success. These two Memory values are overwritten any time you send another request (i.e. use another Integration block). You can use Memory input fields in Custom blocks to save the whole memory.response - or just a part of it, as they are usually JSON objects.

Saving current API response to `memory.client` and `orders` property to `memory.clientOrders`

Saving current API response to memory.client and orders property to memory.clientOrders

Setting default values and mocked data

Setting default values and configurations in Memory is a recommended approach to use consistent settings throughout your project. For instance, you can store the bot's name or default intent score required in output conditions. This allows you to easily use them anywhere in flows and make quick changes to them when needed.

Example of initial settings in Memory

Example of initial settings in Memory

Custom flow settings (advanced steering, loops, debugging & testing)

As mentioned before, Memory is the place to perform various advanced operations using Expression language (AEL) or JavaScript. Here is one example of such operation: creating a simple counter:

Looping through blocks using AEL to create a counter

To create a counter or to loop through an array, you can use combinations of blocks and AEL operations. Below, you'll find an example of implementing simple counter into your project:

{"copiedNodes":[{"id":"60754914-62ad-45cf-a3d6-e49e88513d18","name":"Start context","tags":[],"type":"start","outputs":[{"id":"0b0c4ccb-fb8f-46a9-a27a-e1a67cb10a8b","name":"","type":"Regular","conditions":[]}],"position":{"x":-23,"y":0},"commands":[],"memory":[],"redirect":[],"metadata":{},"inputParameters":{},"conditionalResponses":[]},{"id":"a846fe35-05dc-486c-a27f-9bb2fd7d24df","name":"Set counter to 0","type":"custom","position":{"x":199,"y":0},"outputs":[{"id":"bc9f0994-1af7-4f1e-aa49-3dee71d5c4b2","name":"","conditions":[],"type":"Regular"}],"tags":[],"responses":[""],"quickReplies":[],"attachments":[],"requestUserInput":false,"nluModel":"","useNER":true,"contextReferenceName":"","memory":{"counter":{"value":"0","useJS":false,"index":0}},"commands":[]},{"id":"a34aae2e-1aab-4814-8983-7643a541f982","name":"Point","type":"quick-point","position":{"x":682,"y":135},"outputs":[{"id":"1e9312ed-e110-4e37-864d-6ad28f69f446","name":"","conditions":[],"type":"Regular"}],"tags":[],"requestUserInput":false,"nluModel":"","useNER":true,"commands":[]},{"id":"84ce3676-a32f-4ecf-933b-3e36fdf1eefa","name":"Point","type":"quick-point","position":{"x":402,"y":144},"outputs":[{"id":"df4efdcf-0d3a-4d53-abf9-c543f384e0c2","name":"","conditions":[],"type":"Regular"}],"tags":[],"requestUserInput":false,"nluModel":"","useNER":true,"commands":[]},{"id":"72c2fcf4-7ee6-4bed-8c88-dc8e8a3fc752","name":"Increase counter","type":"custom","position":{"x":439,"y":-1},"outputs":[{"id":"74e4bec2-bdf0-483f-a552-eec429f7afed","name":"Add 1","conditions":[{"type":"and","left":{"value":"system.userInput","useJS":false},"operator":"==","right":{"value":"\"+1\"","useJS":false}}],"type":"Regular"}],"tags":[],"responses":["Counter: {memory.counter}"],"quickReplies":["+1"],"attachments":[],"requestUserInput":true,"nluModel":"","useNER":true,"contextReferenceName":"","memory":{"counter":{"value":"memory.counter + 1","useJS":false,"index":0}},"commands":[]}],"copiedConnections":[{"cssClass":"jtk-connector--bc9f0994-1af7-4f1e-aa49-3dee71d5c4b2-72c2fcf4-7ee6-4bed-8c88-dc8e8a3fc752 ","data":{},"sourceId":"bc9f0994-1af7-4f1e-aa49-3dee71d5c4b2","targetId":"72c2fcf4-7ee6-4bed-8c88-dc8e8a3fc752"},{"cssClass":"jtk-connector--0b0c4ccb-fb8f-46a9-a27a-e1a67cb10a8b-a846fe35-05dc-486c-a27f-9bb2fd7d24df ","data":{},"sourceId":"0b0c4ccb-fb8f-46a9-a27a-e1a67cb10a8b","targetId":"a846fe35-05dc-486c-a27f-9bb2fd7d24df"},{"sourceId":"74e4bec2-bdf0-483f-a552-eec429f7afed","targetId":"a34aae2e-1aab-4814-8983-7643a541f982"},{"sourceId":"1e9312ed-e110-4e37-864d-6ad28f69f446","targetId":"84ce3676-a32f-4ecf-933b-3e36fdf1eefa"},{"sourceId":"df4efdcf-0d3a-4d53-abf9-c543f384e0c2","targetId":"72c2fcf4-7ee6-4bed-8c88-dc8e8a3fc752"}],"copiedFromContextId":43383}
Screenshot of a counter. Paste code into Automate context to try it out

Screenshot of a counter. Paste code into Automate context to try it out


What’s Next

Learn about AEL's methods and APIs: