The situation: I'm developing the chatbot. Today I noticed that the fulfillment code isn't working as expected. The fulfillment code is pretty basic, mostly just triggering custom followup events (e.g. agent.setFollowupEvent('someCustomName')), which then triggers specific intent.
I'm using the fulfillment with the Inline editor for Google Cloud so the webhook server is in Google Cloud.
I'm also using 2 integrations (DF messenger & FB messenger).
Everything worked fine, but today I'm very often seeing an error (specifics below).
Steps I did today and which led to the problem:
'The real' problem: the bot breaks when using Enable beta features and APIs option and agent.setFollowupEvent() in the fulfillment code
My bot is using very simple event triggering. I think the part of the code below is self-explanatory enough, so here it is:
// Dummies
function D_99_01_01(agent) {
agent.add(`...`);
agent.setFollowupEvent('custom_990101');
}
let intentMap = new Map();
// Dummies
intentMap.set('02.01 > some intent to trigger the event (D99.01.01)', D_99_01_01);
agent.handleRequest(intentMap);
The easiest way to explain the problem is: if I don't enable the 'Enable beta features and APIs' option, this code works fine. If I do enable the 'Enable beta features and APIs' option, it doesn't work - in that case I get the error response:
Webhook call failed. Error: UNAVAILABLE, State: URL_UNREACHABLE, Reason: UNREACHABLE_5xx, HTTP status code: 500.
The error happens regardless of how I'm testing/using the bot (while testing inside Dialgoflow itself, while testing on https://console.actions.google.com/, while using the chatbot on production website (integration with DF messenger) or while testing FB messenger integration (app on FB page)).
My partial solution and questions:
Edit: adding the whole code
Package.json (default, didn't touch it):
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "10"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.2.0",
"firebase-admin": "^5.13.1",
"firebase-functions": "^2.0.2",
"dialogflow": "^0.6.0",
"dialogflow-fulfillment": "^0.5.0"
}
}
index.js:
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
/*
function welcome(agent) {
agent.add(`Pozdravljeni!`);
}
function fallback(agent) {
agent.add(`Oprostite, nisem razumela.`);
agent.add(`Lahko ponovite, prosim?`);
}
*/
// Dummies
function D_99_01_01(agent) {
//agent.add(`Text reponse`);
//console.log('Dummy custom_990101 triggered');
//agent.setContext({ name: 'outputCOntext', lifespan: 1, parameters: {}});
agent.add(`...`);
agent.setFollowupEvent('custom_990101');
}
function D_99_01_02(agent) {
agent.add(`...`);
agent.setFollowupEvent('custom_990102');
}
function D_99_01_03(agent) {
agent.add(`...`);
agent.setFollowupEvent('custom_990103');
}
function D_99_02_01(agent) {
agent.add(`...`);
agent.setFollowupEvent('custom_990201');
}
function D_99_03_01(agent) {
agent.add(`...`);
agent.setFollowupEvent('custom_990301');
}
function D_01(agent) {
agent.add(`...`);
agent.setContext({ name: 'Nov_narocnik', lifespan: 0, parameters: {}});
agent.setContext({ name: 'Obstojec_narocnik', lifespan: 0, parameters: {}});
agent.setFollowupEvent('custom_01');
}
function D_02_02(agent) {
agent.add(`...`);
agent.setContext({ name: '01Uvod-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_0202');
}
function D_02_02_01(agent) {
agent.add(`...`);
agent.setContext({ name: 'Obstojec_narocnik', lifespan: 999, parameters: {}});
agent.setContext({ name: '0202Obstojenaronik-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020201');
}
function D_02_02_02(agent) {
agent.add(`...`);
agent.setContext({ name: 'Obstojec_narocnik', lifespan: 999, parameters: {}});
agent.setContext({ name: '0202Obstojenaronik-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020202');
}
function D_02_02_02_SERVICE_NO(agent) {
agent.add(`...`);
agent.setFollowupEvent('custom_020202_SERVICE_NO');
}
function D_02_02_02_SERVICE_NO_CLIENT(agent) {
agent.add(`...`);
agent.setContext({ name: '020202Podpora-STORITEV-ne-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020202_SERVICE_NO_CLIENT');
}
function D_02_02_02_SERVICE_NO_FINISH(agent) {
agent.add(`...`);
agent.setContext({ name: '020202Podpora-STORITEV-ne-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020202_SERVICE_NO_FINISH');
}
function D_02_02_02_SERVICE_NO_SUPPORT(agent) {
agent.add(`...`);
agent.setContext({ name: '020202Podpora-STORITEV-ne-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020202_SERVICE_NO_SUPPORT');
}
function D_02_02_03(agent) {
agent.add(`...`);
agent.setContext({ name: 'Obstojec_narocnik', lifespan: 999, parameters: {}});
agent.setContext({ name: '0202Obstojenaronik-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020203');
}
function D_02_02_03_NO(agent) {
agent.add(`...`);
agent.setContext({ name: '020203Obstojenaronik-klub-followup', lifespan: 2, parameters: {}});
agent.setFollowupEvent('custom_020203_NO');
}
// // Uncomment and edit to make your own intent handler
// // uncomment `intentMap.set('your intent name here', yourFunctionHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function yourFunctionHandler(agent) {
// agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`);
// agent.add(new Card({
// title: `Title: this is a card title`,
// imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
// text: `This is the body text of a card. You can even use line\n breaks and emoji! 💁`,
// buttonText: 'This is a button',
// buttonUrl: 'https://assistant.google.com/'
// })
// );
// agent.add(new Suggestion(`Quick Reply`));
// agent.add(new Suggestion(`Suggestion`));
// agent.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }});
// }
// // Uncomment and edit to make your own Google Assistant intent handler
// // uncomment `intentMap.set('your intent name here', googleAssistantHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function googleAssistantHandler(agent) {
// let conv = agent.conv(); // Get Actions on Google library conv instance
// conv.ask('Hello from the Actions on Google client library!') // Use Actions on Google library
// agent.add(conv); // Add Actions on Google library responses to your agent's response
// }
// // See https://github.com/dialogflow/fulfillment-actions-library-nodejs
// // for a complete Dialogflow fulfillment library Actions on Google client library v2 integration sample
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
//intentMap.set('Default Welcome Intent', welcome);
//intentMap.set('Default Fallback Intent', fallback);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
// Dummies
intentMap.set('02.01 > fizična oseba - no - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.01 > fizična oseba - no - email (D99.01.02)', D_99_01_02);
intentMap.set('02.01 > fizična oseba - no - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.01 > fizična oseba - omrežje - posvet - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.01 > fizična oseba - omrežje - posvet - email (D99.01.02)', D_99_01_02);
intentMap.set('02.01 > fizična oseba - omrežje - posvet - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.01 > ne zdaj - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.01 > ne zdaj - email (D99.01.02)', D_99_01_02);
intentMap.set('02.01 > ne zdaj - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.01 > no - yes - klub (D02.02.03)', D_02_02_03);
intentMap.set('02.02.01 > no - yes - razmerje (D02.02.01)', D_02_02_01);
intentMap.set('02.02.01 > no - yes - podporne storitve (D02.02.02)', D_02_02_02);
intentMap.set('02.02.01 > no - no (D99.02.01)', D_99_02_01);
intentMap.set('02.02.01 > yes - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.01 > yes - email (D99.01.02)', D_99_01_02);
intentMap.set('02.02.01 > yes - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.02.02 Podpora - no - splošno (D02.02)', D_02_02);
intentMap.set('02.02.02 Podpora - no - zaključek (D99.03.01)', D_99_03_01);
intentMap.set('02.02.02 Podpora - tv2go - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
intentMap.set('02.02.02 Podpora - tv2go - yes - email (D99.01.02)', D_99_01_02);
intentMap.set('02.02.02 Podpora - tv2go - yes - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.02 Podpora - tv2go - yes - other - obstoječ naročnik (D02.02.02_SERVICE_NO_CLIENT)', D_02_02_02_SERVICE_NO_CLIENT);
intentMap.set('02.02.02 Podpora - tv2go - yes - other - podpora (D02.02.02_SERVICE_NO_SUPPORT)', D_02_02_02_SERVICE_NO_SUPPORT);
intentMap.set('02.02.02 Podpora - tv2go - yes - other - zaključek (D02.02.02_SERVICE_NO_FINISH)', D_02_02_02_SERVICE_NO_FINISH);
intentMap.set('02.02.02 Podpora - tv2go - yes - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.02.02 Podpora - eračun - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
intentMap.set('02.02.02 Podpora - eposlovanje - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
intentMap.set('02.02.02 Podpora - trajnik - yes - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.02.02 Podpora - trajnik - yes - no service - obstoječ naročnik (D02.02.02_SERVICE_NO_CLIENT)', D_02_02_02_SERVICE_NO_CLIENT);
intentMap.set('02.02.02 Podpora - trajnik - yes - no service - zaključek (D02.02.02_SERVICE_NO_FINISH)', D_02_02_02_SERVICE_NO_FINISH);
intentMap.set('02.02.02 Podpora - trajnik - yes - no service - podpora (D02.02.02_SERVICE_NO_SUPPORT)', D_02_02_02_SERVICE_NO_SUPPORT);
intentMap.set('02.02.02 Podpora - trajnik - yes - email (D99.01.02)', D_99_01_02);
intentMap.set('02.02.02 Podpora - trajnik - yes - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.02 Podpora - trajnik - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
intentMap.set('02.02.02 Podpora - horizont - no (D02.02.02_SERVICE_NO)', D_02_02_02_SERVICE_NO);
intentMap.set('02.02.02 Podpora - horizont - yes - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.02.02 Podpora - horizont - yes - other - podpora (D02.02.02_SERVICE_NO_SUPPORT)', D_02_02_02_SERVICE_NO_SUPPORT);
intentMap.set('02.02.02 Podpora - horizont - yes - other - zaključek (D02.02.02_SERVICE_NO_FINISH)', D_02_02_02_SERVICE_NO_FINISH);
intentMap.set('02.02.02 Podpora - horizont - yes - other - obstoječ naročnik (D02.02.02_SERVICE_NO_CLIENT)', D_02_02_02_SERVICE_NO_CLIENT);
intentMap.set('02.02.02 Podpora - horizont - yes - email (D99.01.02)', D_99_01_02);
intentMap.set('02.02.02 Podpora - horizont - yes - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.02 Podpora - STORITEV - no - zaključek (D99.03.01)', D_99_03_01);
intentMap.set('02.02.02 Podpora - STORITEV - no - obstoječ naročnik (D02.02)', D_02_02);
intentMap.set('02.02.02 Podpora - STORITEV - no - podpora (D02.02.02)', D_02_02_02);
intentMap.set('02.02.03 > yes - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.03 > yes - nič - splošno (D02.02)', D_02_02);
intentMap.set('02.02.03 > yes - nič - zaključek (D99.03.01)', D_99_03_01);
intentMap.set('02.02.03 > yes - nič - klub (D02.02.03_NO)', D_02_02_03_NO);
intentMap.set('02.02.03 > yes - email (D99.01.02)', D_99_01_02);
intentMap.set('02.02.03 > yes - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.02.03 > no - naročilo storitev - yes (D02.02)', D_02_02);
intentMap.set('02.02.03 > no - naročilo storitev - no (D99.02.01)', D_99_02_01);
intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - nič - zaključek (D99.03.01)', D_99_03_01);
intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - nič - klub (D02.02.03_NO)', D_02_02_03_NO);
intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - nič - splošno (D02.02)', D_02_02);
intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - email (D99.01.02)', D_99_01_02);
intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - telefon (D99.01.01)', D_99_01_01);
intentMap.set('02.02.03 > no - naročilo izdelka - pomoč - klepet (D99.01.03)', D_99_01_03);
intentMap.set('02.02.03 > no - naročilo izdelka - brez naročila - klub (D02.02.03_NO)', D_02_02_03_NO);
intentMap.set('02.02.03 > no - naročilo izdelka - brez naročila - zaključek (D99.03.01)', D_99_03_01);
intentMap.set('02.02.03 > no - naročilo izdelka - brez naročila - splošno (D02.02)', D_02_02);
intentMap.set('02.02.03 > no - splošno - yes (D02.02)', D_02_02);
intentMap.set('02.02.03 > no - splošno - no (D99.02.01)', D_99_02_01);
intentMap.set('DFI - telefon (D99.01.01)', D_99_01_01);
intentMap.set('DFI - email (D99.01.02)', D_99_01_02);
intentMap.set('DFI - klepet (D99.01.03)', D_99_01_03);
intentMap.set('DFI - osnovni meni (D01)', D_01);
intentMap.set('DFI - zaključek (D99.03.01)', D_99_03_01);
agent.handleRequest(intentMap);
});
According to the documentation, the Dialogflow fulfillment does not supports agent versioning:
The Dialogflow fulfillment library does not support versioning. If you need to use versioning, choose one of the following options:
- Overwrite the default inline editor code with your custom webhook code.
- Deploy custom webhook code to Cloud Functions directly.
- Fork and modify the Dialogflow fulfillment library to support versioning.
In addition, it's recommended to move your code from the inline editor to a webhook service (eg, creating your own custom handlers in Cloud Functions) when deploying to production.
The inline editor is intended for simple fulfillment testing and prototyping. Once you are ready to build a production application, you should create a webhook service.
On the other hand, the Dialogflow fulfillment library is not longer maintained by Google, and since you've enabled beta features and API, this might be running into compatibility issues, as the first library is not up to date. I would recommend you to disable it, unless you have a real good reason to do use it, such as using Knowledge connectors, which is a beta feature (November, 2021).