feat: adiciona criação e atualização de assistentes, expande parâmetros de configuração e implementa rotulagem automática para handoff de bot.

This commit is contained in:
Rodrigo Borba 2026-01-06 08:18:16 -03:00
parent 477a8eb83a
commit 7dbdea7ca5
5 changed files with 63 additions and 13 deletions

View File

@ -26,6 +26,18 @@ class CaptainAssistant extends ApiClient {
return axios.get(`${this.url}/${assistantId}/tools`); return axios.get(`${this.url}/${assistantId}/tools`);
} }
create(data) {
return axios.post(this.url, {
assistant: data,
});
}
update(id, data) {
return axios.patch(`${this.url}/${id}`, {
assistant: data,
});
}
updateTool(assistantId, toolKey, config) { updateTool(assistantId, toolKey, config) {
return axios.patch(`${this.url}/${assistantId}/tools/${toolKey}`, config); return axios.patch(`${this.url}/${assistantId}/tools/${toolKey}`, config);
} }

View File

@ -63,8 +63,9 @@ const updateStateFromAssistant = assistant => {
state.resolutionMessage = config.resolution_message || ''; state.resolutionMessage = config.resolution_message || '';
state.instructions = config.instructions || ''; state.instructions = config.instructions || '';
state.playbook = config.playbook || ''; state.playbook = config.playbook || '';
state.temperature = config.temperature || 1; state.temperature = config.temperature !== undefined ? config.temperature : 1;
state.distanceThreshold = config.distance_threshold || 0.35; state.distanceThreshold =
config.distance_threshold !== undefined ? config.distance_threshold : 0.35;
state.maxRagResults = config.max_rag_results || 3; state.maxRagResults = config.max_rag_results || 3;
}; };
@ -88,7 +89,7 @@ const handleSystemMessagesUpdate = async () => {
...props.assistant.config, ...props.assistant.config,
handoff_message: state.handoffMessage, handoff_message: state.handoffMessage,
resolution_message: state.resolutionMessage, resolution_message: state.resolutionMessage,
temperature: state.temperature || 1, temperature: state.temperature !== undefined ? state.temperature : 1,
playbook: state.playbook, playbook: state.playbook,
distance_threshold: state.distanceThreshold, distance_threshold: state.distanceThreshold,
max_rag_results: state.maxRagResults, max_rag_results: state.maxRagResults,
@ -166,7 +167,9 @@ watch(
step="0.1" step="0.1"
class="w-full h-1.5 bg-n-slate-3 rounded-lg appearance-none cursor-pointer" class="w-full h-1.5 bg-n-slate-3 rounded-lg appearance-none cursor-pointer"
/> />
<span class="text-sm font-medium text-n-slate-12 w-8 text-right">{{ state.temperature }}</span> <span class="text-sm font-medium text-n-slate-12 w-8 text-right">{{
state.temperature
}}</span>
</div> </div>
<p class="text-xs text-n-slate-11 italic"> <p class="text-xs text-n-slate-11 italic">
{{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.DESCRIPTION') }} {{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.DESCRIPTION') }}
@ -186,7 +189,9 @@ watch(
step="0.01" step="0.01"
class="w-full h-1.5 bg-n-slate-3 rounded-lg appearance-none cursor-pointer" class="w-full h-1.5 bg-n-slate-3 rounded-lg appearance-none cursor-pointer"
/> />
<span class="text-sm font-medium text-n-slate-12 w-8 text-right">{{ state.distanceThreshold }}</span> <span class="text-sm font-medium text-n-slate-12 w-8 text-right">{{
state.distanceThreshold
}}</span>
</div> </div>
<p class="text-xs text-n-slate-11 italic"> <p class="text-xs text-n-slate-11 italic">
{{ t('CAPTAIN.ASSISTANTS.FORM.DISTANCE_THRESHOLD.DESCRIPTION') }} {{ t('CAPTAIN.ASSISTANTS.FORM.DISTANCE_THRESHOLD.DESCRIPTION') }}

View File

@ -161,6 +161,13 @@ class Conversation < ApplicationRecord
def bot_handoff! def bot_handoff!
open! open!
account.labels.find_or_create_by!(title: 'desligar_ia') do |label|
label.description = 'Desliga a IA para este contato/conversa.'
label.color = '#f59e0b'
label.show_on_sidebar = true
end
contact&.add_labels(['desligar_ia'])
add_labels(['desligar_ia'])
dispatcher_dispatch(CONVERSATION_BOT_HANDOFF) dispatcher_dispatch(CONVERSATION_BOT_HANDOFF)
end end

View File

@ -48,17 +48,18 @@ class Api::V1::Accounts::Captain::AssistantsController < Api::V1::Accounts::Base
end end
def assistant_params def assistant_params
permitted = params.require(:assistant).permit(:name, :description, :llm_provider, :llm_model, :api_key, assistant_payload = params[:assistant].presence || params
config: [ permitted = assistant_payload.permit(:name, :description, :llm_provider, :llm_model, :api_key,
:product_name, :role_name, :feature_faq, :feature_memory, :feature_citation, config: [
:welcome_message, :handoff_message, :resolution_message, :product_name, :role_name, :feature_faq, :feature_memory, :feature_citation,
:instructions, :temperature :welcome_message, :handoff_message, :resolution_message,
]) :instructions, :temperature, :playbook, :distance_threshold, :max_rag_results
])
# Handle array parameters separately to allow partial updates # Handle array parameters separately to allow partial updates
permitted[:response_guidelines] = params[:assistant][:response_guidelines] if params[:assistant].key?(:response_guidelines) permitted[:response_guidelines] = assistant_payload[:response_guidelines] if assistant_payload.key?(:response_guidelines)
permitted[:guardrails] = params[:assistant][:guardrails] if params[:assistant].key?(:guardrails) permitted[:guardrails] = assistant_payload[:guardrails] if assistant_payload.key?(:guardrails)
permitted permitted
end end

View File

@ -0,0 +1,25 @@
# Planos pendentes
## Captain: usar tools sem JasmineBrain (status_suites)
Objetivo: deixar o proprio Captain decidir quando chamar tools (ex.: status_suites), sem classificador separado (JasmineBrain).
Proposta:
- Remover o bypass do JasmineBrain no fluxo de resposta.
- Expor a tool status_suites como tool disponivel diretamente ao Captain.
- Atualizar o prompt fixo para:
- chamar status_suites somente quando o usuario perguntar sobre disponibilidade de suites;
- nao chamar para outros assuntos.
- Manter logs para auditar quando a tool foi acionada e o resultado usado.
Arquivos envolvidos:
- enterprise/app/services/captain/llm/assistant_chat_service.rb
- enterprise/app/services/captain/llm/system_prompts_service.rb
- enterprise/app/services/captain/tools/definitions.rb
- enterprise/app/services/captain/tools/tool_runner.rb
Aceite:
- Pergunta sobre disponibilidade chama status_suites.
- Pergunta fora do tema nao chama tool.
- Resposta usa dados retornados pela tool.
- Log explicito de uso da tool.