// -*- mode: typescript; indent-tabs-mode: nil; js-basic-offset: 4 -*-
//
// This file is part of Genie
//
// Copyright 2020 The Board of Trustees of the Leland Stanford Junior University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Giovanni Campagna <gcampagn@cs.stanford.edu>

import assert from 'assert';
import { Ast, } from 'thingtalk';
import { SentenceGeneratorTypes } from 'genie-toolkit';
import * as C from '../ast_manip';
import * as S from '../state_manip';
import * as D from '../dialogue_acts';
import ThingpediaLoader from '../load-thingpedia';
import type * as $Genie from "genie-toolkit";
export default async function($runtime : typeof $Genie.SentenceGeneratorRuntime, $ttUtils : typeof $Genie.ThingTalkUtils, $options : $Genie.SentenceGeneratorTypes.GrammarOptions, $locale : $Genie.I18n.LanguagePack, $grammar : $Genie.SentenceGenerator<any, any>, $loader : ThingpediaLoader) : Promise<void> {

$loader = new ThingpediaLoader($runtime, $ttUtils, $grammar, $locale, $options);
   await (await $runtime.import("../common.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);

await $loader.init();
   await (await $runtime.import("./shared.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./constants.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./timers.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./filters.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./projections.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./aggregation.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./computation.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./who_questions.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./stream_tables.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./commands.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/shared.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/results.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/coref-actions.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/action-confirm.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/action-results.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/aggregation-results.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/coref-questions.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/empty-search.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/initial-request.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/list-proposal.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/recommendation.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/refinement.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/related-questions.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/search-questions.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   await (await $runtime.import("./dlg/slot-fill.genie", __dirname))($runtime, $ttUtils, $options, $locale, $grammar, $loader);
   $grammar.declareContext("ctx_init");
   $grammar.declareContext("ctx_multidomain");
   $grammar.declareContext("ctx_with_result");
   $grammar.declareContext("ctx_with_table_result");
   $grammar.declareContext("ctx_with_aggregation_result");
   $grammar.declareContext("ctx_with_action");
   $grammar.declareContext("ctx_without_action");
   $grammar.declareContext("ctx_with_result_and_action");
   $grammar.declareContext("ctx_with_result_question");
   $grammar.declareContext("ctx_with_result_noquestion");
   $grammar.declareContext("ctx_with_result_argminmax");
   $grammar.declareContext("ctx_without_projection");
   $grammar.declareContext("ctx_for_related_question");
   $grammar.declareContext("ctx_next_statement");
   $grammar.declareContext("ctx_greet");
   $grammar.declareContext("ctx_reinit");
   $grammar.declareContext("ctx_cancel");
   $grammar.declareContext("ctx_end");
   $grammar.declareContext("ctx_search_command");
   $grammar.declareContext("ctx_aggregation_question");
   $grammar.declareContext("ctx_distance_argminmax_question");
   $grammar.declareContext("ctx_argminmax_question");
   $grammar.declareContext("ctx_one_result_question");
   $grammar.declareContext("ctx_empty_direct_question");
   $grammar.declareContext("ctx_empty_search_command");
   $grammar.declareContext("ctx_large_search_command");
   $grammar.declareContext("ctx_single_result_search_command");
   $grammar.declareContext("ctx_complete_search_command");
   $grammar.declareContext("ctx_completed_action_success");
   $grammar.declareContext("ctx_completed_action_error");
   $grammar.declareContext("ctx_confirm_action");
   $grammar.declareContext("ctx_incomplete_action");
   $grammar.declareContext("ctx_incomplete_action_after_search");
   $grammar.declareContext("ctx_learn_more");
   $grammar.declareContext("ctx_display_nonlist_result");
   $grammar.declareContext("ctx_sys_any");
   $grammar.declareContext("ctx_sys_action_success");
   $grammar.declareContext("ctx_sys_action_error");
   $grammar.declareContext("ctx_sys_anything_else");
   $grammar.declareContext("ctx_sys_confirm_action");
   $grammar.declareContext("ctx_sys_display_result");
   $grammar.declareContext("ctx_sys_empty_search");
   $grammar.declareContext("ctx_sys_end");
   $grammar.declareContext("ctx_sys_greet");
   $grammar.declareContext("ctx_sys_learn_more_what");
   $grammar.declareContext("ctx_sys_propose_refined_query");
   $grammar.declareContext("ctx_sys_recommend_many");
   $grammar.declareContext("ctx_sys_recommend_one");
   $grammar.declareContext("ctx_sys_search_question");
   $grammar.declareContext("ctx_sys_slot_fill");
   $grammar.declareContext("ctx_current_query");
   $grammar.declareContext("ctx_next_query");
   $grammar.declareContext("ctx_next_action");
   $grammar.declareContext("ctx_thingpedia_result");
   $grammar.declareContext("ctx_thingpedia_error_message");
   $grammar.declareFunction('context', (state : Ast.DialogueState, contextTable : SentenceGeneratorTypes.ContextTable) : SentenceGeneratorTypes.ContextPhrase[]|null => {
    if (state === null)
        return [S.makeContextPhrase(contextTable.ctx_init, S.initialContextInfo($loader, contextTable))];

    assert(state instanceof Ast.DialogueState, `expected a dialogue state Ast node`);
    if (state.policy !== S.POLICY_NAME)
        return null;
    (global as any).enableBreakpoint = true;
    const ctx = S.getContextInfo($loader, state, contextTable);
    (global as any).enableBreakpoint = false;
    // get the main context tags for this context (the abstract state, in paper terminology)
    const tags = S.tagContextForAgent(ctx);

    const phrases = tags.map((tag) => S.makeContextPhrase(tag, ctx));
    // add auxiliary context non-terminals used for pruning and to simplify generation
    phrases.push(...S.getContextPhrases(ctx));
    return phrases;
});
   $grammar.declareFunction('answer', (state : Ast.DialogueState, answer : Ast.Value, contextTable : SentenceGeneratorTypes.ContextTable) : Ast.DialogueState|null => {
    const ctx = S.getContextInfo($loader, state, contextTable);

    // if the agent proposed something and the user says "yes", we accept the proposal
    if (state.history[state.history.length-1].confirm === 'proposed' &&
        answer instanceof Ast.BooleanValue && answer.value === true) {
        const item = state.history[state.history.length-1].clone();
        item.confirm = 'accepted';
        return S.addNewItem(ctx, 'execute', null, 'accepted', item);
    }

    switch (state.dialogueAct) {
    case 'sys_anything_else':
        if (answer instanceof Ast.BooleanValue) {
            if (answer.value)
                return S.makeSimpleState(ctx, 'reinit', null);
            else
                return S.makeSimpleState(ctx, 'end', null);
        }
        return null;
    case 'sys_recommend_one':
    case 'sys_recommend_two':
    case 'sys_recommend_three':
    case 'sys_recommend_four':
        // "yes" to a recommendation (without a proposed action) is an answer to
        // "would you like to learn more"
        if (answer instanceof Ast.BooleanValue && answer.value === true)
            return S.makeSimpleState(ctx, 'learn_more', null);
        // fallthrough
    case 'sys_display_result':
        // "no" to a recommendation or display result is cancel
        if (answer instanceof Ast.BooleanValue && answer.value === false)
            return S.makeSimpleState(ctx, 'cancel', null);
        return null;

    case 'sys_slot_fill':
        return D.impreciseSlotFillAnswer(ctx, answer);
    case 'sys_search_question':
        return D.impreciseSearchQuestionAnswer(ctx, answer);
    case 'sys_confirm_action':
        if (answer instanceof Ast.BooleanValue) {
            if (answer.value)
                return D.actionConfirmAcceptPhrase(ctx);
            else
                return D.actionConfirmRejectPhrase(ctx);
        }
        return null;
    default:
        return null;
    }
});
   $grammar.declareSymbol("$agent");
   if (!$options.flags.inference) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_greet", undefined), new $runtime.Choice(["hello", "hi"]), new $runtime.Choice(["!", ","]), new $runtime.Choice(["how can i help you", "what are you interested in", "what can i do for you"]), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined, $2 : undefined, $3 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_greet', null))), undefined, {  });
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_init", undefined), new $runtime.Choice(["hello", "hi"]), new $runtime.Choice(["!", ","]), new $runtime.Choice(["how can i help you", "what are you interested in", "what can i do for you"]), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined, $2 : undefined, $3 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_greet', null))), undefined, {  });
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_reinit", undefined), new $runtime.Choice(["how can i help you", "what are you interested in", "what can i do for you"]), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_greet', null))), undefined, {  });
   }
   if ($options.flags.inference) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_greet", undefined), new $runtime.Choice(["hello", "hi"]), new $runtime.Choice(["!", ","]), new $runtime.Choice(["how can i help you", "what can i do for you"]), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined, $2 : undefined, $3 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_greet', null))), undefined, {  });
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_init", undefined), new $runtime.Choice(["hello", "hi"]), new $runtime.Choice(["!", ","]), new $runtime.Choice(["how can i help you", "what can i do for you"]), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined, $2 : undefined, $3 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_greet', null))), undefined, {  });
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_reinit", undefined), new $runtime.Choice(["how can i help you", "what can i do for you"]), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_greet', null))), undefined, {  });
   }
   if ($options.flags.anything_else) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_cancel", undefined), new $runtime.NonTerminal("anything_else_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_anything_else', null))), undefined, {  });
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_end", undefined), "alright ,", new $runtime.Choice(["bye !", "good bye !"])], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_end', null))), undefined, {  });
   }
   if (!$options.flags.anything_else) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_cancel", undefined), "alright ,", new $runtime.Choice(["bye !", "good bye !"])], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_end', null))), undefined, {  });
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_end", undefined), "alright ,", new $runtime.Choice(["bye !", "good bye !"])], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_end', null))), undefined, {  });
   }
   $grammar.addRule("$agent", [new $runtime.NonTerminal("action_success_phrase", undefined)], (($0 : S.AgentReplyRecord) : (S.AgentReplyRecord)|null => { return $0; }), undefined, { identity: (true) });
   if ($options.flags.anything_else) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("action_success_phrase", undefined), new $runtime.NonTerminal("anything_else_phrase", undefined)], ((action : S.AgentReplyRecord, $0 : string) : (S.AgentReplyRecord)|null => S.setEndBit(action, false)), undefined, {  });
   }
   $grammar.addRule("$agent", [new $runtime.NonTerminal("action_error_phrase", undefined)], (($0 : S.AgentReplyRecord) : (S.AgentReplyRecord)|null => { return $0; }), undefined, { identity: (true) });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_display_nonlist_result", undefined), new $runtime.NonTerminal("system_nonlist_result", undefined)], ((ctx : S.ContextInfo, proposal : D.Recommendation) : (S.AgentReplyRecord)|null => D.makeDisplayResultReply(ctx, proposal)), undefined, {  });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_aggregation_question", undefined), new $runtime.NonTerminal("count_aggregation_reply", undefined)], ((ctx : S.ContextInfo, reply : S.AgentReplyRecord) : (S.AgentReplyRecord)|null => reply), undefined, {  });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_aggregation_question", undefined), new $runtime.NonTerminal("other_aggregation_reply", undefined)], ((ctx : S.ContextInfo, reply : S.AgentReplyRecord) : (S.AgentReplyRecord)|null => reply), undefined, {  });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_confirm_action", undefined), new $runtime.NonTerminal("action_confirm_phrase", undefined)], ((ctx : S.ContextInfo, reply : S.AgentReplyRecord) : (S.AgentReplyRecord)|null => reply), undefined, {  });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_empty_search_command", undefined), new $runtime.NonTerminal("empty_search_error", undefined)], ((ctx : S.ContextInfo, error : [Ast.InvocationExpression|null, C.ParamSlot|null]) : (S.AgentReplyRecord)|null => D.makeEmptySearchError(ctx, error)), undefined, {  });
   if (!$options.flags.inference) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("system_generic_proposal", undefined)], ((prop : S.AgentReplyRecord) : (S.AgentReplyRecord)|null => prop), undefined, {  });
   }
   if (!$options.flags.inference) {
       $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_search_command", undefined), new $runtime.NonTerminal("search_question", undefined)], ((ctx : S.ContextInfo, questions : C.ParamSlot[]) : (S.AgentReplyRecord)|null => D.makeSearchQuestion(ctx, questions)), undefined, {  });
   }
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_incomplete_action_after_search", undefined), new $runtime.NonTerminal("slot_fill_question", undefined)], ((ctx : S.ContextInfo, questions : C.ParamSlot[]) : (S.AgentReplyRecord)|null => D.makeSlotFillQuestion(ctx, questions)), undefined, {  });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_complete_search_command", undefined), new $runtime.NonTerminal("system_recommendation", undefined)], ((ctx : S.ContextInfo, proposal : D.Recommendation) : (S.AgentReplyRecord)|null => D.makeRecommendationReply(ctx, proposal)), undefined, {  });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_complete_search_command", undefined), new $runtime.NonTerminal("system_list_proposal", undefined)], ((ctx : S.ContextInfo, proposal : D.ListProposal) : (S.AgentReplyRecord)|null => D.makeListProposalReply(ctx, proposal)), undefined, { weight: (10) });
   $grammar.addRule("$agent", [new $runtime.NonTerminal("ctx_learn_more", undefined), new $runtime.NonTerminal("system_learn_more", undefined)], ((ctx : S.ContextInfo, $0 : string) : (S.AgentReplyRecord)|null => S.makeAgentReply(ctx, S.makeSimpleState(ctx, 'sys_learn_more_what', null))), undefined, {  });
   $grammar.declareSymbol("$user");
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_init", undefined), new $runtime.NonTerminal("greeting", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'greet', null)), undefined, { weight: (0.01), expandchoice: (false) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_init", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.initialRequest($loader, stmt)), undefined, { weight: (0.5) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_init", undefined), new $runtime.NonTerminal("greeting", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, $0 : string, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.initialRequest($loader, stmt)), undefined, { weight: (0.5) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_greet", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.initialRequest($loader, stmt)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_anything_else", undefined), new $runtime.NonTerminal("no_thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'end', null)), undefined, { weight: (0.01) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_anything_else", undefined), new $runtime.NonTerminal("thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'end', null)), undefined, { weight: (0.01) });
   if ($options.flags.anything_else) {
       $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_anything_else", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.startNewRequest($loader, ctx, stmt)), undefined, {  });
       $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_anything_else", undefined), new $runtime.NonTerminal("yes_please_phrase", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, $0 : string, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.startNewRequest($loader, ctx, stmt)), undefined, {  });
       $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_anything_else", undefined), new $runtime.NonTerminal("yes_please_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'reinit', null)), undefined, {  });
   }
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_confirm_action", undefined), new $runtime.NonTerminal("accept_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => D.actionConfirmAcceptPhrase(ctx)), undefined, { weight: (0.9) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_confirm_action", undefined), new $runtime.NonTerminal("reject_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => D.actionConfirmRejectPhrase(ctx)), undefined, { weight: (0.1) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_confirm_action", undefined), new $runtime.NonTerminal("reject_phrase", undefined), new $runtime.Choice(["can you try", "how about"]), new $runtime.NonTerminal("imprecise_slot_fill_answer_phrase", undefined), new $runtime.Choice(["instead ?", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined, answer : Ast.Value|C.InputParamSlot, $2 : undefined) : (Ast.DialogueState)|null => D.actionConfirmChangeParam(ctx, answer)), undefined, { weight: (0.1) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_success", undefined), new $runtime.NonTerminal("thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'cancel', null)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_display_result", undefined), new $runtime.NonTerminal("thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'cancel', null)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_success", undefined), new $runtime.NonTerminal("simple_user_search_question", undefined)], ((ctx : S.ContextInfo, questions : C.ParamSlot[]) : (Ast.DialogueState)|null => D.actionSuccessQuestion(ctx, questions)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_display_result", undefined), new $runtime.NonTerminal("repeat_command_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => D.repeatCommandReply(ctx)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_success", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.startNewRequest($loader, ctx, stmt)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_success", undefined), new $runtime.NonTerminal("yes_please_phrase", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, $0 : string, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.startNewRequest($loader, ctx, stmt)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_display_result", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.startNewRequest($loader, ctx, stmt)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_display_result", undefined), new $runtime.NonTerminal("yes_please_phrase", undefined), new $runtime.NonTerminal("initial_command", undefined)], ((ctx : S.ContextInfo, $0 : string, stmt : Ast.Expression) : (Ast.DialogueState)|null => D.startNewRequest($loader, ctx, stmt)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_error", undefined), new $runtime.NonTerminal("no_thanks_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'cancel', null)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_error", undefined), new $runtime.NonTerminal("nevermind_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'cancel', null)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_action_error", undefined), new $runtime.Choice(["i see ,", "okay", "okay ,", "yeah", "yeah ,"]), new $runtime.Choice(["can you try", "how about"]), new $runtime.NonTerminal("imprecise_slot_fill_answer_phrase", undefined), "?"], ((ctx : S.ContextInfo, $0 : undefined, $1 : undefined, answer : Ast.Value|C.InputParamSlot, $2 : undefined) : (Ast.DialogueState)|null => D.actionErrorChangeParam(ctx, answer)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_empty_search", undefined), new $runtime.NonTerminal("precise_empty_search_change_request", ["functionName" as ("functionName" extends keyof ReturnType<typeof C.expressionKeyFn> ? string : void), 0, "currentTableFunction" as ("currentTableFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, req : Ast.Expression) : (Ast.DialogueState)|null => D.preciseEmptySearchChangeRequest(ctx, req)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_empty_search", undefined), new $runtime.NonTerminal("imprecise_empty_search_change_request", undefined)], ((ctx : S.ContextInfo, req : Ast.Value|C.FilterSlot) : (Ast.DialogueState)|null => D.impreciseEmptySearchChangeRequest(ctx, req)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_search_question", undefined), new $runtime.NonTerminal("precise_search_question_answer", ["functionName" as ("functionName" extends keyof ReturnType<typeof D.preciseSearchQuestionAnswerKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, answer : D.PreciseSearchQuestionAnswer) : (Ast.DialogueState)|null => D.preciseSearchQuestionAnswer(ctx, answer)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_search_question", undefined), new $runtime.NonTerminal("imprecise_search_question_answer", undefined)], ((ctx : S.ContextInfo, answer : Ast.Value|C.FilterSlot|'dontcare') : (Ast.DialogueState)|null => D.impreciseSearchQuestionAnswer(ctx, answer)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_slot_fill", undefined), new $runtime.NonTerminal("precise_slot_fill_answer", ["functionName" as ("functionName" extends keyof ReturnType<typeof C.invocationKeyFn> ? string : void), 0, "nextFunction" as ("nextFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, answer : Ast.Invocation) : (Ast.DialogueState)|null => D.preciseSlotFillAnswer(ctx, answer)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_slot_fill", undefined), new $runtime.NonTerminal("imprecise_slot_fill_answer", undefined)], ((ctx : S.ContextInfo, answer : Ast.Value|C.InputParamSlot) : (Ast.DialogueState)|null => D.impreciseSlotFillAnswer(ctx, answer)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("ask_recommend_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'ask_recommend', null)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_search_question", undefined), new $runtime.NonTerminal("ask_recommend_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => S.makeSimpleState(ctx, 'ask_recommend', null)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_propose_refined_query", undefined), new $runtime.NonTerminal("accept_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => D.positiveProposalReply(ctx)), undefined, { weight: (0.5) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_propose_refined_query", undefined), new $runtime.NonTerminal("negative_proposal_reply", ["functionName" as ("functionName" extends keyof ReturnType<typeof D.negativeProposalReplyKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, reply : D.NegativeProposalReply) : (Ast.DialogueState)|null => D.negativeProposalReply(ctx, reply)), undefined, { weight: (0.5) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("accept_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => D.positiveRecommendationReply($loader, ctx, null, null)), undefined, { weight: (0.7) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("recommendation_accept_phrase_with_action", undefined)], ((ctx : S.ContextInfo, acceptedAction : Ast.Invocation) : (Ast.DialogueState)|null => D.positiveRecommendationReply($loader, ctx, acceptedAction, null)), undefined, { weight: (0.7) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("recommendation_accept_phrase_by_name", undefined)], ((ctx : S.ContextInfo, name : [Ast.EntityValue|Ast.NumberValue, Ast.Invocation|null]) : (Ast.DialogueState)|null => D.positiveRecommendationReply($loader, ctx, name[1], name[0])), undefined, { weight: (0.7) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("tell_me_more_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string) : (Ast.DialogueState)|null => D.recommendationLearnMoreReply(ctx, null)), undefined, { weight: (0.5) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("accept_phrase", undefined), new $runtime.NonTerminal("tell_me_more_phrase", undefined)], ((ctx : S.ContextInfo, $0 : string, $1 : string) : (Ast.DialogueState)|null => D.recommendationLearnMoreReply(ctx, null)), undefined, { weight: (0.5) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("list_proposal_tell_me_more", undefined)], ((ctx : S.ContextInfo, name : Ast.EntityValue|Ast.NumberValue) : (Ast.DialogueState)|null => D.recommendationLearnMoreReply(ctx, name)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("negative_proposal_reply", ["functionName" as ("functionName" extends keyof ReturnType<typeof D.negativeProposalReplyKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, reply : D.NegativeProposalReply) : (Ast.DialogueState)|null => D.negativeRecommendationReply(ctx, reply)), undefined, { weight: (0.6) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => D.recommendationCancelReply(ctx, true)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("ok_thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => D.recommendationCancelReply(ctx, !ctx.aux.action && !ctx.aux.hasLearnMore)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("no_thanks_phrase", undefined), new $runtime.Choice(["goodbye !", ""])], ((ctx : S.ContextInfo, $0 : string, $1 : undefined) : (Ast.DialogueState)|null => D.recommendationCancelReply(ctx, ctx.aux.action || ctx.aux.hasLearnMore)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("related_question", undefined)], ((ctx : S.ContextInfo, question : Ast.DialogueState) : (Ast.DialogueState)|null => question), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_one", undefined), new $runtime.NonTerminal("user_search_question", ["functionName" as ("functionName" extends keyof ReturnType<typeof C.paramArrayKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, questions : C.ParamSlot[]) : (Ast.DialogueState)|null => D.recommendationSearchQuestionReply(ctx, questions)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_learn_more_what", undefined), new $runtime.NonTerminal("user_search_question", ["functionName" as ("functionName" extends keyof ReturnType<typeof C.paramArrayKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, questions : C.ParamSlot[]) : (Ast.DialogueState)|null => D.learnMoreSearchQuestionReply(ctx, questions)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_display_result", undefined), new $runtime.NonTerminal("user_search_question", ["functionName" as ("functionName" extends keyof ReturnType<typeof C.paramArrayKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, questions : C.ParamSlot[]) : (Ast.DialogueState)|null => D.displayResultSearchQuestionReply(ctx, questions)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("positive_list_proposal_reply", undefined)], ((ctx : S.ContextInfo, reply : [Ast.EntityValue|Ast.NumberValue, Ast.Invocation|null, boolean]) : (Ast.DialogueState)|null => D.positiveListProposalReply($loader, ctx, reply)), undefined, { weight: (10 * 0.7) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("list_proposal_accept_phrase_with_action_by_name", undefined)], ((ctx : S.ContextInfo, action : Ast.Invocation) : (Ast.DialogueState)|null => D.positiveListProposalReplyActionByName($loader, ctx, action)), undefined, { weight: (10 * 0.7) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("list_proposal_tell_me_more", undefined)], ((ctx : S.ContextInfo, name : Ast.EntityValue|Ast.NumberValue) : (Ast.DialogueState)|null => D.listProposalLearnMoreReply(ctx, name)), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("negative_proposal_reply", ["functionName" as ("functionName" extends keyof ReturnType<typeof D.negativeProposalReplyKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, reply : D.NegativeProposalReply) : (Ast.DialogueState)|null => D.negativeListProposalReply(ctx, reply)), undefined, { weight: (0.6) });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("related_question", undefined)], ((ctx : S.ContextInfo, question : Ast.DialogueState) : (Ast.DialogueState)|null => question), undefined, {  });
   $grammar.addRule("$user", [new $runtime.NonTerminal("ctx_sys_recommend_many", undefined), new $runtime.NonTerminal("user_search_question_for_list", ["functionName" as ("functionName" extends keyof ReturnType<typeof D.userSearchQuestionForListKeyFn> ? string : void), 0, "currentFunction" as ("currentFunction" extends keyof ReturnType<typeof S.contextKeyFn> ? string : void)])], ((ctx : S.ContextInfo, questions : D.UserSearchQuestionForList) : (Ast.DialogueState)|null => D.listProposalSearchQuestionReply(ctx, questions)), undefined, {  });
};
