@deepseek-ai/dsh-subagent 0.0.1-rc.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.
Files changed (41) hide show
  1. package/LICENSE +28 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +132 -0
  4. package/README.zh.md +132 -0
  5. package/lib/index.js +2392 -0
  6. package/lib/invariant.js +76 -0
  7. package/lib/types/activation-setup-registry.d.ts +57 -0
  8. package/lib/types/activation-setup-registry.js +148 -0
  9. package/lib/types/child-agent.d.ts +139 -0
  10. package/lib/types/child-agent.js +169 -0
  11. package/lib/types/client.d.ts +7 -0
  12. package/lib/types/client.js +7 -0
  13. package/lib/types/continuation.d.ts +375 -0
  14. package/lib/types/continuation.js +951 -0
  15. package/lib/types/depth.d.ts +31 -0
  16. package/lib/types/depth.js +39 -0
  17. package/lib/types/descriptor-seed.d.ts +21 -0
  18. package/lib/types/descriptor-seed.js +24 -0
  19. package/lib/types/descriptor.d.ts +139 -0
  20. package/lib/types/descriptor.js +189 -0
  21. package/lib/types/error.d.ts +11 -0
  22. package/lib/types/error.js +14 -0
  23. package/lib/types/index.d.ts +278 -0
  24. package/lib/types/index.js +338 -0
  25. package/lib/types/invariant.d.ts +13 -0
  26. package/lib/types/invariant.js +91 -0
  27. package/lib/types/lifecycle.d.ts +93 -0
  28. package/lib/types/lifecycle.js +169 -0
  29. package/lib/types/list-children.d.ts +112 -0
  30. package/lib/types/list-children.js +316 -0
  31. package/lib/types/out-of-process.d.ts +115 -0
  32. package/lib/types/out-of-process.js +181 -0
  33. package/lib/types/projection-types.d.ts +60 -0
  34. package/lib/types/projection-types.js +7 -0
  35. package/lib/types/projection.d.ts +48 -0
  36. package/lib/types/projection.js +135 -0
  37. package/lib/types/run-settlement.d.ts +17 -0
  38. package/lib/types/run-settlement.js +59 -0
  39. package/lib/types/types.d.ts +293 -0
  40. package/lib/types/types.js +19 -0
  41. package/package.json +106 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * Internal continuable-subagent manager: stable child ids, descriptor
3
+ * persistence, activation admission, the live ownership graph, cold resume,
4
+ * and child-first disposal behind `ctx.subagents`.
5
+ *
6
+ * A continuable child has one durable Session and at most one process-local
7
+ * {@link Activation} — one residency epoch for a reconstructed child Agent. An
8
+ * Activation is not a request, result, cancellation, or Task boundary: it may
9
+ * execute many FIFO turns and stays resident while descendants it created are
10
+ * still running. The Agent inbox is the only turn queue, so this manager owns
11
+ * residency while the Agent loop owns all turn ordering and execution. No
12
+ * continuable path creates a Task or an intermediate result-bearing wrapper.
13
+ *
14
+ * @module @deepseek-ai/dsh-subagent
15
+ */
16
+ import type { Context } from '@deepseek-ai/cordis';
17
+ import type { Agent } from '@deepseek-ai/dsh-agent';
18
+ import type { ContentBlock, MessageId, MessageSource } from '@deepseek-ai/dsh-llm';
19
+ import { SessionId } from '@deepseek-ai/dsh-session';
20
+ import type { SubagentDescriptorData } from './descriptor.ts';
21
+ import type { ContinuableCreateRequest, ContinuableCreateSpec, SubagentStartRequest } from './types.ts';
22
+ import type { ActivationObserver } from './lifecycle.ts';
23
+ import type SubagentActivationSetupRegistry from './activation-setup-registry.ts';
24
+ /** Attribution for a model coordinator's follow-up to one of its children. */
25
+ export interface CoordinatorMessageSource {
26
+ readonly kind: 'coordinator';
27
+ /** A message another agent addressed to this one (`relay` context form). */
28
+ readonly form: 'relay';
29
+ /** Session id of the agent whose tool call produced the follow-up. */
30
+ readonly senderSessionId: SessionId;
31
+ }
32
+ /** Durable attribution for a continuable child's explicit parent report. */
33
+ export interface SubagentReportMessageSource {
34
+ readonly kind: 'subagent-report';
35
+ /** A message another agent addressed to this one (`relay` context form). */
36
+ readonly form: 'relay';
37
+ /** Session id of the reporting child. */
38
+ readonly senderSessionId: SessionId;
39
+ }
40
+ declare module '@deepseek-ai/dsh-llm' {
41
+ interface MessageSourceMap {
42
+ coordinator: CoordinatorMessageSource;
43
+ 'subagent-report': SubagentReportMessageSource;
44
+ }
45
+ }
46
+ /** Deployment scheduling policy for accepted child reports. */
47
+ export type SubagentReportDelivery = 'quiet' | 'wakeup';
48
+ /** Options for one continuable child's report to its direct parent. */
49
+ export interface SubagentReportOptions {
50
+ /** Already-resolved parent scheduling policy. */
51
+ readonly delivery: SubagentReportDelivery;
52
+ /** Caller cancellation, owning authorization and admission until acceptance. */
53
+ readonly signal: AbortSignal;
54
+ }
55
+ /** What a caller asks for when starting a continuable background child. */
56
+ export interface ContinuableStartSpec {
57
+ /** The `ctx.subagents` provider whose continuable-creation capability establishes the child. */
58
+ readonly provider: string;
59
+ /** The initial delegation's short `description`, persisted as the child's creation label. */
60
+ readonly label: string;
61
+ /**
62
+ * The delegation request. The manager reserves the stable child id, resolves
63
+ * the durable descriptor, and composes the child itself.
64
+ */
65
+ readonly request: Omit<SubagentStartRequest, 'label' | 'signal' | 'outputSchema'>;
66
+ /** Caller cancellation, owning the operation only until inbox acceptance. */
67
+ readonly signal: AbortSignal;
68
+ }
69
+ /** Identities returned once a continuable child accepted its initial prompt. */
70
+ export interface ContinuableStart {
71
+ /** The durable child session id, stable across activations. */
72
+ readonly childId: SessionId;
73
+ /** The accepted initial prompt's inbox message id. */
74
+ readonly messageId: MessageId;
75
+ }
76
+ /**
77
+ * Authority under which one interrupt request is admitted. `user` carries the
78
+ * durable direct-parent address a human client presented; `ancestor` carries
79
+ * the exact live Agent object whose recorded lineage must contain the caller.
80
+ */
81
+ export type SubagentInterruptAuthority = {
82
+ readonly kind: 'user';
83
+ readonly parentSessionId: SessionId;
84
+ } | {
85
+ readonly kind: 'ancestor';
86
+ readonly agent: Agent;
87
+ };
88
+ /** Options for following up with one continuable child. */
89
+ export interface SubagentFollowupOptions {
90
+ /** Durable attribution retained on the delivered message; it grants no authority. */
91
+ readonly source: MessageSource;
92
+ /** Caller cancellation, owning the operation only until inbox acceptance. */
93
+ readonly signal: AbortSignal;
94
+ }
95
+ /**
96
+ * Hooks the manager needs from the owning service. Declared here, by the
97
+ * dependent, so the manager states exactly what it requires instead of
98
+ * depending back on the whole {@link SubagentService}. Package-private: no
99
+ * consumer outside this package supplies a host.
100
+ */
101
+ interface ContinuationHost {
102
+ /**
103
+ * Resolve one provider's continuable-creation contribution, or reject when
104
+ * the provider is unknown or lacks the capability.
105
+ * @param name - the configured provider name.
106
+ * @param request - the reserved identity, delegating parent, and cancellation.
107
+ * @returns the provider's detached creation spec.
108
+ */
109
+ prepareContinuable(name: string, request: ContinuableCreateRequest): Promise<ContinuableCreateSpec>;
110
+ /**
111
+ * Build the lifecycle observer for one Activation's residency epoch.
112
+ * @param provider - the provider name recorded in the durable descriptor.
113
+ * @param childId - the durable child session id.
114
+ * @param parent - the exact live direct parent for scoped dispatch.
115
+ * @returns the observer whose edges this epoch publishes.
116
+ */
117
+ observeActivation(provider: string, childId: SessionId, parent: Agent): ActivationObserver;
118
+ }
119
+ /**
120
+ * The continuable-subagent orchestration service behind `ctx.subagents`. Tool
121
+ * schema and host adapters are consumers of this one contract; foreground
122
+ * one-shot delegation keeps calling `ctx.subagents.start()` and never enters
123
+ * this lifecycle.
124
+ */
125
+ export declare class SubagentContinuationManager {
126
+ private readonly ctx;
127
+ private readonly host;
128
+ private readonly setupRegistry;
129
+ /** Child session id → its live Activation. Process-local, never durable. */
130
+ private activations;
131
+ /** Materializations admitted before drain, tracked through publication or rollback. */
132
+ private readonly materializations;
133
+ private readonly locks;
134
+ /** Structural Cordis owner of every Activation handle. */
135
+ private readonly ownerCtx;
136
+ /**
137
+ * Exact roots whose host teardown has begun, with the live lineage members
138
+ * observed under each root. Entries remain until that exact root leaves the
139
+ * Agent registry, closing admission throughout its host's teardown without
140
+ * poisoning a later same-id replacement.
141
+ */
142
+ private readonly closingScopes;
143
+ private draining;
144
+ constructor(ctx: Context, host: ContinuationHost, setupRegistry: SubagentActivationSetupRegistry);
145
+ /**
146
+ * Start one continuable background child: reserve its durable identity,
147
+ * resolve the provider's detached creation spec, create the child Agent
148
+ * through the private activation-owner scope, establish any continuable-parent
149
+ * ownership, and submit the initial prompt. Resolves when inbox acceptance
150
+ * yields the message id — without waiting for the turn to start or for the
151
+ * message to reach the Session log.
152
+ *
153
+ * Every failure before that acceptance rejects without either id, disposing
154
+ * any created handle and rolling back the Activation and parent ownership.
155
+ * The caller signal owns lookup, materialization, and admission only until
156
+ * acceptance; afterwards the manager owns the Activation independently.
157
+ * @param spec - provider, delegation request, and caller cancellation.
158
+ * @returns the durable child id and the accepted initial prompt's message id.
159
+ */
160
+ startContinuable(spec: ContinuableStartSpec): Promise<ContinuableStart>;
161
+ /**
162
+ * Deliver one later message to a known continuable child as its next FIFO
163
+ * turn. Routing depends only on Activation residency: a `running` Activation
164
+ * enqueues, a `waiting` one wakes the same Agent, and an absent one
165
+ * cold-resumes a new Activation from the persisted Session. The Agent inbox
166
+ * is the only queue, so every accepted message has one observable order.
167
+ *
168
+ * The caller signal owns lookup, materialization, and admission only until
169
+ * inbox acceptance; afterwards the accepted turn cannot be cancelled through
170
+ * this service.
171
+ * @param parent - the exact live direct parent authorizing this delivery.
172
+ * @param childId - the durable child session id.
173
+ * @param content - the user-role content to deliver.
174
+ * @param options - the message source fields and caller cancellation.
175
+ * @returns the accepted message's inbox id.
176
+ * @throws when parent authority, availability, or admission rejects the delivery.
177
+ */
178
+ followup(parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions): Promise<MessageId>;
179
+ /**
180
+ * Interrupt one live continuable child's current turn. Admission is
181
+ * synchronous and the effect is asynchronous: this authorizes the caller,
182
+ * requests `Agent.cancel(cause, { keepInbox: true })` on the target, and
183
+ * returns without waiting for the target to observe the signal or reach
184
+ * quiescence. The Activation, its handle, accepted unclaimed inbox work, and
185
+ * already-published descendants are untouched; work already claimed into the
186
+ * interrupted turn is not requeued. Once the interrupted driver is idle, a
187
+ * waking send resumes the parked queue.
188
+ *
189
+ * An absent target is an accepted no-op, which uniformly covers natural
190
+ * completion races, repeated requests, one-shot ids, and unknown ids without
191
+ * consulting the durable catalog. A target whose disposal transaction is
192
+ * already open is likewise an accepted no-op after authorization.
193
+ * @param targetSessionId - the durable child session id to interrupt.
194
+ * @param authority - the human parent address or exact live ancestor Agent.
195
+ * @throws {SubagentError} `UNAUTHORIZED` when the presented authority does
196
+ * not own the live target: a stale or self-targeting ancestor caller, a
197
+ * parent address that is not the live target's durable direct parent, or
198
+ * an ancestor outside the target's recorded live lineage.
199
+ */
200
+ interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void;
201
+ /**
202
+ * Deliver explicitly selected content from one resident continuable child to
203
+ * its durable direct parent. Sender authorization, parent resolution, and
204
+ * send acceptance share one no-await span. Reporting neither concludes the
205
+ * child's turn nor changes its Activation lifetime.
206
+ * @param child - exact live reporting child; this is the authority credential.
207
+ * @param content - selected model-facing content.
208
+ * @param options - scheduling policy and pre-acceptance cancellation.
209
+ * @returns the stable identity of the message accepted by the parent.
210
+ * @throws {SubagentError} when the sender is unauthorized, the parent is not
211
+ * live, or continuation admission is closing.
212
+ */
213
+ reportFrom(child: Agent, content: ContentBlock[], options: SubagentReportOptions): Promise<MessageId>;
214
+ /** Authorize only the exact Agent of one resident Activation. */
215
+ private authorizeReporter;
216
+ /** Resolve the reporting child's live direct parent from durable lineage. */
217
+ private resolveReportParent;
218
+ /** Deliver one framed report through the selected parent scheduling preset. */
219
+ private deliverReport;
220
+ /** Send one report while translating only the parent's own rejection. */
221
+ private sendReport;
222
+ /**
223
+ * Close admission, await every already-admitted materialization through
224
+ * publication or rollback, then dispose the stable live Activation forest
225
+ * child-first. Sibling branches drain independently: one failure is recorded
226
+ * but never prevents the remaining handles from being attempted, and the
227
+ * aggregate rejects only after every branch settles.
228
+ * @returns once materialization is quiescent and every live Activation released its handle.
229
+ * @throws an aggregate error when any branch failed to release.
230
+ */
231
+ drain(): Promise<void>;
232
+ /**
233
+ * Stop only the continuable descendants of exact live host-owned parents.
234
+ * Admission stays closed for those parent trees until each exact parent
235
+ * leaves the Agent registry; unrelated trees and manager-wide admission stay
236
+ * live.
237
+ * @param parents - exact live roots whose continuable descendants must stop.
238
+ * @returns once every retained descendant Activation released its handle.
239
+ * @throws an aggregate error after all scoped branches settle when any failed.
240
+ */
241
+ drainDescendants(parents: readonly Agent[]): Promise<void>;
242
+ /** Dispose independent roots and report every branch failure after all settle. */
243
+ private disposeRoots;
244
+ /** Return the retained member set for one exact scoped-teardown root. */
245
+ private closingMembers;
246
+ /**
247
+ * Return the exact currently resolvable ancestry from `agent` upward. The
248
+ * first element is always the supplied identity, even when it is already
249
+ * stale; each ancestor after it must be the registry's current exact entry.
250
+ */
251
+ private liveLineage;
252
+ /** Reject new admission once the manager or this exact parent tree began draining. */
253
+ private assertAdmitting;
254
+ /**
255
+ * Derive residency from Agent quiescence and the owned-child set. `running`
256
+ * covers an active admission, an open turn, or accepted waking inbox work.
257
+ *
258
+ * `Agent.status` alone is insufficient: it stays `idle` between an accepted
259
+ * waking send and the microtask that admits it, so a synchronous inbox
260
+ * observer would see `settled` while a turn is already queued. `accepted`
261
+ * holds the ids this manager admitted but has not yet seen drained.
262
+ */
263
+ private stateOf;
264
+ /**
265
+ * Cold-resume a persisted child: inspect and authorize its Session, fold the
266
+ * generic descriptor, create the Activation through `ctx.agents.resume()`,
267
+ * and submit the waiting turn. This never dispatches through a subagent
268
+ * provider — the persisted Session already holds the initial prefix and the
269
+ * descriptor is the whole reconstruction input.
270
+ */
271
+ private coldResume;
272
+ /**
273
+ * Submit to a freshly materialized Activation or roll it back completely.
274
+ * @param activation - the just-published Activation to admit or release.
275
+ * @param content - the initial or resumed message content.
276
+ * @param source - durable fields naming who supplied the accepted message.
277
+ * @param parent - the live direct parent authorizing admission.
278
+ * @param signal - caller cancellation owning admission until acceptance.
279
+ * @returns the accepted inbox message id.
280
+ */
281
+ private submitMaterialized;
282
+ /**
283
+ * Create or resume the child Agent through the private activation-owner
284
+ * scope, install the handle in a fresh Activation, and register ownership on
285
+ * a continuation-managed parent. Rejection leaves no Activation, no handle,
286
+ * and no ownership membership.
287
+ */
288
+ private materialize;
289
+ /**
290
+ * Perform one tracked materialization. The caller keeps the drain barrier
291
+ * registered until this either returns a resident Activation or finishes
292
+ * rollback.
293
+ */
294
+ private materializeTracked;
295
+ /**
296
+ * Release an Activation whose start edge was not published. The memoized
297
+ * transaction remains in the live map until handle disposal settles, so a
298
+ * concurrent drain or delivery observes the same closing boundary.
299
+ */
300
+ private rollbackUnpublished;
301
+ /**
302
+ * Register the child in a continuation-managed parent's owned set before the
303
+ * child can run, so that parent cannot settle while the child is live. A
304
+ * top-level or other non-continuation Agent has no Activation and stays
305
+ * outside the waiting graph.
306
+ */
307
+ private acquireOwnership;
308
+ /** Remove one child from its live owner's set and let that owner re-check settlement. */
309
+ private releaseOwnership;
310
+ /** Let a settlement watcher re-observe quiescence after ownership or inbox changes. */
311
+ private wake;
312
+ /**
313
+ * Submit one message as the child's next FIFO turn and return its accepted
314
+ * inbox id. Acceptance is the operation's success boundary; the manager owns
315
+ * the Activation independently afterwards.
316
+ */
317
+ private submit;
318
+ /**
319
+ * Account one waking send across a resident Activation's settlement window.
320
+ * @param activation - Activation receiving waking inbox work.
321
+ * @param messageId - stable identity of the message about to be sent.
322
+ * @param send - synchronous send that publishes one enqueue occurrence.
323
+ * @returns the accepted message id.
324
+ */
325
+ private admitWaking;
326
+ /**
327
+ * Cross the final admission cutoff and submit without yielding. Signal abort,
328
+ * manager drain, or Activation disposal that wins before this synchronous
329
+ * span rejects without inbox acceptance.
330
+ */
331
+ private submitAdmitted;
332
+ /**
333
+ * Authorize one operation against the durable direct-parent lineage. Other
334
+ * agents, ancestors, teams, workflows, and hosts remain rejected until an
335
+ * explicit authority protocol has a production consumer.
336
+ */
337
+ private authorizeLineage;
338
+ /**
339
+ * Follow one Activation to settlement: wait for Agent quiescence, then for
340
+ * every owned child to complete disposal, and dispose the handle once both
341
+ * hold. A `next-turn` delivered while `waiting` wakes the same Agent and
342
+ * returns it to `running`, so this re-observes rather than settling early.
343
+ */
344
+ private watchSettlement;
345
+ /**
346
+ * Stop one Activation immediately, then release it child-first. The memoized
347
+ * transaction is installed before cancellation or recursive callbacks, so
348
+ * admission and reentrant teardown converge on the same owner.
349
+ *
350
+ * The final session flush is best effort and never prevents handle disposal
351
+ * or ownership release, because retaining a child would permanently pin its
352
+ * ancestors in `waiting`.
353
+ * @param activation - the residency epoch to stop and release.
354
+ * @returns the one disposal transaction owned by this Activation.
355
+ */
356
+ private dispose;
357
+ /**
358
+ * Propagate stop synchronously, then finish the child-first release.
359
+ * @param activation - the Activation whose disposal transaction is installed.
360
+ * @returns once the handle and ownership edge are released.
361
+ */
362
+ private finishDisposal;
363
+ /**
364
+ * Request a best-effort final session flush after the child is quiescent.
365
+ * Listener failure is logged because flush participation cannot identify a
366
+ * particular persistence backend, and teardown must still release ownership.
367
+ * @param activation - the Activation whose final events should be flushed.
368
+ */
369
+ private flushFinalState;
370
+ /** Resolve the persistence service continuable children require, or fail loud. */
371
+ private requirePersistence;
372
+ }
373
+ export type { SubagentDescriptorData };
374
+ export default SubagentContinuationManager;
375
+ //# sourceMappingURL=continuation.d.ts.map