@@ -14,6 +14,7 @@ import { ShimmerText } from '@/components/ui'
1414import { isBrowserAgentAvailable } from '@/lib/browser-agent/transport'
1515import { RETIRED_BROWSER_REQUEST_TAKEOVER_ID } from '@/lib/copilot/tools/retired-tools'
1616import { renderInlineMarkdown } from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/inline-markdown'
17+ import { getVisibleMainAgentItems } from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/main-agent-activity'
1718import type { ToolCallItemProps } from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item'
1819import {
1920 getAgentIcon ,
@@ -47,11 +48,9 @@ export interface AgentGroupProps {
4748 items : AgentGroupItem [ ]
4849 isDelegating ?: boolean
4950 isStreaming ?: boolean
50- /** This group is the latest section in its parent sequence (drives collapse). */
51- isCurrentSection ?: boolean
5251 /** The subagent lane is still open (no subagent_end yet) — i.e. actively running. */
5352 isLaneOpen ?: boolean
54- /** Opens the group on first render without changing production's automatic collapse rules . */
53+ /** Opens a subagent group on first render. */
5554 defaultExpanded ?: boolean
5655 /** Keeps the activity viewport anchored at the top while new rows stream in. */
5756 autoScrollActivity ?: boolean
@@ -151,7 +150,6 @@ export function AgentGroupView({
151150 items,
152151 isDelegating = false ,
153152 isStreaming = false ,
154- isCurrentSection = false ,
155153 isLaneOpen = false ,
156154 defaultExpanded = false ,
157155 autoScrollActivity = true ,
@@ -192,26 +190,15 @@ export function AgentGroupView({
192190 const isWorking =
193191 ! activeBrowserTakeover && ( ( isDelegating && ! resolved ) || ( isStreaming && isLaneOpen ) )
194192
195- // SUBAGENT groups never auto-expand: the collapsed row IS the live view —
196- // label plus latest running tool title. Expanding is a deliberate user
197- // action; only a pending permission prompt or a browser hand-back forces
198- // one open. The MAIN lane ("Sim") is not a delegation card: its narration
199- // and tool calls are the turn itself, so it keeps the original live-expand
200- // behavior (open while streaming/current, settles when superseded).
201- const autoExpanded = isMainAgent && isStreaming && ( isCurrentSection || isLaneOpen || ! resolved )
202- const [ manualExpanded , setManualExpanded ] = useState < boolean | null > (
203- defaultExpanded ? true : null
204- )
193+ const [ manualExpanded , setManualExpanded ] = useState ( defaultExpanded )
205194 const [ expandedTakeoverId , setExpandedTakeoverId ] = useState < string | null > ( null )
206195 // An outstanding permission prompt overrides a manual collapse: the turn
207196 // cannot proceed until it is answered, so hiding it would deadlock the chat
208197 // with nothing on screen to explain why.
209198 const expanded =
210199 hasAwaitingApproval ( items ) ||
211200 nestedBrowserTakeover ||
212- ( activeBrowserTakeover
213- ? expandedTakeoverId === activeBrowserTakeover . id
214- : ( manualExpanded ?? autoExpanded ) )
201+ ( activeBrowserTakeover ? expandedTakeoverId === activeBrowserTakeover . id : manualExpanded )
215202
216203 const toggleExpanded = ( ) => {
217204 if ( activeBrowserTakeover ) {
@@ -221,9 +208,54 @@ export function AgentGroupView({
221208 setManualExpanded ( ! expanded )
222209 }
223210
211+ const visibleItems = isMainAgent ? getVisibleMainAgentItems ( items ) : items
212+ const activity = (
213+ < div className = { cn ( 'flex min-w-0 flex-col gap-1.5' , ! isMainAgent && 'py-0.5 pl-6' ) } >
214+ { visibleItems . map ( ( item , idx ) => {
215+ if ( item . type === 'tool' ) {
216+ return (
217+ < ToolCallComponent
218+ key = { item . data . id }
219+ toolCallId = { item . data . id }
220+ toolName = { item . data . toolName }
221+ displayTitle = { item . data . displayTitle }
222+ status = { item . data . status }
223+ params = { item . data . params }
224+ result = { item . data . result }
225+ streamingArgs = { item . data . streamingArgs }
226+ startedAt = { item . data . startedAt }
227+ />
228+ )
229+ }
230+ if ( item . type === 'agent_group' ) {
231+ return (
232+ < AgentGroupView
233+ key = { item . group . id }
234+ ToolCallComponent = { ToolCallComponent }
235+ renderBrowserTakeover = { renderBrowserTakeover }
236+ agentName = { item . group . agentName }
237+ agentLabel = { item . group . agentLabel }
238+ items = { item . group . items }
239+ isDelegating = { item . group . isDelegating }
240+ isStreaming = { isStreaming }
241+ isLaneOpen = { item . group . isOpen }
242+ />
243+ )
244+ }
245+ return (
246+ < NarrationText
247+ key = { `text-${ idx } ` }
248+ content = { item . content }
249+ isStreaming = { isStreaming && idx === visibleItems . length - 1 }
250+ />
251+ )
252+ } ) }
253+ </ div >
254+ )
255+
224256 return (
225257 < div className = 'flex flex-col gap-1.5' >
226- { hasItems ? (
258+ { isMainAgent ? null : hasItems ? (
227259 < button
228260 type = 'button'
229261 onClick = { toggleExpanded }
@@ -256,60 +288,20 @@ export function AgentGroupView({
256288 ) }
257289 </ div >
258290 ) }
259- { hasItems && (
291+ { isMainAgent ? (
292+ activity
293+ ) : hasItems ? (
260294 < Expandable expanded = { expanded } >
261295 < ExpandableContent >
262296 < BoundedViewport
263297 isStreaming = { isStreaming && autoScrollActivity }
264298 unbounded = { nestedBrowserTakeover }
265299 >
266- < div className = 'flex flex-col gap-1.5 py-0.5' >
267- { items . map ( ( item , idx ) => {
268- if ( item . type === 'tool' ) {
269- return (
270- < ToolCallComponent
271- key = { item . data . id }
272- toolCallId = { item . data . id }
273- toolName = { item . data . toolName }
274- displayTitle = { item . data . displayTitle }
275- status = { item . data . status }
276- params = { item . data . params }
277- result = { item . data . result }
278- streamingArgs = { item . data . streamingArgs }
279- startedAt = { item . data . startedAt }
280- />
281- )
282- }
283- if ( item . type === 'agent_group' ) {
284- return (
285- < div key = { item . group . id } className = 'pl-6' >
286- < AgentGroupView
287- ToolCallComponent = { ToolCallComponent }
288- renderBrowserTakeover = { renderBrowserTakeover }
289- agentName = { item . group . agentName }
290- agentLabel = { item . group . agentLabel }
291- items = { item . group . items }
292- isDelegating = { item . group . isDelegating }
293- isStreaming = { isStreaming }
294- isCurrentSection = { idx === items . length - 1 }
295- isLaneOpen = { item . group . isOpen }
296- />
297- </ div >
298- )
299- }
300- return (
301- < NarrationText
302- key = { `text-${ idx } ` }
303- content = { item . content }
304- isStreaming = { isStreaming && idx === items . length - 1 }
305- />
306- )
307- } ) }
308- </ div >
300+ { activity }
309301 </ BoundedViewport >
310302 </ ExpandableContent >
311303 </ Expandable >
312- ) }
304+ ) : null }
313305 { activeBrowserTakeover && (
314306 < div key = { activeBrowserTakeover . id } className = 'animate-stream-fade-in' >
315307 { renderBrowserTakeover ?.( activeBrowserTakeover . reason ) }
@@ -334,7 +326,7 @@ function NarrationText({ content, isStreaming }: NarrationTextProps) {
334326 const revealed = useSmoothText ( content , isStreaming )
335327
336328 return (
337- < span className = 'pl-6 text-[13px] text-[var(--text-muted)] leading-[18px]' >
329+ < span className = 'text-[13px] text-[var(--text-muted)] leading-[18px]' >
338330 { renderInlineMarkdown ( revealed . trim ( ) ) }
339331 </ span >
340332 )
0 commit comments