Variables & Constants
Variables¶
Variables in Bubblescript can be global and local, meaning they are available from anywhere in Bubblescript or they are only available in the current dialog. Some variables are made available by the system, others are created by the user in the scripts by assignment. All variables can be seen in the panel below the script editor.
user.id
user.frontend
user.first_name
user.last_name
user.presence
...
Variables that start with user.
are special in that they are saved
inside the user record the bot keeps. Note that these are shared
between all conversations between a user and the bot. Those user
variables are also automatically added to the CSV export in the
contacts section of the studio.
Global and local variables¶
Every variable that starts with a "_" is considered a local
variable. This means that the variable only exists within the dialog
or task it was created in. It's value is stored even if another dialog
is invoked in the mean time, but the other dialog won't have access to
that variable, the same is true for tasks. Local variables are great
when they are combined with repeat
loops and conditionals
. They
can have a name that represents what they stand for without having to
worry that a global variable might be overwritten.
Predefined variables¶
Some variables are set (when triggered) by the runtime itself:
-
user
— User-specific data. Data that isremember
ed insideuser
gets stored inside the CRM and is accessible across all of a user's conversations. Besides remembered data, the following fields are always available: -
user.first_name
user.last_name
user.profile_picture
user.timezone
user.locale
-
user.extra
-
bot
— Information about the current bot: -
bot.id
— Unique identifier for the bot bot.title
— Name of the botbot.purpose
— The bot's descriptionbot.privacy_url
— URL to the bot's privacy policybot.profile_picture
— URL to the bot's profile picturebot.locale
— Primary locale the bot speaks (e.g."en"
)bot.extra_locales
— List of additional locales that the bot can speak (e.g.["de", "fi"]
)bot.timezone
— The default timezone the bot is configured forbot.inserted_at
— When the bot was first createdbot.tokens
— List of bot-level integration tokens-
bot.frontends
— List of enabled channels for the bot (e.g.["whatsapp", "phone"]
) -
conversation
— Information about the current conversation: -
conversation.g
— The channel-specific 'conversation ID'; on single-converation channels (e.g. Whatsapp) this will be"main"
. conversation.tags
— List of tags that are set on the conversationconversation.frontend
— The type of the channel, e.g."whatsapp"
conversation.locale
— The current locale that the bot speaks in the conversationconversation.debugging
— Whether or not the conversation is running in the studioconversation.operator
— When an operator participates in the conversation, this containsfirst_name
,last_name
, etc.conversation.addr
— String representing the unique address of the conversationconversation.origin
— For web chats, the URL of the page the conversation started on-
conversation.referrer
— For conversations that were redirected from another conversation, contains the redirect parameters (like.bot
for the bot ID). -
dialog
— Contains information about the execution history and stack -
dialog.history
-
dialog.stack
-
message
— Data related to the user's last message -
answer
— The last response to anask
-
location
— The most recently received location pin -
location.lat
-
location.lon
-
attachment
— The most recently received media attachment -
attachment.type
attachment.url
attachment.caption
-
attachment.metadata
-
event
— The most recently received event -
event.name
-
event.payload
-
schedule_id
— The id of the most recently scheduledemit
visitor
— Visitor-specific data (only accessible within bots running in the chat widget with visitor-tracking enabled)-
nudge
— Set when a conversation was started from clicking a nudge -
frontend
— Channel-specific information about the connected channel. Only one of the channel-specific subfields will be set: -
frontend.email
— An object with the following fields:sender_name
,public_email
,private_email
,threading
. -
frontend.facebook
— An object with the following fields:name
,picture
,about
. frontend.phone
— An object with the following fields:number
,beep
,record
.frontend.telegram
— An object with the following fields:username
,info
.frontend.web_pwa
— An object with the following fields:domains
frontend.web_widget
— An object with the following fields:domains
,visitors
frontend.whatsapp
— An object with the following fields:phone
,provider
,hosting_type
,reengagement_template
,deflection_template
,lock_reenagement
Don't set these reserved variables yourself as they will be overwritten!
Variable types¶
The variable types that can be used in Bubblescript are similar to the variables in Elixir, please visit the link for an in-depth explanation. Any reference in their documentation to the word "iex" is similar to a line typed in Bubblescript.
String¶
A string is text and is always typed in double quotes ("). If you want
to use double quotes in your string, you should escape
them in the
following manner: "this string contains \"double quotes\"".
Strings interpolation¶
Strings can be interpolated by adding #{variable_name}
in the strings
themselves. What this means is that the value in the variable will be added to
the string. Think of this as the "find and replace" function in a text-editor.
This is useful for creating pieces of text that function as templates for
responses or questions.
Examples:
dialog greeting do
name = ask "What is your name?", expecting: @text
say "Hi #{name}"
end
Accessing nested values¶
The following example shows how the value of a Map is displayed by using the key in string interpolation.
user = %{"name" => "Hank"}
say "Hello #{user.name}"
The .
notation used here is the same way a key of a Map is accessed.
List¶
A list can be seen as a sequence of things, where these things can be strings, maps, or other variables. To get the first item in a List you can use the bracket notation [0] Note: List like arrays in most programming languages start at 0 zero!
list = [1, 2, 3]
say list[0] # 1
say length(list) # 3
To iterate over the full array you can use repeat
:
dialog iterate do
list = [1, 2, 3]
repeat element in list do
if element == 3 do
say "and.."
end
say "item #{element}"
end
end
Map¶
A Map is a key->value data structure that allows a value to be stored in with a key. If we would like to see the value, the key is our reference point with which we can find the value.
simple_map = %{"name" => "Bert"}
numbers_as_keys = %{1 => "one",
2 => "two"}
# Here we create a map that will describe a car
car = %{"brand" => nil,
"engine" => %{}} # notice that the value of a map can also be another map.
Note that you can create these maps yourself as well:
car.brand = "Volvo"
car.engine.hp = 200
# car == %{"brand" => %{"engine" => %{"hp" => 200}}}
Autovivification¶
If a key is not found in the map when you assign it in the map, it
will be automatically be created for you. In the example above, when
200 is inserted in the key hp
the preceding map engine will be
created automatically.
Constants¶
Variables starting with an @
are treated as constant values. These
can only be defined outside a dialog.
@constant "key"
@version 12
@message "Hello and welcome!"
dialog main do
say @message
say "My version is: " + @version
end
notice that you do not need to use an assign (=) character for assigning values into a constant!
Operators¶
= (assignment)¶
variable = ask "what's your name?"
variable = "string"
variable = 1
variable = [1,2,3]
variable = first [1,2,3]
addition (+)¶
The +
operator has superpowers.
- It performs addition on numbers:
1 + 3 == 3
- It concatenates strings:
"a" + "b" == "ab"
- It can glue lists together:
[1] + [2, 3] == [1, 2, 3]
- It can even glue lists together when one element is not a list:
1 + [2, 3] == [1, 2, 3]
- It merges maps:
%{"a" => 2} == %{"a" => 1} + %{"a" => 2}
- When it encounters
nil
on either side of the+
, it ignores it:[1, 2] + nil == [1, 2]
subtraction (-)¶
The -
operator is super powered as well.
- It performs regular subtraction:
3 - 2 == 1
- When encountering strings which are numbers, it converts them to numbers:
"100" - "10" == 90
- It can be used to remove elements from a list:
[1, 2] - [1] == [2]
- It can be used to remove substrings from strings:
"paap" - "aa" == "pp"
In all other cases, it raises an error, for instance when you try to subtract a number from a string.
boolean operators¶
The following operators are supported:
a && b # AND
a || b # OR
!a # NOT
a == b # EQUALS
a != b # NOT EQUALS
a <= b # IS SMALLER OR EQUAL TO
a >= b # IS LARGER OR EQUAL TO
a < b # IS SMALLER
a > b # IS LARGER
pipe operator¶
The pipe operator, inherited from Elixir, takes the expression on the left and uses it as the first argument to the function call on the right.
# These two are equivalent:
flatten([1, [2], 3])
[1, [2], 3] |> flatten()
The pipe operator can be used for multiline expression. This can be especially useful when you're performing a sequence of steps. To give a contrived example:
uppercase_b =
["a", ["b"], "c"]
|> Array.flatten()
|> Array.item(1)
|> String.upcase()
assert uppercase_b == "B"
Platform-specific constants¶
The following constants have special meaning, when they are defined.
@timeout
- defines how long the script will be allowed to run after the last message that a user sent. After the conversation expires, the chat process is suspended until it is activated again (by a user message or an event sent to the bot). When the conversation resumes, the__resume__
dialog is executed and after that the conversation continues on the place where it was suspended.@delay
- defines the standard delay (in seconds) after the bot shows a message to the user@typing_indicator
- defines the standard delay (in seconds) how long the typing indicator should be displayed before any message is shown to the user.@ask_timeout
- defines how long to wait for a user to give an answer on a question (ask)@duckling_reftime
- When set to"start_of_day"
, all Duckling-related message triggers are calculated with a reference time from the start of the day instead of the current time.
Example:
@ask_timeout :infinity
@timeout "15m"
@delay 1
@typing_indicator 1
# Other time formats
@timeout "1h"
@timeout "60s"
@timeout "200ms"
Besides these globals that can be overwritten there are some read only globals that you MUST NOT overwrite:
@intents
- is a list of all intents defined in the intents files (read only)@skills
- is a list of the skills (modules) this bot has (read only)
Note: the intents and data files you create also create constants that can conflict with these system constants. So don't create an intent or data file with the name
skills
orintents
Intent constants¶
When you create new intents via the training panel or directly in the training yaml file they will be exposed in the code as constants. So the @yes
constant refers to the yes
intent.
Loading constants from a file¶
When adding a YAML or a JSON file in the DialoX studio, the contents of that file is exposed in a constant which is named after the JSON/YAML script file name.
Data files are a convenient way to keep data outside the bot script contents, but still embedded as part of the bot.
For instance, when you create a YAML file called people
with the
following contents:
- name: Arjan
age: 38
- name: Pete
age: 22
- name: Julie
age: 32
The contents of the people
file is now accessible in your bot script
under the constant @people
. It can be used like this:
repeat person in @people do
say "Name: " + person.name
say "age: " + person.age
end
When a data file is defined in a folder, say, a data file named
data/people
, the slash in the filename will be transliterated into an underscore, so that in this case, the constant name becomes@data_people
.Read more about data files and content management
Constant accumulation¶
The accumulate
top-level statement can be used to merge constants from
different files together into a list. The use case of this is that sometimes
there are various skills in a bot which all contribute to some list
constant. This cannot be done using a normal constant because constants
overwrite each other when they are defined in multiple files.
So by prepending the constant with the accumulate
keyword, the value is forced
to be a list and collected from all script files.
As an example, when you have in one file:
accumulate @list 1
And in another:
accumulate @list 2
The @list
constant will contain the list [1, 2]
.