feat: Add a setting to keep conversations pending on bot failures (#13512)

Adds an account-level setting `keep_pending_on_bot_failure` to control
whether conversations should move from pending to open when agent bot
webhooks fail.

Some users experience occasional message drops and don't want
conversations to automatically reopen due to transient bot failures.
This setting gives accounts control over that behavior. This is a
temporary setting which will be removed in future once a proper fix for
it is done, so it is not added in the UI.
This commit is contained in:
Pranav
2026-02-10 17:27:42 -08:00
committed by GitHub
parent 0ad47d87f4
commit 8f95fafff4
3 changed files with 62 additions and 11 deletions

View File

@@ -74,10 +74,11 @@ describe Webhooks::Trigger do
context 'when webhook type is agent bot' do
let(:webhook_type) { :agent_bot_webhook }
let!(:pending_conversation) { create(:conversation, inbox: inbox, status: :pending, account: account) }
let!(:pending_message) { create(:message, account: account, inbox: inbox, conversation: pending_conversation) }
it 'reopens conversation and enqueues activity message if pending' do
conversation.update(status: :pending)
payload = { event: 'message_created', conversation: { id: conversation.id }, id: message.id }
payload = { event: 'message_created', id: pending_message.id }
expect(RestClient::Request).to receive(:execute)
.with(
@@ -92,11 +93,11 @@ describe Webhooks::Trigger do
perform_enqueued_jobs do
trigger.execute(url, payload, webhook_type)
end
end.not_to(change { message.reload.status })
end.not_to(change { pending_message.reload.status })
expect(conversation.reload.status).to eq('open')
expect(pending_conversation.reload.status).to eq('open')
activity_message = conversation.reload.messages.order(:created_at).last
activity_message = pending_conversation.reload.messages.order(:created_at).last
expect(activity_message.message_type).to eq('activity')
expect(activity_message.content).to eq(agent_bot_error_content)
end
@@ -118,9 +119,52 @@ describe Webhooks::Trigger do
end.not_to(change { message.reload.status })
expect(Conversations::ActivityMessageJob).not_to have_been_enqueued
expect(conversation.reload.status).to eq('open')
end
it 'keeps conversation pending when keep_pending_on_bot_failure setting is enabled' do
account.update(keep_pending_on_bot_failure: true)
payload = { event: 'message_created', id: pending_message.id }
expect(RestClient::Request).to receive(:execute)
.with(
method: :post,
url: url,
payload: payload.to_json,
headers: { content_type: :json, accept: :json },
timeout: webhook_timeout
).and_raise(RestClient::ExceptionWithResponse.new('error', 500)).once
trigger.execute(url, payload, webhook_type)
expect(Conversations::ActivityMessageJob).not_to have_been_enqueued
expect(pending_conversation.reload.status).to eq('pending')
end
it 'reopens conversation when keep_pending_on_bot_failure setting is disabled' do
account.update(keep_pending_on_bot_failure: false)
payload = { event: 'message_created', id: pending_message.id }
expect(RestClient::Request).to receive(:execute)
.with(
method: :post,
url: url,
payload: payload.to_json,
headers: { content_type: :json, accept: :json },
timeout: webhook_timeout
).and_raise(RestClient::ExceptionWithResponse.new('error', 500)).once
expect do
perform_enqueued_jobs do
trigger.execute(url, payload, webhook_type)
end
end.not_to(change { pending_message.reload.status })
expect(pending_conversation.reload.status).to eq('open')
activity_message = pending_conversation.reload.messages.order(:created_at).last
expect(activity_message.message_type).to eq('activity')
expect(activity_message.content).to eq(agent_bot_error_content)
end
end
end