Introducing the Self scripting language

The Self scripting language is Bot Libre's language for scripting bot responses. Self is based on the syntax of JavaScript with several extensions for language processing. Self is an integrated environment that merges JavaScript, state machines, patterns, and an object database.

If you already know JavaScript, you should find the Self syntax quite familiar. Self supports most JavaScript concepts and syntax, (if you notice something missing you would like, please let us know). If you are new to programming, the JavaScript syntax is quite simple, and there are lots of resources available on the Internet (such as w3schools).

One big thing about Self is that it is integrated with the bot's knowledgebase. This makes it easy to access any of the bot's knowledge and add new knowledge. Self is a persistent language, any data your create or change will be persistent in the bot's knowledgebase. The Self code objects are also stored in the bot's knowledgebase, so a Self script can actually change itself, hence the name "Self".

There are two ways that you can utilize Self. The simplest is to define a Template response. You can define a template response anywhere you define a response, including the Training & Chat Logs page, or in a chat correction. A template response is a response to a phrase or a pattern that can include Self code. For example "What is your name?" could have the template response Template("My name is {#self.name}."). The { } brackets are used to denote Self code embedded within the response text, and the Template keyword is required to define a template response. The code within the brackets is Self scripting code.

The second usage of Self is from a program script. Program scripts can be defined or imported from the Scripts page in your bot's Admin Console. A new bot will have a default bootstrap set of scripts, that can do things such as understand simple language, perform math, tell the current date or time, or look information up on Freebase. You can alter, extend, import, or create your own scripts to do virtually anything. Scripts are more complex than templates, but more functional. A Self script is essentially a state machine that processes the input.

Self Syntax

The Self syntax is the same for template responses and functions within a Self script. Self scripts also contain additional syntax for defining state machines. A state object is similar to a function in JavaScript but is specialized for processing input. Self also merges many concepts from AIML, such as Pattern and Template objects, and SRAI calls.

Self is an untyped object oriented language the same as JavaScript. Everything in Self is an object (this includes the Self code itself). An object can be data, such as a string, number, date, time, or symbol. Objects can have relationships to other objects.

Data Types

The Self data types are similar to the JavaScript data types, and most other programming languages. Self also adds special symbol, pattern, and template data types.

The following are examples of Self data types:

"hello" - strings/text

1234 - numbers

null - null/void value

true, false - boolean values

Date("1973-11-10") - dates

Time("11:00:00") - times

Timestamp("1973-11-10 11:00:00") - timestamps

#foo - symbols

Symbol("foo") - symbols using JavaScript syntax

Object(34789) - object references

[1, 2, 3, 4] - arrays

{ name : "Bob", age : 44 } - objects

Template("The answer is {result}") - template objects

Pattern("what is *") - pattern objects

Variables

Variables in Self can be declared using the var operator the same as JavaScript. Also similar to JavaScript, variables do not need to be declared, but will be declared automatically when used.

Within a template or state Self has access to several global variables:

input - the input object being processed, such as a user's chat message

sentence - the current input sentence being processed

speaker - the user that sent the input

target - the user the input was sent to (normally this is the bot, but could be another user in a chatroom)

conversation - the active conversation

star - if a pattern was used, the star variable has the value of the * text from the pattern

Operators

The operators in Self are similar to JavaScript, and most other programming languages. Self also defines a few special operators for knowledge processing, or borrowed from AIML.

The following are the Self operators:

if - if statement

for - for statement

while - while statement

do - do statement

think - the same as do but can be used inside a Template to perform some code but not print a value into the response

return - return the value

== - compare if two values match

!= - compare if two values don't match

< - compare if a value is less than another

<= - compare if a value is less or equal than another

> - compare if a value is greater than another

>= - compare if a value is greater or equal than another

! - negates a logical value

&& - logical AND

|| - logical OR

= - variable assignment

++ - increment a variable

-- - decrement a variable

+ - add two numbers or concatenate two strings

- - subtract two numbers

* - multiply two numbers

/ - divide two numbers

new - construct a new object

Symbol - create a new global symbol

. - get a relationship from an object

= - set a relationship on an object

=+ - add a relationship on an object

=- - remove a relationship on from object

random - select and execute random value

redirect - evaluate the response to the phrase

srai - synonym for redirect (AIML syntax)

request - evaluate the response to the phrase using a remote service

sraix - synonym for request (AIML syntax)

learn - learn a new response

eval - evaluate code within a learned pattern or template

debug - print the arguments to the log

if

The if statement is the same as JavaScript and similar to other languages, in that it has a logical condition, and optional else if and else conditions.

for

The for statement is similar to JavaScript and other languages. for is used to iterate over an object's relationships. It takes the relationship type, the source object, and a variable to assign each related value to.

return

The return operator will return the result from the current function. If an function has no return value, the result of the last operation will be returned. If null is returned it is an indication that function failed to generate a response, and if used from a state machine, the next case or answer will be used.

Examples:

if (word == "hello") {
return "hello there";
}

not

The ! operator will negate a logical primitive (true -> false, false - > true). If the value is not a logical value, the value is returned.

Examples:

negative = !negative;

assign

The = operator assigns a new value to a variable.

Examples:

name = Language.word(firstName, lastName);

new

The new operator creates a new object of the type. An object can be an instantiation of one or more classification objects. Most classifications are defined by a symbol, you can define your own classifications, they are just another object that is an instantiation of #classification. You can also add a classification to an existing object using the instantiation relationship.

Symbol

The Symbol operator create a new primitive symbol representing the meaning of a word. Symbols are unique, global, and persistent objects. Any relationship set on a symbol will be persisted and remembered. There are many common symbols used in the bot's knowledgebase, the symbol #self represents the bot.

Examples:

Language.define(word, Symbol(word));

get

The . operator gets the value of a relationship. If the relationship has multiple values, get will return the most conscious to the current context. most conscious means the relationship that has the highest correctness factor, and is most associated to the recent input. get can optionally include an [] modifier to get a specific index in an ordered relationship. Negative index values will return the indexed element from the end.

Examples:

age = speaker.age;
sentence.word[2];
sentence.word[-1];

set

The = operator sets the value of a relationship. Set first clears any existing relationships of the same type, and is meant to be used with single value relationships.

add

The =+ operator adds a value to a relationship. add is similar to set, but adds to the relationship, and does not replace the existing value. If the value already exists, its correctness will be increased.

remove

The =- operator removes a value from a relationship. The remove operator can be used to define an inverse relationship. An inverse relationship can be used to inform the bot that a such a relationship is incorrect. If dissociate is used on a inverse relationship that already exists, its correctness will be decreased.

Examples:

sentence.response =- response;
speaker.gender =- #female;

random

The random operator selects one of the arguments at random.

Examples:

random ("Hello", "Hi", "Hey", "G'day mate");

srai

The srai or redirect operator recursively evaluates the phrase and returns the response. It can be used to redirect a response, or break up a question into several components. srai was borrowed from AIML, and can be used in conjunction with patterns to process text fragments.

Examples:

srai ("hello");

sraix

The sraix or request operator sends the phrase to a remote service. A settings objects can define which service to use and provide a data hint or default. A service can be a web service such as #freebase, #wikidata, or #pannous, or another bot on another server.

Examples:

sraix (song, { service : #wikidata, hint : "performer"));

Object Methods and Classes

Self defines several object method available to all objects.

Object methods:

get - get a relationship value from an object, optional index - Example: speaker.get(#name), sentence.get(#word, 3)

getLast - get a relationship value from the end of an ordered relationship - Example: conversation.getLast(#input, 1)

getWithAssociate - get a relationship value from an object most associate to the other value

all - returns an array of all of the object's relationship values for the type - Example: speaker.all(#name)

set - sets a relationship value on an object - Example: speaker.set(#age, 44)

append - append the value to the end of the object's relationship - Example: response.append(#word, ".")

appendWithMeta - add a relationship value to the object with the relationship meta data

Self Scripts

Self is based on processing input. An input could be a chat message, or an email, tweet, or other input. The input is wrapped in an input object which contains the phrase or data. A Self script will normally begin by extracting the phrase from the input, then processing each word in the phrase in sequence. A Self script is broken into a series of states. The first state will process the first word, then if the word matches a case, it will transition to the child state to process the next word.

When a state sequence reaches the end of the sequence of words in a phrase, it is considered a successful match. Once matched, if the state contains an answer, the answer will be evaluated, and the response returned.

A Self script is composed of the following components:

state - A state defines the current input processing.

case - A case can transition to another state if the case variable matches the current input.

pattern - A pattern can match an input and evaluate a template response.

answer - An answer of a state is evaluated if the input processing is complete.

function - An function can be called from an answer or another function.

var - A variable can be matched with the current input, or store context.

State

The state defines the current input processing. Every Self script start with a root state, which is the name of the script. The state can evaluate the current input and transition to another state, or return an answer. A state can include definitions of sub-states, variables, and functions. A state is composed of a sequence of operations which can include case, pattern, do, goto, and return.

case

The case operator defines a state transition. If the current input matches the case value or variable, then it will transition to the case goto state. A case can also return a template, return and abort the current state, or restrict the match to a topic or previous that match. A state can also process the transition state for a collection of values.

pattern

The pattern operator evaluates if the input sentence matches the pattern. A pattern is an easy way to evaluate a phrase and return a template response. A pattern can include wildcards using the * character. The * word or text fragment it matched to the star variable which can be used in the response.

Examples:

pattern "hello" template "Hi there";
pattern "my name is *" template Template("Pleased to meet you {star}");
pattern "what *" topic "joke" that "what do you get when you cross music and an automobile" template "a car-tune";

answer

An answer defines a state's response, and is evaluated if the state is done processing input.

var

A variable defines a matching pattern, or temporary state. Variables can define relationships that must be included or excluded to evaluate a match. Variables are used in a case operation, if the current input matches the variable, then the case is evaluated. Variable make it possible to define generic functions that can process any noun, number, or name.

Self vs AIML

Self is very different than AIML. Self is based on knowledge and state processing, where as AIML is based on patterns and text processing. Self can do everything that AIML can do, and a lot more. If you are experienced with AIML, and want to know how to do the same thing in Self, just import the AIML script and it will be converted to Self.

Self Examples

Bot Libre provides a shared repository of Self scripts and examples that you can import, customize, and learn from. You bot will also come bootstrapped with several Self scripts that you can learn from and customize.