ask-cli-x
Version:
Alexa Skills Kit (ASK) Command Line Interfaces
243 lines (242 loc) • 12.5 kB
JavaScript
"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;