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`);
}
create(data) {
return axios.post(this.url, {
assistant: data,
});
}
update(id, data) {
return axios.patch(`${this.url}/${id}`, {
assistant: data,
});
}
updateTool(assistantId, 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.instructions = config.instructions || '';
state.playbook = config.playbook || '';
state.temperature = config.temperature || 1;
state.distanceThreshold = config.distance_threshold || 0.35;
state.temperature = config.temperature !== undefined ? config.temperature : 1;
state.distanceThreshold =
config.distance_threshold !== undefined ? config.distance_threshold : 0.35;
state.maxRagResults = config.max_rag_results || 3;
};
@ -88,7 +89,7 @@ const handleSystemMessagesUpdate = async () => {
...props.assistant.config,
handoff_message: state.handoffMessage,
resolution_message: state.resolutionMessage,
temperature: state.temperature || 1,
temperature: state.temperature !== undefined ? state.temperature : 1,
playbook: state.playbook,
distance_threshold: state.distanceThreshold,
max_rag_results: state.maxRagResults,
@ -166,7 +167,9 @@ watch(
step="0.1"
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>
<p class="text-xs text-n-slate-11 italic">
{{ t('CAPTAIN.ASSISTANTS.FORM.TEMPERATURE.DESCRIPTION') }}
@ -186,7 +189,9 @@ watch(
step="0.01"
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>
<p class="text-xs text-n-slate-11 italic">
{{ t('CAPTAIN.ASSISTANTS.FORM.DISTANCE_THRESHOLD.DESCRIPTION') }}

View File

@ -161,6 +161,13 @@ class Conversation < ApplicationRecord
def bot_handoff!
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)
end

View File

@ -48,17 +48,18 @@ class Api::V1::Accounts::Captain::AssistantsController < Api::V1::Accounts::Base
end
def assistant_params
permitted = params.require(:assistant).permit(:name, :description, :llm_provider, :llm_model, :api_key,
assistant_payload = params[:assistant].presence || params
permitted = assistant_payload.permit(:name, :description, :llm_provider, :llm_model, :api_key,
config: [
:product_name, :role_name, :feature_faq, :feature_memory, :feature_citation,
:welcome_message, :handoff_message, :resolution_message,
:instructions, :temperature
:instructions, :temperature, :playbook, :distance_threshold, :max_rag_results
])
# 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
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.