botbuilder-dialogs-adaptive
Version:
Rule system for the Microsoft BotBuilder dialog system.
281 lines • 13 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ActionScope = exports.ActionScopeCommands = void 0;
/**
* @module botbuilder-dialogs-adaptive
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
const botbuilder_1 = require("botbuilder");
const botbuilder_dialogs_1 = require("botbuilder-dialogs");
const converters_1 = require("../converters");
const telemetryLoggerConstants_1 = require("../telemetryLoggerConstants");
const OFFSET_KEY = 'this.offset';
var ActionScopeCommands;
(function (ActionScopeCommands) {
ActionScopeCommands["GotoAction"] = "goto";
ActionScopeCommands["BreakLoop"] = "break";
ActionScopeCommands["ContinueLoop"] = "continue";
})(ActionScopeCommands = exports.ActionScopeCommands || (exports.ActionScopeCommands = {}));
/**
* `ActionScope` manages execution of a block of actions, and supports Goto, Continue and Break semantics.
*/
class ActionScope extends botbuilder_dialogs_1.Dialog {
/**
* Creates a new `ActionScope` instance.
*
* @param actions The actions for the scope.
*/
constructor(actions = []) {
super();
/**
* The actions to execute.
*/
this.actions = [];
this.actions = actions;
}
/**
* @param property The key of the conditional selector configuration.
* @returns The converter for the selector configuration.
*/
getConverter(property) {
switch (property) {
case 'actions':
return converters_1.DialogListConverter;
default:
return super.getConverter(property);
}
}
/**
* Gets a unique `string` which represents the version of this dialog. If the version
* changes between turns the dialog system will emit a DialogChanged event.
*
* @returns Unique `string` which should only change when dialog has changed in a
* way that should restart the dialog.
*/
getVersion() {
const versions = this.actions.map((action) => action.getVersion() || '').join('');
return botbuilder_1.StringUtils.hash(versions);
}
/**
* Gets the child [Dialog](xref:botbuilder-dialogs.Dialog) dependencies so they can be added to the containers [Dialog](xref:botbuilder-dialogs.Dialog) set.
*
* @returns The child [Dialog](xref:botbuilder-dialogs.Dialog) dependencies.
*/
getDependencies() {
return this.actions;
}
/**
* Called when the [Dialog](xref:botbuilder-dialogs.Dialog) is started and pushed onto the dialog stack.
*
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param _options Optional. Initial information to pass to the dialog.
* @returns A `Promise` representing the asynchronous operation.
*/
beginDialog(dc, _options) {
return __awaiter(this, void 0, void 0, function* () {
if (this.actions && this.actions.length > 0) {
return yield this.beginAction(dc, 0);
}
else {
return yield dc.endDialog();
}
});
}
/**
* Called when the [Dialog](xref:botbuilder-dialogs.Dialog) is _continued_, where it is the active dialog and the
* user replies with a new activity.
*
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @returns A `Promise` representing the asynchronous operation.
*/
continueDialog(dc) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.onNextAction(dc);
});
}
/**
* Called when a child [Dialog](xref:botbuilder-dialogs.Dialog) completed its turn, returning control to this dialog.
*
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param _reason [DialogReason](xref:botbuilder-dialogs.DialogReason), reason why the dialog resumed.
* @param result Optional. Value returned from the dialog that was called. The type
* of the value returned is dependent on the child dialog.
* @returns A `Promise` representing the asynchronous operation.
*/
resumeDialog(dc, _reason, result) {
return __awaiter(this, void 0, void 0, function* () {
if (result && typeof result === 'object' && Object.hasOwnProperty.call(result, 'actionScopeCommand')) {
return yield this.onActionScopeResult(dc, result);
}
return yield this.onNextAction(dc, result);
});
}
/**
* @protected
* Called when returning control to this [Dialog](xref:botbuilder-dialogs.Dialog) with an [ActionScopeResult](xref:botbuilder-dialogs-adaptive.ActionScopeResult)
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param actionScopeResult The [ActionScopeResult](xref:botbuilder-dialogs-adaptive.ActionScopeResult).
* @returns A `Promise` representing the asynchronous operation.
*/
onActionScopeResult(dc, actionScopeResult) {
return __awaiter(this, void 0, void 0, function* () {
switch (actionScopeResult.actionScopeCommand) {
case ActionScopeCommands.GotoAction:
return yield this.onGotoAction(dc, actionScopeResult);
case ActionScopeCommands.BreakLoop:
return yield this.onBreakLoop(dc, actionScopeResult);
case ActionScopeCommands.ContinueLoop:
return yield this.onContinueLoop(dc, actionScopeResult);
default:
throw new Error(`Unknown action scope command returned: ${actionScopeResult.actionScopeCommand}.`);
}
});
}
/**
* @protected
* Called when returning control to this [Dialog](xref:botbuilder-dialogs.Dialog) with an [ActionScopeResult](xref:botbuilder-dialogs-adaptive.ActionScopeResult)
* with the property `ActionCommand` set to `GoToAction`.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param actionScopeResult The [ActionScopeResult](xref:botbuilder-dialogs-adaptive.ActionScopeResult).
* @returns A `Promise` representing the asynchronous operation.
*/
onGotoAction(dc, actionScopeResult) {
return __awaiter(this, void 0, void 0, function* () {
const offset = this.actions.findIndex((action) => {
return action.id == actionScopeResult.actionId;
});
if (offset >= 0) {
return yield this.beginAction(dc, offset);
}
else if (dc.stack.length > 1) {
return yield dc.endDialog(actionScopeResult);
}
else {
throw new Error(`GotoAction: could not find an action of '${actionScopeResult.actionId}'`);
}
});
}
/**
* @protected
* Called when returning control to this [Dialog](xref:botbuilder-dialogs.Dialog) with an [ActionScopeResult](xref:botbuilder-dialogs-adaptive.ActionScopeResult)
* with the property `ActionCommand` set to `BreakLoop`.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param actionScopeResult Contains the actions scope result.
* @returns A `Promise` representing the asynchronous operation.
*/
onBreakLoop(dc, actionScopeResult) {
return __awaiter(this, void 0, void 0, function* () {
return yield dc.endDialog(actionScopeResult);
});
}
/**
* @protected
* Called when returning control to this [Dialog](xref:botbuilder-dialogs.Dialog) with an [ActionScopeResult](xref:botbuilder-dialogs-adaptive.ActionScopeResult)
* with the property `ActionCommand` set to `ContinueLoop`.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param actionScopeResult Contains the actions scope result.
* @returns A `Promise` representing the asynchronous operation.
*/
onContinueLoop(dc, actionScopeResult) {
return __awaiter(this, void 0, void 0, function* () {
return yield dc.endDialog(actionScopeResult);
});
}
/**
* @protected
* Called when the [Dialog](xref:botbuilder-dialogs.Dialog) continues to the next action.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param result Optional. Value returned from the dialog that was called. The type
* of the value returned is dependent on the child dialog.
* @returns A `Promise` representing the asynchronous operation.
*/
onNextAction(dc, result) {
return __awaiter(this, void 0, void 0, function* () {
// Check for any plan changes
let hasChanges = false;
let root = dc;
let parent = dc;
while (parent) {
const ac = parent;
if (ac && ac.changes && ac.changes.length > 0) {
hasChanges = true;
}
root = parent;
parent = root.parent;
}
// Apply any changes
if (hasChanges) {
// Recursively call continueDialog() to apply changes and continue execution.
return yield root.continueDialog();
}
// Increment our offset into the actions and being the next action
const nextOffset = dc.state.getValue(OFFSET_KEY, 0) + 1;
if (nextOffset < this.actions.length) {
return yield this.beginAction(dc, nextOffset);
}
// else we fire the end of actions
return yield this.onEndOfActions(dc, result);
});
}
/**
* @protected
* Called when the [Dialog](xref:botbuilder-dialogs.Dialog)'s action ends.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param result Optional. Value returned from the dialog that was called. The type
* of the value returned is dependent on the child dialog.
* @returns A `Promise` representing the asynchronous operation.
*/
onEndOfActions(dc, result) {
return __awaiter(this, void 0, void 0, function* () {
return yield dc.endDialog(result);
});
}
/**
* @protected
* Starts a new [Dialog](xref:botbuilder-dialogs.Dialog) and pushes it onto the dialog stack.
* @param dc The [DialogContext](xref:botbuilder-dialogs.DialogContext) for the current turn of conversation.
* @param offset Optional, value returned from the dialog that was called. The type
* of the value returned is dependent on the child dialog.
* @returns A `Promise` representing the asynchronous operation.
*/
beginAction(dc, offset) {
return __awaiter(this, void 0, void 0, function* () {
dc.state.setValue(OFFSET_KEY, offset);
if (!this.actions || this.actions.length <= offset) {
return yield dc.endDialog();
}
const action = this.actions[offset];
const actionName = action.constructor.name;
const properties = {
DialogId: action.id,
Kind: `Microsoft.${actionName}`,
ActionId: `Microsoft.${action.id}`,
};
this.telemetryClient.trackEvent({ name: telemetryLoggerConstants_1.TelemetryLoggerConstants.DialogActionEvent, properties: properties });
return yield dc.beginDialog(action.id);
});
}
/**
* @protected
* Builds the compute Id for the dialog.
* @returns A `string` representing the compute Id.
*/
onComputeId() {
const ids = this.actions.map((action) => action.id);
return `ActionScope[${botbuilder_1.StringUtils.ellipsisHash(ids.join(','), 50)}]`;
}
}
exports.ActionScope = ActionScope;
//# sourceMappingURL=actionScope.js.map