Writing Action Code

Actions are snippets of JavaScript (ES5) code running in the context of the conversation session as part of a conversation dialog step. Actions offers enormous power to the scenario composer. Basically, it allows you to take control over the Bot Framework's APIs to be able to modify and extend your bot's functionality. You can add an Action object anywhere on the designer canvas by dragging the Action icon onto the canvas. An Action object has one entry point and one exit node.
Asynchronous actions
There are two types of actions: synchronous and asynchronous. In synchronous code, when the code snippets finish execution the next element is called automatically.
On the other hand, when writing asynchronous code, you must check the Asynchronous checkbox so that the automatic call to the next element will be canceled. The Health Bot Service framework can't assume when to call the next element, so you as the scenario author need to provide explicit instructions on when to move to the next element by using a next() expression. See an example of asynchronous action in the section Writing actions best practices.
Actions runtime context
Code written in an action runs in a special runtime sandbox called a NodeJS VM. When this context is created, it is empty of any objects -- a clean slate. We need to pass to this VM all the objects the author of the action might need to complete their task.
The author will want to pass their most used objects to the action, in addition to the require object -- the one that allows you to import other node objects as long as they exist in our package.json.
Below is a list of objects we pass to the action sandbox with links to more information:
| Object | Description |
|---|---|
| Session | Bot framework's current running session. |
| Require | Allows you to import node modules. This is a special version of require you can use to import only packages that are white listed |
| Builder | Allows you to build bot messages, as well as attachments and cards, and send them to the client. |
| Moment | Allows you to manipulate the date and time library. |
| Next | next() is the function you should call when you want to progress to the next step in an asynchronous action. |
| request-promise | Follow the link to view the request-promise library. This object is used to call rest APIs. |
| Config | Configuration object allows access to the values of tenants’ configuration. |
| Underscore | Follow the link to view a useful JavaScript library. |
White Listed Packages
Below is a list of useful Node JS modules you can import with require:
| Package | Description |
|---|---|
crypto |
Cryptographical functions |
path |
Path utilities |
string-decoder |
String utilities |
querystring |
Query string parsing |
url |
Url parsing |
util |
NodeJS Utilities |
jsonwebtoken |
JSON Web Token implementation (symmetric and asymmetric) |
node-sha1 |
Exports a SHA1 function that uses node's crypto module under the hood |
object-path |
Access deep object properties using a path |
request-promise |
The simplified HTTP request client request with Promise support, powered by Bluebird |
soap |
A minimal node SOAP client |
strformat |
String formatting for Node.js and AngularJS |
to-markdown |
HTML-to-Markdown converter |
ttl |
Simple in-memory cache for JavaScript |
underscore |
JavaScript's functional programming helper library |
xml2js |
Simple XML to JavaScript object converter |
Extending the session function
In addition to all the built-in functionality of the session function, the Health Bot Service has added custom programmatic functionality for you, the author.
| Function | Description |
|---|---|
session.trace(message: string, level:number) |
Output trace string to the debug window level: 0-3 |
session.saveFeedback(message: string) |
Write feedback string for this user |
Writing actions best practices
The following is a brief list of best practices to keep in mind when authoring actions:
You can always press Ctrl + Space to get a list of variables and functions you can use in actions.
Be careful not to write infinite loops or overly heavy code in an action. Actions can't run for more than two seconds. After two seconds, the action will fail with a timeout error.
Note: This does not mean that asynchronous operations can't run for more than two seconds.
You can access the arguments passed to the current scenario by using the ${scenarioArgs} variable.
Example
See below for an example of an asynchronous action for saving feedback:
session.saveFeedback("This was a very good experience").then(function() {
next();
}).catch(function(err) {
session.trace("Error writing feedback " + err.message, 3 /*crtitical error*/);
});
Writing in-line expressions
Everything that is available to the action author is also available in in-line expressions in some steps. These expressions should be very simple -- for example, concatenating strings. If you want to write more complex code, use actions before you get to the step that needs the result from the expression.
The in-line expression will not be evaluated if there is only a literal string. The string "as-is" will be returned.