Files
deepseek-harness/packages/subagent/tool-subagent-control
Dudu-0223 853f4d5cfb refactor(subagent): drop host-user authority and split lifecycle publication
Remove the host-user continuation capability and the public residency query,
then separate the seam's public event payloads from its internal lifecycle
control interfaces.

`followup()` now takes the exact live direct parent `Agent` instead of a
`SubagentAuthority` union. No production adapter ever supplied user authority,
so the `UserAuthorityGrant` brand token existed only to stop a forged
discriminant from bypassing the direct-parent check — deleting the branch
retires the token, its mint method, and that attack surface together.

Narrowing `parent` from `Agent | undefined` to `Agent` removes three special
cases, including the path where a parentless epoch dispatched its lifecycle
events unscoped. Scoped-versus-global dispatch is now decided by the event, not
by whether a caller happened to have a parent.

`activationState()` had no caller; `ActivationState`, `ActivationObserver`, and
`ContinuationHost` are package-private.

New `src/lifecycle.ts` owns the contained emitter, the one-shot run observer,
and the Activation observer, while `SubagentRunInfo`/`SubagentRunEndInfo` move
to `src/types.ts` beside the other consumer-facing contracts. Those payloads are
public API — dsh-jsonrpc, hooks-claude, and the package invariant all consume
them — whereas the observer is a contract between two in-package collaborators,
so they no longer share a home merely for both being lifecycle-shaped. The
service keeps ownership of the scope carrier: `scopeTarget()` composes the
service's own context filter, so a narrowed stand-in would silently change
scope filtering.

Also drops now-unused dsh-tasks-local and dsh-tool-tasks dev dependencies, and
corrects the README claim that a pre-residency failure emits a terminal edge —
that path only ever rethrew.
2026-08-02 12:51:08 +08:00
..

@deepseek-ai/dsh-tool-subagent-control

English | 中文

The optional, globally named send_message tool: a thin adapter over ctx.subagents.followup(). Provider-bound @deepseek-ai/dsh-tool-subagent instances register distinct delegation tools per transport; this separately loaded package registers one shared follow-up tool, so multiple delegation tools never register duplicate global controls. Its presence does not determine whether a delegation tool starts continuable work.

The tool performs no lifecycle routing — residency and cold resume belong to the subagent service. It supplies exact live parent authority ({ kind: 'parent', agent }) from exec.agent and attributes every message as durable provenance { kind: 'coordinator', senderSessionId: parent.id }, which the service retains but never treats as authority. Every message becomes the subagent's next FIFO turn through Agent.followup(): if the child is still working, the message waits until its current turn finishes, so it cannot redirect work already underway. The tool forwards its execution signal, which owns admission only until inbox acceptance; once the child accepts the message the accepted turn cannot be cancelled through this tool. The child does not reply to the sender — its transcript by that id is the source of what it did. A delivery failure becomes an errored tool result stating the message was not delivered.

Model Experience

Tool schema

What the model sees

The generated send_message schema: subagent_id and message, describing that the message becomes the subagent's next turn, that the subagent does not reply, and that a failure means the message was not delivered.

Token effect

Fixed schema cost per parent request.

KV Cache effect

Prefix-stable; the schema does not change at runtime.

Delivery result

What the model sees

message queued as the next turn for subagent <subagent_id> on acceptance; the canonical output carries the accepted messageId. A failure — an unauthorized or unknown child, a descriptor-less child that cannot be resumed, or admission rejected — is an errored result whose message states the message was not delivered.

Token effect

One short acknowledgement per call; the child's response never returns through this tool, so its output enters parent history only if a caller reads the child transcript and relays it.

KV Cache effect

Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.

Known Limitations and Deferred Work

  • A queued message has no independent result — acceptance returns only its inbox messageId; the child's work on that turn lands in the durable child Session, read by its subagent id, and is neither delivered back nor collected through this tool.
  • No steering of the current turn — every message opens a later FIFO turn, so a message sent while the child is working runs only after its current turn finishes and cannot redirect it.