From 2866b29f3a582dc8d308404fe26d5fe2303c670e Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma Date: Wed, 6 May 2026 13:44:28 +0700 Subject: [PATCH] feat(voice): reuse open conversation for Twilio outbound calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accept an optional conversation_id in POST /contacts/:id/call. When the hint matches the picked voice inbox, OutboundCallBuilder reuses that conversation instead of creating a new one — mirroring the WhatsApp calling flow so the agent stays in the same thread. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../api/v1/accounts/contacts/calls_controller.rb | 12 +++++++++++- .../app/services/voice/outbound_call_builder.rb | 9 +++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/enterprise/app/controllers/api/v1/accounts/contacts/calls_controller.rb b/enterprise/app/controllers/api/v1/accounts/contacts/calls_controller.rb index 8217e1a37..88290a999 100644 --- a/enterprise/app/controllers/api/v1/accounts/contacts/calls_controller.rb +++ b/enterprise/app/controllers/api/v1/accounts/contacts/calls_controller.rb @@ -10,7 +10,8 @@ class Api::V1::Accounts::Contacts::CallsController < Api::V1::Accounts::BaseCont account: Current.account, inbox: voice_inbox, user: Current.user, - contact: contact + contact: contact, + conversation: existing_conversation ) render json: { @@ -38,4 +39,13 @@ class Api::V1::Accounts::Contacts::CallsController < Api::V1::Accounts::BaseCont inbox end end + + # Reuse the open conversation when the caller is already inside it; ignore + # the hint if it doesn't belong to the picked voice inbox. + def existing_conversation + return nil if params[:conversation_id].blank? + + conversation = Current.account.conversations.find_by(display_id: params[:conversation_id]) + conversation if conversation && conversation.inbox_id == voice_inbox.id + end end diff --git a/enterprise/app/services/voice/outbound_call_builder.rb b/enterprise/app/services/voice/outbound_call_builder.rb index 6c350c5e1..30a74099e 100644 --- a/enterprise/app/services/voice/outbound_call_builder.rb +++ b/enterprise/app/services/voice/outbound_call_builder.rb @@ -1,15 +1,16 @@ class Voice::OutboundCallBuilder attr_reader :account, :inbox, :user, :contact - def self.perform!(account:, inbox:, user:, contact:) - new(account: account, inbox: inbox, user: user, contact: contact).perform! + def self.perform!(account:, inbox:, user:, contact:, conversation: nil) + new(account: account, inbox: inbox, user: user, contact: contact, conversation: conversation).perform! end - def initialize(account:, inbox:, user:, contact:) + def initialize(account:, inbox:, user:, contact:, conversation: nil) @account = account @inbox = inbox @user = user @contact = contact + @existing_conversation = conversation end def perform! @@ -18,7 +19,7 @@ class Voice::OutboundCallBuilder ActiveRecord::Base.transaction do contact_inbox = ensure_contact_inbox! - conversation = create_conversation!(contact_inbox) + conversation = @existing_conversation || create_conversation!(contact_inbox) call_sid = initiate_call! call = create_call!(conversation, call_sid) message = Voice::CallMessageBuilder.new(call).perform!