Revert subagent group eager auto-collapse

This commit is contained in:
Siddharth Ganesan
2026-08-13 15:28:48 -07:00
parent 6f36331b7a
commit 0cab4d0589
3 changed files with 19 additions and 12 deletions
@@ -110,6 +110,7 @@ describe('AgentGroup browser takeover', () => {
agentLabel: 'Browser Agent',
items: [tool('success'), browserTakeover(reason)],
isStreaming: true,
isCurrentSection: true,
isLaneOpen: true,
})
)
@@ -183,6 +184,7 @@ describe('AgentGroup browser takeover', () => {
agentLabel: 'Browser Agent',
items: [takeover],
isStreaming: true,
isCurrentSection: true,
isLaneOpen: true,
})
)
@@ -204,6 +206,7 @@ describe('AgentGroup browser takeover', () => {
agentLabel: 'Browser Agent',
items: [completedTakeover],
isStreaming: true,
isCurrentSection: true,
isLaneOpen: true,
})
)
@@ -37,6 +37,8 @@ interface AgentGroupProps {
items: AgentGroupItem[]
isDelegating?: boolean
isStreaming?: boolean
/** This group is the latest section in its parent sequence (drives collapse). */
isCurrentSection?: boolean
/** The subagent lane is still open (no subagent_end yet) — i.e. actively running. */
isLaneOpen?: boolean
}
@@ -108,6 +110,7 @@ export function AgentGroup({
items,
isDelegating = false,
isStreaming = false,
isCurrentSection = false,
isLaneOpen = false,
}: AgentGroupProps) {
const AgentIcon = getAgentIcon(agentName)
@@ -120,18 +123,17 @@ export function AgentGroup({
const isWorking =
!activeBrowserTakeover && ((isDelegating && !resolved) || (isStreaming && isLaneOpen))
// Expand while the turn is live and the subagent is still working: the lane
// is open, or there is unresolved work. When the lane closes and the work
// resolves the group collapses — with parallel subagents, finished siblings
// fold away while the still-running ones stay open, instead of every group
// lingering expanded until the next section starts. Keying "still running"
// off the lane-open signal (not `resolved` alone) avoids a collapse/reopen
// flicker mid-run: a subagent's tools all momentarily read "done" in the gap
// between its last search and its `respond` ("Gathering thoughts") tool,
// transiently flipping `resolved` true; the open lane bridges that gap. The
// turn ending (isStreaming false) collapses everything; a manual toggle pins
// the choice.
const autoExpanded = isStreaming && (isLaneOpen || !resolved)
// Expand while the turn is live and any of: the lane is open (the subagent is
// actively running), this is the current/latest section, or there is unresolved
// work. A finished group stays open until the NEXT section starts (it is no
// longer the latest), instead of collapsing the instant its own work resolves.
// Keying "still running" off the lane-open signal (not `resolved` alone) avoids
// a collapse/reopen flicker on parallel siblings: a subagent's tools all
// momentarily read "done" in the gap between its last search and its `respond`
// ("Gathering thoughts") tool, transiently flipping `resolved` true; the open
// lane bridges that gap so the row never collapses mid-run. The turn ending
// (isStreaming false) collapses everything; a manual toggle pins the choice.
const autoExpanded = isStreaming && (isCurrentSection || isLaneOpen || !resolved)
const [manualExpanded, setManualExpanded] = useState<boolean | null>(null)
const [expandedTakeoverId, setExpandedTakeoverId] = useState<string | null>(null)
// An outstanding permission prompt overrides a manual collapse: the turn
@@ -217,6 +219,7 @@ export function AgentGroup({
items={item.group.items}
isDelegating={item.group.isDelegating}
isStreaming={isStreaming}
isCurrentSection={idx === items.length - 1}
isLaneOpen={item.group.isOpen}
/>
</div>
@@ -957,6 +957,7 @@ function MessageContentInner({
items={segment.items}
isDelegating={segment.isDelegating}
isStreaming={isStreaming}
isCurrentSection={i === segments.length - 1}
isLaneOpen={segment.isOpen}
/>
</div>