@hydraharness/harness-subagent 0.1.1-rc.5

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/lib/index.js +2743 -0
  4. package/lib/invariant.js +76 -0
  5. package/lib/types/activation-setup-registry.d.ts +57 -0
  6. package/lib/types/activation-setup-registry.js +148 -0
  7. package/lib/types/assistant-output.d.ts +48 -0
  8. package/lib/types/assistant-output.js +72 -0
  9. package/lib/types/budget.d.ts +34 -0
  10. package/lib/types/budget.js +54 -0
  11. package/lib/types/child-agent.d.ts +139 -0
  12. package/lib/types/child-agent.js +169 -0
  13. package/lib/types/client.d.ts +7 -0
  14. package/lib/types/client.js +7 -0
  15. package/lib/types/continuation.d.ts +457 -0
  16. package/lib/types/continuation.js +1157 -0
  17. package/lib/types/depth.d.ts +31 -0
  18. package/lib/types/depth.js +39 -0
  19. package/lib/types/descriptor-seed.d.ts +21 -0
  20. package/lib/types/descriptor-seed.js +24 -0
  21. package/lib/types/descriptor.d.ts +139 -0
  22. package/lib/types/descriptor.js +189 -0
  23. package/lib/types/error.d.ts +11 -0
  24. package/lib/types/error.js +14 -0
  25. package/lib/types/index.d.ts +296 -0
  26. package/lib/types/index.js +374 -0
  27. package/lib/types/invariant.d.ts +13 -0
  28. package/lib/types/invariant.js +91 -0
  29. package/lib/types/lifecycle.d.ts +113 -0
  30. package/lib/types/lifecycle.js +177 -0
  31. package/lib/types/list-children.d.ts +112 -0
  32. package/lib/types/list-children.js +316 -0
  33. package/lib/types/out-of-process.d.ts +117 -0
  34. package/lib/types/out-of-process.js +211 -0
  35. package/lib/types/projection-types.d.ts +60 -0
  36. package/lib/types/projection-types.js +7 -0
  37. package/lib/types/projection.d.ts +95 -0
  38. package/lib/types/projection.js +150 -0
  39. package/lib/types/run-settlement.d.ts +17 -0
  40. package/lib/types/run-settlement.js +66 -0
  41. package/lib/types/types.d.ts +315 -0
  42. package/lib/types/types.js +19 -0
  43. package/package.json +112 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a
3
+ * capability-validating asynchronous start API. Providers establish a
4
+ * child before returning its run, so fulfillment is the single publication and
5
+ * ownership-transfer boundary.
6
+ *
7
+ * Unlike the bash seam (one executor per context, second load throws), MULTIPLE
8
+ * providers coexist here: each registers under a unique name and a caller picks
9
+ * one by name. The shape mirrors the LLM adapter registry
10
+ * (`LlmRuntime.registerAdapter`), not the single-service bash executor.
11
+ *
12
+ * This package owns the Service Definition role of the capability seam. Service Providers
13
+ * (`@hydraharness/harness-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing
14
+ * consumer (`@hydraharness/harness-tool-subagent`) are separate packages.
15
+ *
16
+ * Public operations express caller intent: `start` returns one published owned
17
+ * one-shot run, `startContinuable` establishes a durable continuable child, and
18
+ * `followup` delivers later content without exposing whether the child is
19
+ * resident. Continuable children never become a {@link SubagentRun}: the
20
+ * continuation manager holds their `AgentHandle` directly and orders every turn
21
+ * through the child's own inbox, so providers contribute only the detached
22
+ * creation spec and see no handle, turn, or teardown. Child and descendant
23
+ * discovery read the live session store and optional session persistence
24
+ * directly and do not require that continuation runtime.
25
+ *
26
+ * Same-process providers are trusted typed collaborators. Requests, provider
27
+ * descriptors, results, and lifecycle payloads are borrowed immutable values;
28
+ * serialization and hostile-input validation belong at real process, worker,
29
+ * persistence, and model boundaries.
30
+ *
31
+ * @module @hydraharness/harness-subagent
32
+ */
33
+ import { Context, Service } from '@hydraharness/cordis';
34
+ import z from '@hydraharness/schemastery';
35
+ import { type DelegationLimits } from './budget.ts';
36
+ export { delegationRoot } from './budget.ts';
37
+ export type { DelegationLimits } from './budget.ts';
38
+ import type { Scoped } from '@hydraharness/harness-scope';
39
+ import type { ContentBlock, MessageId } from '@hydraharness/harness-llm';
40
+ import type { Agent } from '@hydraharness/harness-agent';
41
+ import type { SessionId } from '@hydraharness/harness-session';
42
+ import type { SubagentProvider, SubagentRun, SubagentRunEndInfo, SubagentRunInfo, SubagentStartRequest } from './types.ts';
43
+ import type { ContinuableStart, ContinuableStartSpec, SubagentFollowupOptions, SubagentInterruptAuthority, SubagentReportOptions } from './continuation.ts';
44
+ import type { ContinuableSetupContribution } from './activation-setup-registry.ts';
45
+ import type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts';
46
+ export * from './out-of-process.ts';
47
+ export { AssistantOutputFold, finalAssistantOutput } from './assistant-output.ts';
48
+ export { SubagentRunId } from './types.ts';
49
+ export type { ContinuableCreateRequest, ContinuableCreateSpec, ResolvedSubagentStartRequest, SubagentCapabilities, SubagentProvider, SubagentResult, SubagentRun, SubagentStartRequest, SubagentStopReason, SubagentStopReasonMap, } from './types.ts';
50
+ export { foldSubagentDescriptor, snapshotSubagentDescriptor, SUBAGENT_DESCRIPTOR_VERSION, } from './descriptor.ts';
51
+ export type { ContinuableSubagentDescriptorData, ContinuableSubagentDescriptorInput, OneShotSubagentDescriptorData, OneShotSubagentDescriptorInput, SubagentDescriptorData, SubagentDescriptorInput, } from './descriptor.ts';
52
+ export { seedDescriptorTurn } from './descriptor-seed.ts';
53
+ export { SubagentError } from './error.ts';
54
+ export { settleRun } from './run-settlement.ts';
55
+ export { assertSubagentMaxDepth, delegationDepthOf } from './depth.ts';
56
+ export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, SubagentDepthError, } from './child-agent.ts';
57
+ export type { ChildComposition, DelegatedPolicyOverrides } from './child-agent.ts';
58
+ export type { ContinuableStart, ContinuableStartSpec, CoordinatorMessageSource, SubagentFollowupOptions, SubagentInterruptAuthority, SubagentReportDelivery, SubagentReportMessageSource, SubagentReportOptions, SubagentSettledMessageSource, } from './continuation.ts';
59
+ export type { ContinuableSetupContribution } from './activation-setup-registry.ts';
60
+ export type { SubagentDescendantListEntry, SubagentListEntry } from './list-children.ts';
61
+ export type { SubagentRunEndInfo, SubagentRunInfo } from './types.ts';
62
+ export type { SubagentIdentityProjection, SubagentTimingProjection } from './projection-types.ts';
63
+ declare module '@hydraharness/cordis' {
64
+ interface Context {
65
+ subagents: SubagentRuntime;
66
+ }
67
+ interface Events {
68
+ /**
69
+ * A provider became resolvable in the registry.
70
+ * @param provider - the registered provider.
71
+ * @mode emit
72
+ */
73
+ 'subagent/provider-added'(provider: SubagentProvider): void;
74
+ /**
75
+ * A provider left the registry. Accepted runs remain holder-owned.
76
+ * @param name - the provider name that no longer resolves.
77
+ * @mode emit
78
+ */
79
+ 'subagent/provider-removed'(name: string): void;
80
+ /**
81
+ * A provider established a published child. For in-process providers,
82
+ * `ctx.agents.get(info.id)` resolves during this notification.
83
+ * Scope-filtered dispatch keys the carrier by the delegating parent, so a
84
+ * parent-scoped listener observes only its own delegations. Paired with
85
+ * `subagent/end`.
86
+ * @param info - the provider and published child identity.
87
+ * @hydraScopeScan unsupported
88
+ * @mode emit
89
+ */
90
+ 'subagent/start'(this: Scoped<SubagentRuntime>, info: SubagentRunInfo): void;
91
+ /**
92
+ * A published child settled. Scope-filtered dispatch uses the same delegating
93
+ * parent carrier as `subagent/start`, so the lifecycle pair reaches the
94
+ * same scoped audience.
95
+ * @param info - the run identity and terminal outcome.
96
+ * @hydraScopeScan unsupported
97
+ * @mode emit
98
+ */
99
+ 'subagent/end'(this: Scoped<SubagentRuntime>, info: SubagentRunEndInfo): void;
100
+ }
101
+ }
102
+ /** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */
103
+ export declare class SubagentRuntime extends Service {
104
+ private providers;
105
+ private continuations;
106
+ /** Deployment contributions composed into unpublished continuable children. */
107
+ private readonly setupRegistry;
108
+ /**
109
+ * The contained lifecycle-edge publisher. Built here because scoped dispatch
110
+ * keys its carrier by this exact service instance, whose own context filter
111
+ * composes into the carrier.
112
+ */
113
+ private readonly emitLifecycle;
114
+ static Config: z<DelegationLimits>;
115
+ private readonly admit;
116
+ constructor(ctx: Context, config?: DelegationLimits);
117
+ /**
118
+ * Establish one durable continuable child and deliver its initial prompt.
119
+ * Resolves when the child's inbox accepts that prompt, without waiting for the
120
+ * turn to start or for the message to reach the Session log; any earlier
121
+ * failure rejects with no ids and rolls back the child entirely.
122
+ * @param spec - provider, delegation request, and caller cancellation.
123
+ * @returns the durable child id and the accepted prompt's message id.
124
+ * @throws when continuation services are unavailable or materialization fails.
125
+ */
126
+ startContinuable(spec: ContinuableStartSpec): Promise<ContinuableStart>;
127
+ /**
128
+ * Deliver one later message to a continuable child as its next FIFO turn. A
129
+ * resident child's Agent inbox accepts it directly (waking a `waiting`
130
+ * Activation), while an absent one is cold-resumed from its persisted
131
+ * Session. The Agent inbox is the only queue, so every accepted message has
132
+ * one observable order.
133
+ * @param parent - the exact live direct parent authorizing this delivery.
134
+ * @param childId - durable child session id.
135
+ * @param content - user-role content to deliver.
136
+ * @param options - the message source fields and caller cancellation, which stops the
137
+ * operation only before inbox acceptance.
138
+ * @returns the accepted message's inbox id.
139
+ * @throws when continuation services are unavailable, parent authority is
140
+ * rejected, or the message was not admitted.
141
+ */
142
+ followup(parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions): Promise<MessageId>;
143
+ /**
144
+ * Interrupt one live continuable child's current turn under a human parent
145
+ * address or an exact live ancestor Agent. Fire-and-return: the cancel
146
+ * signal is issued before this returns, but the target may keep running
147
+ * until it observes the signal. Unclaimed pending inbox work, the Activation,
148
+ * and published descendants are preserved; claimed work is not requeued.
149
+ * Once the interrupted driver is idle, a waking send resumes the parked FIFO
150
+ * queue. An absent target — including a one-shot or unknown id —
151
+ * is an accepted no-op, as is a manager-less composition, which cannot own a
152
+ * live Activation.
153
+ * @param targetSessionId - the durable child session id to interrupt.
154
+ * @param authority - the human parent address or exact live ancestor Agent.
155
+ * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the
156
+ * live target.
157
+ */
158
+ interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void;
159
+ /**
160
+ * Deliver selected content from one live continuable child to its durable
161
+ * direct parent. The child is the authority credential; callers cannot name a
162
+ * recipient. Reporting does not conclude the child's turn or Activation.
163
+ * @param child - exact live reporting child.
164
+ * @param content - selected model-facing content.
165
+ * @param options - parent scheduling and pre-acceptance cancellation.
166
+ * @returns the stable identity of the parent-accepted message.
167
+ * @throws when continuation services are unavailable, sender authorization
168
+ * fails, or the direct parent is not live.
169
+ */
170
+ reportFrom(child: Agent, content: ContentBlock[], options: SubagentReportOptions): Promise<MessageId>;
171
+ /**
172
+ * Compose one deployment capability into every continuable child's
173
+ * unpublished creation context on fresh creation and cold resume. Grants wait
174
+ * for the next Activation; removing the contribution revokes every resident
175
+ * installation immediately.
176
+ * @param contribution - synchronous child-scope installer.
177
+ * @returns the exact Cordis effect disposer.
178
+ */
179
+ registerContinuableSetup(contribution: ContinuableSetupContribution): () => void;
180
+ /**
181
+ * Close continuable admission below exact live parent Agents, stop only their
182
+ * visible descendant Activations synchronously, then await admitted scoped
183
+ * materializations and release those forests child-first. The scoped cutoff
184
+ * lasts until each exact parent leaves the registry; unrelated parent trees
185
+ * remain live.
186
+ * @param parents - exact host-owned parent Agents entering teardown.
187
+ * @returns once every retained descendant Activation released its `AgentHandle`.
188
+ * @throws an aggregate error after all branches settle when any failed.
189
+ */
190
+ drainContinuableDescendants(parents: readonly Agent[]): Promise<void>;
191
+ /**
192
+ * Release selected resident continuable direct children of one exact live
193
+ * parent. Other children of the same parent remain admitted and resident.
194
+ * Absent targets and a manager-less composition are accepted no-ops.
195
+ * @param parent - exact live direct parent authorizing the selected release.
196
+ * @param childIds - durable direct-child ids to release when resident.
197
+ * @returns once every selected Activation released its `AgentHandle`.
198
+ * @throws {SubagentError} `UNAUTHORIZED` when a resident target belongs to a
199
+ * different parent or the supplied parent identity is stale.
200
+ */
201
+ drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise<void>;
202
+ /**
203
+ * Enumerate the parent's direct session-backed subagents without loading or
204
+ * resuming an Agent and without any query service: the listing merges the live
205
+ * session store with optional session persistence (live-preferred) and
206
+ * serves each child's durable mode/label from the registered `subagent`
207
+ * projection unit down a three-rung ladder — the registry's watermark
208
+ * snapshot for a live child; for a cold one, a durable projection-cache
209
+ * row when the optional cache serves an own-suffix identity (its `seq`
210
+ * gate proves the value postdates the fork seed, where a child's own
211
+ * descriptor is immutable once appended), else one persistence inspection
212
+ * folded through the registry. The
213
+ * projection fold is the single classification authority; per-child
214
+ * diagnostics relay a fold that served no identity or a failed inspection,
215
+ * never a list-time descriptor parse. Absent persistence, enumeration is
216
+ * live-only (a cold child cannot be resumed then either, so its absence is
217
+ * capability absence, not an error). This service consults no Agent
218
+ * registrations, Activations, or providers.
219
+ *
220
+ * Every persistence read receives `signal`, and the listing rechecks
221
+ * cancellation around each of those awaits. Read rejections that settle
222
+ * after an abort become a stable `SubagentError` with code `CANCELLED`.
223
+ * @param parentSessionId - parent session whose direct children are listed.
224
+ * @param signal - caller-owned cancellation forwarded to persistence reads
225
+ * and observed around every read await.
226
+ * @returns children and per-child diagnostics ordered by `createdAt`, then id.
227
+ * @throws {@link SubagentError} when the projection registry or the session
228
+ * store is not mounted, or the caller cancels the listing.
229
+ */
230
+ listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise<SubagentListEntry[]>;
231
+ /**
232
+ * Enumerate the root's complete session-backed subagent tree in stable
233
+ * pre-order from one live-preferred corpus, without loading or resuming an
234
+ * Agent. Ordinary sessions and one-shot children remain traversal nodes so
235
+ * continuable descendants below them are discovered; each returned entry
236
+ * adds its durable `parentId` and root-relative `depth`. Identity resolution,
237
+ * diagnostics, optional persistence, and cancellation follow the same
238
+ * projection-backed contract as {@link listChildren}.
239
+ * @param rootSessionId - session whose complete descendant tree is listed.
240
+ * @param signal - caller-owned cancellation forwarded to persistence reads
241
+ * and observed around every read await.
242
+ * @returns children and per-candidate diagnostics with tree position, in
243
+ * stable pre-order.
244
+ * @throws {@link SubagentError} under the same conditions as {@link listChildren}.
245
+ */
246
+ listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise<SubagentDescendantListEntry[]>;
247
+ /**
248
+ * Register a provider under its name. Registration is effect-scoped and HMR
249
+ * safe; removing a provider blocks new starts but does not revoke runs that
250
+ * were already returned to their holders.
251
+ * @param provider - the trusted provider implementation.
252
+ * @returns the exact Cordis effect disposer.
253
+ */
254
+ registerProvider(provider: SubagentProvider): () => void;
255
+ /**
256
+ * Look up a provider by name.
257
+ * @param name - the provider name.
258
+ * @returns the provider, or undefined when absent.
259
+ */
260
+ getProvider(name: string): SubagentProvider | undefined;
261
+ /**
262
+ * List registered provider names in insertion order.
263
+ * @returns the registered names.
264
+ */
265
+ list(): string[];
266
+ /**
267
+ * Establish a published child on the named provider. Capability and semantic
268
+ * checks run before delegation. Provider ownership lasts until its promise
269
+ * fulfills; a rejection therefore has no run for the caller to dispose and
270
+ * emits no run lifecycle events. Post-publication turn and infrastructure
271
+ * failures settle through the returned run.
272
+ * @param name - the provider to use.
273
+ * @param request - child label, prompt, parent, signal, and optional capabilities.
274
+ * @returns the published holder-owned run.
275
+ */
276
+ start(name: string, request: SubagentStartRequest): Promise<SubagentRun>;
277
+ /**
278
+ * Resolve one provider's detached continuable-creation contribution. Method
279
+ * presence on the provider IS the capability, so a provider without it is
280
+ * rejected before the manager reserves any child resources.
281
+ */
282
+ private prepareContinuable;
283
+ /** Look up a provider for dispatch or fail loud. */
284
+ private expectProvider;
285
+ /** Resolve the optional continuable-subagent manager or fail loud. */
286
+ private requireContinuations;
287
+ /**
288
+ * Build the lifecycle observer for one continuable Activation's residency
289
+ * epoch, so the manager publishes its edges without owning event dispatch.
290
+ */
291
+ private observeActivation;
292
+ /** Reject the first requested capability that the provider lacks. */
293
+ private assertCapabilities;
294
+ }
295
+ export default SubagentRuntime;
296
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a
3
+ * capability-validating asynchronous start API. Providers establish a
4
+ * child before returning its run, so fulfillment is the single publication and
5
+ * ownership-transfer boundary.
6
+ *
7
+ * Unlike the bash seam (one executor per context, second load throws), MULTIPLE
8
+ * providers coexist here: each registers under a unique name and a caller picks
9
+ * one by name. The shape mirrors the LLM adapter registry
10
+ * (`LlmRuntime.registerAdapter`), not the single-service bash executor.
11
+ *
12
+ * This package owns the Service Definition role of the capability seam. Service Providers
13
+ * (`@hydraharness/harness-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing
14
+ * consumer (`@hydraharness/harness-tool-subagent`) are separate packages.
15
+ *
16
+ * Public operations express caller intent: `start` returns one published owned
17
+ * one-shot run, `startContinuable` establishes a durable continuable child, and
18
+ * `followup` delivers later content without exposing whether the child is
19
+ * resident. Continuable children never become a {@link SubagentRun}: the
20
+ * continuation manager holds their `AgentHandle` directly and orders every turn
21
+ * through the child's own inbox, so providers contribute only the detached
22
+ * creation spec and see no handle, turn, or teardown. Child and descendant
23
+ * discovery read the live session store and optional session persistence
24
+ * directly and do not require that continuation runtime.
25
+ *
26
+ * Same-process providers are trusted typed collaborators. Requests, provider
27
+ * descriptors, results, and lifecycle payloads are borrowed immutable values;
28
+ * serialization and hostile-input validation belong at real process, worker,
29
+ * persistence, and model boundaries.
30
+ *
31
+ * @module @hydraharness/harness-subagent
32
+ */
33
+ import { Service } from '@hydraharness/cordis';
34
+ import z from '@hydraharness/schemastery';
35
+ import { delegationAdmission } from "./budget.js";
36
+ export { delegationRoot } from "./budget.js";
37
+ import { scopeTarget } from '@hydraharness/harness-scope';
38
+ import { assertObjectJsonSchema } from '@hydraharness/harness-tools';
39
+ import { SubagentError } from "./error.js";
40
+ import { assertSubagentMaxDepth } from "./depth.js";
41
+ import { createActivationObserver, createLifecycleEmitter, observeRun } from "./lifecycle.js";
42
+ import SubagentContinuationManager from "./continuation.js";
43
+ import SubagentActivationSetupRegistry from "./activation-setup-registry.js";
44
+ import { listChildren as listSubagentChildren, listDescendants as listSubagentDescendants } from "./list-children.js";
45
+ import { snapshotSubagentDescriptor } from "./descriptor.js";
46
+ import { subagentIdentityProjectionDefinition, subagentTimingProjectionDefinition } from "./projection.js";
47
+ export * from "./out-of-process.js";
48
+ export { AssistantOutputFold, finalAssistantOutput } from "./assistant-output.js";
49
+ export { SubagentRunId } from "./types.js";
50
+ export { foldSubagentDescriptor, snapshotSubagentDescriptor, SUBAGENT_DESCRIPTOR_VERSION, } from "./descriptor.js";
51
+ export { seedDescriptorTurn } from "./descriptor-seed.js";
52
+ export { SubagentError } from "./error.js";
53
+ export { settleRun } from "./run-settlement.js";
54
+ export { assertSubagentMaxDepth, delegationDepthOf } from "./depth.js";
55
+ export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegatedPolicyOverrides, childSessionMeta, resolveChildAgentOptions, resolveChildDepth, SubagentDepthError, } from "./child-agent.js";
56
+ /** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */
57
+ export class SubagentRuntime extends Service {
58
+ providers = new Map();
59
+ continuations;
60
+ /** Deployment contributions composed into unpublished continuable children. */
61
+ setupRegistry = new SubagentActivationSetupRegistry();
62
+ /**
63
+ * The contained lifecycle-edge publisher. Built here because scoped dispatch
64
+ * keys its carrier by this exact service instance, whose own context filter
65
+ * composes into the carrier.
66
+ */
67
+ emitLifecycle;
68
+ static Config = z.object({
69
+ maxActivePerTree: z.number(),
70
+ maxChildrenPerTree: z.number(),
71
+ });
72
+ admit;
73
+ constructor(ctx, config = {}) {
74
+ super(ctx, 'subagents');
75
+ this.admit = delegationAdmission(ctx, config);
76
+ this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent));
77
+ ctx.inject(['agents'], (childCtx) => {
78
+ const manager = new SubagentContinuationManager(childCtx, {
79
+ admit: this.admit,
80
+ prepareContinuable: (name, request) => this.prepareContinuable(name, request),
81
+ observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent),
82
+ }, this.setupRegistry);
83
+ this.continuations = manager;
84
+ childCtx.effect(() => () => {
85
+ /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
86
+ if (this.continuations === manager)
87
+ this.continuations = undefined;
88
+ }, 'subagents.continuationBinding()');
89
+ });
90
+ ctx.inject(['sessionProjections'], (projectionCtx) => {
91
+ projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
92
+ projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
93
+ });
94
+ }
95
+ /**
96
+ * Establish one durable continuable child and deliver its initial prompt.
97
+ * Resolves when the child's inbox accepts that prompt, without waiting for the
98
+ * turn to start or for the message to reach the Session log; any earlier
99
+ * failure rejects with no ids and rolls back the child entirely.
100
+ * @param spec - provider, delegation request, and caller cancellation.
101
+ * @returns the durable child id and the accepted prompt's message id.
102
+ * @throws when continuation services are unavailable or materialization fails.
103
+ */
104
+ async startContinuable(spec) {
105
+ return this.requireContinuations().startContinuable(spec);
106
+ }
107
+ /**
108
+ * Deliver one later message to a continuable child as its next FIFO turn. A
109
+ * resident child's Agent inbox accepts it directly (waking a `waiting`
110
+ * Activation), while an absent one is cold-resumed from its persisted
111
+ * Session. The Agent inbox is the only queue, so every accepted message has
112
+ * one observable order.
113
+ * @param parent - the exact live direct parent authorizing this delivery.
114
+ * @param childId - durable child session id.
115
+ * @param content - user-role content to deliver.
116
+ * @param options - the message source fields and caller cancellation, which stops the
117
+ * operation only before inbox acceptance.
118
+ * @returns the accepted message's inbox id.
119
+ * @throws when continuation services are unavailable, parent authority is
120
+ * rejected, or the message was not admitted.
121
+ */
122
+ async followup(parent, childId, content, options) {
123
+ return this.requireContinuations().followup(parent, childId, content, options);
124
+ }
125
+ /**
126
+ * Interrupt one live continuable child's current turn under a human parent
127
+ * address or an exact live ancestor Agent. Fire-and-return: the cancel
128
+ * signal is issued before this returns, but the target may keep running
129
+ * until it observes the signal. Unclaimed pending inbox work, the Activation,
130
+ * and published descendants are preserved; claimed work is not requeued.
131
+ * Once the interrupted driver is idle, a waking send resumes the parked FIFO
132
+ * queue. An absent target — including a one-shot or unknown id —
133
+ * is an accepted no-op, as is a manager-less composition, which cannot own a
134
+ * live Activation.
135
+ * @param targetSessionId - the durable child session id to interrupt.
136
+ * @param authority - the human parent address or exact live ancestor Agent.
137
+ * @throws {SubagentError} `UNAUTHORIZED` when the authority does not own the
138
+ * live target.
139
+ */
140
+ interrupt(targetSessionId, authority) {
141
+ this.continuations?.interrupt(targetSessionId, authority);
142
+ }
143
+ /**
144
+ * Deliver selected content from one live continuable child to its durable
145
+ * direct parent. The child is the authority credential; callers cannot name a
146
+ * recipient. Reporting does not conclude the child's turn or Activation.
147
+ * @param child - exact live reporting child.
148
+ * @param content - selected model-facing content.
149
+ * @param options - parent scheduling and pre-acceptance cancellation.
150
+ * @returns the stable identity of the parent-accepted message.
151
+ * @throws when continuation services are unavailable, sender authorization
152
+ * fails, or the direct parent is not live.
153
+ */
154
+ async reportFrom(child, content, options) {
155
+ return this.requireContinuations().reportFrom(child, content, options);
156
+ }
157
+ /**
158
+ * Compose one deployment capability into every continuable child's
159
+ * unpublished creation context on fresh creation and cold resume. Grants wait
160
+ * for the next Activation; removing the contribution revokes every resident
161
+ * installation immediately.
162
+ * @param contribution - synchronous child-scope installer.
163
+ * @returns the exact Cordis effect disposer.
164
+ */
165
+ registerContinuableSetup(contribution) {
166
+ // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
167
+ return this.ctx.effect(() => this.setupRegistry.register(contribution), 'subagents.registerContinuableSetup()');
168
+ }
169
+ /**
170
+ * Close continuable admission below exact live parent Agents, stop only their
171
+ * visible descendant Activations synchronously, then await admitted scoped
172
+ * materializations and release those forests child-first. The scoped cutoff
173
+ * lasts until each exact parent leaves the registry; unrelated parent trees
174
+ * remain live.
175
+ * @param parents - exact host-owned parent Agents entering teardown.
176
+ * @returns once every retained descendant Activation released its `AgentHandle`.
177
+ * @throws an aggregate error after all branches settle when any failed.
178
+ */
179
+ async drainContinuableDescendants(parents) {
180
+ const manager = this.continuations;
181
+ // Absent continuation services means nothing was ever materialized.
182
+ if (manager === undefined)
183
+ return;
184
+ await manager.drainDescendants(parents);
185
+ }
186
+ /**
187
+ * Release selected resident continuable direct children of one exact live
188
+ * parent. Other children of the same parent remain admitted and resident.
189
+ * Absent targets and a manager-less composition are accepted no-ops.
190
+ * @param parent - exact live direct parent authorizing the selected release.
191
+ * @param childIds - durable direct-child ids to release when resident.
192
+ * @returns once every selected Activation released its `AgentHandle`.
193
+ * @throws {SubagentError} `UNAUTHORIZED` when a resident target belongs to a
194
+ * different parent or the supplied parent identity is stale.
195
+ */
196
+ async drainContinuableChildren(parent, childIds) {
197
+ const manager = this.continuations;
198
+ if (manager === undefined)
199
+ return;
200
+ await manager.drainChildren(parent, childIds);
201
+ }
202
+ /**
203
+ * Enumerate the parent's direct session-backed subagents without loading or
204
+ * resuming an Agent and without any query service: the listing merges the live
205
+ * session store with optional session persistence (live-preferred) and
206
+ * serves each child's durable mode/label from the registered `subagent`
207
+ * projection unit down a three-rung ladder — the registry's watermark
208
+ * snapshot for a live child; for a cold one, a durable projection-cache
209
+ * row when the optional cache serves an own-suffix identity (its `seq`
210
+ * gate proves the value postdates the fork seed, where a child's own
211
+ * descriptor is immutable once appended), else one persistence inspection
212
+ * folded through the registry. The
213
+ * projection fold is the single classification authority; per-child
214
+ * diagnostics relay a fold that served no identity or a failed inspection,
215
+ * never a list-time descriptor parse. Absent persistence, enumeration is
216
+ * live-only (a cold child cannot be resumed then either, so its absence is
217
+ * capability absence, not an error). This service consults no Agent
218
+ * registrations, Activations, or providers.
219
+ *
220
+ * Every persistence read receives `signal`, and the listing rechecks
221
+ * cancellation around each of those awaits. Read rejections that settle
222
+ * after an abort become a stable `SubagentError` with code `CANCELLED`.
223
+ * @param parentSessionId - parent session whose direct children are listed.
224
+ * @param signal - caller-owned cancellation forwarded to persistence reads
225
+ * and observed around every read await.
226
+ * @returns children and per-child diagnostics ordered by `createdAt`, then id.
227
+ * @throws {@link SubagentError} when the projection registry or the session
228
+ * store is not mounted, or the caller cancels the listing.
229
+ */
230
+ listChildren(parentSessionId, signal) {
231
+ return listSubagentChildren(this.ctx, parentSessionId, signal);
232
+ }
233
+ /**
234
+ * Enumerate the root's complete session-backed subagent tree in stable
235
+ * pre-order from one live-preferred corpus, without loading or resuming an
236
+ * Agent. Ordinary sessions and one-shot children remain traversal nodes so
237
+ * continuable descendants below them are discovered; each returned entry
238
+ * adds its durable `parentId` and root-relative `depth`. Identity resolution,
239
+ * diagnostics, optional persistence, and cancellation follow the same
240
+ * projection-backed contract as {@link listChildren}.
241
+ * @param rootSessionId - session whose complete descendant tree is listed.
242
+ * @param signal - caller-owned cancellation forwarded to persistence reads
243
+ * and observed around every read await.
244
+ * @returns children and per-candidate diagnostics with tree position, in
245
+ * stable pre-order.
246
+ * @throws {@link SubagentError} under the same conditions as {@link listChildren}.
247
+ */
248
+ listDescendants(rootSessionId, signal) {
249
+ return listSubagentDescendants(this.ctx, rootSessionId, signal);
250
+ }
251
+ /**
252
+ * Register a provider under its name. Registration is effect-scoped and HMR
253
+ * safe; removing a provider blocks new starts but does not revoke runs that
254
+ * were already returned to their holders.
255
+ * @param provider - the trusted provider implementation.
256
+ * @returns the exact Cordis effect disposer.
257
+ */
258
+ registerProvider(provider) {
259
+ const name = provider.name;
260
+ // oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
261
+ return this.ctx.effect(function* () {
262
+ if (this.providers.has(name)) {
263
+ throw new SubagentError(`a subagent provider named "${name}" is already registered`, 'DUPLICATE_PROVIDER');
264
+ }
265
+ this.providers.set(name, provider);
266
+ yield () => {
267
+ this.providers.delete(name);
268
+ this.emitLifecycle('subagent/provider-removed', name);
269
+ };
270
+ // A throwing added-listener unwinds the yielded rollback, matching the
271
+ // repository's fail-loud registration semantics.
272
+ this.ctx.emit('subagent/provider-added', provider);
273
+ }.bind(this), 'subagents.registerProvider()');
274
+ }
275
+ /**
276
+ * Look up a provider by name.
277
+ * @param name - the provider name.
278
+ * @returns the provider, or undefined when absent.
279
+ */
280
+ getProvider(name) {
281
+ return this.providers.get(name);
282
+ }
283
+ /**
284
+ * List registered provider names in insertion order.
285
+ * @returns the registered names.
286
+ */
287
+ list() {
288
+ return [...this.providers.keys()];
289
+ }
290
+ /**
291
+ * Establish a published child on the named provider. Capability and semantic
292
+ * checks run before delegation. Provider ownership lasts until its promise
293
+ * fulfills; a rejection therefore has no run for the caller to dispose and
294
+ * emits no run lifecycle events. Post-publication turn and infrastructure
295
+ * failures settle through the returned run.
296
+ * @param name - the provider to use.
297
+ * @param request - child label, prompt, parent, signal, and optional capabilities.
298
+ * @returns the published holder-owned run.
299
+ */
300
+ async start(name, request) {
301
+ const provider = this.expectProvider(name);
302
+ this.assertCapabilities(provider, request);
303
+ assertSubagentMaxDepth(request.maxDepth);
304
+ if (request.outputSchema !== undefined)
305
+ assertObjectJsonSchema(request.outputSchema);
306
+ const descriptor = snapshotSubagentDescriptor({
307
+ mode: 'one-shot',
308
+ provider: name,
309
+ ...request.label !== undefined ? { label: request.label } : {},
310
+ });
311
+ const resolved = { ...request, descriptor };
312
+ const release = this.admit(request.parent, true);
313
+ try {
314
+ const run = await provider.start(resolved);
315
+ void run.result.then(release, release);
316
+ return observeRun(this.emitLifecycle, name, request.parent, run);
317
+ }
318
+ catch (error) {
319
+ release();
320
+ throw error;
321
+ }
322
+ }
323
+ /**
324
+ * Resolve one provider's detached continuable-creation contribution. Method
325
+ * presence on the provider IS the capability, so a provider without it is
326
+ * rejected before the manager reserves any child resources.
327
+ */
328
+ async prepareContinuable(name, request) {
329
+ const provider = this.expectProvider(name);
330
+ if (provider.prepareContinuable === undefined) {
331
+ throw new SubagentError(`subagent provider "${provider.name}" does not support continuable children `
332
+ + '(no prepareContinuable capability)', 'UNSUPPORTED_CAPABILITY');
333
+ }
334
+ return provider.prepareContinuable(request);
335
+ }
336
+ /** Look up a provider for dispatch or fail loud. */
337
+ expectProvider(name) {
338
+ const provider = this.providers.get(name);
339
+ if (provider === undefined) {
340
+ throw new SubagentError(`no subagent provider registered for "${name}"`, 'NO_PROVIDER');
341
+ }
342
+ return provider;
343
+ }
344
+ /** Resolve the optional continuable-subagent manager or fail loud. */
345
+ requireContinuations() {
346
+ if (this.continuations === undefined) {
347
+ throw new SubagentError('continuable subagents require the agents service', 'CONTINUATION_UNAVAILABLE');
348
+ }
349
+ return this.continuations;
350
+ }
351
+ /**
352
+ * Build the lifecycle observer for one continuable Activation's residency
353
+ * epoch, so the manager publishes its edges without owning event dispatch.
354
+ */
355
+ observeActivation(provider, childId, parent) {
356
+ return createActivationObserver(this.emitLifecycle, provider, childId, parent);
357
+ }
358
+ /** Reject the first requested capability that the provider lacks. */
359
+ assertCapabilities(provider, request) {
360
+ const needs = [
361
+ { when: request.outputSchema !== undefined, cap: 'outputSchema' },
362
+ { when: request.maxDepth !== undefined, cap: 'depthLimit' },
363
+ { when: request.toolFilter !== undefined, cap: 'toolFilter' },
364
+ { when: request.persona !== undefined, cap: 'persona' },
365
+ ];
366
+ for (const { when, cap } of needs) {
367
+ if (when && !provider.capabilities[cap]) {
368
+ throw new SubagentError(`subagent provider "${provider.name}" does not support the "${cap}" capability`, 'UNSUPPORTED_CAPABILITY');
369
+ }
370
+ }
371
+ }
372
+ }
373
+ export default SubagentRuntime;
374
+ //# sourceMappingURL=index.js.map