Need a bit of Alexa-to-Jovo advice

v3
amazon-alexa

#1

Alexa has some native support for a few questions about the recording currently playing – among the MusicRecording intents, it has phrases that should get routed to the active skill’s Amazon.SearchAction handling. (See https://developer.amazon.com/en-US/docs/alexa/custom-skills/musicrecording-intents.html)

I’m not clear on what would need to be done in Jovo to catch and respond to those queries.

My attempts to guess the appropriate incantations in the app.js/handler.js haven’t yet succeeded.

Developers: Should this be doable with Jovo, and if so what’s the trick?

(I can implement equivalent queries directly in my skill, but then I would have to explicitly Ask the skill to get them routed appropriately, rather than just being able to say “Echo, who’s the performer?” I’ll do that if I must, but I’d rather have the skill’s behavior be more like other music skills. Though admittedly said skills are probably tied a lot deeper into Amazon’s presumed data structures for music catalogs.)


#2

I haven’t used these intents yet, but from the requests in the documentation, it seems like they are typical intent strings that would need to be added as intent handlers, e.g.

'AMAZON.SearchAction<object@MusicRecording[producer]>'() {
  // ...
}

What happens if you try this? Could you also send a full request JSON that you receive in your skill if you test a query like this?


#3

Ah. I’m still having trouble wrapping my head around quoted strings as “function” names; I was expecting that I could define AMAZON.SearchAction and treat the rest as parameter types. I’ll try it that way.

Query for “Who performs this song” when the skill is in stopped mode:

{
   "version": "1.0",
   "session": {
      "new": true,
      "sessionId": "amzn1.echo-api.session.55690c28-4052-4500-a7ff-a9642cdd65ba",
      "application": {
         "applicationId": "amzn1.ask.skill.c952aa96-df06-4cbf-a9a9-46b7b4113871"
      },
      "attributes": {},
      "user": {
         "userId": "amzn1.ask.account.AFG4ORA6CUUX3VDUDSGGSO6KTYNN6Y6TN7SNYYBOGRFEVEJNFFXJWPLLRSVAA7Z64XO7JBXSBGXGQDPCFBLPFEGHBJYPCA4RDB4JIV3ISLQ5SL4EHTFIFYZJCLWPBB7KY44M5B6NFBNIYBLRW6FDM2SS4YTNJJA2G7ILVFPHPZMCT3OWKCNJUHI2LMGYOWUEZWKWRH3ALTUIAEY"
      }
   },
   "context": {
      "AudioPlayer": {
         "offsetInMilliseconds": 1461816,
         "token": "null",
         "playerActivity": "STOPPED"
      },
      "Extensions": {
         "available": {}
      },
      "System": {
         "application": {
            "applicationId": "amzn1.ask.skill.c952aa96-df06-4cbf-a9a9-46b7b4113871"
         },
         "user": {
            "userId": "amzn1.ask.account.AFG4ORA6CUUX3VDUDSGGSO6KTYNN6Y6TN7SNYYBOGRFEVEJNFFXJWPLLRSVAA7Z64XO7JBXSBGXGQDPCFBLPFEGHBJYPCA4RDB4JIV3ISLQ5SL4EHTFIFYZJCLWPBB7KY44M5B6NFBNIYBLRW6FDM2SS4YTNJJA2G7ILVFPHPZMCT3OWKCNJUHI2LMGYOWUEZWKWRH3ALTUIAEY"
         },
         "device": {
            "deviceId": "amzn1.ask.device.AG73RQEX4T2TCJ4WYDKYHCXAFRGNWAHK4QSIZDKARG52EN4FCWAQVVG4GYZDJUIPV66HCV6QUYTNVZMVTIX56DGZ3SSXLV2ZEI4AG5LH2SADPGHSPGQIR72Y4SMXY2AVWJCDQ4CSCY57SV54H7MT5ZBPTN4A",
            "supportedInterfaces": {
               "AudioPlayer": {}
            }
         },
         "apiEndpoint": "https://api.amazonalexa.com",
         "apiAccessToken": "(...elided...)",
         "unit": {
            "unitId": "amzn1.ask.unit.AG4K633PFRTQ46UOUMDB3ULGNHTYA4PWMDYLVQ3P7WRZ6V6IWKHIKXBPU2766EC5UPF6GXONHQN7A5RRTV5KOHTGIFF4NE5HOBLFPFGDAXE3IGYAZBW6L4R6SXK4EJQYEY"
         }
      }
   },
   "request": {
      "type": "IntentRequest",
      "requestId": "amzn1.echo-api.request.2d23e065-9a13-444a-bf4f-a01241bf7411",
      "locale": "en-US",
      "timestamp": "2021-10-12T13:34:59Z",
      "intent": {
         "name": "AMAZON.SearchAction<object@MusicRecording[byArtist.musicGroupMember]>",
         "confirmationStatus": "NONE",
         "slots": {
            "object.byArtist.musicGroupMember.type": {
               "name": "object.byArtist.musicGroupMember.type",
               "value": "performed",
               "confirmationStatus": "NONE",
               "source": "USER",
               "slotValue": {
                  "type": "Simple",
                  "value": "performed"
               }
            }
         }
      }
   }
}

#4

Trying it that way, during build the Google Action phase tells me

 »   Error: There was a problem:
 »
 »   [ERR] ENOENT: no such file or directory, open
 »   'C:\Users\keshlam\jovo\new-sounds-on-demand\platforms\googleAction\dialogf
 »   low\intents\AMAZON.SearchAction<object@MusicRecording[byArtist]>.json'

Moving these into the Alexa-specific portion of the model file (and changing the empty “phrases” to be called “samples”) changed the error message; now alexaSkill deploy is telling me

 »   [ERR] smapiUpdateInteractionModel:Server cannot process the request due to
 »    a client error e.g. the input interaction model is invalid.

So I’m not sure how to express this in the Jovo model such that it will be correctly generated into the platform-specific grammars, even just the Amazon one. Any hints?


#5

Can you show how you’ve done it?


#6

I’ve done a bit of flailing around, but the most recent attempt was as follows. Apologies for the variation in indentation seen here; probably a tabs vs. spaces issue.

  "alexa": {
    "interactionModel": {
        "languageModel": {
            "intents": [
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.PauseIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
		    {
			"name": "AMAZON.SearchAction<object@MusicRecording[byArtist]>",
			"samples": []
		    },
		    {
			"name": "AMAZON.SearchAction<object@MusicRecording[byArtist.musicGroupMember]>",
			"samples": []
		    },
		    {
			"name": "AMAZON.SearchAction<object@MusicRecording[duration]>",
			"samples": []

		    }, 
		    {
			"name": "AMAZON.SearchAction<object@MusicRecording[inAlbum]>",
			"samples": []

		    }, 
		    {
			"name": "AMAZON.SearchAction<object@MusicRecording[producer]>",
			"samples": []
		    } 

            ]
        }
    }

The problem might be that the Amazon implied samples are conflicting with explicit phrases elsewhere in my model, but it’d be nice to have that tell me something more explicit/useful…


#7

The examples in the official Alexa docs don’t have samples: https://developer.amazon.com/en-US/docs/alexa/custom-skills/musicrecording-intents.html#intent-signature

One idea is to add the intents in the Alexa Developer Console and use jovo get alexaSkill to retrieve the model. You can then look at the files in the platforms folder to see how they differ from what you had before.


#8

Well, on the JSON side, adding the intents via the console creates the entries

        {
            "name": "AMAZON.SearchAction<object@MusicRecording[byArtist.musicGroupMember]>",
            "samples": []
        },
        {
            "name": "AMAZON.SearchAction<object@MusicRecording[byArtist]>",
            "samples": []
        },
        {
            "name": "AMAZON.SearchAction<object@MusicRecording[duration]>",
            "samples": []
        },
        {
            "name": "AMAZON.SearchAction<object@MusicRecording[inAlbum]>",
            "samples": []
        },
        {
            "name": "AMAZON.SearchAction<object@MusicRecording[producer]>",
            "samples": []
        }

… which is what the docs suggested we should use for this set. Of course they don’t put stubs into the Javascript code since we didn’t let them generate that.

Pasted the above into the Alexa-specific portion of my model (after CancelIntent) and tested (using a renamed copy of the project, of course). Created entries in app.js with the long names, quoted as you suggested. This time it seems happier. Not sure what I did differently, other than copypasting those names to make Darned Sure I didn’t mistype them.

Well, at least there’ll be an example on git soon for others to look at so they don’t make my mistake, whatever it was…

QUESTION: I just noticed that in index.js (which I’d never had to edit), you have a section called IntentMap, which appears to associate AMAZON.Whatever with WhateverIntent. Could/should that be updated so I could use more meaningful intent names in app.js?


#9

Unfortunately it looks like the ability to say “Alexa, who’s playing this song” as a non-prefixed command (without specifying “ask myskillname”) either isn’t available for apps that haven’t received special permission to accept non-prefixed commands … or there’s something else I need to do to tell the system that we are capable of responding to these queries.

I seem to remember that there is a “can you process this” handshake for at least some operations; I’ll go diving back into the Alexa apps to try to find documentation for that and see if it’s relevant.

But at least I should now accept all the Alexa-standardized phrasings of these requests that other Alexa apps do. It’s a step forward-ish.

Pushed what I’ve got so far to Git, even if it does currently just respond with a polite version of “I’m sorry, Dave. I can’t do that.”


#10

Does Jovo automatically provide default canHandle() processing for Alexa (https://developer.amazon.com/en-US/docs/alexa/custom-skills/handle-requests-sent-by-alexa.html#handle-intents)? I haven’t seen a canHandle() method in your examples… and I’m not certain what effect not having it has, especially on non-prefixed requests.


#11

The docs say that this feature is still in preview, so this might be it

canHandle is specific for the official ASK SDK, which uses a different approach than Jovo. In v4, we offer something in-between, which we hope brings together the best of both worlds: https://v4.jovo.tech/docs/handlers#handler-routing-and-the-handle-decorator


#12

Ok; at some point I need to look into migrating to v4.

The reason I’m asking is that I think (but am not sure) that canHandle may be part of how Alexa decides where to direct prefixless “who is the performer” queries, and I’m still trying to figure out how to make that work as smoothly as default routing of stop and resume do. Or if that’s even possible without having the special permissions from Amazon needed to petition for prefixless command handling.

Learning three or more intersecting “languages” at once is sometimes more interesting than I would prefer…


#13

Following up on this: Alexa canHandle does indeed seem to be used to route prefixless commands to the most-recently-added handler which is willing to process them. So I will need it, or an equivalent, eventually to tell Alexa that my Jovo handler wants to know about “who is playing” questions. Note that this occurs at a level before Jovo’s internal dispatch, so your routing will need to handshake with the Alexa behavior to make that work.

Meanwhile… Is there any way to implement canHandle in Jovo3? I tried implementing it on my handler alongside the intent handling functions, but it isn’t being called – which may mean Amazon hasn’t yet authorized me to try it, or may mean Jovo isn’t passing the call through.

canHandle(handlerInput : HandlerInput) : boolean {
	return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
	    && (
		Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.SearchAction<object@MusicRecording[byArtist.musicGroupMember]>"
		|| Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.SearchAction<object@MusicRecording[byArtist]>"
		|| Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.SearchAction<object@MusicRecording[duration]>"
		|| Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.SearchAction<object@MusicRecording[inAlbum]>"
		|| Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.SearchAction<object@MusicRecording[producer]>"
	    )
},

#14

canHandle doesn’t work like this in a Jovo project, ASK SDK and Jovo are completely different frameworks and don’t work together.

If the requests don’t reach your Jovo endpoint, this seems like it’s setup problem and not a problem how Jovo handles the request. If the requests get logged in your terminal when testing, the approach highlighted above should work:

If you want to map multiple intent names to the same intent handler, you can also add them to the intentMap


#15

Please pardon the questions. It isn’t always obvious how much of the platform’s framework is still present behind the scenes and being front-ended by Jovo, versus being replaced by Jovo.

Prefixless commands other than the core set (next/previous/stop/resume) are definitely not being logged by Jovo.

It may be that Amazon has simply not yet granted my skill permission to implement prefixless commands; their docs say they may not do so until/unless a skill has demonstrated significant usage/popularity. (There is the risk of interfering with other prefixless operations, both native and skill-based, so they seem to want to wait until there’s evidence that the skill is interesting enough to justify this.)

Or it may be that, as the Alexa documentation suggests, canHandle is mandatory for additional prefixless commands, even those defined by the Alexa SDK.

Or both.

I’d be a lot happier if someone could confirm/demonstrate that Jovo will support prefixless commands if and when Amazon lets me use them. I can live without them for now, but to create an idiomatic Alexa skill I’ll want them eventually.


#16

No problem, this is what this forum is here for.

The Alexa API doesn’t care how the app is built. It sends a JSON request and expects a JSON response. Developers decide which framework they want to use to build the desired JSON responses. Jovo and ASK SDK are completely different frameworks in that sense that they use different strategies to build this functionality.

The Alexa API doesn’t know which method was used to generate the JSON response it receives, it only cares about the contents of the response.

I don’t think the problem is that a specific method isn’t being used, but rather that the requests never enter the service. If it were a request that Jovo can’t handle, it would throw an error, it wouldn’t be ignored

Since these prefixless commands are intent requests, they work the same way in Jovo as other intents work. See my above answer for an example:


#17

https://developer.amazon.com/en-US/docs/alexa/custom-skills/understand-name-free-interaction-for-custom-skills.html

… seems to say it really isn’t that simple. Unless Jovo is handling all those details for us.


#18

@jan: The answer to what Jovo events are currently getting through to my code appears to be “nothing”. The lambda isn’t even being invoked for the name-free requests, according to my cloudwatch console logs; instead the default Alexa handler catches them and responds with some version of “Hmmm. I don’t know.”

These ARE present as intents and intent handlers. Take a look for yourself; my code is current on github. And they appear to work when explicitly directed to my skill, or when my skill is explicitly waiting for them. Though I’ve implemented enough synonyms that it isn’t immediately certain whether the built-in or my own grammar is accepting them.

As I say, there is some evidence that Amazon won’t let name-free events reach me yet. So this may be expected behavior until I get a lot more users. I was hoping otherwise. As demonstrated in Amazon’s TV commercials, “Hey Alexa, who is singing this” should work. Eventually.


#19

@jan: For what it’s worth,

https://developer.amazon.com/en-US/docs/alexa/custom-skills/using-nfi-toolkit-cli.html

says name-free interactions have to be declared in a separate clause of the interaction model, and have to distinguish between modal LAUNCH and transient INTENT.

That makes sense for custom commands, certainly. I would hope they don’t make folks jump through that hoop for built-in name-free interactions… but I don’t see any other way to say "Yes, I really want to respond to AMAZON.SearchAction requests.