actions-on-google / actions-on-google-nodejs

Node.js client library for Actions on Google
https://actions-on-google.github.io/actions-on-google-nodejs
Apache License 2.0
900 stars 197 forks source link

Reset dialogflow slot filling state for parameter #345

Closed Wimsen closed 4 years ago

Wimsen commented 4 years ago

Hello!

Is there a way to reset the dialogflow slot filling state for a parameter, so that the user would have to provide/specify it again?

This would be useful in cases where incoming parameters for an intent has to be validated in fulfillment. If the parameter spoken by the user cannot be used for some reason, it would be really useful to reset the slot filling state for that parameter and ask the user to provide a different value for the parameter.

Wimsen commented 4 years ago

Update: I eventually found a solution for this by manipulating the contexts Dialogflow sets. Here is a general method

export const resetSlotFillingForParameter = (conv, intentId, existingParameters, parameter) => {
    const intentName = conv.intent
        .trim()
        .toLowerCase()
        .replace(/\s/g, "_");
    let idDialogContext = `${intentId}_id_dialog_context`;
    let nameDialogContext = `${intentName}_dialog_context`;
    let parameterContext = `${intentName}_dialog_params_${parameter.toLowerCase()}`;

    const slotFillingRegex = /.*contexts\/(?<contextName>.*dialog_params.*)/;
    let existingSlotFillingContexts = [];
    for (const context of conv.contexts) {
        const isSlotFillingContext = slotFillingRegex.test(context.name);
        if (isSlotFillingContext) {
            const match = slotFillingRegex.exec(context.name);
            existingSlotFillingContexts.push(match.groups.contextName);
        }
    }

    const updatedParameters = {
        ...existingParameters,
        [parameter]: ""
    };

    // Delete slot filling contexts for other parameters
    existingSlotFillingContexts.forEach(contextName => conv.contexts.delete(contextName));

    // Reset slot filling state for the current parameter
    conv.contexts.set(idDialogContext, 2, updatedParameters);
    conv.contexts.set(nameDialogContext, 2, updatedParameters);
    conv.contexts.set(parameterContext, 1, updatedParameters);
};

I still feel that manually manipulating these contexts is quite prone to error, and would like to see this functionality included in the library.

Fleker commented 4 years ago

Could you wrap this into a plugin or app.middleware?

app.middleware(conv => {
    conv.resetSlotFilling = (intentId, existingParameters, parameter) => {
        // Your logic
   }
})

Then you could more easily load it and share functionality.

Wimsen commented 4 years ago

Yes, certainly possible to add a function on conv using middleware.

I'm not sure if this is safe enough to make a PR and include it in the library, but it seems to work for now.

Fleker commented 4 years ago

I'm not sure if it's something that would need to be directly built into the library. Feel free to make a PR, as @Canain would provide more of a decision, although you could also build it as a separate middleware library as well.