iachat/enterprise/app/services/captain/mcp/tools/add_label_tool.rb
Rodribm10 9ed3491d55 feat(captain/mcp): suite de 9 tools MCP + pricing tables Dolce Amore
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>
2026-05-01 20:13:16 -03:00

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