feat(captain/mcp): get_assistant_scenario tool — Construtor copia identidade de outro agente
Construtor atende 'copiar maps/endereço/telefone/wifi da Lara' sem o admin redigitar. Tool retorna o markdown bruto do scenario (default Daniela_Reservas) do assistant fonte; LLM extrai os campos relevantes. Cobre o gap entre get_assistant_pricing (preços estruturados) e get_assistant_faqs (Q&As): essa retorna prompt CRU pra LLM interpretar campos não estruturados (contatos, links, wifi, persona). Hot-patched + USR1 no Puma e Construtor. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dd9e11da14
commit
0f39945f43
@ -22,6 +22,7 @@ class Captain::Mcp::ToolRegistry
|
|||||||
Captain::Mcp::Tools::ListAssistantsTool,
|
Captain::Mcp::Tools::ListAssistantsTool,
|
||||||
Captain::Mcp::Tools::GetAssistantPricingTool,
|
Captain::Mcp::Tools::GetAssistantPricingTool,
|
||||||
Captain::Mcp::Tools::GetAssistantFaqsTool,
|
Captain::Mcp::Tools::GetAssistantFaqsTool,
|
||||||
|
Captain::Mcp::Tools::GetAssistantScenarioTool,
|
||||||
Captain::Mcp::Tools::SaveAgentSpecTool
|
Captain::Mcp::Tools::SaveAgentSpecTool
|
||||||
# Captain::Mcp::Tools::HandoffTool — fluxo via automation hoje, MCP futuro
|
# Captain::Mcp::Tools::HandoffTool — fluxo via automation hoje, MCP futuro
|
||||||
].freeze
|
].freeze
|
||||||
|
|||||||
@ -0,0 +1,69 @@
|
|||||||
|
# Tool MCP: retorna o texto completo de um cenário (instruction) de um
|
||||||
|
# assistente existente.
|
||||||
|
#
|
||||||
|
# Caso de uso: Construtor pergunta "copiar identidade/maps/wifi/telefone
|
||||||
|
# da Lara?". Tool retorna o markdown bruto do scenario solicitado pra o
|
||||||
|
# Construtor (LLM) extrair os campos relevantes.
|
||||||
|
#
|
||||||
|
# Diferente de get_assistant_pricing (que parseia preços) e
|
||||||
|
# get_assistant_faqs (que lista responses): essa retorna o RAW PROMPT
|
||||||
|
# pra LLM interpretar livremente.
|
||||||
|
class Captain::Mcp::Tools::GetAssistantScenarioTool < Captain::Mcp::Tools::BaseTool
|
||||||
|
DEFAULT_SCENARIO_TITLE = 'Daniela_Reservas'.freeze
|
||||||
|
MAX_CHARS = 20_000
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def name
|
||||||
|
'get_assistant_scenario'
|
||||||
|
end
|
||||||
|
|
||||||
|
def description
|
||||||
|
'Retorna o texto MARKDOWN completo de um cenário (prompt) de um ' \
|
||||||
|
'assistente existente. Use pra copiar identidade da unidade ' \
|
||||||
|
'(endereço, telefone, WhatsApp, maps, wifi, etc), persona ou ' \
|
||||||
|
'qualquer outro detalhe que esteja no prompt do agente fonte. ' \
|
||||||
|
'Default scenario_title="Daniela_Reservas".'
|
||||||
|
end
|
||||||
|
|
||||||
|
def input_schema
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
assistant_id: {
|
||||||
|
type: 'integer',
|
||||||
|
description: 'ID do assistente fonte.'
|
||||||
|
},
|
||||||
|
scenario_title: {
|
||||||
|
type: 'string',
|
||||||
|
description: "Título do cenário (default: '#{DEFAULT_SCENARIO_TITLE}'). Use list_assistants pra ver opções.",
|
||||||
|
default: DEFAULT_SCENARIO_TITLE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required: ['assistant_id']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(args, context:) # rubocop:disable Lint/UnusedMethodArgument, Metrics/AbcSize
|
||||||
|
assistant = Captain::Assistant.find_by(id: args['assistant_id'])
|
||||||
|
return error_response("Assistente #{args['assistant_id']} não encontrado.") if assistant.blank?
|
||||||
|
|
||||||
|
title = args['scenario_title'].to_s.presence || DEFAULT_SCENARIO_TITLE
|
||||||
|
scenario = assistant.scenarios.find_by(title: title)
|
||||||
|
|
||||||
|
if scenario.blank?
|
||||||
|
avail = assistant.scenarios.pluck(:title)
|
||||||
|
return error_response(
|
||||||
|
"Cenário '#{title}' não existe em #{assistant.name}. Disponíveis: #{avail.join(', ')}."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
text = scenario.instruction.to_s
|
||||||
|
text = "#{text.first(MAX_CHARS)}\n\n... [truncado em #{MAX_CHARS} chars] ..." if text.size > MAX_CHARS
|
||||||
|
|
||||||
|
text_response("# Cenário '#{title}' de #{assistant.name}\n\n#{text}")
|
||||||
|
rescue StandardError => e
|
||||||
|
Rails.logger.error("[Captain::Mcp::GetAssistantScenarioTool] error: #{e.class}: #{e.message}")
|
||||||
|
error_response("Erro ao buscar cenário: #{e.message}")
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user