Skip to content

[front] fix: stop sticky human mention re-inserting in the composer - #32281

Open
frankaloia wants to merge 2 commits into
mainfrom
frank/fix-sticky-human-mention-reinsert
Open

[front] fix: stop sticky human mention re-inserting in the composer#32281
frankaloia wants to merge 2 commits into
mainfrom
frank/fix-sticky-human-mention-reinsert

Conversation

@frankaloia

@frankaloia frankaloia commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes dust-tt/tasks#10353.

In a multi-user conversation, the user's handle kept popping back into the composer after every message/answer and couldn't be dismissed.

Root cause

The "sticky human mentions" feature (#25480). The sticky mention is derived from your own last sent message:

const lastUserMessage = allMessages.filter(isUserMessage).findLast(
  (m) => ... && m.user?.id === context.user.id && ...   // your messages only
);
// autoMentions = lastUserMessage.richMentions, iff they are all human mentions

autoMentions becomes stickyMentions, and the draft-restore effect in InputBarContainer.tsx inserts them via editorService.resetWithMentions(...). That effect re-runs whenever stickyMentions changes reference — and stickyMentions derives from lastUserMessage, which gets a new object reference on every conversation store update (another participant's message, an agent answer, each streaming tick). Its only guard was editorService.isEmpty(), so whenever the composer was empty it re-inserted the mention.

So stickyMentions = "the human mentions in the last message I sent," and whether it reappears is entirely a function of what you last sent:

  • You send with @B still in it — the default, because the composer pre-fills @B, so unless you delete the chip whatever you type goes out as "@b …". Your new last message still mentions @BautoMentions is still [@B] → after the composer clears it re-inserts @B. This is the vicious loop: the prefill guarantees your next message keeps the mention, which keeps it sticky, which prefills again.
  • You send without @B (deleted the chip, sent a plain message) — your last message has no mention → autoMentions returns [] → nothing inserted. Cleared.

Two consequences:

  • It reappears after every message/answer (your last message still carries the mention, and the churn re-inserts it on every store update while the box is empty).
  • You can't dismiss it: deleting the chip empties the composer, and the next update (or the clear/re-render during your own send) re-inserts it before you can get a mention-less message out. Once it's back, the "editor not empty" guard stops the later-empty derivation from removing it — so the only escape is to send a message without the mention.

Fix

Gate the insertion on an idempotency key (conversation.sId, source message sId) held in a ref — insert at most once per source message:

  • Deleting the chip now sticks — same source id, already offered → not re-inserted.
  • Streaming / other participants' messages don't re-insert — your last message's sId is unchanged.
  • Re-prefill still works — sending a new message that keeps the mention changes the source id, so it re-arms (preserving the intended stickiness; the submit handler only clears the editor and relies on this effect to re-prefill).
  • Sending a message with no mention clears it naturally (autoMentions returns []).

Plumbs stickyMentionsSourceId (the current user's last message sId) through AgentInputBar → InputBar → InputBarContainer, documented with a @cc [label:react] contract on the prop.

Pattern

The guard is the codebase's standard "run once per id" ref idiom — same shape as useAutoOpenSidePanel.ts (autoOpenedFilesForRef === agentMessage.sId), the composite-key initKey guards (MCPServerAuthConnection.tsx), and the sibling useHandleMentions.tsx (prevConversationIdRef) that handles agent sticky mentions.

Testing

  • npx tsgo --noEmit (front): no new errors (pre-existing unrelated archiver decl only).
  • biome check + cc-check format/list on the changed file: clean; the new contract is discoverable.

Behavior reasoned through the effect's re-run conditions; there's no automated harness for this tiptap+Virtuoso composer.

Risk

Low, scoped to the sticky human-mention prefill. Agent-mention selection (useHandleMentions) is untouched. Agent builder passes no source id and only has agent sticky mentions, so it's unaffected.

Deploy Plan

  1. Deploy fron

Reviewer

r? @ykmsd Eng runner ticket https://github.com/dust-tt/tasks/issues/10353

frankaloia and others added 2 commits September 10, 2026 13:06
In a multi-user conversation, if your last message mentioned only human
user(s), the "sticky human mentions" feature re-inserted that mention into the
composer on every conversation update — incoming messages from other
participants, agent answers, and streaming ticks. Because the insertion effect
re-ran whenever stickyMentions (derived from the last user message) got a new
reference, and only guarded on the editor being empty, the mention kept popping
back and could not be dismissed: deleting it emptied the editor, and the next
update re-inserted it (#10353).

Gate the prefill on an idempotency key of (conversation sId, source message
sId). The mention is inserted at most once per source message, re-arming only
when the user sends a new message or switches conversation — preserving the
intended stickiness while ignoring unrelated updates and honoring deletion.
Plumbs stickyMentionsSourceId (the current user's last message sId) through
AgentInputBar -> InputBar -> InputBarContainer and documents the invariant with
a @cc contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bare #10353 refs resolve to the wrong issue inside dust-tt/dust; keep the
explanatory prose without the number.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@frankaloia
frankaloia requested a review from ykmsd September 10, 2026 17:39

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc-verify: violations found!

  • sticky-human-mentions-prefill-once-per-source: Dismissed mentions reappear

user={context.user}
onSubmit={context.handleSubmit}
stickyMentions={autoMentions}
stickyMentionsSourceId={lastUserMessage?.sId ?? null}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new sticky-human-mentions-prefill-once-per-source contract on InputBarContainerProps.stickyMentionsSourceId conflicts with the pre-existing optimistic-message lifecycle: lastUserMessage changes from placeholder-user-message-* to a server ID for the same send (ConversationViewer.tsx:1296). If acknowledgment occurs while the initial prefill remains, the ref keeps the placeholder key; dismissing the mention and receiving another update then reinserts it without a new message.

// prefilled, so we insert them once per source rather than on every re-render. Without this,
// streaming updates and other participants' messages would keep re-inserting the mention into
// the empty composer, and the user could not dismiss it.
const appliedStickyMentionKeyRef = useRef<string | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new sticky-human-mentions-prefill-once-per-source contract on InputBarContainerProps.stickyMentionsSourceId also conflicts with the pre-existing UserAnswerRequired swap in AgentInputBar, which unmounts the composer when an earlier agent run asks a question. Answering remounts it with this ref reset to null, so a previously dismissed human mention is inserted again for the unchanged conversation and source message.

@Fraggle Fraggle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants