Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions front/components/assistant/conversation/AgentInputBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ export const AgentInputBar = ({ context }: AgentInputBarProps) => {
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.

lastRequestedModel={lastRequestedModel}
conversation={context.conversation}
draftKey={context.draftKey}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ interface InputBarProps {
conversation?: ConversationWithoutContentType;
space?: SpaceType;
stickyMentions?: RichMention[];
stickyMentionsSourceId?: string | null;
defaultAgentId?: string | null;
isDefaultAgentLoading?: boolean;
lastRequestedModel?: ModelSelectionType | null;
Expand Down Expand Up @@ -121,6 +122,7 @@ export const InputBar = React.memo(function InputBar({
draftKey,
space,
stickyMentions,
stickyMentionsSourceId,
defaultAgentId,
isDefaultAgentLoading,
lastRequestedModel = null,
Expand Down Expand Up @@ -767,6 +769,7 @@ export const InputBar = React.memo(function InputBar({
pendingInputText={pendingInputText}
onEnterKeyDown={handleSubmit}
stickyMentions={stickyMentions}
stickyMentionsSourceId={stickyMentionsSourceId}
defaultAgentId={defaultAgentId}
isDefaultAgentLoading={isDefaultAgentLoading}
lastRequestedModel={lastRequestedModel}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,17 @@ export interface InputBarContainerProps {
isSelectableSpacesLoading?: boolean;
onSelectedSpaceIdsChange?: (spaceIds: string[]) => Promise<string[] | null>;
stickyMentions?: RichMention[];
/**
* @cc [owner:frankaloia,label:react] sticky-human-mentions-prefill-once-per-source
* Sticky human mentions MUST be prefilled into the composer at most once per
* (conversation, source message). `stickyMentionsSourceId` identifies that source — the sId of
* the current user's last message the mentions derive from. Callers MUST set it so the prefill
* re-arms only when the user sends a new message (new source id) or switches conversation, not
* on unrelated conversation updates (streaming, other participants' messages). Re-inserting on
* every update re-adds the mention to the empty composer and prevents the user from dismissing
* it.
*/
stickyMentionsSourceId?: string | null;
user: UserType | null;
}

Expand All @@ -278,6 +289,7 @@ const InputBarContainer = ({
selectedAgent,
pendingInputText,
stickyMentions,
stickyMentionsSourceId,
actions,
disableAutoFocus,
disableUserMentions,
Expand Down Expand Up @@ -853,6 +865,11 @@ const InputBarContainer = ({
selectedSingleAgentRef.current = selectedSingleAgent;
// Skip auto-save (especially clearDraft on empty) until initial content is restored.
const hasCompletedInitialContentRestoreRef = useRef(false);
// Tracks the (conversation, source message) for which sticky human mentions were last
// 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.


const saveCurrentDraftWithSelectedSpaces = useCallback(
(spaceIds: string[]) => {
Expand Down Expand Up @@ -1387,7 +1404,6 @@ const InputBarContainer = ({

// Restore draft text when switching conversations (including new conversations).
// Agent selection is handled by useHandleMention.
// biome-ignore lint/correctness/useExhaustiveDependencies: ignored using `--suppress`
useEffect(() => {
hasCompletedInitialContentRestoreRef.current = false;

Expand Down Expand Up @@ -1421,10 +1437,19 @@ const InputBarContainer = ({
return;
}

// No draft — insert sticky user mentions into the editor
// No draft — insert sticky user mentions into the editor, but only once per source message.
// The effect re-runs on every conversation update (streaming, other participants' messages),
// so without this key it would keep re-inserting the mention into the empty composer and the
// user could never dismiss it. The key changes when the current user sends a new message (new
// source id) or switches conversation, which is exactly when we want to re-prefill.
const stickyUserMentions = stickyMentions?.filter(isRichUserMention) ?? [];
if (stickyUserMentions.length > 0) {
const stickyMentionKey = `${conversation?.sId ?? "new"}::${stickyMentionsSourceId ?? ""}`;
if (
stickyUserMentions.length > 0 &&
appliedStickyMentionKeyRef.current !== stickyMentionKey
) {
editorService.resetWithMentions(stickyUserMentions, disableAutoFocus);
appliedStickyMentionKeyRef.current = stickyMentionKey;
}

hasCompletedInitialContentRestoreRef.current = true;
Expand All @@ -1436,6 +1461,7 @@ const InputBarContainer = ({
editorService,
getDraft,
stickyMentions,
stickyMentionsSourceId,
disableAutoFocus,
]);

Expand Down
Loading