feat: update status on agent bot assignment (#14870)
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.
This commit is contained in:
@@ -19,20 +19,55 @@ describe Conversations::AssignmentService do
|
||||
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)
|
||||
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil, status: :pending)
|
||||
end
|
||||
|
||||
it 'sets the agent and clears agent bot' do
|
||||
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
|
||||
|
||||
@@ -45,8 +80,8 @@ describe Conversations::AssignmentService do
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the agent bot and clears human assignee' do
|
||||
conversation.update!(assignee: agent, assignee_agent_bot: nil)
|
||||
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
|
||||
|
||||
@@ -54,6 +89,25 @@ describe Conversations::AssignmentService do
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user