Files
deepseek-harness/packages/subagent
Tianyi Cui 861791d2d8 Contain subagent lifecycle listeners per-listener, not per-emit
A single try/catch around ctx.emit prevented a thrown subagent/start or
subagent/end listener from propagating, but cordis emit dispatches listeners in
a `.map(cb => cb())` that HALTS on the first throw — so a bad subscriber still
starved the listeners registered after it, violating the AGENTS.md
callback-boundary rule ("one bad subscriber must not starve the listeners after
it"). Resolve the listener callbacks via ctx.events.dispatch and contain each
call individually, the same per-listener guarantee BashExecutor.notifyTaskDone
gives its own listener set.

The two containment tests now register TWO listeners where the first throws and
assert the second still observes the event (start) and the settle (end) — a
regression that fails on the per-emit code (verified: reverted, watched both go
red, restored).
2026-06-21 23:44:07 +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
tool-subagent/ Model-facing subagent delegation tool over ctx.subagents (registers on ctx.tools)

The interface lives at subagent/subagent/. Provider implementations live in their own packages — the in-process dsh-subagent-spawn / dsh-subagent-fork and the out-of-process dsh-subagent-acp — plus the test-only dsh-subagent-mock in support. All product packages except the mock.

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