Katella Platform

Skill Builder

Katella allows you to add custom skills connecting to external APIs. Skills created are accessible by your entire team. Start with Team Settings, go to Custom Skills and click on Add a Skill.

Define a Skill

Start by entering a skill name, preferable starting with a verb or verb-ing. Katella may prompts "Did you mean to " when she's not sure of a match.

To trigger a skill, enter a few English sentences users may want to ask. Try not to use overly generic sentences that may match multiple skills. Start with 5-10 sentences and improve them later on.

For your convenience, we have pre-trained a few triggers in various domains that can be used immediately by your team. This list is expected to grow significantly as we enable more domains. You may use these triggers in addition to defining your own.

Collecting Inputs

A skill may required inputs from the user or data from a remote API before it can be executed. Inputs maybe marked Required or Optional. Optional inputs will only be extracted from the original sentence that triggered the skill, while Required inputs will repetitively prompt users to complete the missing info.

Katella supports three types of inputs: System, Local, and Remote input

All inputs collected here become variables, which can be referenced at the later steps using our Expression Language

Making API call

Once the inputs have been collected, your skill may make an optional remote call to request or submit the information to an external API.

Here you may compose a URL using the inputs collected earlier. Inputs are referenced by using expression brackets {inputX}. Depending on the input types, you may even walk the object graph with expressions such as {input2.values[0].name}

Apps can predefine BaseURL and may required Authorization at team/user level. By selecting one here, you can define the URL Path such that it will be appended to the App's BaseURL. Authorization tokens (if any) will also be passed automatically to this App.

Skill Response

You may respond to the users with three widget types: Text, Card, and Cards.

Each will be rendered appropriately for different messaging clients (Slack, MS Teams, Hangouts Chat,..). Additionally each widget includes a voice-friendly, SSML-compatible field, which will be used for voice-only clients (Google Home, Alexa,..)

Here you have access to the inputs (if any) collected earlier, as well as the output of the API call. The output is expected to be JSON, and you may use our Expression Language to walk the object graph.

Input Types

Inputs are data collected from the user or remote APIs.

System input

Also called Name Entities, System inputs are primitive entities that can be extracted from user's sentences. Built-in System inputs include PERSON, EMAIL, WORKER (combined PERSON and EMAIL), LOCATION, DATE, DATE RANGE, TIME, TIME RANGE, ON/OFF, TEXT

These are the expressions available for each Input type.

PERSON

Collecting a person's name from user input (e.g where is Ronald?)

{inputX}- direct reference output the person's name
EMAIL

Collecting an email from the user. In supported clients (Slack, Hangouts, Teams,..), user may also use @mention a teammate (e.g Get @peter's calendar)

{inputX}- output the email
WORKER

A worker is flexible and may collect either a name or an email from the user (most modern APIs have a way to look up a person using one or the other). If the user references themselves (e.g who am I, what's my business title,..), the input will be populated with the current user's name and email

{inputX}- direct reference output the person's name if exists, otherwise the person's email
{inputX.self}- whether the user referenced themselves (e.g who am I, my address, ...) instead of another person
{inputX.hasEmail}- whether an email was specified
{inputX.hasName}- whether a person's name was specified
{inputX.email}- output the email if exists
{inputX.name}- output the name if exists
{inputX.firstName}- output the first name if exists
{inputX.lastName}- output the last name if exists
{inputX.same(someEmail, someName)}- check if the worker is the same person as the email and/or name specified. Use null for value you don't want to compare (e.g input3.same(null, "Peter") will check if our Worker's name is Peter)
LOCATION

Collecting a city, state, or country from user input (e.g how's the weather in London?)

{inputX}- output the location
DATE

Extract a date from user input. This Input understands a variety of formats including tomorrow, next Tues, in 5 days, 4/2 ...

{inputX}- output ISO standard date format yyyy-mm-dd.
{inputX.pretty}- output user-friendly date (e.g today, Tuesday 4/3, ..).
{inputX.toStartOfDay}- convert a date into a start-of-day date time (yyyy-mm-dd 00:00:00). The resulting TIME object can use any of the TIME expressions.
{inputX.toEndOfDay}- convert a date into an end-of-day date time (yyyy-dd-dd 23:59:59). The resulting TIME object can be chained further.
{inputX.plus(no_of_days)}- add the specified # of days to our date. The result is also a DATE object, which can be chained further.
{inputX.plusYears(no_of_years)}- add the specified # of years to our date. The result is also a DATE object, which can be chained further.
{inputX.equals("yyyy-mm-dd")}- verify if our date is the same as the specified string representing a date.
{inputX.isBefore("yyyy-mm-dd")}- verify if our date is at an earlier time than the specified string representing a date.
{inputX.isAfter("yyyy-mm-dd")}- verify if our date is at a later time than the specified string representing a date.
DATE RANGE

Extract a start date and an optional end date from user input. Alternatively, user can enters a date and a duration. This Inputs understand a variety of formats including today (same start/end date), this week (Monday to Sunday this week), next Tuesday to Fri, next 3 days ...

{inputX.start}- output the start date in ISO standard format YYYY-MM-DD. The resulting object is a DATE, so all expressions for DATE input type can be further chained.
{inputX.end}- output the end date in ISO standard format YYYY-MM-DD. The resulting object can be chained with all DATE expressions (e.g inputX.end.toEndOfDay )
{inputX.pretty}- output user-friendly date range (e.g today, from Sat 7/6 to Mon 7/8, ..).
{inputX.contains("YYYY-MM-DD")}- whether this date falls inside our date range.
{inputX.days}- number of days from start date to end date.
{inputX.nextRange}- move our Date Range forward by the number of days in our range (e.g if our range represents this week, nextRange() would be the week after).
{inputX.previousRange}- move our Date Range backward by the number of days in our range (e.g if our range represents today, previousRange() would be yesterday).
{inputX.dates}- return a list of dates from our input. If referenced directly, the output will be an list of ISO standard dates, separated by commas and surrounded by square brackets (e.g ["2017-04-01", "2017-04-02"] ). This is suitable to be used as the JSON payload to external APIs. Additional expressions may be used to generate the desired text output. For example this expression inputX.dates.{ #this + "T00:00:00" } converts our dates to datetimes, outputing ["2017-04-01T00:00:00", "2017-04-02T00:00:00"].
TIME

Collecting a date & time from the user. Accepted formats include tomorrow at 9, now, 4pm next Wed, ...

{inputX}- output ISO standard datetime (with user timezone) format yyyy-mm-ddThh:mm:ss+|-hhmm. The majority of APIs would accept this format.
{inputX.pretty}- output user-friendly text (e.g Wed 3/4 at 3pm)
{inputX.plus(no_of_days)}- add the specified # of days to our datetime. The result is also a TIME object, which can be chained further (e.g {input3.plus(7).pretty} outputs user-friendly text 7 days after our datetime input)
{inputX.plusHours(no_of_hours)}- add the specified # of hours to our date time. The result is also a TIME object.
{inputX.plusMinutes(no_of_minutes)}- add the specified # of minutes to our date time. The result is also a TIME object.
TIME RANGE

Extract a start datetime and an end datetime (or start datetime and duration). If only 1 datetime is detected and a duration is not specified, a fallback duration of 30 minutes will be used. Accepted formats include: today at 3pm for 15 min, from today 2pm to noon tomorrow, at midnight (today at midnight for 30 minutes) ..

{inputX.start}- output the start datetime (including user timezone) in ISO standard format yyyy-mm-ddThh:mm:ss+|-hhmm. The resulting object is a TIME, so all expressions for TIME input type can be further chained (e.g {input2.start.plusHours(12).pretty} output the friendly datetime 12 hours after our start datetime input).
{inputX.end}- output the ending datetime in ISO standard format yyyy-mm-ddThh:mm:ss+|-hhmm. The resulting object can be chained with all TIME expressions.
{inputX.pretty}- output user-friendly date time range (e.g Wed 9/4 2:30 - 3:00pm, Sat 7/6 9AM to Mon 7/8 3PM, ..)
ON/OFF

collect user's intention to enable to disable a device. This maybe used for the office's smart devices, or more generically as an On/Off toggle.

{inputX}- whether it is true (ON) or false (OFF). If this Input is Optional, and user doesn't specify whether it is ON or OFF, referencing the Input will return null
TEXT

Collecting a text snippet from user. User can specify the value by enclosing the text portion in double quotes (e.g translate "Hello" to French). Otherwise, Katella will prompt user to enter the text.

{inputX}- output the text.

Local input

coming soon

Remote input

coming soon

Output widgets

Katella outputs user responses as Text, Card, or a list of Cards. These widgets will work with all of our supported messaging clients (Slack, MS Teams, Google Hangouts) as well as the voice-only Google Home.

To construct the user output, you have access to all Skill Inputs collected ({input1}, {input2}, {input3}, ...), as well as the output of the API call ({output}). Additionally, there are a variety of helper functions to help format and process the API calls (see Expression Language).

Text

Simply output the user response as a formatted text string. You may combine texts and expressions, as well as formatted text.

By default, voice-only clients like Google Home will read out the output text. If you want to fine tune the speech, populate the voice-friendly output field with the desired output. You may use all supported SSML tag as specified here, including pause, sound clips, speed, pitch, volume, ...

Here are the corresponding outputs from Slack, Google Hangouts and Microsoft Teams:

screenshot
screenshot
screenshot

Card

Katella supports Rich Card across messaging clients. A Card supports these fields:
card message

show a message before the card (e.g here is your result)

title

title of the card. This field does not support formatted text.

title url

the external URL to navigate to when user taps on the card title. On some messaging clients, the URL is opened when the whole card is tapped.

image

specify a URL to load an card image

text

the multi-line card description

labels/values

a list of label/value fields, useful when displaying form items. The label does not support formatted text.

voice-friendly text

SSML-compatible field for voice-only devices

Cards

This widget enables you iterate through a data set (normally the API output) and return a list of Cards, each of which has the same format as the Card widget.
message

a single message to be shown before all the cards (e.g You have zero/five results)

loop expression

expression-only field resolving to a list of entries to loop through, normally the JSON output (or its subset) of the API call.

Note: within the loop expression, all expressions referencing the loop item need a prefix of item.*. For others (input1, input2,...) you do not need the prefix.

title

title of each card (e.g {item.name} to get each "name" child inside this loop). This field does not support formatted text.

title url

the external URL (e.g {item.url}) to navigate to when user taps on each card title. On some messaging clients, the URL is opened when the whole card is tapped.

image

specify the URL to each card's image

text

the multi-line card description for each card

labels/values

a list of label/value fields, useful when displaying form items. The label does not support formatted text.


By default, voice-only clients will read the message, then the first item of the cards only. You may fine tune the speech by populating the voice-friendly output.

Text Formatting

Katella supports formatted text that will work across all messaging clients. Note that not all widget fields will support formatted text.
Bold
*my bold text*
Italic
_italic text here_
Inline code
`monospace text with emphasis`

Helper functions

Katella comes with utilities (helper functions) to help format text, manage datetime, filter item lists, and many others. These are invoked by prefix the expression with @ sign, and their inputs can be raw text, JSON, expressions, or even inputs/output.
@DateTime

utilities to format and manipulate date and time

{@DateTime.prettyDate("yyyy-mm-dd")}

converts an ISO-standard date (or date time) to user-friendly text (e.g tomorrow, Friday 5/4, ...)


{@DateTime.prettyTime("yyyy-mm-ddThh-mm-ss")}

converts an ISO-standard date time (with/without timezone) to user-friendly time-only text (e.g 2PM,..)


{@DateTime.prettyDateTime("yyyy-mm-ddThh-mm-ss")}

converts an ISO-standard date time (with/without timezone) to user-friendly text (e.g tomorrow at 2PM, Wed 3/4 at 9AM, ...)


{@DateTime.prettyDateTimeFromTimestamp(epoch_no_seconds)}

converts an Unix timestamp (# of seconds since Jan 1st 1970) to user-friendly text (e.g tomorrow at 2PM, Wed 3/4 at 9AM, ...)


{@DateTime.prettyDateRange(startDate, endDate)}

converts two ISO-standard dates (start and end date) to a user-friendly date range text (e.g yesterday to tomorrow, Wed 5/4 to Fri 5/6, ...). Note that start and end date can be the same, in which case a friendly date text is returned (e.g Friday 5/4, ...)


{@DateTime.prettyDuration(no_of_seconds)}

converts a number of seconds duration to user-friendly text (e.g 1 hour 2 minutes, 4 days, ...)


{@DateTime.toRelativeMoment("yyyy-mm-ddThh-mm-ss")}

converts an ISO-standard date time to relative moment (e.g in 5 minutes, 3 days ago, ...)


{@DateTime.getYear("yyyy-mm-dd")}

return the year from an ISO-standard date or date time (e.g 2018)


{@DateTime.getMonth("yyyy-mm-dd")}

return the month number (1-12) from an ISO-standard date or date time


{@DateTime.getDay("yyyy-mm-dd")}

return the day (1-31) from an ISO-standard date or date time


{@DateTime.isDate("yyyy-mm-dd")}

whether the provided text is a valid ISO-standard date or date time string


{@DateTime.asDate("yyyy-mm-dd")}

convert an ISO-standard date or date time into a DATE object, which can be further chained.


{@DateTime.today()}

return the user's today date as a DATE object, which can be further chained. Referencing this directly returns an ISO-standard date.


{@DateTime.now()}

return the user's datetime at this moment as a TIME object, which can be further chained. Referencing this directly returns an ISO-standard date time.


{@DateTime.isToday("yyyy-mm-dd")}

whether the provided ISO-standard date is the same as today's date (based on user's timezone). This will return null if the date is invalid, otherwise true or false.


{@DateTime.isFuture("yyyy-mm-dd")}

whether the provided ISO-standard date is in the future (based on user's timezone). This will return null if the date is invalid, otherwise true or false.


{@DateTime.isPast("yyyy-mm-dd")}

whether the provided ISO-standard date is in the past (based on user's timezone). This will return null if the date is invalid, otherwise true or false.


@Formatter

format text/json/html and convert currency, percent, and more

{@Formatter.lowercase(text_to_lowercase)}

convert the text to all lowercase


{@Formatter.singularPlural(count, singularWord, pluralWord)}

utility to output a word as singular/plural (e.g 1 person, 4 items,...) depending on its count variable. For example, this expression {@Formatter.singularPlural(myJson.people.count, "person", "persons")} will traverse a JSON to the people's count, and output 4 persons if the count is more than 1 (or 1 person if the count is 0 or 1)


{@Formatter.flattenList(array_of_texts)}

concatenate a list of texts, separated by a comma and capping at 10 items max. If we have more than 10 items, this will list out the first 10 strings, followed by the left-over count (e.g +3 more).


{@Formatter.flattenList(array_of_texts, max_count)}

same as above except you may specified the max of of items to cap by here.


{@Formatter.decodeHtml(html_text)}

unescape html text that may have been escaped on various external API.


{@Formatter.asNumber(number_text)}

convert text to a number, returning null if the text is not a number. The result can be use with math operations (+ - * /) to calculate other numbers.


{@Formatter.asInteger(number_text)}

convert text to an integer, returning null if the text is not a number. The result can be use with math operations (+ - * /) to calculate other numbers.


@System

utils dealing with list, random, filter logic, ..

{@System.random(array_of_texts)}

pick an item from the array of text at random. The input can be a JSON array from APIs or hardcoded, e.g {@System.random({"first item", "second item"})}


{@System.empty(text)}

whether this specified text resolved to null or empty


{@System.filter(item_list, expression_key, value)}

given a list of objects and the expression key to each item's nested text attribute, iterate through and filter only the items that matches the specified value. This utility returns the filtered list, which is an array that can be further chained.

For example if each item has a child node manufacturer, the expression {@System.filter(output.cars, "manufacturer", "Porsche")} will return only the list of car objects with manufacturer equals "Porsche".


{@System.filterPartial(item_list, expression_key, value)}

same as above except a partial match (not exact) will be used to filter the items. The list will be ordered with the best matched item on top.


Expression Language

coming soon