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:
Shivam Mishra
2025-07-21 16:42:12 +05:30
committed by GitHub
parent bb9e3a5495
commit b71a0da10d
21 changed files with 1139 additions and 6 deletions

View File

@@ -33,15 +33,119 @@ RSpec.describe Captain::Scenario, type: :model do
let(:account) { create(:account) }
let(:assistant) { create(:captain_assistant, account: account) }
describe 'before_save :populate_tools' do
it 'calls populate_tools before saving' do
describe 'before_save :resolve_tool_references' do
it 'calls resolve_tool_references before saving' do
scenario = build(:captain_scenario, assistant: assistant, account: account)
expect(scenario).to receive(:populate_tools)
expect(scenario).to receive(:resolve_tool_references)
scenario.save
end
end
end
describe 'tool validation and population' do
let(:account) { create(:account) }
let(:assistant) { create(:captain_assistant, account: account) }
before do
# Mock available tools
allow(described_class).to receive(:available_tool_ids).and_return(%w[
add_contact_note add_private_note update_priority
])
end
describe 'validate_instruction_tools' do
it 'is valid with valid tool references' do
scenario = build(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Use [@Add Contact Note](tool://add_contact_note) to document')
expect(scenario).to be_valid
end
it 'is invalid with invalid tool references' do
scenario = build(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Use [@Invalid Tool](tool://invalid_tool) to process')
expect(scenario).not_to be_valid
expect(scenario.errors[:instruction]).to include('contains invalid tools: invalid_tool')
end
it 'is invalid with multiple invalid tools' do
scenario = build(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Use [@Invalid Tool](tool://invalid_tool) and [@Another Invalid](tool://another_invalid)')
expect(scenario).not_to be_valid
expect(scenario.errors[:instruction]).to include('contains invalid tools: invalid_tool, another_invalid')
end
it 'is valid with no tool references' do
scenario = build(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Just respond politely to the customer')
expect(scenario).to be_valid
end
it 'is valid with blank instruction' do
scenario = build(:captain_scenario,
assistant: assistant,
account: account,
instruction: '')
# Will be invalid due to presence validation, not tool validation
expect(scenario).not_to be_valid
expect(scenario.errors[:instruction]).not_to include(/contains invalid tools/)
end
end
describe 'resolve_tool_references' do
it 'populates tools array with referenced tool IDs' do
scenario = create(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'First [@Add Contact Note](tool://add_contact_note) then [@Update Priority](tool://update_priority)')
expect(scenario.tools).to eq(%w[add_contact_note update_priority])
end
it 'sets tools to nil when no tools are referenced' do
scenario = create(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Just respond politely to the customer')
expect(scenario.tools).to be_nil
end
it 'handles duplicate tool references' do
scenario = create(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Use [@Add Contact Note](tool://add_contact_note) and [@Add Contact Note](tool://add_contact_note) again')
expect(scenario.tools).to eq(['add_contact_note'])
end
it 'updates tools when instruction changes' do
scenario = create(:captain_scenario,
assistant: assistant,
account: account,
instruction: 'Use [@Add Contact Note](tool://add_contact_note)')
expect(scenario.tools).to eq(['add_contact_note'])
scenario.update!(instruction: 'Use [@Update Priority](tool://update_priority) instead')
expect(scenario.tools).to eq(['update_priority'])
end
end
end
describe 'factory' do
it 'creates a valid scenario with associations' do
account = create(:account)