Skip to content

Commit 7a13426

Browse files
committed
apply SkillDialog updates from microsoft/botbuilder-dotnet#3474
1 parent c82e31f commit 7a13426

File tree

3 files changed

+77
-50
lines changed

3 files changed

+77
-50
lines changed

libraries/botbuilder-dialogs/src/skillDialog.ts

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,24 @@
66
* Licensed under the MIT License.
77
*/
88

9-
import { Activity, ActivityTypes, BotFrameworkSkill, ConversationState, ConversationReference, StatePropertyAccessor, TurnContext } from 'botbuilder-core';
10-
import { Dialog, DialogTurnResult } from './dialog';
9+
import {
10+
Activity,
11+
ActivityTypes,
12+
ConversationReference,
13+
TurnContext
14+
} from 'botbuilder-core';
15+
import {
16+
Dialog,
17+
DialogInstance,
18+
DialogReason,
19+
DialogTurnResult
20+
} from './dialog';
1121
import { DialogContext } from './dialogContext';
1222
import { SkillDialogArgs } from './skillDialogArgs';
1323
import { SkillDialogOptions } from './skillDialogOptions';
1424

1525
export class SkillDialog extends Dialog {
16-
private readonly _activeSkillProperty: StatePropertyAccessor;
17-
private readonly _conversationState: ConversationState; // Why is this restricted to ConversationState?
18-
private readonly _dialogOptions: SkillDialogOptions;
26+
protected dialogOptions: SkillDialogOptions;
1927

2028
/**
2129
* A sample dialog that can wrap remote calls to a skill.
@@ -24,51 +32,36 @@ export class SkillDialog extends Dialog {
2432
* The options parameter in `beginDialog()` must be a `SkillDialogArgs` object with the initial parameters
2533
* for the dialog.
2634
*
27-
* @param SkillDialogOptions
2835
* @param dialogOptions
29-
* @param ConversationState
30-
* @param conversationState
36+
* @param dialogId
3137
*/
32-
public constructor(dialogOptions: SkillDialogOptions, conversationState: ConversationState) {
33-
super('SkillDialog'); // What about Dialog Id?
38+
public constructor(dialogOptions: SkillDialogOptions, dialogId?: string) {
39+
super(dialogId);
3440
if (!dialogOptions) {
3541
throw new TypeError('Missing dialogOptions parameter');
3642
}
37-
38-
if (!conversationState) {
39-
throw new TypeError('Missing conversationState parameter');
40-
}
41-
42-
this._dialogOptions = dialogOptions;
43-
this._conversationState = conversationState;
44-
45-
this._activeSkillProperty = conversationState.createProperty<BotFrameworkSkill>('botbuilder-dialogs.SkillDialog.ActiveSkillProperty');
43+
this.dialogOptions = dialogOptions;
4644
}
4745

4846
public async beginDialog(dc: DialogContext, options?: {}): Promise<DialogTurnResult> {
49-
const dialogArgs = SkillDialog.validateBeginDialogOptions(options);
47+
const dialogArgs = SkillDialog.validateBeginDialogArgs(options);
5048

5149
await dc.context.sendTraceActivity(`${ this.id }.beginDialog()`, undefined, undefined, `Using activity of type: ${ dialogArgs.activity.type }`);
5250

53-
// Store Skill information for this dialog instance
54-
await this._activeSkillProperty.set(dc.context, dialogArgs.skill);
55-
5651
// Create deep clone of the original activity to avoid altering it before forwarding it.
5752
const clonedActivity = this.cloneActivity(dialogArgs.activity);
5853

5954
// Apply conversation reference and common properties from incoming activity before sending.
6055
const skillActivity = TurnContext.applyConversationReference(clonedActivity, TurnContext.getConversationReference(dc.context.activity), true) as Activity;
6156

6257
// Send the activity to the skill.
63-
await this.sendToSkill(dc, skillActivity, dialogArgs.skill);
58+
await this.sendToSkill(dc.context, skillActivity);
6459
return Dialog.EndOfTurn;
6560
}
6661

6762
public async continueDialog(dc: DialogContext): Promise<DialogTurnResult> {
6863
await dc.context.sendTraceActivity(`${ this.id }.continueDialog()`, undefined, undefined, `ActivityType: ${ dc.context.activity.type }`);
6964

70-
// Retrieve the current skill information from ConversationState
71-
var skillInfo = await this._activeSkillProperty.get(dc.context, null);
7265

7366
// Handle EndOfConversation from the skill (this will be sent to the this dialog by the SkillHandler if received from the Skill)
7467
if (dc.context.activity.type === ActivityTypes.EndOfConversation) {
@@ -79,12 +72,28 @@ export class SkillDialog extends Dialog {
7972
// Forward only Message and Event activities to the skill
8073
if (dc.context.activity.type === ActivityTypes.Message || dc.context.activity.type === ActivityTypes.Event) {
8174
// Just forward to the remote skill
82-
await this.sendToSkill(dc, dc.context.activity, skillInfo);
75+
await this.sendToSkill(dc.context, dc.context.activity);
8376
}
8477

8578
return Dialog.EndOfTurn;
8679
}
8780

81+
public async endDialog(context: TurnContext, instance: DialogInstance, reason: DialogReason): Promise<void> {
82+
// Send of of conversation to the skill if the dialog has been cancelled.
83+
if (reason == DialogReason.cancelCalled || reason == DialogReason.replaceCalled) {
84+
await context.sendTraceActivity(`${ this.id }.EndDialogAsync()`, undefined, undefined, `ActivityType: ${ context.activity.type }`);
85+
86+
const reference = TurnContext.getConversationReference(context.activity);
87+
// Apply conversation reference and common properties from incoming activity before sending.
88+
const activity = TurnContext.applyConversationReference({ type: ActivityTypes.EndOfConversation }, reference, true);
89+
activity.channelData = context.activity.channelData;
90+
91+
await this.sendToSkill(context, activity as Activity);
92+
}
93+
94+
await super.endDialog(context, instance, reason);
95+
}
96+
8897
/**
8998
* Clones the Activity entity.
9099
* @param activity Activity to clone.
@@ -93,18 +102,14 @@ export class SkillDialog extends Dialog {
93102
return Object.assign({} as Activity, activity);
94103
}
95104

96-
private static validateBeginDialogOptions(options: any): SkillDialogArgs {
105+
private static validateBeginDialogArgs(options: any): SkillDialogArgs {
97106
if (!options) {
98107
throw new TypeError('Missing options parameter');
99108
}
100109

101110
const dialogArgs = options as SkillDialogArgs;
102111

103-
if (dialogArgs.skill == undefined || dialogArgs.skill == null) {
104-
throw new TypeError(`"skill" undefined or null in options`);
105-
}
106-
107-
if (dialogArgs.activity === undefined || dialogArgs.activity === null) {
112+
if (!dialogArgs.activity) {
108113
throw new TypeError(`"activity" is undefined or null in options.`);
109114
}
110115

@@ -117,15 +122,16 @@ export class SkillDialog extends Dialog {
117122
return dialogArgs;
118123
}
119124

120-
private async sendToSkill(dc: DialogContext, activity: Activity, skillInfo: BotFrameworkSkill): Promise<void> {
125+
private async sendToSkill(context: TurnContext, activity: Activity): Promise<void> {
126+
// Create a conversationId to interact with the skill and send the activity
127+
const skillConversationId = await this.dialogOptions.conversationIdFactory.createSkillConversationId(TurnContext.getConversationReference(activity) as ConversationReference);
128+
121129
// Always save state before forwarding
122130
// (the dialog stack won't get updated with the skillDialog and things won't work if you don't)
123-
await this._conversationState.saveChanges(dc.context, true);
124-
125-
// Create a conversationId to interact with the skill and send the activity
126-
const skillConversationId = await this._dialogOptions.conversationIdFactory.createSkillConversationId(TurnContext.getConversationReference(activity) as ConversationReference);
127-
const response = await this._dialogOptions.skillClient.postActivity(this._dialogOptions.botId, skillInfo.appId, skillInfo.skillEndpoint, this._dialogOptions.skillHostEndpoint, skillConversationId, activity);
128-
131+
await this.dialogOptions.conversationState.saveChanges(context, true);
132+
const skillInfo = this.dialogOptions.skill;
133+
const response = await this.dialogOptions.skillClient.postActivity(this.dialogOptions.botId, skillInfo.appId, skillInfo.skillEndpoint, skillInfo.skillEndpoint, skillConversationId, activity);
134+
129135
// Inspect the skill response status
130136
if (!(response.status >= 200 && response.status <= 299)) {
131137
throw new Error(`Error invoking the skill id: "${ skillInfo.id }" at "${ skillInfo.skillEndpoint }" (status is ${ response.status }). \r\n ${ response.body }`);

libraries/botbuilder-dialogs/src/skillDialogArgs.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,12 @@
66
* Licensed under the MIT License.
77
*/
88

9-
import { Activity, BotFrameworkSkill } from 'botbuilder-core';
9+
import { Activity } from 'botbuilder-core';
1010

1111
/**
1212
* A class with dialog arguments for a SkillDialog.
1313
*/
1414
export interface SkillDialogArgs {
15-
/**
16-
* The BotFrameworkSkill that the dialog will call.
17-
*/
18-
skill: BotFrameworkSkill;
19-
2015
/**
2116
* The Activity to send to the skill.
2217
*/

libraries/botbuilder-dialogs/src/skillDialogOptions.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,41 @@
66
* Licensed under the MIT License.
77
*/
88

9-
import { BotFrameworkClient, SkillConversationIdFactoryBase } from 'botbuilder-core';
9+
import {
10+
BotFrameworkClient,
11+
BotFrameworkSkill,
12+
ConversationState,
13+
SkillConversationIdFactoryBase
14+
} from 'botbuilder-core';
1015

1116
export interface SkillDialogOptions {
12-
17+
/**
18+
* The the Microsoft app ID of the bot calling the skill.
19+
*/
1320
botId: string;
1421

22+
/**
23+
* The BotFrameworkSkill that the dialog will call.
24+
*/
25+
conversationIdFactory: SkillConversationIdFactoryBase;
26+
27+
/**
28+
* The ConversationState to be used by the Dialog.
29+
*/
30+
conversationState: ConversationState;
31+
32+
/**
33+
* The BotFrameworkSkill the dialog will call.
34+
*/
35+
skill: BotFrameworkSkill;
36+
37+
/**
38+
* The BotFrameworkClient used to call the remote skill.
39+
*/
1540
skillClient: BotFrameworkClient;
1641

42+
/**
43+
* The callback Url for the skill host.
44+
*/
1745
skillHostEndpoint: string;
18-
19-
conversationIdFactory: SkillConversationIdFactoryBase;
2046
}

0 commit comments

Comments
 (0)