From e5335fa52bfdb1761d60ae5cb92c011f30a9d929 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Wed, 10 Jun 2026 19:44:44 +0300 Subject: [PATCH] [Chat] Fix duplicate messages when history fetch races firehose (#10839) Co-authored-by: Claude Fable 5 --- src/state/messages/convo/agent.ts | 35 ++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts index 5e5cf3111e..ba5e759f52 100644 --- a/src/state/messages/convo/agent.ts +++ b/src/state/messages/convo/agent.ts @@ -917,17 +917,27 @@ export class Convo { ChatBskyConvoDefs.isLogCreateMessage(ev) && ChatBskyConvoDefs.isMessageView(ev.message) ) { - /** - * If this message is already in new messages, it was added by our - * sending logic, and is based on client-ordering. When we receive - * the "committed" event from the log, we should replace this - * reference and re-insert in order to respect the order we received - * from the log. + /* + * If this message is already in past messages, the initial + * history fetch raced this log event and already returned it. + * Update in place rather than inserting a duplicate into new + * messages. */ - if (this.newMessages.has(ev.message.id)) { - this.newMessages.delete(ev.message.id) + if (this.pastMessages.has(ev.message.id)) { + this.pastMessages.set(ev.message.id, ev.message) + } else { + /** + * If this message is already in new messages, it was added by our + * sending logic, and is based on client-ordering. When we receive + * the "committed" event from the log, we should replace this + * reference and re-insert in order to respect the order we received + * from the log. + */ + if (this.newMessages.has(ev.message.id)) { + this.newMessages.delete(ev.message.id) + } + this.newMessages.set(ev.message.id, ev.message) } - this.newMessages.set(ev.message.id, ev.message) needsCommit = true } else if ( ChatBskyConvoDefs.isLogDeleteMessage(ev) && @@ -964,7 +974,12 @@ export class Convo { } else { const systemView = toSystemMessageView(ev) if (systemView) { - this.newMessages.set(systemView.id, systemView) + // same as above: avoid duplicating if history fetch won the race + if (this.pastMessages.has(systemView.id)) { + this.pastMessages.set(systemView.id, systemView) + } else { + this.newMessages.set(systemView.id, systemView) + } needsCommit = true } }