Dustin Coates in Googleassistant

Actions on Google SDK V2 Preview: Intent Handling

Dialogflow (ne API.AI) V1 hits end of life in May of 2018, and the Actions on Google team is working to bring a new JavaScript SDK that will support the new interface. V2 of the Actions on Google SDK is now available in alpha on Github and can be used (gingerly) in Google Assistant apps using Dialogflow V2. We’ll take a look at the new SDK in a series of posts, and today is how to handle Dialogflow intents.

A Refresher on Actions on Google SDK V1

In V1, you would create a map that had keys corresponding to the intent name and the value of a function that handled the inbound intent.

const LIGHT_ACTION = 'lights';
const TEMPERATURE_ACTION = `temperature`;
const ALL_DEVICES_ACTION = `all_devices`;
const RESET_ACTION = `reset`;

function setLights (app) {}
function setTemperature (app) {}
function manageDevices (app) {}
function reset (app) {}

exports.MyAction = functions.https.onRequest((request, response) => {
  const app = new App({request, response});

  let actionMap = new Map();
  actionMap.set(LIGHT_ACTION, setLights);
  actionMap.set(TEMPERATURE_ACTION, setTemperature);
  actionMap.set(ALL_DEVICES_ACTION, manageDevices);
  actionMap.set(RESET_ACTION, reset);

  app.handleRequest(actionMap);
});

It works, but it’s a little clunky. This example doesn’t really show the extent of it, since the handler functions are devoid of any body taking up space. Everything is kept separate from each other, impeding understanding for developers coming to a project for the first time—or a developer returning after an extended time away. (Though, in reality, this isn’t that much different from what you have with the Alexa SDK, but using a map instead of an array of objects.)
Additionally, most everything flowed through the app object that came as an argument to the handler. app.getArgument grabbed argument values, while app.tell handled the response, app.buildBasicCard built a card, etc.

Handling Intents in Actions SDK V2

V2 of the SDK starts by making the intention of the code clearer. Now, instead of actionMap.set (what does that mean to a newcomer, anyway?), there is app.intent.

const functions = require('firebase-functions');
const { dialogflow } = require('actions-on-google');

const app = dialogflow({
  debug: true
});

app.intent('lights', (conv, parameters, triggerQuery) => {
  const light = parameters.light;
  conv.ask(`What do you want to do with that light?`);
  conv.ask(`Do you want to turn that light on?`);
});

exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

The intent handlers accept three arguments: conv, the parameters, and the triggered query. conv replaces the response building that app previously handled. There’s still app, you can see, but it is now global and can thus have global settings, such as debugging status, or can be used to set up data on instatiation. Inside the intent, conv comes with methods to ask or close (similar to ask and tell in V1). The second argument contains the parameters that have been plucked out, as an object. This comes with keys for the parameter name and its associated value.

app.intent('lights', (conv, parameters, triggerQuery) => {
  console.log(parameters);
  // {light: 'living room'}

  const light = parameters.light;
  conv.ask(`What do you want to do with that light?`);
  conv.ask(`Do you want to turn that light on?`);
});

This cleans things up by not requiring app.getArgument for every single argument. Using destructuring cleans it up even more (i.e. app.intent('lights', (conv, {lights})=> {})).

In a future post, I’ll look more at sending the response back from the Actions SDK. That’s it for today for handling intents. Want to know more? Follow along on Twitter to get updates to all of the posts in this series.