Skip to content

Commit 4ee8b03

Browse files
chon219stevengum
andauthored
Updated Dialog Manager to work with skills (#2343)
* updated dialog manager to support skills * reordered properties of dialog manager * make dialog manager's dialogs property public * added tests for dialog manager * code style change * added test to get/set root dialog of dialog manager * move sendStateSnapshotTrace() to dialog manager * added test for state trace in dialog manager * added skill extensions to inject skill client and conversation id factory * updated test of beginSkill to use extensions * use static functions instead of extensions Co-authored-by: Steven Gum <[email protected]>
1 parent fd3e25f commit 4ee8b03

File tree

7 files changed

+474
-74
lines changed

7 files changed

+474
-74
lines changed

libraries/botbuilder-dialogs-adaptive/src/actions/beginSkill.ts

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
* Copyright (c) Microsoft Corporation. All rights reserved.
66
* Licensed under the MIT License.
77
*/
8-
import { SkillDialog, SkillDialogOptions, DialogContext, DialogTurnResult, DialogManager, BeginSkillDialogOptions } from 'botbuilder-dialogs';
8+
import { SkillDialog, SkillDialogOptions, DialogContext, DialogTurnResult, BeginSkillDialogOptions } from 'botbuilder-dialogs';
99
import { BoolExpression, StringExpression } from 'adaptive-expressions';
10+
import { Activity, ActivityTypes } from 'botbuilder-core';
1011
import { TemplateInterface } from '../template';
11-
import { Activity, ActivityTypes, BotFrameworkClient, SkillConversationIdFactoryBase } from 'botbuilder-core';
12-
13-
const SKILL_CLIENT = Symbol('skillClient');
14-
const CONVERSATION_ID_FACTORY = Symbol('conversationIdFactory');
12+
import { skillClientKey, skillConversationIdFactoryKey } from '../skillExtensions';
1513

1614
export class BeginSkill extends SkillDialog {
1715

@@ -87,14 +85,14 @@ export class BeginSkill extends SkillDialog {
8785
// Setup the skill to call
8886
const botId = this.botId.getValue(dcState);
8987
const skillHostEndpoint = this.skillHostEndpoint.getValue(dcState);
90-
if (botId) { this.dialogOptions.botId = botId }
91-
if (skillHostEndpoint) { this.dialogOptions.skillHostEndpoint = skillHostEndpoint }
92-
if (this.skillAppId) { this.dialogOptions.skill.id = this.dialogOptions.skill.appId = this.skillAppId.getValue(dcState) }
93-
if (this.skillEndpoint) { this.dialogOptions.skill.skillEndpoint = this.skillEndpoint.getValue(dcState) }
94-
if (this.connectionName) { this.dialogOptions.connectionName = this.connectionName.getValue(dcState) }
95-
if (!this.dialogOptions.conversationState) { this.dialogOptions.conversationState = dc.dialogManager.conversationState }
96-
if (!this.dialogOptions.skillClient) { this.dialogOptions.skillClient = dc.context.turnState.get(SKILL_CLIENT) }
97-
if (!this.dialogOptions.conversationIdFactory) { this.dialogOptions.conversationIdFactory = dc.context.turnState.get(CONVERSATION_ID_FACTORY) }
88+
if (botId) { this.dialogOptions.botId = botId; }
89+
if (skillHostEndpoint) { this.dialogOptions.skillHostEndpoint = skillHostEndpoint; }
90+
if (this.skillAppId) { this.dialogOptions.skill.id = this.dialogOptions.skill.appId = this.skillAppId.getValue(dcState); }
91+
if (this.skillEndpoint) { this.dialogOptions.skill.skillEndpoint = this.skillEndpoint.getValue(dcState); }
92+
if (this.connectionName) { this.dialogOptions.connectionName = this.connectionName.getValue(dcState); }
93+
if (!this.dialogOptions.conversationState) { this.dialogOptions.conversationState = dc.dialogManager.conversationState; }
94+
if (!this.dialogOptions.skillClient) { this.dialogOptions.skillClient = dc.context.turnState.get(skillClientKey); }
95+
if (!this.dialogOptions.conversationIdFactory) { this.dialogOptions.conversationIdFactory = dc.context.turnState.get(skillConversationIdFactoryKey); }
9896

9997
// Get the activity to send to the skill.
10098
options = {} as BeginSkillDialogOptions;
@@ -126,17 +124,6 @@ export class BeginSkill extends SkillDialog {
126124
protected onComputeId(): string {
127125
const appId = this.skillAppId ? this.skillAppId.toString() : '';
128126
const activity = this.activity ? this.activity.toString() : '<activity>';
129-
return `Skill[${appId}:${activity}]`;
130-
}
131-
132-
/**
133-
* Configures the skill client and conversation ID factory to use.
134-
* @param dm DialogManager to configure.
135-
* @param skillClient Skill client instance to use.
136-
* @param conversationIdFactory Conversation ID factory to use.
137-
*/
138-
static setSkillHostOptions(dm: DialogManager, skillClient: BotFrameworkClient, conversationIdFactory: SkillConversationIdFactoryBase): void {
139-
dm.initialTurnState.set(SKILL_CLIENT, skillClient);
140-
dm.initialTurnState.set(CONVERSATION_ID_FACTORY, conversationIdFactory);
127+
return `Skill[${ appId }:${ activity }]`;
141128
}
142129
}

libraries/botbuilder-dialogs-adaptive/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export * from './input';
1919
export * from './luis';
2020
export * from './recognizers';
2121
export * from './selectors';
22+
export * from './skillExtensions';
2223
export * from './templates';
2324
export * from './adaptiveDialog';
2425
export * from './languageGenerationMiddleware';
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @module botbuilder-dialogs-adaptive
3+
*/
4+
/**
5+
* Copyright (c) Microsoft Corporation. All rights reserved.
6+
* Licensed under the MIT License.
7+
*/
8+
9+
import { DialogManager } from 'botbuilder-dialogs';
10+
import { BotFrameworkClient, SkillConversationIdFactoryBase } from 'botbuilder-core';
11+
12+
export const skillClientKey = Symbol('SkillClient');
13+
export const skillConversationIdFactoryKey = Symbol('SkillConversationIdFactory');
14+
15+
export class SkillExtensions {
16+
/**
17+
* Configures the skill client to use.
18+
*/
19+
public static useSkillClient(dialogManager: DialogManager, skillClient: BotFrameworkClient): DialogManager {
20+
dialogManager.initialTurnState.set(skillClientKey, skillClient);
21+
return dialogManager;
22+
}
23+
24+
/**
25+
* Configures the skill conversation id factory to use.
26+
*/
27+
public static useSkillConverationIdFactory(dialogManager: DialogManager, skillConversationIdFactory: SkillConversationIdFactoryBase): DialogManager {
28+
dialogManager.initialTurnState.set(skillConversationIdFactoryKey, skillConversationIdFactory);
29+
return dialogManager;
30+
}
31+
}

libraries/botbuilder-dialogs-adaptive/tests/beginSkill.test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const {
1212
} = require('botbuilder-core');
1313
const { BoolExpression, StringExpression } = require('adaptive-expressions');
1414
const { DialogManager, DialogTurnStatus } = require('botbuilder-dialogs');
15-
const { BeginSkill } = require('../lib')
15+
const { BeginSkill, SkillExtensions } = require('../lib')
1616

1717

1818
class SimpleConversationIdFactory extends SkillConversationIdFactoryBase {
@@ -81,7 +81,8 @@ describe('BeginSkill', function() {
8181
const conversationState = new ConversationState(new MemoryStorage());
8282
const dm = new DialogManager();
8383
dm.conversationState = conversationState;
84-
BeginSkill.setSkillHostOptions(dm, skillClient, new SimpleConversationIdFactory());
84+
SkillExtensions.useSkillClient(dm, skillClient);
85+
SkillExtensions.useSkillConverationIdFactory(dm, new SimpleConversationIdFactory());
8586

8687
// Setup skill dialog
8788
const dialog = new BeginSkill();

libraries/botbuilder-dialogs/src/dialogHelper.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Activity,
1414
TurnContext,
1515
} from 'botbuilder-core';
1616
import { DialogContext, DialogState } from './dialogContext';
17-
import { Dialog, DialogTurnStatus } from './dialog';
17+
import { Dialog, DialogTurnStatus, DialogTurnResult } from './dialog';
1818
import { DialogEvents } from './dialogEvents';
1919
import { DialogSet } from './dialogSet';
2020
import { AuthConstants, GovConstants, isSkillClaim } from './prompts/skillsHelpers';
@@ -80,7 +80,7 @@ export async function runDialog(dialog: Dialog, context: TurnContext, accessor:
8080
}
8181

8282
if (result.status === DialogTurnStatus.complete || result.status === DialogTurnStatus.cancelled) {
83-
if (sendEoCToParent(context)) {
83+
if (shouldSendEndOfConversationToParent(context, result)) {
8484
const endMessageText = `Dialog ${ dialog.id } has **completed**. Sending EndOfConversation.`;
8585
await context.sendTraceActivity(telemetryEventName, result.result, undefined, `${ endMessageText }`);
8686

@@ -95,7 +95,12 @@ export async function runDialog(dialog: Dialog, context: TurnContext, accessor:
9595
* Helper to determine if we should send an EoC to the parent or not.
9696
* @param context
9797
*/
98-
function sendEoCToParent(context: TurnContext): boolean {
98+
export function shouldSendEndOfConversationToParent(context: TurnContext, turnResult: DialogTurnResult): boolean {
99+
if (!(turnResult.status == DialogTurnStatus.complete || turnResult.status == DialogTurnStatus.cancelled)) {
100+
// The dialog is still going, don't return EoC.
101+
return false;
102+
}
103+
99104
const claimIdentity = context.turnState.get(context.adapter.BotIdentityKey);
100105
// Inspect the cached ClaimsIdentity to determine if the bot was called from another bot.
101106
if (claimIdentity && isSkillClaim(claimIdentity.claims)) {
@@ -114,7 +119,7 @@ function sendEoCToParent(context: TurnContext): boolean {
114119
}
115120

116121
// Recursively walk up the DC stack to find the active DC.
117-
function getActiveDialogContext(dialogContext: DialogContext): DialogContext {
122+
export function getActiveDialogContext(dialogContext: DialogContext): DialogContext {
118123
const child = dialogContext.child;
119124
if (!child) {
120125
return dialogContext;
@@ -123,7 +128,7 @@ function getActiveDialogContext(dialogContext: DialogContext): DialogContext {
123128
return getActiveDialogContext(child);
124129
}
125130

126-
function isFromParentToSkill(context: TurnContext): boolean {
131+
export function isFromParentToSkill(context: TurnContext): boolean {
127132
// If a SkillConversationReference exists, it was likely set by the SkillHandler and the bot is acting as a parent.
128133
if (context.turnState.get(SkillConversationReferenceKey)) {
129134
return false;

0 commit comments

Comments
 (0)