feat: scenario tools [CW-4597] (#11908)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
116
spec/enterprise/lib/captain/tools/add_contact_note_tool_spec.rb
Normal file
116
spec/enterprise/lib/captain/tools/add_contact_note_tool_spec.rb
Normal file
@@ -0,0 +1,116 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::AddContactNoteTool, type: :model do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:tool) { described_class.new(assistant) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:conversation) { create(:conversation, account: account, inbox: inbox, contact: contact) }
|
||||
let(:tool_context) { Struct.new(:state).new({ contact: { id: contact.id } }) }
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the correct description' do
|
||||
expect(tool.description).to eq('Add a note to a contact profile')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the correct parameters' do
|
||||
expect(tool.parameters).to have_key(:note)
|
||||
expect(tool.parameters[:note].name).to eq(:note)
|
||||
expect(tool.parameters[:note].type).to eq('string')
|
||||
expect(tool.parameters[:note].description).to eq('The note content to add to the contact')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
context 'when contact exists' do
|
||||
context 'with valid note content' do
|
||||
it 'creates a contact note and returns success message' do
|
||||
note_content = 'This is a contact note'
|
||||
|
||||
expect do
|
||||
result = tool.perform(tool_context, note: note_content)
|
||||
expect(result).to eq("Note added successfully to contact #{contact.name} (ID: #{contact.id})")
|
||||
end.to change(Note, :count).by(1)
|
||||
|
||||
created_note = Note.last
|
||||
expect(created_note.content).to eq(note_content)
|
||||
expect(created_note.account).to eq(account)
|
||||
expect(created_note.contact).to eq(contact)
|
||||
expect(created_note.user).to eq(assistant.account.users.first)
|
||||
end
|
||||
|
||||
it 'logs tool usage' do
|
||||
expect(tool).to receive(:log_tool_usage).with(
|
||||
'add_contact_note',
|
||||
{ contact_id: contact.id, note_length: 19 }
|
||||
)
|
||||
|
||||
tool.perform(tool_context, note: 'This is a test note')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with blank note content' do
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: '')
|
||||
expect(result).to eq('Note content is required')
|
||||
end
|
||||
|
||||
it 'does not create a note' do
|
||||
expect do
|
||||
tool.perform(tool_context, note: '')
|
||||
end.not_to change(Note, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with nil note content' do
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: nil)
|
||||
expect(result).to eq('Note content is required')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when contact does not exist' do
|
||||
let(:tool_context) { Struct.new(:state).new({ contact: { id: 999_999 } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: 'Some note')
|
||||
expect(result).to eq('Contact not found')
|
||||
end
|
||||
|
||||
it 'does not create a note' do
|
||||
expect do
|
||||
tool.perform(tool_context, note: 'Some note')
|
||||
end.not_to change(Note, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when contact state is missing' do
|
||||
let(:tool_context) { Struct.new(:state).new({}) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: 'Some note')
|
||||
expect(result).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when contact id is nil' do
|
||||
let(:tool_context) { Struct.new(:state).new({ contact: { id: nil } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: 'Some note')
|
||||
expect(result).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
it 'returns true for public tools' do
|
||||
expect(tool.active?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,125 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::AddLabelToConversationTool, type: :model do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:tool) { described_class.new(assistant) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:conversation) { create(:conversation, account: account, inbox: inbox, contact: contact) }
|
||||
let(:label) { create(:label, account: account, title: 'urgent') }
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: conversation.id } }) }
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the correct description' do
|
||||
expect(tool.description).to eq('Add a label to a conversation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the correct parameters' do
|
||||
expect(tool.parameters).to have_key(:label_name)
|
||||
expect(tool.parameters[:label_name].name).to eq(:label_name)
|
||||
expect(tool.parameters[:label_name].type).to eq('string')
|
||||
expect(tool.parameters[:label_name].description).to eq('The name of the label to add')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
context 'when conversation exists' do
|
||||
context 'with valid label that exists' do
|
||||
before { label }
|
||||
|
||||
it 'adds label to conversation and returns success message' do
|
||||
result = tool.perform(tool_context, label_name: 'urgent')
|
||||
expect(result).to eq("Label 'urgent' added to conversation ##{conversation.display_id}")
|
||||
|
||||
expect(conversation.reload.label_list).to include('urgent')
|
||||
end
|
||||
|
||||
it 'logs tool usage' do
|
||||
expect(tool).to receive(:log_tool_usage).with(
|
||||
'added_label',
|
||||
{ conversation_id: conversation.id, label: 'urgent' }
|
||||
)
|
||||
|
||||
tool.perform(tool_context, label_name: 'urgent')
|
||||
end
|
||||
|
||||
it 'handles case insensitive label names' do
|
||||
result = tool.perform(tool_context, label_name: 'URGENT')
|
||||
expect(result).to eq("Label 'urgent' added to conversation ##{conversation.display_id}")
|
||||
end
|
||||
|
||||
it 'strips whitespace from label names' do
|
||||
result = tool.perform(tool_context, label_name: ' urgent ')
|
||||
expect(result).to eq("Label 'urgent' added to conversation ##{conversation.display_id}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'with label that does not exist' do
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, label_name: 'nonexistent')
|
||||
expect(result).to eq('Label not found')
|
||||
end
|
||||
|
||||
it 'does not add any labels to conversation' do
|
||||
expect do
|
||||
tool.perform(tool_context, label_name: 'nonexistent')
|
||||
end.not_to(change { conversation.reload.labels.count })
|
||||
end
|
||||
end
|
||||
|
||||
context 'with blank label name' do
|
||||
it 'returns error message for empty string' do
|
||||
result = tool.perform(tool_context, label_name: '')
|
||||
expect(result).to eq('Label name is required')
|
||||
end
|
||||
|
||||
it 'returns error message for nil' do
|
||||
result = tool.perform(tool_context, label_name: nil)
|
||||
expect(result).to eq('Label name is required')
|
||||
end
|
||||
|
||||
it 'returns error message for whitespace only' do
|
||||
result = tool.perform(tool_context, label_name: ' ')
|
||||
expect(result).to eq('Label name is required')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation does not exist' do
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: 999_999 } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, label_name: 'urgent')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation state is missing' do
|
||||
let(:tool_context) { Struct.new(:state).new({}) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, label_name: 'urgent')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation id is nil' do
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: nil } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, label_name: 'urgent')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
it 'returns true for public tools' do
|
||||
expect(tool.active?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
124
spec/enterprise/lib/captain/tools/add_private_note_tool_spec.rb
Normal file
124
spec/enterprise/lib/captain/tools/add_private_note_tool_spec.rb
Normal file
@@ -0,0 +1,124 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::AddPrivateNoteTool, type: :model do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:tool) { described_class.new(assistant) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:conversation) { create(:conversation, account: account, inbox: inbox, contact: contact) }
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: conversation.id } }) }
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the correct description' do
|
||||
expect(tool.description).to eq('Add a private note to a conversation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the correct parameters' do
|
||||
expect(tool.parameters).to have_key(:note)
|
||||
expect(tool.parameters[:note].name).to eq(:note)
|
||||
expect(tool.parameters[:note].type).to eq('string')
|
||||
expect(tool.parameters[:note].description).to eq('The private note content')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
context 'when conversation exists' do
|
||||
context 'with valid note content' do
|
||||
it 'creates a private note and returns success message' do
|
||||
note_content = 'This is a private note'
|
||||
|
||||
expect do
|
||||
result = tool.perform(tool_context, note: note_content)
|
||||
expect(result).to eq('Private note added successfully')
|
||||
end.to change(Message, :count).by(1)
|
||||
end
|
||||
|
||||
it 'creates a private note with correct attributes' do
|
||||
note_content = 'This is a private note'
|
||||
|
||||
tool.perform(tool_context, note: note_content)
|
||||
|
||||
created_message = Message.last
|
||||
expect(created_message.content).to eq(note_content)
|
||||
expect(created_message.message_type).to eq('outgoing')
|
||||
expect(created_message.private).to be true
|
||||
expect(created_message.account).to eq(account)
|
||||
expect(created_message.inbox).to eq(inbox)
|
||||
expect(created_message.conversation).to eq(conversation)
|
||||
end
|
||||
|
||||
it 'logs tool usage' do
|
||||
expect(tool).to receive(:log_tool_usage).with(
|
||||
'add_private_note',
|
||||
{ conversation_id: conversation.id, note_length: 19 }
|
||||
)
|
||||
|
||||
tool.perform(tool_context, note: 'This is a test note')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with blank note content' do
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: '')
|
||||
expect(result).to eq('Note content is required')
|
||||
end
|
||||
|
||||
it 'does not create a message' do
|
||||
expect do
|
||||
tool.perform(tool_context, note: '')
|
||||
end.not_to change(Message, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with nil note content' do
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: nil)
|
||||
expect(result).to eq('Note content is required')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation does not exist' do
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: 999_999 } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: 'Some note')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
|
||||
it 'does not create a message' do
|
||||
expect do
|
||||
tool.perform(tool_context, note: 'Some note')
|
||||
end.not_to change(Message, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation state is missing' do
|
||||
let(:tool_context) { Struct.new(:state).new({}) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: 'Some note')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation id is nil' do
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: nil } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, note: 'Some note')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
it 'returns true for public tools' do
|
||||
expect(tool.active?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
117
spec/enterprise/lib/captain/tools/update_priority_tool_spec.rb
Normal file
117
spec/enterprise/lib/captain/tools/update_priority_tool_spec.rb
Normal file
@@ -0,0 +1,117 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::UpdatePriorityTool, type: :model do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:tool) { described_class.new(assistant) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let(:conversation) { create(:conversation, account: account, inbox: inbox, contact: contact) }
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: conversation.id } }) }
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the correct description' do
|
||||
expect(tool.description).to eq('Update the priority of a conversation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the correct parameters' do
|
||||
expect(tool.parameters).to have_key(:priority)
|
||||
expect(tool.parameters[:priority].name).to eq(:priority)
|
||||
expect(tool.parameters[:priority].type).to eq('string')
|
||||
expect(tool.parameters[:priority].description).to eq('The priority level: low, medium, high, urgent, or nil to remove priority')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
context 'when conversation exists' do
|
||||
context 'with valid priority levels' do
|
||||
%w[low medium high urgent].each do |priority|
|
||||
it "updates conversation priority to #{priority}" do
|
||||
result = tool.perform(tool_context, priority: priority)
|
||||
expect(result).to eq("Priority updated to '#{priority}' for conversation ##{conversation.display_id}")
|
||||
|
||||
expect(conversation.reload.priority).to eq(priority)
|
||||
end
|
||||
end
|
||||
|
||||
it 'removes priority when set to nil' do
|
||||
conversation.update!(priority: 'high')
|
||||
|
||||
result = tool.perform(tool_context, priority: 'nil')
|
||||
expect(result).to eq("Priority updated to 'none' for conversation ##{conversation.display_id}")
|
||||
|
||||
expect(conversation.reload.priority).to be_nil
|
||||
end
|
||||
|
||||
it 'removes priority when set to empty string' do
|
||||
conversation.update!(priority: 'high')
|
||||
|
||||
result = tool.perform(tool_context, priority: '')
|
||||
expect(result).to eq("Priority updated to 'none' for conversation ##{conversation.display_id}")
|
||||
|
||||
expect(conversation.reload.priority).to be_nil
|
||||
end
|
||||
|
||||
it 'logs tool usage' do
|
||||
expect(tool).to receive(:log_tool_usage).with(
|
||||
'update_priority',
|
||||
{ conversation_id: conversation.id, priority: 'high' }
|
||||
)
|
||||
|
||||
tool.perform(tool_context, priority: 'high')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid priority levels' do
|
||||
it 'returns error message for invalid priority' do
|
||||
result = tool.perform(tool_context, priority: 'invalid')
|
||||
expect(result).to eq('Invalid priority. Valid options: low, medium, high, urgent, nil')
|
||||
end
|
||||
|
||||
it 'does not update conversation priority' do
|
||||
original_priority = conversation.priority
|
||||
|
||||
tool.perform(tool_context, priority: 'invalid')
|
||||
|
||||
expect(conversation.reload.priority).to eq(original_priority)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation does not exist' do
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: 999_999 } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, priority: 'high')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation state is missing' do
|
||||
let(:tool_context) { Struct.new(:state).new({}) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, priority: 'high')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation id is nil' do
|
||||
let(:tool_context) { Struct.new(:state).new({ conversation: { id: nil } }) }
|
||||
|
||||
it 'returns error message' do
|
||||
result = tool.perform(tool_context, priority: 'high')
|
||||
expect(result).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
it 'returns true for public tools' do
|
||||
expect(tool.active?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user