fix: prevent Captain bot collisions (#15324)

Prevents Captain from being scheduled for replies or
inactive-conversation resolution when an inbox already has an active
AgentBot or Dialogflow integration.

## Closes


[CW-7834](https://linear.app/chatwoot/issue/CW-7834/prevent-captain-from-processing-agentbot-and-dialogflow-conversations)

## Why

Captain and an external inbox bot could both process conversations from
the same inbox.

## What this change does

- Distinguishes external inbox bots from Captain in the existing bot
predicate.
- Skips Captain reply scheduling when an external bot is active.
- Skips Captain inactive-resolution scheduling when an external bot is
active.

## Validation

- Connect an AgentBot to a Captain-enabled inbox and confirm Captain
does not reply or schedule inactive resolution.
- Enable Dialogflow on a Captain-enabled inbox and confirm Captain does
not reply.
- Remove the external bot integration and confirm Captain resumes normal
processing.

---------

Co-authored-by: Aakash Bakhle <48802744+aakashb95@users.noreply.github.com>
This commit is contained in:
Sojan Jose
2026-08-05 04:04:46 -07:00
committed by GitHub
parent 343bb15d07
commit 3b74f9c359
7 changed files with 42 additions and 7 deletions

View File

@@ -46,6 +46,17 @@ RSpec.describe Account::ConversationsResolutionSchedulerJob, type: :job do
end
end
it 'does not enqueue resolution jobs for inboxes with an external bot' do
regular_inbox = create(:inbox, account: account)
create(:captain_inbox, captain_assistant: assistant, inbox: regular_inbox)
create(:agent_bot_inbox, inbox: regular_inbox, agent_bot: create(:agent_bot, account: account))
expect do
described_class.perform_now
end.not_to have_enqueued_job(Captain::InboxPendingConversationsResolutionJob)
.with(regular_inbox)
end
context 'when an assistant has been deleted before its inbox link is cleaned up' do
let!(:orphaned_inbox) { create(:inbox, account: account) }
let!(:regular_inbox) { create(:inbox, account: account) }

View File

@@ -202,6 +202,16 @@ RSpec.describe MessageTemplates::HookExecutionService do
end
end
it 'does not schedule Captain for inbox bot integrations' do
expect(Captain::Conversation::ResponseBuilderJob).not_to receive(:perform_later)
agent_bot_inbox = create(:agent_bot_inbox, inbox: inbox, agent_bot: create(:agent_bot, account: account))
create(:message, conversation: conversation, message_type: :incoming, account: account)
agent_bot_inbox.destroy!
create(:integrations_hook, :dialogflow, inbox: inbox, account: account)
create(:message, conversation: conversation, message_type: :incoming, account: account)
end
context 'when conversation is not pending' do
before do
conversation.update!(status: :open)