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.
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/falseIdentificaçã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ção | Parâmetros | Permissão exigida |
|---|---|---|
| cadastrar_animal | ear_tag, breed, sex, property (opcional) | rebanho:write · perfil fazenda |
| registrar_peso | ear_tag, weight | rebanho:write · perfil fazenda |
| registrar_vacina | ear_tag, vaccine_name, cost (opcional) | rebanho:write · perfil fazenda |
| registrar_movimento | ear_tag, movement_type, value (opcional) | rebanho:write · perfil fazenda |
| cadastrar_servico_ordem | client_name, service_name, quantity | prestador:write · perfil prestador |
| consultar_saldo | period (opcional, default mês atual) | financeiro:read |
| consultar_animal | ear_tag | rebanho:read · perfil fazenda |
| consultar_cliente | client_name | prestador:read · perfil prestador |
| gerar_relatorio | tipo (financeiro|rebanho|lavoura|prestador), period | varia pelo tipo: só financeiro tem PDF pronto |
| ambigua | nenhum | sem 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.