fix(captain/hermes-builder): namespace controller correto + botao iniciar
Bug: controller estava em enterprise/api/v1/accounts/captain/ com namespace Enterprise:: — convencao Chatwoot eh enterprise/app/controllers/api/v1/... direto, classe Api::V1::Accounts::Captain::HermesBuilderController. Sem namespace Enterprise::. 404 acontecia porque rotas registravam Captain:: sem prefixo Enterprise::. Move controller pro path correto. Remove diretorios vazios criados. UX: adiciona endpoint POST /start que envia comando-gatilho oculto pro Construtor comecar fluxo socratico — admin nao precisa digitar primeira mensagem. Vue mostra empty state com botao "Iniciar criacao" em vez de exigir mensagem inicial. i18n keys novas: START + EMPTY_STATE atualizado em pt_BR + en. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bfa06597f2
commit
041766b427
@ -14,6 +14,10 @@ class HermesBuilder extends ApiClient {
|
|||||||
return axios.post(this.url, { text });
|
return axios.post(this.url, { text });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
return axios.post(`${this.url}/start`);
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
return axios.delete(`${this.url}/reset`);
|
return axios.delete(`${this.url}/reset`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.",
|
"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": "Clear conversation",
|
||||||
"RESET_CONFIRM": "Clear current conversation with the Builder?",
|
"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)",
|
"PLACEHOLDER": "Type and press Enter to send (Shift+Enter for new line)",
|
||||||
"SEND": "Send",
|
"SEND": "Send",
|
||||||
"SESSION_LABEL": "Session:",
|
"SESSION_LABEL": "Session:",
|
||||||
"SEND_FAILED": "Send failed: {message}",
|
"SEND_FAILED": "Send failed: {message}",
|
||||||
"RESET_FAILED": "Failed to clear session."
|
"RESET_FAILED": "Failed to clear session.",
|
||||||
|
"START": "Start creation"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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.",
|
"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": "Limpar conversa",
|
||||||
"RESET_CONFIRM": "Limpar conversa atual com o Construtor?",
|
"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)",
|
"PLACEHOLDER": "Escreva e Enter pra enviar (Shift+Enter pula linha)",
|
||||||
"SEND": "Enviar",
|
"SEND": "Enviar",
|
||||||
"SESSION_LABEL": "Sessão:",
|
"SESSION_LABEL": "Sessão:",
|
||||||
"SEND_FAILED": "Erro ao enviar: {message}",
|
"SEND_FAILED": "Erro ao enviar: {message}",
|
||||||
"RESET_FAILED": "Falha ao limpar sessão."
|
"RESET_FAILED": "Falha ao limpar sessão.",
|
||||||
|
"START": "Iniciar criação"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 => {
|
const formatTime = iso => {
|
||||||
if (!iso) return '';
|
if (!iso) return '';
|
||||||
const d = new Date(iso);
|
const d = new Date(iso);
|
||||||
@ -124,7 +142,10 @@ watch(messages, () => nextTick().then(scrollToBottom), { deep: true });
|
|||||||
|
|
||||||
<section ref="scrollContainer" class="messages">
|
<section ref="scrollContainer" class="messages">
|
||||||
<div v-if="!messages.length" class="empty-state">
|
<div v-if="!messages.length" class="empty-state">
|
||||||
{{ t('CAPTAIN_HERMES_BUILDER.EMPTY_STATE') }}
|
<p>{{ t('CAPTAIN_HERMES_BUILDER.EMPTY_STATE') }}</p>
|
||||||
|
<Button variant="primary" :disabled="sending" @click="startSession">
|
||||||
|
{{ t('CAPTAIN_HERMES_BUILDER.START') }}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="(msg, idx) in messages"
|
v-for="(msg, idx) in messages"
|
||||||
@ -216,6 +237,14 @@ watch(messages, () => nextTick().then(scrollToBottom), { deep: true });
|
|||||||
color: var(--color-text-light, #9ca3af);
|
color: var(--color-text-light, #9ca3af);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.msg {
|
.msg {
|
||||||
|
|||||||
@ -60,6 +60,7 @@ Rails.application.routes.draw do
|
|||||||
namespace :captain do
|
namespace :captain do
|
||||||
resources :hermes_builder, only: [:index, :create] do
|
resources :hermes_builder, only: [:index, :create] do
|
||||||
collection do
|
collection do
|
||||||
|
post :start
|
||||||
delete :reset
|
delete :reset
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
# 5. UI faz GET /messages a cada 2s (polling) e renderiza
|
# 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).
|
# 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
|
before_action :authorize_admin
|
||||||
|
|
||||||
def index
|
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
|
render json: { error: "Falha ao contatar Construtor: #{e.message}" }, status: :bad_gateway
|
||||||
end
|
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
|
def reset
|
||||||
HermesBuilder::Storage.clear(session_key)
|
HermesBuilder::Storage.clear(session_key)
|
||||||
render json: { ok: true }
|
render json: { ok: true }
|
||||||
Loading…
Reference in New Issue
Block a user