feat: APIs to assign agents_bots as assignee in conversations (#12836)

## Summary
- add an assignee_agent_bot_id column as an initital step to prototype
this before fully switching to polymorphic assignee
- update assignment APIs and conversation list / show endpoints to
reflect assignee as agent bot
- ensure webhook payloads contains agent bot assignee


[Codex
Task](https://chatgpt.com/codex/tasks/task_e_6912833377e48326b6641b9eee32d50f)

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
Sojan Jose
2025-11-18 18:20:58 -08:00
committed by GitHub
parent 70c183ea6e
commit 5f2b2f4221
23 changed files with 316 additions and 52 deletions

View File

@@ -21,9 +21,18 @@ class AgentBot < ApplicationRecord
include AccessTokenable
include Avatarable
scope :accessible_to, lambda { |account|
account_id = account&.id
where(account_id: [nil, account_id])
}
has_many :agent_bot_inboxes, dependent: :destroy_async
has_many :inboxes, through: :agent_bot_inboxes
has_many :messages, as: :sender, dependent: :nullify
has_many :assigned_conversations, class_name: 'Conversation',
foreign_key: :assignee_agent_bot_id,
dependent: :nullify,
inverse_of: :assignee_agent_bot
belongs_to :account, optional: true
enum bot_type: { webhook: 0 }

View File

@@ -20,6 +20,7 @@
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer not null
# assignee_agent_bot_id :bigint
# assignee_id :integer
# campaign_id :bigint
# contact_id :bigint
@@ -65,6 +66,7 @@ class Conversation < ApplicationRecord
validates :inbox_id, presence: true
validates :contact_id, presence: true
before_validation :validate_additional_attributes
before_validation :reset_agent_bot_when_assignee_present
validates :additional_attributes, jsonb_attributes_length: true
validates :custom_attributes, jsonb_attributes_length: true
validates :uuid, uniqueness: true
@@ -98,6 +100,7 @@ class Conversation < ApplicationRecord
belongs_to :account
belongs_to :inbox
belongs_to :assignee, class_name: 'User', optional: true, inverse_of: :assigned_conversations
belongs_to :assignee_agent_bot, class_name: 'AgentBot', optional: true
belongs_to :contact
belongs_to :contact_inbox
belongs_to :team, optional: true
@@ -180,6 +183,18 @@ class Conversation < ApplicationRecord
true
end
# Virtual attribute till we switch completely to polymorphic assignee
def assignee_type
return 'AgentBot' if assignee_agent_bot_id.present?
return 'User' if assignee_id.present?
nil
end
def assigned_entity
assignee_agent_bot || assignee
end
def tweet?
inbox.inbox_type == 'Twitter' && additional_attributes['type'] == 'tweet'
end
@@ -226,6 +241,12 @@ class Conversation < ApplicationRecord
self.additional_attributes = {} unless additional_attributes.is_a?(Hash)
end
def reset_agent_bot_when_assignee_present
return if assignee_id.blank?
self.assignee_agent_bot_id = nil
end
def determine_conversation_status
self.status = :resolved and return if contact.blocked?
@@ -251,8 +272,8 @@ class Conversation < ApplicationRecord
end
def list_of_keys
%w[team_id assignee_id status snoozed_until custom_attributes label_list waiting_since first_reply_created_at
priority]
%w[team_id assignee_id assignee_agent_bot_id status snoozed_until custom_attributes label_list waiting_since
first_reply_created_at priority]
end
def allowed_keys?