From f0f8322cce231f1b73531d9c8cc8d3eed6e95d51 Mon Sep 17 00:00:00 2001 From: Rodribm10 Date: Sat, 2 May 2026 14:07:15 -0300 Subject: [PATCH] fix(captain/mcp): tool descriptions sem exemplos motel-flavored + brand match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1: send_suite_images_tool description mencionava 'Master, Luxo, Mini Chalé 45' como exemplos. Quando outros agentes (ex: Juliana de Qnn01) faziam tools/list, o LLM via essas categorias e usava como referência — respondia oferecendo Mini Chalé 45 e Suíte Ouro pra cliente do 1001 Noites Ceilândia (que não tem essas categorias). Removidos exemplos. Bug 2: lookup_brand fazia fuzzy match permissivo demais. 'Hoteis 1001 Noites' e 'Hotel 1001 Noites Prime' ambos contêm '1001 Noites' — quem vinha primeiro no .find ganhava (Prime, ID menor). Juliana de Qnn01 (brand 'Hoteis 1001 Noites') saiu do Construtor com SOUL.md dizendo 'Hotel 1001 Noites Prime'. Fix: prioriza brand do parent_unit (fonte canônica), depois exact-match casecmp, depois fuzzy. Tudo isso vale pra Construtor entregar agente certo da próxima vez — foram os 2 erros de provisionamento da Juliana hoje. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../captain/mcp/tools/save_agent_spec_tool.rb | 15 ++++++++++----- .../captain/mcp/tools/send_suite_images_tool.rb | 12 +++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/enterprise/app/services/captain/mcp/tools/save_agent_spec_tool.rb b/enterprise/app/services/captain/mcp/tools/save_agent_spec_tool.rb index 8e6bc163b..48c413b2b 100644 --- a/enterprise/app/services/captain/mcp/tools/save_agent_spec_tool.rb +++ b/enterprise/app/services/captain/mcp/tools/save_agent_spec_tool.rb @@ -130,11 +130,16 @@ class Captain::Mcp::Tools::SaveAgentSpecTool < Captain::Mcp::Tools::BaseTool def lookup_brand(parent, brand_name) return nil if parent.nil? - if brand_name.present? - hit = Captain::Brand.where(account_id: parent.account_id).find { |b| brand_matches?(b.name, brand_name) } - return hit if hit - end - parent.captain_inboxes.first&.captain_unit&.brand + # Sempre prefere a brand do parent_unit (fonte de verdade — Construtor copiou + # daquele agente). Spec.brand passado é só hint, pode estar errado/abreviado. + parent_brand = parent.captain_unit&.brand || parent.captain_inboxes.first&.captain_unit&.brand + return parent_brand if parent_brand + + return nil if brand_name.blank? + + candidates = Captain::Brand.where(account_id: parent.account_id) + candidates.find { |b| b.name.casecmp?(brand_name) } || + candidates.find { |b| brand_matches?(b.name, brand_name) } end def parent_unit_for(parent) diff --git a/enterprise/app/services/captain/mcp/tools/send_suite_images_tool.rb b/enterprise/app/services/captain/mcp/tools/send_suite_images_tool.rb index dab07c60f..9997969f8 100644 --- a/enterprise/app/services/captain/mcp/tools/send_suite_images_tool.rb +++ b/enterprise/app/services/captain/mcp/tools/send_suite_images_tool.rb @@ -5,8 +5,10 @@ # Captain::GalleryItem da inbox atual (com fallback pra acervo global) e # envia até `limit` imagens como mensagens outgoing na conversa. # -# Search: aceita `suite_category` (ex: "Master", "Luxo") OU `suite_number` -# (ex: "101"), mutuamente exclusivos. Match case-insensitive, fuzzy. +# Search: aceita `suite_category` (nome da categoria configurada na unidade) +# OU `suite_number` (ex: "101"), mutuamente exclusivos. Match case-insensitive, +# fuzzy. NÃO incluir exemplos de categorias específicas aqui — vaza pro LLM +# em outros agentes via tools/list. # # Pré-requisito: cadastro do Captain::GalleryItem via painel UI do # Chatwoot — Captain::Mcp não cria fotos, só consome o catálogo. @@ -22,8 +24,8 @@ class Captain::Mcp::Tools::SendSuiteImagesTool < Captain::Mcp::Tools::BaseTool def description 'Envia fotos da suíte pra conversa do cliente. Use quando ele pedir foto/imagem ' \ '("manda uma foto", "tem como ver?"). Busca no catálogo da inbox atual (fallback ' \ - 'global). Passe `suite_category` (ex: "Master", "Luxo", "Mini Chalé 45") OU ' \ - '`suite_number` (ex: "101") — não combine os dois.' + 'global). Passe `suite_category` (nome da categoria conforme cadastro da unidade) ' \ + 'OU `suite_number` (ex: "101") — não combine os dois.' end def input_schema # rubocop:disable Metrics/MethodLength @@ -36,7 +38,7 @@ class Captain::Mcp::Tools::SendSuiteImagesTool < Captain::Mcp::Tools::BaseTool }, suite_category: { type: 'string', - description: 'Nome/tipo da suíte (ex: "Master", "Luxo", "Mini Chalé 45"). Use quando o cliente pede pelo NOME da categoria.' + description: 'Nome/tipo da suíte conforme cadastro da unidade. Use quando o cliente pede pelo NOME da categoria.' }, suite_number: { type: 'string',