A skill manifest defines the device class of the skill, which describes how a skill will be loaded by the system, how it will be configured, and what it does. For example, the device class of The Cat API skill looks like this:
class @com.thecatapi{
import loader from @org.thingpedia.v2();
import config from @org.thingpedia.config.none();
entity cat;
query cat(out id: Entity(com.thecatapi:cat),
out picture_url: Entity(tt:picture),
out link: Entity(tt:url));
}
Note that the annotations are omitted for simplicity, which will be introduced later. See the full manifest here
The device class has three types of statements: import statements, entity declaractions, and function declaration statements. Each statement terminates with a semicolon.
The import statements import modules loader
and config
for the device, to specify how the device will be loaded by the system and how it will be initially configured or authenticated.
The @org.thingpedia.v2()
loader module is the most flexible. It allows the user to supply additional JS package code to customize the configuration of the device and the behavior of each function. Other loader modules include @org.thingpedia.rss
and @org.thingpedia.generic_rest.v1
. They give users the ability to write a device with standard RSS and RESTful interfaces without any JS code. For more details, please refer to declarative Thingpedia entries.
The @org.thingpedia.config.none
config module is the most basic config module. It is suitable for devices that require no authentication or those that only require an API key.
More options such as OAuth and IoT discovery are described in the complete guide for authentication and discovery.
Entity statements declare a certain entity type before it is used in a query. They are used to provide the metadata associated with an entity type. The syntax of entity statements is
entity <name> <annotation>* ;
The entity statement also specifies whether Named Entity Recognition should be available for a certain type, using the #[has_ner]
annotation. Entities that can be referred by the name should have #[has_ner=true]
; entities that opaque IDs should have #[has_ner=false]
. The default is true
if the annotation is unspecified. For example, the restaurant
entity in the Yelp skill should be supported by NER, while an entity for tweets should not. Thus they should be declared as follows:
entity restaurant #[has_ner=true];
entity tweet #[has_ner=false];
All entity types declared can be used within the device class with the skill name prefix. For example, in the Yelp skill, we declared entity type restaurant
, so we can set parameters with type com.yelp:restaurant
.
A ThingTalk program interacts with a Genie skill through two types of functions: queries and actions. Thus, the first step is to decide on what queries and actions you should expose.
The only requirement imposed by Thingpedia is that queries are free of side effects, and actions have side effects. Generally speaking, this means that queries correspond to "nouns" or "concepts", while actions correspond to "verbs" or "intents". Other than that, the design of which functions to include is highly skill-specific.
Additional qualifiers can be used to specify the property of the query. A query is monitorable
if it's meaningful to monitor changes in its return value. A query is a list
query if it returns multiple results.
For example, a query to return the latest emails would be considered both monitorable
and list
, and its declaration will look like this:
monitorable list latest_emails (...);
For Yelp, the restaurant
query returns a list of restaurants, but it's not very useful to ask if there is a new restaurant added to Yelp, so we mark it as list
.
To take full advantage of the functionality we provided in ThingTalk (filtering, chaining, etc.), every parameter needed for both input and output must be listed. A parameter is described as follows:
[in req | in opt | out] <name> : <type> <annotation>* ;
A parameter can be either in req
(required input), in opt
(optional input), or out
(output). The type
of a parameter could be String, Number, Boolean, Date, Time, Location, Entity, etc. For the full list, see the ThingTalk reference.
Each query that requires named entity recognition should have an id
output parameter. It needs to have an entity type with the same name as the query. All other parameters should have a self-explanable natural name in snake case.
Annotations are used to provide additional information to the corresponding code. Annotations always come after the code and before the semicolon. There are two types of annotations: natural language annotation and implementation annotation.
Natural language annotations, as the name suggests, are the annotation related to how a function or parameter are referred to in natural language. Natural language annotations will be translated to different languages based on users' profiles. The annotations are denoted by #_[<key>=<value>]
.
Each function is required to have a confirmation
natural language annotation: a string used to construct a precise natural language representation of a ThingTalk program. For actions, use the imperative form, and for queries use the noun-phrase form. Unlike the canonical
form, the confirmation
string can refer to required arguments with $argname
or ${argname}
(the latter is only needed if the argument is immediately followed by a letter, number, or underscore). Only one confirmation
string can be provided.
Finally, parameters are also required to have a canonical
natural language annotation. The annotation must be a noun phrase if it is specified as a string or array of strings, but you can specify the annotation as an object to provide different canonical forms in different parts of speech. Refer to the Genie annotation reference for more details.
Implementation annotations are used for describing certain implementation characteristics of a function. They are denoted by #[<key>=<value>]
(without the underscore used by natural language annotations).
Here is a list of required implementation annotations for functions:
doc
: This is used for documentation for developers.poll_interval
(required for monitorable queries): This is used to specify how often the query will be fired if it is monitored. It takes a duration, e.g., #[poll_interval=5min]
.A lot more annotations are supported in Thingpedia - for not only functions but also parameters and for the class itself. They will give you a better user experience and better natural language support for your device. Check Thingpedia annotation reference for more details. Annotations used by Genie to generate high-quality dialogues are listed in the Genie annotation reference. Annotations are also used by certain loaders; those annotations are listed in the guide to Thingpedia loaders.
Ok, now you have declared all your APIs and provided the necessary minimum amount of metadata so that Genie can talk to your service.
The next step is to shore up the natural language support. Check out the materials on natural language understanding for Thingpedia devices and dialogues to ensure high-quality understanding of natural language and a good user experience in Genie.