Implementa o lado Captain da integração Nível 2 (Hermes como cérebro). Ativação por inbox via env var CAPTAIN_HERMES_INBOX_IDS — inboxes não listadas seguem usando o orquestrador interno do Captain (Daniela_Reservas etc) sem mudança alguma. Princípio "só adiciona, não retira". Componentes: - enterprise/app/services/captain/hermes.rb Módulo helper de config (env vars, URLs, secrets per-inbox). - enterprise/app/services/captain/hermes/client.rb Service que monta payload (msg + contexto da conversa/inbox/contato) e faz POST autenticado via HMAC-SHA256 (X-Hub-Signature-256) no webhook do Hermes Agent (porta 8644). DispatchError em falha de rede/HTTP. - enterprise/app/jobs/captain/hermes/outgoing_job.rb Wrapper Sidekiq do Client. Retry 3x em DispatchError. - app/controllers/webhooks/captain/hermes_callback_controller.rb Recebe callback do plugin captain-http-callback do Hermes. Valida HMAC se CAPTAIN_HERMES_CALLBACK_SECRET setado, identifica conversation pela última pending da inbox (janela 5min) e cria mensagem outgoing. - config/routes.rb Rota POST /webhooks/captain/hermes_callback (fora de /api/v1/accounts). - enterprise/app/services/enterprise/message_templates/hook_execution_service.rb Branch novo no schedule_captain_response: se Hermes habilitado pra inbox, dispara HermesOutgoingJob; senão, fluxo Captain interno como antes. Env vars (todas opcionais; sem set = Hermes desabilitado em todas inboxes): - CAPTAIN_HERMES_INBOX_IDS (CSV de inbox.id) - CAPTAIN_HERMES_WEBHOOK_BASE_URL (default http://172.17.0.1:8644) - CAPTAIN_HERMES_CALLBACK_SECRET (HMAC validar callbacks de entrada) - CAPTAIN_HERMES_SUBSCRIPTION_SECRET_INBOX_<id> (HMAC assinar saídas) Limitação: identificação da conversation no callback usa última pending da inbox dentro de 5min. OK pra PoC com 1 conversa de teste por vez. Em produção, melhorar mapeando delivery_id ↔ conversation_id em Redis. Próximo passo manual (admin VPS): criar subscription no Hermes: hermes webhook subscribe captain-inbox-1 \\ --prompt 'Cliente disse: {message}. Responda como Daniela ...' \\ --deliver http_callback \\ --deliver-chat-id 'http://CAPTAIN_HOST/webhooks/captain/hermes_callback?inbox_id=1' Depois set CAPTAIN_HERMES_INBOX_IDS=1 + CAPTAIN_HERMES_SUBSCRIPTION_SECRET_INBOX_1 no stack do Captain e testar pela inbox Angelina. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
33 lines
1.2 KiB
Ruby
33 lines
1.2 KiB
Ruby
# Dispara o webhook do Hermes Agent assincronamente quando uma mensagem
|
|
# do cliente chega numa inbox marcada como Hermes-enabled.
|
|
#
|
|
# Acionado pelo Enterprise::MessageTemplates::HookExecutionService no lugar do
|
|
# Captain::Conversation::ResponseBuilderJob padrão, quando
|
|
# Captain::Hermes.enabled_for?(inbox) retorna true.
|
|
class Captain::Hermes::OutgoingJob < ApplicationJob
|
|
queue_as :default
|
|
|
|
retry_on Captain::Hermes::Client::DispatchError, attempts: 3, wait: 5.seconds
|
|
|
|
def perform(conversation_id, message_id)
|
|
conversation = Conversation.find_by(id: conversation_id)
|
|
message = Message.find_by(id: message_id)
|
|
|
|
if conversation.blank? || message.blank?
|
|
Rails.logger.warn(
|
|
"[Captain::Hermes::OutgoingJob] conversation/message not found: c=#{conversation_id} m=#{message_id}"
|
|
)
|
|
return
|
|
end
|
|
|
|
unless Captain::Hermes.enabled_for?(conversation.inbox)
|
|
Rails.logger.info(
|
|
"[Captain::Hermes::OutgoingJob] inbox #{conversation.inbox_id} not in CAPTAIN_HERMES_INBOX_IDS — skipping"
|
|
)
|
|
return
|
|
end
|
|
|
|
Captain::Hermes::Client.new(conversation.inbox).dispatch(message: message, conversation: conversation)
|
|
end
|
|
end
|