diff --git a/app/javascript/dashboard/api/captain/hermesBuilder.js b/app/javascript/dashboard/api/captain/hermesBuilder.js index 4782271c0..cea68963f 100644 --- a/app/javascript/dashboard/api/captain/hermesBuilder.js +++ b/app/javascript/dashboard/api/captain/hermesBuilder.js @@ -14,6 +14,10 @@ class HermesBuilder extends ApiClient { return axios.post(this.url, { text }); } + start() { + return axios.post(`${this.url}/start`); + } + reset() { return axios.delete(`${this.url}/reset`); } diff --git a/app/javascript/dashboard/i18n/locale/en/captain.json b/app/javascript/dashboard/i18n/locale/en/captain.json index 1db4eae22..08b88f46a 100644 --- a/app/javascript/dashboard/i18n/locale/en/captain.json +++ b/app/javascript/dashboard/i18n/locale/en/captain.json @@ -899,11 +899,12 @@ "HEADER_DESCRIPTION": "Chat with the Builder to create a new Hermes agent. It asks questions and saves the spec as JSON for review at the end.", "RESET": "Clear conversation", "RESET_CONFIRM": "Clear current conversation with the Builder?", - "EMPTY_STATE": "Type \"hello\" to start. The Builder will guide you.", + "EMPTY_STATE": "Ready to create a new Hermes agent? Click \"Start creation\" and the Builder will guide you.", "PLACEHOLDER": "Type and press Enter to send (Shift+Enter for new line)", "SEND": "Send", "SESSION_LABEL": "Session:", "SEND_FAILED": "Send failed: {message}", - "RESET_FAILED": "Failed to clear session." + "RESET_FAILED": "Failed to clear session.", + "START": "Start creation" } } \ No newline at end of file diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/captain.json b/app/javascript/dashboard/i18n/locale/pt_BR/captain.json index 543584605..cbbc6c9a2 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/captain.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/captain.json @@ -900,11 +900,12 @@ "HEADER_DESCRIPTION": "Converse com o Construtor pra criar um novo agente Hermes. Ele faz perguntas e ao final salva a especificação em JSON pra revisão.", "RESET": "Limpar conversa", "RESET_CONFIRM": "Limpar conversa atual com o Construtor?", - "EMPTY_STATE": "Mande \"olá\" pra começar. O Construtor vai te guiar.", + "EMPTY_STATE": "Pronto pra criar um novo agente Hermes? Clica em \"Iniciar criação\" e o Construtor te guia.", "PLACEHOLDER": "Escreva e Enter pra enviar (Shift+Enter pula linha)", "SEND": "Enviar", "SESSION_LABEL": "Sessão:", "SEND_FAILED": "Erro ao enviar: {message}", - "RESET_FAILED": "Falha ao limpar sessão." + "RESET_FAILED": "Falha ao limpar sessão.", + "START": "Iniciar criação" } } \ No newline at end of file diff --git a/app/javascript/dashboard/routes/dashboard/captain/builder/Index.vue b/app/javascript/dashboard/routes/dashboard/captain/builder/Index.vue index 23e5a0806..de5cc933e 100644 --- a/app/javascript/dashboard/routes/dashboard/captain/builder/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/captain/builder/Index.vue @@ -88,6 +88,24 @@ const resetSession = async () => { } }; +const startSession = async () => { + if (sending.value) return; + sending.value = true; + try { + await hermesBuilderApi.start(); + // Construtor vai responder com primeira pergunta via callback async + // — polling pega em ~2s + } catch (e) { + useAlert( + t('CAPTAIN_HERMES_BUILDER.SEND_FAILED', { + message: e.response?.data?.error || e.message || 'unknown', + }) + ); + } finally { + sending.value = false; + } +}; + const formatTime = iso => { if (!iso) return ''; const d = new Date(iso); @@ -124,7 +142,10 @@ watch(messages, () => nextTick().then(scrollToBottom), { deep: true });
- {{ t('CAPTAIN_HERMES_BUILDER.EMPTY_STATE') }} +

{{ t('CAPTAIN_HERMES_BUILDER.EMPTY_STATE') }}

+
nextTick().then(scrollToBottom), { deep: true }); color: var(--color-text-light, #9ca3af); font-size: 14px; text-align: center; + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; + + p { + margin: 0; + } } .msg { diff --git a/config/routes.rb b/config/routes.rb index 9e6648927..c8e0a556a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,6 +60,7 @@ Rails.application.routes.draw do namespace :captain do resources :hermes_builder, only: [:index, :create] do collection do + post :start delete :reset end end diff --git a/enterprise/app/controllers/enterprise/api/v1/accounts/captain/hermes_builder_controller.rb b/enterprise/app/controllers/api/v1/accounts/captain/hermes_builder_controller.rb similarity index 66% rename from enterprise/app/controllers/enterprise/api/v1/accounts/captain/hermes_builder_controller.rb rename to enterprise/app/controllers/api/v1/accounts/captain/hermes_builder_controller.rb index 9d4efcc56..f2aac82ea 100644 --- a/enterprise/app/controllers/enterprise/api/v1/accounts/captain/hermes_builder_controller.rb +++ b/enterprise/app/controllers/api/v1/accounts/captain/hermes_builder_controller.rb @@ -8,7 +8,7 @@ # 5. UI faz GET /messages a cada 2s (polling) e renderiza # # Sessão é por account+user (1 admin → 1 sessão de builder por vez). -class Enterprise::Api::V1::Accounts::Captain::HermesBuilderController < Api::V1::Accounts::BaseController +class Api::V1::Accounts::Captain::HermesBuilderController < Api::V1::Accounts::BaseController before_action :authorize_admin def index @@ -29,6 +29,21 @@ class Enterprise::Api::V1::Accounts::Captain::HermesBuilderController < Api::V1: render json: { error: "Falha ao contatar Construtor: #{e.message}" }, status: :bad_gateway end + # Inicia sessão limpa enviando comando-gatilho oculto pro Construtor pra + # ele começar o fluxo socrático de criação. UI chama este endpoint + # quando admin clica "Iniciar" — sem ter que digitar primeira msg. + def start + HermesBuilder::Storage.clear(session_key) + HermesBuilder::Dispatcher.send_to_construtor( + session_id: session_id, + message: '__START__ Inicie o fluxo de criação de novo agente Hermes. Comece pela primeira pergunta do Bloco 1 (nome do agente).' + ) + render json: { ok: true, session_id: session_id }, status: :accepted + rescue HermesBuilder::Dispatcher::DispatchError => e + Rails.logger.error("[HermesBuilder#start] dispatch failed: #{e.message}") + render json: { error: "Falha ao contatar Construtor: #{e.message}" }, status: :bad_gateway + end + def reset HermesBuilder::Storage.clear(session_key) render json: { ok: true }