fix(agent-bot): Dispatch conversation_status_changed event to agent bots (#14002)

Agent bots assigned to a conversation were not receiving
`conversation_status_changed` webhook events. This meant bots could not
react to status transitions like moving a conversation to **pending**.
The deprecated `conversation_opened` and `conversation_resolved` events
were still being delivered, but the newer unified
`conversation_status_changed` event was silently dropped because
`AgentBotListener` had no handler for it.


## What changed

- Added `conversation_status_changed` handler to `AgentBotListener`,
matching the pattern already used by `WebhookListener`. The payload
includes `changed_attributes` so bots know which status transition
occurred.

## How to test

1. Configure an agent bot with an `outgoing_url` (e.g. a webhook.site
endpoint).
2. Assign the bot to an inbox or conversation.
3. Change a conversation's status to **pending** (or any other status).
4. Verify the bot receives a `conversation_status_changed` event with
the correct `changed_attributes`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Muhsin Keloth
2026-04-06 14:05:50 +04:00
committed by GitHub
parent 95463230cb
commit 50d6ebaaca
2 changed files with 47 additions and 0 deletions

View File

@@ -15,6 +15,15 @@ class AgentBotListener < BaseListener
agent_bots_for(inbox, conversation).each { |agent_bot| process_webhook_bot_event(agent_bot, payload) }
end
def conversation_status_changed(event)
conversation = extract_conversation_and_account(event)[0]
changed_attributes = extract_changed_attributes(event)
inbox = conversation.inbox
event_name = __method__.to_s
payload = conversation.webhook_data.merge(event: event_name, changed_attributes: changed_attributes)
agent_bots_for(inbox, conversation).each { |agent_bot| process_webhook_bot_event(agent_bot, payload) }
end
def conversation_updated(event)
conversation = extract_conversation_and_account(event)[0]
changed_attributes = extract_changed_attributes(event)

View File

@@ -65,6 +65,44 @@ describe AgentBotListener do
end
end
describe '#conversation_status_changed' do
let(:event_name) { 'conversation.status_changed' }
let(:changed_attributes) { { status: %w[open pending] } }
let!(:event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation, changed_attributes: changed_attributes) }
context 'when agent bot is not configured' do
it 'does not send webhook' do
expect(AgentBots::WebhookJob).not_to receive(:perform_later)
listener.conversation_status_changed(event)
end
end
context 'when agent bot is configured on inbox' do
it 'sends webhook with changed_attributes' do
create(:agent_bot_inbox, inbox: inbox, agent_bot: agent_bot)
expect(AgentBots::WebhookJob).to receive(:perform_later).with(
agent_bot.outgoing_url,
hash_including(event: 'conversation_status_changed', changed_attributes: anything)
).once
listener.conversation_status_changed(event)
end
end
context 'when conversation is assigned to an agent bot' do
before do
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil)
end
it 'sends webhook to the assigned agent bot' do
expect(AgentBots::WebhookJob).to receive(:perform_later).with(
agent_bot.outgoing_url,
hash_including(event: 'conversation_status_changed', changed_attributes: anything)
).once
listener.conversation_status_changed(event)
end
end
end
describe '#conversation_updated' do
let(:event_name) { 'conversation.updated' }