!DEFINITION
The "!" command is for defining variables within RiveScript. It's used to define information about the
bot, define global arrays that can be used in multiple triggers, or override interpreter globals such as
debug mode.
The format of the "!" command is as follows:
! type name = value
Where "type" is one of "version, global, var, array, sub," or "person". The "name" is the name of the
variable being defined, and "value" is the value of said variable.
Whitespace surrounding the "=" sign should be stripped out.
Setting a value to "<undef>" will undefine the variable (deleting it or uninitializing it, depending on
the implementation).
The variable types supported are detailed as follows:
version
It's highly recommended practice that new RiveScript documents explicitly define the version of
RiveScript that they are following. RiveScript 2.00 has some compatibility issues with the old 1.x line
(see "REVERSE COMPATIBILITY"). Newer RiveScript versions should encourage that RiveScript documents
define their own version numbers.
! version = 2.00
global
This should override a global variable at the interpreter level. The obvious variable name might be
"debug" (to enable/disable debugging within the RiveScript interpreter).
The interpreter should take extra care not to allow reserved globals to be overridden by this command in
ways that might break the interpreter.
Examples:
! global debug = 1
var
This should define a "bot variable" for the bot. This should only be used in an initialization sense;
that is, as the interpreter loads the document, it should define the bot variable as it reads in this
line. If you'd want to redefine or alter the value of a bot variable, you should do so using a tag inside
of a RiveScript document (see "TAGS").
Examples:
! var name = RiveScript Bot
! var age = 0
! var gender = androgynous
! var location = Cyberspace
! var generator = RiveScript
array
This will create an array of strings, which can then be used later in triggers (see "+ TRIGGER"). If the
array contains single words, separating the words with a space character is fine. If the array contains
items with multiple words in them, separate the entries with a pipe symbol ("|").
Examples:
! array colors = red green blue cyan magenta yellow black white orange brown
! array be = is are was were
! array whatis = what is|what are|what was|what were
Arrays have special treatment when spanned over multiple lines. Each extension of the array data is
treated individually. For example, to break an array of many single-words into multiple lines of
RiveScript code:
! array colors = red green blue cyan
^ magenta yellow black white
^ orange brown
The data structure pulled from that code would be identical to the previous example above for this array.
Since each extension line is processed individually, you can combine the space-delimited and pipe-
delimited formats. In this case, we can add some color names to our list that have multiple words in
them.
! array colors = red green blue cyan magenta yellow
^ light red|light green|light blue|light cyan|light magenta|light yellow
^ dark red|dark green|dark blue|dark cyan|dark magenta|dark yellow
^ white orange teal brown pink
^ dark white|dark orange|dark teal|dark brown|dark pink
Finally, if your array consists of almost entirely single-word items, and you want to add in just one
multi-word item, but don't want to require an extra line of RiveScript code to accomplish this, just use
the "\s" tag where you need spaces to go.
! array blues = azure blue aqua cyan baby\sblue sky\sblue
sub
The "sub" variables are for defining substitutions that should be run against the client's message before
any attempts are made to match it to a reply.
The interpreter should do the minimum amount of formatting possible on the client's message until after
it has been passed through all the substitution patterns.
NOTE: Spaces are allowed in both the variable name and the value fields.
Examples:
! sub what's = what is
! sub what're = what are
! sub what'd = what did
! sub a/s/l = age sex location
! sub brb = be right back
! sub afk = away from keyboard
! sub l o l = lol
person
The "person" variables work a lot like "sub"s do, but these are run against the bot's response,
specifically within "<person>" tags (See "TAGS").
Person substitutions should swap first- and second-person pronouns. This is so that ex. if the client
asks the bot a direct question using "you" when addressing the bot, if the bot uses the client's message
in the response it should swap "you" for "I".
Examples:
! person you are = I am
! person i am = you are
! person you = I
! person i = you
>LABEL
The ">" and "<" commands are for defining a subset of your code under a certain label. The label command
takes between one and three arguments. The first argument defines the type of the label, which is one of
"begin, topic," or "object". The various types are as follows.
begin
This is a special label used with the "BEGIN block". Every message the client sends to the bot gets
passed through the Begin Statement first, and the response in there determines whether or not to get an
actual reply.
Here's a full example of the Begin Statement.
> begin
+ request
- {ok}
< begin
In the "BEGIN block", the trigger named ""request"" is called by the interpreter, and it should return
the tag ""{ok}"" to tell the interpreter that it's OK to get a real reply. This way the bot could have a
"maintenance mode," or could filter the results of your trigger based on a variable.
Here's a maintenance mode example:
> begin
+ request
* <id> eq <bot master> => {ok} // Always let the bot master get a reply
* <env maint> eq true => Sorry, I'm not available for chat right now!
- {ok}
< begin
// Allow the owner to change the maintenance mode
+ activate maintenance mode
* <id> eq <bot master> => <env maint=true>Maintenance mode activated.
- You're not my master! You can't tell me what to do!
+ deactivate maintenance mode
* <id> eq <bot master> => <env maint=false>Maintenance mode deactivated.
- Only my master can deactivate maintenance mode!
With this example, if the global variable "maint" is set to "true", the bot will always reply "Sorry, I'm
not available for chat right now!" when a user sends it a message -- unless the user is the bot's owner.
Here is another example that will modify the response formatting based on a bot variable called "mood,"
to simulate humanoid moods for the bot:
> begin
+ request
* <get mood> == happy => {ok} :-)
* <get mood> == sad => {lowercase}{ok}{/lowercase}
* <get mood> == angry => {uppercase}{ok}{/uppercase}
- {ok}
< begin
In this example the bot will use smiley faces when it's happy, reply in all lowercase when it's sad, or
all uppercase when it's angry. If its mood doesn't fall into any of those categories, it replies
normally.
Here is one last example: say you want your bot to interview its users when they first talk to it, by
asking them for their name:
> begin
+ request
* <get name> == undefined => {topic=newuser}{ok}
- {ok}
< begin
> topic newuser
+ *
- Hello! My name is <bot name>! I'm a robot. What's your name?
+ _
% * what is your name
- <set name=<formal>>Nice to meet you, <get name>!{topic=random}
< topic
Begin blocks are optional! They are not required. You only need to manually define them if you need to do
any "pre-processing" or "post-processing" on the user's message or the bot's response. Having no begin
block is the same as having a super basic begin block, which always returns "{ok}".
topic
A topic is a smaller set of responses to which the client will be bound until the topic is changed to
something else. The default topic is "random".
The "topic" label only requires one additional argument, which is the name of the topic. The topic's name
should be one word and lowercase.
Example:
+ i hate you
- Well then, I won't talk to you until you take that back.{topic=apology}
> topic apology
+ *
- I won't listen to you until you apologize for being mean to me.
- I have nothing to say until you say you're sorry.
+ (sorry|i apologize)
- Okay. I guess I'll forgive you then.{topic=random}
< topic
Topics are able to "include" and "inherit" triggers that belong to a different topic. When a topic
"includes" another topic, it means that the triggers in another topic are made available in the topic
that did the inclusion (hereby called the "source topic", which includes triggers from the "included
topic").
When a topic inherits another topic, it means that the entire collection of triggers of the source topic
and any included topics, will have a higher matching priority than the inherited topics.
See "Sorting +Triggers" to see how triggers are sorted internally. The following example shows how
includes and inheritance works:
// This is in the default "random" topic and catches all non-matching
// triggers.
+ *
- I'm afraid I don't know how to reply to that!
> topic alpha
+ alpha trigger
- Alpha's response.
< topic
> topic beta
+ beta trigger
- Beta's response.
<
> topic gamma
+ gamma trigger
- Gamma's response.
< topic
> topic delta
+ delta trigger
- Delta's response.
+ *
- You can't access any other triggers! Haha!
< topic
These are all normal topics. Alpha, beta, and gamma all have a single trigger corresponding to their
topic names. If the user were put into one of these topics, this is the only trigger available. Anything
else would give them a "NO REPLY" error message. They are unable to match the "*" trigger at the top,
because that trigger belongs to the ""random"" topic, and they're not in that topic.
Now let's see how we can pair these topics up with includes and inheritance.
> topic ab includes alpha
+ hello bot
- Hello human!
< topic
// Matching order:
alpha trigger
hello bot
If the user were put into topic ""ab"", they could match the trigger "hello bot" as well as the trigger
"alpha trigger", as if they were both in the same topic.
Note that in the matching order, "alpha trigger" is at the top: this is because it is the longest
trigger. If the user types "alpha trigger", the interpreter knows that "alpha trigger" does not belong to
the topic "ab", but since "ab" includes triggers from "alpha", the interpreter searches there and finds
the trigger. Then it gives the user the correct reply of "Alpha's response."
> topic abc includes alpha beta
+ how are you
- Good, how are you?
< topic
// Matching order:
how are you
alpha trigger
beta trigger
In this case, "how are you" is on the top of the matching list because it has three words, then "alpha
trigger" and "beta trigger" -- "alpha trigger" is first because it is longer than "beta trigger", even
though they both have 2 words.
Now consider this example:
> topic abc includes alpha beta
+ how are you
- Good, how are you?
+ *
- You matched my star trigger!
< topic
// Matching order:
how are you
alpha trigger
beta trigger
*
Notice what happened here: we had a trigger of simply "*" in the "abc" topic - "*" is the fallback
trigger which matches anything that wasn't matched by a better trigger. But this trigger is at the end of
our matching list! This is because the triggers available in the "alpha" and "beta" topics are included
in the "abc" topic, meaning they all share the same "space" when the triggers are sorted. Since "*" has
the lowest sort priority, it ends up at the very end of the collective list.
What if we want "*", or any other short trigger, to match in our current topic before anything in an
included topic? We need to "inherit" another topic. Consider this:
> topic abc inherits alpha beta
+ how are you
- Good, how are you?
+ *
- You matched my star trigger!
< topic
// Matching order:
how are you
*
alpha trigger
beta trigger
Now the "*" trigger is the second on the matching list. Because "abc" inherits alpha and beta, it means
that the collection of triggers inside "abc" are sorted independently, and then the triggers of alpha and
beta are sorted. So this way every trigger in "abc" inherits, or overrides, all triggers in the inherited
topics.
Of course, using a "*" trigger in a topic that inherits other topics is useless, because you could just
leave the topic as it is. However it might be helpful in the case that a trigger in your topic is very
short or has very few words, and you want to make sure that this trigger will have a good chance of
matching before anything that appears in a different topic.
You can combine inherited and included topics together, too.
> topic abc includes alpha beta delta inherits gamma
+ how are you
- Good, how are you?
< topic
// Matching order:
how are you
alpha trigger
delta trigger
beta trigger
*
gamma trigger
In this example, the combined triggers from abc, alpha, beta, and delta are all merged together in one
pool and sorted amongst themselves, and then triggers from gamma are placed after them in the sort list.
This effectively means you can combine the triggers from multiple topics together, and have ALL of those
triggers override triggers from an inherited topic.
You can use as many "includes" and "inherits" keywords as you want, but the order you specify them has no
effect. So the following two formats are identical:
> topic alpha includes beta inherits gamma
> topic alpha inherits gamma includes beta
In both cases, alpha and beta's triggers are pooled and have higher priority than gamma's. If gamma wants
to include beta and have alpha's triggers be higher priority than gamma's and beta's, gamma will need to
include beta first.
> topic gamma includes beta
> topic alpha inherits gamma
In this case the triggers in "alpha" are higher priority than the combined triggers in gamma and beta.
object
Objects are bits of program code that the interpreter should try to process. The programming language
that the interpreter was written in will determine whether or not it will attempt to process the object.
See "OBJECT MACROS" for more information on objects.
The "object" label should have two arguments: a lowercase single-word name for the object, and the
programming language that the object should be interpreted by, which should also be lowercase.
Example:
> object encode perl
my ($obj,$method,@args) = @_;
my $msg = join(" ",@args);
use Digest::MD5 qw(md5_hex);
use MIME::Base64 qw(encode_base64);
if ($method eq 'md5') {
return md5_hex($msg);
}
else {
return encode_base64($msg);
}
< object
+TRIGGER
The "+" command is the basis for all things that actually do stuff within a RiveScript document. The
trigger command is what matches the user's message to a response.
The trigger's text should be entirely lowercase and not contain any symbols (except those used for
matching complicated messages). That is, a trigger that wants to match ""what's your name"" shouldn't be
used; you should use a "sub"stitution to convert "what's" into "what is" ahead of time.
Example:
+ are you a bot
- How did you know I'm a robot?
AtomicTrigger
An atomic trigger is a trigger that matches nothing but plain text. It doesn't contain any wildcards
("*") or optionals, but it may contain alternations. Atomic triggers should take higher priority for
matching a client's message than should triggers containing wildcards and optionals.
Examples:
+ hello bot
+ what is your name
+ what is your (home|office) phone number
+ who is george w bush
TriggerWildcards
Using an asterisk ("*") in the trigger will make it act as a wildcard. Anything the user says in place of
the wildcard may still match the trigger. For example:
+ my name is *
- Pleased to meet you, <star>.
An asterisk ("*") will match any character (numbers and letters). If you want to only match numbers, use
"#", and to match only letters use "_". Example:
// This will ONLY take a number as the wildcard.
+ i am # years old
- I will remember that you are <star> years old.
// This will ONLY take letters but not numbers.
+ my name is _
- Nice to meet you, <star>.
The values matched by the wildcards can be retrieved in the responses by using the tags "<star1>",
"<star2>", "<star3>", etc. in the order that the wildcard appeared. "<star>" is an alias for "<star1>".
TriggerAlternations
An alternation in a trigger is a sub-set of strings, in which any one of the strings will still match the
trigger. For example, the following trigger should match both "are you okay" and "are you alright":
+ are you (okay|alright)
Alternations can contain spaces in them, too.
+ (are you|you) (okay|alright)
That would match all of the following questions from the client:
are you okay
are you alright
you okay
you alright
Alternations match the same as wildcards do; they can be retrieved via the "<star>" tags.
TriggerOptionals
Triggers can contain optional words as well. Optionals are written similarly to alternations, but they
use square braces. The following example would match both "what is your phone number" as well as "what is
your home phone number"
+ what is your [home] phone number
Optionals do NOT match like wildcards do. They do NOT go into the "<star>" tags. The reason for this is
that optionals are optional, and won't always match anything if the client didn't actually say the
optional word(s).
ArraysinTriggers
Arrays defined via the "! DEFINITION" "array" commands can be used within a trigger. This is the only
place where arrays are used, and they're added as a convenience feature.
For example, you can make an array of color names, and then use that array in multiple triggers, without
having to copy a whole bunch of alternation code between triggers.
! array colors = red green blue cyan magenta yellow black white orange brown
+ i am wearing a (@colors) shirt
- I don't know if I have a shirt that's colored <star>.
+ my favorite color is (@colors)
- I like <star> too.
+ i have a @colors colored *
- Have you thought about getting a <star> in a different color?
When an array is called within parenthesis, it should be matched into a "<star>" tag. When the
parenthesis are absent, however, it should not be matched into a "<star>" tag.
PriorityTriggers
A new feature proposed for RiveScript 2.00 is to add a priority tag to triggers. When the interpreter
sorts all the loaded triggers into a search sequence, any triggers that have a priority defined will be
sorted with higher priority triggers first.
The idea is to have "important" triggers that should always be matched before a different trigger, which
may have been a better match, can be tried. The best example would be for commands. For example:
+ google *
- Searching Google... <call>google <star></call>
+ * or not
- Or yes. <@>
In that example, if the bot had a Google search function and the user wanted to search for whether or not
Perl is a superior programming language to PHP, the user might ask ""google is perl better than php or
not"". However, without priorities in effect, that question would actually match the ""* or not""
trigger, because that trigger has more words than ""google *"" does.
Adding a priority to the ""google *"" trigger would ensure that conflicts like this don't happen, by
always sorting the Google search trigger with higher priority than the other.
+ {weight=100}google *
- Searching Google... <call>google <star></call>
NOTE: It would NOT be recommended to put a priority tag on every one of your triggers. To the interpreter
this might mean extra processing work to sort prioritized triggers by each number group. Only add
priorities to triggers that need them.
-RESPONSE
The "-" tag is used to indicate a response to a matched trigger. A single response to a single trigger is
called an "atomic response." When more than one response is given to a single trigger, the collection of
responses become a "random response," where a response is chosen randomly from the list. Random responses
can also use a "{weight}" tag to improve the likelihood of one response being randomly chosen over
another.
AtomicResponse
A single response to a single trigger makes an Atomic Response. The bot will respond pretty much the same
way each time the trigger is matched.
Examples:
+ hello bot
- Hello human.
+ my name is *
- Nice to meet you, <star>.
+ i have a (@colors) shirt
- You're not the only one that has a <star> shirt.
RandomResponse
Multiple responses to a single trigger will be chosen randomly.
+ hello
- Hey there!
- Hello!
- Hi, how are you?
+ my name is *
- Nice to meet you, <star>.
- Hi, <star>, my name is <bot name>.
- <star>, nice to meet you.
WeightedRandomResponse
When using random responses, it's possible to give weight to them to change the likelihood that a
response will be chosen. In this example, the response of "Hello there" will be much more likely to be
chosen than would the response of "Hi".
+ hello
- Hello there!{weight=50}
- Hi.
When the "{weight}" tag isn't used, a default weight of 1 is implied for that response. The "{weight}"
should always be a number greater than zero and must be an integer (no decimal point).
%PREVIOUS
The "%" command is for drawing the user back to finish a short discussion. Its behavior is similar to
using topics, but is implied automatically and used for short-term things. It's also less strict than
topics are; if the client replies in a way that doesn't match, a normal reply is given anyway. For
example:
+ knock knock
- Who's there?
+ *
% who is there
- <star> who?
+ *
% * who
- lol! <star>! That's hilarious!
The text of the "%" command looks similar to the text next to the trigger. In essence, they work the
same; the only difference is that the "%" command matches the last thing that the bot sent to you.
Here's another example:
+ i have a dog
- What color is it?
+ (@colors)
% what color is it
- That's an odd color for a dog.
In that case, if the client says "I have a dog," the bot will reply asking what color it is. Now, if I
tell it the color in my next message, it will reply back and tell me what an odd color that is. However,
if I change the topic instead and say something else to the bot, it will answer my new question anyway.
This is in contrast to using topics, where I'd be stuck inside of the topic until the bot resets the
topic to "random".
Similarly to the wildcards in "+ Trigger", the wildcards matched in the "% Previous" command are put into
"<botstar>". See "TAGS" for more information.
^CONTINUE
The "^" command is used to continue the text of a lengthy previous command down to the new line. It can
be used to extend any other command. Example:
+ tell me a poem
- Little Miss Muffit sat on her tuffet\n
^ in a nonchalant sort of way.\n
^ With her forcefield around her,\n
^ the Spider, the bounder,\n
^ Is not in the picture today.
Note that when the "^" command continues the previous command, no spaces or line breaks are implied at
the joining of the two lines. The "\s" and "\n" tags must be explicitly defined where needed.
@REDIRECT
The "@" command is used to redirect an entire response to appear as though the client asked an entirely
different question. For example:
+ my name is *
- Nice to meet you, <star>.
+ call me *
@ my name is <star>
If the client says "call me John", the bot will redirect it as though the client actually said "my name
is John" and give the response of "Nice to meet you, John."
*CONDITION
The "*" command is used with conditionals when replying to a trigger. Put simply, they compare two
values, and when the comparison is true the associated response is given. The syntax is as follows:
* value symbol value => response
The following inequality symbols may be used:
== equal to
eq equal to (alias)
!= not equal to
ne not equal to (alias)
<> not equal to (alias)
< less than
<= less than or equal to
> greater than
>= greater than or equal to
In each of the value places, tags can be used to i.e. insert client or bot variables.
Examples:
+ am i a boy or a girl
* <get gender> eq male => You told me you were a boy.
* <get gender> eq female => You told me you were a girl.
- You never told me what you were.
+ am i your master
* <id> eq <bot master> => Yes, you are.
- No, you're not my master.
+ my name is *
* <get name> eq <star> => I know, you told me that already.
* <get name> ne undefined => Did you get a name change?<set name=<star>>
- <set name=<star>>Nice to meet you, <star>.
It's recommended practice to always include at least one response in case all of the conditionals return
false.
NOTE: Conditionals are tried in the order they appear in the RiveScript document, and the next condition
is tried when the previous ones are false.
//COMMENT
The "//" command is for putting comments into your RiveScript document. The C-style multiline comment
syntax "/* */" is also supported.
Comments on their own line should be ignored by all interpreters. For inline comments, only the "//"
format is acceptable. If you want a literal "//" in your RiveScript data, escape at least one of the
symbols, i.e. "\//" or "\/\/" or "/\/".
Examples:
// A single regular comment
/*
This comment can span
multiple lines
*/
> begin // The "BEGIN" block
+ request // This is required
- {ok} // An {ok} means to get a real reply
< begin//End the begin block