Skip to content

feat(desktop): open chat subagents in stacked right panes - #5830

Closed
hackice20 wants to merge 2 commits into
ParadevAI:mainfrom
hackice20:feat/subagent-side-panes
Closed

hackice20 wants to merge 2 commits into
ParadevAI:mainfrom
hackice20:feat/subagent-side-panes

Conversation

@hackice20

@hackice20 hackice20 commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

What & why

When a Mastra chat agent spawns subagents, their activity was only visible inline in the parent chat (or after navigating into nested tool UI). This adds automatic side panes so you can watch the parent and each subagent at once — first subagent opens to the right of the parent chat; later ones stack underneath that column.

  • New subagent pane kind bound to { parentSessionId, toolCallId }
  • Auto-open on new activeSubagents entries (idempotent per toolCallId)
  • Live activity from harness state, with message-history fallback after completion

Addresses the “display subagent activity in a new pane” request (#5077).

How I tested it

  • image:
Screenshot From 2026-07-21 20-22-13
  • Unit tests:
    • openSubagentPane (open right / stack / focus existing)
    • resolveSubagentEntries (live map vs message history vs fallback)
  • Manual (v2 workspace Chat pane, not terminal agents):
    1. Open + → Chat
    2. Prompt: “Use 2–3 explore subagents in parallel to investigate X, Y, and Z.”
    3. Confirm stacked right panes open and update while subagents run

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass (CI fails on lint warnings too)
  • "Allow edits from maintainers" is checked on fork PRs

Summary by cubic

Chat subagents now open in stacked right panes so you can watch the parent chat and each subagent at the same time. First opens to the right; later ones stack in the same column, and we don’t refocus if the pane already exists. Addresses #5077.

  • New Features
    • Added a subagent pane keyed by { parentSessionId, toolCallId } with live updates and message-history fallback.
    • Auto-open from activeSubagents; idempotent per toolCallId; skips existing panes (no focus steal).
    • Layout: opens to the right of the parent chat; subsequent subagents stack underneath.
    • Introduced useAutoOpenSubagentPanes, openSubagentPane, and SubagentPane/SubagentPaneTitle with tests for open/stack/no-refocus and entry/title resolution.

Written for commit d6b0db9. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added dedicated subagent panes to the workspace dashboard.
    • Automatically opens subagent panes as activity begins, avoiding duplicates.
    • Displays subagent status, task details, results, errors, and execution information.
    • Organizes multiple subagent panes beside the related chat and focuses existing panes when applicable.
    • Added descriptive subagent titles and a Bot icon for easier identification.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This repository has used its 100 free open-source review credits for this billing period. An organization admin can enable additional billed reviews, or reviews resume next period.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds subagent panes to the workspace dashboard, including pane state, placement and stacking, chat-history resolution, rendering, titles, registry integration, and automatic opening from active chat subagents.

Changes

Subagent pane placement

Layer / File(s) Summary
Pane contract and placement
apps/desktop/.../v2-workspace/$workspaceId/types.ts, apps/desktop/.../utils/openSubagentPane/*
Adds SubagentPaneData, supports it in PaneViewerData, and implements subagent lookup, focusing, right-side opening, stacking, and placement tests.

Subagent resolution and rendering

Layer / File(s) Summary
Subagent data resolution
apps/desktop/.../SubagentPane/utils/resolveSubagentEntries/*
Resolves subagent entries from active state or message history, parses results and statuses, derives titles, and tests live, historical, and fallback data.
Subagent pane UI
apps/desktop/.../SubagentPane/*
Renders subagent execution messages or a waiting state and provides a dynamic pane title with tooltip and active-state styling.

Chat auto-open wiring

Layer / File(s) Summary
Chat context and pane registration
apps/desktop/.../ChatPane/*, apps/desktop/.../usePaneRegistry.tsx
Passes pane, tab, and store context through chat components and registers the subagent pane with its icon, title, renderer, and close label.
Automatic subagent opening
apps/desktop/.../useAutoOpenSubagentPanes/*
Normalizes active subagent entries and opens each unseen tool call once, avoiding existing panes and resetting tracking when the parent session or pane changes.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise, conventional, and accurately summarizes the main change: opening chat subagents in stacked right panes.
Description check ✅ Passed The description follows the template and includes what changed, why, testing steps, screenshots, and a completed checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/useAutoOpenSubagentPanes.ts (1)

1-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deep relative imports instead of tsconfig path aliases across the new subagent-pane wiring. As per coding guidelines, apps/desktop/**/*.{ts,tsx} should "Use the path aliases defined in tsconfig.json whenever possible." Several new/changed files reach the shared types.ts/utils modules via long relative chains (up to 6 levels) instead of an alias, which breaks silently on file moves. Same root cause at every site below.

  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/useAutoOpenSubagentPanes.ts#L1-L6: replace ../../../../../../types and ../../../../../../utils/openSubagentPane with the tsconfig alias equivalents.
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/ChatPane.tsx#L1-L4: replace ../../../../types with the alias.
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/types.ts#L1-L4: replace ../../../../../../types with the alias.
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/utils/openSubagentPane/openSubagentPane.ts#L7-L7: replace ../../types with the alias.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/useAutoOpenSubagentPanes.ts
around lines 1 - 6, Replace the deep relative imports with the configured
tsconfig path aliases for shared types and openSubagentPane. Apply this in
useAutoOpenSubagentPanes.ts, ChatPane.tsx, WorkspaceChatInterface/types.ts, and
utils/openSubagentPane/openSubagentPane.ts, preserving the imported symbols and
behavior.

Source: Coding guidelines

apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/utils/openSubagentPane/openSubagentPane.test.ts (1)

117-143: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen the "focuses an existing pane" test to assert the actual focus side effect.

This test checks the return value ("focused") and pane count, but never asserts tab.activePaneId/activeTabId after the second call. Given the "existing pane" branch's focus behavior is exactly what's implicated in the auto-open focus-stealing concern (see useAutoOpenSubagentPanes.ts), adding an assertion here would guard against regressions in either direction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/utils/openSubagentPane/openSubagentPane.test.ts
around lines 117 - 143, Strengthen the existing “focuses an existing pane” test
around the second openSubagentPane call by asserting the tab’s activePaneId and
the workspace’s activeTabId reflect the existing pane and tab after the call.
Preserve the current return-value and single-pane assertions.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.test.ts (1)

31-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the isError branch.

Tests cover the "completed" message-history path but not isError: true, which drives the error/"Failed" status shown in the UI. Worth adding a case to lock in that behavior.

✅ Suggested additional test
it("marks the subagent as errored when the tool result failed", () => {
	const entries = resolveSubagentEntries({
		toolCallId: "tool-4",
		activeSubagents: new Map(),
		messages: [
			{
				id: "msg-2",
				role: "assistant",
				content: [
					{
						type: "tool_call",
						id: "tool-4",
						name: "subagent",
						args: { task: "Explore", agentType: "explore" },
					},
					{
						type: "tool_result",
						id: "tool-4",
						result: "Not logged in",
						isError: true,
					},
				],
				createdAt: new Date(),
			},
		] as never,
		fallback: {},
	});

	expect((entries[0]?.[1] as { status: string }).status).toBe("error");
	expect((entries[0]?.[1] as { error?: string }).error).toBe(
		"Not logged in",
	);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.test.ts
around lines 31 - 62, Add a test alongside the existing “falls back to message
history” case in resolveSubagentEntries tests that supplies a failed tool_result
with isError: true, then assert the returned entry has status "error" and
preserves the result text in its error field.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx (1)

4-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Promote ChatPane's subagent rendering/hook out of ChatPane — now used by 2+ sibling panes. SubagentExecutionMessage, toSubagentViewModels, and useWorkspaceChatDisplay are all still nested under ChatPane/..., but SubagentPane and SubagentPaneTitle now depend on them too, creating fragile coupling across pane-module boundaries.

  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx#L4-L5: import SubagentExecutionMessage/useChatDisplay from their new shared location instead of ../ChatPane/....
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.ts#L3-L7: same for toSubagentViewModels/UseChatDisplayReturn.
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/components/SubagentPaneTitle/SubagentPaneTitle.tsx#L5: same for useChatDisplay.

As per path instructions: "Co-locate components, hooks, utilities, constants, configuration, tests, and stories with their usage; nest single-use items under the parent and promote items used two or more times to the highest shared parent." Relocate these to the shared parent directory (e.g. usePaneRegistry/components/ or usePaneRegistry/hooks/) and update the three import sites above.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx
around lines 4 - 5, Promote SubagentExecutionMessage, toSubagentViewModels,
useWorkspaceChatDisplay, and UseChatDisplayReturn from ChatPane into the shared
usePaneRegistry parent, then update imports in
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx
(lines 4-5),
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.ts
(lines 3-7), and
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/components/SubagentPaneTitle/SubagentPaneTitle.tsx
(line 5) to use the new shared locations.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/useAutoOpenSubagentPanes.ts:
- Around line 70-85: The initialization logic in useAutoOpenSubagentPanes must
account for subagent panes that already exist before opening active entries, so
the initial effect does not refocus them. Reuse the pane registry’s
existing-pane lookup or non-focusing ensure-exists path to mark existing
toolCallIds without calling the focusing openSubagentPane; only genuinely new
subagents should be opened and focused.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/useAutoOpenSubagentPanes.ts:
- Around line 1-6: Replace the deep relative imports with the configured
tsconfig path aliases for shared types and openSubagentPane. Apply this in
useAutoOpenSubagentPanes.ts, ChatPane.tsx, WorkspaceChatInterface/types.ts, and
utils/openSubagentPane/openSubagentPane.ts, preserving the imported symbols and
behavior.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx:
- Around line 4-5: Promote SubagentExecutionMessage, toSubagentViewModels,
useWorkspaceChatDisplay, and UseChatDisplayReturn from ChatPane into the shared
usePaneRegistry parent, then update imports in
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx
(lines 4-5),
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.ts
(lines 3-7), and
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/components/SubagentPaneTitle/SubagentPaneTitle.tsx
(line 5) to use the new shared locations.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.test.ts:
- Around line 31-62: Add a test alongside the existing “falls back to message
history” case in resolveSubagentEntries tests that supplies a failed tool_result
with isError: true, then assert the returned entry has status "error" and
preserves the result text in its error field.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/`$workspaceId/utils/openSubagentPane/openSubagentPane.test.ts:
- Around line 117-143: Strengthen the existing “focuses an existing pane” test
around the second openSubagentPane call by asserting the tab’s activePaneId and
the workspace’s activeTabId reflect the existing pane and tab after the call.
Preserve the current return-value and single-pane assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66665c87-6cda-43c9-b78d-6032683cef0c

📥 Commits

Reviewing files that changed from the base of the PR and between 616bb67 and 674eab9.

📒 Files selected for processing (17)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/ChatPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/ChatPaneInterface.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/WorkspaceChatInterface/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/hooks/useAutoOpenSubagentPanes/useAutoOpenSubagentPanes.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/SubagentPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/components/SubagentPaneTitle/SubagentPaneTitle.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/components/SubagentPaneTitle/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/SubagentPane/utils/resolveSubagentEntries/resolveSubagentEntries.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/usePaneRegistry.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/utils/openSubagentPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/utils/openSubagentPane/openSubagentPane.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/utils/openSubagentPane/openSubagentPane.ts

@Kitenite

Copy link
Copy Markdown
Member

Closing: main already ships this. ChatPane it edits was deleted with legacy chat in 8f2753b (#6461). Thanks for the PR; if you think the shipped version misses a case, open an issue and link this.

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.

2 participants