There is an official Amazon blog on how to do dialog hooks and code is available on GitHub. Documentation fully describes syntax of JSON objects that Lex and Lambda exchange. But it took me some time to try this code and experiment to understand what each of the options means. I find it ridiculous that the tool which provides the natural language UI is lacking the description in natural language.
Lex only takes Lambda functions deployed in the same region where the bot is, which is not very handy as Lex is only available in a couple of US regions. I guess, it will get better once Lex is made available in every region, but as for now the Lambda function has to switch between regions if the rest of the infrastructure is located somewhere else.
There are two places in the intent where you can put the Lambda code hook, one on initialisation and one on fulfillment, one helps you to customise the conversation and check business rules, and the other can do, for example, a database call to place the order. These could be two different Lambda functions, or just one. If you have more than one intent in your bot, they can also call the same Lambda function, that’s how the example Lex Lambda function is organised. So, you can make Lambda functions very specific and have two per intent, or you can write just one per bot and it will be more like an app rather than a function as such. I can see pros and cons for both options. You probably want to check if you have enough items in stock before placing the order, so you need to connect to the database in both validation and fulfillment code hooks. It feels easier to write this code just once. On the other hand, the code is just a lot of “if”s with different reaction of each combination, so it could be lengthy and unreadable if all the possible logic is stuffed into one Lambda function.
Once you have added the initialisation and validation code hook, it can not have dead ends, each logic path should be handled within the code. It is not obvious, but once the code hook is enabled, it takes over the slot type prompts. The code hook is called after every user’s input. First time it is called after the intent is recognised from the user’s message; it allows some intitialisation code to be executed, like the customer counter increased by one. If you don’t want to build the slot types response cards in code and happy with the static slot type prompts you have set up on the intent page, you can delegate the privilege of collecting the slot values back to bot. The same response the function should send if all the slots satisfy the business rules, so it makes sense to have this “delegate” dialog action type response at the very bottom of all the checks. This response should include all the slot types values in explicit form. I find it weird as you can manipulate values from code and change the original user’s choices.
If slot type values don’t satisfy the business rules you have coded, these logic paths should fire the “Elicit slot” dialog action type. It forces user to choose another value for a slot. You can only elicit one slot at a time.
After all the slot type values passed the validation, bot confirms the intent (if the confirmation prompt or a code for “Confirm intent” dialog action type is provided) and calls the fulfillment code hook. This code path should return the “close” dialog action type response after it has finished with the actual order placement. Here is your chance to pass some values to the next intent to make bot look more intelligent, e.g. in the Amazon example bot after user has booked a hotel, they can book a car within the same session with some slots pre-filled from the first intent. The session attributes response part, which was quite useless until this point (unless you used it to store some session-specific data which is not slots values), could transfer key-value pairs between intents. In the example bot last confirmed reservation slot values are crammed into one string, probably to save the space; there are some limitations on the session attributes size as they are sent in POST header back in user’s request. Another intent can use different Lambda initialisation function, but it should know that some values could be passed this way and look for the key in session attributes.
The only dialog action type I haven’t mentioned so far is “Elicit Intent”. When user’s initial message doesn’t match any of the intents’ utterances bot fires one of the clarification prompts from “Error handling” menu to elicit intent. I couldn’t find how to replace this prompt from code, as Lambda functions are hooked to intents, but this event happens before intent is recognised. Also I couldn’t find where it would be logical to give this response in code hook, unless you want to quit the current intent badly. It is not mentioned in Amazon examples either.