Feature Proposal: Conversational Components


#21

Thanks for the feedback Mark!

There is no convention. You can name components as you like.

I think there has to be made some small tweaks for it to work in a state, which should be fairly easy to implement. As for one of them being inside a different state, I am not sure about the amount of work it would take. I also don’t really see a scenario in which it would be useful. The typical scenario I have in my head would be: Inside State A, delegate to a component. Receive the response inside the CompletedIntent inside the same state and route to what ever state you want from that point on. Do you have one in your mind?

There is no naming convention. You have the possibility to specify the component’s name inside it’s name property (which might actually better fit into the config now that I think about it). If there was no name specified the framework will use the constructor’s name (in the example’s case PHONE_NUMBER). The component’s name will be used to reference the component from that point on, whether in delegate or with this.$components. It’s not currently implemented, but if you try to access it with a wrong name, you will simply receive an error.

Yes, that’s possible.

Example:

module.exports = {
    components: {
        PHONE_NUMBER: {
            numberOfFails: 3
        }
    }
};

You can access the component’s config, outside and inside the component, using this.$components.componentName.config

The config inside the component is used as a default configuration provided by the dev. The changes you want to make to that default config will be made inside the app’s root config file, just like the example above.
The changes made in the root config are merged into the component’s default config.

The intentMap is handled a little different. The component’s intentMap is never merged into the app’s one. If a component is active, it’s intentMap will be used, else the app’s one.

Yes, since you make changes to the component’s config using the root config files, the staging feature you already use will work here as well.

Not implemented yet, but should be possible.

Difficult to answer, since it would be different for each component (e.g. amount of work to abstract it for every location).

Yes, I agree. In the updated version everything is inside a state.

I can see, how that could be a problem, but I’d say that’s a problem that can’t be addressed on framework/component side. Do you have an idea?

Yes, I agree. In the case of Stop and Cancel, the current idea is to send out a response (specifying the status as rejected) and routing to the onCompletedIntent at which point the dev can take over.

I prefer Ask, Confirm, Validate, but I’m open for discussion.

Good idea. Might implement that in a further version.

If one went that route, it might make sense to split each component into multiple for each location, e.g. US_PHONE_NUMBER is its own component and DE_PHONE_NUMBER as well.

There’s no real reason, as far as I know.

Yes, should be possible.

Thanks again for the feedback! There should be an updated version of the phone number example out soon.


#22

If given permission, I can get the user’s mobile phone number using:

const mobileNumber = await this.$alexaSkill.$user.getMobileNumber();

This can then be used in the PHONE_NUMBER component to first validate (does it exist) and then use as a default value:

USER: Send me a text
ALEXA: Would you like to send the info to 555.867.5309?
USER: No
ALEXA: What phone number should I use?
USER: 555.555.5555
ALEXA: You want to send the text to 555.555.5554. Correct?
USER: No
ALEXA: What's the phone number?
...

There needs to be a way to pass the default phone number.

Option 1

// options param, completion handler
const options = {
  defaultPhoneNumber: '555.867.5309'
};

this.delegate('PHONE_NUMBER', 'CompletedIntent', options);

Option 2

// options param only
const options = {
  defaultPhoneNumber: '555.867.5309',
  completedHandler: 'CompletedIntent'
};

this.delegate('PHONE_NUMBER', options);

Option 3

// pass to $components
this.components$.PHONE_NUMBER.$params.defaultPhoneNumber = '555.867.5309';
this.delegate('PHONE_NUMBER', 'CompletedIntent');

Which option do you think is better?


#23

I like this one best! Maybe not every component will have a completedHandler, so making this part of the options makes sense to me


#24

You can use an Entity for this. You can build an entity with all the known values of possibilities you would use and create an intent the receives only that value.

But, I highly recommend you, that for no screen devices, to not prompt more than two options to the user. It can turn to be complicated to both the user and you.


#25

@renatoalencar I agree that overloading the user with options makes for a poor experience. However sometimes giving a list of choices is appropriate. For example listing products or article titles.

Allowing the user to select an item by name instead of ordinal value improves this experience. However, when you are pulling data from an API it may be hard to list all the possible entities since they can change frequently and have highly varied values. Alexa has support for Dynamic Entities which might do the trick, however I haven’t found something like that for Google Assistant.


#26

You can use the automated expansion option, if you want to try to generalize your entity.


#27

By the way, this is in the works :rocket: Thanks for the great suggestion.

cc @Kaan_Kilic


#28

I am struggling with the language model merge. I am using de-DE.js files (with the proposed component structure) but the jovo build command won’t merge my component model. I also tried switching to “*.json” files - no difference.


#29

The merge-feature is still in development (cc @rubenaeg). Right now, you have to merge by hand. Working on improving the whole process!