Custom plugins
A plugin is a custom set of actions that can be added to your BotTalk scenario. Plugins can extend functionality or add new features to BotTalk. BotTalk plugins can be written in any programming language and integrate seamlessly with BotTalk using the Plugin Protocol.
In order to create you own BotTalk plugin you should have a basic understanding of any programming language and you should be able to run your own server.
Steps to Create a BotTalk Plugin
- Identify what actions your plugin will add to BotTalk
- Create a
Plugin Manifest
- Add your plugin to BotTalk through
Discovery Process
- Implement the logic for your plugin’s actions on your server
Identify Plugin Actions
Since a plugin is a set of actions, a good place to design your own plugin will be to identify the actions you want to implement.
Use Case 1: Plugin as an API Wrapper
Say, you want to extend BotTalk with some features that will help you make requests to OpenWeather API. You could try using getUrl
action for this of course. But you want to separate your business logic and scenario logic.
In your scenario you want to be able to use the current
action to get the current weather for the selected city. So let’s take a look how this action might look like, when your plugin is finished:
- name: Check weather for City
actions:
- btopenweather.current:
city: '{{my_city}}'
units: 'metric'
- sendText: >
The current temperature in {{my_city}} is {{ btopenweather_temp }}.
The humidity is {{ btopenweather_humidity }}.
And the pressure is {{ btopenweather_pressure }}.
As you can see we introduce the plugin using a namespace btopenweather
(we’ll talk about namespaces more in Discover Process
section). It is followed by the action name current
that takes two parameters - city
and units
.
In the next action sendText
you can see the use of three variables: btopenweather_temp
, btopenweather_humidity
, btopenweather_pressure
. Those are the return values that our plugin provides. Once again you can identify the variables the plugin returns by the namespace btopenweather
followed by the underscore.
Use Case 2: Extend JSON Response with a Plugin
Let’s go even further. What if you not only wanted to create a plugin as a way to conveniently wrap a third-party API with the BotTalk syntax? What if you wanted to introduce really new functionality? For instance, wouldn’t it be cool if your Google Action not only asked a user for a city, but also gave the visual clues - called suggestion chips:
At the time of this writing, BotTalk does not support suggestion chips, so you decide to extend this functionality yourself!
How such an action might look like when your plugin is finished? Something like that:
- name: Initial step
actions:
- sendText: 'What city are you in? '
- btopenweather.cities:
cities:
- Berlin
- Cologne
- London
- getInput:
next:
what_city: Check weather for City
You can directly see your plugin action by the namespace prefix btopenweather
. The action takes one parameter cities
, which is a list of cities you want to appear in Google Action as suggestion chips.
Use Case 3: Replace JSON Response with a Plugin
But it’s not all. Now that you’ve got the taste of real power that BotTalk plugins give you, you want to do something amazing: you want to send the complete payload to an assistant directly.
For example, you want to provide a specific output that only Echo Show devices with screen support - List Templates.
Before Plugins in order to do that you would have to abandon BotTalk completely and write everything from scratch on your server. But now you can easily let BotTalk do the hard parts - state management, dialog flow, sessions - and only do this one part - List Rendering - on your server.
That’s how the finished action might look like in BotTalk scenario:
- name: Replace Output Completely
actions:
- btopenweather.list:
output: true
Your plugin defines a new action list
that only have one purpose - make a request to your server and return the complete json
directly to the Echo Show of the user. As soon as BotTalk sees output: true
- it knows all it has to do is just transfer your response to an assistant.
And yes, your plugin can also get an access to the whole request json
from the assistant: just use input: true
directive in your plugin action!
Create a Plugin Manifest
Now that you identified how your future plugin actions will look like in BotTalk scenarios, it’s time to define them in a Plugin Manifest.
Plugin Manifest is a json
format that your server sends to BotTalk in order for it to identify what kind actions your plugin introduces, what parameters they need and what return values they might return.
Let’s take a look at the Plugin Manifest for our plugin:
{
"service":"OpenWeather Plugin for BotTalk",
"description":"Wrapping the OpenWeather API and giving it as the BotTalk actions",
"actions":{
"current":{
"endpoint":"/weather_plugin/current",
"description":"Current weather in the city",
"params":{
"city":"The name of the city",
"units":"The measurements units. For Fahrenheit use units=imperial, for Celsius use units=metric"
},
"returns":{
"temp":"Current temperature",
"pressure":"Current pressure",
"humidity":"Current humidity",
"temp_min":"Minimal temperature",
"temp_max":"Maximum temperature"
}
},
"cities":{
"endpoint":"/weather_plugin/cities",
"description":"Get the list of cities - just a shortcut",
"params":{
"cities":"An array of city names"
}
},
"list":{
"endpoint":"/weather_plugin/list",
"description":"Completely replaces output and sends it directly to smart assistant. Demostrated here is the ListTemplate2 for Alexa"
}
}
}
Here is the Plugin Manifest schema for your reference:
service
: A short name for your plugindescription
: What does you plugin supposed to do?actions
: An object with actions that your plugin introduces.[action_name]
: This is the name that you will use after your plugin namespace followed by the dot.endpoint
: To which address BotTalk should send aPOST
request, once your plugin action has been calleddescription
: What does this action do?params
: The object with parameters that your new action takes.[param_name]: [Description of possible values]
returns
: What variables does your plugin return?[variable_name]: [Description of the possible value]
As you can see your server needs to provide 3 endpoints for your actions: /weather_plugin/current
, /weather_plugin/cities
and /weather_plugin/list
.
Every time BotTalk meets your plugin action in the scenario it will make a POST
request to the corresponding endpoint. Sending the parameters that you defined in the POST
body.
Adding a Plugin to BotTalk - Discovery Process
Now that you have written your Plugin Manifest it’s time to add it to BotTalk.
You do that by opening the Plugins tab and clicking on the Create your own plugin button:
In this form you can give your plugin a name and provide a unique namespace that will identify your plugin actions. The URL endpoint of your plugin is the URL that BotTalk calls to get your Plugin Manifest (see the previous section). As a last parameter in the form you’re asked to provide a secret token. BotTalk will subscribe every request to your server endpoints with that token. It is your responsibility to check for this token on the server side.
After you fill in the form and send it the BotTalk will start the discovery process - meaning it will try getting you Plugin Manifest by calling the endpoint you’ve provided.
When the discovery is finished and your Plugin Manifest if validated, you will see you plugin in the plugin list. Including all the actions and parameters you have written in your manifest:
If you want to change your actions, add new ones, edit some parameters etc. - you can do so by editing your Plugin Manifest and then clicking on the Re-Discovery button.
Implement the Logic for Plugin Actions
Now that you defined the actions for your plugin and let the BotTalk discover your plugin, it’s time to actually implement the logic for you actions.
In this section we’ll only describe the json
the endpoints should return in order for your actions to work. You can see the actual implementation in our GitHub Respository.
current
As we described before in our Plugin Manifest this action takes two parameters: city
and units
and returns the JSON object with the current weather conditions:
{
"temp": 15.2,
"pressure": 1038,
"humidity": 41,
"temp_min": 14,
"temp_max": 16
}
Just a reminder: BotTalk stores those values as context variables
by prefixing them with your plugin’s namespace and underscore. So you can use them in your scenario like that:
- name: Check weather for City
actions:
- btopenweather.current:
city: '{{my_city}}'
units: 'metric'
- sendText: >
The current temperature in {{my_city}} is {{ btopenweather_temp }}.
The humidity is {{ btopenweather_humidity }}.
And the pressure is {{ btopenweather_pressure }}.
cities
For this action we need to do something more sophisticated on the server side. We need to tell the BotTalk to inject a certain object into the json
response it will then send back to the assistant.
We do that by providing the following response:
{
"inject": {
"payload.google.richResponse.suggestions": [
{
"title": "Cologne"
},
{
"title": "Berlin"
},
{
"title": "London"
}
]
}
}
So essentially we’re telling BotTalk that we want to inject
our custom object containing suggestion chips into the following json key: payload.google.richResponse.suggestions
.
You can learn more about the json
structure of Google Action response for suggestion chips here.
list
Finally, our most ambitious goal was to replace the response BotTalk is sending to an assistant completely. Remember, we’re doing that in order to implement a custom List Rendering for Echo Show that BotTalk does not support (yet) out of the box.
We do that by taking the whole response json
and packing it into the output
key.
That’s how our plugin endpoint response will look like:
{
"output": {
"version": "1.0",
"response": {
"shouldEndSession": true,
"directives": [
{
"type": "Display.RenderTemplate",
"template": {
"type": "ListTemplate2",
"listItems": [
{
"token": "token",
"image": {
"sources": [
{
"url": "https://via.placeholder.com/1200x1000"
}
],
"contentDescription": "Description"
},
"textContent": {
"primaryText": {
"text": "primary text",
"type": "RichText"
},
"secondaryText": {
"text": "secondary text",
"type": "RichText"
},
"tertiaryText": {
"text": "tertiary text",
"type": "RichText"
}
}
},
{
"token": "token",
"image": null,
"textContent": {
"primaryText": {
"text": "primary text",
"type": "RichText"
},
"secondaryText": {
"text": "secondary text",
"type": "RichText"
},
"tertiaryText": {
"text": "tertiary text",
"type": "RichText"
}
}
}
],
"title": "Title",
"token": "token"
}
}
],
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Here is your list, soldier</speak>"
}
},
"sessionAttributes": {}
}
}
In you BotTalk scenario all you have to do is define output: true
under this action:
- name: Replace Output Completely
actions:
- btopenweather.list:
output: true
This way the response your plugin’s endpoint provided will be sent to an assistant resulting in this beautiful list template on Echo Show: