Tools novas em enterprise/app/services/captain/mcp/tools/: - generate_pix: Pix Inter via PricingTable + fallback link reserva-1001 - check_pix_payment: consulta Inter + dispara ConfirmationService - send_suite_images: fotos da galeria (Captain::GalleryItem) via wuzapi - reschedule_reservation: remarca reserva (regra 3h antecedência Dolce) - update_contact: persiste nome/CPF/email/notas no Contact - get_contact_history: markdown do histórico do cliente on-demand - react_to_message: reage com emoji via wuzapi (is_reaction=true) Captain::Mcp::PricingTables: tabela hardcoded Dolce Amore (8 categorias x 4 periodos + regras de pessoa extra). Backend e fonte de verdade — LLM nao inventa preco. add_label_tool: cria Label oficial automaticamente se nao existir, aceita conversation_id em arguments. mcp_controller: aceita X-Captain-Account-Id/Assistant-Id/Inbox-Id como fallback de contexto. tool_registry: 9 tools ativas. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 lines
2.9 KiB
Ruby
83 lines
2.9 KiB
Ruby
# Tool MCP: adiciona uma etiqueta na conversation atual.
|
|
#
|
|
# Caso de uso: Hermes detecta cliente recorrente / VIP / situação especial
|
|
# e quer marcar a conversa pro time humano filtrar depois.
|
|
#
|
|
# Exemplos de uso pelo LLM:
|
|
# - "marca como cliente_recorrente"
|
|
# - "etiqueta como pedido_desconto"
|
|
class Captain::Mcp::Tools::AddLabelTool < Captain::Mcp::Tools::BaseTool
|
|
class << self
|
|
def name
|
|
'add_label'
|
|
end
|
|
|
|
def description
|
|
'Adiciona uma etiqueta (label) à conversa atual do cliente. ' \
|
|
'Use pra marcar contexto importante: cliente_recorrente, pedido_desconto, ' \
|
|
'reclamacao, vip, etc. A etiqueta deve ser snake_case curto.'
|
|
end
|
|
|
|
def input_schema
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
label: {
|
|
type: 'string',
|
|
description: 'Nome da etiqueta em snake_case (ex: "cliente_recorrente").'
|
|
},
|
|
conversation_id: {
|
|
type: 'integer',
|
|
description: 'ID interno da conversa (cid) que aparece em [ctx: cid=N] no início da mensagem do cliente. Obrigatório.'
|
|
}
|
|
},
|
|
required: %w[label conversation_id]
|
|
}
|
|
end
|
|
end
|
|
|
|
def call(args, context:)
|
|
label = args['label'].to_s.strip.downcase
|
|
return error_response('Argumento "label" é obrigatório.') if label.blank?
|
|
|
|
conversation = resolve_conversation(args, context)
|
|
return error_response('Conversation atual não encontrada. Passe conversation_id em arguments (cid do [ctx]).') if conversation.blank?
|
|
|
|
ensure_account_label!(conversation.account, label)
|
|
conversation.add_labels([label])
|
|
text_response("Etiqueta '#{label}' adicionada à conversa #{conversation.display_id}.")
|
|
rescue StandardError => e
|
|
Rails.logger.error("[Captain::Mcp::AddLabelTool] error: #{e.class}: #{e.message}")
|
|
error_response("Falha ao adicionar etiqueta: #{e.message}")
|
|
end
|
|
|
|
private
|
|
|
|
# LLM passa conversation_id em arguments (lendo do [ctx: cid=N]).
|
|
# Context (header/body) fica como fallback caso algum dia o cliente MCP
|
|
# passe a propagar contexto automaticamente.
|
|
def resolve_conversation(args, context)
|
|
conv_id = args['conversation_id'].presence ||
|
|
context[:conversation_internal_id] ||
|
|
context[:conversation_id]
|
|
return nil if conv_id.blank?
|
|
|
|
Conversation.find_by(id: conv_id) || Conversation.find_by(display_id: conv_id)
|
|
end
|
|
|
|
# Conversation#add_labels só salva a tag via acts_as_taggable. Pra a label
|
|
# aparecer no sidebar/dropdown da UI do Chatwoot, ela precisa existir como
|
|
# registro oficial em account.labels (model Label). Se não existir, criamos
|
|
# com cor neutra — gerência pode ajustar depois pelo painel.
|
|
def ensure_account_label!(account, title)
|
|
return if account.labels.exists?(title: title)
|
|
|
|
account.labels.create!(
|
|
title: title,
|
|
description: 'Criada automaticamente via MCP (Hermes Agent)',
|
|
color: '#5C7CFA',
|
|
show_on_sidebar: true
|
|
)
|
|
end
|
|
end
|