Inside a step, goto some other step. The step's memories are saved and its messages are sent right after this instruction, and before the next step is started.
Special cases:
If the target step does not exist, the conversation will be closed.
If the target step is end, the conversation is closed.
goto behaves as return in other languages: anything after a goto is ignored, the goto is immediately executed.
To reach another flow, you can also use goto flow otherflow .
onestep:goto somestep say "after the goto" /* will not be executed */goto someotherstep /* will not be executed */somestep: say "hi"someotherstep: /* will not be executed */ say "hey"
say
Send a message to the end user. For the full reference on Components
say "The quick brown fox jumps over the lazy dog."
debug
Print a simplify version of the following value. Its output is a special debug component (same structure as a Text component with a debug content_type).
If the value is a primitive (String, Number...), it will be printed entirely.
If it is an Object or Array, only the structure of the first level will be printed.
Unlike the say keyword, it can also be used inside native CSML functions:
fnis_triple_even(num):do triple = num *3 debug triplereturn (triple%2)
hold
Wait for user input: simply hold the conversation in place until the user responds.
somestep: say "What's up doc?" hold remember updoc = eventgoto end
hold_secure
introduced in CSML v1.10.0
Same as hold, except any user input that comes after that will not be saved in any CSML memory or displayable. However, you can perform operations on the value itself. This is a good use case for secret values that should not be saved in clear text anywhere in a database:
start: say "Type something super secret, I promise I won't tell!" hold_secure // indicates that the next input will be secure // Value can not be displayed back or remembered in any way say "this is a secret: {{event}}" // prevented by CSML remember impossible = event // prevented by CSMLdo impossible = event // prevented by CSML // You can however perform operations on the event, // for example checking if the value is acceptedif (event =="password") say "This is hardly a good secret!"else say "OK, good good"
This keyword should be used with extreme care. It is for example a very bad practice to ask users for their password in a chat, and it should not be used for this purpose. However, this keyword can be extremely useful to share data (personal information, short-lived secrets...) that requires extra precautions or should not be stored in clear text (or at all).
remember
Save a value to the bot's memory with the given key. It can later be retrieved (as soon as the next step) with "{{memory_item}}".
By default, the scope is bot/user/channel. The same user on a different channel, or a different user on the same channel, or the same user with a different bot will get a fresh memory instance.
// remember a hardcoded valueremember truc ="tutu"// remember a local variabledo myvar =123remember tata = myvar// overriding a local variable's scopedo myvar =123 // `myvar` has a local scoperemember myvar = myvar // `myvar` is now a globally-available memorydo myvar = myvar // `myvar` will still be available globally
do
Execute the following expression.
Usually used for executing functions without caring for its return value, or for updating values of objects or arrays.
When used in an assignment (as in x = y), the value x is saved as a local (temporary) variable.
// execute a functiondoFn("someFunc")// assign new valuesdoarray[3] ="X"doobj.val.toto =123// however, this will fail:remember myarr = [1,2]domyarr[42] =1 // the array needs to have at least the requested number of itemsremember myobj =Object("key"="value")domyobj.missing.otherkey =1 // all the parent properties must exist and be objects as well
forget
The forget keyword lets you forget memories selectively, or globally.
forget something // forget a single memoryforget [something, otherthing, thirdthing] // forget several memories at onceforget * // forget EVERYTHING (dangerous!)
Root-level keywords
These keywords can only be used at the root of the flow, outside of any step
const
Declare constant values that are accessible and immutable across the whole flow. Two different flows can have a different set of const or different values for the same const!
const MY_CONST =42start: say "The value of MY_CONST is {{MY_CONST}}" // The value of MY_CONST is 42do MY_CONST =14 // Forbidden! MY_CONST is immutable
Save any value as a local variable, only available within the step. Local variables remain in memory after the step is done.
doButton("A") as btn1// is equivalent todo btn2 =Button("B")// say and save a component at the same timesayQuestion(title="Pick one", buttons = [btn1, btn2] as btnlist) as myquestion// repeat the same questionsay myquestion
if / else if / else
Simple logic operators if, else if and else. See examples.
// regular notationif (1>2) { say "I have my doubts"} elseif ("mi casa"=="tu casa") { say "Welcome home"} else { say "The force is strong with you"}// shorthand notationif (sky =="blue") goto beachelsegoto restaurant
foreach
Iterate over each element of an array.
do array = ["a","b","c"]foreach (val, index) in array { say "at position {{index}} is element with value {{val}}"}
while
A simple loop with a condition check at every turn
do i =0while (i <3) { say "i = {{i}}"do i = i +1}
break, continue
Exit from loop early, or skip an iteration
remember lightsabers = [ {"color": "red","owner": "Kylo Ren"}, {"color": "purple","owner": "Mace Windu"}, {"color": "yellow","owner": "Rey Skywalker"}, {"color": "green","owner": "Yoda"}, {"color": "red","owner": "Darth Vader"}, {"color": "green","owner": "Luke Skywalker"}, ]foreach (ls) in lightsabers { // we want to skip any red lightsaberif (ls.color =="red") continue say "{{ls.owner}} had a {{ls.color}} lightsaber" // we want to stop after we find the first green lightsaberif (ls.color =="green") break}say "There might be even more lightsabers!"
Deprecated keywords
match (deprecated)
This syntax is obsolete, but for backwards-compatibility reasons remains valid CSML. However, prefer using the event.match(...) alternative which is much more versatile.
Whether or not a variable "equals", in any way, another variable.
doButton( title ="I agree", accept = ["OK","yes","right"]) as btn/* a direct click on the button will match the button *//* typing "yes" will match the button *//* typing "of course" will not match the button */if (event match btn) { // Note: this is equivalent to event.match(btn) say "good"} else { say "not good"}
use..as (deprecated)
This syntax is obsolete, but for backwards-compatibility reasons remains valid CSML.
See as keyword.
use 42 as answersay "The answer is {{answer}}"
Operators
Mathematical Operators
In CSML, you can use the 4 basic mathematical operators +, -, * and /, as well as the modulo operator %. The regular order of operations applies.
Additionally, since CSML v1.8.0, you can use the shortcut += and -= operators to add/subtract and assign values at the same time:
do i =8do i +=5say "i = {{i}}" // i = 13
String Concatenation
Starting with CSML v1.8.0, you can concatenate two or more strings together by using the + sign:
do val1 ="John"do val2 ="Nutella"say val1 +" likes "+ val2 // John likes Nutella
It is also possible to use string templating to insert any value in another string:
do val1 ="John"do val2 ="Nutella"say "{{val1}} likes {{val2}}" // John likes Nutella