Files

12 KiB
Raw Permalink Blame History

Secretária Virtual — Roadmap Completo (Opção 3 Híbrida)

Arquitetura Alvo

Plugin Alemão (satélite)                      Motor NewWhats
┌──────────────────────────────┐              ┌──────────────────────────────┐
│  webhook-receiver.js         │   POST ask   │  ProtocolEngine (brain.ts)   │
│  └─ context-builder.js       │ ───────────► │  system prompt dinâmico      │
│     └─ DB local (clientes,   │              │  histórico + summarização     │
│        planos, promoções)    │ ◄─────────── │  fallback chain AI providers │
│                              │    reply     │  sec_conversations/messages   │
│  HandoffButton (UI)          │              │                              │
│  └─ per-chat mode:           │  PATCH mode  │  chat_handoff_mode           │
│     ia | humano | pausado    │ ───────────► │  (campo por conversa)        │
└──────────────────────────────┘              └──────────────────────────────┘

LEGENDA DE STATUS

  • Implementado e funcionando
  • 🔲 Pendente — não iniciado
  • 🚧 Parcialmente feito

BLOCO 1 — Handoff Humano ↔ IA (Botão Flutuante)

Botão flutuante acima do input bar no chat. Um clique pausa a IA e o humano assume. Outro clique devolve o controle à IA. Se o humano ficar 15 min sem responder (ou a conexão cair), a IA reassume automaticamente.

1.1 — Motor: campo de modo por conversa

  • 🔲 Adicionar coluna handoff_mode ENUM(ia, humano, pausado) DEFAULT ia na tabela sec_conversations (migration Knex)
  • 🔲 Adicionar coluna handoff_human_at TIMESTAMP NULL na tabela sec_conversations (registra quando humano assumiu)
  • 🔲 Rodar migration no motor (plugins/secretaria/migrate.ts)

1.2 — Motor: rotas de handoff (ext-api)

  • 🔲 Criar PATCH /ext/v1/sec/conversations/:id/handoff — body { mode: 'ia'|'humano' } — atualiza handoff_mode e handoff_human_at
  • 🔲 Em POST /ext/v1/secretaria/ask — verificar handoff_mode antes de chamar brain: se humano, retornar { skipped: true } sem chamar IA

1.3 — Motor: timer de retomada automática (15 min)

  • 🔲 Criar job BullMQ handoff-timeout no motor: ao mudar para modo humano, enfileirar job com delay de 15 min
  • 🔲 Job verifica se handoff_mode ainda é humano E handoff_human_at há mais de 15 min → muda para ia → emite evento WebSocket conversation.handoff para o satélite
  • 🔲 Ao receber mensagem humana (PATCH /handoff mode=humano), cancelar job anterior e enfileirar novo (reset do timer)
  • 🔲 Se conexão WS do satélite cair (disconnect), mudar todas as conversas desse satélite em modo humano para ia automaticamente

1.4 — Frontend: NwService métodos

  • 🔲 Adicionar NwService.getHandoffMode(chatId)GET /nw/v1/sec/conversations/:id/handoff (ou campo incluso no chat)
  • 🔲 Adicionar NwService.setHandoffMode(chatId, mode)PATCH /nw/v1/sec/conversations/:id/handoff

1.5 — Frontend: HandoffButton component (WhatsAppInbox.tsx)

  • 🔲 Criar componente HandoffButton — botão flutuante posicionado absolute bottom-[72px] right-4 z-20
  • 🔲 Estado local handoffMode: 'ia' | 'humano' por chat — carrega ao abrir o chat
  • 🔲 Visual quando modo ia: ícone Bot verde com tooltip "IA respondendo — clique para assumir"
  • 🔲 Visual quando modo humano: ícone UserCheck laranja pulsando com tooltip "Você está respondendo — clique para devolver à IA" + contador regressivo de 15 min
  • 🔲 Ao clicar: chama NwService.setHandoffMode, atualiza estado local otimisticamente
  • 🔲 Mostrar o botão apenas se sessão CONNECTED e chat selecionado
  • 🔲 Esconder o botão se auto-reply mode = off (secretária desligada globalmente)

1.6 — Frontend: exibição visual no chat

  • 🔲 Injetar mensagem de sistema no fluxo de mensagens ao mudar de modo: "🤖 IA assumiu o atendimento" / "👤 Atendente humano assumiu"
  • 🔲 Header do chat mostrar badge discreto: IA (verde) ou Humano (laranja)

1.7 — Frontend: retomada automática via WebSocket

  • 🔲 Escutar evento WS conversation.handoff → atualizar handoffMode local sem recarregar a página
  • 🔲 Exibir toast "Secretária retomou o atendimento automaticamente (15 min sem resposta)"

1.8 — Motor: emitir evento WS ao retomar

  • 🔲 Após job BullMQ retomar modo ia, emitir via WS { event: 'conversation.handoff', data: { chatId, mode: 'ia', reason: 'timeout' } } para o satélite correto

1.9 — Webhook receiver: respeitar handoff

  • 🔲 Em webhook-receiver.js, antes de chamar /secretaria/ask, consultar modo da conversa
  • 🔲 Se modo humano → não chamar IA, apenas registrar mensagem recebida
  • 🔲 Resetar timer de 15 min ao detectar mensagem do atendente humano (mensagem fromMe: true)

BLOCO 2 — Injeção de Contexto Local (Opção 3 Híbrida)

Hoje a secretária fica cega ao DB do projeto. O plugin precisa enriquecer cada chamada ao motor com dados reais do cliente.

2.1 — Motor: ampliar brain.chat() para aceitar contexto

  • 🔲 Modificar brain.tschat(convId, message, opts?: { contextData?: object; systemExtra?: string })
  • 🔲 Serializar contextData como bloco de texto e appendar ao system prompt antes da chamada à IA
  • 🔲 Modificar POST /ext/v1/secretaria/ask → extrair context e system_prompt_extra do body e repassar ao brain

2.2 — Plugin: criar context-builder.js

  • 🔲 Criar sistema-nuvem/plugins/newwhats/context-builder.js
  • 🔲 Implementar buildContext(phone):
    • Buscar cliente pelo telefone no DB alemão (tabela users ou clients)
    • Buscar status de assinatura do clube
    • Buscar último pedido / histórico recente (últimos 3)
    • Buscar promoções ativas do dia
    • Buscar vagas abertas (caso relevante)
  • 🔲 Retornar objeto { cliente, plano, ultimos_pedidos, promocoes_ativas }

2.3 — Plugin: webhook-receiver usa context-builder

  • 🔲 Modificar webhook-receiver.js: extrair número do remetente de data.from
  • 🔲 Chamar context-builder.js com o número antes de chamar /secretaria/ask
  • 🔲 Enviar context e system_prompt_extra no payload do ask

BLOCO 3 — Tool Calling (IA que age, não só fala)

Sem tools, a IA só gera texto. Com tools ela pode agendar, buscar e escalar.

3.1 — Motor: suporte a tools no ProtocolEngine

  • Criado plugins/secretaria/tools.ts com interface ToolDef { name, description, parameters, execute() }
  • Tools implementadas: listar_horarios, agendar_horario, escalar_humano, encerrar_protocolo
  • brain.chat() aceita tools?: string[] — resolve via resolveTools() e habilita tool calling
  • Loop de tool calling por provider: OpenAI (tool_calls), Anthropic (tool_use), Gemini (functionCall) — máx 5 iterações
  • Fallback gracioso: se nenhum provider com tools disponível, usa modo texto normal
  • POST /ext/v1/secretaria/ask aceita tools: string[] e repassa ao brain com hooks + tenantId

3.2 — Plugin: integração com tools do motor

  • webhook-receiver.js inclui tools: ['listar_horarios', 'agendar_horario', 'escalar_humano', 'encerrar_protocolo'] no payload do ask
  • escalar_humano aciona handoff_mode=humano + emite ext:handoff via HookBus → chega ao frontend via WS
  • buscar_cliente / verificar_plano resolvidos via context-builder.js (Bloco 2) — contexto pré-computado injetado no system prompt, não como tool call (mais simples e confiável)

BLOCO 4 — Painel Admin: Melhorias

4.1 — Visualização de conversa

  • Sub-tab Conversas: clicar em protocolo abre drawer lateral com todas as mensagens
  • Botão "Finalizar protocolo" no drawer → POST /sec/conversations/:id/finalize
  • Badge visual em conversas com handoff_mode = humano (ícone laranja)
  • Badge visual em conversas escaladas (status = escalated)

4.2 — Chat de teste inline

  • Sub-tab "Testar" no painel Secretária: campo de texto + botão enviar
  • Chama /secretaria/ask com um chatId de teste fictício e exibe resposta
  • Útil para testar prompts sem precisar de celular conectado

4.3 — Segurança das API Keys

  • GET /ext/v1/sec/keys mascarar valores: sk-...**** (mostrar só prefixo + últimos 4 chars)
  • Campo de senha no painel com placeholder •••••••• quando já salvo

BLOCO 5 — Escalação Real

5.1 — Detecção e notificação

  • Motor: escalar_humano tool emite ext:escalated com protocolNumber + motivo
  • Motor: ws-bridge encaminha ext:escalatedconversation.escalated ao satélite
  • Motor: listener em buildExtRoutes envia WA ao admin_notify_phone configurado
  • Motor: GET/PUT /sec/keys inclui admin_notify_phone (em claro, não mascarado)
  • Painel: toast laranja ⚠️ Escalação ao receber conversation.escalated via WS
  • Painel: badge "Escalada" vermelho nas conversas (implementado no Bloco 4)
  • Painel: campo "WhatsApp do administrador" na aba Config

RESUMO PRIORIZADO

# Bloco Tarefa Impacto Esforço
1 Handoff Migration: handoff_mode + handoff_human_at 🔴 Crítico Trivial
2 Handoff PATCH /sec/conversations/:id/handoff + skip no ask 🔴 Crítico Pequeno
3 Handoff HandoffButton React component 🔴 Crítico Pequeno
4 Handoff Timer 15 min via BullMQ + retomada automática 🔴 Crítico Médio
5 Handoff Evento WS conversation.handoff 🟠 Alto Pequeno
6 Handoff Webhook-receiver respeitar modo humano 🟠 Alto Pequeno
7 Contexto context-builder.js no plugin 🔴 Crítico Médio
8 Contexto Motor aceitar context no brain.chat() 🔴 Crítico Pequeno
9 Contexto Webhook receiver enviar contexto no ask 🟠 Alto Pequeno
10 Painel Visualizar mensagens do protocolo + finalizar 🟡 Médio Pequeno
11 Painel Mascarar API keys 🟡 Médio Trivial
12 Tools Tool calling no ProtocolEngine 🟠 Alto Grande
13 Tools Tools locais no plugin (buscar_cliente, etc.) 🟠 Alto Médio
14 Escalação Notificação real ao admin + handoff automático 🟡 Médio Médio
15 Painel Chat de teste inline 🟢 Baixo Pequeno

FLUXO ALVO COMPLETO

Mensagem recebida no WA
  │
  ▼
webhook-receiver.js
  ├─ extrai phone do remetente
  ├─ context-builder.js → { cliente, plano, pedidos, promoções }
  ├─ verifica handoff_mode da conversa
  │    ├─ modo "humano" → não chama IA, reseta timer 15min, fim
  │    └─ modo "ia" → continua
  └─ POST /secretaria/ask { chatId, message, context, tools: [...] }
       │
       ▼
  Motor ProtocolEngine.chat()
       ├─ monta system prompt = persona + knowledge + rules + calendar + context_local
       ├─ chama IA com tool definitions
       │    ├─ IA chama tool → executa → retorna resultado → IA gera resposta
       │    └─ IA responde diretamente
       └─ retorna { reply, conversationId, protocolNumber }
            │
            ▼
       webhook-receiver.js envia reply via WA ao cliente

Humano clica HandoffButton
  ├─ PATCH /sec/conversations/:id/handoff { mode: "humano" }
  ├─ BullMQ enfileira job com delay 15min
  ├─ UI exibe badge laranja + contador regressivo
  └─ próximas mensagens WA → webhook ignora IA

15 min sem resposta humana (ou WS cai)
  ├─ BullMQ job dispara → mode = "ia"
  ├─ Motor emite WS conversation.handoff
  └─ UI atualiza badge → toast "Secretária retomou"