diff --git a/enterprise/app/models/concerns/agentable.rb b/enterprise/app/models/concerns/agentable.rb index 3515f0041..1c8c91ef9 100644 --- a/enterprise/app/models/concerns/agentable.rb +++ b/enterprise/app/models/concerns/agentable.rb @@ -1,52 +1,50 @@ module Concerns::Agentable extend ActiveSupport::Concern - included do - def agent - Agents::Agent.new( - name: agent_name, - instructions: ->(context) { agent_instructions(context) }, - tools: agent_tools, - model: agent_model + def agent + Agents::Agent.new( + name: agent_name, + instructions: ->(context) { agent_instructions(context) }, + tools: agent_tools, + model: agent_model + ) + end + + def agent_instructions(context = nil) + enhanced_context = prompt_context + + if context + state = context.context[:state] || {} + conversation_data = state[:conversation] || {} + contact_data = state[:contact] || {} + enhanced_context = enhanced_context.merge( + conversation: conversation_data, + contact: contact_data ) end - def agent_instructions(context = nil) - enhanced_context = prompt_context + Captain::PromptRenderer.render(template_name, enhanced_context.with_indifferent_access) + end - if context - state = context.context[:state] || {} - conversation_data = state[:conversation] || {} - contact_data = state[:contact] || {} - enhanced_context = enhanced_context.merge( - conversation: conversation_data, - contact: contact_data - ) - end + private - Captain::PromptRenderer.render(template_name, enhanced_context.with_indifferent_access) - end + def agent_name + raise NotImplementedError, "#{self.class} must implement agent_name" + end - private + def template_name + self.class.name.demodulize.underscore + end - def agent_name - raise NotImplementedError, "#{self.class} must implement agent_name" - end + def agent_tools + [] # Default implementation, override if needed + end - def template_name - self.class.name.demodulize.underscore - end + def agent_model + 'gpt-4.1-mini' + end - def agent_tools - [] # Default implementation, override if needed - end - - def agent_model - 'gpt-4.1-mini' - end - - def prompt_context - raise NotImplementedError, "#{self.class} must implement prompt_context" - end + def prompt_context + raise NotImplementedError, "#{self.class} must implement prompt_context" end end diff --git a/lib/chatwoot_exception_tracker.rb b/lib/chatwoot_exception_tracker.rb index d2879a08c..9d321e514 100644 --- a/lib/chatwoot_exception_tracker.rb +++ b/lib/chatwoot_exception_tracker.rb @@ -1,9 +1,3 @@ -############### -# One library to capture_exception and send to the specific service. -# # e as exception, u for user and a for account (user and account are optional) -# Usage: ChatwootExceptionTracker(e, user: u, account: a).capture_exception -############ - class ChatwootExceptionTracker def initialize(exception, user: nil, account: nil) @exception = exception @@ -12,12 +6,28 @@ class ChatwootExceptionTracker end def capture_exception + write_exception_to_file if Rails.env.development? capture_exception_with_sentry if ENV['SENTRY_DSN'].present? Rails.logger.error @exception end private + def write_exception_to_file + error_dir = Rails.root.join('errors') + FileUtils.mkdir_p(error_dir) + timestamp = Time.now.strftime('%Y%m%d-%H%M%S') + filename = "#{timestamp}-#{SecureRandom.hex(4)}.log" + filepath = error_dir.join(filename) + + File.open(filepath, 'w') do |file| + file.puts "Exception: #{@exception.class} - #{@exception.message}" + file.puts "User: #{@user&.id} (#{@user&.email})" if @user + file.puts "Account: #{@account&.id} (#{@account&.name})" if @account + file.puts "Backtrace:\n#{@exception.backtrace&.join("\n")}" + end + end + def capture_exception_with_sentry Sentry.with_scope do |scope| if @account.present?