fix(captain): resolve Hermes quoted replies by internal id
Some checks failed
Build and Push to GHCR (multi-arch) / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Build and Push to GHCR (multi-arch) / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Build and Push to GHCR (multi-arch) / merge (push) Has been cancelled

This commit is contained in:
Rodribm10 2026-05-24 17:22:05 -03:00
parent 572b9ccd10
commit cbbfccaf42
2 changed files with 53 additions and 3 deletions

View File

@ -5,10 +5,11 @@ class Captain::Hermes::ReplyContextBuilder
end end
def perform def perform
return nil if reply_to_external_id.blank? return nil if reply_reference.blank?
{ {
external_id: reply_to_external_id, external_id: reply_to_external_id,
message_id: reply_to_message_id,
found: quoted_message.present?, found: quoted_message.present?,
quoted_message: quoted_message_snapshot quoted_message: quoted_message_snapshot
}.compact }.compact
@ -38,6 +39,8 @@ class Captain::Hermes::ReplyContextBuilder
[CONTEXTO DE RESPOSTA DO WHATSAPP] [CONTEXTO DE RESPOSTA DO WHATSAPP]
O cliente respondeu citando uma mensagem anterior. O cliente respondeu citando uma mensagem anterior.
Interprete a resposta atual como referência direta a essa mensagem citada. Interprete a resposta atual como referência direta a essa mensagem citada.
Se a resposta atual usar termos como "esse valor", "desse valor", "essa", "esse" ou "isso",
resolva a referência usando a mensagem citada antes do restante do histórico.
Mensagem citada (#{quoted[:sender_label]}, #{quoted[:created_at]}): #{quoted_content} Mensagem citada (#{quoted[:sender_label]}, #{quoted[:created_at]}): #{quoted_content}
TEXT TEXT
end end
@ -46,18 +49,31 @@ class Captain::Hermes::ReplyContextBuilder
<<~TEXT.strip <<~TEXT.strip
[CONTEXTO DE RESPOSTA DO WHATSAPP] [CONTEXTO DE RESPOSTA DO WHATSAPP]
O cliente respondeu citando uma mensagem anterior, mas o Chatwoot não encontrou o conteúdo da mensagem citada. O cliente respondeu citando uma mensagem anterior, mas o Chatwoot não encontrou o conteúdo da mensagem citada.
ID externo citado: #{reply_context[:external_id]} Referência citada: #{reply_reference}
TEXT TEXT
end end
def reply_reference
reply_to_external_id.presence || reply_to_message_id.presence
end
def reply_to_external_id def reply_to_external_id
@reply_to_external_id ||= message.in_reply_to_external_id.presence || @reply_to_external_id ||= message.in_reply_to_external_id.presence ||
message.content_attributes.to_h['in_reply_to_external_id'].presence || message.content_attributes.to_h['in_reply_to_external_id'].presence ||
message.content_attributes.to_h[:in_reply_to_external_id].presence message.content_attributes.to_h[:in_reply_to_external_id].presence
end end
def reply_to_message_id
@reply_to_message_id ||= message.in_reply_to_id.presence ||
message.content_attributes.to_h['in_reply_to'].presence ||
message.content_attributes.to_h[:in_reply_to].presence
end
def quoted_message def quoted_message
@quoted_message ||= conversation.messages.find_by(source_id: reply_to_external_id) @quoted_message ||= begin
found_by_id = conversation.messages.find_by(id: reply_to_message_id) if reply_to_message_id.present?
found_by_id || conversation.messages.find_by(source_id: reply_to_external_id)
end
end end
def quoted_message_snapshot def quoted_message_snapshot

View File

@ -50,6 +50,40 @@ RSpec.describe Captain::Hermes::Client do
expect(payload[:message]).to include('Pode reservar essa') expect(payload[:message]).to include('Pode reservar essa')
end end
it 'includes quoted context when Chatwoot stores the reply as an internal message id' do
quoted_message = create(
:message,
account: account,
inbox: inbox,
conversation: conversation,
message_type: :outgoing,
content: "Stilo hoje fica assim:\n1h R$ 50\nValor pra ate 2 pessoas.",
source_id: 'WAID:quoted-stilo'
)
reply = create(
:message,
account: account,
inbox: inbox,
conversation: conversation,
message_type: :incoming,
content: 'Quero uma 1 hora na suite desse valor',
source_id: 'WAID:reply-stilo',
in_reply_to_id: quoted_message.id
)
payload = client.send(:build_payload, message: reply, conversation: conversation)
expect(payload[:reply_context]).to include(
message_id: quoted_message.id,
external_id: quoted_message.source_id,
found: true
)
expect(payload[:message]).to include('Stilo hoje fica assim')
expect(payload[:message]).to include('1h R$ 50')
expect(payload[:message]).to include('resolva a referência usando a mensagem citada')
expect(payload[:message]).to include('Quero uma 1 hora na suite desse valor')
end
it 'keeps the combined incoming text while adding quote context' do it 'keeps the combined incoming text while adding quote context' do
quoted_message = create( quoted_message = create(
:message, :message,