Exchanging data with Skills
Exchange data to and from Skills using the SkillDialog
There are situations when it’s helpful to pass data between Skills. Information can be provided to a Skill to perform slot-filling therefore limiting the interactions the user has to perform (e.g. share the current location). Additionally, a Skill can interact with the user through responses as usual but also return data back to the underlying caller which can be used for other purposes. For example, a Virtual Assistant could invoke the Calendar, ToDo and Weather Skill to retrieve information and generate a “Your Day Today” card experience bringing together disparate information. These action
interactions could be silent to the end user with data being returned from each interaction or be interactive depending on your scenario.
Bot Framework Skills provides the capability to pass data to a Skill through the Value
property on the Activity sent to the Skill through the SkillDialog. Conversely, when a Skill ends a dialog using EndDialogAsync
an object can be returned which is marshalled back to the caller for use. You can set this Value property in any-way you desire but an example end to end flow is shown below to guide next steps.
Action invocation is supported by Bot Framework based Bots including Virtual Assistant along with Power Virtual Agents.
Pre and Post Processing
In order to pass data to a Skill and process data returned from a Skill, one technique is to create a Pre
and Post
waterfall step for each Skill you wish to invoke, an example of this is shown below.
var skillSteps = new WaterfallStep[]
{
PreSkillStepAsync,
PostSkillStepAsync,
};
AddDialog(new WaterfallDialog("WeatherActionInvoke", skillSteps));
You can then invoke this Skill by starting the Waterfall dialog:
return await innerDc.BeginDialogAsync("WeatherActionInvoke");
Sending data to a Skill
In the Pre
processing step you can pass data to the Skill by populating the Value
property on the Activity with the object you wish to serialize and pass to the Skill. The example below, shows an Action
within the Skill called WeatherForecast
being invoked and location information being passed. This activity is then passed to the SkillDialog which will process and send across to the skill.
private async Task<DialogTurnResult> PreSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var evt = stepContext.Context.Activity.AsEventActivity();
if (evt != null)
{
LocationInfo location = new LocationInfo();
location.Location = "51.4644018,-2.1177246,14";
var activity = (Activity)Activity.CreateEventActivity();
activity.Name = "WeatherForecast";
activity.Value = location;
// Create the BeginSkillDialogOptions
var skillDialogArgs = new BeginSkillDialogOptions { Activity = activity };
// Start the skillDialog instance with the arguments.
return await stepContext.BeginDialogAsync("WeatherSkill", skillDialogArgs, cancellationToken);
}
return await stepContext.NextAsync();
}
Retrieving data after a Skill interaction
The Post
processing step will be invoked once the Skill processing has been completed. If data has been returned you will find this within the stepContext.Result
property.
private async Task<DialogTurnResult> PostSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// stepContext.Result has any returning data from a Skill
if (stepContext.Result != null)
{
var returnObject = JsonConvert.SerializeObject(stepContext.Result);
// Perform your processing here
}
return await stepContext.NextAsync();
}
Retrieving data within a Skill
Within your Skill, you then need to handle the Event triggered by the previous steps to retrieve the data and start dialog processing as usual. With the Virtual Assistant and Skill Template this would be within your RouteStepAsync
method. The example below shows handling the WeatherForecast
event used above and retrieving data from the Value
property of an activity. You could then populate the state object with information used by downstream dialogs. An example Action is provided with the Skill Template and you can review the implementation here
case "WeatherForecast":
{
LocationInfo locationData = null;
if (ev.Value is JObject location)
{
locationData = location.ToObject<LocationInfo>();
// Process data here
}
// Start a dialog to process..
return await stepContext.BeginDialogAsync(YOUR_DIALOG.id, options);
Returning data back to the caller from a Skill
Finally, once a Skill has finished processing it can optionally decide to return supporting data to the caller through the result
parameter on EndDialogAsync
. You have complete control over the structure of the returned object. In this example the forecast data is returned to the caller which can make use of it as required.
return await sc.EndDialogAsync(new WeatherForecastInformation { Forecast = forecast });
Summary
Exchanging data to and from Skills is an optional, but powerful way to build proactive and reactive experiences including those that aggregate data from a variety of Skills to create a more unified experience.