fix(agent-bot): Include changed_attributes in conversation_updated webhook (#14001)
The `conversation_updated` webhook sent to AgentBots did not include
`changed_attributes`, making it impossible for bots to distinguish
between different types of conversation updates (e.g. bot assignment vs
label change vs status change).
This aligns the AgentBot webhook payload with the existing
`WebhookListener` behavior, which already includes `changed_attributes`.
## How to reproduce
1. Assign an AgentBot to a conversation
2. Then update the conversation (e.g. add a label)
3. **Before fix:** Both events arrive with identical payload structure —
bot cannot tell them apart
4. **After fix:** Each event includes `changed_attributes` showing
exactly what changed
## What changed
- **`AgentBotListener#conversation_updated`**: Added
`changed_attributes` to the webhook payload using
`extract_changed_attributes` (same pattern as `WebhookListener`)
## How to test
1. Assign an AgentBot to a conversation via API
2. Check the webhook payload — should include:
```json
"changed_attributes": [
{ "assignee_agent_bot_id": { "previous_value": null, "current_value": 7
} }
]
```
3. Update the conversation (e.g. add a label)
4. Check the webhook payload — `changed_attributes` should reflect the
label change, not bot assignment
🤖 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:
@@ -17,9 +17,10 @@ class AgentBotListener < BaseListener
|
||||
|
||||
def conversation_updated(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)
|
||||
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
|
||||
|
||||
|
||||
@@ -59,9 +59,10 @@ describe AgentBotListener do
|
||||
|
||||
describe '#conversation_updated' do
|
||||
let(:event_name) { 'conversation.updated' }
|
||||
let!(:event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation) }
|
||||
|
||||
context 'when agent bot is not configured' do
|
||||
let!(:event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation) }
|
||||
|
||||
it 'does not send webhook' do
|
||||
expect(AgentBots::WebhookJob).not_to receive(:perform_later)
|
||||
listener.conversation_updated(event)
|
||||
@@ -69,22 +70,34 @@ describe AgentBotListener do
|
||||
end
|
||||
|
||||
context 'when agent bot is configured on inbox' do
|
||||
it 'sends webhook to the inbox agent bot' do
|
||||
let!(:event) { Events::Base.new(event_name, Time.zone.now, conversation: conversation) }
|
||||
|
||||
it 'sends webhook to the inbox agent bot 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,
|
||||
conversation.webhook_data.merge(event: 'conversation_updated')).once
|
||||
conversation.webhook_data.merge(event: 'conversation_updated',
|
||||
changed_attributes: nil)).once
|
||||
listener.conversation_updated(event)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation is assigned to an agent bot' do
|
||||
let!(:event) do
|
||||
Events::Base.new(event_name, Time.zone.now, conversation: conversation,
|
||||
changed_attributes: { 'assignee_agent_bot_id' => [nil, agent_bot.id] })
|
||||
end
|
||||
|
||||
before do
|
||||
conversation.update!(assignee_agent_bot: agent_bot, assignee: nil)
|
||||
end
|
||||
|
||||
it 'sends webhook to the assigned agent bot' do
|
||||
it 'sends webhook with changed_attributes to the assigned agent bot' do
|
||||
expected_changed_attributes = [{ 'assignee_agent_bot_id' => { previous_value: nil, current_value: agent_bot.id } }]
|
||||
expect(AgentBots::WebhookJob).to receive(:perform_later).with(agent_bot.outgoing_url,
|
||||
conversation.webhook_data.merge(event: 'conversation_updated')).once
|
||||
conversation.webhook_data.merge(
|
||||
event: 'conversation_updated',
|
||||
changed_attributes: expected_changed_attributes
|
||||
)).once
|
||||
listener.conversation_updated(event)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user