diff --git a/app/src/pages/Conversations.tsx b/app/src/pages/Conversations.tsx index a3c43a843..640bce73a 100644 --- a/app/src/pages/Conversations.tsx +++ b/app/src/pages/Conversations.tsx @@ -1859,13 +1859,6 @@ const Conversations = ({ const isAgentTextMode = msg.sender === 'agent' && agentMessageViewMode === 'text'; return (
- {shouldRenderTimelineBeforeLatestAgentMessage && - latestVisibleAgentMessage?.id === msg.id && ( - setOpenSubagentTaskId(sub.taskId)} - /> - )}
; })()} - {shouldRenderTimelineBeforeLatestAgentMessage && - latestVisibleAgentMessage?.id === msg.id && ( - - )} {latestVisibleMessage?.id === msg.id && (

{formatRelativeTime(msg.createdAt)} @@ -2254,14 +2237,34 @@ const Conversations = ({

)} - {/* Tool call timeline */} - {selectedThreadToolTimeline.length > 0 && - !shouldRenderTimelineBeforeLatestAgentMessage && ( - setOpenSubagentTaskId(sub.taskId)} - /> - )} + {/* Agentic task insights — rendered exactly once AFTER the full + message list. A single logical assistant turn can be persisted + as multiple agent ThreadMessages; anchoring the panel before the + last agent message split the response into two disconnected + chunks (issue #3717, Bug 2). Hoisting it here keeps the panel + after the complete response regardless of how many agent + messages the turn produced — both for the settled/inline case + (shouldRenderTimelineBeforeLatestAgentMessage) and the live + in-flight fallback. */} + {selectedThreadToolTimeline.length > 0 && ( + setOpenSubagentTaskId(sub.taskId)} + /> + )} + {/* "View full agent process" — only in the settled/inline state + (turn finished, an agent message exists). Hoisted out of the + per-message map alongside the panel above so it renders once + after the response, never interleaved between bubbles. */} + {shouldRenderTimelineBeforeLatestAgentMessage && ( + + )} {isSending && rustChat && (