UNPKG

ask-cli-x

Version:

Alexa Skills Kit (ASK) Command Line Interfaces

243 lines (242 loc) 12.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EvaluateMode = void 0; const dialog_evaluate_controller_1 = require("../../controllers/dialog-controller/dialog-evaluate-controller"); const inputs_1 = require("../../model/dialog/inputs"); const cli_retriable_error_1 = require("../../exceptions/cli-retriable-error"); const simulation_response_1 = require("../../controllers/dialog-controller/types/simulation-response"); const types_1 = require("../../controllers/dialog-controller/types"); class EvaluateMode extends dialog_evaluate_controller_1.DialogEvaluateController { constructor(config) { // No iea why we had to make a new prop for project? super({ ...config, project: config.projectInstance || config.project }); this.view = config.view; } async start() { this.view.outputHeader(); // Start with the input new session flag and an empty evaluate context. let state = { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.TURN_START, newSession: this.initialNewSession, evaluateContext: { interactionBlock: [], }, }; while (state) { state = await this.handleState(state); } } async handleState(state) { switch (state.state) { case dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.TURN_START: this.view.outputEmpty(); return await this.handleDialogTurn(state.newSession || false, state.evaluateContext); // start correction view if users disagree with the Alexa response case dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_START: // Output header and then transition to the possibly repeating correction states. this.view.outputCorrectionModeHeader(); return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_CONTINUE, correctionContext: state.correctionContext }; case dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_CONTINUE: const nextState = await this.handleDialogCorrection(state.correctionContext); this.view.outputViewSeparator(); return nextState; case dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_COMPLETE: this.view.outputAlexaResponses(state.correctionContext.last.alexaResponses); return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.TURN_START, evaluateContext: this.commitCorrection(state.correctionContext), }; case dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.END: this.view.outputFooter(); return; default: const exhaustive = state; return exhaustive; } } /** * Requests user input, simulates the input, then requests user acceptance on the output. * If the user rejects the output. Transition to the Correction state. */ async handleDialogTurn(newSession, evaluateContext) { var _a; const simulateResult = await this.requestAndSimulateUtteranceUntilSuccessful(newSession, evaluateContext); if ((0, inputs_1.isQuitCommandInput)(simulateResult)) { return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.END }; } const { alexaResponses, delegationType } = simulateResult.last; const egress = delegationType === simulation_response_1.DelegationType.Egress; if (!egress && (0, types_1.isCorrectionTurnResult)(simulateResult.last)) { const partitionedLineGroups = await this.partitionAndFormatAstLines(simulateResult, simulateResult.last, alexaResponses); const acceptAcdl = await this.view.requestUserAcdlResponseAcceptance(partitionedLineGroups); try { if (acceptAcdl) { const updatedEvaluateContext = await this.acceptTurn(simulateResult); return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.TURN_START, newSession: false, evaluateContext: updatedEvaluateContext }; } else { const correctionContext = await this.rejectTurn(simulateResult); return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_START, correctionContext: correctionContext }; } } catch (e) { this.view.outputError((_a = e.message) !== null && _a !== void 0 ? _a : e); throw e; } } else { // Output all responses this.view.outputAlexaResponses(alexaResponses); if (egress) { const doSave = await this.view.requestSaveOnEgress(); if (doSave) { this.view.outputSpecialCommandResult(await this.handleSaveCommand(evaluateContext)); } } // Stay in the turn stat on egress and/or not ACDL return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.TURN_START, newSession: false, evaluateContext }; } } /** * Allows users to enter valid commands until an utterance is given. * Once an utterance is given, simulate the utterance. * If a retry-able error is thrown, warn and go back to asking for user input. * * @returns SimulationResult or a Quit command, intended to be terminal. */ async requestAndSimulateUtteranceUntilSuccessful(newSession, evaluateContext) { var _a; try { const utteranceOrQuit = await this.getUntilUtteranceOrQuit(evaluateContext); if ((0, inputs_1.isQuitCommandInput)(utteranceOrQuit)) { return utteranceOrQuit; } const turn = await this.simulateUtterance(evaluateContext, utteranceOrQuit.utterance, newSession); return { ...evaluateContext, last: turn, }; } catch (e) { if (e instanceof cli_retriable_error_1.RetriableServiceError || e instanceof cli_retriable_error_1.CliRetriableError) { this.view.outputWarning(`${e.message}\n`); return this.requestAndSimulateUtteranceUntilSuccessful(newSession, evaluateContext); } else { this.view.outputError((_a = e.message) !== null && _a !== void 0 ? _a : e); throw e; } } } async handleDialogCorrection(correctionContext) { var _a; const acceptPrediction = await this.requestUserAcceptAcdlPrediction(correctionContext); // User accepted, progress the conversation if (acceptPrediction) { try { const [complete, updatedContext] = this.acceptPrediction(correctionContext); if (complete) { // All done and accepted, finish up the correction state. return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_COMPLETE, correctionContext: updatedContext }; } else { // show next turn return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_CONTINUE, correctionContext: updatedContext }; } } catch (e) { if (e instanceof cli_retriable_error_1.RetriableServiceError || e instanceof cli_retriable_error_1.CliRetriableError) { this.view.outputWarning(`${e.message}\n`); return this.handleDialogCorrection(correctionContext); } else { this.view.outputError((_a = e.message) !== null && _a !== void 0 ? _a : e); throw e; } } } else { const updatedContext = this.rejectPrediction(correctionContext); const updatedContext2 = await this.requestCorrectionAndApplyUntilSuccessful(updatedContext); // Rejected the prediction, and provided a correction // loop back to the start of the correction state to continue the conversation return { state: dialog_evaluate_controller_1.DIALOG_STATE_MACHINE.CORRECTION_CONTINUE, correctionContext: updatedContext2 }; } } /** * Presents ACDL and requests acceptance if applicable * @returns user accept the correction or the correction cannot be accepted. */ async requestUserAcceptAcdlPrediction(correctionContext) { try { this.view.outputPredictedAcdl(this.turnToAcdl(correctionContext)); const disableCorrection = this.shouldDisableTurnCorrection(correctionContext); if (disableCorrection) { this.view.outputDisabledCorrectionMessage(); } // Accept the prediction if the user accepted or if we don't allow for correction. return disableCorrection || (await this.view.requestUserAcceptsPrediction()); } catch (e) { this.view.outputError(e.message); throw e; } } async requestCorrectionAndApplyUntilSuccessful(correctionContent) { try { const correctionOrEndTurn = await this.getUntilCorrectionsOrEndTurn(correctionContent); return await this.updateCorrectionContextWithCorrections(correctionContent, correctionOrEndTurn); } catch (e) { if (e instanceof cli_retriable_error_1.RetriableServiceError || e instanceof cli_retriable_error_1.CliRetriableError) { this.view.outputWarning(`${e.message}\n`); return this.requestCorrectionAndApplyUntilSuccessful(correctionContent); } else { this.view.outputError(e.message); throw e; } } } async getUntilUtteranceOrQuit(evaluateContext) { const utteranceOrCommand = await this.view.requestUserUtteranceOrCommand(); if ((0, inputs_1.isCommand)(utteranceOrCommand)) { if ((0, inputs_1.isQuitCommand)(utteranceOrCommand.command)) { return utteranceOrCommand; } if ((0, inputs_1.isCommandOfType)(utteranceOrCommand.command, [inputs_1.SpecialCommand.SAVE, inputs_1.SpecialCommand.VARS])) { const result = await this.handleOutputSpecialCmds(evaluateContext, utteranceOrCommand.command); this.view.outputSpecialCommandResult(result); } else { throw new cli_retriable_error_1.CliRetriableError(`Command "${utteranceOrCommand.command}" not recognized. Supported commands: ".quit", ".save", ".vars". Please try again.`); } // Repeat on non-terminal command. return await this.getUntilUtteranceOrQuit(evaluateContext); } else { return utteranceOrCommand; } } async getUntilCorrectionsOrEndTurn(evaluateContext) { var _a; const correctionsInput = await this.view.requestUserCorrectionAcdl(); if ((0, inputs_1.isCommand)(correctionsInput.content)) { if ((0, inputs_1.isCommandOfType)(correctionsInput.content.command, [inputs_1.SpecialCommand.END_TURN])) { return correctionsInput.content; } if ((0, inputs_1.isCommandOfType)(correctionsInput.content.command, [inputs_1.SpecialCommand.VARS])) { const result = await this.handleOutputSpecialCmds(evaluateContext, correctionsInput.content.command); this.view.outputSpecialCommandResult(result); } else { throw new cli_retriable_error_1.CliRetriableError(`Command "${correctionsInput.content.command}" not recognized. Supported commands: ".endTurn", ".vars". Please try again.`); } return await this.getUntilCorrectionsOrEndTurn(evaluateContext); } else { return { content: correctionsInput.content, type: !!((_a = correctionsInput.type) === null || _a === void 0 ? void 0 : _a.correction) ? correctionsInput.type : undefined }; } } } exports.EvaluateMode = EvaluateMode;