UNPKG

botbuilder-dialogs-adaptive

Version:

Rule system for the Microsoft BotBuilder dialog system.

281 lines • 13 kB
"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