Agente WhatsApp

O agente permite cadastrar e consultar dados do Tibé por mensagem de texto livre no WhatsApp. O Tibé nunca fala diretamente com a Meta Cloud API: o N8N é o único intermediário nos dois sentidos.

Status de infraestrutura: o código deste módulo está completo e testado, mas a infra externa (número Salvy, Meta Business Manager, workflow N8N em produção) ainda não foi provisionada. Os endpoints abaixo funcionam e podem ser chamados diretamente para teste.

Fluxo completo

1. Usuário manda mensagem no WhatsApp
2. Meta Cloud API entrega o evento ao webhook configurado no N8N
3. N8N normaliza o payload e chama:
     POST /api/internal/whatsapp/resolve-contact  { phone }
   → identifica tenant_id, user_id, role e os perfis ativos
4. N8N chama a API do LLM, enviando:
     - a mensagem do usuário
     - o contexto do tenant (perfis ativos)
     - meta.recent_history (últimas 5 interações, já devolvidas pelo passo 3)
     - a definição das 10 intenções suportadas
5. O LLM classifica a intenção e extrai os parâmetros
6. N8N chama:
     POST /api/internal/whatsapp/execute-action  { tenant_id, user_id, intent, parameters }
   → o Tibé executa a ação (ou pede um dado faltante, ou pede confirmação)
7. N8N envia reply_text de volta ao usuário via Meta Cloud API
8. Se a ação exigia confirmação, o próximo "sim"/"não" do usuário volta ao passo 4,
   e o N8N deve reenviar a MESMA intenção+parâmetros com confirmed: true/false

Identificação de contato

resolve-contact é o único endpoint do sistema que legitimamente busca através de todos os tenants: ele ainda não sabe a quem o telefone pertence. Ele busca primeiro um WhatsAppContact já vinculado; se não existir, busca um User ativo com aquele telefone cadastrado em algum tenant e cria o vínculo na hora (esse é o first_contact). Se nenhum User tiver aquele telefone, devolve identified: false: o número simplesmente não pertence a ninguém no sistema, e nenhuma ação de escrita pode ser executada.

Intenções suportadas

IntençãoParâmetrosPermissão exigida
cadastrar_animalear_tag, breed, sex, property (opcional)rebanho:write · perfil fazenda
registrar_pesoear_tag, weightrebanho:write · perfil fazenda
registrar_vacinaear_tag, vaccine_name, cost (opcional)rebanho:write · perfil fazenda
registrar_movimentoear_tag, movement_type, value (opcional)rebanho:write · perfil fazenda
cadastrar_servico_ordemclient_name, service_name, quantityprestador:write · perfil prestador
consultar_saldoperiod (opcional, default mês atual)financeiro:read
consultar_animalear_tagrebanho:read · perfil fazenda
consultar_clienteclient_nameprestador:read · perfil prestador
gerar_relatoriotipo (financeiro|rebanho|lavoura|prestador), periodvaria pelo tipo: só financeiro tem PDF pronto
ambiguanenhumsem checagem: pede esclarecimento

Cada intenção roteia para a mesma função de lib/actions/* usada pelas rotas web equivalentes: não existe lógica de negócio duplicada para o canal WhatsApp. Se um parâmetro obrigatório está faltando (ex: cadastrar animal sem sexo) ou é ambíguo (ex: tenant com mais de uma propriedade e nenhuma especificada), o agente responde pedindo o dado faltante em vez de adivinhar ou falhar silenciosamente.

Confirmação para ações de alto valor

Venda/compra de animal e ordens de serviço acima de R$ 5.000 exigem confirmação explícita antes de persistir: o agente responde “Confirma a venda do animal 1234 por R$ 6.000,00? Responda ‘sim’ para confirmar” e devolve requires_confirmation: true junto com os parâmetros originais em auxiliary_data. O N8N deve reenviar a mesma intenção com confirmed: true quando o usuário concordar.

Como camada de segurança independente do LLM, o Tibé também interpreta “sim”/“não” a partir do texto bruto da mensagem (campo message_text), reconhecendo variações como “confirmo”, “isso mesmo”, “pode”, “cancela”, “errado”: mesmo que o N8N não tenha resolvido a confirmação sozinho.

Contexto de curto prazo

Toda mensagem recebida e toda resposta enviada são gravadas em AgentConversationLog. As últimas 5 interações de cada contato voltam em meta.recent_history na resposta de resolve-contact: é esse histórico que o N8N deve enviar ao LLM para manter continuidade de conversa (ex: entender “e o segundo?” depois de uma lista).

Relatórios pelo WhatsApp

gerar_relatorio com tipo: "financeiro" devolve um link assinado de PDF real (mesma função usada pelo botão “Exportar” do painel web). Os tipos rebanho, lavoura e prestador ainda respondem “não disponível”: não há gerador de PDF dedicado para eles ainda.