fix review findings: correct teardown framing (dispose, not cancel+whenIdle)
Codex's second pass caught that the prior doc fix swapped one wrong primitive for another: framing teardown as cancel()+whenIdle() (or awaiting agent.whenIdle() on disposal) is still wrong. whenIdle() only OBSERVES quiescence; cancel() only stops queued/in-flight work. Neither unregisters the agent or detaches the session. Real teardown is AgentHandle.dispose(), whose disposer does `stop(); await agent.done` — stop the loop, await its exit, and unregister (packages/core/agent-loop/src/index.ts:271). Copying the old framing would reintroduce the orphaned-agent/session leak the AgentHandle seam exists to prevent. - docs/architecture.md: whenIdle() is a non-owner quiescence-observation hook, explicitly NOT teardown; teardown is `await AgentHandle.dispose()`. - docs/cookbook/extension-cookbook.md (prose + the ts comment): tear agents down via AgentHandle.dispose(), not agent.whenIdle(). - docs/rfc/proposed/feature/2026-06-14-acp-agent-client-protocol.md: the lifecycle/disposal paragraph routes teardown through the handle's dispose().
This commit is contained in:
@@ -113,7 +113,7 @@ Tool schemas are deliberately **part of the assembly**: "what the model is told
|
||||
- `steer(content)` — mid-turn injection, drained **between steps**; behaves like `send` when idle
|
||||
- `inject(content)` — in-session context (`context/message` event); the next request sees it (Claude Code attachment / system-reminder analog). An inject made while the agent is *running* joins the open turn; an inject while *idle* is wrapped in a one-shot turn (`turn/start{trigger:injection}` → `context/message` → `turn/end`) so every event stays turn-enclosed (see [the turn-enclosure invariant](rfc/implemented/architecture/2026-06-15-turn-enclosure-invariant.md)).
|
||||
- `cancel(reason)` — the single public stop primitive: clears queued + steering work, aborts the in-flight step, and drops a turn about to start (the pre-step window) so a queued-but-not-started prompt never runs and cannot be batched into the cancelled turn. A UI/ACP `session/cancel` maps to it.
|
||||
- `whenIdle()` — resolves once the agent reaches quiescence after settling out of `running` (resolves immediately when already idle; awaits the loop exit when disposed). The teardown signal: `cancel()` then `await whenIdle()` guarantees the in-flight turn has fully stopped. Observes the transition without disposing the agent.
|
||||
- `whenIdle()` — resolves once the agent reaches quiescence after settling out of `running` (resolves immediately when already idle; awaits the loop exit when disposed). A non-owner's quiescence-observation hook: it lets a consumer await the current work settling **without** disposing the agent. It is NOT teardown — it does not stop queued work, unregister the agent, or detach the session; a lifecycle owner tears an agent down with `await AgentHandle.dispose()` (which stops the loop, awaits its exit, and unregisters).
|
||||
- `session`, `status`, `options`
|
||||
|
||||
**TODO(sub-agents)**: `spawn`/`fork` land on `AgentLoop.create()` — fork seeds the child Session with the parent's event log, spawn starts fresh; children are ordinary `Agent` handles so `steer()` and event subscription work uniformly. Inter-agent channels beyond these primitives are deliberately deferred.
|
||||
|
||||
Reference in New Issue
Block a user