Reconcile Claude background task state

This commit is contained in:
iris-ai committed 2026-09-15 12:49:22 -04:00
1 parent f0661919bb
commit 9fd21af4e8
6 files changed
+310 -24

No files matched your search

+20 -6
View File
@@ -86,6 +86,20 @@ transcript is still being written to and its process is the session's to stop.
status ends it from the update, since the failure to avoid is a subagent
nothing ever finishes.
Since Claude Code 2.1.261, `background_tasks_changed { tasks: [...] }` is
the authoritative level beside those edges: its set replaces the previous
set, so a missed terminal edge cannot leave a subagent running forever. Its
ids are deliberately not correlated with the edge stream; the useful claim
here is whether the set is empty. The edges still carry mapping, outcome
and closing summary. On adoption the driver sends a repeated `initialize`,
which makes a current CLI send the full set; an older CLI accepts it and sends no level,
leaving the edge-based path unchanged. A snapshot is reconciled immediately
when the persisted parent status proves it is between turns, and otherwise
at the next `result` boundary -- while a turn is open, a foreground agent is
legitimately absent from the background set. Reconciliation writes
`Status Exited`, which is also what makes a formerly stale row deletable;
a task notification ordered after the level can still add its summary.
The two rules this replaces were both wrong, in opposite directions. The
parent's `tool_result` is not it: a backgrounded Task's arrives at launch
("Async agent launched..."), so ending there truncated a running agent's
@@ -117,12 +131,12 @@ transcript is still being written to and its process is the session's to stop.
**While any task is outstanding the session's turn ends in
`Status Waiting` rather than `Idle`.** `Idle` means "waiting for a person",
and a session with a backgrounded subagent is not doing that. Two sources:
the translator's `open_tasks`, and `Subagents::any_open` -- which is what
covers a subagent launched before a backend restart adopted the session,
whose `task_started` is behind the offset its stdout is read from. That
second lookup is also what lets such a subagent's ending be recognised at
all.
and a session with a backgrounded subagent is not doing that. The edge
fallback has two sources: the translator's `open_tasks`, and
`Subagents::any_open` -- which covers a subagent launched before a backend
restart adopted the session, whose `task_started` is behind the durable
stdout offset. On current Claude versions the replace-semantics level above
reconciles both at a safe turn boundary.
**A limit the account hits inside a subagent is hoisted to the session**
as well as recorded here, because `resume.rs` can only schedule against a