feat(secretaria): Secretária IA separada por sessão (agente por número)

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>
This commit is contained in:
VPS 4 Deploy Agent
2026-07-05 19:51:25 +02:00
parent 8a53236502
commit 213990d51f
15 changed files with 960 additions and 85 deletions
@@ -46,6 +46,7 @@ export class ProtocolEngine {
hooks?: HookBus
tenantId?: string
clinicaId?: string // clínica do canal/workspace (escopo da ponte de agenda)
instanceId?: string // número/sessão que recebeu a mensagem (escopo do calendário interno)
},
): Promise<string> {
this.notifyCtx = { hooks: opts?.hooks, tenantId: opts?.tenantId }
@@ -127,6 +128,7 @@ export class ProtocolEngine {
conversationId,
extChatId: conversation.ext_chat_id ?? undefined,
tenantId: opts?.tenantId,
instanceId: opts?.instanceId,
hooks: opts?.hooks,
agenda: {
url: agendaUrl,