refatorar: Unificar a resolução de contexto para ferramentas e mover a lógica do rótulo 'desligar_ia' do contato para a conversa.

This commit is contained in:
Rodrigo Borba 2026-01-15 17:24:28 -03:00
parent 445a7d663a
commit 975a4be7e4
8 changed files with 27 additions and 6 deletions

View File

@ -100,7 +100,6 @@ class Captain::Llm::AssistantChatService < Llm::BaseAiService
def handle_tool_side_effects(tool_key, conversation)
return unless tool_key == 'escalar_humano'
conversation.contact.add_labels(['desligar_ia'])
conversation.add_labels(['desligar_ia'])
conversation.custom_attributes['ai_disabled'] = true
conversation.save!

View File

@ -39,7 +39,7 @@ module Captain
private
def contact_has_disabled_label?
@contact.labels.exists?(name: 'desligar_ia')
@conversation.labels.exists?(name: 'desligar_ia')
rescue StandardError
false
end

View File

@ -25,6 +25,16 @@ class Captain::Tools::BaseTool < RubyLLM::Tool
actual_params.with_indifferent_access
end
def resolve_context(tool_context)
if tool_context.respond_to?(:state)
tool_context.state
elsif tool_context.is_a?(Hash)
tool_context
else
{}
end.with_indifferent_access
end
def active?
true
end

View File

@ -4,7 +4,7 @@ class Captain::Tools::AddContactNoteTool < Captain::Tools::BasePublicTool
def perform(tool_context, args = {})
note = args[:note] || args['note']
contact = find_contact(tool_context.state)
contact = find_contact(resolve_context(tool_context))
return 'Contact not found' unless contact
return 'Note content is required' if note.blank?

View File

@ -4,7 +4,7 @@ class Captain::Tools::AddLabelToConversationTool < Captain::Tools::BasePublicToo
def perform(tool_context, args = {})
label_name = args[:label_name] || args['label_name']
conversation = find_conversation(tool_context.state)
conversation = find_conversation(resolve_context(tool_context))
return 'Conversation not found' unless conversation
label_name = label_name&.strip&.downcase

View File

@ -4,7 +4,7 @@ class Captain::Tools::AddPrivateNoteTool < Captain::Tools::BasePublicTool
def perform(tool_context, args = {})
note = args[:note] || args['note']
conversation = find_conversation(tool_context.state)
conversation = find_conversation(resolve_context(tool_context))
return 'Conversation not found' unless conversation
return 'Note content is required' if note.blank?

View File

@ -39,6 +39,18 @@ class Captain::Tools::BasePublicTool < Agents::Tool
end.with_indifferent_access
end
def resolve_context(tool_context)
# Handle the case where tool_context is a Hash (Agents gem / Sub-agents)
# or an Object with a state reader (RubyLLM / Main Agent)
if tool_context.respond_to?(:state)
tool_context.state
elsif tool_context.is_a?(Hash)
tool_context
else
{}
end.with_indifferent_access
end
private
def account_scoped(model_class)

View File

@ -4,7 +4,7 @@ class Captain::Tools::UpdatePriorityTool < Captain::Tools::BasePublicTool
def perform(tool_context, args = {})
priority = args[:priority] || args['priority']
@conversation = find_conversation(tool_context.state)
@conversation = find_conversation(resolve_context(tool_context))
return 'Conversation not found' unless @conversation
@normalized_priority = normalize_priority(priority)