diff --git a/desktop/src/app/routes/ChannelRouteScreen.tsx b/desktop/src/app/routes/ChannelRouteScreen.tsx index 2855e44af..1e1b3ff43 100644 --- a/desktop/src/app/routes/ChannelRouteScreen.tsx +++ b/desktop/src/app/routes/ChannelRouteScreen.tsx @@ -168,6 +168,24 @@ export function ChannelRouteScreen({ const effectiveAgentConversationReplyId = isChannelTasksEnabled ? targetAgentConversationReplyId : null; + const targetAgentConversationBackfillKey = + effectiveAgentConversationReplyId && !selectedPostId + ? [ + channelId, + effectiveAgentConversationReplyId, + targetMessageId ?? "", + targetThreadRootId ?? "", + ].join(":") + : null; + const [ + completedTargetAgentConversationBackfillKey, + setCompletedTargetAgentConversationBackfillKey, + ] = React.useState(null); + const targetAgentConversationBackfillPending = Boolean( + targetAgentConversationBackfillKey && + completedTargetAgentConversationBackfillKey !== + targetAgentConversationBackfillKey, + ); // Reset spliced target events when the channel context changes (channel // switch or entering/leaving a forum post). Tied to channel identity rather @@ -201,6 +219,7 @@ export function ChannelRouteScreen({ !targetThreadRootId) || selectedPostId ) { + setCompletedTargetAgentConversationBackfillKey(null); return () => { isCancelled = true; }; @@ -233,21 +252,29 @@ export function ChannelRouteScreen({ effectiveAgentConversationReplyId ?? targetMessageId, effectiveAgentConversationReplyId, targetThreadRootId, - ).then((events) => { - if (!isCancelled) { - queryClient.setQueryData( - channelMessagesKey(channelId), - (currentEvents) => mergeRouteEvents(currentEvents, events), - ); - setTargetMessageEvents((currentEvents) => { - const eventsById = new Map(); - for (const event of [...currentEvents, ...events]) { - eventsById.set(event.id, event); - } - return Array.from(eventsById.values()); - }); - } - }); + ) + .then((events) => { + if (!isCancelled) { + queryClient.setQueryData( + channelMessagesKey(channelId), + (currentEvents) => mergeRouteEvents(currentEvents, events), + ); + setTargetMessageEvents((currentEvents) => { + const eventsById = new Map(); + for (const event of [...currentEvents, ...events]) { + eventsById.set(event.id, event); + } + return Array.from(eventsById.values()); + }); + } + }) + .finally(() => { + if (!isCancelled && targetAgentConversationBackfillKey) { + setCompletedTargetAgentConversationBackfillKey( + targetAgentConversationBackfillKey, + ); + } + }); return () => { isCancelled = true; @@ -257,6 +284,7 @@ export function ChannelRouteScreen({ channelId, queryClient, effectiveAgentConversationReplyId, + targetAgentConversationBackfillKey, targetMessageId, targetThreadRootId, ]); @@ -283,6 +311,9 @@ export function ChannelRouteScreen({ }} selectedForumPostId={selectedPostId} targetAgentConversationReplyId={effectiveAgentConversationReplyId} + targetAgentConversationBackfillPending={ + targetAgentConversationBackfillPending + } targetForumReplyId={targetReplyId} targetMessageEvents={targetMessageEvents} targetMessageId={targetMessageId} diff --git a/desktop/src/features/channels/ui/ChannelScreen.tsx b/desktop/src/features/channels/ui/ChannelScreen.tsx index 3d7ddc6af..ac79b84d4 100644 --- a/desktop/src/features/channels/ui/ChannelScreen.tsx +++ b/desktop/src/features/channels/ui/ChannelScreen.tsx @@ -88,6 +88,7 @@ export function ChannelScreen({ onCloseForumPost, onSelectForumPost, selectedForumPostId, + targetAgentConversationBackfillPending = false, targetAgentConversationReplyId, targetForumReplyId, targetMessageEvents, @@ -743,6 +744,7 @@ export function ChannelScreen({ goChannel, messageProfilesReady, openAgentConversation, + targetBackfillPending: targetAgentConversationBackfillPending, targetAgentConversationReplyId: isChannelTasksEnabled ? targetAgentConversationReplyId : null, diff --git a/desktop/src/features/channels/ui/ChannelScreen.types.ts b/desktop/src/features/channels/ui/ChannelScreen.types.ts index 5401c44b1..24c23745a 100644 --- a/desktop/src/features/channels/ui/ChannelScreen.types.ts +++ b/desktop/src/features/channels/ui/ChannelScreen.types.ts @@ -12,6 +12,7 @@ export type ChannelScreenProps = { onCloseForumPost: () => void; onSelectForumPost: (postId: string) => void; selectedForumPostId: string | null; + targetAgentConversationBackfillPending?: boolean; targetAgentConversationReplyId: string | null; targetForumReplyId: string | null; targetMessageEvents: RelayEvent[]; diff --git a/desktop/src/features/channels/ui/useAgentConversationRouteTarget.ts b/desktop/src/features/channels/ui/useAgentConversationRouteTarget.ts index b4e7029d6..09f10bbd2 100644 --- a/desktop/src/features/channels/ui/useAgentConversationRouteTarget.ts +++ b/desktop/src/features/channels/ui/useAgentConversationRouteTarget.ts @@ -31,6 +31,7 @@ type UseAgentConversationRouteTargetInput = { input: OpenAgentConversationInput, options?: { publishMarker?: boolean }, ) => void; + targetBackfillPending: boolean; targetAgentConversationReplyId: string | null; timelineMessages: readonly TimelineMessage[]; }; @@ -63,6 +64,7 @@ export function useAgentConversationRouteTarget({ goChannel, messageProfilesReady, openAgentConversation, + targetBackfillPending, targetAgentConversationReplyId, timelineMessages, }: UseAgentConversationRouteTargetInput) { @@ -98,6 +100,9 @@ export function useAgentConversationRouteTarget({ if (!sourceMessage) { return; } + if (!marker && targetBackfillPending) { + return; + } if (!marker?.agentPubkey && !agentLookupReady) { return; } @@ -160,6 +165,7 @@ export function useAgentConversationRouteTarget({ goChannel, messageProfilesReady, openAgentConversation, + targetBackfillPending, targetAgentConversationReplyId, timelineMessages, ]);