Estas últimas semanas estoy dedicando tiempo a crear un par de skills para Alexa que me están sirviendo para profundizar más y aprender temas nuevos. A partir de lo que aprendo elaboro un listado de posibles posts y los priorizo. Haciendo esto me he dado cuenta que hasta ahora no había hablado de algo esencial en una Alexa Skill y que sale mucho en errores de certificación: la skill session.

Aunque no tiene nada de complicado me viene bien contarlo aquí para luego enlazar otros temas: gestión del contexto, persistencia, recuperar información del usuario/dispositivo, contenido de una request/response, etc.

Skill Session

Request

Con la invocación de una skill por parte de un usuario se crea una session que viajará con la request al back. La estructura de esa request da para otro post pero veamos aquí la parte que corresponde a la session:

La info que tenemos en la session es:

  • Un flag new que nos indica si estamos creando la sesión en esta petición, valor a true, o ya estaba abierta, valor a false.
  • Un sessionId como identificador único de la sesión activa de un usuario. Es un valor consistente en cada petición siguiente con la sesión abierta.
  • Un objeto application que contiene información sobre la skill que crea la sesión. De esta forma se pueden hacer comprobaciones en back que la petición viene de la skill que se espera. Si alojas el back en AWS Lambda y conectas la función con un trigger de Alexa para tu skill se hará ese check de forma automática.
  • Un objeto user que tiene información sobre la cuenta que está usando la skill. Escribiré otro post sobre el uso del user y otro objeto en la request que es persona. Por el momento, como punto más importante, de aquí sacamos el userId que representa de forma única a la cuenta Amazon para la cual la skill está activa. Veremos el uso y otros detalles de este userId en otros posts.

El envío de la info de sesión va con cada request al back con la sesión abierta pero con el flag de new a false.

Response

Una vez se procese la petición en el back se envía una response a Alexa. Uno de los parámetros de esa respuesta es el flag shouldEndSession de cuyo valor dependerá lo que pase a continuación:

true > La sesión finaliza de forma que la skill termina de ejecutarse. A partir de ahí cualquier petición la manejará Alexa. Cuidado con el cierre de sesión en skills con APL ya que la skill se cierra y si el usuario tenía que leer algo por pantalla no podrá. Es un defecto habitual que se detecta también en certificación.

false > Alexa queda a la espera de una respuesta manteniendo la sesión y el micrófono abiertos. Se pueden dar a su vez varias posibilidades:

  • Si el usuario dice algo que corresponda a un intent de la skill se genera la request correspondiente hacía el back. En esa petición la sesión ya llevará el flag new a false.
  • Si el usuario no dice nada en un tiempo determinado se cierra el micro. En el caso de que la response llevara un reprompt se vuelve a abrir el micro unos segundos más.
  • Una vez que el usuario ya no responde más y se cierra el micro, es posible que la sesión quede abierta por un periodo corto de tiempo. Este es el caso en dispositivos con pantalla donde el usuario aún puede interactuar con la skill ya que la sesión se mantiene abierta por un rato con el micro cerrado. Para ello tendría que realizar la petición despertando primero a Alexa. Esta petición iría directa a la skill sin tener que invocarla. En el caso de otros dispositivos la sesión finalizaría.

undefined/null > Aquí el comportamiento depende del tipo de dispositivo o de la respuesta. En la documentación oficial cuentan las variantes.

La sesión y el proceso de certificación

Uno de los problemas más comunes que reportan en el proceso de certificación es el manejo incorrecto de la sesión de la skill. En concreto de la decisión que toma el desarrollador para dejar abierta o cerrar la sesión en la respuesta de un Intent.

Cuando estás creando las respuestas para el usuario debes pensar si tras esa interacción esperas otra a continuación. Por ejemplo, en el caso de mi skill de Estrenos de Cine tengo ambas situaciones:

  • El usuario pregunta por los estrenos de esta semana y tengo respuesta de estrenos desde la API. Informo al usuario de las películas y, desde back, indico que quiero que se cierre la sesión luego. No espero otra interacción una vez que le he dado al usuario lo que pedía.
  • El usuario pregunta por los estrenos de esta semana pero la API no me retorna ninguno. Lo que hago en ese caso es mandarle al usuario una pregunta, ya que no tengo los estrenos, si quiere conocer la cartelera actual. O, aunque no se lo indique, también podría preguntar por otra fecha, no es una ejecución lineal. En este caso, en la respuesta de back, indico que quiero que la sesión se quede abierta.

En este código podemos ver ambos casos enviando un shouldEndSession en la respuesta:

Si por ejemplo hubiéramos cerrado la sesión en el segundo escenario, nos lo hubieran detectado como error en el proceso de certificación. Le estamos haciendo una pregunta al usuario pero luego cerramos la sesión, con lo cual la respuesta no la va a manejar la skill sino Alexa.

Esto también suele pasar cuando manejamos el Intent de Amazon.HelpIntent donde, habitualmente, lo que esperamos luego es una interacción por parte del usuario.

Igualmente saber cuándo dejar la sesión abierta o no, afecta mucho a la experiencia de usuario final. Podemos llegar a crear una skill que acabe siendo muy pesada esperando siempre respuestas a interacciones que se podrían finalizar de una sola vez.

Para skills con APL, como decía en la primera parte del post, hay que tener cuidado con cerrar la sesión desde el back. En mi skill de Estrenos de Cine estaba cerrando la sesión con la respuesta y esto producía que un usuario no pudiera leer los estrenos de cine por pantalla. Se cerraba la skill al terminar la salida de audio, mostrando el listado, pero se cerraba enseguida.

SessionEndedRequest

Hay un tema que no había visto documentado en mis primeros procesos de certificación y que descubrí cuando me lo detectaron como fallo. No tenía contemplado una SessionEndedRequest a mi back.

Una SessionEndedRequest es una petición que Alexa hace al back de una skill para indicar que una sesión finalizó. Esta petición se produce si:

  • El usuario dice utterances como "salir" o "quitar".
  • El usuario no responde o dice algo que no corresponde a ningún Intent definido en el modelo.
  • Se produce un error.

Como dato curioso, una respuesta a esta petición debe ser vacía:

Hay otras formas de manejar situaciones que envían esta request, como el FallbackIntent o registrar un ErrorHandler y lo veremos en otro post.

Nota: si es la skill, indicado por back, quien decide finalizar la sesión con el flag shouldEndSession a true no habrá esa SessionEndedRequest.


Un punto que no comento, porque no se ve en la sesión de ejemplo que pongo arriba, es el tema de los atributos de sesión. Ese será mi siguiente post y el motivo inicial de haber escrito este primero :)