Skip to content

feat(desktop): surface linked child sessions in the session workbar #1457

Description

@Astro-Han

Summary

Linked child sessions move out of the conversation list and into the session workbar. The sidebar returns to one row per conversation intent; delegated work gets a permanent, interactive home beside the parent that dispatched it — and one home, not three.

This supersedes the conservative v1 projection from #1366 / #1400, which rendered every child as an indented row under its parent.

Decision

One identity, two faces. A subagent's identity is its preset — subagent_id, name, capability profile, model route — configured in 设置 · 子 Agent (#1999, rebuilt in #2008). Every child session already records which preset spawned it: SubagentSessionRuntime carries presetId, agentName, and profile (packages/core/src/session.ts:120-124). The runtime surface reads that identity instead of inventing its own labels, and the settings page reads back which of its presets are running. No new contract is needed for either direction.

Sidebar — child sessions no longer occupy rows. A parent row carries a N subagent chip only while something needs attention (amber: a child is waiting for permission or failed; blue: a child is running). The chip disappears once every child settles, so history does not accumulate badges. The nested row rendering (packages/ui/src/session-history-list.tsx:179, :375) and the data-subagent background in sidebar.css:237 — which collides with the active-row tint — are removed.

Session workbarSessionWorkbar gains a fourth tab, 子 Agent, with a persistent count (session-workbar-layout.ts:8 currently knows tasks | browser | files | quote). It lists the active session's direct children, attention first, then most recent. A row reads as preset name · profile · model, not as a session title, reusing the vocabulary subagent-preset-presentation.ts already defines.

Graph folds into the same tab. AgentGraphPanel currently floats above the composer whenever a session runs in graph mode (app-shell.tsx:2215). Graph is one topology of delegation, not a separate kind of work, so it becomes the tab's graph-mode presentation rather than a second panel. Without this, landing the tab would leave two surfaces both answering "how is my delegated work doing" — the exact duplication this issue exists to remove.

Opening a child — selecting a row turns the panel into a mini chat for that child session, with a back affordance, a composer, and inline permission prompts. The parent conversation stays put in the main pane. QuoteCompanionPanel already runs a full interactive chat inside this panel, so this reuses a proven seam instead of adding one. An "open in main pane" escape hatch covers long child conversations.

Transcriptsubagent and agent_swarm tool results already carry childSessionId (packages/core/src/events.ts:699, :722) and the previews currently ignore it. Each item gets an action that opens the child in the workbar.

Projection — one pure read-model helper in @maka/core, projectSessionDelegation(parent) → { total, attention, counts }, backs the sidebar chip, the tab count, and the TUI. Desktop and the TUI share these semantics; they do not share layout. The TUI session picker is a modal list the user opens deliberately, so it keeps its current flattened tree.

Rationale

The workbar is already the "work attached to this conversation" surface: its Tasks tab lists this session's todos, its Files tab lists this session's artifacts. Delegated work is the same class of thing, so it belongs there. No new surface is invented — and with the graph panel folded in, one existing surface is retired.

The conversation list answers "which conversation do I want", not "how is my delegated work doing". agent_swarm allows up to 32 items (agent-swarm-tools.ts:38), so the current tree can bury a day of real conversations under a single parent.

Keeping the child in the workbar also keeps the parent on screen. Jumping the main pane to the child would discard the context that explains why the child exists.

Naming rows by preset rather than by session title is what makes the tab legible at swarm scale: 32 children under one parent are distinguishable by what they were dispatched to do, not by 32 auto-generated titles.

Scope

Three PRs, in this order:

  1. A home for child sessionsprojectSessionDelegation, the 子 Agent tab, preset-identity rows, the in-panel mini chat, and the transcript entry point. After this lands, children are reachable from both the workbar and the existing sidebar tree: redundant, but safe.
  2. Graph folds inAgentGraphPanel becomes the tab's graph-mode presentation; the composer-adjacent mount is removed. Independently reviewable: it changes where an existing panel lives, not what it shows.
  3. Sidebar back to a conversation list — the attention chip, plus removal of the nested tree rendering and subagent row styling.

1 must come first: dropping the sidebar tree before the tab exists would leave children with no entry point. 2 and 3 are independent of each other.

Explicitly not doing

  • Nested delegation trees. No built-in agent profile carries agent_spawn or agent_swarm, and every profile's system prompt forbids nested agent tools (agent-catalog.ts:119, :143, :169). Grandchildren do not exist today, so the workbar lists direct children only.
  • Run history on the settings page. Reading preset identity back into 设置 · 子 Agent ("2 running, last used 3h ago") is the natural next step once the projection exists, but it is a separate surface with its own questions about retention. Tracked separately after 1 lands.
  • Promoting or pinning a child to top level. The tab count is always present, so a finished child stays reachable without one.
  • A dedicated delegated-work view. It would duplicate what the swarm tool card already answers.
  • Any change to child-session runtime, storage, or permission semantics.

Follow-up: #1467

Deleting a parent currently leaves its children as orphan root rows, so deleting a large-swarm parent drops a dozen headless rows into the list. Proposal: archive those children instead of orphaning or cascading them.

Cascading deletion is not safe here. Session deletion is permanent and tombstoned against reuse (session-metadata-transfer.ts:65, sqlite-session-metadata-store.ts:159), and a child owns its own artifacts under ${sessionId}/… (artifact-store.ts:65). Archiving preserves the data, keeps the main list clean, and reuses existing lifecycle semantics.

This changes delete behaviour rather than navigation presentation, so it is tracked in #1467 and reviewed there.

Validation

Storybook states: eight mixed-status children, a 32-item swarm, all children settled (chip absent), the workbar at 320px, and the mini chat in its permission state.

One live journey: dispatch a swarm, watch the parent chip turn amber, open the workbar, select the permission-blocked child, approve inline, return to the list.

References

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions