Modelo de Ação Universal

Contexto

Os Cartões Adaptáveis são snippets da interface do usuário independentes de plataforma, criados usando um formato JSON leve, que os aplicativos e serviços podem compartilhar. Os Cartões Adaptáveis não só se adaptam à aparência do host, mas também oferecem funcionalidades avançadas de interação. Para obter mais informações sobre os Cartões Adaptáveis, visite adaptivecards.io.

Como a popularidade dos Cartões Adaptáveis cresceu, hosts diferentes começaram a dar suporte a modelos de ação diferentes e isso levou a uma fragmentação. Para resolver esse problema, as equipes do Teams, do Outlook e dos Cartões Adaptáveis trabalharam na criação de um modelo de ação de bot universal compatível entre hosts. Esse esforço levou ao seguinte:

  • A generalização dos Bots e do Bot Framework como a maneira de implementar cenários adaptáveis baseados em cartão tanto para o Teams (Bots) quanto para o Outlook (Mensagem Acionável)
  • Action.Execute como uma substituição tanto para Action.Submit (atualmente usados por Bots) quanto para Action.Http (atualmente usado por Mensagens Acionáveis)
  • Recursos populares compatíveis apenas com Mensagens Acionáveis disponibilizados para Bots, especificamente:
    • A capacidade de um cartão ser atualizado no momento em que é exibido
    • A capacidade de ações Action.Execute de retornarem um cartão atualizado para ser exibido imediatamente no cliente

Para obter mais informações sobre Mensagens Acionáveis no Outlook, confira a documentação das Mensagens Acionáveis

Para obter detalhes sobre diferentes cenários possíveis com Ações Universais no Teams, confira a Referência de cartões do Teams.

Antes de Action.Execute Com Action.Execute
An image depicting the current inconsistent model in Teams and Outlook An image depicting the consistent model that is enabled with Action.Execute in Teams and Outlook
An image showing how Adaptive Card JSONs look like with current inconsistent model An image showing how Adaptive Card JSONs would look the same with new Action.Execute based model

Fonte: Cartões Adaptáveis @ Microsoft Build 2020

O restante deste documento se concentra em documentar o modelo de ação de Bot universal no contexto do Teams e do Outlook. Se você já estiver usando os Cartões Adaptáveis no Teams com o Bot, poderá usar o mesmo Bot com algumas alterações para dar suporte a Action.Execute. Se você estiver usando as Mensagens Acionáveis no Outlook, precisará desenvolver um Bot com suporte a Action.Execute. Atualmente, o suporte em clientes do Outlook para modelos de ação de Bot universal está em desenvolvimento ativo.

Esquema

IMPORTANTE

O modelo de ação de Bot universal é introduzido no esquema de Cartões Adaptáveis versão 1.4. Para usar essas novas funcionalidades, a propriedade version do Cartão Adaptável precisa ser definida como 1.4 ou superior, conforme mostrado nos exemplos abaixo. Observe que isso tornará seu Cartão Adaptável incompatível com clientes mais antigos (Outlook ou Teams) que não dão suporte ao modelo de ação de Bot universal.

Se você usar a propriedade refresh e/ou Action.Execute e especificar uma versão do cartão < 1.4, ocorrerá o seguinte:

Cliente Comportamental
Outlook O cartão NÃO funcionará. refresh não será cumprido e Action.Execute não será renderizado. Seu cartão pode até ser completamente rejeitado.
Teams O cartão talvez não funcione (o refresh pode não ser cumprido e as ações Action.Execute podem não ser renderizadas) dependendo da versão do cliente do Teams.

Para garantir a compatibilidade máxima no Teams, considere definir suas ações Action.Execute com uma ação Action.Submit na propriedade fallback.

Confira a seção de Compatibilidade com versões anteriores abaixo para obter mais informações.

Action.Execute

Ao criar Cartões Adaptáveis, use Action.Execute no lugar de Action.Submit e de Action.Http. O esquema para Action.Execute é bastante semelhante ao de Action.Submit.

JSON de exemplo

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "TextBlock",
      "text": "Present a form and submit it back to the originator"
    },
    {
      "type": "Input.Text",
      "id": "firstName",
      "placeholder": "What is your first name?"
    },
    {
      "type": "Input.Text",
      "id": "lastName",
      "placeholder": "What is your last name?"
    },
    {
      "type": "ActionSet",
      "actions": [
        {
          "type": "Action.Execute",
          "title": "Submit",
          "verb": "personalDetailsFormSubmit",
          "fallback": "Action.Submit"
        }
      ]
    }
  ]
}

Propriedades

Propriedade Type Obrigatória Descrição
tipo "Action.Execute" Sim Deve ser "Action.Execute".
verbo string Não Uma cadeia de caracteres de conveniência que pode ser usada pelo desenvolvedor para identificar a ação
data string, object Não Dados iniciais com os quais os campos de entrada serão combinados. Essas são propriedades essencialmente 'ocultas'.
title string Não Rótulo para um botão ou link que representa esta ação.
iconUrl uri Não Ícone opcional a ser mostrado na ação em conjunto com o título. Dá suporte a um URI de dados nos Cartões Adaptáveis versão 1.2 ou posterior
style ActionStyle Não Controla o estilo de uma Ação, que influencia a forma como a ação é exibida, falada etc.
fallback <action object>, "drop" Não Descreve o que fazer quando Action.Execute não é compatível com o cliente que está exibindo o cartão.
requires Dictionary<string> Não Uma série de pares chave/valor que indica os recursos que o item exige com a versão mínima correspondente. Quando um recurso está ausente ou é de uma versão insuficiente, o fallback é disparado.

Mecanismo de atualização

Juntamente com Action.Execute, agora há suporte para um novo mecanismo de atualização, possibilitando a criação de Cartões Adaptáveis que são atualizados automaticamente no momento em que são exibidos. Isso garante que os usuários sempre vejam dados atualizados. Um caso típico de uso da atualização é uma solicitação de aprovação: uma vez que ela foi aprovada, é melhor que não seja apresentado aos usuários nenhum cartão solicitando que eles aprovem (o que já foi feito), mas, em vez disso, que sejam fornecidas a eles informações sobre a hora em que a solicitação foi aprovada e por quem.

Para permitir que um Cartão Adaptável seja atualizado automaticamente, defina a propriedade refresh dele, que incorpora uma action do tipo Action.Execute, bem como uma matriz de userIds.

Propriedade Type Obrigatória Descrição
action "Action.Execute" Sim Precisa ser uma instância de ação do tipo "Action.Execute".
userIds Array<string> Sim Uma matriz de MRIs de usuários para os quais a Atualização Automática precisa ser habilitada.

IMPORTANTE: se a propriedade da lista userIds não estiver incluída na seção refresh do cartão, o cartão NÃO será atualizado automaticamente na exibição. Em vez disso, um botão será apresentado ao usuário para permitir que ele seja atualizado manualmente. O motivo disso é que os canais/chats no Teams podem incluir um número grande de membros. Se muitos membros estivessem exibindo o canal simultaneamente, a atualização automática incondicional resultaria em muitas chamadas simultâneas para o bot, que não escalaria. Para mitigar o possível problema de escala, a propriedade userIds sempre deve ser incluída para identificar quais usuários devem obter uma atualização automática, sendo que um máximo de 60 IDs de usuário são permitidas atualmente. Confira userIds na atualização para obter mais detalhes.

Observe que a propriedade userIds é ignorada no Outlook e que a propriedade refresh é sempre cumprida automaticamente. Não há nenhum problema de escala no Outlook, pois os usuários normalmente exibirão o cartão em momentos diferentes.

JSON de exemplo

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "originator":"c9b4352b-a76b-43b9-88ff-80edddaa243b",
  "version": "1.4",
  "refresh": {
    "action": {
      "type": "Action.Execute",
      "title": "Submit",
      "verb": "personalDetailsCardRefresh"
    },
    "userIds": []
  },
  "body": [
    {
      "type": "TextBlock",
      "text": "Present a form and submit it back to the originator"
    },
    {
      "type": "Input.Text",
      "id": "firstName",
      "placeholder": "What is your first name?"
    },
    {
      "type": "Input.Text",
      "id": "lastName",
      "placeholder": "What is your last name?"
    },
    { 
      "type": "ActionSet",
      "actions": [
        {
          "type": "Action.Execute",
          "title": "Submit",
          "verb": "personalDetailsFormSubmit",
          "fallback": "Action.Submit"
        }
      ]
    }
  ]
}

Observação importante para desenvolvedores de Mensagens Acionáveis do Outlook

Quando você desenvolver cenários mensagens acionáveis do Outlook, será necessário especificar a propriedade originator do Cartão Adaptável. originator é um GUID (identificador global exclusivo) gerado no momento em que um Bot assina o canal do Outlook. Ele é usado pelo Outlook para validar que o Cartão Adaptável foi enviado por um Bot autorizado. O Cartão Adaptável não será renderizado no Outlook se originator estiver ausente. O originator foi ignorado no Teams.

Atividade de invocação adaptiveCard/action

Quando um Action.Execute é executado no cliente (seja a ação de atualização ou uma ação explicitamente realizada por um usuário clicando em um botão), um novo tipo de atividade de invocação (adaptiveCard/action) é feita ao Bot. Uma solicitação de atividade de invocação típica adaptiveCard/action será semelhante ao seguinte:

Formato de solicitação

{ 
  "type": "invoke",
  "name": "adaptiveCard/action",

  // ... other properties omitted for brevity

  "value": { 
    "action": { 
      "type": "Action.Execute", 
      "id": "abc", 
      "verb": "def",
      "data": { ... } 
    },
    "trigger": "automatic | manual" 
  }
} 
Campo Descrição
value.action Uma cópia da ação, conforme definido no Cartão Adaptável. Assim como com Action.Submit, a propriedade data da ação inclui os valores das várias entradas no cartão, se houver alguma
value.trigger Indica se a ação foi disparada explicitamente (pelo usuário, clicando em um botão) ou implicitamente (por meio de atualização automática)

Formato de resposta

Se o Bot tiver processado uma atividade de invocação de entrada adaptiveCard/action (ou seja, se o código do Bot tiver estado envolvido de alguma maneira no processamento da solicitação), o código de status da resposta HTTP retornado pelo bot precisará ser igual a 200 e o corpo da resposta HTTP precisará estar formatado da seguinte maneira:

{ 
    "statusCode": <number (200 – 599)>, 
    "type": "<string>", 
    "value": "<object>"
} 
Campo Descrição
statusCode Um código de status de resposta HTTP igual a 200 não significa necessariamente que o bot foi capaz de processar com êxito a solicitação. Um aplicativo cliente PRECISA sempre examinar a propriedade statucCode no corpo da resposta para saber como o Bot processou a solicitação. statusCode é um número que varia de 200 a 599 que espelha valores de código de status HTTP e deve ser um substatus para o resultado do bot que processa a invocação. Um valor ausente, nulo ou indefinido para statusCode implica em um valor de 200 (Êxito).
tipo Um conjunto de constantes de cadeia de caracteres bem conhecidas que descrevem a forma esperada da propriedade value
value Um objeto que é específico do tipo de corpo da resposta

Códigos de status compatíveis

A seguinte tabela lista os valores permitidos para statusCode, type e value no corpo da resposta do Bot:

Código do Status Tipo Esquema de valor Observações
200 application/vnd.microsoft.card.adaptive Adaptive Card A solicitação foi processada com êxito e a resposta inclui um Cartão Adaptável que o cliente deve exibir no lugar do atual.
200 application/vnd.microsoft.activity.message string A solicitação foi processada com êxito e a resposta inclui uma mensagem que o cliente deve exibir.
400 application/vnd.microsoft.error Objeto de erro (TODO: precisa de link) A solicitação de entrada era inválida.
401 application/vnd.microsoft.activity.loginRequest OAuthCard (TODO: precisa de link) O cliente precisa solicitar que o usuário se autentique.
401 application/vnd.microsoft.error.inccorectAuthCode nulo O estado de autenticação passado pelo cliente era incorreto e a autenticação falhou.
412 application/vnd.microsoft.error.preconditionFailed Objeto de erro (TODO: precisa de link) Falha no fluxo de autenticação de SSO.
500 application/vnd.microsoft.error Objeto de erro (TODO: precisa de link) Erro inesperado.

Resumo: como aproveitar o modelo de ação de Bot universal

  1. Use Action.Execute em vez de Action.Submit. Para atualizar um cenário existente no Teams, substitua todas as instâncias de Action.Submit por Action.Execute. Para atualizar um cenário existente no Outlook, confira a seção de compatibilidade com versões anteriores mostrada abaixo.
  2. Para que os cartões apareçam no Outlook, adicione o campo originator. Confira o JSON de exemplo acima.
  3. Adicione uma cláusula refresh ao Cartão Adaptável se você desejar aproveitar o mecanismo de atualização automática ou se seu cenário exigir exibições específicas do usuário. Não deixe de especificar a propriedade userIds para identificar quais usuários (no máximo 60) receberão atualizações automáticas.
  4. Manipular solicitações de invocação adaptiveCard/action em seu Bot
  5. Sempre que o Bot precisar retornar um novo cartão como resultado do processamento de uma Action.Execute, você poderá usar o contexto da solicitação de invocação para gerar cartões criados especificamente para um determinado usuário. Verifique se a resposta está em conformidade com o esquema de resposta definido acima.

Compatibilidade com versões anteriores

Outlook

O novo modelo de ação universal Action.Execute é uma partida do modelo de ação Action.Http usado atualmente pelas Mensagens Acionáveis do Outlook, nas quais as ações são codificadas no Cartão Adaptável como chamadas HTTP explícitas. O modelo Action.Execute possibilita que os desenvolvedores implementem cenários que "simplesmente funcionam" no Outlook e no Teams. Cenários de Mensagens Acionáveis podem usar o modelo Action.Http ou o novo modelo Action.Execute, mas não ambos. Os cenários que usam o modelo universal Action.Execute precisam ser implementados como bots e assinar o canal Outlook Actionable Messages.

Observações importantes

  • Cenários implementados usando o modelo universal Action.Execute não serão compatíveis com versões mais antigas do Outlook
  • Há trabalho em andamento para permitir que cenários de Mensagens Acionáveis existentes migrem diretamente para o modelo universal Action.Execute

Teams

Para que seus cartões sejam compatíveis com versões anteriores e trabalhem para usuários em versões mais antigas do Teams, suas ações Action.Execute devem incluir uma propriedade fallback definida como uma Action.Submit. O bot deve ser codificado de modo que possa processar Action.Execute e Action.Submit. Observe que não é possível que o bot retorne um novo cartão ao processar uma Action.Submit, de modo que o comportamento de fallback via Action.Submit fornecerá uma experiência degradada para o usuário final.

Observação importante

Alguns clientes mais antigos do Teams não dão suporte à propriedade fallback quando não são encapsulados em um ActionSet. Para não interromper esses clientes, é altamente recomendável que você encapsule todos os Action.Execute em ActionSet. Confira o exemplo abaixo de como encapsular Action.Execute em ActionSet.

No exemplo abaixo, observe que a propriedade version do cartão está definida como 1.2 e a Action.Execute está definida com um Action.Submit como o fallback dela. Quando o Action.Execute for renderizado em um cliente do Teams que dá suporte aos Cartões Adaptáveis 1.4, ele será renderizado e funcionará conforme o esperado. Em clientes do Teams que não dão suporte aos Cartões Adaptáveis 1.4, o Action.Submit será renderizado no lugar do Action.Execute.

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.2",
  "body": [
    {
      "type": "TextBlock",
      "text": "Present a form and submit it back to the originator"
    },
    {
      "type": "Input.Text",
      "id": "firstName",
      "placeholder": "What is your first name?"
    },
    {
      "type": "Input.Text",
      "id": "lastName",
      "placeholder": "What is your last name?"
    },
    {
      "type": "ActionSet",
      "actions": [
        {
          "type": "Action.Execute",
          "title": "Submit",
          "verb": "personalDetailsFormSubmit",
          "fallback": {
            "type": "Action.Submit",
            "title": "Submit"
          }  
        }
      ]
    }
  ]
}

Referências