## Description Adds the account-level `unread_count_for_filters` feature flag as the dark-launch gate for filtered sidebar unread counts. This reuses the deprecated `quoted_email_reply` flag slot, resets the reused bit for existing accounts, and removes stale defaults so new accounts do not reference the old flag. This also adds the feature where we are now calculating the unread counts for built in filters like mentions, participating and unattended along with unread count for saved filters/folders. Closes [CW-7262](https://linear.app/chatwoot/issue/CW-7262/unread-counts-for-filters-folders) ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update
102 lines
4.0 KiB
Ruby
102 lines
4.0 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe Captain::ReplySuggestionService do
|
|
subject(:service) { described_class.new(account: account, conversation_display_id: conversation.display_id, user: agent) }
|
|
|
|
let(:account) { create(:account) }
|
|
let(:agent) { create(:user, account: account, name: 'Jane Smith') }
|
|
let(:inbox) { create(:inbox, account: account) }
|
|
let(:conversation) { create(:conversation, account: account, inbox: inbox) }
|
|
let(:captured_messages) { [] }
|
|
|
|
before do
|
|
create(:installation_config, name: 'CAPTAIN_OPEN_AI_API_KEY', value: 'test-key')
|
|
create(:message, conversation: conversation, message_type: :incoming, content: 'I need help')
|
|
allow(account).to receive(:feature_enabled?).and_call_original
|
|
allow(account).to receive(:feature_enabled?).with('captain_tasks').and_return(true)
|
|
|
|
mock_response = instance_double(RubyLLM::Message, content: 'Sure, I can help!', input_tokens: 50, output_tokens: 20)
|
|
mock_chat = instance_double(RubyLLM::Chat)
|
|
mock_context = instance_double(RubyLLM::Context, chat: mock_chat)
|
|
|
|
allow(Llm::Config).to receive(:with_api_key).and_yield(mock_context)
|
|
allow(mock_chat).to receive(:with_tool).and_return(mock_chat)
|
|
allow(mock_chat).to receive(:on_end_message).and_return(mock_chat)
|
|
allow(mock_chat).to receive(:with_instructions) { |msg| captured_messages << { role: 'system', content: msg } }
|
|
allow(mock_chat).to receive(:add_message) { |args| captured_messages << args }
|
|
allow(mock_chat).to receive(:ask) do |msg|
|
|
captured_messages << { role: 'user', content: msg }
|
|
mock_response
|
|
end
|
|
end
|
|
|
|
describe '#perform' do
|
|
it 'routes through the editor feature' do
|
|
expect(Llm::FeatureRouter).to receive(:resolve).with(feature: 'editor', account: account).and_call_original
|
|
|
|
service.perform
|
|
end
|
|
|
|
it 'returns the suggested reply' do
|
|
result = service.perform
|
|
|
|
expect(result[:message]).to eq('Sure, I can help!')
|
|
end
|
|
|
|
it 'formats conversation using LlmFormatter' do
|
|
service.perform
|
|
|
|
user_message = captured_messages.find { |m| m[:role] == 'user' }
|
|
expect(user_message[:content]).to include('Message History:')
|
|
expect(user_message[:content]).to include('User: I need help')
|
|
end
|
|
|
|
context 'with chat channel' do
|
|
it 'uses chat-specific instructions' do
|
|
service.perform
|
|
|
|
system_prompt = captured_messages.find { |m| m[:role] == 'system' }[:content]
|
|
expect(system_prompt).to include('CHAT conversation')
|
|
expect(system_prompt).to include('brief, conversational')
|
|
expect(system_prompt).not_to include('EMAIL conversation')
|
|
end
|
|
end
|
|
|
|
context 'with email channel' do
|
|
let(:email_channel) { create(:channel_email, account: account) }
|
|
let(:inbox) { create(:inbox, account: account, channel: email_channel) }
|
|
|
|
it 'uses email-specific instructions' do
|
|
service.perform
|
|
|
|
system_prompt = captured_messages.find { |m| m[:role] == 'system' }[:content]
|
|
expect(system_prompt).to include('EMAIL conversation')
|
|
expect(system_prompt).to include('professional email')
|
|
expect(system_prompt).not_to include('CHAT conversation')
|
|
end
|
|
|
|
context 'when agent has a signature' do
|
|
let(:agent) { create(:user, account: account, name: 'Jane Smith', message_signature: "Best,\nJane Smith") }
|
|
|
|
it 'includes the signature in the prompt' do
|
|
service.perform
|
|
|
|
system_prompt = captured_messages.find { |m| m[:role] == 'system' }[:content]
|
|
expect(system_prompt).to include("Best,\nJane Smith")
|
|
end
|
|
end
|
|
|
|
context 'when agent has no signature' do
|
|
let(:agent) { create(:user, account: account, name: 'Jane Smith', message_signature: nil) }
|
|
|
|
it 'falls back to agent name for sign-off' do
|
|
service.perform
|
|
|
|
system_prompt = captured_messages.find { |m| m[:role] == 'system' }[:content]
|
|
expect(system_prompt).to include("sign-off using the agent's name: Jane Smith")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|