@xneog/dsh-subagent 0.1.0 → 0.1.3-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +108 -76
- package/README.zh.md +112 -80
- package/lib/index.js +1258 -718
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +923 -0
- package/lib/typert.remote-client.d.ts +27 -0
- package/lib/typert.remote-client.js +159 -0
- package/lib/types/assistant-output.d.ts +3 -3
- package/lib/types/assistant-output.js +8 -4
- package/lib/types/child-agent.d.ts +16 -5
- package/lib/types/child-agent.js +51 -13
- package/lib/types/client.d.ts +2 -1
- package/lib/types/client.js +1 -1
- package/lib/types/continuation.d.ts +100 -72
- package/lib/types/continuation.js +439 -169
- package/lib/types/control-types.d.ts +144 -0
- package/lib/types/control-types.js +9 -0
- package/lib/types/control.d.ts +67 -0
- package/lib/types/control.js +115 -0
- package/lib/types/descriptor-seed.d.ts +1 -1
- package/lib/types/descriptor-seed.js +1 -1
- package/lib/types/descriptor.d.ts +6 -1
- package/lib/types/descriptor.js +6 -2
- package/lib/types/index.d.ts +103 -69
- package/lib/types/index.js +436 -287
- package/lib/types/internal.d.ts +59 -0
- package/lib/types/internal.js +58 -0
- package/lib/types/lifecycle.js +4 -3
- package/lib/types/list-children.d.ts +12 -59
- package/lib/types/list-children.js +166 -101
- package/lib/types/out-of-process.d.ts +5 -2
- package/lib/types/out-of-process.js +42 -4
- package/lib/types/projection-types.d.ts +4 -3
- package/lib/types/projection.d.ts +55 -8
- package/lib/types/projection.js +33 -17
- package/lib/types/run-settlement.js +17 -6
- package/lib/types/types.d.ts +25 -0
- package/package.json +67 -37
- package/lib/types/activation-setup-registry.d.ts +0 -57
- package/lib/types/activation-setup-registry.js +0 -148
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/subagent/subagent/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: c6c89b59309f5ca0e83e6940e7250cb1bcb19169
|
|
6
|
+
README.zh.md: 383219bd10a700fc9a17134b4fcf00c193540021
|
package/README.md
CHANGED
|
@@ -1,122 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "The subagent delegation seam for users and maintainers choosing a provider backend, composing delegation tools, or debugging child-agent runs."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @xneog/dsh-subagent
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
The [subagent family overview](../README.md) maps implementations and model-facing consumers. This package owns the provider registry, shared request and result contracts, durable descriptors, and continuable-child orchestration. Multiple named providers may coexist behind that contract.
|
|
8
|
-
|
|
9
|
-
## Service API
|
|
10
|
-
|
|
11
|
-
`SubagentRuntime` has these operations:
|
|
12
|
-
|
|
13
|
-
| Member | Meaning |
|
|
14
|
-
|---|---|
|
|
15
|
-
| `registerProvider(provider)` | Register one trusted same-process implementation by name. Registration is effect-scoped; removing it prevents new starts but does not revoke runs already returned to callers. Duplicate names fail loud. |
|
|
16
|
-
| `getProvider(name)` | Return the provider, or `undefined` when absent. |
|
|
17
|
-
| `list()` | Return provider names in insertion order. |
|
|
18
|
-
| `start(name, request)` | Validate an ordinary caller request, resolve its detached `one-shot` descriptor, then await the provider until a real one-shot child is published. Fulfillment returns a holder-owned `SubagentRun`; rejection means the provider has already cleaned every unpublished startup resource, while post-publication turn or infrastructure faults settle through the run. Continuable children never enter through this operation. |
|
|
19
|
-
| `startContinuable(spec)` | Establish one durable continuable child and deliver its initial prompt. Resolves with `{ childId, messageId }` when the child's inbox accepts that prompt, without waiting for the turn to start or for the message to reach the Session log; any earlier failure rejects with no ids and rolls the child back entirely. Requires `ctx.agents`, session persistence, and a provider with the `prepareContinuable` capability. |
|
|
20
|
-
| `followup(parent, childId, content, { source, signal })` | Deliver one later message from the exact live direct parent as the child's next FIFO turn, matching `Agent.followup()` terminology, and return the accepted `MessageId`. A resident child's inbox accepts it directly (waking a waiting Activation); an absent one cold-resumes from its persisted Session. Requires `ctx.agents`; cold resume also requires session persistence. |
|
|
21
|
-
| `interrupt(targetSessionId, authority)` | Interrupt one live continuable child's current turn under a human durable parent address (`{ kind: 'user', parentSessionId }`) or an exact live ancestor Agent (`{ kind: 'ancestor', agent }`). Admission is synchronous and the effect asynchronous: it issues `Agent.cancel(cause, { keepInbox: true })` and returns without waiting for the target to observe the signal. Unclaimed pending inbox work, the Activation, and published descendants are preserved; work already claimed into the interrupted turn is not requeued. An absent target is an accepted no-op; a wrong parent address or a stale, self-targeting, or non-ancestor caller rejects with `UNAUTHORIZED`. |
|
|
22
|
-
| `reportFrom(child, content, { delivery, signal })` | Deliver one selected message from the exact live continuable child to its exact live direct parent and return the accepted stable `MessageId`. Quiet delivery injects context; waking delivery submits one later parent turn. |
|
|
23
|
-
| `registerContinuableSetup(contribution)` | Compose an optional deployment capability into each continuable child's unpublished scope, with immediate revocation from resident children. |
|
|
24
|
-
| `drainContinuableDescendants(parents)` | Close admission below exact live host-owned parent Agents, stop only their visible continuable descendants, await materializations admitted below those roots through publication or rollback, then release the selected forests child-first. The cutoff lasts until each exact parent leaves the registry; unrelated parent forests and manager-wide admission remain live. |
|
|
25
|
-
| `listChildren(parentSessionId, signal?)` | List direct session-backed subagents with their `one-shot`/`continuable` mode, `running`/`inactive` activity, origin-classified one-level `hasChildren` hint, and per-child diagnostics, ordered by `createdAt` then id, without loading or resuming them. Reads the live session store and optional session persistence directly (live-only enumeration when persistence is absent) and requires the mounted `sessionProjections` registry; it does not require `ctx.agents`, the continuation manager, or any query service. |
|
|
26
|
-
| `listDescendants(rootSessionId, signal?)` | Flatten the root's complete session tree in stable pre-order from the same live-preferred corpus, adding each subagent entry's durable `parentId` and root-relative `depth`. Ordinary sessions and one-shot children remain traversal nodes so continuable descendants below them are discovered. Identity, diagnostics, dependencies, and cancellation follow `listChildren()`. |
|
|
27
|
-
|
|
28
|
-
`SubagentStartRequest.label` is an optional short durable display label for a session-backed one-shot child. Model-facing delegation supplies its existing `description`; lower-level callers need not invent presentation metadata. Continuable starts always carry their own required label. `signal` is required and is the canonical cancellation channel for a one-shot `start`. An abort before publication makes `start()` reject after rollback; an abort after publication cancels the returned run's remaining turn work without hiding its id. The request may also select a model, require structured output, cap delegation depth, restrict child tools, or set a child persona. For a continuable start or follow-up, the caller signal owns lookup, materialization, and admission only until inbox acceptance; afterward the manager owns the Activation independently, so later caller cancellation neither cancels the accepted turn nor disposes the child.
|
|
29
|
-
|
|
30
|
-
Follow-up authority comes from the exact live direct parent recorded in the child's durable header. Cold resume checks that authority before reconstruction and again in the final no-await inbox-admission span, so a parent unregistered or replaced during materialization cannot authorize delivery. The `source` on a follow-up records who supplied the delivered message and grants no authority.
|
|
10
|
+
## Summary
|
|
31
11
|
|
|
32
|
-
|
|
12
|
+
`dsh-subagent` is the service behind child-agent delegation: an agent hands a task to a named child, collects the finished result, and — for continuable children — keeps sending follow-up work across turns. Multiple providers coexist under one contract, so a single composition can offer in-process children, out-of-process ACP or SDK children, and real Codex or Claude Code children side by side. Children come in two shapes: one-shot runs that settle with a single result, and continuable children whose durable session accepts later messages and can be interrupted. The same service answers discovery questions — which children exist, their mode, activity, and lineage — without loading or resuming them. Mount it with at least one provider backend and a delegation tool; the backends and the model-facing tools live in sibling packages.
|
|
33
13
|
|
|
34
|
-
##
|
|
14
|
+
## Table of Contents
|
|
35
15
|
|
|
36
|
-
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
- `depthLimit` — enforce `maxDepth`.
|
|
40
|
-
- `toolFilter` — apply the requested child tool restriction.
|
|
41
|
-
- `persona` — apply a per-child persona.
|
|
23
|
+
-----
|
|
42
24
|
|
|
43
|
-
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
44
27
|
|
|
45
|
-
|
|
28
|
+
This package is the contract every delegation setup shares. You enable it by mounting the service together with one or more provider backends and the model-facing delegation tool; from then on, an agent can delegate work and the service routes each request to the named provider.
|
|
46
29
|
|
|
47
|
-
|
|
30
|
+
### Enabling delegation
|
|
48
31
|
|
|
49
|
-
|
|
32
|
+
Mount the service with a provider and the delegation tool. The provider registers under the name you configure (the in-process spawn backend defaults to `spawn`); the tool row names that provider so the model sees a static tool. A minimal one-shot setup:
|
|
50
33
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
```yaml
|
|
35
|
+
- name: '@xneog/dsh-subagent'
|
|
36
|
+
- name: '@xneog/dsh-subagent-spawn-in-process'
|
|
37
|
+
- name: '@xneog/dsh-tool-subagent'
|
|
38
|
+
config:
|
|
39
|
+
provider: spawn
|
|
40
|
+
toolName: subagent
|
|
41
|
+
```
|
|
54
42
|
|
|
55
|
-
|
|
43
|
+
An agent that calls the tool gets the child's final answer as the tool result. Mounting the service alone changes nothing: nothing can delegate until a provider and a tool are composed.
|
|
56
44
|
|
|
57
|
-
|
|
45
|
+
### One-shot and continuable children
|
|
58
46
|
|
|
59
|
-
|
|
47
|
+
One-shot children run once and settle with a single result, plus an optional structured output and a safe diagnostic on failure. A start request may override the child Agent's provider, model, reasoning effort, and output-token limit through `agentOptions`; every requested option requires the provider's matching capability. Continuable children keep a durable session and accept later messages in order: the caller receives a stable child id, sends adjacent-Agent messages, and can interrupt the current turn without destroying the child. The tool row's `backgroundMode` picks the shape (`one-shot` by default, or `continuable` on providers that support it).
|
|
60
48
|
|
|
61
|
-
|
|
49
|
+
### Messaging, interrupting, and discovering
|
|
62
50
|
|
|
63
|
-
|
|
51
|
+
Every exact live Agent can use `sendMessage()` with a direct continuable child; a resident continuable child can also use it with its direct parent. A working target receives the message through Steer at its nearest step; an idle target starts a turn, and only a direct child can be cold-resumed. The parent can also interrupt a running descendant or list its children at any time. A browser continuation prompt may carry image parts: the Host admits and persists each image batch through the attachment store before the child inbox accepts the message, and refuses delivery when the child's declared model does not accept image input. Discovery covers both shapes: the service lists direct children and the full descendant tree — mode, activity, and lineage — reading live session state and optional persistence, without loading any child.
|
|
64
52
|
|
|
65
|
-
|
|
53
|
+
### Failure and recovery
|
|
66
54
|
|
|
67
|
-
|
|
55
|
+
Requests that need a capability the chosen provider lacks fail loudly at start rather than being silently ignored. A failed child run returns a stop reason, and provider backends add a safe diagnostic; a cancelled request settles as `aborted`. Children are isolated: a crashed or misbehaving child cannot corrupt the parent's session.
|
|
68
56
|
|
|
69
|
-
|
|
57
|
+
-----
|
|
70
58
|
|
|
71
|
-
|
|
59
|
+
<a id="understand-the-implementation"></a>
|
|
60
|
+
## Understand the implementation
|
|
72
61
|
|
|
73
|
-
|
|
62
|
+
<details>
|
|
63
|
+
<summary>Implementation internals — click to expand</summary>
|
|
74
64
|
|
|
75
|
-
|
|
65
|
+
This section explains how the service is built and where the observable behavior comes from; the full contract lives in [Use this package](#use-this-package).
|
|
76
66
|
|
|
77
|
-
|
|
67
|
+
### Design concept
|
|
78
68
|
|
|
79
|
-
|
|
69
|
+
- **One service, many providers.** The service is a named-provider registry; each backend registers under a unique name and a request picks one by name.
|
|
70
|
+
- **Two child shapes.** One-shot runs transfer ownership at publication; continuable children keep a durable Session and at most one process-local Activation.
|
|
71
|
+
- **Fulfillment is publication.** A provider's `start()` fulfills only after a real child exists, so the caller always owns a live run or nothing.
|
|
72
|
+
- **Trusted same-process values.** Requests, descriptors, and results are borrowed immutable; serialization and hostile-input validation belong at process and wire boundaries.
|
|
80
73
|
|
|
81
|
-
|
|
74
|
+
### Source map
|
|
82
75
|
|
|
83
|
-
|
|
76
|
+
| File | Role |
|
|
77
|
+
|---|---|
|
|
78
|
+
| [`src/index.ts`](src/index.ts) | Service entry: provider registry, start and continuation API, lifecycle events |
|
|
79
|
+
| [`src/continuation.ts`](src/continuation.ts) | Continuable children: identity reservation, Activation residency, adjacent messaging, interrupt, settlement |
|
|
80
|
+
| [`src/internal.ts`](src/internal.ts) | Host-only Queue and Steer adapters for browser and Team message protocols |
|
|
81
|
+
| [`src/types.ts`](src/types.ts) | Public request, result, and provider contracts |
|
|
82
|
+
| [`src/descriptor.ts`](src/descriptor.ts) | Versioned `subagent/descriptor` session-event vocabulary |
|
|
83
|
+
| [`src/child-agent.ts`](src/child-agent.ts) | Child composition, delegated policy, depth helpers |
|
|
84
|
+
| [`src/list-children.ts`](src/list-children.ts) | Discovery over the live session store and optional persistence |
|
|
85
|
+
| [`src/control.ts`](src/control.ts) | Browser control assembly: catalog activity sampling, browser-zone validation, failure codes |
|
|
86
|
+
| [`src/control-types.ts`](src/control-types.ts) | Client-safe catalog row, control requests, receipts, and failures |
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
### One-shot flow
|
|
86
89
|
|
|
87
|
-
A
|
|
90
|
+
A request is validated against the provider's advertised capabilities, a durable descriptor is snapshotted, and the provider builds the child. Both in-process providers advertise `agentOptions`: child creation merges requested fields over the provider, model, and reasoning effort in the parent's latest logged request, falls back to creation options before the first request, and retains the configured token limit. A route change without an explicit effort clears the inherited route-owned effort so the selected model resolves its default. DSH SDK also advertises this capability and publishes immutable `agentRouteDefaults`, which supply its instance provider/model defaults before exact-route preflight; `start()` still owns direct callers and the output cap. ACP, Codex, and Claude Code reject agent-route overrides rather than silently ignoring them. On success the run is published and ownership transfers to the caller; on failure the provider rolls back every unpublished resource. The result carries the child's final output, an optional structured value, a stop reason, and an optional safe diagnostic.
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
### Continuable flow
|
|
90
93
|
|
|
91
|
-
The
|
|
94
|
+
The manager reserves a child identity, resolves the durable descriptor, creates (or cold-resumes) the child Agent, installs it in an Activation, and submits the prompt. Model-authored messages cross one parent/child edge through fixed Steer scheduling; host protocols retain an internal Queue adapter for distinct turns. An absent direct-child Activation cold-resumes from the persisted session. When a resident Activation settles, the manager tells the child's direct parent in the parent's own turn stream.
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
### Ownership and invariants
|
|
94
97
|
|
|
95
|
-
|
|
98
|
+
- **Publication is the boundary** — before it the provider owns the setup and must roll back on failure; after it the caller owns the run and must dispose it.
|
|
99
|
+
- **Registration is effect-scoped** — removing a provider blocks new starts but never revokes accepted runs.
|
|
100
|
+
- **Agent-message authority is exact adjacency** — `sendMessage()` requires the exact live sender; every sender may target a direct continuable child, while only a sender with a resident continuable Activation may target its direct parent.
|
|
101
|
+
- **The descriptor is log-only** — a session event absent from model history and retained across compaction; a continuable descriptor records the resolved child provider, model, and reasoning effort explicitly for cold resume.
|
|
96
102
|
|
|
97
|
-
|
|
103
|
+
</details>
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
-----
|
|
100
106
|
|
|
101
|
-
|
|
107
|
+
<a id="further-exploration"></a>
|
|
108
|
+
## Further Exploration
|
|
102
109
|
|
|
103
|
-
|
|
110
|
+
Read these pages when the package-level contract is not enough. They move from the shared seam to the backends, the model-facing tools, and the design decisions.
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
- [Subagent subsystem](../../../docs/subsystems/subagent.md) — the service contract, provider contract, and terminal result semantics.
|
|
113
|
+
- [Subagent capability seam](../../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md) — the design record for the delegation capability family.
|
|
114
|
+
- [Continuable background subagents](../../../.agents/notes/implemented/feature/2026-07-21-continuable-background-subagents.md) — durable children that accept follow-up turns.
|
|
115
|
+
- [In-process spawn backend](../subagent-spawn-in-process/README.md) — the simplest provider to compose.
|
|
116
|
+
- [Out-of-process ACP backend](../subagent-acp/README.md) — children with their own runtime over the Agent Client Protocol.
|
|
117
|
+
- [Merged subagent control service](../../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md) — the follow-up, interrupt, and listing surface.
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
-----
|
|
108
120
|
|
|
121
|
+
<a id="model-experience"></a>
|
|
109
122
|
## Model Experience
|
|
110
123
|
|
|
111
124
|
### Settlement notice
|
|
112
125
|
|
|
113
126
|
#### What the model sees
|
|
114
127
|
|
|
115
|
-
One user-role parent message opening with the outcome — `Background subagent <child-id> finished and will do no further work unless you send it more.`, or the matching line for a child that was stopped, ran out of room, declined, or failed — followed by `Its closing message:` and the child's final assistant content, or `It left no closing message.` when it produced none. This
|
|
128
|
+
One user-role parent message opening with the outcome — `Background subagent <child-id> finished and will do no further work unless you send it more.`, or the matching line for a child that was stopped, ran out of room, declined, or failed — followed by `Its closing message:` and the child's final assistant content, or `It left no closing message.` when it produced none. This runtime-owned notice is distinct from model-authored parent/child messages, which use `sendMessage()` and `AgentMessageSource`; delegation schemas and model controls belong to the Consumer packages.
|
|
116
129
|
|
|
117
130
|
#### Token effect
|
|
118
131
|
|
|
119
|
-
One notice per settled Activation in the parent's request, sized by the child's final message. A child that
|
|
132
|
+
One notice per settled Activation in the parent's request, sized by the child's final message. A child that sends its own message and then settles costs the parent both.
|
|
120
133
|
|
|
121
134
|
#### KV Cache effect
|
|
122
135
|
|
|
@@ -144,11 +157,30 @@ Prefix-stable within a child: the statement never changes during the child's lif
|
|
|
144
157
|
|
|
145
158
|
## Known Limitations and Deferred Work
|
|
146
159
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- **
|
|
153
|
-
- **
|
|
160
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
These limits define when the seam is a poor fit or needs special operational care. They are current package constraints, not a general delegation comparison or a task backlog.
|
|
164
|
+
|
|
165
|
+
- **ACP children remain one-shot and are not trace-enumerable** — an ACP run has no local child session in the parent's session corpus, and remote providers need an Activation ownership contract before they can support continuable children.
|
|
166
|
+
- **Adjacent model messaging only** — `sendMessage()` requires an exact live sender; every sender may target a direct continuable child, while only a sender with a resident continuable Activation may target its direct parent. Browser prompts use the separate Queue control path.
|
|
167
|
+
- **A direct parent must remain live for child-to-parent delivery** — the service has no durable parent mailbox; a missing parent rejects the message instead of accepting work it cannot wake.
|
|
168
|
+
- **Wake gap during cancellation convergence** — a follow-up accepted after an interrupt signal but before the driver becomes idle stays queued until another waking send.
|
|
169
|
+
- **Process-local residency** — the Activation inbox and ownership graph do not coordinate two harness processes; concurrent access to one persistence store needs a durable mailbox and cross-process lease protocol.
|
|
170
|
+
- **No replay of accepted-but-unlogged messages** — a crash can lose an accepted prompt that never reached the child's session log; the lost message is not replayed automatically.
|
|
171
|
+
- **No durable parent mailbox** — child-to-parent messages require a resident continuable child and live direct parent, and provide acceptance identity rather than exactly-once delivery.
|
|
154
172
|
- **Lifecycle events are observe-only** — a run-affecting `subagent/end` continuation or decision API waits for a concrete consumer.
|
|
173
|
+
|
|
174
|
+
<a id="dev-note"></a>
|
|
175
|
+
### Dev Note
|
|
176
|
+
|
|
177
|
+
<details>
|
|
178
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
179
|
+
|
|
180
|
+
This Dev Note is working context for maintainers: open questions and undecided directions. It is explicitly non-authoritative — shipped behavior and limits live in the sections above and in the package code.
|
|
181
|
+
|
|
182
|
+
- **Cross-process continuation** — a durable mailbox and lease protocol would let two harness processes share one persistence store.
|
|
183
|
+
- **Continuable ACP children** — requires persisting the remote session id and a per-child continuation advertisement.
|
|
184
|
+
- **Host-user delivery** — a future host adapter needs a concrete authenticated interaction before the seam gains a user delivery capability.
|
|
185
|
+
|
|
186
|
+
</details>
|