Skip to content

Commit

Permalink
[TypeScript] Update How-To docs (microsoft#1314)
Browse files Browse the repository at this point in the history
* Adding Skills Support to a V4 Bot (not based on Virtual Assistant Template)

* Skill Enabling a V4 Bot (not based on Skill Template)
  • Loading branch information
enzocano authored and ryanisgrig committed May 8, 2019
1 parent 4afe143 commit 9f0f726
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 0 deletions.
107 changes: 107 additions & 0 deletions docs/howto/skills/typescript/addskillsupportforv4bot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Adding Skills Support to a V4 Bot (not based on Virtual Assistant Template)

## Table of Contents
- [Adding Skills Support to a V4 Bot (not based on Virtual Assistant Template)](#adding-skills-support-to-a-v4-bot-not-based-on-virtual-assistant-template)
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Libraries](#libraries)
- [Skill Configuration](#skill-configuration)
- [Skill Dialog Registration](#skill-dialog-registration)
- [Routing utterances to Skills](#routing-utterances-to-skills)

## Overview

Creating a Bot Framework Bot through the [Virtual Assistant template](/docs/overview/virtualassistant.md) is the easiest way to get started with using Skills. If you have an existing v4 based Bot, the recommended approach would be to take the resulting project from this template and bring across your custom dialogs to get started quickly.

If, however you have an existing V4 Bot that you wish to add Skill capability then please follow the steps below.

## Libraries

- Add `botbuilder-solutions` and `botbuilder-skills` npm packages to your solution.

## Skill Configuration

The 'botbuilder-skills' package provides a `ISkillManifest` interface that describes a Skill. Your bot should maintain a collection of registered Skills typically serialized into a `JSON` configuration file. The Virtual Assistant template uses a `skills.json` file for this purpose that can be found in the `src` directory.

That file must have the following structure:
```json
{
"skills": []
}
```

As part of your Configuration processing you should construct a collection of registered Skills by deserializing this file, for example:
```typescript
import { skills as skillsRaw } from './skills.json';
const skills: ISkillManifest[] = skillsRaw;
```

> NOTE: The `botbuilder-skills` package also provides a `IBotSettings` interface that can be used to storage the keys/secrets of the services that will be used to connect services to the bot.
## Skill Dialog Registration
In your `index.ts` file register a `SkillDialog` for each registered skill as shown below, this uses the collection of Skills that you created in the previous step.
```typescript
// Register skill dialogs
const skillDialogs: SkillDialog[] = skills.map((skill: ISkillManifest) => {
const authDialog: MultiProviderAuthDialog|undefined = buildAuthDialog(skill, botSettings);
const credentials: MicrosoftAppCredentialsEx = new MicrosoftAppCredentialsEx(
botSettings.microsoftAppId || '',
botSettings.microsoftAppPassword || '',
skill.msAppId);

return new SkillDialog(skill, credentials, adapter.telemetryClient, skillContextAccessor, authDialog);
});
```

For scenarios where Skills require authentication connections you need to create an associated `MultiProviderAuthDialog`
```typescript
// This method creates a MultiProviderAuthDialog based on a skill manifest.
function buildAuthDialog(skill: ISkillManifest, settings: Partial<IBotSettings>): MultiProviderAuthDialog|undefined {
if (skill.authenticationConnections !== undefined && skill.authenticationConnections.length > 0) {
if (settings.oauthConnections !== undefined) {
const oauthConnections: IOAuthConnection[] | undefined = settings.oauthConnections.filter(
(oauthConnection: IOAuthConnection) => {
return skill.authenticationConnections.some((authenticationConnection: IAuthenticationConnection) => {
return authenticationConnection.serviceProviderId === oauthConnection.provider;
});
});
if (oauthConnections !== undefined) {
return new MultiProviderAuthDialog(oauthConnections);
}
} else {
throw new Error(`You must configure at least one supported OAuth connection to use this skill: ${skill.name}.`);
}
}

return undefined;
}
```

## Routing utterances to Skills

Within your Main/Router dialog you firstly need to ensure the SkillDialogs registered previously are added to the dialog stack:
```typescript
skillDialogs.forEach((skillDialog: SkillDialog) => {
this.addDialog(skillDialog);
});
```

Add the following code after your Dispatcher has executed passing the registered Skills and the Intent returned from the Dispatcher. If the `isSkill` method returns true then you start the appropriate SkillDialog instance passing the Skill Manifest Id and the matching intent.
```typescript
// Identify if the dispatch intent matches any Action within a Skill if so, we pass to the appropriate SkillDialog to hand-off
const identifiedSkill: ISkillManifest | undefined = SkillRouter.isSkill(this.settings.skills, intent);
if (identifiedSkill !== undefined) {
// We have identiifed a skill so initialize the skill connection with the target skill
// the dispatch intent is the Action ID of the Skill enabling us to resolve the specific action and identify slots
await dc.beginDialog(identifiedSkill.id);

// Pass the activity we have
const result: DialogTurnResult = await dc.continueDialog();

if (result.status === DialogTurnStatus.complete) {
await this.complete(dc);
}
} else {
// Your normal intent routing logic
}
```
103 changes: 103 additions & 0 deletions docs/howto/skills/typescript/skillenablingav4bot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Skill Enabling a V4 Bot (not based on Skill Template)

## Table of Contents
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Libraries](#libraries)
- [Adapter](#adapter)
- [Startup](#startup)
- [Add Skill Endpoint](#add-skill-endpoint)
- [Manifest Template](#manifest-template)

## Overview

Creating a Skill through the [Skill template](/docs/tutorials/typescript/skill.md#create-your-skill) is the easiest way to get started with creating a new Skill. If you have an existing v4 based Bot, the recommended approach would be to take the resulting project from this template and bring across your custom dialogs to get started quickly.

If however you want to manually enable your Bot to be called as a Skill follow the steps below.

## Libraries

- Add `botbuilder-solutions` and `botbuilder-skills` npm packages to your solution.

## Adapter

Create a Custom Adapter that derives from the `SkillHttpBotAdapter` and ensure the `SkillMiddleware` is added
```typescript
export class CustomSkillAdapter extends SkillHttpBotAdapter {
constructor(
telemetryClient: TelemetryClient,
conversationState: ConversationState,
skillContextAccessor: StatePropertyAccessor<SkillContext>,
dialogStateAccessor: StatePropertyAccessor<DialogState>,
...
) {
super(telemetryClient);
[...]
this.use(new SkillMiddleware(conversationState, skillContextAccessor, dialogStateAccessor));
[...]
}
}
```

## Startup

Add the new adapter to your `index.ts` file.

```typescript
const skillBotAdapter: CustomSkillAdapter = new CustomSkillAdapter(
telemetryClient,
conversationState,
skillContextAccessor,
dialogStateAccessor,
...);
const skillAdapter: SkillHttpAdapter = new SkillHttpAdapter(
skillBotAdapter
);
```

## Add Skill Endpoint

Update your `index.ts` to handle messages to interact with the bot as a skill.

```typescript
// Listen for incoming assistant requests
server.post('/api/skill/messages', (req: restify.Request, res: restify.Response) => {
// Route received a request to adapter for processing
skillAdapter.processActivity(req, res, async (turnContext: TurnContext) => {
// route to bot activity handler.
await bot.run(turnContext);
});
});
```

## Manifest Template

Create a `manifestTemplate.json` file in the root of your Bot. Ensure at a minimum the root level `id`, `name`, `description` and action details are completed. This file should be shared to the bot that will use this bot as a skill.
```json
{
"id": "",
"name": "",
"description": "",
"iconUrl": "",
"authenticationConnections": [ ],
"actions": [
{
"id": "",
"definition": {
"description": "",
"slots": [ ],
"triggers": {
"utteranceSources": [
{
"locale": "en",
"source": [
"luisModel#intent"
]
}
]
}
}
}
]
}
```

0 comments on commit 9f0f726

Please sign in to comment.