fix(hermes): debounce agrupava msgs de turns ANTIGOS (default_scope ASC)
Bug raiz que causou todos os problemas de "Hermes repetindo info de
turns anteriores" hoje:
Message tem default_scope order(created_at: :asc). O combined_incoming_
content fazia .order(created_at: :desc) que GERA SQL com 2 orderings
em conflito ("ORDER BY created_at ASC, created_at DESC") — no Postgres
o ASC ganha quando a primeira coluna é igual. Resultado:
last_real_outgoing virava a MAIS ANTIGA outgoing (a saudação inicial),
não a mais recente. Aí o scope incoming agrupava TODAS as msgs do
cliente desde o "Oi" da Juliana, juntando wifi+pet num turn só.
Caso real conv 6064 (2026-05-02 21:18):
T1: cliente "Preciso senha wifi" → Hermes "Prime2025"
T2: cliente "Posso levar animais?"
→ debounce agrupou ["Preciso senha wifi", "Posso levar animais"]
como se fossem MSGS DO MESMO TURN, mandou pro Hermes como
"Cliente acabou de dizer: Preciso senha wifi.\nPosso levar animais?"
→ Hermes consultou faq_lookup com query "senha wifi e animais"
→ Resposta: "Senha Prime2025 e pode levar animais"
Fix: usa .reorder(created_at: :desc) que sobrescreve default_scope,
gerando SQL limpa com só "ORDER BY created_at DESC".
Camadas 3 (strip linhas) e 4 (topic gating) que adicionei antes são
paliativos válidos como defesa em profundidade, mas o problema raiz
era esse default_scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ebf98c90f4
commit
f1d3a124d5
@ -55,17 +55,24 @@ class Captain::Hermes::OutgoingJob < ApplicationJob
|
|||||||
# Concatena texto de todas as msgs incoming entre a última resposta real
|
# Concatena texto de todas as msgs incoming entre a última resposta real
|
||||||
# (não-reaction) do agente e a msg âncora. Retorna nil se só tem 1 msg
|
# (não-reaction) do agente e a msg âncora. Retorna nil se só tem 1 msg
|
||||||
# (pra dispatch usar message.content normal).
|
# (pra dispatch usar message.content normal).
|
||||||
|
#
|
||||||
|
# Atenção: usa `reorder` em vez de `order` porque o model Message tem
|
||||||
|
# default_scope `order(created_at: :asc)` — sem reorder, a SQL final fica
|
||||||
|
# `ORDER BY created_at ASC, created_at DESC` e o ASC ganha. Resultado:
|
||||||
|
# last_real_outgoing virava a MAIS ANTIGA, agrupando msgs de turns
|
||||||
|
# passados (caso real: Hermes recebia "wifi+pet" colado mesmo em turns
|
||||||
|
# separados — visto em conv 6064 em 2026-05-02).
|
||||||
def combined_incoming_content(conversation, anchor_message)
|
def combined_incoming_content(conversation, anchor_message)
|
||||||
last_real_outgoing = conversation.messages
|
last_real_outgoing = conversation.messages
|
||||||
.where(message_type: :outgoing)
|
.where(message_type: :outgoing)
|
||||||
.where("(content_attributes ->> 'is_reaction') IS NULL OR (content_attributes ->> 'is_reaction') != 'true'")
|
.where("(content_attributes ->> 'is_reaction') IS NULL OR (content_attributes ->> 'is_reaction') != 'true'")
|
||||||
.order(created_at: :desc)
|
.reorder(created_at: :desc)
|
||||||
.first
|
.first
|
||||||
|
|
||||||
scope = conversation.messages.where(message_type: :incoming).where('created_at <= ?', anchor_message.created_at)
|
scope = conversation.messages.where(message_type: :incoming).where('created_at <= ?', anchor_message.created_at)
|
||||||
scope = scope.where('created_at > ?', last_real_outgoing.created_at) if last_real_outgoing
|
scope = scope.where('created_at > ?', last_real_outgoing.created_at) if last_real_outgoing
|
||||||
|
|
||||||
texts = scope.order(:created_at).pluck(:content).map(&:to_s).reject(&:blank?).uniq
|
texts = scope.reorder(created_at: :asc).pluck(:content).map(&:to_s).reject(&:blank?).uniq
|
||||||
return nil if texts.size <= 1
|
return nil if texts.size <= 1
|
||||||
|
|
||||||
Rails.logger.info("[Captain::Hermes::Debounce] agrupando #{texts.size} msgs do cliente em conv #{conversation.id}")
|
Rails.logger.info("[Captain::Hermes::Debounce] agrupando #{texts.size} msgs do cliente em conv #{conversation.id}")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user