import { Intent } from 'ask-sdk-model'; import { Control, ControlInitiativeHandler, ControlInputHandler, ControlInputHandlingProps, ControlProps, ControlState } from '../../controls/Control'; import { ControlInput } from '../../controls/ControlInput'; import { ControlResultBuilder } from '../../controls/ControlResult'; import { ControlServicesProps } from '../../controls/ControlServices'; import { InteractionModelContributor } from '../../controls/mixins/InteractionModelContributor'; import { StateValidationFunction } from '../../controls/Validation'; import { ControlInteractionModelGenerator } from '../../interactionModelGeneration/ControlInteractionModelGenerator'; import { ModelData } from '../../interactionModelGeneration/ModelTypes'; import { ResponseStyleEvaluator } from '../../modality/ModalityEvaluation'; import { ControlResponseBuilder } from '../../responseGeneration/ControlResponseBuilder'; import { SystemAct } from '../../systemActs/SystemAct'; import { StringOrList } from '../../utils/BasicTypes'; import { DeepRequired } from '../../utils/DeepRequired'; import { Question, QuestionnaireContent } from './QuestionnaireControlStructs'; import { AskIfCompleteAct, AskIfCompleteTerseAct, AskQuestionAct, CompletedAct, QuestionAnsweredAct, QuestionnaireCompletionRejectedAct } from './QuestionnaireControlSystemActs'; /** * Props for a QuestionnaireControl. */ export interface QuestionnaireControlProps extends ControlProps { /** * Unique identifier for control instance */ id: string; /** * Content for the questionnaire. */ questionnaireData: QuestionnaireContent | ((control: QuestionnaireControl, input: ControlInput) => QuestionnaireContent); /** * Determines if the Control must obtain a value. * * If `true`: * - the Control report isReady() = false if no value has been obtained. * - the control will take the initiative when given the opportunity. */ required?: boolean | ((control: QuestionnaireControl, input: ControlInput) => boolean); /** * Determine if the questionnaire is considered valid, i.e. has no input errors and * is considered 'sufficiently complete' for the purposes of the Skill. * * Default: `true`, i.e. no validation and user can 'be done' whenever they wish. * * Usage: * - Validation functions return either `true` or a `ValidationResult` to * describe what validation failed. */ valid?: StateValidationFunction; /** * Props to customize the relationship between the control and the * interaction model. */ interactionModel?: QuestionnaireControlInteractionModelProps; /** * Props to configure input handling. */ inputHandling?: QuestionnaireControlInputHandlingProps; /** * Props to configure dialog policy. */ dialog?: { confirmationRequired?: boolean | ((control: QuestionnaireControl, input: ControlInput) => boolean); }; /** * Props to customize the prompt fragments that will be added by * `this.renderAct()`. */ prompts?: QuestionnaireControlPromptProps; /** * Props to customize the reprompt fragments that will be added by * `this.renderAct()`. */ reprompts?: QuestionnaireControlPromptProps; /** * Props to customize the APL generated by this control. */ apl?: QuestionnaireControlAPLProps; /** * Props to customize services used by the control. */ services?: ControlServicesProps; /** * Function that determines the preferred response style based on input * and input modality history. * * Default: Function always returns indeterminate response style, which * causes the decision to be deferred to the function configured in ControlManager. */ responseStyleEvaluator?: ResponseStyleEvaluator; } /** * Mapping of action slot values to the capability that this control supports. * * Behavior: * - This control will not handle an input if the action-slot is filled with an * value whose ID is not associated with a capability. */ export interface QuestionnaireControlActionProps { /** * Action slot value IDs that are associated with the "start/open/resume the questionnaire" capability. * * Default: ['builtin_start', 'builtin_resume'] */ activate?: string[]; /** * Action slot value IDs that are associated with the "complete questionnaire" capability. * * Default ['builtin_complete'] */ complete?: string[]; /** * Action slot value IDs that are associated with the "answer a question" capability. * * Default ['builtin_answer', 'builtin_select'] */ answer?: string[]; } /** * Props associated with the interaction model. */ export declare class QuestionnaireControlInteractionModelProps { /** * Target-slot values associated with this Control as a whole. * * These targets are used to associate utterances to 'the questionnaire' as a whole. * For example, if the user says "open the questionnaire", it will be parsed as a * `GeneralControlIntent` with slot values `action = open` and `target = questionnaire`. * * Default: `['builtin_it', 'builtin_questionnaire']` * * Usage: * - If this prop is defined, it replaces the default; it is not additive to the * defaults. To add an additional target to the defaults, copy the defaults and * amend. * - A control can be associated with many targets, eg ['questionnaire', * 'customerServiceFeedback', 'feedback'] * - It is a good idea to associate with general targets (e.g. feedback) and also with * specific targets (e.g. customerServiceFeedback) so that the user can say either * general or specific things. * - The association does not have to be exclusive, and general target slot values * will often be associated with many controls. In situations where there is * ambiguity about what the user is referring to, the parent controls must resolve * the confusion. * - The 'builtin_*' IDs are associated with default interaction model data (which can * be extended as desired). Any other IDs will require a full definition of the * allowed synonyms to be added to the interaction model. * * Control behavior: * - The control will not handle an input that mentions a target that is not defined * by this prop. */ targets?: string[]; /** * All target slots that are used by individual questions. * * Default: [] * * Purpose: * - the user may give an answer to a specific question, e.g. "I like cats" which is * parsed as a ValueControlIntent with value=like target=cats. To achieve * this, the slotType associated with this control must include the value 'like' * and the targets slotType must include 'cats'. * * Why can't the targets be pulled from questionnaire content? * - because the questionnaire content is dynamic at runtime, but the complete list * of targets must be known at build time. * * Control behavior: * - at build time, all the targets listed here will be verified to exist in the * interaction model. */ allQuestionTargets?: string[]; /** * Action slot-values associated to the capabilities of the control as a whole * * Default: * ``` * { * activate: ['builtin_start', 'builtin_resume'], * complete: ['builtin_complete'] * } * ``` * * Action slot-values associate utterances to a control. For example, if the user says * "change the time", it is parsed as a `GeneralControlIntent` with slot values * `action = change` and `target = time`. Only controls that are registered with the * `change` action should offer to handle this intent. * * Usage: * - This allows users to refer to an action using more domain-appropriate words. For * example, a user might like to say 'show two items' rather that 'set item count * to two'. To achieve this, include the slot-value-id 'show' in the list * associated with the 'set' capability and ensure the interaction-model includes * an action slot value with id=show and appropriate synonyms. * - The 'builtin_*' IDs are associated with default interaction model data (which * can be extended as desired). Any other IDs will require a full definition of the * allowed synonyms in the interaction model. */ actions?: QuestionnaireControlActionProps; /** * Slot type that includes entries for the answers provided by the questionnaire. * * Default: none * * If the questions are not strictly yes/no, `slotType` provides the values that the * user can say. Every legal answer should be present in `slotType` and all legal * answers *that are not in conflict with other sample utterances* should be present * in `filteredSlotType`. * * Example: * * If the questionnaire answers are "yes", "no" and "maybe", the `slotType` * should have values for all three and the `filteredSlotType` should only have "maybe". * ``` * interactionModel: { * slotType: 'YesNoMaybe', * filteredSlotType: 'Maybe' * } * ``` */ slotType?: string; /** * Slot type that includes entries for the answers that do not conflict with * the sample utterances of built-in intents or custom intents. * * Default: identical to `slotType`. * * Purpose: * - During interaction-model-generation the `filteredSlotType` is used * in sample-utterances that would cause conflicts if the regular * slotType was used. * - If utterance conflicts persist the skill will not receive the built-in intent * which may break other interactions. * * Example: * * If the questionnaire answers are "yes", "no" and "maybe", the `slotType` * should have values for all three and `filteredSlotType` should only have "maybe". * ``` * interactionModel: { * slotType: 'YesNoMaybe', * filteredSlotType: 'Maybe' * } * ``` */ filteredSlotType?: string; } export interface QuestionnaireControlInputHandlingProps extends ControlInputHandlingProps { /** * Function that maps an intent to a choice ID defined in for props.slotValue. * * Default: `IntentUtils.defaultIntentToValueMapper` which converts "AMAZON.YesIntent" * to 'yes' and so on. Generally, `(.+)*Intent" -> 'value'`. * * Purpose: * * Some simple utterances intended for this control will be interpreted as intents * that are unknown to this control. This function allows them to be recognized as * answers. * * Whenever the questionnaire has asked a direct question to the user, e.g. "A: do * you like cats?" the subsequent intents will be tested using this function. If it * produces a valid answer id the input will be considered an answer to the question. * * Example: * * Assume `slotType: 'YesNoMaybe'` and `filteredSlotType = 'Maybe'`. An utterance of * 'U: yes' will be interpreted as an `AMAZON.YesIntent`. To ensure that intent * can be interpreted as the 'yes' answer to a questionnaire question an * intentToChoiceMapper must be defined. The default is sufficient for this case * and for most cases that involve intents with conventional naming. */ intentToChoiceMapper: (intent: Intent) => string | undefined; customHandlingFuncs?: ControlInputHandler[]; } /** * Props to customize the prompt fragments that will be added by * `this.renderAct()`. */ export declare class QuestionnaireControlPromptProps { askQuestionAct?: StringOrList | ((act: AskQuestionAct, input: ControlInput) => StringOrList); questionAnsweredAct?: StringOrList | ((act: QuestionAnsweredAct, input: ControlInput) => StringOrList); questionnaireCompleted?: StringOrList | ((act: CompletedAct, input: ControlInput) => StringOrList); questionnaireCompletionRejected?: StringOrList | ((act: QuestionnaireCompletionRejectedAct, input: ControlInput) => StringOrList); acknowledgeNotCompleteAct?: StringOrList | ((act: QuestionnaireCompletionRejectedAct, input: ControlInput) => StringOrList); askIfComplete?: StringOrList | ((act: AskIfCompleteAct, input: ControlInput) => StringOrList); askIfCompleteTerse?: StringOrList | ((act: AskIfCompleteTerseAct, input: ControlInput) => StringOrList); } export declare type AplContent = { document: any; dataSource: any; }; export declare type QuestionnaireControlAplDocumentPropNewStyle = AplContent | QuestionnaireControlAplContentFunc; export declare type QuestionnaireControlAplContentFunc = (control: QuestionnaireControl, input: ControlInput) => AplContent; /** * Props associated with the APL produced by QuestionnaireControl. */ export declare class QuestionnaireControlAPLProps { /** * Determines if APL should be produced. * * Default: true */ enabled?: boolean | ((input: ControlInput) => boolean); /** * Custom APL to show all questions while asking one in particular. * * Default: ``` QuestionnaireControlAPLPropsBuiltIns.DefaultAskQuestion({ title: 'Please select...', submitButtonText: 'Submit >', radioButtonPressesBlockUI: true } ``` */ askQuestion?: QuestionnaireControlAplDocumentPropNewStyle; } export declare type QuestionnaireUserAnswers = { [index: string]: { choiceId: string; }; }; interface LastInitiativeState { /** * Tracks the last act initiated from the control. */ actName?: string; } /** * State tracked by a QuestionnaireControl. */ export declare class QuestionnaireControlState implements ControlState { /** * The answers as a map of (questionId, answerId) pairs. */ value: QuestionnaireUserAnswers; /** * Tracks the last initiative act from the control */ lastInitiative: LastInitiativeState; /** * Which questionId is active, aka in focus. */ focusQuestionId?: string; /** * Whether the user has explicitly completed the questionnaire. */ userExplicitlyCompleted: boolean; /** * Whether the user has been ask if they are done and replied 'no'. */ userDisconfirmedCompletion: boolean; /** * Should we require an explicit completion. * (e.g. after rejecting are you done, or re-activating the control) */ requiresExplicitCompletion: boolean; } /** * A Control that asks a series of questions, where each question has the same * answer-options. * * Capabilities: * - Activate the questionnaire. "I'd like to answer the personality questionnaire" * - Answer a question directly. "Yes I have headache" // "yes to question three" * - Bring a question in to focus. "U: skip to headache" // "U: move to question ten" * - Confirm an answer * - Show the entire questionnaire on APL enabled devices (with interactivity) */ export declare class QuestionnaireControl extends Control implements InteractionModelContributor { state: QuestionnaireControlState; inputWasAnswerByTouch: boolean; activatedThisTurn: boolean; private rawProps; props: DeepRequired; private handleFunc?; private initiativeFunc?; private log; constructor(props: QuestionnaireControlProps); /** * Merges the user-provided props with the default props. * * Any property defined by the user-provided data overrides the defaults. */ static mergeWithDefaultProps(props: QuestionnaireControlProps): DeepRequired; standardInputHandlers: ControlInputHandler[]; canHandle(input: ControlInput): Promise; handle(input: ControlInput, resultBuilder: ControlResultBuilder): Promise; private isActivate; private handleActivate; private isMappedAnswerToAskedQuestion; private handleMappedAnswerToAskedQuestion; private isSpecificAnswerToAskedQuestion; private handleSpecificAnswerToAskedQuestion; private isFeedbackAnswerToSpecificQuestion; private handleFeedbackAnswerToSpecificQuestion; private isSpecificAnswerToSpecificQuestion; private handleSpecificAnswerToSpecificQuestion; private isSpecificAnswerByTouch; private handleSpecificAnswerByTouch; private isCompletionRequestByVoice; private isCompletionRequestByTouch; private handleCompletionRequest; private isBareYesToCompletionQuestion; private isBareNoToCompletionQuestion; private handleBareNoToCompletionQuestion; standardInitiativeHandlers: ControlInitiativeHandler[]; canTakeInitiative(input: ControlInput): Promise; takeInitiative(input: ControlInput, resultBuilder: ControlResultBuilder): Promise; private wantsToKeepAplInitiative; private keepAplInitiative; private wantsToAskLineItemQuestion; private askLineItemQuestion; private wantsToAskIfComplete; private askIfComplete; /** * Evaluate the questionnaireContent prop */ getQuestionnaireContent(input: ControlInput): QuestionnaireContent; private evaluateAPLPropNewStyle; stringifyStateForDiagram(): string; renderAct(act: SystemAct, input: ControlInput, builder: ControlResponseBuilder): Promise; private addStandardAPL; /** * Note: this assumes that the root container has `id='root'` and that it defines * variables called `disableContent` and `enableWaitIndicator`. * * Custom APL documents should adhere to these conventions if they want to make use of * input suppression to avoid racing inputs. Alternatively, subclass * `QuestionnaireControl` and and alter the behavior for `render()` when act is an * instance of `ActiveAPLInitiativeAct` changed. * * This solution is not exposed as with props based customization as there may be * better solutions. Let's not lock this pattern in until we know it is needed. * */ private reEnableExistingAPLForUserInput; updateInteractionModel(generator: ControlInteractionModelGenerator, imData: ModelData): void; /** * Clear the state of this control. */ clear(): void; updateAnswer(questionId: string, choiceId: string | undefined, input: ControlInput, resultBuilder: ControlResultBuilder): void; getQuestionContentById(questionId: string, input: ControlInput): DeepRequired; getChoiceIndexById(content: QuestionnaireContent, answerId: string): number | undefined; getQuestionIndexById(content: QuestionnaireContent, questionId: string): number; /** * Determine if the control is idle and should not take initiative. * @param input - Input. */ private isActive; private getFirstUnansweredQuestion; private setCompletionFlag; private getSlotTypes; addCompletionActIfImplicitlyComplete(input: ControlInput, resultBuilder: ControlResultBuilder): void; /** * Evaluate a boolean prop. * * @param propValue - Constant or function producing boolean * @param input - The input object */ evaluateBooleanPropNewStyle(propValue: boolean | ((control: QuestionnaireControl, input: ControlInput) => boolean), input: ControlInput): boolean; evaluatePromptShortForm(propValue: string | ((control: QuestionnaireControl, input: ControlInput) => string), input: ControlInput): string; } export {}; //# sourceMappingURL=QuestionnaireControl.d.ts.map