nest the whole sub-agent run under its Agent card (T-264)

A sub-agent's sidechain run used to spill loose into the main chain,
indistinguishable from main-thread items. Now:

- _sidechainFold routes every sidechain item to its owning Agent/Task
  tool-use by walking the parentUuid chain up to the Agent message it
  branches off (nearest-preceding Agent as fallback) — correct even for
  parallel agents.
- The run (prose / thinking / tool cards) nests in an "agent run"
  ClideHolderCard UNDER the Agent card, suppressed from the top level. The
  prompt still folds into the call (T-263); a successful sidechain tool
  result folds into its own tool card inside the run, so it isn't a
  separate step.
- When a run is shown, the Agent card's returned-result segment is dropped
  (it duplicates the run's final output, note E) — but kept when no run
  was captured, so output is never lost.

Tests: run nesting, returned-result dedup, parallel-run attachment (would
fail under nearest-preceding), and folded-result-not-double-counted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 11:26:09 +02:00
co-authored by Claude Opus 4.8
parent 5253b7b759
commit db6ecbd5df
5 changed files with 223 additions and 47 deletions
@@ -818,3 +818,4 @@ INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by,
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-266', 'status', 'backlog', 'in_progress', NULL, '2026-06-08 08:47:43', '2026-06-08 08:47:43', '2026-06-08 08:47:43', NULL, '0eebe9e270a6a7a4b9cccfb9ffbe5dc4', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-266', 'status', 'in_progress', 'done', NULL, '2026-06-08 09:04:12', '2026-06-08 09:04:12', '2026-06-08 09:04:12', NULL, 'fecc7bc78e18d5dd3c613d6583371fc3', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-264', 'status', 'backlog', 'in_progress', NULL, '2026-06-08 09:07:02', '2026-06-08 09:07:02', '2026-06-08 09:07:02', NULL, 'd82d792cf5ef8e77c581bea27f2cd8e3', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-264', 'status', 'in_progress', 'done', NULL, '2026-06-08 09:25:50', '2026-06-08 09:25:50', '2026-06-08 09:25:50', NULL, '274e5d99e4db192a6b4cf6902f12df45', 1) ON CONFLICT(hash) DO NOTHING;
+15
View File
@@ -1957,3 +1957,18 @@ INSERT INTO tickets (id, type, parent_id, title, description, status, priority,
Repro: open the composer, type ''/'' then a command fragment; (a) include a ''-'' and watch the list; (b) arrow-select an item and press Tab repeatedly.
Acceptance: ''-'' is treated as a normal command-name character (suggestions keep filtering through hyphens); Tab reliably completes the highlighted suggestion every time (insert via completeSlash). Add/extend unit tests in slash_commands_test.dart for hyphenated queries and a composer widget test for Tab-accept.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-08 09:20:00', '2026-06-08 09:20:00', NULL, 'a15f416969aef224d838bf28d016b82a', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-264', 'story', 'T-267', 'Nest the whole sub-agent run under its Agent card (attribute sidechain via parentUuid)', 'Completion of T-263. T-263 folds the sub-agent PROMPT into the Agent card, but the sub-agent run itself — its prose, thinking, and tool calls — still renders inline in the MAIN conversation chain. A reader cannot tell where the sub-agent run ends and the main thread resumes; sidechain items are visually indistinguishable from main-thread items.
Root cause: the conversation is a flat list of ConversationItems rendered by _ConversationTurn (lib/builtin/claude/src/conversation_view.dart build ~L130, _ConversationTurn ~L182). isSidechain exists on every item (transcript_reader.dart ~L46) but no rendering/grouping logic reads it. activity_cluster.dart groups consecutive meta runs but is sidechain-agnostic.
Design: use the parentUuid link (parsed in T-263) to group an ENTIRE sidechain run as a nested region OWNED by its spawning Agent card. The run renders as a distinct, attributed, collapsible region (indent / attribution band / nested holder) under the Agent call rather than as loose cards in the main chain. Per the user rule from T-263, the run results stay VISIBLE (not folded away) this is about attribution and containment, not hiding.
Scope:
- Build a sidechain-aware grouping pass (extend or complement activity_cluster.groupConversation) that collects all items sharing a sidechain ancestry (via parentUuid chain back to the Agent tool_use) into one nested group.
- Render that group as a nested region under the Agent card (visual indent / attribution), keeping the sub-agent results first-class within it.
- Handle parallel agents (each run nests under its own card), nested sub-agents, and background agents.
- Orphan sidechain items (no resolvable parent) degrade to the current inline rendering but still attributed (see T-264/relabel work).
Depends on T-263 (parentUuid parsing + Agent card as container). Pairs with the sidechain-prose relabel ticket. Note the holder-card restyle + auto-scroll race is a separate design discussion (see the holder-card ticket).
Refs: D-78. Builds on T-263. Related: T-262, T-230 (activity card grouping).', 'done', 'medium', NULL, NULL, 'D-78', '2026-06-07 08:40:25', '2026-06-08 09:25:50', NULL, 'e3afb1ab7a0530c0b8dbd5775cc3803d', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);