diff --git a/enterprise/app/services/captain/assistant/agent_runner_service.rb b/enterprise/app/services/captain/assistant/agent_runner_service.rb index 193f6d3..e0d6f05 100755 --- a/enterprise/app/services/captain/assistant/agent_runner_service.rb +++ b/enterprise/app/services/captain/assistant/agent_runner_service.rb @@ -182,7 +182,7 @@ class Captain::Assistant::AgentRunnerService def build_and_wire_agents # In Delegation Mode, we only use the orchestrator agent. # The sub-agents (scenarios) are now dynamic tools of this agent. - [@assistant.agent] + [@assistant.agent(user: @conversation&.contact, conversation: @conversation)] end def sanitize_global_api_key diff --git a/enterprise/app/services/captain/tools/tool_runner.rb b/enterprise/app/services/captain/tools/tool_runner.rb index 851479a..32cbcb7 100644 --- a/enterprise/app/services/captain/tools/tool_runner.rb +++ b/enterprise/app/services/captain/tools/tool_runner.rb @@ -71,7 +71,7 @@ module Captain tool = Captain::Tools::ScenarioDelegatorTool.new(scenario, user: @contact, conversation: @conversation) # ScenarioDelegatorTool expects 'pergunta_interna' - params = { 'pergunta_interna' => @additional_data[:message] } + params = { pergunta_interna: @additional_data[:message] } execution_result = tool.execute(params) if execution_result.is_a?(String) diff --git a/enterprise/lib/captain/tools/base_public_tool.rb b/enterprise/lib/captain/tools/base_public_tool.rb index 10303fa..fe557f3 100755 --- a/enterprise/lib/captain/tools/base_public_tool.rb +++ b/enterprise/lib/captain/tools/base_public_tool.rb @@ -19,6 +19,13 @@ class Captain::Tools::BasePublicTool < Agents::Tool [] end + def execute(*args, **kwargs) + # Adapter for RubyLLM -> Agents::Tool compatibility + # RubyLLM calls execute(**params), Agents::Tool expects execute(input) + input = args.first || kwargs + super(input) + end + private def account_scoped(model_class) diff --git a/enterprise/lib/captain/tools/handoff_tool.rb b/enterprise/lib/captain/tools/handoff_tool.rb index 797f248..e43a8c7 100755 --- a/enterprise/lib/captain/tools/handoff_tool.rb +++ b/enterprise/lib/captain/tools/handoff_tool.rb @@ -31,7 +31,7 @@ class Captain::Tools::HandoffTool < Captain::Tools::BasePublicTool sender: @assistant, account: conversation.account, inbox: conversation.inbox, - content: reason + content: reason || 'Solicitação de atendimento humano' ) # Trigger the bot handoff (sets status to open + dispatches events) diff --git a/enterprise/lib/captain/tools/scenario_delegator_tool.rb b/enterprise/lib/captain/tools/scenario_delegator_tool.rb index 9425034..65a4331 100644 --- a/enterprise/lib/captain/tools/scenario_delegator_tool.rb +++ b/enterprise/lib/captain/tools/scenario_delegator_tool.rb @@ -18,7 +18,9 @@ module Captain::Tools param :pergunta_interna, type: 'string', desc: 'A pergunta ou instrução detalhada que você quer enviar para este departamento.' - def perform(_tool_context, pergunta_interna:) + def perform(_tool_context, args = {}) + pergunta_interna = args[:pergunta_interna] || args['pergunta_interna'] + # Instanciamos o agente do cenário, que já carrega suas próprias ferramentas (custom tools, etc) agent = @scenario.agent(user: @user, conversation: @conversation) diff --git a/scripts/debug_db_connection.rb b/scripts/debug_db_connection.rb new file mode 100644 index 0000000..7d72d0c --- /dev/null +++ b/scripts/debug_db_connection.rb @@ -0,0 +1,24 @@ +# scripts/debug_db_connection.rb +puts 'Loading Account...' +acc = Account.first +puts "Account Loaded: #{acc.name}" + +inbox = Inbox.find_by(name: 'Wuzapi') || Inbox.first +puts "Inbox: #{inbox.name}" + +assistant = Captain::Assistant.find_by(name: 'Jasmine') || Captain::Assistant.first +puts "Assistant: #{assistant.name}" + +unit = Captain::Unit.find_by(name: 'Unidade Ceilândia') || Captain::Unit.first +puts "Unit: #{unit.name}" + +puts "CaptainInbox table name: #{CaptainInbox.table_name}" +puts "Table 'captain_inboxes' exists? #{ActiveRecord::Base.connection.table_exists?('captain_inboxes')}" + +puts 'Trying a query on CaptainInbox...' +begin + puts "Count: #{CaptainInbox.count}" +rescue StandardError => e + puts "Error: #{e.message}" + puts e.backtrace +end diff --git a/scripts/test_real_pix_conversational.rb b/scripts/test_real_pix_conversational.rb new file mode 100644 index 0000000..4e440d9 --- /dev/null +++ b/scripts/test_real_pix_conversational.rb @@ -0,0 +1,93 @@ +# test_real_pix_conversational.rb +# usage: bundle exec rails runner scripts/test_real_pix_conversational.rb + +# 1. Setup Context +require Rails.root.join('enterprise/app/services/captain/llm/assistant_chat_service.rb') + +account = Account.first +inbox = Inbox.find_by(name: 'Wuzapi') || Inbox.first +assistant = Captain::Assistant.find_by(name: 'Jasmine') || Captain::Assistant.first +# Force use of ENV key if assistant key is likely invalid/old +puts "ENV Key suffix: #{ENV['OPENAI_API_KEY'].to_s[-4..-1]}" +assistant.api_key = ENV['OPENAI_API_KEY'] if ENV['OPENAI_API_KEY'].present? +assistant.save(validate: false) + +puts "Assistant Key (col) after: #{assistant.reload.api_key.to_s[-4..-1]}" + +unit = Captain::Unit.find_by(name: 'Unidade Ceilândia') || Captain::Unit.first + +puts '--- Context Setup ---' +puts "Account: #{account.name}" +puts "Inbox: #{inbox.name}" +puts "Assistant: #{assistant.name}" +puts "Unit: #{unit.name}" + +# Ensure Inbox has a Captain Unit for pricing to work +puts "CaptainInbox table: #{CaptainInbox.table_name}" +cc_inbox = CaptainInbox.find_or_initialize_by(inbox: inbox, assistant: assistant) +cc_inbox.unit = unit +cc_inbox.assistant = assistant +cc_inbox.save! + +# Ensure Contact Exists +contact = Contact.find_or_create_by!(name: 'Rodrigo Teste', phone_number: '+5561999999999', account: account) +puts "Contact: #{contact.name}" + +# Ensure ContactInbox exists +contact_inbox = ContactInbox.find_or_create_by!(contact: contact, inbox: inbox, source_id: contact.phone_number) + +# Ensure Conversation Exists +conversation = Conversation.create!( + account: account, + inbox: inbox, + contact: contact, + contact_inbox: contact_inbox, + status: :open +) +puts "Conversation ID: #{conversation.display_id}" + +# 2. Simulate User Interaction needing Sub-Agent +puts "\n--- Simulating User Request for Reservation ---" + +# Step A: User asks for reservation +msg1 = conversation.messages.create!( + content: 'Quero reservar a suíte stilo para quinta que vem', + account: account, + inbox: inbox, + message_type: :incoming, + sender: contact +) +puts "User: #{msg1.content}" + +# Step B: Run Jasmine (Process the message) +puts '--- Running Jasmine Brain ---' +puts "Captain constants: #{Captain.constants}" +begin + puts "Captain::LLM defined? #{defined?(Captain::LLM)}" +rescue StandardError + puts 'Captain::LLM not defined' +end +begin + puts "Captain::Llm defined? #{defined?(Captain::Llm)}" +rescue StandardError + puts 'Captain::Llm not defined' +end + +service = Captain::Llm::AssistantChatService.new(assistant: assistant, conversation: conversation) +puts "Service API Key resolved to: #{service.send(:api_key).to_s[-4..-1]}" + +response = service.generate_response(additional_message: msg1.content) + +puts "Jasmine Response: #{response}" + +if response.to_s.include?('dificuldades técnicas') + puts '❌ TEST FAILED: Agent returned technical error.' + exit 1 +elsif response.to_s.include?('transferir') || response.to_s.include?('encaminhar') + puts '⚠️ TEST WARNING: Agent triggered handoff (could be expected if tool failed silently or strictly).' +else + puts '✅ TEST PASSED: Agent responded without generic error.' +end + +# 3. Validation +# intended_result: sub-agent 'Daniela' should have run 'check_availability' successfully