Skip to content

fix(mothership): parallel subagent rendering#4299

Open
icecrasher321 wants to merge 1 commit intostagingfrom
fix/subagent-parallel-render
Open

fix(mothership): parallel subagent rendering#4299
icecrasher321 wants to merge 1 commit intostagingfrom
fix/subagent-parallel-render

Conversation

@icecrasher321
Copy link
Copy Markdown
Collaborator

Summary

Parallel subagent rendering would sometime leave lane looking like it was still running, even though everything works correctly.

Type of Change

  • Bug fix

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 25, 2026 3:55am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 25, 2026

PR Summary

Medium Risk
Touches the SSE streaming pipeline and message segmentation logic; mistakes could cause missing/duplicated subagent groups or incorrect “still running” UI state during parallel subagent runs.

Overview
Fixes parallel subagent rendering by deduping subagent lifecycle markers in the Go SSE stream: subagent start now avoids reopening an already-open subagent block (and avoids duplicating entries in subAgentParentStack).

Updates the message-content block parser to skip rendering dispatch tool_calls when a later subagent block for the same agent appears, preventing orphan/duplicate groups that could leave a lane looking active after completion.

Reviewed by Cursor Bugbot for commit 340c154. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR fixes a visual bug where parallel subagent lanes would appear to still be running after completion. It does so via two coordinated changes: in stream.ts, a duplicate-guard on contentBlocks prevents the same open subagent block from being pushed twice on repeated start events; in message-content.tsx, dispatch tool_call blocks for a subagent are skipped when a proper subagent content block already exists later in the stream, preventing the "running" indicator from persisting incorrectly.

Confidence Score: 4/5

Safe to merge — changes are narrowly scoped to the parallel subagent rendering path and introduce no regressions in the normal single-agent flow.

Only P2 findings present. Both changes are logically sound: the duplicate-open-block guard in stream.ts correctly uses endedAt === undefined as the open-block signal, and the pre-pass skip in message-content.tsx correctly defers to the later subagent block. The single P2 note is an optional performance improvement (O(n) scan) that does not affect correctness.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/lib/copilot/request/go/stream.ts Changed two guards in subagent span start handling: includes() replaces a last-element check on the parent stack, and a .some() scan replaces a coupled last-element+last-block check to prevent duplicate open subagent blocks. Both are linear scans that are acceptable for typical stack/block sizes.
apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx Adds a pre-pass over blocks to build a lastSubagentBlockIndex map, then skips dispatch tool_call blocks whose matching subagent content block already exists later in the array, eliminating the stale "running" lane indicator.

Sequence Diagram

sequenceDiagram
    participant SSE as SSE Stream
    participant SL as stream.ts
    participant CB as contentBlocks[]
    participant UI as message-content.tsx

    Note over SSE,UI: Parallel subagent scenario (A & B start together)

    SSE->>SL: span.start (subagentName=A, toolCallId=A1)
    SL->>CB: includes(A1)? No → push A1 to stack
    SL->>CB: some(open A block)? No → push {type:subagent, content:A}

    SSE->>SL: span.start (subagentName=B, toolCallId=B1)
    SL->>CB: includes(B1)? No → push B1 to stack
    SL->>CB: some(open B block)? No → push {type:subagent, content:B}

    Note over SSE,SL: Duplicate start event for A (retry/reconnect)
    SSE->>SL: span.start (subagentName=A, toolCallId=A1)
    SL->>CB: includes(A1)? Yes → skip stack push
    SL->>CB: some(open A block)? Yes → skip block push ✓

    SSE->>SL: dispatch tool_call for A (blocks[i])
    SL->>CB: push tool_call block

    UI->>UI: parseBlocks() called
    UI->>UI: pre-pass: lastSubagentBlockIndex = {A→idx7, B→idx8}
    UI->>UI: tool_call dispatch for A at idx5 → hasSubagentBlockAfter(A,5)? Yes → skip ✓
    UI->>UI: subagent block for A at idx7 → render AgentGroup(A)
    UI->>UI: subagent block for B at idx8 → render AgentGroup(B)
Loading

Reviews (1): Last reviewed commit: "fix(mothership): parallel subagent rende..." | Re-trigger Greptile

Comment thread apps/sim/lib/copilot/request/go/stream.ts
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 340c154. Configure here.

) {
context.contentBlocks.push({
type: 'subagent',
content: subagentName,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parallel same-name subagents collapse into single block

Medium Severity

The alreadyOpen check for subagent blocks incorrectly dedupes by subagentName without considering toolCallId. This results in only one subagent block being created for parallel instances sharing a name. Consequently, the first subagent's end event prematurely closes the shared block, causing visual inconsistencies where lanes finish early and subsequent text attaches to an ended block.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 340c154. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant