fix(captain/mcp): tool descriptions sem exemplos motel-flavored + brand match
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) <noreply@anthropic.com>
This commit is contained in:
parent
ed21722dc4
commit
f0f8322cce
@ -130,11 +130,16 @@ class Captain::Mcp::Tools::SaveAgentSpecTool < Captain::Mcp::Tools::BaseTool
|
|||||||
def lookup_brand(parent, brand_name)
|
def lookup_brand(parent, brand_name)
|
||||||
return nil if parent.nil?
|
return nil if parent.nil?
|
||||||
|
|
||||||
if brand_name.present?
|
# Sempre prefere a brand do parent_unit (fonte de verdade — Construtor copiou
|
||||||
hit = Captain::Brand.where(account_id: parent.account_id).find { |b| brand_matches?(b.name, brand_name) }
|
# daquele agente). Spec.brand passado é só hint, pode estar errado/abreviado.
|
||||||
return hit if hit
|
parent_brand = parent.captain_unit&.brand || parent.captain_inboxes.first&.captain_unit&.brand
|
||||||
end
|
return parent_brand if parent_brand
|
||||||
parent.captain_inboxes.first&.captain_unit&.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
|
end
|
||||||
|
|
||||||
def parent_unit_for(parent)
|
def parent_unit_for(parent)
|
||||||
|
|||||||
@ -5,8 +5,10 @@
|
|||||||
# Captain::GalleryItem da inbox atual (com fallback pra acervo global) e
|
# Captain::GalleryItem da inbox atual (com fallback pra acervo global) e
|
||||||
# envia até `limit` imagens como mensagens outgoing na conversa.
|
# envia até `limit` imagens como mensagens outgoing na conversa.
|
||||||
#
|
#
|
||||||
# Search: aceita `suite_category` (ex: "Master", "Luxo") OU `suite_number`
|
# Search: aceita `suite_category` (nome da categoria configurada na unidade)
|
||||||
# (ex: "101"), mutuamente exclusivos. Match case-insensitive, fuzzy.
|
# 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
|
# Pré-requisito: cadastro do Captain::GalleryItem via painel UI do
|
||||||
# Chatwoot — Captain::Mcp não cria fotos, só consome o catálogo.
|
# 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
|
def description
|
||||||
'Envia fotos da suíte pra conversa do cliente. Use quando ele pedir foto/imagem ' \
|
'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 ' \
|
'("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 ' \
|
'global). Passe `suite_category` (nome da categoria conforme cadastro da unidade) ' \
|
||||||
'`suite_number` (ex: "101") — não combine os dois.'
|
'OU `suite_number` (ex: "101") — não combine os dois.'
|
||||||
end
|
end
|
||||||
|
|
||||||
def input_schema # rubocop:disable Metrics/MethodLength
|
def input_schema # rubocop:disable Metrics/MethodLength
|
||||||
@ -36,7 +38,7 @@ class Captain::Mcp::Tools::SendSuiteImagesTool < Captain::Mcp::Tools::BaseTool
|
|||||||
},
|
},
|
||||||
suite_category: {
|
suite_category: {
|
||||||
type: 'string',
|
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: {
|
suite_number: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user