Conversation
🦋 Changeset detectedLatest commit: 7d306f9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Cold reconstruction can produce stale or duplicate task state and does not reliably identify members lost from earlier turns.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 3
Open (3)
What changed in this PR
Persists subagent lifecycle events so cold transcript reads can reconstruct Swarm members after restarts.
Changes:
- Makes subagent lifecycle events durable and replayable.
- Rebuilds member tasks/references and marks interrupted foreground members lost.
- Adds persistence and cold-reconstruction coverage.
| File | Description |
|---|---|
.changeset/restore-swarm-members.md |
Records the user-visible fix. |
packages/agent-core-v2/src/session/subagent/mirrorAgentRun.ts |
Makes lifecycle events durable. |
packages/agent-core-v2/test/state/eventDispatcher.test.ts |
Tests persistence and replay. |
packages/transcript/src/history/foldFacts.ts |
Reconstructs tasks and member references. |
packages/transcript/test/layers.test.ts |
Tests lifecycle folding. |
packages/kap-server/src/services/transcript/transcriptService.ts |
Reconciles restored task liveness. |
packages/kap-server/test/services/transcript.test.ts |
Tests cold Swarm restoration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| activity === 'idle' && task.kind === 'subagent' && !task.detached && task.state === 'running' && | ||
| (task.agentId === undefined || | ||
| liveAgents?.handleOf(task.agentId)?.accessor.get(IAgentLoopService).snapshot().state !== 'running') |
| const subagentTasks = new Map<string, string>(); | ||
| const subagentRefs = new Map<string, Map<string, { ref: AgentRef; index?: number }>>(); |
| tasks.set(taskId, { | ||
| ...task, | ||
| state, | ||
| endedAt: state === 'running' ? undefined : recordTimeIso(record), | ||
| resultSummary: typeof record['resultSummary'] === 'string' ? record['resultSummary'] : task.resultSummary, | ||
| error: typeof record['error'] === 'string' ? record['error'] : task.error, |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d306f9fec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| tasks.set(taskId, { | ||
| ...task, | ||
| state, | ||
| endedAt: state === 'running' ? undefined : recordTimeIso(record), | ||
| resultSummary: typeof record['resultSummary'] === 'string' ? record['resultSummary'] : task.resultSummary, | ||
| error: typeof record['error'] === 'string' ? record['error'] : task.error, |
There was a problem hiding this comment.
Restore usage from completed subagent records
When a completed Swarm or Agent task is reopened, its durable subagent.completed record contains usage, but this fold only copies the summary and error into the task. The live projector's onSubagentRun includes that usage, so the cold snapshot silently loses token-usage details and differs from what the client saw before restart; copy validated usage into the restored task as well.
Useful? React with 👍 / 👎.
| activity === 'idle' && task.kind === 'subagent' && !task.detached && task.state === 'running' && | ||
| (task.agentId === undefined || | ||
| liveAgents?.handleOf(task.agentId)?.accessor.get(IAgentLoopService).snapshot().state !== 'running') |
There was a problem hiding this comment.
Mark stale members lost during a later parent turn
If a restart leaves a foreground member unfinished and the user starts a new parent-agent turn before transcript backfill, activity is turn, so this outer condition prevents the idle or absent child from becoming lost. Nothing subsequently terminalizes that old task, leaving the previous Swarm member displayed as running indefinitely; the decision needs to distinguish the member's originating turn from an unrelated current turn.
Useful? React with 👍 / 👎.

Related Issue
Reported during testing of the Swarm member list in the desktop client; no separate issue.
Problem
After restarting the server with a foreground Swarm still in progress, reopening the conversation shows no members. The child conversations remain on disk, but their spawn and completion events were transient, so the cold transcript cannot reconstruct the member tasks or their parent tool calls.
What changed
Existing conversations recorded before this fix do not contain the required association facts and cannot be reconstructed reliably. This change preserves new runs; it does not infer associations from child names or creation order.
Validation: 274 targeted tests across transcript folding, cold transcript reads, event persistence/replay, and subagent scope lifecycle. Regression cases cover interrupted members, completed/failed/cancelled members, multiple Swarm calls, member ordering, background task lifecycle, reused members, parent filtering, and historical child conversation reads. Type checks pass for agent-core-v2, kap-server, and transcript. Targeted type-aware lint passes with pre-existing warnings only; the no-comments check passes.
Checklist
gen-changesetsskill.