refactor: Extrai lógica para métodos auxiliares em MessageBuilder e Jasmine::PlaygroundController e ajusta formatação.
This commit is contained in:
parent
b80d35a307
commit
a392d81f06
2
Gemfile
2
Gemfile
@ -271,4 +271,4 @@ group :development, :test do
|
||||
gem 'spring-watcher-listen'
|
||||
end
|
||||
|
||||
gem "rqrcode", "~> 3.2"
|
||||
gem 'rqrcode', '~> 3.2'
|
||||
|
||||
@ -51,16 +51,14 @@ class Messages::MessageBuilder
|
||||
file: uploaded_attachment
|
||||
)
|
||||
|
||||
attachment.file_type = if uploaded_attachment.is_a?(String)
|
||||
file_type_by_signed_id(
|
||||
uploaded_attachment
|
||||
)
|
||||
else
|
||||
file_type(uploaded_attachment&.content_type)
|
||||
end
|
||||
attachment.file_type = resolve_file_type(uploaded_attachment)
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_file_type(attachment)
|
||||
attachment.is_a?(String) ? file_type_by_signed_id(attachment) : file_type(attachment&.content_type)
|
||||
end
|
||||
|
||||
def process_emails
|
||||
return unless @conversation.inbox&.inbox_type == 'Email'
|
||||
|
||||
@ -222,11 +220,18 @@ class Messages::MessageBuilder
|
||||
@private = @params[:private] || false
|
||||
@message_type = @params[:message_type] || 'outgoing'
|
||||
@attachments = @params[:attachments]
|
||||
@automation_rule = content_attributes&.dig(:automation_rule_id)
|
||||
# Try to find in_reply_to in params (top level) or content_attributes
|
||||
@in_reply_to = @params[:in_reply_to_id] || @params[:in_reply_to] || content_attributes&.dig(:in_reply_to)
|
||||
@automation_rule = extract_automation_rule
|
||||
@in_reply_to = extract_in_reply_to
|
||||
@items = content_attributes&.dig(:items)
|
||||
end
|
||||
|
||||
def extract_automation_rule
|
||||
content_attributes&.dig(:automation_rule_id)
|
||||
end
|
||||
|
||||
def extract_in_reply_to
|
||||
@params[:in_reply_to_id] || @params[:in_reply_to] || content_attributes&.dig(:in_reply_to)
|
||||
end
|
||||
end
|
||||
|
||||
Messages::MessageBuilder.prepend_mod_with('Messages::MessageBuilder')
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
module Api
|
||||
module V1
|
||||
module Accounts
|
||||
class FrequentQuestionsController < Api::V1::Accounts::BaseController
|
||||
def index
|
||||
@frequent_questions = Current.account.frequent_questions.order(occurrence_count: :desc).limit(50)
|
||||
end
|
||||
end
|
||||
end
|
||||
class Api::V1::Accounts::FrequentQuestionsController < Api::V1::Accounts::BaseController
|
||||
def index
|
||||
@frequent_questions = Current.account.frequent_questions.order(occurrence_count: :desc).limit(50)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,43 +1,33 @@
|
||||
module Api
|
||||
module V1
|
||||
module Accounts
|
||||
module Inboxes
|
||||
module Jasmine
|
||||
class CollectionsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
class Api::V1::Accounts::Inboxes::Jasmine::CollectionsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
|
||||
def index
|
||||
# Returns collections linked to this inbox
|
||||
collection_ids = @inbox.inbox_collections.pluck(:collection_id)
|
||||
@collections = Current.account.jasmine_collections.where(id: collection_ids)
|
||||
render json: @collections
|
||||
end
|
||||
def index
|
||||
# Returns collections linked to this inbox
|
||||
collection_ids = @inbox.inbox_collections.pluck(:collection_id)
|
||||
@collections = Current.account.jasmine_collections.where(id: collection_ids)
|
||||
render json: @collections
|
||||
end
|
||||
|
||||
def create
|
||||
# Link an existing collection to this inbox
|
||||
collection = Current.account.jasmine_collections.find(params[:collection_id])
|
||||
link = @inbox.inbox_collections.create!(
|
||||
collection: collection,
|
||||
priority: params[:priority] || 0
|
||||
)
|
||||
render json: link
|
||||
end
|
||||
def create
|
||||
# Link an existing collection to this inbox
|
||||
collection = Current.account.jasmine_collections.find(params[:collection_id])
|
||||
link = @inbox.inbox_collections.create!(
|
||||
collection: collection,
|
||||
priority: params[:priority] || 0
|
||||
)
|
||||
render json: link
|
||||
end
|
||||
|
||||
def destroy
|
||||
# Unlink a collection from this inbox
|
||||
link = @inbox.inbox_collections.find_by!(collection_id: params[:id])
|
||||
link.destroy!
|
||||
head :no_content
|
||||
end
|
||||
def destroy
|
||||
# Unlink a collection from this inbox
|
||||
link = @inbox.inbox_collections.find_by!(collection_id: params[:id])
|
||||
link.destroy!
|
||||
head :no_content
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,53 +1,43 @@
|
||||
module Api
|
||||
module V1
|
||||
module Accounts
|
||||
module Inboxes
|
||||
module Jasmine
|
||||
class ConfigsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
before_action :fetch_or_initialize_config
|
||||
class Api::V1::Accounts::Inboxes::Jasmine::ConfigsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
before_action :fetch_or_initialize_config
|
||||
|
||||
def show
|
||||
render json: @config
|
||||
end
|
||||
def show
|
||||
render json: @config
|
||||
end
|
||||
|
||||
def update
|
||||
if @config.update(config_params)
|
||||
render json: @config
|
||||
else
|
||||
render json: { error: @config.errors.full_messages.join(', ') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
|
||||
def fetch_or_initialize_config
|
||||
@config = ::Jasmine::InboxConfig.find_or_initialize_by(
|
||||
account: Current.account,
|
||||
inbox: @inbox
|
||||
)
|
||||
end
|
||||
|
||||
def config_params
|
||||
params.permit(
|
||||
:is_enabled,
|
||||
:system_prompt,
|
||||
:playbook_prompt,
|
||||
:model,
|
||||
:temperature,
|
||||
:rag_distance_threshold,
|
||||
:rag_max_results,
|
||||
:mode,
|
||||
intent_keywords: {}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
def update
|
||||
if @config.update(config_params)
|
||||
render json: @config
|
||||
else
|
||||
render json: { error: @config.errors.full_messages.join(', ') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
|
||||
def fetch_or_initialize_config
|
||||
@config = ::Jasmine::InboxConfig.find_or_initialize_by(
|
||||
account: Current.account,
|
||||
inbox: @inbox
|
||||
)
|
||||
end
|
||||
|
||||
def config_params
|
||||
params.permit(
|
||||
:is_enabled,
|
||||
:system_prompt,
|
||||
:playbook_prompt,
|
||||
:model,
|
||||
:temperature,
|
||||
:rag_distance_threshold,
|
||||
:rag_max_results,
|
||||
:mode,
|
||||
intent_keywords: {}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,85 +1,75 @@
|
||||
module Api
|
||||
module V1
|
||||
module Accounts
|
||||
module Inboxes
|
||||
module Jasmine
|
||||
class PlaygroundController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
before_action :fetch_config
|
||||
class Api::V1::Accounts::Inboxes::Jasmine::PlaygroundController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
before_action :fetch_config
|
||||
|
||||
def test
|
||||
message_content = params[:message]
|
||||
|
||||
return render json: { error: 'Message is required' }, status: :bad_request if message_content.blank?
|
||||
return render json: { error: 'Jasmine is not enabled for this inbox' }, status: :unprocessable_entity unless @config&.is_enabled?
|
||||
def test
|
||||
return render json: { error: 'Message is required' }, status: :bad_request if params[:message].blank?
|
||||
return render json: { error: 'Jasmine is not enabled for this inbox' }, status: :unprocessable_entity unless @config&.is_enabled?
|
||||
|
||||
# Create a mock message object for BrainService
|
||||
mock_message = OpenStruct.new(
|
||||
content: message_content,
|
||||
inbox: @inbox,
|
||||
conversation: mock_conversation
|
||||
)
|
||||
begin
|
||||
response = generate_response(params[:message])
|
||||
render json: build_success_payload(response)
|
||||
rescue StandardError => e
|
||||
handle_error(e)
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
response = ::Jasmine::BrainService.new(
|
||||
inbox: @inbox,
|
||||
conversation: mock_conversation,
|
||||
message: mock_message
|
||||
).respond
|
||||
private
|
||||
|
||||
render json: {
|
||||
response: response,
|
||||
debug: {
|
||||
model: @config.model,
|
||||
temperature: @config.temperature,
|
||||
rag_threshold: @config.rag_distance_threshold
|
||||
}
|
||||
}
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[Jasmine::Playground] Error: #{e.message}\n#{e.backtrace.first(5).join("\n")}"
|
||||
render json: { error: e.message }, status: :internal_server_error
|
||||
end
|
||||
end
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
|
||||
private
|
||||
def fetch_config
|
||||
@config = ::Jasmine::InboxConfig.find_by(
|
||||
account: Current.account,
|
||||
inbox: @inbox
|
||||
)
|
||||
end
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
def generate_response(content)
|
||||
# Create a mock message object for BrainService
|
||||
mock_message = OpenStruct.new(content: content, inbox: @inbox, conversation: mock_conversation)
|
||||
::Jasmine::BrainService.new(inbox: @inbox, conversation: mock_conversation, message: mock_message).respond
|
||||
end
|
||||
|
||||
def fetch_config
|
||||
@config = ::Jasmine::InboxConfig.find_by(
|
||||
account: Current.account,
|
||||
inbox: @inbox
|
||||
)
|
||||
end
|
||||
def build_success_payload(response)
|
||||
{
|
||||
response: response,
|
||||
debug: {
|
||||
model: @config.model,
|
||||
temperature: @config.temperature,
|
||||
rag_threshold: @config.rag_distance_threshold
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def mock_conversation
|
||||
# Create a minimal mock conversation for playground testing
|
||||
@mock_conversation ||= begin
|
||||
mock = OpenStruct.new(
|
||||
id: 0,
|
||||
account_id: Current.account.id,
|
||||
inbox_id: @inbox.id,
|
||||
custom_attributes: { 'jasmine_state' => {} }
|
||||
)
|
||||
|
||||
# Mock messages method to return empty array that responds to query methods
|
||||
def mock.messages
|
||||
[]
|
||||
end
|
||||
|
||||
# Mock update! to do nothing (playground doesn't need state persistence)
|
||||
def mock.update!(**attrs)
|
||||
# no-op for playground
|
||||
end
|
||||
|
||||
mock
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
def handle_error(err)
|
||||
Rails.logger.error "[Jasmine::Playground] Error: #{err.message}\n#{err.backtrace.first(5).join("\n")}"
|
||||
render json: { error: err.message }, status: :internal_server_error
|
||||
end
|
||||
|
||||
def mock_conversation
|
||||
# Create a minimal mock conversation for playground testing
|
||||
@mock_conversation ||= begin
|
||||
mock = OpenStruct.new(
|
||||
id: 0,
|
||||
account_id: Current.account.id,
|
||||
inbox_id: @inbox.id,
|
||||
custom_attributes: { 'jasmine_state' => {} }
|
||||
)
|
||||
|
||||
# Mock messages method to return empty array that responds to query methods
|
||||
def mock.messages
|
||||
[]
|
||||
end
|
||||
|
||||
# Mock update! to do nothing (playground doesn't need state persistence)
|
||||
def mock.update!(**attrs)
|
||||
# no-op for playground
|
||||
end
|
||||
|
||||
mock
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,93 +1,90 @@
|
||||
module Api
|
||||
module V1
|
||||
module Accounts
|
||||
module Inboxes
|
||||
module Jasmine
|
||||
class ToolsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
class Api::V1::Accounts::Inboxes::Jasmine::ToolsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
|
||||
def index
|
||||
configs = ::Jasmine::ToolConfig.where(inbox: @inbox).index_by(&:tool_key)
|
||||
|
||||
tools = ::Jasmine::ToolConfig::DEFINITIONS.map do |key, definition|
|
||||
config = configs[key]
|
||||
{
|
||||
key: key,
|
||||
name: definition[:name],
|
||||
method: definition[:method].to_s.upcase,
|
||||
url: definition[:url],
|
||||
description: definition[:description],
|
||||
is_enabled: config&.is_enabled || false,
|
||||
plug_play_id: config&.plug_play_id,
|
||||
plug_play_token: config&.plug_play_token.present? ? '****' : nil,
|
||||
last_test: config ? {
|
||||
at: config.last_tested_at,
|
||||
status: config.last_test_status,
|
||||
error: config.last_test_error,
|
||||
duration: config.last_test_duration_ms
|
||||
} : nil
|
||||
}
|
||||
end
|
||||
def index
|
||||
configs = ::Jasmine::ToolConfig.where(inbox: @inbox).index_by(&:tool_key)
|
||||
render json: serialize_tools(configs)
|
||||
end
|
||||
|
||||
render json: tools
|
||||
end
|
||||
def update
|
||||
return render(json: { error: 'Invalid tool key' }, status: :bad_request) unless valid_tool_key?(params[:id])
|
||||
|
||||
def update
|
||||
tool_key = params[:id] # Using :id from route as tool_key
|
||||
|
||||
unless ::Jasmine::ToolConfig::DEFINITIONS.key?(tool_key)
|
||||
return render json: { error: 'Invalid tool key' }, status: :bad_request
|
||||
end
|
||||
config = find_config(params[:id])
|
||||
update_config_attributes(config)
|
||||
|
||||
config = ::Jasmine::ToolConfig.find_or_initialize_by(
|
||||
account: Current.account,
|
||||
inbox: @inbox,
|
||||
tool_key: tool_key
|
||||
)
|
||||
|
||||
# Update attributes
|
||||
config.is_enabled = params[:is_enabled]
|
||||
config.plug_play_id = params[:plug_play_id]
|
||||
|
||||
# Secure token update: only update if present and not masked/empty
|
||||
new_token = params[:plug_play_token]
|
||||
if new_token.present? && new_token != '****'
|
||||
config.plug_play_token = new_token
|
||||
end
|
||||
|
||||
if config.save
|
||||
render json: {
|
||||
key: config.tool_key,
|
||||
is_enabled: config.is_enabled,
|
||||
plug_play_id: config.plug_play_id,
|
||||
plug_play_token: '****'
|
||||
}
|
||||
else
|
||||
render json: { error: config.errors.full_messages.join(', ') }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def test
|
||||
tool_key = params[:id]
|
||||
|
||||
begin
|
||||
runner = ::Jasmine::ToolRunner.new(@inbox, tool_key)
|
||||
result = runner.run
|
||||
render json: result
|
||||
rescue => e
|
||||
Rails.logger.error "[JasmineTools] Test failed: #{e.try(:message)}"
|
||||
render json: { success: false, error: "Server Error: #{e.try(:message)}" }, status: :internal_server_error
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if config.save
|
||||
render json: success_payload(config)
|
||||
else
|
||||
render(json: { error: config.errors.full_messages.join(', ') }, status: :unprocessable_entity)
|
||||
end
|
||||
end
|
||||
|
||||
def test
|
||||
tool_key = params[:id]
|
||||
|
||||
begin
|
||||
runner = ::Jasmine::ToolRunner.new(@inbox, tool_key)
|
||||
result = runner.run
|
||||
render json: result
|
||||
rescue StandardError => e
|
||||
Rails.logger.error "[JasmineTools] Test failed: #{e.try(:message)}"
|
||||
render json: { success: false, error: "Server Error: #{e.try(:message)}" }, status: :internal_server_error
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
|
||||
def valid_tool_key?(key)
|
||||
::Jasmine::ToolConfig::DEFINITIONS.key?(key)
|
||||
end
|
||||
|
||||
def find_config(key)
|
||||
::Jasmine::ToolConfig.find_or_initialize_by(account: Current.account, inbox: @inbox, tool_key: key)
|
||||
end
|
||||
|
||||
def update_config_attributes(config)
|
||||
config.is_enabled = params[:is_enabled]
|
||||
config.plug_play_id = params[:plug_play_id]
|
||||
new_token = params[:plug_play_token]
|
||||
config.plug_play_token = new_token if new_token.present? && new_token != '****'
|
||||
end
|
||||
|
||||
def success_payload(config)
|
||||
{ key: config.tool_key, is_enabled: config.is_enabled, plug_play_id: config.plug_play_id, plug_play_token: '****' }
|
||||
end
|
||||
|
||||
def serialize_tools(configs)
|
||||
::Jasmine::ToolConfig::DEFINITIONS.map do |key, definition|
|
||||
build_tool_hash(key, definition, configs[key])
|
||||
end
|
||||
end
|
||||
|
||||
def build_tool_hash(key, definition, config)
|
||||
{
|
||||
key: key,
|
||||
name: definition[:name],
|
||||
method: definition[:method].to_s.upcase,
|
||||
url: definition[:url],
|
||||
description: definition[:description],
|
||||
is_enabled: config&.is_enabled || false,
|
||||
plug_play_id: config&.plug_play_id,
|
||||
plug_play_token: config&.plug_play_token.present? ? '****' : nil,
|
||||
last_test: serialize_last_test(config)
|
||||
}
|
||||
end
|
||||
|
||||
def serialize_last_test(config)
|
||||
return unless config
|
||||
|
||||
{
|
||||
at: config.last_tested_at,
|
||||
status: config.last_test_status,
|
||||
error: config.last_test_error,
|
||||
duration: config.last_test_duration_ms
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
47
progresso/2026-01-25_correcao_lint_backend.md
Normal file
47
progresso/2026-01-25_correcao_lint_backend.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Correção de Lint e Refatoração Backend
|
||||
|
||||
## Contexto
|
||||
|
||||
Ocorreram diversos erros de Lint (RuboCop) no backend, bloqueando o CI/CD ou a qualidade do código. Os principais arquivos afetados foram `MessageBuilder` e `ToolsController`.
|
||||
|
||||
## Ações Realizadas
|
||||
|
||||
### 1. Refatoração `MessageBuilder` (`app/builders/messages/message_builder.rb`)
|
||||
|
||||
- **Problema:** Classe muito longa (`Metrics/ClassLength`) e complexidade ciclomática alta.
|
||||
- **Solução:**
|
||||
- Lógica de `file_type` extraída para método auxiliar `resolve_file_type`.
|
||||
- Métodos `extract_automation_rule`, `extract_in_reply_to` e `should_process_liquid?` compactados (one-liners).
|
||||
- Redução geral de linhas e complexidade.
|
||||
|
||||
### 2. Refatoração `ToolsController` (`app/controllers/api/v1/accounts/inboxes/jasmine/tools_controller.rb`)
|
||||
|
||||
- **Problema:** Métodos longos (`Metrics/MethodLength`) e complexos (`Metrics/AbcSize`).
|
||||
- **Solução:**
|
||||
- Extração da validação de chave para `valid_tool_key?`.
|
||||
- Extração da busca de config para `find_config`.
|
||||
- Extração da atualização de atributos para `update_config_attributes`.
|
||||
- Extração da serialização de resposta para `success_payload`, `build_tool_hash` e `serialize_last_test`.
|
||||
- Correção de `Style/EmptyElse`.
|
||||
|
||||
### 3. Correções Gerais
|
||||
|
||||
- **Specs (`whatsapp_spec.rb`, `contact_spec.rb`):** Quebra de comentários longos para satisfazer `Layout/LineLength`.
|
||||
- **StringLiterals:** Padronização para aspas simples.
|
||||
- **ClassAndModuleChildren:** Formato compacto adotado onde necessário.
|
||||
|
||||
## Validação
|
||||
|
||||
- **RuboCop:** 0 ofensas.
|
||||
- **RSpec:** 0 falhas nos testes unitários das classes afetadas.
|
||||
|
||||
## Como Reverter
|
||||
|
||||
Checkouts nos arquivos originais:
|
||||
|
||||
```bash
|
||||
git checkout app/builders/messages/message_builder.rb
|
||||
git checkout app/controllers/api/v1/accounts/inboxes/jasmine/tools_controller.rb
|
||||
git checkout spec/models/channel/whatsapp_spec.rb
|
||||
git checkout spec/models/contact_spec.rb
|
||||
```
|
||||
@ -2,7 +2,7 @@ FactoryBot.define do
|
||||
factory :jasmine_inbox_config, class: 'Jasmine::InboxConfig' do
|
||||
association :account
|
||||
association :inbox
|
||||
name { "Test Jasmine" }
|
||||
name { 'Test Jasmine' }
|
||||
is_enabled { true }
|
||||
end
|
||||
|
||||
@ -10,7 +10,7 @@ FactoryBot.define do
|
||||
association :account
|
||||
sequence(:name) { |n| "Collection #{n}" }
|
||||
visibility { :private }
|
||||
|
||||
|
||||
trait :private do
|
||||
visibility { :private }
|
||||
association :owner_inbox, factory: :inbox
|
||||
@ -32,6 +32,6 @@ FactoryBot.define do
|
||||
factory :jasmine_document, class: 'Jasmine::Document' do
|
||||
association :account
|
||||
association :collection, factory: :jasmine_collection
|
||||
content { "Sample Content" }
|
||||
content { 'Sample Content' }
|
||||
end
|
||||
end
|
||||
|
||||
@ -22,7 +22,8 @@
|
||||
# Indexes
|
||||
#
|
||||
# index_channel_whatsapp_on_phone_number (phone_number) UNIQUE
|
||||
# index_channel_whatsapp_provider_connection (provider_connection) WHERE ((provider)::text = ANY ((ARRAY['baileys'::character varying, 'zapi'::character varying])::text[])) USING gin
|
||||
# index_channel_whatsapp_provider_connection (provider_connection)
|
||||
# WHERE ((provider)::text = ANY ((ARRAY['baileys'::character varying, 'zapi'::character varying])::text[])) USING gin
|
||||
#
|
||||
require 'rails_helper'
|
||||
require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb'
|
||||
|
||||
@ -32,9 +32,11 @@
|
||||
# index_contacts_on_company_id (company_id)
|
||||
# index_contacts_on_lower_email_account_id (lower((email)::text), account_id)
|
||||
# index_contacts_on_name_email_phone_number_identifier (name,email,phone_number,identifier) USING gin
|
||||
# index_contacts_on_nonempty_fields (account_id,email,phone_number,identifier) WHERE (((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))
|
||||
# index_contacts_on_nonempty_fields (account_id,email,phone_number,identifier)
|
||||
# WHERE (((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))
|
||||
# index_contacts_on_phone_number_and_account_id (phone_number,account_id)
|
||||
# index_resolved_contact_account_id (account_id) WHERE (((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))
|
||||
# index_resolved_contact_account_id (account_id)
|
||||
# WHERE (((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))
|
||||
# uniq_email_per_account_contact (email,account_id) UNIQUE
|
||||
# uniq_identifier_per_account_contact (identifier,account_id) UNIQUE
|
||||
#
|
||||
|
||||
@ -32,11 +32,11 @@ RSpec.describe Jasmine::InboxCollection do
|
||||
let!(:account) { create(:account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let!(:other_inbox) { create(:inbox, account: account) }
|
||||
|
||||
|
||||
let!(:private_coll) { create(:jasmine_collection, :private, owner_inbox: inbox, account: account) }
|
||||
let!(:shared_coll) { create(:jasmine_collection, :shared, account: account) }
|
||||
|
||||
context 'validations' do
|
||||
context 'when linking collections' do
|
||||
it 'allows linking private collection to owner inbox' do
|
||||
link = build(:jasmine_inbox_collection, inbox: inbox, collection: private_coll, account: account)
|
||||
expect(link).to be_valid
|
||||
@ -45,7 +45,7 @@ RSpec.describe Jasmine::InboxCollection do
|
||||
it 'prevents linking private collection to non-owner inbox' do
|
||||
link = build(:jasmine_inbox_collection, inbox: other_inbox, collection: private_coll, account: account)
|
||||
expect(link).not_to be_valid
|
||||
expect(link.errors[:base]).to include("Private collections can only be linked to their owner inbox")
|
||||
expect(link.errors[:base]).to include('Private collections can only be linked to their owner inbox')
|
||||
end
|
||||
|
||||
it 'allows linking shared collection to any inbox in account' do
|
||||
|
||||
@ -3,19 +3,15 @@ require 'rails_helper'
|
||||
RSpec.describe Jasmine::SemanticSearchService do
|
||||
subject { described_class.new(inbox) }
|
||||
|
||||
let!(:account) { create(:account) }
|
||||
let!(:inbox) { create(:inbox, account: account) }
|
||||
let!(:config) { create(:jasmine_inbox_config, inbox: inbox, account: account, is_enabled: true) }
|
||||
let(:account) { create(:account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:config) { create(:jasmine_inbox_config, inbox: inbox, account: account, is_enabled: true) }
|
||||
|
||||
let!(:collection_private) { create(:jasmine_collection, name: 'Private', visibility: :private, owner_inbox: inbox, account: account) }
|
||||
let!(:collection_shared) { create(:jasmine_collection, name: 'Shared', visibility: :shared, account: account) }
|
||||
let(:collection_private) { create(:jasmine_collection, name: 'Private', visibility: :private, owner_inbox: inbox, account: account) }
|
||||
let(:collection_shared) { create(:jasmine_collection, name: 'Shared', visibility: :shared, account: account) }
|
||||
|
||||
# Link collections: Private (High Priority), Shared (Low Priority)
|
||||
let!(:link_private) { create(:jasmine_inbox_collection, inbox: inbox, collection: collection_private, priority: 10, account: account) }
|
||||
let!(:link_shared) { create(:jasmine_inbox_collection, inbox: inbox, collection: collection_shared, priority: 0, account: account) }
|
||||
|
||||
let!(:doc_private) { create(:jasmine_document, collection: collection_private, content: 'Private Secret', account: account) }
|
||||
let!(:doc_shared) { create(:jasmine_document, collection: collection_shared, content: 'Shared Knowledge', account: account) }
|
||||
let(:doc_private) { create(:jasmine_document, collection: collection_private, content: 'Private Secret', account: account) }
|
||||
let(:doc_shared) { create(:jasmine_document, collection: collection_shared, content: 'Shared Knowledge', account: account) }
|
||||
|
||||
# Mock Embedding Service behavior by creating chunks directly with known vectors
|
||||
# Query Vector: [1.0, 0.0, ...]
|
||||
@ -24,6 +20,19 @@ RSpec.describe Jasmine::SemanticSearchService do
|
||||
# Irrelevant: [0.0, 1.0, ...] -> Distance ~1.0
|
||||
|
||||
before do
|
||||
# Ensure all `let` variables are initialized
|
||||
account
|
||||
inbox
|
||||
config
|
||||
collection_private
|
||||
collection_shared
|
||||
doc_private
|
||||
doc_shared
|
||||
|
||||
# Link collections
|
||||
create(:jasmine_inbox_collection, inbox: inbox, collection: collection_private, priority: 10, account: account)
|
||||
create(:jasmine_inbox_collection, inbox: inbox, collection: collection_shared, priority: 0, account: account)
|
||||
|
||||
# Create chunks manually to bypass job/api dependency
|
||||
create_chunk(doc_private, [0.9] + ([0.0]*1535))
|
||||
create_chunk(doc_shared, [0.8] + ([0.0]*1535))
|
||||
|
||||
@ -1,22 +1,21 @@
|
||||
# test_multi_agent_flow.rb
|
||||
assistant = Captain::Assistant.find_by(name: 'Jasmine (Hotel Prime)')
|
||||
account = assistant.account
|
||||
|
||||
def simulate_handoff(assistant, user_msg)
|
||||
puts "\n=========================================================="
|
||||
puts "USUÁRIO: #{user_msg}"
|
||||
|
||||
|
||||
# Usando o motor Multi-Agente (V2) sem conversation real para o Playground
|
||||
runner = Captain::Assistant::AgentRunnerService.new(assistant: assistant)
|
||||
|
||||
|
||||
# Capturando o resultado do motor
|
||||
result = runner.generate_response(message_history: [{ role: 'user', content: user_msg }])
|
||||
|
||||
|
||||
puts "AGENTE QUE RESPONDEU: #{result['agent_name']}"
|
||||
puts "RESPOSTA FINAL: #{result['response']}"
|
||||
puts "RACIOCÍNIO: #{result['reasoning']}"
|
||||
puts "SENTIMENTO: #{result['sentiment']}"
|
||||
puts "=========================================================="
|
||||
puts '=========================================================='
|
||||
end
|
||||
|
||||
simulate_handoff(assistant, "Gostaria de agendar um quarto para amanhã às 22h")
|
||||
simulate_handoff(assistant, 'Gostaria de agendar um quarto para amanhã às 22h')
|
||||
|
||||
@ -12,7 +12,6 @@ if channel
|
||||
puts 'Updating existing channel...'
|
||||
channel.phone_number = phone_number
|
||||
channel.provider_config['webhook_url'] = webhook_url
|
||||
channel.save(validate: false)
|
||||
else
|
||||
puts 'Creating new channel...'
|
||||
account = Account.first
|
||||
@ -26,8 +25,8 @@ else
|
||||
'webhook_url' => webhook_url
|
||||
}
|
||||
)
|
||||
channel.save(validate: false)
|
||||
end
|
||||
channel.save(validate: false)
|
||||
|
||||
# Ensure inbox exists
|
||||
inbox = Inbox.find_by(channel: channel)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user