"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ALL_TOOL_NAMES = exports.BUILTIN_TOOLS = void 0; exports.resolveTools = resolveTools; // ── Helpers ──────────────────────────────────────────────────────────────────── function fmtDate(d) { return d.toISOString().split('T')[0]; } // ── Tools ────────────────────────────────────────────────────────────────────── exports.BUILTIN_TOOLS = [ // ── listar_horarios ────────────────────────────────────────────────────────── { name: 'listar_horarios', description: 'Lista os horários disponíveis na agenda para agendamento. ' + 'Use antes de propor datas ao cliente. ' + 'Se não informar a data, retorna os próximos 7 dias.', parameters: { type: 'object', properties: { data: { type: 'string', description: 'Data no formato YYYY-MM-DD. Opcional — padrão: próximos 7 dias.', }, }, }, async execute(args, ctx) { const from = args['data'] ?? fmtDate(new Date()); const to = args['data'] ?? fmtDate(new Date(Date.now() + 7 * 86400000)); const slots = await ctx.db('sec_calendar') .where('status', 'available') .whereBetween('date', [from, to]) .orderBy('date').orderBy('time_start') .limit(20); if (!slots.length) { return { disponivel: false, mensagem: 'Nenhum horário disponível no período informado.' }; } return { disponivel: true, horarios: slots.map(s => ({ id: s.id, data: s.date, inicio: String(s.time_start).slice(0, 5), fim: String(s.time_end).slice(0, 5), titulo: s.title, })), }; }, }, // ── agendar_horario ────────────────────────────────────────────────────────── { name: 'agendar_horario', description: 'Reserva um horário disponível na agenda para o cliente. ' + 'Use listar_horarios primeiro para obter o slot_id correto.', parameters: { type: 'object', properties: { slot_id: { type: 'string', description: 'ID do horário retornado por listar_horarios.' }, nome_cliente: { type: 'string', description: 'Nome completo do cliente.' }, telefone_cliente: { type: 'string', description: 'Telefone do cliente (opcional).' }, }, required: ['slot_id', 'nome_cliente'], }, async execute(args, ctx) { const slot = await ctx.db('sec_calendar') .where({ id: args['slot_id'], status: 'available' }) .first(); if (!slot) { return { ok: false, erro: 'Horário não encontrado ou já reservado. Chame listar_horarios novamente.' }; } await ctx.db('sec_calendar').where({ id: args['slot_id'] }).update({ status: 'booked', attendee_name: args['nome_cliente'], attendee_phone: args['telefone_cliente'] ?? null, updated_at: new Date(), }); return { ok: true, confirmacao: { data: slot.date, inicio: String(slot.time_start).slice(0, 5), fim: String(slot.time_end).slice(0, 5), titulo: slot.title, nome: args['nome_cliente'], }, }; }, }, // ── escalar_humano ─────────────────────────────────────────────────────────── { name: 'escalar_humano', description: 'Transfere o atendimento para um atendente humano quando a situação exige. ' + 'Use quando: cliente pede explicitamente, problema financeiro sensível, raiva intensa, ' + 'ou quando você não consegue resolver após tentativas honestas.', parameters: { type: 'object', properties: { motivo: { type: 'string', description: 'Motivo da transferência (ex: "cliente insatisfeito com cobrança").', }, }, }, async execute(args, ctx) { await ctx.db('sec_conversations').where({ id: ctx.conversationId }).update({ handoff_mode: 'humano', handoff_human_at: new Date(), status: 'escalated', }); const conv = await ctx.db('sec_conversations').where({ id: ctx.conversationId }).first(); if (ctx.hooks && ctx.tenantId && ctx.extChatId) { const chatId = ctx.extChatId.includes(':') ? ctx.extChatId.split(':').slice(1).join(':') : ctx.extChatId; const payload = { tenantId: ctx.tenantId, conversationId: ctx.conversationId, chatId, protocolNumber: conv?.protocol_number ?? '', motivo: args['motivo'] ?? '', }; ctx.hooks.emit('ext:handoff', { ...payload, mode: 'humano', reason: 'escalation' }).catch(() => { }); ctx.hooks.emit('ext:escalated', payload).catch(() => { }); } return { ok: true, escalado: true, motivo: args['motivo'] ?? 'Solicitado pelo sistema' }; }, }, // ── encerrar_protocolo ─────────────────────────────────────────────────────── { name: 'encerrar_protocolo', description: 'Encerra o protocolo de atendimento após resolver o problema do cliente. ' + 'Use apenas quando tiver certeza de que tudo foi resolvido.', parameters: { type: 'object', properties: { resumo: { type: 'string', description: 'Breve resumo do que foi tratado e resolvido neste atendimento.', }, }, required: ['resumo'], }, async execute(args, ctx) { const summary = args['resumo'] ?? 'Atendimento encerrado.'; const conv = await ctx.db('sec_conversations').where({ id: ctx.conversationId }).first(); await ctx.db('sec_conversations').where({ id: ctx.conversationId }).update({ status: 'closed', summary, updated_at: new Date(), }); await ctx.db('sec_messages').where({ conversation_id: ctx.conversationId }).delete(); return { ok: true, protocolo: conv?.protocol_number ?? '', resumo: summary }; }, }, ]; function resolveTools(names) { return names .map(n => exports.BUILTIN_TOOLS.find(t => t.name === n)) .filter((t) => t !== undefined); } exports.ALL_TOOL_NAMES = exports.BUILTIN_TOOLS.map(t => t.name); //# sourceMappingURL=tools.js.map