fix(subagent): require durability participant

This commit is contained in:
Dudu-0223
2026-07-27 11:50:21 +08:00
committed by imccyu
parent 88f913a9ae
commit efc47b6a76
18 changed files with 150 additions and 26 deletions
@@ -31,7 +31,7 @@ The low-level `ctx.subagents` seam stays collection-, Task-, and persistence-agn
### Task and cancellation ownership
The initial background delegation asks the control service to start the child and register its Task. A continuable provider confirms the activation's final session state durable before fulfilling a successful run result. Task settlement awaits that result, calls `run.dispose()` (through the control service's `settleRun`), and only then records the `TaskOutcome`; `task_kill` aborts the active run, whose settlement path still disposes it. A terminal Task therefore leaves the durable child session but no live child Agent. A failed required durability checkpoint rejects the run with stable code `DURABILITY_FAILED` and the backend failure as its cause; the control service records a failed Task whose detail explains that the latest state was not confirmed persisted and may be unavailable or stale on resume.
The initial background delegation asks the control service to start the child and register its Task. A continuable provider confirms the activation's final session state durable before fulfilling a successful run result. Task settlement awaits that result, calls `run.dispose()` (through the control service's `settleRun`), and only then records the `TaskOutcome`; `task_kill` aborts the active run, whose settlement path still disposes it. A terminal Task therefore leaves the durable child session but no live child Agent. A required durability checkpoint with no installed listener or a failing listener rejects the run with stable code `DURABILITY_FAILED` and the checkpoint failure as its cause; the control service records a failed Task whose detail explains that the latest state was not confirmed persisted and may be unavailable or stale on resume.
Every later turn creates another Task. Its producer resources cover only that activation, never the child session. It reaches one terminal status, has one result, and is never reopened. The exact live parent Agent remains the Task registry owner: disposing that instance cancels, awaits, and removes its Tasks. Task APIs authorize a caller whose session id matches that owner, but a same-id replacement does not become the notification or teardown target. This preserves the `settleRun()` contract and bounds Task-owned live children by concurrent work rather than historical session count.
@@ -109,7 +109,7 @@ Task records and active-run associations are process-local. Persistence makes th
## Testing
- `packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts` pins the continuable durability boundary: a permanent flush failure rejects with `DURABILITY_FAILED` and its cause, a transient loop-checkpoint failure can succeed on the final confirmation, cancellation owns either final-checkpoint outcome, resume also confirms durability, and foreground runs remain best-effort. `packages/subagent/subagent/tests/continuation.spec.ts` drives the real stack (agent loop, JSONL persistence, spawn/fork providers, Task service, and `ctx.subagents`) keylessly: initial and resumed activations create fresh Tasks and dispose their runs before terminal; the descriptor event is turn-enclosed, model-hidden, versioned, and durable under the service-allocated child id; cancellation, steering, cold follow-up, authorization, ownership conflicts, and resume races retain the contracts described above.
- `packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts` pins the continuable durability boundary: an absent or detached flush listener and a permanent listener failure reject with `DURABILITY_FAILED`, a transient loop-checkpoint failure can succeed on the final confirmation, cancellation owns either final-checkpoint outcome, resume also confirms durability, and foreground runs remain best-effort. `packages/subagent/subagent/tests/continuation.spec.ts` drives the real stack (agent loop, JSONL persistence, spawn/fork providers, Task service, and `ctx.subagents`) keylessly: initial and resumed activations create fresh Tasks and dispose their runs before terminal; the descriptor event is turn-enclosed, model-hidden, versioned, and durable under the service-allocated child id; cancellation, steering, cold follow-up, authorization, ownership conflicts, and resume races retain the contracts described above.
- `packages/subagent/tool-subagent-control/tests/tool-subagent-control.spec.ts` pins the `send_message` schema, coordinator attribution, both route renderings, the not-delivered failure, the no-agent rejection, and HMR disposal.
- `packages/subagent/tool-subagent/tests/tool-subagent.spec.ts` covers the configured background route: continuable mode requires a resumable provider and returns both ids without requiring `send_message`, while one-shot mode keeps the plain Task acknowledgement even when the provider can resume.
- `packages/sdk/helper/tests/project.spec.ts` pins the Task service and model-facing Task controls in generated spawn and fork compositions.