Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Available in CSML v1.5+
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The event
keyword is a special variable in CSML that contains whatever the user did last. It can be generally be used as a simple string, but it is in fact a much more complex object that contains a lot of information about what the user did.
In its essence, event
contains the full message payload as received by the bot. There is a type and a content. The content is an object that contains a text, a payload, a url, other objects... it can be anything, and in general, its content can be derived from the events type. However, using it as "{{event}}"
in a string (or simply in say event
without any curly brace and double quote) will behave as a string.
event
contains a number of useful methods that can be used to perform various operations.
In many cases we want to find whether the user's input matches some value to perform conditional logic. For example, in the following example, we want to make sure that the user clicked on the right answer:
In some cases, you may also want to make sure that the user clicked on a button or typed any accepted response, in which case you can add several parameters to the .match() method:
The result of event.match(...)
is whatever was matched, or Null
. So the above example, if using the language to its full potential, could also be used like this for even more control over what value is remembered:
Similar to event.match()
, but takes an array as argument. It also returns the matched value, if any. In many places, it is easier to use as listing all the individual items of the array. The same example as above would now read:
Returns the type of event. For example, if the user typed something, event.get_type()
will be "text"
. Or if the user clicked on a button (which yields a payload
the type of event is "payload"
.
To access any value in the content body of the event, simply use the dot notation with its expected property name. If it does not exist, this will return Null
.
Any good chatbot probably needs to be able to save and work with information gathered from the user at some point. The memory API provided in CSML is one of the most important parts of the language.
As you will see, some variables need to be stored in a long-term memory, while some variables are just temporary variables needed for local work. Some information is also provided by the context of the user and injected by the channel itself at the beginning of the conversation.
In this chapter, we will see how to save and use various types of memories depending on your scenario.
To output the value of any variable in a string, you can use the string interpolation helper: double curly braces {{ }}
.
This makes it extremely easy to concatenate multiple values of any type into a single string. Objects, arrays and numbers will be stringified automatically and missing properties will be evaluated as NULL
.
To concatenate two strings, you can also use the +
operator (starting in CSML v1.8.0):
CSML message components all have a matching message format for client use in regular JSON
. They can be extended by adding additional properties to the content
wrapper.
Component payloads can be included into one another seamlessly. For example:
CSML (Conversational Standard Meta Language) is an Open-Source, Domain-Specific Language designed for developing rich conversational experiences easily. It makes creating powerful chatbots extremely easy.
Written itself in Rust, the purpose of this language is to simplify the creation and maintenance of rich conversational interactions between humans and machines. With a very expressive and text-only syntax, CSML flows are easy to write and understand, making it easy to deploy and maintain conversational agents.
CSML natively handles short and long-term memory slots, metadata injection, and connecting to any third party API or injecting arbitrary code in any programming language thanks to its powerful runtime APIs.
By using the CSML language, any developer can integrate arbitrarily complex conversational agents on any channel (Facebook Messenger, Slack, Facebook Workplace, Microsoft Teams, custom webapp, ...) and make any bot available to any end user. In addition to the language itself, , an online, full-featured development and deployment platform, comes with a large number of channel integrations that work out of the box, but developers are free to add new custom integrations by using the CSML interfaces.
This is a simple CSML flow example, which describes a conversation between a user and a machine.
A CSML flow
contains several steps
, which are defined by a name (which must be unique within a flow) followed by a colon. Each step contains instructions on how to handle the interactions within the step, what to say, what to remember, where to go. The syntax is very descriptive and contains very few keywords.
This goal of the example flow on the right is to retrieve the name of the user.
To do so, we will first check if we already have it in memory. If so, we can use it to greet our user, and close this conversation. Otherwise, we can go to a different step and simply ask for it. When the user responds, we will be able to remember
the name for future use, and close the conversation.
This simple flow shows a few of the features of the language. There are many more, which we will go into in detail now!
Local or temporary variables are only usable within the current step. It is rather a way to write more readable, expressive code. But they are really powerful, because they allow you to do everything that a regular memory does, but temporarily. For more information about local variables, see the as
keyword.
Local variables are useful for temporary calculations. You do not want to memorize your internal temporary steps, rather save useful information about the user.
Long-term memories on the other hand are at the core of the purpose of CSML. When two persons converse, they constantly memorize information, which they can reuse in other discussions. For example, if I gathered that my friend likes Iron Man, I might propose later that we go see Captain America together. I do not have to ask them again about their favorite film, because I already learned this information before, even if it was in a different conversation, even if the topic of that conversation might have been completely unrelated.
The memory API is very powerful: by default a bot never forgets anything about the current user. For more information, see the remember
keyword.
CSML provides a _memory
global, read-only variable, which contains all variables saved until now for the current user. This especially useful if you need to debug the state of a user's memory at any given step:
Variables and memories (of any type) can not be larger than 50KB. Using data larger than 50KB in variables (for example as the return value of a function) may result in undefined behavior. Also, please note that messages larger than 30KB in size can not be displayed in the test webapp.
As an open-source programming language, there are several ways you can get started with CSML, either by compiling the sources yourself, using Docker, or using , a free online development environment provided by .
The easiest way to create CSML Chatbots is by using the free online development playground available at . No dependencies, no installation, no signup required!
➡ Try CSML Playground now on !
You can also create a free account on CSML Studio, a professional online development and deployment tool for all your CSML chatbots. Read more , and head over to the !
CSML Studio includes everything you need to create, develop and maintain your chatbots. You get a code editor and test chatbox, built-in services to author functions and install custom or managed integrations, deploy to many different communication channels including Messenger, Workplace Chat, Microsoft Teams, Slack, Whatsapp... and monitor the usage with custom analytics.
➡ Try CSML Studio now on !
To run CSML on your own machine, you will need a way to run the engine (CSML comes with bindings for nodejs or directly in rust), as well as a database. Optionally, you will also need a custom App
runtime ().
explains how to run the CSML engine on your own server. It may be a useful starting point for a custom installation of CSML!
We provide an easy-to-use docker image to run CSML on your own computer. To get started, follow the instructions .
We provide builds for macOS and linux (arm64) for every new version of the CSML engine. You can find them on the releases page of the . For the latest available version, visit .
CSML is able to handle many types of messages by default.
To send a message to the end user, simply use the keyword say
followed by the message type you want to send.
You can style text using Markdown. Some channels however only partially support Markdown (Messenger for example only allows bold, italic, strikethrough, but not tables), so don't get too fancy there.
Below is a list of default valid message components, which are automatically converted to nicely formatted messages for the channel in which the user is talking with the bot.
Components may receive additional optional parameters to accommodate the needs of certain channels.
For example, in the Messenger channel you can add a button_type="quick_reply"
parameter to the Question
component to provide a different type of buttons.
A conversation with a chatbot is not very different from a human-to-human dialogue: sometimes the user talks, sometimes the bot talks.
CSML provides a solution when you need the chatbot wait for the user's input: using the hold
keyword, the chatbot will remember its position in the conversation and simply wait until the user says something, then continue from there.
When receiving an event from an end-user, the CSML interpreter will try to:
match it with a new flow,
or consume it in the existing conversation,
or trigger the default flow as defined in the bot settings,
by order of priority.
CSML Events are made available in the script when a step is triggered by a user's input. The event
object is a complex structure which contains a lot more than just the string that was typed by the user. It contains a lot of information that is used by the CSML interpreter, for example the custom button payload to match a list of choices offered to the user. This makes it easy to handle both a click on a "OK" button or the user typing the word "yes".
By default, events are only expected when:
the flow was just triggered, the current step being triggered is start
the bot asked something to the user, and is waiting for the user's input at the same step
In those cases, a local variable, event
, is made available, with the content of the user request. When no event is available, event is set to NULL
.
The maximum theoretical size of a say
payload is 16KB. However, each channel will have different limitations depending on the type of component. For a Text
component for example, most channels are limited to a few hundred characters.
Please refer to each channel's official documentation to find out the practical limitations of each component.
CSML is written in Rust. You can find the source code of the CSML interpreter and engine on , and compile it from source as per the instructions.
name
description
fallback
Text(string)
Output a simple string (with no styling attached). This is also the default type, alias of say "string"
. This component supports Markdown on channels that allow text formatting.
Wait(number)
Wait number
milliseconds before sending the next message
Typing(number)
Display a typing indicator for number
milliseconds
Wait(number)
Url(string, text="text", title="title")
Format string
as the URL. Optionally, the text and title parameters can provide a way to make "nicer" links, where supported.
Text(string)
Image(string)
Display the image available at URL string
Text(string)
Video(string)
Display the video available at URL string
. Supports Youtube, Dailymotion and Vimeo URLs, or mp4 and ogg.
Url(string)
Audio(string)
Display the audio available at URL string
. Supports Soundcloud embed links, or mp3, wav and ogg.
Url(string)
Button(string)
Display string
inside a clickable button
Text(string*)
Question(title = string(, buttons = [Button]))
Display a list of buttons with a header of string
. Title parameter is optional.
Text(string) + list of buttons
Card(title="string", buttons=[Button], image_url="string")
Display nicely formatted content in a Carousel
component (on supported channels). Only title is mandatory.
Question(title, buttons) or Text(title)
Carousel(cards=[Card])
Display a list of Card
components in a carousel (on supported channels). The cards parameter is mandatory.
Inside any given step, a number of global variables are made available to the developer. These variables include past memories, step context, and request metadata. Some of these variables are available globally, including in CSML functions:
event
: contains the user input, or NULL
when empty. See The Event.
_metadata
: read-only object that is injected into the conversation by the channel.
Usage: _metadata.something
_env
: read-only object containing the bot's defined environment variables.
Usage: _env.something
_memory
: read-only object containing the user's current memory state. This is especially helpful if you need to print the full state of the user's memory for debugging purposes!
The _metadata
global contains user-level context for each request.
This memory type is injected by the channel at the beginning of the conversation and contains any data that the channel already knows about the user that can be used in the conversation later. For example, this could include the user's full name or email address, their job title, where they are from...
The _context
can be found under _metadata
and contains current_step, current_flow and default_flow
This memory type is injected and updated automaticaly at the start of each step
The _env
global contains bot-level context for the entire bot and is shared across all users of the bot.
This memory type is injected by the bot itself and is meant to contain any data that the bot would need for common tasks across all users. For example, this is where you store the API keys, endpoints, feature flags...
A flow is made of at least one step (called start
), but can also contain as many steps as necessary. You should think of steps as individual, simple bits of logic, linked inside the same conversation topic (which is the flow).
To go from one step to the next, you can simply use the keyword goto
(or goto step
) followed by the name of the step.
To finish a flow (and close the conversation), add goto end
.
If, at the end of a step, the goto end
instruction is omitted, the conversation will be closed anyway.
In other words,goto end
can be used to exit of a conversation early at any point, but it is implicitly added at the end of all steps if no other goto
instruction is present.
Similarly to navigating between steps of the same flow, you can go to the beginning of any other flow by using the goto flow
keyword. This will trigger the start
step of the target flow and close the current flow, so coming back to the first flow will actually go back to the beginning of that flow.
Introduced in CSML v1.2
If you want to reach a specific step in a specific flow, you can use the @ notation:
This is the universal way of navigating between steps and flow. The above two methods are actually special cases of this notation:
When the @flow_name
part is not specified, CSML interprets it as "in the current flow". So goto stepname
actually is shorthand notation for goto stepname@current_flow
, where current_flow
is dynamically matched from the name of the current flow, and works accordingly.
When the step_name
part is not specified, CSML interprets it as start
. So as @
means "flow", goto @flow_name
is the same as goto start@flow_name
which is also the same as goto flow flow_name
.
Introduced in CSML v1.5
As you can see above, steps and flows use strings as identifiers, but they are expressed without double quotes "..."
. In order to navigate to dynamically set steps or flows, CSML adds a special syntax, similar to the dereference pointer concept in other languages.
To go to a variable step or flow, you can reference the variable name prefixed with a $
sign:
Any of the syntaxes presented above are supported. For instance:
Please note that dot notation (accessing child properties in an object or array, i.e a.b
) is not supported in variable flow and step names.
CSML is a dynamically-typed language, even though it is written in Rust, a strong-typed, memory-safe, low-level language. It can handle a lot of different types but some magic happens behind the scenes to make it as easy for the developers to use the language.
In this section, let's learn more about how CSML handles the various quirks a chatbot needs to solve!
CSML is able to natively understand literal types (int
, float
, string
, ...).
integer
and float
are separate types, but most of the time you should not have to worry about it and consider it as a more generic and virtual number
type.
You can also express booleans with true
or false
.
Since CSML v1.1, you can also use \n
, \t
, \r
, \
and "
characters in strings, with proper escaping (\
and "
must be preceded by a \
while a single \
will be ignored). For example:
NULL
is its own type. Missing values evaluate to NULL
. The CSML interpreter will automatically parse the object with the usual dot notation x.y.z
and detect the type of the resulting property. If one of the properties in the chain does not exist or is not an object itself, it will evaluate to NULL
.
You can create an object by returning a JSON-like object from any function, or directly in the CSML code with the Object()
helper function or by using a shorthand notation similar to JSON format.
You can also iterate over an array (represented by items inside square brackets: ["a", "b", "c"]
) with the foreach
keyword, and access any of its items by using its index in square brackets notation: items[2]
.
Note that foreach creates a copy of each item as it iterates over the array. So for example, in this next example, the array is not modified:
You can modify the contents of an array either by assigning a new value to any of the items in the array, adding new items at the end with array.push(elem)
or removing the last element with array.pop()
.
You can also use Array methods to apply changes or get data from arrays.
To print any value as a string, simply use the Text(value)
component or use the curly-brace template syntax "{{value}}"
The CSML engine is able to automatically handle the execution of any payload, any code, in any language, thanks to the built-in App()
macro. With CSML Apps, you can integrate your own business logic, on your own servers, in your language of choice.
When used together with custom serverless function runtimes (cloud-based such as AWS Lambda, Azure Functions, Google Cloud Functions), or on-premise with FnProject, OpenFaas or OpenWhisk), CSML Functions are a good way to execute custom business logic outside of the context of the conversation.
Deprecation notice: the original Fn()
notation for calling Apps (formerly called Functions) in your CSML code has been replaced by the newer App()
built-in as of CSML v1.5. Both notations will continue to work until CSML v2 is released, but this documentation will only reference the new App()
usage from now on.
App
on CSML StudioWhen using the CSML Studio, the heavy setup of creating an App
runtime is already done for you, which means that you can easily import functions in java, python, nodejs, go... without any additional setup, simply by uploading your code and calling the function in your CSML script.
CSML Studio also comes with many ready-to-use integrations that are installable in one-click.
App
callsTo execute external functions in any programming language when provided a fn_endpoint
.
For example, when a App
is called, a HTTP POST request will be performed to the provided fn_endpoint
with the following payload:
The endpoint should return a JSON payload, formatted as follows:
If the function fails, or returns an invalid payload, CSML will convert it as a Null
value.
The following repository provides an easy way to run your own nodejs runtime: https://github.com/CSML-by-Clevy/csml-fn-endpoint-node
Follow the instructions to install and add your own apps!
As in any turing-complete programming language, CSML is able to handle any type of logic, in the form of loops and if/else statements.
As a CSML developer, you can easily implement any logic based on any variable or event, and very expressively decide how your conversation should be handled. Own of the main advantages of CSML is its descriptive textual interface, making it easy for anyone to understand the logic. It just makes sense and hides all the complexity of decision trees behind the simple concepts that every developer knows and uses.
A large part of developing CSML flows is about finding out whether an event matches a value in order to redirect the user to one step or another. The language comes with a number of helpers and operators:
comparison operators ==
, !=
, <
, >
, <=
, >=
match
keyword
&&
and ||
operators
if
, else if
, else
keywords
CSML functions are a simple way to define simple functional code that can be reused across all of your flows. They are defined in any flow file and use the same CSML syntax that is available in any other steps.
Conceptually, they can be viewed as simple placeholders that you can insert at any place in any flow, to perform repetitive tasks.
Declaring a function is similar to declaring a step with some minor differences:
the name of the function is preceded by the keyword fn
,
there is a list of parameters between parentheses after the name of the function,
but also, like a step declaration, it ends with a semicolon :
or is surrounded by braces {...}
(new syntax introduced in v1.10.0)
Here is an example of a simple my_double_add()
function, that takes 2 parameters, multiplies each of them by 2, then adds those numbers together, and returns the result:
There is no limit on how many functions a flow can have, and of course you can call a function from within another function. The above example could be rewritten as:
CSML native functions are isolated from the bot itself and can't interact with the memory or display messages. They have only access to non-state-binding keywords: do, if, foreach and return.
However, other builtins can be used!
Functions are by default attached to the flow where they are written. However, you can import functions from other flows to reuse them elsewhere!
You can also use a global import by not defining the flow from which a function can be imported.
Warning! If there is more than one flow defining a function with the same name, it will just import one of them randomly.
Don't use the same name on several functions, or specify which flow you want to import from
You can import multiple functions at once, and even rename them:
introduced in CSML v1.10.0
CSML Modules are an easy way to reuse CSML Functions across multiple chatbots or to provide access to your own services to other chatbot developers. You can create functions in separate flows that you can host on a repository to ease access.
A module at its core is simply a valid CSML flow, that exposes one or several functions, which can be imported into other flows without needing to copy the flow multiple times in multiple bots. An other benefit of using modules is that it makes it easier to replicate changes across multiple changes.
To use a module, you must first declare it as a dependancy to your chatbot. This is done in the modules section of the body when creating a new version of a chatbot or chatting with an unversioned chatbot.
Some example modules are given in this repository: https://github.com/CSML-by-Clevy/csml-modules
Let's import the buttons
module into a flow to access the YesNoButtons
function and make it easier to display Yes/No types of buttons.
The module specification is as follows:
name: buttons url: https://raw.githubusercontent.com/CSML-by-Clevy/csml-modules/master/modules/buttons.csml auth: none
Then you can simply import it in your CSML script as you would any other function, the only difference being the modules/
prefix that tells CSML that it should look for this function in the buttons
module and not in the bot's other flows.
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
.
Send a message to the end user. For the full reference on Components
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:
Wait for user input: simply hold
the conversation in place until the user responds.
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:
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).
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.
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.
The forget
keyword lets you forget memories selectively, or globally.
These keywords can only be used at the root of the flow, outside of any step
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
!
Save any value as a local variable, only available within the step. Local variables remain in memory after the step is done.
Simple logic operators if
, else if
and else
. See examples.
Iterate over each element of an array.
A simple loop with a condition check at every turn
Exit from loop early, or skip an iteration
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.
This syntax is obsolete, but for backwards-compatibility reasons remains valid CSML.
See as
keyword.
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:
Starting with CSML v1.8.0, you can concatenate two or more strings together by using the +
sign:
It is also possible to use string templating to insert any value in another string:
Encode data using hash and HMAC methods:
The data
parameter is the data to encrypt or encode, and it must be a string.
The algorithm must be one of the following values:
Unlike the create_hash
method, create_hmac
requires a key to function. The list of accepted algorithms is the same.
The encoding must be either "base64"
or "hex"
.
When any operation fails, Null
is returned and a say Error(error_message)
is emitted.
CSML includes a native SMTP client, allowing you to easily send emails from your chatbot.
All incoming events are theoretically strings.
The reason is simple: there is no way for a chat client to differenciate between for example a number
type and a string
type as this was typed into an input field or spoken to a voice interface.
However, the language must have a way to perform arithmetic operations anyway.
At the same time, any external function used in the program can return any arbitrary JSON-like object representation, or string, or any type of value.
To handle all these cases at runtime, the CSML interpreter will automatically detect the type of any variable and try to make the best decision depending on how you want to use it. This process is called type inference.
The example below shows how it works for numbers.
Macros are built-in functions that perform some common tasks. Below is a list of some common macros that you can use at any stage in your CSML flows.
Return one the elements of the array passed in the first argument at random.
Useful for randomisation of dialogue parts!
If the first element exists return it, otherwise return the second argument as a default value
Given an array, return it with its elements in a random order.
Especially useful in questions to randomize the available options!
Return whether a string is contained in another string.
Return the length of a given string or array
Return a random floating point number in the range 0-1 (0 included, 1 excluded).
Return the largest integer less than or equal to the given number.
This is useful to generate a random integer in a given range:
Generate a random UUID (v1 or v4, defaults to v4)
The Time()
helpers lets your manipulate timestamps and dates easily.
CSML's Time function is based on Rust's Chrono library. All the formatting options are listed here: https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html
Check if a variable has been saved in the chatbot's memory before for the current user.
Exists
only checks for the existance of top-level variable names in the chatbot's memory for the current user, i.e obj
and not obj.prop
You can easily encode and decode data to and from Base64 and Hex:
This can for example be useful when using Basic Auth in HTTP calls:
But in general, they are useful methods to encode/decode non-URL-safe or non-ASCII data to ensure exchanges between systems run smoothly.
Base64 and Hex are NOT encryption methods!
The JWT module lets you encode, decode and verify Json Web Tokens easily!
exemple: JWT(data).sign(algorithm, secret)
data
: json object to sign and convert to a JWT token
algorithm
: see below
secret
: a secret string used to sign the JWT
This method returns a properly encoded JWT as a string.
exemple: JWT(token).decode(algorithm, secret)
token
: the token to decode
Note: decode
does not try to verify that the token is valid. It simply decodes its payload back to the original form.
This method returns the full JWT data, in the form:{ "payload": { ... your data }, "headers": { "alg": ALG, "typ": "JWT" }}
exemple: JWT(token).verify(claims, algorithm, secret)
claims
: set of claims (in JSON form) to verify the JWT against
This method returns the full JWT data, in the form:{ "payload": { ... your data }, "headers": { "alg": ALG, "typ": "JWT" }}
JWT supports the following algorithms: HS256
, HS384
, HS512
(corresponding to HMAC using SHA-256, SHA-384 and SHA-512 respectively).
The secret key must be a valid, url-safe string.
When a sign, decode or verify operation fails, Null
is returned and a say Error(error_message)
is emitted.
Return the list of all 1st-level properties in the target object.
Return the list of all 1st-level-property values in the target object.
Remove the given property from the target object.
Return the number of 1st-level properties in the target object.
Insert all elements of the parameter object into the target object.
Return the number of elements contained in the target array.
Add an element at the end of an array.
Remove the last element of an array.
Create a new Array with all elements reversed
Add the elements of the array to the initial array
Add an element at position n of an array (shifting the position of all the following elements).
Remove the nth element of an array (unshifting the position of all the following elements).
Returns a new array with all the values found in the original array matching the given value.
Return the same string in all uppercase characters.
Return the same string in all lowercase characters.
Return the length of the target string.
Return whether the string contains another string or expression.
Return whether a string starts with another string or expression.
Return whether a string ends with another string or expression.
Return all the matches of the string or expression in the target string, or Null if none are found.
About _regex methods:
The \
(backslash) character has a special meaning. For technical reasons, in all strings, it must be properly escaped, by convention by adding another \
in front of itself, to avoid being interpreted as a special character. For example, if you mean to write the exact string "\n"
you must in fact write \\n
, otherwise \n
will be interpreted as a line break.
We follow this nomenclature for CSML Regex handling, so a single Regex backslash must be written as a "\\"
string, and an escaped backslash (that behaves as a literal "\"
string character) must in fact be escaped twice, once for being in a string, and once for being in a Regex: you have to write "\\\\"
to result in the Regex syntax \\
which in turn matches the literal "\"
string.
In a future release of CSML we might introduce a "raw string" method to bypass this limitation.
Create a new array of size n
Return a new array with all items between start
and end
. Some rules apply:
If end
is not specified, all the items after start
are returned.
When specified, end
must be ≥ start
.
If any of the parameters is < 0, the count is made from the end of the array.
These methods are useful ways to construct a new arrays from existing arrays. They are inspired from similar methods in other languages and follow the same general syntax.
Here are some examples of what these methods can help you achieve:
Convert an array of arrays to an array containing all elements of the 1st level arrays.
You can find more info about the particular regex syntax used in the *_regex
methods on .
Return the same string in all uppercase characters.
Return the same string in all lowercase characters.
Return the same string with the first letter in uppercase. The rest of the string remains unchanged.
Returns a new string with both leading and trailing whitespace removed. .trim_left()
and .trim_right()
only trim the leading and trainling whitespace respectively.
Return the length of the target string.
Return whether the string contains another string or expression.
Replace the first, all or any occurrence matching the predicate:
Return whether a string starts with another string or expression.
Return whether a string ends with another string or expression.
Return all the matches of the string or expression in the target string, or Null if none are found.
About _regex methods:
The \
(backslash) character has a special meaning. For technical reasons, in all strings, it must be properly escaped, by convention by adding another \
in front of itself, to avoid being interpreted as a special character. For example, if you mean to write the exact string "\n"
you must in fact write \\n
, otherwise \n
will be interpreted as a line break.
We follow this nomenclature for CSML Regex handling, so a single Regex backslash must be written as a "\\"
string, and an escaped backslash (that behaves as a literal "\"
string character) must in fact be escaped twice, once for being in a string, and once for being in a Regex: you have to write "\\\\"
to result in the Regex syntax \\
which in turn matches the literal "\"
string.
In a future release of CSML we might introduce a "raw string" method to bypass this limitation.
Return whether the given string represents a numerical value, an int, a float.
Split a string by a given separator and return an array containing all elements in order. The separator can be a single or multiple characters. If the separator can not be found in the string, the returned array will only contain the original string.
Cut a string between the start
and end
characters. Some rules apply:
If end
is not specified, all the characters after start
are returned.
When specified, end
must be ≥ start
.
If any of the parameters is < 0, the count is made from the end of the string.
Convert a string representing a number to a value cast as an integer or float:
Convert yaml to json and back
Although CSML differentiates between Float and Integer, all methods are available on all Number types. Hence, the Number type does not really exist but represents indifferently Float and Integer.
Given the automatic type inference, CSML will automatically try to map integers and floats to whichever type makes more sense in the context.
Raise the target integer to the power of the given integer.
Return the absolute value of the target number.
Return the cosine, sine or tangent of the target number.
Round the number respectively down, up or using mathematical rounding.
Custom components are clearly an advanced feature of CSML. Unless you are missing specific features with the default capabilities of standard CSML message components, you probably will never need to learn more about this topic!
Feel free to skip to the next section 😉
Under the hood, all message components are created using a JSON-based templating system to describe how the component should behave, what properties it should accept, which are required or optional, their type, etc.
For instance, here is the low-level code to generate the simple Text()
component:
Which outputs the following JSON payload when used in a CSML flow:
Obviously, more complex components are also possible. Here is an example with the standard Button()
component:
You will notice the use of the $_get
keyword. This function retrieves the value of the given parameter and sets if in place. So for example, in our example, the button's payload will be set to what the developers sets, or by default to the value of the title
parameter. Same thing goes for the accepts
property, which results in the following output:
Each component is made of a list of params, that all have the same structure:
if set to true, will display an error when the value is not set in the flow
describe the type of the parameter to accept
Null
Bool
Number
String
Array
Object
default value to set on the object
values to add to the object in all cases (even if a default value is set)
$_get
: will inject the value of the given parameter
$_set
: will set the field to a specific value
In some cases, you may want to specialize your chatbot for one specific channel, which has some complex formats available that you want to make easier to use. For example, CSML Studio has a QuickReply
custom component, which is a quicker way to create quick replies, which are features of Messenger, Workplace Chat and the Webapp channels.
If you are making a specialized chatbot for a specific channel, consider using custom components to make your life easier!
There are two ways to import your own custom components in the CSML Engine and use them in your flows.
as local components by adding a list of custom components to your chatbot's configuration when calling the engine. In that case, you should add a custom_components
parameter to your bot description with an array of key/value objects where the key is the name of the component and the value its definition.
Native components and local components behave exactly as standard components. The only difference is that local components are used with a prefix (Component.MyComponent
) in your flows, whereas native components can be called directly (MyComponent
). This allows you to define different components per bot for the same engine instance, while being able to use common components across all your chatbots. Similarly, local components are easier to share with other users of your chatbots as they can be packaged together.
Note: only valid claims are verified. See the list of official claims in the JWT specs .
You can find more info about the particular regex syntax used in the *_regex
methods on .
This Python documentation explains why it especially matters in Regex syntax to escape backslashes:
This Python documentation explains why it especially matters in Regex syntax to escape backslashes:
Encode and decode URI/URIComponent (see )
Encode and decode
In addition to the , you can also add your own custom message components using the same templating format.
as native components by saving your all your custom component files in files in a given directory, and set the COMPONENTS_DIR environment variable in your . In that case, the name of the component will be the name of the file (without the extension).
The following methods are common to all CSML primitive types.
Return the type of the target value (string
, array
, object
, float
, boolean
, int
, null
)
Return the target value formatted as a string.
Check if a variable can be interpreted as a number (float or int)
Check if the variable can be interpreted as an int
Check if the variable can be interpreted as an float
Some functions may resolve to an error due to a faulty user input, an unreachable API, or some other bug in the code. You can check the result of such functions call (like HTTP()
or App())
with .is_error()
, and get more information with .get_info()
.
CSML includes a native HTTP client. The following verbs are accepted:
GET
POST
PUT
PATCH
DELETE
HTTP will automatically add the following headers to any request:
Content-Type: application/json;
Accept: application/json
In other words, HTTP requests only allow you to send and query json-formatted data.
To build your request, you can chain explicit methods to the HTTP function. No request is actually performed until .send()
is added, allowing you to gradually build your request.
Here is a simple example:
You can also create more complex requests:
The available methods are:
.get()
/ .post(body)
/ .put(body)
/ .patch(body)
/ .delete()
: set the request verb, and add an optional JSON-formatted body
.set(data)
: set the request headers, where {"x-api-key":"somevalue"}
is added as x-api-key:somevalue
headers
.auth(username, password)
set basic auth headers
.query(data)
: set the query strings, where {"key":"value"}
is automatically translated to ?key=value
.disable_ssl_verify()
: for situations where you know that the endpoint comes with an invalid SSL certificate, you can disable SSL verification to bypass this protection. This option should only be used if you know what you are doing!
You can check whether the call returned a response by using the .is_error()
method on the response object.
The .get_info()
method lets you inspect the response of HTTP calls, even when the call returns an error (in which case .get_info()
will also contain the body):
.is_error()
and .get_info()
are very useful methods to correctly handle HTTP responses!