From 8ec1b652faa0677ef60815a4838544857b2fb174 Mon Sep 17 00:00:00 2001 From: Rodribm10 Date: Tue, 14 Apr 2026 10:35:43 -0300 Subject: [PATCH] feat: tool GenerateReservationLink para jasmine gerar links prefill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cria Captain::Tools::GenerateReservationLinkTool que constrói URL pré-preenchida do reserva-1001 com dados coletados em conversa. Registra entrada generate_reservation_link em tools.yml e documenta RESERVA_1001_BASE_URL no .env.example. Co-Authored-By: Claude Sonnet 4.6 --- .env.example | 3 + config/agents/tools.yml | 5 + .../tools/generate_reservation_link_tool.rb | 131 ++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 enterprise/app/services/captain/tools/generate_reservation_link_tool.rb diff --git a/.env.example b/.env.example index 92dcf75be..c8bac09ef 100644 --- a/.env.example +++ b/.env.example @@ -104,3 +104,6 @@ AIOS_VERSION=2.2.0 # Token used to authenticate calls from the reserva-1001 app to the public # reservation endpoint. Generate via `openssl rand -hex 32` in production. RESERVA_1001_API_TOKEN= + +# Reserva Rede 1001 — URL base do app publico (usada pela Jasmine pra gerar links prefill) +RESERVA_1001_BASE_URL=http://localhost:5180 diff --git a/config/agents/tools.yml b/config/agents/tools.yml index e2c66429d..bab72f685 100644 --- a/config/agents/tools.yml +++ b/config/agents/tools.yml @@ -54,3 +54,8 @@ title: 'Criar Reserva' description: 'Cria uma reserva draft quando o cliente confirmar suíte, preço e horário de chegada' icon: 'calendar-add' + +- id: generate_reservation_link + title: 'Gerar Link de Reserva' + description: 'Gera um link da pagina publica de reserva ja pre-preenchida, pronto para o cliente revisar e pagar' + icon: 'link' diff --git a/enterprise/app/services/captain/tools/generate_reservation_link_tool.rb b/enterprise/app/services/captain/tools/generate_reservation_link_tool.rb new file mode 100644 index 000000000..5b87028bc --- /dev/null +++ b/enterprise/app/services/captain/tools/generate_reservation_link_tool.rb @@ -0,0 +1,131 @@ +# frozen_string_literal: true + +# rubocop:disable Metrics/MethodLength +# Ferramenta que gera um link pré-preenchido da página pública de reserva +# (reserva-1001). A Jasmine invoca isso após coletar os dados do cliente +# em conversa e envia a URL como mensagem outgoing. +class Captain::Tools::GenerateReservationLinkTool < Captain::Tools::BaseTool + DEFAULT_BASE_URL = 'http://localhost:5180' + + def name + 'generate_reservation_link' + end + + def description + <<~DESC.strip + Gera um link da pagina publica de reserva (Reserva Rede 1001) com os + dados ja pre-preenchidos. Use esta ferramenta quando ja tiver coletado + em conversa: marca, unidade, categoria da suite, permanencia, + data/hora de check-in e ao menos nome + telefone + CPF do cliente. + Envie o link retornado ao cliente como mensagem outgoing para ele + revisar e pagar. Todos os parametros sao opcionais - passe o que + souber, a pagina aceita preenchimento parcial. + DESC + end + + def tool_parameters_schema + { + type: 'object', + properties: { + marca: { + type: 'string', + description: 'Nome da marca. Ex: "Hotel 1001 Noites".' + }, + unidade: { + type: 'string', + description: 'Nome da unidade do hotel. Ex: "Hotel 1001 Aguas Lindas".' + }, + permanencia: { + type: 'string', + description: 'Permanencia escolhida. Ex: "3hrs", "4hrs", "Pernoite".' + }, + categoria: { + type: 'string', + description: 'Categoria da suite. Ex: "Standard", "Hidromassagem".' + }, + checkin_at: { + type: 'string', + description: 'Data e horario de check-in em ISO 8601. Ex: "2026-04-14T22:00:00".' + }, + nome: { + type: 'string', + description: 'Nome completo do cliente.' + }, + telefone: { + type: 'string', + description: 'Telefone do cliente (com ou sem DDI).' + }, + cpf: { + type: 'string', + description: 'CPF do cliente (apenas numeros ou com pontuacao).' + }, + email: { + type: 'string', + description: 'Email do cliente (opcional).' + }, + observacao: { + type: 'string', + description: 'Observacao ou preferencia especial do cliente (opcional).' + } + } + } + end + + def execute(*args, **params) + actual_params = resolve_params(args, params) + base = ENV.fetch('RESERVA_1001_BASE_URL', DEFAULT_BASE_URL) + query = build_query(actual_params) + url = query.empty? ? base : "#{base}/?#{query}" + + { + formatted_message: "Pronto! Clique no link para revisar e pagar a entrada via PIX:\n#{url}", + raw_payload: url, + success: true + } + rescue StandardError => e + Rails.logger.error("[GenerateReservationLinkTool] falha: #{e.class} - #{e.message}") + { formatted_message: 'Nao consegui gerar o link agora. Tente novamente em instantes.', success: false } + end + + private + + def build_query(actual_params) + mapping = { + marca: actual_params[:marca], + unidade: actual_params[:unidade], + permanencia: actual_params[:permanencia], + categoria: actual_params[:categoria], + checkin: actual_params[:checkin_at], + nome: actual_params[:nome], + telefone: actual_params[:telefone], + cpf: actual_params[:cpf], + email: actual_params[:email], + obs: actual_params[:observacao] + } + cleaned = mapping.compact.reject { |_, v| v.to_s.strip.empty? } + URI.encode_www_form(cleaned) + end + + def resolve_params(args, params) + merged = params.to_h + + args.each do |arg| + next unless arg.is_a?(Hash) + next if tool_context_hash?(arg) + + merged = arg.merge(merged) + end + + merged.with_indifferent_access + end + + def tool_context_hash?(hash) + hash.key?(:state) || + hash.key?('state') || + hash.key?(:context) || + hash.key?('context') || + hash.key?(:conversation) || + hash.key?('conversation') + end +end +# rubocop:enable Metrics/MethodLength