Tela "Construtor" no painel Captain (acessivel em sidebar pra admins) que permite criar novo agente Hermes via chat guiado com agente Construtor (profile Hermes separado). Backend (admin scope): - POST /api/v1/accounts/:id/captain/hermes_builder — manda mensagem do admin pro gateway do Construtor (Hermes na porta 8646) - GET — retorna historico da sessao (Rails.cache, TTL 4h) - DELETE /reset — limpa sessao - POST /webhooks/captain/builder_callback — recebe respostas async do Construtor via plugin captain-http-callback do Hermes - HermesBuilder::Storage (Rails.cache) — persiste msgs por session_key (account_id + user_id) com role/content/created_at - HermesBuilder::Dispatcher — encaminha pro webhook do Construtor com HMAC opcional via ENV HERMES_BUILDER_WEBHOOK_SECRET Frontend: - Pagina Vue HermesBuilder/Index.vue — chat simples com: * Lista de mensagens com bubbles user/construtor * Indicador "digitando..." enquanto aguarda resposta * Input com Enter pra enviar / Shift+Enter pra nova linha * Polling 2s pra novas msgs * Botao Limpar conversa - API client em api/captain/hermesBuilder.js - Rota captain_hermes_builder_index (admin only) - Item no sidebar Captain "Construtor (Hermes)" - i18n keys CAPTAIN.HERMES_BUILDER em pt_BR + en UX flow: Admin abre tela → digita "olá" → Construtor pergunta nome → admin responde → marca, persona, tabela (com opcao copiar de existente), regras, FAQs, identidade → resumo → confirmar → Construtor chama save_agent_spec → JSON salvo em /tmp/agent-specs/<slug>.json pra revisao posterior. NAO cria filesystem do profile nem registros DB (etapa SEPARADA, prox sessao). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
46 lines
1.7 KiB
Ruby
46 lines
1.7 KiB
Ruby
# Encaminha mensagens da UI Hermes Builder pro gateway do Construtor (Hermes).
|
|
#
|
|
# Configuração:
|
|
# ENV['HERMES_BUILDER_WEBHOOK_URL'] — default: http://172.17.0.1:8646/webhooks/construtor-admin
|
|
# ENV['HERMES_BUILDER_WEBHOOK_SECRET'] — secret HMAC pra assinar payload
|
|
#
|
|
# Construtor responde async via plugin captain-http-callback que faz POST
|
|
# pra /webhooks/captain/builder_callback (HermesBuilderCallbackController).
|
|
module HermesBuilder::Dispatcher
|
|
DEFAULT_URL = 'http://172.17.0.1:8646/webhooks/construtor-admin'.freeze
|
|
TIMEOUT = 10
|
|
|
|
class DispatchError < StandardError; end
|
|
|
|
module_function
|
|
|
|
def send_to_construtor(session_id:, message:)
|
|
payload = { message: message, hermes_session_id: session_id }
|
|
body = payload.to_json
|
|
headers = signed_headers(body)
|
|
|
|
Rails.logger.info("[HermesBuilder::Dispatcher] sending session=#{session_id} (#{message.length} chars)")
|
|
|
|
response = HTTParty.post(webhook_url, body: body, headers: headers, timeout: TIMEOUT)
|
|
return response if response.success? || response.code == 202
|
|
|
|
raise DispatchError, "Construtor returned HTTP #{response.code}: #{response.body.to_s.truncate(200)}"
|
|
rescue HTTParty::Error, Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNREFUSED => e
|
|
raise DispatchError, "Network error contacting Construtor (#{e.class}): #{e.message}"
|
|
end
|
|
|
|
def webhook_url
|
|
ENV.fetch('HERMES_BUILDER_WEBHOOK_URL', DEFAULT_URL)
|
|
end
|
|
|
|
def signed_headers(body)
|
|
headers = { 'Content-Type' => 'application/json; charset=utf-8' }
|
|
secret = ENV.fetch('HERMES_BUILDER_WEBHOOK_SECRET', nil)
|
|
if secret.present?
|
|
sig = OpenSSL::HMAC.hexdigest('SHA256', secret, body)
|
|
headers['X-Hub-Signature-256'] = "sha256=#{sig}"
|
|
end
|
|
headers
|
|
end
|
|
end
|