description, kind
| description | kind |
|---|---|
| Shared messaging, interruption, and child discovery tools for users and maintainers composing or debugging continuable-child control. | package-reference |
@deepseek-ai/dsh-tool-subagent-control
English | 中文
Summary
dsh-tool-subagent-control lets agents message and interrupt subagents and list continuable children. One plugin instance registers all three tools for a scope shared by multiple delegation backends. Parents and continuable children inherit the same messaging definition and ordering. Tool presence does not select the delegation lifecycle.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Mount this package once per tool scope. It requires tools, subagents, and agents.
Minimal configuration
With the required services available, load the subagent service, a backend, the delegation tool, and this package to expose all three control and discovery tools:
- name: '@deepseek-ai/dsh-subagent'
- name: '@deepseek-ai/dsh-subagent-spawn-in-process'
- name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: spawn
- name: '@deepseek-ai/dsh-tool-subagent-control'
This package takes no configuration. Its main entry registers send_message, interrupt_agent, and list_agents together; existing tool restrictions can hide individual tools.
send_message
Sends a message to an Agent named by agent_id: any exact live Agent may target its direct continuable child, while a resident continuable child may also target its direct parent. A working target receives the message at its nearest step boundary through Steer; an inactive target starts or resumes a turn through the continuation lifecycle. The call returns only acceptance (the accepted message's stable messageId), never a reply. A failure — an unsupported target, unavailable parent, unknown child, descriptor-less child that cannot be resumed, or rejected admission — states the message was not delivered.
interrupt_agent
External executions stop permanently and cannot receive follow-ups. Local targets stop only their current turn: queued messages stay parked until a later send_message, descendants keep running, and the child stays available for follow-ups. The call returns when the stop request is accepted, not when the target is quiet; interrupting an already-finished agent is an accepted no-op, and self, sibling, stale, and non-ancestor callers get errored results.
list_agents
Lists the continuable children below the calling agent: children (default) reads direct children from the parent catalog without opening child logs; descendants recursively reads child catalogs in stable pre-order, annotating each entry with its durable direct-parent session id and depth. Status comes from the live Agent registry — running or inactive. External entries are omitted without reading a child Session. Readable one-shot children are omitted from output but their catalogs remain traversal nodes. Unknown modes and unreadable child catalogs, including one-shot children, appear as diagnostics only in descendants scope. Ordinary Session forks are not catalog entries, so neither those forks nor their descendants are listed from the source Session.
Understand the implementation
Implementation internals — click to expand
This section explains what the tools delegate to the subagent service; the observable behavior is covered in Use this package.
Design concept
Thin adapters over ctx.subagents.sendMessage(), interrupt(), and the list projections; the tools perform no lifecycle routing. Residency, cold resume, and authorization belong to the service, and the tools pass the exact live calling agent (exec.agent) as both sender and authority.
Delivery and signal ownership
The tool forwards its execution signal, which owns admission only until inbox acceptance. Once the target accepts a message, it cannot be cancelled through this tool. Every message is framed as Agent <sender-id> sent a message: and recorded with { kind: 'agent-message', form: 'relay', senderSessionId: sender.id }; the service derives that attribution and never treats it as authority.
Listing projection
list_agents derives the root id from the calling agent, reads the service catalog without a cursor, refines each candidate's status through the live Agent registry, and omits one-shot children because they cannot accept send_message. Descendant traversal preserves each parent catalog's event order. Unknown modes produce diagnostics while their catalogs remain traversable; unreadable catalogs produce diagnostics and stop that branch. Descendants absent from reachable catalogs cannot be discovered.
Source map
| File | Role |
|---|---|
src/index.ts |
Shared registration of all three tools |
src/list-agents.ts |
list_agents registration: direct-child discovery and status refinement |
Further Exploration
Read these pages when the package-level contract is not enough; they move from the tool schemas to the continuation service behind them.
- Subagent subsystem — continuable children, activations, inbox, interrupt, and follow-up authority.
- dsh-tool-subagent — the delegation tool that starts continuable children.
- Generated tool catalog — the tool schemas.
Model Experience
Tool schema
What the model sees
The generated schemas: send_message takes agent_id and message; interrupt_agent takes agent_id; list_agents accepts an optional scope.
Token effect
Fixed schema cost per parent request.
KV Cache effect
Prefix-stable; the schema does not change at runtime.
Interrupt result
What the model sees
interrupt requested for agent <agent_id> on acceptance. An unauthorized caller — self, sibling, stale, or non-ancestor — is an errored result naming the rejection; an absent or settled target still renders the acceptance line.
Token effect
One short acknowledgement per call; the interrupted turn's abort is visible only in the child's own transcript.
KV Cache effect
Append-only; each result follows the reusable request prefix.
Delivery result
What the model sees
message delivered to agent <agent_id> on acceptance; the canonical output carries the accepted messageId. A failure — a non-adjacent target, unavailable parent, unknown child, 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 target's response never returns through this call. A child uses the same tool with its initial task's parent id to append selected content to parent history.
KV Cache effect
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
Listing result
What the model sees
One line per continuable child in stable catalog order: <id> [<status>] — <label> (running = executing a turn; inactive = no turn executing, whether loaded or stored; neither status describes task completion or outcome). Only descendants scope adds <id> [diagnostic: <reason>] for an unknown mode or unreadable child catalog, including an unreadable one-shot child. The descendants scope inserts parent=<id> depth=<n> before the label dash on every line, in pre-order. Readable one-shot children are omitted; (no subagents) means no continuable child or diagnostic survived the projection.
Token effect
Grows linearly with the listed continuable children and diagnostics — reachable catalog descendants under the descendants scope; there is no cursor or cap, so long-lived parents with many persisted children pay the full list each call.
KV Cache effect
Append-only; each result follows the reusable request prefix.
Known Limitations and Deferred Work
These limits define what the control tools cannot observe or steer; they are current package constraints.
- A delivered message has no independent result — acceptance returns only its inbox
messageId; later target work lands in that target's durable Session and is never collected through this tool. A reply is another explicitly addressedsend_message, not this call's result. - Only supported adjacent Agents can communicate — every sender may target a direct continuable child, only a sender with a resident continuable Activation may target its direct parent, and that parent must remain live; siblings and deeper descendants are not message targets, and only direct-child delivery supports cold activation.
- Listing is a snapshot, not a delivery promise — it may race publication, disposal, or a later message, and another process may activate a child this process reports as
inactive; cross-process accuracy requires a shared lease.interrupt_agentperforms the authoritative live-lineage check itself, so discovery staleness cannot grant authority. - No pagination or deletion — the complete stably ordered set is returned, and persisted children remain listed for as long as their sessions remain in persistence; a service-level bound or delete operation is a later product decision.
Dev Note
Working context for maintainers — click to expand
None.