Skill Connectionsを使用したタスクのリクエスト



Skill Connectionsを使用したタスクのリクエスト

Alexaスキルは、Skill Connectionsを使って、Amazonまたはプロバイダースキルのタスクをリクエストできます。たとえば、レシピスキルは、印刷スキルにレシピを印刷するようリクエストできます。スキルをリクエスタースキルにする前に、プロバイダースキルに実行させたいタスクを決めて、Amazon定義済みタスクとプロバイダースキルが提供するカスタムタスクのどちらを使うかを決定します。Skill Connectionsの概要については、Skill Connectionsとはを参照してください。

プロバイダースキルのタスクをリクエストする

リクエスタースキルは、プロバイダースキルのタスクをリクエストします。可能であれば、プロバイダースキルはリクエスタースキルのリクエストを実行します。

プロバイダーに制御を渡すには、スキルがConnections.StartConnectionディレクティブを送信します。ユーザー検証後にスキルに制御を戻すには、AlexaがスキルにSessionResumedRequestを送信します。既存のスキルをリクエスタースキルに変更し、プロバイダースキルにタスクをリクエストできるようにします。

プロバイダースキルのタスクをリクエストする場合、リクエスタースキルは、タスク実行後に制御を戻すかどうかを指定できます。その場合、onCompletionフィールドを次のように設定します。

  • RESUME_SESSIONを指定すると、制御がリクエスタースキルに戻り、ユーザーは元のリクエスタースキルセッションの同じ場所に戻ります。
  • SEND_ERRORS_ONLYを指定すると、エラーの場合には通知しますが、制御は戻りません。
  • デフォルト設定は、RESUME_SESSIONです。

スキルをSkill Connectionsタスクのリクエスターにする

  1. Connections.StartConnectionディレクティブを返すハンドラーを実装します。
  2. リクエスタースキルのConnections.StartConnectionディレクティブで指定したonCompletion値に応じて、次のいずれかを実装します。
    • リクエスタースキルがRESUME_SESSIONを指定した場合、SessionResumedRequestリクエストからの応答を受信するハンドラーを実装します。プロバイダースキルがタスクを完了すると、このハンドラーはプロバイダースキルからリクエスタースキルに制御を戻せるようにします。
    • リクエスタースキルがSEND_ERRORS_ONLYを指定した場合、System.ExceptionEncounteredリクエストからの応答を受信するハンドラーを実装します。プロバイダースキルがタスクを完了できない場合、このハンドラーはAlexaからリクエスタースキルにエラー通知を返せるようにします。

遷移プロンプト

リクエスタースキルからプロバイダースキルへの遷移中、Alexaは常にリクエストの転送を示すプロンプトを出します。これは、リクエスタースキルがConnections.StartConnectionディレクティブにRESUME_SESSIONSEND_ERRORS_ONLYのどちらを指定した場合でも同じです。このプロンプトはカスタマイズできません。

  • わかりました。{requester_skill_name}は{provider_skill_name}スキルを使ってリクエストを実行します。{provider_skill_name}にリクエストを送信していいですか?

リクエスタースキルがSEND_ERRORS_ONLYを指定した場合、Alexaは制御を返すプロンプトを出しません。リクエスタースキルがRESUME_SESSIONを指定した場合、プロバイダースキルからリクエスタースキルに制御を戻す間、Alexaは常に制御を戻すプロンプトを出します。このプロンプトはカスタマイズできません。

  • {requester_skill_name}に戻ります。

Connections.StartConnectionディレクティブを返すハンドラーを実装してSkill Connectionsを使用する

応答オブジェクトにConnections.StartConnectionディレクティブをセットすることで、リクエスタースキルはSkill Connectionsリクエストを送信できます。以下の例を参照してください。

明示的またはデフォルトでRESUME_SESSIONを指定したConnections.StartConnectionディレクティブを返す

onCompletionフィールドにRESUME_SESSIONをセットした場合、Connections.StartConnectionディレクティブを返す際にサービスコードのshouldEndSessionフラグを未定義のままにする必要があります。

Managed Skill Connectionsの場合

Managed Skill Connectionsでは、Amazon定義済みタスクのみがサポートされます。以下の例では、task_nameは常にAMAZON.{name}の形式にする必要があります。例:AMAZON.PrintPDF

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}',
            'input': {
               ...
            },
            'onCompletion': 'RESUME_SESSION',
            'token': '...'
        })
        .getResponse();

onCompletionフィールドは必須ではなく、RESUME_SESSIONはデフォルト値のため、以下の例の実行結果は前の例と同じになります。

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}',
            'input': {
               ...
            },
            'token': '...'
        })
        .getResponse();

Direct Skill Connectionsの場合

Direct Skill Connectionsでは、Amazon定義済みタスクとカスタムタスクの両方がサポートされます。以下の例では、task_nameの形式は2通りあります。

  • Amazonの定義済みタスクの場合、形式はAMAZON.{name}AMAZON.PrintPDFなど)になります。
  • カスタムタスクの場合、形式は{provider_skill_id}.{name}amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDownなど)になります。
return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}?provider={provider_skill_id}',
            'input': {
               ...
            },
            'onCompletion': 'RESUME_SESSION',
            'token': '...'
        })
        .getResponse();

SEND_ERRORS_ONLYを指定したConnections.StartConnectionディレクティブを返す

onCompletionフィールドにSEND_ERRORS_ONLYを指定する場合、サービスコードのshouldEndSessionフラグをtrueにセットする必要があります。

Managed Skill Connectionsの場合

Managed Skill Connectionsでは、Amazon定義済みタスクのみがサポートされます。以下の例では、task_nameは常にAMAZON.{name}の形式にする必要があります。例:AMAZON.PrintPDF

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}',
            'input': {
               ...
            },
            'onCompletion': 'SEND_ERRORS_ONLY'
        })
        .withShouldEndSession(true)
        .getResponse();

Direct Skill Connectionsの場合

Direct Skill Connectionsでは、Amazon定義済みタスクとカスタムタスクの両方がサポートされます。以下の例では、task_nameの形式は2通りあります。

  • Amazonの定義済みタスクの場合、形式はAMAZON.{name}AMAZON.PrintPDFなど)になります。
  • カスタムタスクの場合、形式は{provider_skill_id}.{name}amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDownなど)になります。
return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://{task_name}/{version_number}?provider={provider_skill_id}',
            'input': {
               ...
            },
            'onCompletion': 'SEND_ERRORS_ONLY'
        })
        .withShouldEndSession(true)
        .getResponse();

応答のアトリビュート

アトリビュート説明
type必須です。ディレクティブの種類を指定します。この場合はConnections.StartConnectionです。
uri必須です。タスクとタスクのバージョンを定義するリソースです。
input任意です。送信するタスクリクエストのリクエストオブジェクトを含みます。
token任意です。トークンは、そのままスキルのSessionResumedRequestに返されます。タスクリクエストの完了後、このトークンを使用して、リクエスタースキルを再開できます。
onCompletion任意です。タスクの完了後にリクエスタースキルを再開するかどうかを定義する列挙フィールドです。RESUME_SESSIONまたはSEND_ERRORS_ONLYを指定できます。RESUME_SESSIONの場合、タスクが完了するとリクエスタースキルはSessionResumedRequestを受け取ります。SEND_ERRORS_ONLYの場合、エラーが発生した場合のみ、リクエスタースキルはSystem.ExceptionEncounteredを受け取ります。
デフォルト値はRESUME_SESSIONです。

Skill Connectionsリクエストから応答を受け取るハンドラーを実装する

onCompletionアトリビュートにSEND_ERRORS_ONLYを指定しない場合でも、リクエスタースキルは元のタスクリクエストのSkill Connections応答を受け取るハンドラーを実装する必要があります。応答ハンドラーを実装しない場合、スキルに処理されない例外が発生し、リクエスタースキルにはプロバイダースキルから制御が戻されなくなります。

タスクリクエストに対するSkill Connectionsの応答を受け取るハンドラーを実装するには

  • 次の例に示すように、SessionResumedRequestハンドラーをスキルに追加します。リクエスタースキルがSessionResumedRequestを受け取ると、Connections.StartConnectionディレクティブが返されたときに、スキルの以前のセッションに戻ります。

例:応答ハンドラーを実装する

次の例は、Skill Connectionsリクエストの応答を受け取るハンドラーを実装する方法を示しています。

const SessionResumedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionResumedRequest';
  },
  handle(handlerInput) {
    const status = handlerInput.requestEnvelope.request.cause.status;
    const code = status.code;
    const message = status.message;
    console.log(`SessionResumedRequestがステータスコード${code}とメッセージ「${message}」を受け取りました`);

    // 現在のsessionIdは、元のConnections.StartConnectionディレクティブが返されたときの前回のIntentRequestと同じです。
    const currentSessionId = handlerInput.requestEnvelope.session.sessionId;

    // リクエスタースキルのエクスペリエンスが継続します。この例では、音声をレンダリングします。

    return handlerInput.responseBuilder
        .speak("リクエスタースキルがSessionResumedRequestを受け取りました")
        .getResponse();
  }
};

例: SessionResumedRequestリクエストのJSONスキーマ

onCompletionRESUME_SESSIONをセットすると、リクエスターはSessionResumedRequestオブジェクトを受け取ります。リクエストのresultはタスク定義で定義されます。

{
    "type": "SessionResumedRequest",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "cause": {
        "type": "ConnectionCompleted",
        "token": "...",
        "status": {
            "code": "200",
            "message": "OK"
        },
        "result": {
            "key1": "value1",
            "key2": "value2"
        }
    }
}

SessionResumedRequestのステータスコードアトリビュート

Managed Skill Connectionsの場合

Alexaは、タスクリクエスト呼び出しで以下のステータスコードをどれでも返すことができます。

タスクリクエストを実行しているプロバイダースキルは、任意の有効なHTTPコードを返すことができます。

  • status: リクエストのステータスです。
  • code:ステータスコードです。
    • 200: リクエストは正常に実行されました。
    • 204: ユーザーがSkill Connectionsの使用を拒否しました。
    • 227: プロバイダーがアカウントリンクされていません。
    • 400: 不正なリクエスト - リクエストは無効です。
    • 403 : リクエスターはプロバイダーを呼び出すことができません。
    • 404: 現在利用可能なプロバイダーがありません。
    • 500: サーバーエラーです。
  • message: リクエストの結果を表すテキスト文字列のメッセージです。たとえば、「配車予約が正常に完了しました」などのようになります。

Direct Skill Connectionsの場合

リクエスタースキルは、以下のステータスコードのみを返します。タスクリクエストを実行しているプロバイダースキルは、以下のHTTPコードのいずれかのみを返すことができます。

  • status: リクエストのステータスです。
  • code:ステータスコードです。
    • 200: リクエストは正常に実行されました。
    • 400: 不正なリクエスト - リクエストは無効です。
    • 403 : リクエスターはプロバイダーを呼び出すことができません。
    • 404: 現在利用可能なプロバイダーがありません。
    • 500: サーバーエラーです。
  • message: リクエストの結果を表すテキスト文字列のメッセージです。たとえば、「配車予約が正常に完了しました」などのようになります。

詳細については、Alexaから送信されたリクエストを処理するを参照してください。

System.ExceptionEncounteredを処理するハンドラーを実装する

リクエスタースキルがonCompletionSEND_ERRORS_ONLYを指定し、リクエストされたタスクが完了しなかったときに通知を受け取る場合は、リクエスタースキルにSystem.ExceptionEncounteredリクエストを処理するハンドラーを実装する必要があります。System.ExceptionEncounteredリクエストは、次の例のようになります。

{
   "type": "System.ExceptionEncountered",
   "requestId": "unique.id.for.the.request",
   "timestamp": "次の形式のリクエストのタイムスタンプ:  2018-04-11T15:15:25Z",
   "locale": "en-USなどのロケールコード",
   "error": {
      "type": "INVALID_RESPONSEなどのエラーコード",
      "message": "発生したエラーの説明"
   },
   "cause": {
      "requestId": "エラーの原因となったリクエストの一意のID"
   }
}

以下は、System.ExceptionEncounteredを処理するコードの例です。注: このリクエストは通知専用です。すべての応答は無視されます。

const SystemExceptionEncounteredHandler = {
   canHandle(handlerInput) {
      const request = handlerInput.requestEnvelope.request;
      return request.type === 'System.ExceptionEncountered';
   },
   handle(handlerInput) {
      console.dir(handlerInput.requestEnvelope.request);
      return handlerInput.responseBuilder 
         .getResponse();
   },
};

System.ExceptionEncounteredリクエストのエラータイプ

Managed Skill Connections、Direct Skill Connectionsのいずれの場合も、リクエスタースキルがSystem.ExceptionEncounteredリクエストで受け取るエラーは以下のタイプのみです。

  • error: エラー情報を持つオブジェクトが含まれています。
  • type: 特定のタイプのエラーを識別します。
    • INVALID_RESPONSE: リクエスタースキルからの接続開始の応答は無効です。
    • INTERNAL_ERROR: 内部サービスエラーが発生しました。
  • message: デバイスが検出したエラーの説明です。例:「配車予約リクエストが失敗しました」

タスクリクエストの例

以下は、スキルがIntentRequestの処理時に、Amazon定義済みタスクのAMAZON.PrintPDFとカスタムタスクのamzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDownの実行をリクエストする方法の例です。

RESUME_SESSIONを指定したManaged Skill Connectionsの場合

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://AMAZON.PrintPDF/1',
        'onCompletion': 'RESUME_SESSION',
        'input': {
          '@type': 'PrintPDFRequest',
          '@version': '1',
          'title': 'タイトル',
          'description': '説明',
          'url': 'http://www.example.com/flywheel.pdf'
        },
        'token': '...'
      })
      .getResponse();
  }
};

SEND_ERRORS_ONLYを指定したManaged Skill Connectionsの場合

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://AMAZON.PrintPDF/1',
        'onCompletion': 'SEND_ERRORS_ONLY',
        'input': {
          '@type': 'PrintPDFRequest',
          '@version': '1',
          'title': 'タイトル',
          'description': '説明',
          'url': 'http://www.example.com/flywheel.pdf'
        }
      })
    .withShouldEndSession(true)
    .getResponse();
  }
};

RESUME_SESSIONを指定したAmazon定義済みタスクのDirect Skill Connectionsの場合

const TestIntentRequestHandler = {
   canHandle(handlerInput) {
     const request = handlerInput.requestEnvelope.request;
     return request.type === 'IntentRequest'
       && request.intent.name === 'TestIntent';
   },
   handle(handlerInput) {
     return handlerInput.responseBuilder
       .addDirective({
         'type': 'Connections.StartConnection',
         'uri': 'connection://AMAZON.PrintPDF/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
         'onCompletion': 'RESUME_SESSION',
         'input': {
           '@type': 'PrintPDFRequest',
           '@version': '1',
           'title': 'タイトル',
           'description': '説明',
           'url': 'http://www.example.com/flywheel.pdf'
         },
         'token': '...'
       })
       .getResponse();
   }
};

SEND_ERRORS_ONLYを指定したAmazon定義済みタスクのDirect Skill Connectionsの場合

const TestIntentRequestHandler = {
   canHandle(handlerInput) {
     const request = handlerInput.requestEnvelope.request;
     return request.type === 'IntentRequest'
       && request.intent.name === 'TestIntent';
   },
   handle(handlerInput) {
     return handlerInput.responseBuilder
       .addDirective({
         'type': 'Connections.StartConnection',
         'uri': 'connection://AMAZON.PrintPDF/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
         'onCompletion': 'SEND_ERRORS_ONLY',
         'input': {
           '@type': 'PrintPDFRequest',
           '@version': '1',
           'title': 'タイトル',
           'description': '説明',
           'url': 'http://www.example.com/flywheel.pdf'
         }
       })
       .withShouldEndSession(true)
       .getResponse();
   }
};

RESUME_SESSIONを指定したカスタムタスクのDirect Skill Connectionsの場合

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
        'onCompletion': 'RESUME_SESSION',
        'input': {
          'upperLimit': 10,
          'lowerLimit': 1
        },
        'token': '...'
      })
      .getResponse();
  }
};

SEND_ERRORS_ONLYを指定したカスタムタスクのDirect Skill Connectionsの場合

const TestIntentRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'TestIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .addDirective({
        'type': 'Connections.StartConnection',
        'uri': 'connection://amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef.CountDown/1?provider=amzn1.ask.skill.12345678-90ab-cdef-1234-567890abcdef',
        'input': {
          'upperLimit': 10,
          'lowerLimit': 1
        },
        'onCompletion': 'SEND_ERRORS_ONLY'
      })
      .withShouldEndSession(true)
      .getResponse();
  }
};

リクエスタースキルをテストする

スキルをリクエスタースキルに変更したら、ほかの呼び出しのテストと同様にテストできます。リクエスタースキルがタスクリクエストを開始したら、Alexaは可能性のあるプロバイダーリストからタスクリクエストに最適なプロバイダーを選択し、選択された公開中のプロバイダースキルにAlexaサービスがリクエストをルーティングします。

さらに、リクエスタースキルでRESUME_SESSIONを指定する場合、受け取る可能性のあるさまざまなステータスコードの処理方法もテストする必要があります。特定のステータスコードのSessionResumedRequestを受け取ったときにスキルがどう応答するかをテストするには、AMAZON.TestStatusCodeタスクを定義したConnections.StartConnectionディレクティブを返すようリクエスタースキルを変更します。このディレクティブが返される応答の本文には、inputにテスト対象のステータスコードが含まれます。

例:SessionResumedRequestハンドラーが404ステータスコードを処理する方法をテストする

SessionResumedRequestハンドラーが404のステータスコードを受け取った場合の処理方法をテストするには、スキルが以下のディレクティブを返す必要があります。

return handlerInput.responseBuilder
        .addDirective({
            'type': 'Connections.StartConnection',
            'uri': 'connection://AMAZON.TestStatusCode/1',
            'input': {
                'code': '404'
            }
        })
        .getResponse();

その後、リクエスタースキルは、inputで定義されたステータスコードを含むSessionResumedRequestオブジェクトを受け取ります。

{
    "type": "SessionResumedRequest",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "cause": {
        "type": "ConnectionCompleted",
        "status": {
            "code": "404",
            "message": "ステータスコードのテストに成功しました"
        }
    }
}

リクエスタースキルを公開する

リクエスタースキルの認定要件は、リクエスター以外のスキルの要件と同じです。

リクエスタースキルをまだ公開していない場合は、通常どおりテストしてスキル申請の要件を満たしてから、スキルの認定を申請します。Amazonがそのスキルを認定すると、そのスキルは一般に公開され、リクエスタースキルとして機能するようになります。Amazonで既に認定されているスキルを後からリクエスタースキルに変更する場合は、開発者がそのスキルを公開すると、変更が一般に公開されます。

Alexaスキルを公開する方法の詳細については、スキルの認定と公開を参照してください。

開発者サポート

問い合わせやサポートについては、Skill Connectionsチームにお問い合わせください。メールアドレスは、skill-connections-v2-beta@amazon.comです。