question

Ben avatar image
Ben asked

Intent ConfirmationStatus cannot be changed with Dialog.Delegate directive

I have a dialog where I delegate Alexa to collect two slots and ask the confirmation prompt. If the user says "no" to the confirmation prompt, I want to restart the dialog by deleting the slot values and setting the intent confirmationStatus to "NONE".

While Alexa starts to elicit the first slot, the confirmation status remains as "DENIED" which leads to a loop. I used the method described here to reset the status.

This is the updated intent sent back from my skill

{
  "name": "StartSingleGameIntent",
  "confirmationStatus": "NONE",
  "slots": {
    "player_one": {
      "name": "player_one",
      "confirmationStatus": "NONE",
      "source": "USER"
    },
    "player_two": {
      "name": "player_two",
      "confirmationStatus": "NONE",
      "source": "USER"
    }
  }
}

But the next request still has the "DENIED" status:

{
  "name": "StartSingleGameIntent",
  "confirmationStatus": "DENIED",
  "slots": {
    "player_one": {
      "name": "player_one",
      "value": "ben",
      "confirmationStatus": "NONE",
      "source": "USER"
    },
    "player_two": {
      "name": "player_two",
      "confirmationStatus": "NONE"
    }
  }
}

Here are my handlers:

const StartSingleGameStartedIntentHandler = {
  canHandle(handlerInput) {
    return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
      Alexa.getIntentName(handlerInput.requestEnvelope) === 'StartGameIntent' &&
      Alexa.getDialogState(handlerInput.requestEnvelope) === 'STARTED';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder.addDelegateDirective(handlerInput.requestEnvelope.request.intent).getResponse();
  }
};
const StartSingleGameInProgressIntentHandler = {
  canHandle(handlerInput) {
    return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
      Alexa.getIntentName(handlerInput.requestEnvelope) === 'StartGameIntent' &&
      Alexa.getDialogState(handlerInput.requestEnvelope) === 'IN_PROGRESS';
  },
  handle(handlerInput) {
    const currentIntent = handlerInput.requestEnvelope.request.intent;
    console.log("Dialog in progress %s", JSON.stringify(currentIntent));
    if (currentIntent.confirmationStatus === "DENIED") {
      let intent = handlerInput.requestEnvelope.request.intent;
      intent.confirmationStatus = "NONE";
      Object.keys(intent.slots).forEach(slotName => {
        const slot = intent.slots[slotName];
        delete slot.value;
      });
      console.log("New intent %s", JSON.stringify(intent));
      const speechText = "Ok, let's try again";
      return handlerInput.responseBuilder
        .speak(speechText)
        .addDirective({
          type: "Dialog.Delegate",
          updatedIntent: intent
        })
        .getResponse();
     
    }
    // if Intent is confirmed, delegate to complete dialog
    return handlerInput.responseBuilder.addDelegateDirective(currentIntent).getResponse();
  }
};


const StartSingleGameCompletedIntentHandler = {
  canHandle(handlerInput) {
    return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
      Alexa.getIntentName(handlerInput.requestEnvelope) === 'StartGameIntent' &&
      Alexa.getDialogState(handlerInput.requestEnvelope) === 'COMPLETED';
  },
  handle(handlerInput) {
    console.log("Status COMPLETED");
    const currentIntent = handlerInput.requestEnvelope.request.intent;
    const playerOne = currentIntent.slots.player_one.value;
    const playerTwo = currentIntent.slots.player_two.value;
    const speech = 'Ok, ' + playerOne + ' versus ' + playerTwo + '!';
    return handlerInput.responseBuilder.speak(speech).withShouldEndSession(true).getResponse();
  }
};

And here is the relevant part from the interaction model

{
  "interactionModel": {
    "languageModel": {
      "invocationName": "kicker tracker",
      "intents": [
        {
          "name": "StartSingleGameIntent",
          "slots": [
            {
              "name": "player_one",
              "type": "AMAZON.FirstName",
              "samples": [
                "{player_one}"
              ]
            },
            {
              "name": "player_two",
              "type": "AMAZON.FirstName",
              "samples": [
                "{player_two}"
              ]
            }
          ],
          "samples": [
            "{player_one} versus {player_two}",
            "{player_one} against {player_two}"
          ]
        }
      ],
      "types": []
    },
    "dialog": {
      "intents": [
        {
          "name": "StartGameIntent",
          "delegationStrategy": "SKILL_RESPONSE",
          "confirmationRequired": true,
          "prompts": {
            "confirmation": "Confirm.Intent.331442628749"
          },
          "slots": [
            {
              "name": "player_one",
              "type": "AMAZON.FirstName",
              "confirmationRequired": false,
              "elicitationRequired": true,
              "prompts": {
                "elicitation": "Elicit.Slot.1074854715089.1393950695631"
              }
            },
            {
              "name": "player_two",
              "type": "AMAZON.FirstName",
              "confirmationRequired": false,
              "elicitationRequired": true,
              "prompts": {
                "elicitation": "Elicit.Slot.1074854715089.404108193608"
              }
            }
          ]
        }
      ],
      "delegationStrategy": "ALWAYS"
    },
    "prompts": [
      {
        "id": "Elicit.Slot.1074854715089.1393950695631",
        "variations": [
          {
            "type": "PlainText",
            "value": "Who is the first player?"
          }
        ]
      },
      {
        "id": "Elicit.Slot.1074854715089.404108193608",
        "variations": [
          {
            "type": "PlainText",
            "value": "Who plays against {player_one} ?"
          }
        ]
      },
      {
        "id": "Confirm.Intent.331442628749",
        "variations": [
          {
            "type": "PlainText",
            "value": "{player_one} versus {player_two}, correct?"
          }
        ]
      }
    ]
  }
}
alexa skills kitnodejsinteraction modeldialog modeldialog directive
10 |3000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Anand@Amazon avatar image
Anand@Amazon answered

Hello @Ben

Sorry for late response !!

Can you share skill ID too which will help us in our investigation?

10 |3000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Armand avatar image
Armand answered

@Ben @Anand@Amazon

Did you find any solution for this?

10 |3000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

tahiat avatar image
tahiat answered

Does anyone got the solution for this problem. I also facing the same issue


1 comment
10 |3000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Hey @tahiat

Can you share Skill ID and error message which will help us in finding the root cause?

0 Likes 0 ·
Nathan Friend avatar image
Nathan Friend answered

@Anand@Amazon I'm running into the same thing! Here's how I'm handling the "DENIED" code path: https://gitlab.com/nfriend/days-until/-/blob/1c600d2b940544662c10eceedcfc6100d6f115c0/lambda/src/handlers/start-countdown-intent-handler.ts#L274. Once the intent has been denied confirmation once, restarting it (i.e. clearing and re-eliciting) doesn't clear "intent.confirmationStatus: 'DENIED'".

My skill ID is amzn1.ask.skill.bbc0e286-5827-4303-933c-21e84ec5baae

1 comment
10 |3000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Hey @Nathan Friend

Sorry for late response.

Can you logged request and response JSON and share with us for further investigation?

0 Likes 0 ·