Assigning a conversation to an Agent Bot now moves it to pending. Assigning a bot-owned pending conversation to a human opens it again, while other assignment changes preserve the existing status. This makes existing Agent Bot ownership behave like an AI handoff without depending on the assignment dropdown UI work. Closes: https://linear.app/chatwoot/issue/CW-7448/apply-agent-bot-assignment-behavior ## Why Agent Bot ownership should remove conversations from the main open queue while the bot is handling them. Explicit human takeover should bring a bot-owned pending conversation back to the open queue and clear the bot owner. ## What changed - Agent Bot assignment clears the human assignee and marks the conversation pending. - Human assignment clears the Agent Bot owner and opens the conversation only when it was bot-owned and pending. - Ordinary human assignment, non-pending bot takeover, and unassignment preserve the existing conversation status. - Manual human takeover uses the existing assignment and status events. Bot-initiated handoffs continue to use the existing bot-handoff event path. ## Validation - Assign an open conversation to an Agent Bot through the assignment API and verify it becomes pending. - Assign that bot-owned pending conversation to a human and verify it becomes open. - Verify ordinary human assignment, non-pending bot takeover, and unassignment do not force a status change.
115 lines
3.7 KiB
Ruby
115 lines
3.7 KiB
Ruby
require 'rails_helper'
|
|
|
|
describe Conversations::AssignmentService do
|
|
let(:account) { create(:account) }
|
|
let(:agent) { create(:user, account: account) }
|
|
let(:agent_bot) { create(:agent_bot, account: account) }
|
|
let(:conversation) { create(:conversation, account: account) }
|
|
|
|
describe '#perform' do
|
|
context 'when assignee_id is blank' do
|
|
before do
|
|
conversation.update!(assignee: agent, assignee_agent_bot: agent_bot)
|
|
end
|
|
|
|
it 'clears both human and bot assignees' do
|
|
described_class.new(conversation: conversation, assignee_id: nil).perform
|
|
|
|
conversation.reload
|
|
expect(conversation.assignee_id).to be_nil
|
|
expect(conversation.assignee_agent_bot_id).to be_nil
|
|
end
|
|
|
|
it 'preserves conversation status' do
|
|
conversation.update!(status: :snoozed, snoozed_until: 1.day.from_now)
|
|
|
|
described_class.new(conversation: conversation, assignee_id: nil).perform
|
|
|
|
expect(conversation.reload.status).to eq('snoozed')
|
|
end
|
|
end
|
|
|
|
context 'when assigning a user' do
|
|
before do
|
|
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil, status: :pending)
|
|
end
|
|
|
|
it 'sets the agent, clears agent bot and opens the conversation' do
|
|
result = described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
|
|
|
conversation.reload
|
|
expect(result).to eq(agent)
|
|
expect(conversation.assignee_id).to eq(agent.id)
|
|
expect(conversation.assignee_agent_bot_id).to be_nil
|
|
expect(conversation.status).to eq('open')
|
|
end
|
|
|
|
it 'starts the waiting clock when opening a bot-owned pending conversation' do
|
|
conversation.update!(waiting_since: nil)
|
|
|
|
freeze_time do
|
|
described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
|
|
|
expect(conversation.reload.waiting_since).to eq(Time.current)
|
|
end
|
|
end
|
|
|
|
it 'preserves status for ordinary human assignment changes' do
|
|
conversation.update!(assignee_agent_bot: nil, status: :resolved)
|
|
|
|
described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
|
|
|
expect(conversation.reload.status).to eq('resolved')
|
|
end
|
|
|
|
it 'preserves status when taking over a bot-owned non-pending conversation' do
|
|
conversation.update!(assignee_agent_bot: agent_bot, status: :resolved)
|
|
|
|
described_class.new(conversation: conversation, assignee_id: agent.id).perform
|
|
|
|
expect(conversation.reload.status).to eq('resolved')
|
|
end
|
|
end
|
|
|
|
context 'when assigning an agent bot' do
|
|
let(:service) do
|
|
described_class.new(
|
|
conversation: conversation,
|
|
assignee_id: agent_bot.id,
|
|
assignee_type: 'AgentBot'
|
|
)
|
|
end
|
|
|
|
it 'sets the agent bot, clears human assignee and marks the conversation pending' do
|
|
conversation.update!(assignee: agent, assignee_agent_bot: nil, status: :open)
|
|
|
|
result = service.perform
|
|
|
|
conversation.reload
|
|
expect(result).to eq(agent_bot)
|
|
expect(conversation.assignee_agent_bot_id).to eq(agent_bot.id)
|
|
expect(conversation.assignee_id).to be_nil
|
|
expect(conversation.status).to eq('pending')
|
|
end
|
|
|
|
it 'marks a resolved conversation pending' do
|
|
conversation.update!(status: :resolved)
|
|
|
|
service.perform
|
|
|
|
expect(conversation.reload.status).to eq('pending')
|
|
end
|
|
|
|
it 'marks a snoozed conversation pending and clears the snooze timestamp' do
|
|
conversation.update!(status: :snoozed, snoozed_until: 1.day.from_now)
|
|
|
|
service.perform
|
|
|
|
conversation.reload
|
|
expect(conversation.status).to eq('pending')
|
|
expect(conversation.snoozed_until).to be_nil
|
|
end
|
|
end
|
|
end
|
|
end
|