Núcleo desta mudança (separação por sessão):
- migrate.ts: sec_numbers.agent_id (FK→sec_agents, ON DELETE SET NULL) e
sec_calendar.instance_id, com índices (aditivo/idempotente).
- ext-api routes.ts: runtime resolve o agente pelo NÚMERO que recebeu a
mensagem (sec_numbers[instanceId].agent_id, fallback: 1º ativo); rotas
admin /secretaria/numbers e /secretaria/calendar aceitam os novos campos.
- brain.ts/tools.ts: instanceId no contexto; sec_calendar interno filtrado
por sessão; parse de jid robusto (.pop(), suporta 2 e 3 partes).
- secretaria/routes.ts: paridade (agent_id em numbers, instance_id no calendar).
Testado em dev (newwhats.dev refrescado): agentes resolvidos por instância;
fallback e FK ON DELETE SET NULL verificados via ext-api.
Obs.: por estarem no mesmo working tree não-commitado do newwhats.local,
ext-api/routes.ts e secretaria/tools.ts também trazem o trabalho acumulado
da integração do satélite (ações de inbox: delete/react/typing/labels/forward
e admin /secretaria/*; tools identificar_numero/cadastrar_paciente do odonto).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A secretária passa a "lembrar" do cliente entre conversas:
- tabela sec_contact_memory (fato + embedding JSON), chave = ext_chat_id/contact_name.
- na sumarização (a cada ~10 trocas) extrai fatos duradouros do cliente via LLM
e salva com embedding + dedup por similaridade (>0.92).
- buildSystemPrompt injeta "MEMÓRIA DO CLIENTE" com os fatos mais relevantes à
pergunta (cosseno); sem chave de embedding usa os mais recentes; tudo com
fallback silencioso (não regride).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adiciona busca semântica na Base de Conhecimento da secretária:
- embeddings.ts: chunking, embed (OpenAI text-embedding-3-small ou Gemini
text-embedding-004) e similaridade cosseno — tudo na aplicação, sem pgvector.
- tabela sec_knowledge_chunks (vetor em JSON/text) com índices.
- brain.ts: no nó 'knowledge', injeta só os top-4 trechos relevantes à pergunta
do usuário; indexação lazy por hash do conteúdo. Fallback para o conteúdo
inteiro se não houver chave de embedding ou em qualquer falha (não regride).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
O createTable de sec_messages não tinha usage_tokens/provider_used/model_used,
mas brain.ts insere esses campos — quebrando com "column does not exist" em
qualquer banco criado antes dessas colunas (ex.: clones). Adiciona as colunas
ao createTable e um bloco idempotente hasColumn/alterTable (padrão já usado no
arquivo) que garante as colunas em tabelas pré-existentes no boot.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>