feat: Migrate ruby llm captain (#12981)
Co-authored-by: aakashb95 <aakash@chatwoot.com> Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
@@ -19,19 +19,8 @@ RSpec.describe Captain::Tools::Copilot::GetArticleService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the expected parameter schema' do
|
||||
expect(service.parameters).to eq(
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
article_id: {
|
||||
type: 'number',
|
||||
description: 'The ID of the article to retrieve'
|
||||
}
|
||||
},
|
||||
required: %w[article_id]
|
||||
}
|
||||
)
|
||||
it 'defines article_id parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:article_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -79,13 +68,13 @@ RSpec.describe Captain::Tools::Copilot::GetArticleService do
|
||||
describe '#execute' do
|
||||
context 'when article_id is blank' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute({})).to eq('Missing required parameters')
|
||||
expect(service.execute(article_id: nil)).to eq('Article not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when article is not found' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute({ 'article_id' => 999 })).to eq('Article not found')
|
||||
expect(service.execute(article_id: 999)).to eq('Article not found')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -94,7 +83,7 @@ RSpec.describe Captain::Tools::Copilot::GetArticleService do
|
||||
let(:article) { create(:article, account: account, portal: portal, author: user, title: 'Test Article', content: 'Content') }
|
||||
|
||||
it 'returns the article in llm text format' do
|
||||
result = service.execute({ 'article_id' => article.id })
|
||||
result = service.execute(article_id: article.id)
|
||||
expect(result).to eq(article.to_llm_text)
|
||||
end
|
||||
|
||||
@@ -104,7 +93,7 @@ RSpec.describe Captain::Tools::Copilot::GetArticleService do
|
||||
let(:other_article) { create(:article, account: other_account, portal: other_portal, author: user, title: 'Other Article') }
|
||||
|
||||
it 'returns not found message' do
|
||||
expect(service.execute({ 'article_id' => other_article.id })).to eq('Article not found')
|
||||
expect(service.execute(article_id: other_article.id)).to eq('Article not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,19 +19,8 @@ RSpec.describe Captain::Tools::Copilot::GetContactService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the expected parameter schema' do
|
||||
expect(service.parameters).to eq(
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
contact_id: {
|
||||
type: 'number',
|
||||
description: 'The ID of the contact to retrieve'
|
||||
}
|
||||
},
|
||||
required: %w[contact_id]
|
||||
}
|
||||
)
|
||||
it 'defines contact_id parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:contact_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -78,14 +67,14 @@ RSpec.describe Captain::Tools::Copilot::GetContactService do
|
||||
|
||||
describe '#execute' do
|
||||
context 'when contact_id is blank' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute({})).to eq('Missing required parameters')
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(contact_id: nil)).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when contact is not found' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute({ 'contact_id' => 999 })).to eq('Contact not found')
|
||||
expect(service.execute(contact_id: 999)).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,7 +82,7 @@ RSpec.describe Captain::Tools::Copilot::GetContactService do
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
|
||||
it 'returns the contact in llm text format' do
|
||||
result = service.execute({ 'contact_id' => contact.id })
|
||||
result = service.execute(contact_id: contact.id)
|
||||
expect(result).to eq(contact.to_llm_text)
|
||||
end
|
||||
|
||||
@@ -102,7 +91,7 @@ RSpec.describe Captain::Tools::Copilot::GetContactService do
|
||||
let(:other_contact) { create(:contact, account: other_account) }
|
||||
|
||||
it 'returns not found message' do
|
||||
expect(service.execute({ 'contact_id' => other_contact.id })).to eq('Contact not found')
|
||||
expect(service.execute(contact_id: other_contact.id)).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,19 +19,8 @@ RSpec.describe Captain::Tools::Copilot::GetConversationService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the expected parameter schema' do
|
||||
expect(service.parameters).to eq(
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
conversation_id: {
|
||||
type: 'number',
|
||||
description: 'The ID of the conversation to retrieve'
|
||||
}
|
||||
},
|
||||
required: %w[conversation_id]
|
||||
}
|
||||
)
|
||||
it 'defines conversation_id parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:conversation_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -107,15 +96,9 @@ RSpec.describe Captain::Tools::Copilot::GetConversationService do
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when conversation_id is blank' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute({})).to eq('Missing required parameters')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation is not found' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute({ 'conversation_id' => 999 })).to eq('Conversation not found')
|
||||
expect(service.execute(conversation_id: 999)).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -124,7 +107,7 @@ RSpec.describe Captain::Tools::Copilot::GetConversationService do
|
||||
let(:conversation) { create(:conversation, account: account, inbox: inbox) }
|
||||
|
||||
it 'returns the conversation in llm text format' do
|
||||
result = service.execute({ 'conversation_id' => conversation.display_id })
|
||||
result = service.execute(conversation_id: conversation.display_id)
|
||||
expect(result).to eq(conversation.to_llm_text)
|
||||
end
|
||||
|
||||
@@ -143,7 +126,7 @@ RSpec.describe Captain::Tools::Copilot::GetConversationService do
|
||||
content: 'Private note content',
|
||||
private: true)
|
||||
|
||||
result = service.execute({ 'conversation_id' => conversation.display_id })
|
||||
result = service.execute(conversation_id: conversation.display_id)
|
||||
|
||||
# Verify that the result includes both regular and private messages
|
||||
expect(result).to include('Regular message')
|
||||
@@ -157,7 +140,7 @@ RSpec.describe Captain::Tools::Copilot::GetConversationService do
|
||||
let(:other_conversation) { create(:conversation, account: other_account, inbox: other_inbox) }
|
||||
|
||||
it 'returns not found message' do
|
||||
expect(service.execute({ 'conversation_id' => other_conversation.display_id })).to eq('Conversation not found')
|
||||
expect(service.execute(conversation_id: other_conversation.display_id)).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,32 +18,6 @@ RSpec.describe Captain::Tools::Copilot::SearchArticlesService do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the expected parameter schema' do
|
||||
expect(service.parameters).to eq(
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
query: {
|
||||
type: 'string',
|
||||
description: 'Search articles by title or content (partial match)'
|
||||
},
|
||||
category_id: {
|
||||
type: 'number',
|
||||
description: 'Filter articles by category ID'
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: %w[draft published archived],
|
||||
description: 'Filter articles by status'
|
||||
}
|
||||
},
|
||||
required: ['query']
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user is an admin' do
|
||||
let(:user) { create(:user, :administrator, account: account) }
|
||||
@@ -95,15 +69,9 @@ RSpec.describe Captain::Tools::Copilot::SearchArticlesService do
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when query is blank' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute({})).to eq('Missing required parameters')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no articles are found' do
|
||||
it 'returns no articles found message' do
|
||||
expect(service.execute({ 'query' => 'test' })).to eq('No articles found')
|
||||
expect(service.execute(query: 'test', category_id: nil, status: nil)).to eq('No articles found')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -113,7 +81,7 @@ RSpec.describe Captain::Tools::Copilot::SearchArticlesService do
|
||||
let!(:article2) { create(:article, account: account, portal: portal, author: user, title: 'Test Article 2', content: 'Content 2') }
|
||||
|
||||
it 'returns formatted articles with count' do
|
||||
result = service.execute({ 'query' => 'Test' })
|
||||
result = service.execute(query: 'Test', category_id: nil, status: nil)
|
||||
expect(result).to include('Total number of articles: 2')
|
||||
expect(result).to include(article1.to_llm_text)
|
||||
expect(result).to include(article2.to_llm_text)
|
||||
@@ -124,7 +92,7 @@ RSpec.describe Captain::Tools::Copilot::SearchArticlesService do
|
||||
let!(:article3) { create(:article, account: account, portal: portal, author: user, category: category, title: 'Test Article 3') }
|
||||
|
||||
it 'returns only articles from the specified category' do
|
||||
result = service.execute({ 'query' => 'Test', 'category_id' => category.id })
|
||||
result = service.execute(query: 'Test', category_id: category.id, status: nil)
|
||||
expect(result).to include('Total number of articles: 1')
|
||||
expect(result).to include(article3.to_llm_text)
|
||||
expect(result).not_to include(article1.to_llm_text)
|
||||
@@ -137,7 +105,7 @@ RSpec.describe Captain::Tools::Copilot::SearchArticlesService do
|
||||
let!(:article4) { create(:article, account: account, portal: portal, author: user, title: 'Test Article 4', status: 'draft') }
|
||||
|
||||
it 'returns only articles with the specified status' do
|
||||
result = service.execute({ 'query' => 'Test', 'status' => 'published' })
|
||||
result = service.execute(query: 'Test', category_id: nil, status: 'published')
|
||||
expect(result).to include(article3.to_llm_text)
|
||||
expect(result).not_to include(article4.to_llm_text)
|
||||
end
|
||||
|
||||
@@ -19,27 +19,8 @@ RSpec.describe Captain::Tools::Copilot::SearchContactsService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the expected parameter schema' do
|
||||
expect(service.parameters).to eq(
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
email: {
|
||||
type: 'string',
|
||||
description: 'Filter contacts by email'
|
||||
},
|
||||
phone_number: {
|
||||
type: 'string',
|
||||
description: 'Filter contacts by phone number'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Filter contacts by name (partial match)'
|
||||
}
|
||||
},
|
||||
required: []
|
||||
}
|
||||
)
|
||||
it 'defines email, phone_number, and name parameters' do
|
||||
expect(service.parameters.keys).to contain_exactly(:email, :phone_number, :name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,25 +67,25 @@ RSpec.describe Captain::Tools::Copilot::SearchContactsService do
|
||||
end
|
||||
|
||||
it 'returns contacts when filtered by email' do
|
||||
result = service.execute({ 'email' => 'test1@example.com' })
|
||||
result = service.execute(email: 'test1@example.com')
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).not_to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
it 'returns contacts when filtered by phone number' do
|
||||
result = service.execute({ 'phone_number' => '+1234567890' })
|
||||
result = service.execute(phone_number: '+1234567890')
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).not_to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
it 'returns contacts when filtered by name' do
|
||||
result = service.execute({ 'name' => 'Contact 1' })
|
||||
result = service.execute(name: 'Contact 1')
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).not_to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
it 'returns all matching contacts when no filters are provided' do
|
||||
result = service.execute({})
|
||||
result = service.execute
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ RSpec.describe Captain::Tools::Copilot::SearchConversationsService do
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('search_conversations')
|
||||
expect(service.name).to eq('search_conversation')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,10 +19,8 @@ RSpec.describe Captain::Tools::Copilot::SearchConversationsService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the correct parameter schema' do
|
||||
params = service.parameters
|
||||
expect(params[:type]).to eq('object')
|
||||
expect(params[:properties]).to include(:contact_id, :status, :priority)
|
||||
it 'defines the expected parameters' do
|
||||
expect(service.parameters.keys).to contain_exactly(:status, :contact_id, :priority, :labels)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -90,35 +88,35 @@ RSpec.describe Captain::Tools::Copilot::SearchConversationsService do
|
||||
let!(:resolved_conversation) { create(:conversation, account: account, status: 'resolved', priority: 'low') }
|
||||
|
||||
it 'returns all conversations when no filters are applied' do
|
||||
result = service.execute({})
|
||||
result = service.execute
|
||||
expect(result).to include('Total number of conversations: 2')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'filters conversations by status' do
|
||||
result = service.execute({ 'status' => 'open' })
|
||||
result = service.execute(status: 'open')
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'filters conversations by contact_id' do
|
||||
result = service.execute({ 'contact_id' => contact.id })
|
||||
result = service.execute(contact_id: contact.id)
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'filters conversations by priority' do
|
||||
result = service.execute({ 'priority' => 'high' })
|
||||
result = service.execute(priority: 'high')
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'returns appropriate message when no conversations are found' do
|
||||
result = service.execute({ 'status' => 'snoozed' })
|
||||
result = service.execute(status: 'snoozed')
|
||||
expect(result).to eq('No conversations found')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,19 +19,8 @@ RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the expected parameter schema' do
|
||||
expect(service.parameters).to eq(
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
term: {
|
||||
type: 'string',
|
||||
description: 'The search term to find Linear issues'
|
||||
}
|
||||
},
|
||||
required: %w[term]
|
||||
}
|
||||
)
|
||||
it 'defines term parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:term)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -76,7 +65,7 @@ RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
describe '#execute' do
|
||||
context 'when Linear integration is not enabled' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute({ 'term' => 'test' })).to eq('Linear integration is not enabled')
|
||||
expect(service.execute(term: 'test')).to eq('Linear integration is not enabled')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,8 +78,12 @@ RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
end
|
||||
|
||||
context 'when term is blank' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute({ 'term' => '' })).to eq('Missing required parameters')
|
||||
before do
|
||||
allow(linear_service).to receive(:search_issue).with('').and_return({ data: [] })
|
||||
end
|
||||
|
||||
it 'returns no issues found message' do
|
||||
expect(service.execute(term: '')).to eq('No issues found, I should try another similar search term')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,7 +93,7 @@ RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
end
|
||||
|
||||
it 'returns the error message' do
|
||||
expect(service.execute({ 'term' => 'test' })).to eq('API Error')
|
||||
expect(service.execute(term: 'test')).to eq('API Error')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,7 +103,7 @@ RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
end
|
||||
|
||||
it 'returns no issues found message' do
|
||||
expect(service.execute({ 'term' => 'test' })).to eq('No issues found, I should try another similar search term')
|
||||
expect(service.execute(term: 'test')).to eq('No issues found, I should try another similar search term')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -131,7 +124,7 @@ RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
end
|
||||
|
||||
it 'returns formatted issues' do
|
||||
result = service.execute({ 'term' => 'test' })
|
||||
result = service.execute(term: 'test')
|
||||
expect(result).to include('Total number of issues: 1')
|
||||
expect(result).to include('Title: Test Issue')
|
||||
expect(result).to include('ID: TEST-123')
|
||||
|
||||
@@ -20,19 +20,8 @@ RSpec.describe Captain::Tools::SearchDocumentationService do
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'returns the required parameters schema' do
|
||||
expected_schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
search_query: {
|
||||
type: 'string',
|
||||
description: 'The search query to look up in the documentation.'
|
||||
}
|
||||
},
|
||||
required: ['search_query']
|
||||
}
|
||||
|
||||
expect(service.parameters).to eq(expected_schema)
|
||||
it 'defines query parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:query)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -56,7 +45,7 @@ RSpec.describe Captain::Tools::SearchDocumentationService do
|
||||
end
|
||||
|
||||
it 'returns formatted responses for the search query' do
|
||||
result = service.execute({ 'search_query' => question })
|
||||
result = service.execute(query: question)
|
||||
|
||||
expect(result).to include(question)
|
||||
expect(result).to include(answer)
|
||||
@@ -70,7 +59,7 @@ RSpec.describe Captain::Tools::SearchDocumentationService do
|
||||
end
|
||||
|
||||
it 'returns an empty string' do
|
||||
expect(service.execute({ 'search_query' => question })).to eq('No FAQs found for the given query')
|
||||
expect(service.execute(query: question)).to eq('No FAQs found for the given query')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user