95 lines
3.7 KiB
Ruby
95 lines
3.7 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?).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 '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
|