Files
deepseek-harness/packages/subagent
Tianyi Cui 547aacee2f fix: honor the teardown order on owner unload; make the structured commit unconditional
Adversarial-review findings (own reviewer agent), each verified and pinned:

B1: agents.register() returned a wrapper lambda, so the factory composite's
yield could not identity-nest it — on OWNER unload the unregistration (and
agent/disposed) disposed as a concurrent sibling, firing mid-drain while
the final turn was still closing (pre-existing on master; this branch's
docs re-assert the order, so it must be true). register() now returns the
EXACT cordis effect disposer (the Scope.rawDispose move); the composite
nests it and owner unload runs stop/drain -> unregister -> detach -> scope
like every other path. Regression test pins turn-end before disposed
before detach on owner unload.

B2: the structured two-phase commit could promote a stale stage when a
later capture call REUSED the orphaned stage's call id with a body that
never staged (denied downstream, or invalid args throwing pre-stage). The
runtime's pre-execute listener now clears any stale stage unconditionally
when a new capture call enters the pipeline — only a call's own body can
stage for its commit; the call-id mismatch guard becomes a defensive
second layer. Repro test: blocked capture then same-id invalid call.

C1: an explicit empty toolFilter config now fails at plugin LOAD (the
check is self-contained) instead of killing every delegation at child
setup. C2: Scope.dispose/ScopeHost.dispose @returns state the single-shot
repeat-call semantics honestly.
2026-07-09 04:48:52 +08:00
..

subagent/ — subagent capability family

The subagent seam: an agent delegating work to a child agent. Like the bash and llm families this is a capability seam (see capability seams) — but with one defining difference: multiple provider implementations coexist in one context, registered by name, rather than the single-implementation bash shape. The registry mirrors the LLM adapter registry.

Package Role ctx key
subagent/ Abstract subagent seam: named-provider registry + vocabulary ctx.subagents
subagent-inprocess/ Shared in-process run driver (pure lib; registers nothing)
subagent-spawn/ In-process backend: a fresh child agent (registers on ctx.subagents)
subagent-fork/ In-process backend: a child seeded with the parent's completed-turn prefix (registers on ctx.subagents)
subagent-acp/ Out-of-process backend: a child agent in a spawned subprocess, driven over ACP (registers on ctx.subagents)
tool-subagent/ Model-facing subagent delegation tool over ctx.subagents (registers on ctx.tools)

The interface lives at subagent/subagent/. The in-process subagent-spawn / subagent-fork backends share the subagent-inprocess driver (a pure library — both depend on it, neither on the other), and the out-of-process subagent-acp backend ships alongside them here; the test-only dsh-subagent-mock (in support) is separate. All product packages except the mock.

The proposal and design rationale: docs/rfc/implemented/feature/2026-06-21-subagent-capability-seam.md.