Implement Custom Tasks in Your Skill
customtasks
.If you have an Alexa skill, you can modify it to perform custom tasks.
- You can use custom tasks to make functionality available to other skills via direct skill connections. See Use Skill Connections to Request Tasks.
- You can use Quick Links for Alexa to take your customers to a specific custom task within your skill and pass input parameters. See Create a Quick Link for Your Custom Task.
- You can make your custom tasks available as actions that users can choose in Alexa Routines. See Integrate Your Custom Task with Alexa Routines.
Prerequisites
This walkthrough requires the use of the ASK CLI v2, which can be found in the ASK CLI GitHub repo.
- If you have an existing skill created using ASK CLI v1, you need to upgrade your skill package to CLI v2.
- If you have an existing skill created using ASK CLI X (ASK CLI v2 public beta version), you need to manually change some skill project structure and then use ASK CLI v2.
Modify your skill package to support custom tasks
When you create or modify a skill with the ASK CLI, rather than the developer console, you can edit your skill package directly. For more information, see Skill package format.
To modify your skill package
- In the
skill-package
folder where you store yourskill.json
file, create a subfolder namedtasks
. Thetasks
folder is for task definition files.
Create a task definition file
Task definitions follow the OpenAPI V3 specifications, with the following restrictions:
- The name of the task definition file must be in the form
{TaskName}.{TaskVersion}.json
, where{TaskName}
is the task name and{TaskVersion}
is the task version number. For example,CountDown.1.json
. - The name of the task is represented as a path. For example, if your task name is
CountDown
, in OpenAPI spec, it would be/CountDown
. - The version of the task can only be a positive integer.
- Only one task definition is allowed per file, which means there should only be one path per file.
- Only inline references are currently allowed.
- The payload of the task is represented as the
POST
body of the previously mentioned specified path, andPOST
is the only HTTP method that is supported. - The
requestBody
of thePOST
supports onlyapplication/json
. - The
responses
of thePOST
supports onlyapplication/json
. - The
x-amzn-alexa-access-scope
field of theinfo
is a custom extension field for access control that supportspublic
andvendor-private
settings. If no access scope value is specified in the task definition, the default value isvendor-private
. - The
x-amzn-display-details
field of theinfo
object is an optional custom extension field where you can add a language localization mapping for the task title. You can use this field to make your custom task available through a quick link or as an Alexa Routines action. - The
x-amzn-display-details
field inside theInput
properties of the task component is a custom extension field to add human-readable strings and an optional language localization mapping for the task input parameters. You can use this field to make your custom task available through a quick link or as an Alexa Routines action.
The following ASK CLI 2.0 example is a response.
$ ask smapi get-task -s <yourSkillId> --task-name amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown --task-version 1
{
"openapi": "3.0.0",
"info": {
"title": "A task to count down numbers",
"version": "1",
"x-amzn-alexa-access-scope": "public",
"x-amzn-display-details": {
"en-US": {
"title": "Count down",
"description": "A task to count down numbers"
},
"es-US": {
"title": "Cuenta regresiva",
"description": "Una tarea para contar números"
}
}
},
"tags": [{
"name": "count down"
}],
"paths": {
"/CountDown": {
"summary": "Count Down",
"description": "To start a count down",
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Input"
}
}
}
},
"responses": {
"200": {
"description": "When the count down finishes successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuccessfulResponse"
}
}
}
},
"400": {
"description": "When the given parameters fail validations - e.g. lowerLimit cannot be higher than upperLimit"
},
"500": {
"description": "When the count down fails"
}
}
}
}
},
"components": {
"schemas": {
"Input": {
"type": "object",
"properties": {
"upperLimit": {
"type": "number",
"maximum": 100,
"minimum": 1,
"x-amzn-display-details": {
"en-US": {
"name": "Upper Limit",
"description": "Input the upper limit"
},
"es-US": {
"name": "Limite superior",
"description": "Ingrese el límite superior"
}
}
},
"lowerLimit": {
"type": "number",
"maximum": 100,
"minimum": 1,
"x-amzn-display-details": {
"en-US": {
"name": "Lower Limit",
"description": "Input the lower limit"
},
"es-US": {
"name": "Límite inferior",
"description": "Ingrese el límite inferior"
}
}
}
}
},
"SuccessfulResponse": {
"type": "object",
"properties": {
"endTime": {
"type": "string",
"format": "date-time"
}
}
}
}
}
}
To create a task definition file
- In a text editor, create a new task definition file in
/tasks
directory calledCountDown.1.json
, and then copy the following JSON into it.
{
"openapi": "3.0.0",
"info": {
"title": "Task to perform a count down",
"version": "1",
"x-amzn-alexa-access-scope": "public"
},
"tags": [{
"name": "count down"
}],
"paths": {
"/CountDown": {
"summary": "Count Down",
"description": "To start a count down",
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Input"
}
}
}
},
"responses": {
"200": {
"description": "When the count down finishes successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuccessfulResponse"
}
}
}
},
"400": {
"description": "When the given parameters fail validations - e.g. lowerLimit cannot be higher than upperLimit"
},
"500": {
"description": "When the count down fails"
}
}
}
}
},
"components": {
"schemas": {
"Input": {
"type": "object",
"properties": {
"upperLimit": {
"type": "number",
"maximum": 100,
"minimum": 1
},
"lowerLimit": {
"type": "number",
"maximum": 100,
"minimum": 1
}
}
},
"SuccessfulResponse": {
"type": "object",
"properties": {
"endTime": {
"type": "string",
"format": "date-time"
}
}
}
}
}
}
Add test examples to certify your task definitions
When you test and submit your skill for certification the functionality of your custom task will be verified. You must provide test examples for your custom task in the task definition file. These test examples are used to generate input to invoke the custom task handler under your skill's AWS Lambda function during pre-certification and certification validation.
Test example definitions follow the OpenAPI V3 specification, with the following restrictions:
- For each custom task, there must be at least one test example provided along with the custom task definition. You can provide up to five test examples for each custom task.
- Make sure that your test examples are valid and result in a successful response when your skill's custom task is invoked.
- Each test example includes the following fields:
Name | Required? | Type | Description |
---|---|---|---|
summary |
No | String | Summary of the test example. |
description |
No | String | Description of the test example. |
value |
Yes | Object | Valid custom task input that conforms to the task definition. |
To add test examples to a task definition file
- In a text editor, add test examples to your task definition file under this path:
post/requestBody/content/application/json/examples
. Following is an example of a task definition request body with test examples added.
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Input"
},
"examples": {
"countdownTenToOne": {
"summary": "Example input for countdown from 10 to 1.",
"description": "The example inputs are used for validation of the task",
"value": {
"upperLimit": 10,
"lowerLimit": 1
}
},
"countdownHundredToNinety": {
"summary": "Example input for countdown from 100 to 90",
"description": "The example inputs are used for validation of the task",
"value": {
"upperLimit": 100,
"lowerLimit": 90
}
}
}
}
}
}
Implement task functionality in an AWS Lambda function
Next, implement the CountDown
functionality in AWS Lambda. This walkthrough uses Python.
Tasks.CompleteTask
or Connections.StartConnection
directive, your response can't include audio, video player, or Alexa Presentation Language (APL) directives.class CountDownTaskHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
task = handler_input.request_envelope.request.task
return is_request_type("LaunchRequest")(handler_input)\
and task and task.name == "amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown"
def handle(self, handler_input):
# Perform countdown and complete the task
response_builder = handler_input.response_builder
task = handler_input.request_envelope.request.task
lower_limit = task.input['lowerLimit']
upper_limit = task.input['upperLimit']
count_down_speech = [i + '<break time="1ms" />' for i in range(lower_limit, upper_limit)]
response_builder.speak("<ssml>" + "".join(count_down_speech) + "</ssml>")
response_builder.add_directive(CompleteTaskDirective(...))
return response_builder.response
Make your task available to other skills
To make your new task available to other skills, you must register the skill that implements the same custom task created in your skill package.
To register the skill that implements the task
- Edit your
skill.json
file as shown in the following example.
{
...
"apis": {
"custom": {
...
"tasks": [{
"name": "CountDown",
"version": "1"
}]
}
}
}
Deploy your skill
To make your skill's tasks available to requester skills, you must deploy the skill as follows.
To deploy a new skill
- In the ASK CLI, run the
ask deploy
command.
--debug
option to verify that your skill's tasks have been successfully deployed.To add custom tasks to an existing skill for deployment (ASK CLI)
- If you have an existing skill created using ASK CLI v1, you need to Migrate your skill from ASK CLI V1 to ASK CLI V2, and then run the
ask deploy
command. - If you have an existing skill created using ASK CLI X (ASK CLI v2 public beta version), you need to manually change some skill project structure and then use ASK CLI v2 to run the
ask deploy
command.
After you deploy your skill, the task is created under your skill's private namespace in the development
stage.
To add custom tasks to an existing skill for deployment (SMAPI)
If you're using SMAPI to programmatically manage your skill, you can follow these steps to deploy tasks to your existing skill:
- Get an access token for use in subsequent steps. You must provide this token in the
Authorization
header for all SMAPI requests. For details about getting an access token, see Get an Access Token for SMAPI. - (Optional) If you don't have a copy of your skill package locally:
- Export it in the skill package format.
- Get the status for the export request. When the status of the export request is
SUCCEEDED
, the response contains a URL to download a zip archive of the exported skill in thelocation
field under theskill
field.
- Edit the skill locally and make changes to task definitions as desired.
- Zip the skill package.
- Upload the zipped skill package to a public URL, or create a presigned upload URL that you can use to upload the skill package to Amazon S3.
- Import the uploaded skill package to your skill.
- Check the status of the import request to verify that the skill has been successfully imported.
To invoke your task handler
- Invoke your task handler through the ASK CLI
invoke-skill-end-point
command as shown in the following example to confirm that your task logic runs correctly. Note that this command doesn't run the task workflow; to do that, your skill must be certified and published. For more information about how to use this command, see the ASK CLI Command Reference.
$ ask smapi invoke-skill-end-point -s {skillId} --stage {skillStage} --skill-request-body file:./input.json --endpoint-region {endpoint-region}
The input.json
file looks like the following example.
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.aaf7b112-434c-11e7-2563-6bbd1672c748",
"application": {
"applicationId": "{YourProviderSkillId}"
},
"user": {
"userId": "amzn1.ask.account.12345ABCDEFGH"
}
},
"context": {
"System": {
"application": {
"applicationId": "{YourProviderSkillId}"
},
"user": {
"userId": "amzn1.ask.account.12345ABCDEFGH"
}
}
},
"request": {
"type": "LaunchRequest",
"requestId": "amzn1.echo-api.request.da528275-5aa6-4f69-8038-06efc94d1923",
"timestamp": "2020-01-29T23:11:48Z",
"locale": "en-US",
"task": {
"name": "{YourProviderSkillId}.{taskName}",
"version": "{taskVersion}",
"input": {
...
}
}
}
}
Restrict access to your custom task
You can restrict access to a custom task. Two access levels are currently supported.
- Public: Your task will be exposed to all skills.
- Vendor Private: Your task will only be exposed to the skills under your vendor - i.e., it will not show up in search results performed by other vendors' skill developers.
By default, all custom tasks start with the Vendor Private access level. In order to set the access level for your task, you must modify the info
section in your task definition file to include the x-amzn-alexa-access-scope
field, with either public
(for Public access) or vendor-private
(for Vendor Private access).
How to make a custom task available for skill connections
To expose tasks to other skills, your provider skill must be certified and published. Submit your skill for certification and publication as described in Skill Certification and Publication. After it is certified and published to the live
stage, your task becomes part of the task catalog and is available for other skills to use through Skill Connections.
A developer can discover your task via the ASK CLI search-task
and get-task
commands.
search-task
and get-task
commands as currently implemented won't return your tasks, not even for you.You can use the -h
option to see command-line help for CLI commands, for example, ask smapi search-task -h
.
The following ASK CLI 2.0 example shows the ask smapi search-task
command with all options specified. (Only skillId
is required. You can use any skillId
under your developer account. provider-skill-id
is optional. If the provider skill id is specified, the result will show all the custom tasks your developer account has access to under that provider skill.)
ask smapi search-task -s <skillId> --keywords <keywords> --provider-skill-id <providerSkillId> --max-results <max-results> —-next-token <nextToken>
The following ASK CLI 2.0 example shows the output.
$ ask smapi search-task -s {skillId} --keywords "count down"
{
"taskSummaryList": [
{
"description": "A task to count down numbers",
"name": "amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown",
"version": "1"
},
{
"description": "Count down numbers from 100 to 1",
name": "amzn1.ask.skill.12345678-abcd-cdef-1234-abcdefabcdef.CountDown",
"version": "1"
}
]
}
$ ask smapi search-task -s <yourSkillId> --provider-skill-id "amzn1.ask.skill.12345678-abcd-cdef-1234-abcdefabcdef"
{
"taskSummaryList": [
{
"description": "Count down numbers from 100 to 1",
"name": "amzn1.ask.skill.12345678-abcd-cdef-1234-abcdefabcdef.CountDown",
"version": "1"
}
]
}
The following ASK CLI 2.0 example shows the ask smapi get-task
command with all options specified (All the options are required.)
ask smapi get-task -s <yourSkillId> --task-name <providerSkillID>.<name> --task-version <task-version>
The following ASK CLI 2.0 example is a response.
Here is the command:
$ ask smapi get-task -s <yourSkillId> --task-name amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown --task-version 1
Here is the output:
{
"openapi": "3.0.0",
"info": {
"title": "A task to count down numbers",
"version": "1",
"x-amzn-alexa-access-scope": "public"
},
"tags": [{
"name": "count down"
}],
"paths": {
"/CountDown": {
"summary": "Count Down",
"description": "To start a count down",
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Input"
}
}
}
},
"responses": {
"200": {
"description": "When the count down finishes successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuccessfulResponse"
}
}
}
},
"400": {
"description": "When the given parameters fail validations - e.g. lowerLimit cannot be higher than upperLimit"
},
"500": {
"description": "When the count down fails"
}
}
}
}
},
"components": {
"schemas": {
"Input": {
"type": "object",
"properties": {
"upperLimit": {
"type": "number",
"maximum": 100,
"minimum": 1
},
"lowerLimit": {
"type": "number",
"maximum": 100,
"minimum": 1
}
}
},
"SuccessfulResponse": {
"type": "object",
"properties": {
"endTime": {
"type": "string",
"format": "date-time"
}
}
}
}
}
}
How does my task get invoked through Skill Connections?
After your task is certified and published to the live
stage, your task can be requested by other skills through the task's canonical ID, which is a concatenation of your skillId
and the task's name, such as {ProviderSkillId}.CountDown
.
For a requester skill to connect to your task, that skill must return the following directive in its skill response. To request a custom task, requester skill must send a direct skill connection, specifying the provider skill ID in the URI.
Tasks.CompleteTask
or Connections.StartConnection
directive, your response can't include audio, video player, or Alexa Presentation Language (APL) directives.{
"type": "Connections.StartConnection",
"uri": "connection://{ProviderSkillId}.CountDown/1?provider={ProviderSkillId}",
"input": {
"lowerLimit": 1,
"upperLimit": 10
}
}
For more details about how a task is requested, see Request a task from a provider skill.
Related topics
Last updated: Apr 30, 2024