Dialogflow v2 API + Actions v2 API: MalformedResponse 'final_response' must be set - actions-on-google

I'm trying to start working on Google Actions v2 API together with Dialgoflow v2 API.
I have the following example (so far in Dialogflow -> Fulfillment Webhook) taken from official Google Actions Migration Guide , but unfortunately I keep getting MalformedResponse 'final_response' must be set error.
'use strict';
const functions = require('firebase-functions');
const { dialogflow } = require('actions-on-google');
const app = dialogflow();
app.intent('Default Welcome Intent', conv => {
conv.ask('How are you?');
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
And response is:
{
"responseMetadata": {
"status": {
"code": 13,
"message": "Failed to parse Dialogflow response into AppResponse because of empty speech response",
"details": [
{
"#type": "type.googleapis.com/google.protobuf.Value",
"value": "{\"id\":\"542fe4a8-6017-429f-81c3-61ba568e3659\",\"timestamp\":\"2018-04-19T20:16:25.606Z\",\"lang\":\"en-us\",\"result\":{},\"status\":{\"code\":200,\"errorType\":\"success\"},\"sessionId\":\"1524168985362\"}"
}
]
}
}
}
Please any idea why this can be happening?

Change this line:
conv.ask('How are you?');
to this:
conv.close('How are you?');
the close method configures the required final_response field for you

Related

How to use the Zoho Desk Invoke API (Proxy) to call the Zoho Desk Push-Data to Desk (aka Import) endpoint?

I am trying to use the Zoho Desk Invoke API (Proxy) to call the Zoho Desk Push-Data to Desk (aka Import) endpoint.
This is what my code looks like:
// Build the payload
const invokeApiRequestPayload = {
"securityContext":"edbsnc50b85a3cd964126073f50499ae29a3d6ed3c31123e535e901cdda1b2a312dc0a66c638e2beb2724fffc355faebabf1acd65c3883227c2d329d0c9f62cbbdf26ba4553375b5b11cab90c57590c6b48a3",
"requestURL":"https://desk.zoho.com.au/api/v1/channels/{{installationId}}/import",
"headers":{
"Content-Type":"application/json"
},
"postBody":{
"data":{
"tickets":[
{
"actor":{
"email":"test#gmail.com",
"name":"Tom Billy",
"extId":"NjPk2E6J83g41uDKsD6DznLzz323"
},
"subject":"testing new ticket",
"createdTime":"2022-07-24T01:13:44.419Z",
"status":"Open",
"extId":"YCdHTnu93pQbyNoyZzId"
}
],
"threads":[
{
"contentType":"text/html",
"createdTime":"2022-07-24T01:13:44.419Z",
"extId":"YGrfU6quGoDESjX5HEZM",
"extParentId":"YCdHTnu93pQbyNoyZzId",
"actor":{
"extId":"NjPk2E6J83g41uDKsD6DznLzz323",
"name":"Tom Billy",
"email":"test#gmail.com"
},
"canReply":true,
"content":"testing one two three<br>"
}
]
}
},
"connectionLinkName":"zohodesk",
"requestType":"POST",
"queryParams":{
"orgId":"7002257443"
}
};
// Generate the Hmac
const stringToHash = 'requestURL=https://desk.zoho.com.au/api/v1/channels/{{installationId}}/import&requestType=POST&queryParams={"orgId":"7002257443"}&postBody={"data":{"tickets":[{"extId":"YCdHTnu93pQbyNoyZzId","status":"Open","subject":"testing new ticket","createdTime":"2022-07-24T01:13:44.419Z","actor":{"extId":"NjPk2E6J83g41uDKsD6DznLzz323","name":"Tom Billy","email":"test#gmail.com"}}],"threads":[{"extId":"YGrfU6quGoDESjX5HEZM","extParentId":"YCdHTnu93pQbyNoyZzId","actor":{"extId":"NjPk2E6J83g41uDKsD6DznLzz323","name":"Tom Billy","email":"test#gmail.com"},"content":"testing one two three<br>","createdTime":"2022-07-24T01:13:44.419Z","canReply":true,"contentType":"text/html"}]}}&headers={"Content-Type":"application/json"}&connectionLinkName=zohodesk';
const hmac = crypto
.createHmac('sha256', 'mysecret123')
.update(stringToHash)
.digest('hex');
// The hmac created from the above code is '2aa21d41882223e2e23ad7004cfdc5a0317db5192fdff84431f0515d4f4e004b'
// Make the Invoke API request using Axios
const axiosOptions = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
hash: hmac,
},
params: {
orgId: '7002257443',
},
};
return await axios
.post(
'https://desk.zoho.com.au/api/v1/invoke',
invokeApiRequestPayload,
axiosOptions
)
.catch((error) => {
functions.logger.error(error);
throw new functions.https.HttpsError('unknown', error.message, error);
});
But I always get back Error 422 UNPROCESSABLE_ENTITY:
{
"errorCode":"UNPROCESSABLE_ENTITY",
"message":"`Extra query parameter '{\"securityContext\":\"edbsnc50b85a3cd964126073f50499ae29a3d6ed3c31123e535e901cdda1b2a312dc0a66c638e2beb2724fffc355faebabf1acd65c3883227c2d329d0c9f62cbbdf26ba4553375b5b11cab90c57590c6b48a3\",\"requestURL\":\"https://desk.zoho.com.au/api/v1/channels/{{installationId}}/import\",\"requestType\":\"POST\",\"postBody\":{\"data\":{\"tickets\":[{\"extId\":\"YCdHTnu93pQbyNoyZzId\",\"status\":\"Open\",\"subject\":\"testing new ticket\",\"createdTime\":\"2022-07-24T01:13:44.419Z\",\"actor\":{\"extId\":\"NjPk2E6J83g41uDKsD6DznLzz323\",\"name\":\"Tom Billy\",\"email\":\"test#gmail.com\"}}],\"threads\":[{\"extId\":\"YGrfU6quGoDESjX5HEZM\",\"extParentId\":\"YCdHTnu93pQbyNoyZzId\",\"actor\":{\"extId\":\"NjPk2E6J83g41uDKsD6DznLzz323\",\"name\":\"Tom Billy\",\"email\":\"test#gmail.com\"},\"content\":\"testing one two three<br>\",\"createdTime\":\"2022-07-24T01:13:44.419Z\",\"canReply\":true,\"contentType\":\"text/html\"}]}},\"headers\":{\"Content-Type\":\"application/json\"},\"queryParams\":{\"orgId\":\"7002257443\"},\"connectionLinkName\":\"zohodesk\"}' is present in the input.`"
}
The Zoho Desk docs have this explanation for the UNPROCESSABLE_ENTITY error code:
This errorCode value appears if the input does not fulfil the
conditions necessary for successfully executing the API.
And looking at the returned error message details it seems to be complaining that I have an "Extra query parameter". That does not make sense to me, because I included it as the payload required by the Zoho Desk Invoke API (Proxy).
Can anyone see what I am doing wrong?

Calling OpenWeather API from Watson Assistant: "Direct CloudFunctions call was not successful"

I am trying to use the openweathermap API with Watson Assistant, but I am getting "Webhook call was not successful. Response code is [404]. (and there is 1 more error in the log)."
(I am working from the book by Sabharwal, et al., with my own improvisations for the obsolete elements, like #sys-location.)
I created a Cloud Functions Action called "https://us-south.functions.appdomain.cloud/api/v1/web/my-account-email%40dev/default/Weather-Connection" and checked Enable as Web Action. The action code was imported from the git repo for the book:
let rp = require('request-promise')
function main(params) {
const options = {
uri: "http://api.openweathermap.org/data/2.5/weather?q=" + encodeURIComponent(params.object_of_interest)+ "&units=metric&APPID=19e8588cb3d7d0623e3a5a8ec529232f" ,
json: true
}
return rp(options)
.then(res => {
WeatherReport = "Current Temperature : " +res.main.temp+ ", Pressure : " + res.main.pressure + ", Humidity : " + res.main.humidity + ", temp min : " + res.main.temp_min + " , temp max : " + res.main.temp_max
return { WeatherReport
}
})
}
In the Assistant Options the webhook URI is set to
https://us-south.functions.appdomain.cloud/api/v1/web/my-account-email%40dev/default/Weather-Connection.json.
The "Assistant responds" JSON is
The "Assistant responds" JSON is
{
"output": {
"text": {
"values": [],
"selection_policy": "sequential"
}
},
"actions": [
{
"name": "/my-account-email%40dev/default/Weather-Connection.json",
"type": "cloud_function",
"parameters": {
"object_of_interest": "$location"
},
"credentials": "$credentials",
"result_variable": "$response"
}
],
"context": {
"credentials": {
"api_key": "[my-openweathermap-api-key]"
},
"object_of_interest": "#object_of_interest"
}
}
For debugging, I included a dialog node that displays the value of $location, and it is okay (e.g. "London").
The "Try it out" pane prints {"cloud_functions_call_error":"The requested resource does not exist."} When I click on the Error icon I get a Runtime error pop-up saying, Direct CloudFunctions call was not successful. Http response code is [404]. (and there is 1 more error in the log).
I am not getting any output from running the CLI command ibmcloud fn activation list(I'm not sure that's the right way to check the logs).
I have tested the Weather-Connection function by invoking the Action with parameter {"object_of_interest": "London"}, and it works.
Everything is deployed in the same region (us-south) and namespace.
I can't think of anything else to try.
I just cracked it. I was trying to show the result using the text response is <? $webhook_result_1.response ?> when it should just have been response is <? $webhook_result_1 ?>.

Twilio AutoPilot Redirect to webhook Error - 90100

I've bluid a bot in Twilio AutoPilot and once my bot collected all the information, I need it run a redirect to a webhook.
This webhook works outgoing (I do receive the collected information on the end point) however I'm getting an 90100 error.
This is my code for the webhook:
Code of webhook in Twilio Functions
exports.handler = function(context, event, callback) {
const response = {
actions: [
{
"say": "ik heb denk ik een call naar Zapier gemaakt."
},
{
"redirect": {
"uri": "https://hooks.zapier.com/hooks/catch/xxxxxxxx/oxp6a20/?client=" + event.UserIdentifier + "&materiaal=" + event.Field_materiaal_Value.toLowerCase(),
"method": "POST"
}
}
]
}
callback(null, response);
};
What am I doing wrong?!

Having an issue with Dialogflow API WebhookResponse V2 for Actions for Google

I'm testing Actions for Google, so I created some simple Sinatra application which looks something like:
require 'sinatra'
require 'json'
post '/google_assistant_api' do
content_type :json
case intent_name
when "input_welcome"
decorated_response
when "Recipe name"
basic_card
end
end
private
def decorated_response
{
source: "test source",
speech: "speech",
display_text: "something"
}.to_json
end
def intent_name
parsed_request["queryResult"]["intent"]["displayName"]
end
def parsed_request
#parsed_request ||= JSON.parse(request.body.read)
end
def basic_card
{
"fulfillmentText": "ACTIONS_ON_GOOGLE",
"fulfillmentMessages": [
{
"platform": "PLATFORM_UNSPECIFIED",
"text": {
"text": [
"string text"
]
},
"image": {
"imageUri": "https://avatars3.githubusercontent.com/u/119195?
s=400&v=4"
},
"basicCard": {
"title": "title string",
"subtitle": "subtitle",
"formattedText": "formatted text",
"image": {
"imageUri": "https://avatars3.githubusercontent.com/u/119195"
},
"buttons": []
}
}
],
"source": "source string"
}.to_json
end
Please note that I'm using V2 of the API and testing using google assistant:
I tried many other response formats based on https://gist.github.com/manniru/f52af230669bd3ed2e69ffe4a76ab309 with no luck. I keep getting:
Sorry! there was no response from the Agent. Please try later.
Is there anyone who tried non nodejs response with luck? I would appreciate any sample response as the simple response seems to be working, however as for the basic card I'm having no luck.
Dialogflow's v2 API uses a different format for webhook requests and responses which is documented here:
Dialogflow v2 Webhook Request
Dialogflow v2 Webhook Response
It appears that your code is using the old format.

How to ask permission in Actions on Google without the SDK?

I would like to know the name of the user, however I cannot use the nodejs sdk since I use another language.
How can I ask for permission?
I would prefer a way with the normal json responses.
I hacked this minimal script to get the JSON reponse which the nodejs sdk would return:
gaction.js:
const DialogflowApp = require('actions-on-google').DialogflowApp;
const app = new DialogflowApp({
request: {
body: {
result: {
action: 'Test',
contexts: []
}
},
get: (h) => h
},
response: {
append: (h, v) => console.log(`${h}: ${v}`),
status: (code) => {
return {send: (resp) => console.log(JSON.stringify(resp, null, 2))}
}
}
});
function testCode(app) {
app.askForPermission('To locate you', app.SupportedPermissions.DEVICE_PRECISE_LOCATION);
}
app.handleRequest(new Map().set('Test', testCode));
I'm still no node.js expert so this might be not an optimal solution. When you have installed node and run the command npm install actions-on-google, this will install the necessary dependencies.
When done you just need to run node gaction which will create this output:
Google-Assistant-API-Version: Google-Assistant-API-Version
Content-Type: application/json
{
"speech": "PLACEHOLDER_FOR_PERMISSION",
"contextOut": [
{
"name": "_actions_on_google_",
"lifespan": 100,
"parameters": {}
}
],
"data": {
"google": {
"expect_user_response": true,
"no_input_prompts": [],
"is_ssml": false,
"system_intent": {
"intent": "assistant.intent.action.PERMISSION",
"spec": {
"permission_value_spec": {
"opt_context": "To locate you",
"permissions": [
"DEVICE_PRECISE_LOCATION"
]
}
}
}
}
}
}
If you send now the JSON above you will be asked from Google Home. Have fun!
The request/response JSON formats for the API.AI webhooks with Actions is documented at https://developers.google.com/actions/apiai/webhook
As you've discovered, the data.google.permissions_request attribute contains two fields regarding the request:
opt_context contains a string which is read to give some context about why you're asking for the information.
permissions is an array of strings specifying what information you're requesting. The strings can have the values
NAME
DEVICE_COARSE_LOCATION
DEVICE_PRECISE_LOCATION
If you are using Java or Kotlin there is an Unofficial SDK. It matches the official SDK api nearly exactly.
https://github.com/TicketmasterMobileStudio/actions-on-google-kotlin