@morlay/dsh-subagent 0.0.9 → 0.0.10

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/src/index.ts CHANGED
@@ -27,32 +27,36 @@
27
27
  *
28
28
  * @module @deepseek-ai/dsh-subagent
29
29
  */
30
- import type { Volatile } from '@deepseek-ai/cordis'
30
+ import type { Volatile } from "@deepseek-ai/cordis";
31
31
 
32
- import { Context } from '@deepseek-ai/cordis'
33
- import z from '@deepseek-ai/schemastery'
34
- import type {} from '@deepseek-ai/dsh-working-directory'
35
- import type {} from '@deepseek-ai/dsh-attachment'
36
- import { scopeTarget } from '@deepseek-ai/dsh-scope'
37
- import type {} from '@deepseek-ai/dsh-subagent'
32
+ import { Context } from "@deepseek-ai/cordis";
33
+ import z from "@deepseek-ai/schemastery";
34
+ import type {} from "@deepseek-ai/dsh-working-directory";
35
+ import type {} from "@deepseek-ai/dsh-attachment";
36
+ import { scopeTarget } from "@deepseek-ai/dsh-scope";
37
+ import type {} from "@deepseek-ai/dsh-subagent";
38
38
  // 服务面声明(`ctx.agentPresets`)由它给:回报指引按会话挂的 preset 选文案。
39
- import type {} from '@deepseek-ai/dsh-agent-preset-registry'
40
- import { assertObjectJsonSchema } from '@deepseek-ai/dsh-tools'
41
- import type { ContentBlock, MessageId, MessageSource } from '@deepseek-ai/dsh-llm'
42
- import type { Agent } from '@deepseek-ai/dsh-agent'
43
- import type { SessionId } from '@deepseek-ai/dsh-session'
44
- import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time'
45
- import { Remote, RemoteError, TypertRemoteService, principalOf, type Principal } from '@deepseek-ai/dsh-typert-protocol'
39
+ import type {} from "@deepseek-ai/dsh-agent-preset-registry";
40
+ import { assertObjectJsonSchema } from "@deepseek-ai/dsh-tools";
41
+ import type { ContentBlock, MessageId, MessageSource } from "@deepseek-ai/dsh-llm";
42
+ import type { Agent } from "@deepseek-ai/dsh-agent";
43
+ import type { SessionId } from "@deepseek-ai/dsh-session";
44
+ import { canonicalClientTimeZone } from "@deepseek-ai/dsh-util-time";
46
45
  import {
47
- rejectPrompt, validateControlRequest,
48
- } from './vendor/dsh-subagent/control.ts'
46
+ Remote,
47
+ RemoteError,
48
+ TypertRemoteService,
49
+ principalOf,
50
+ type Principal,
51
+ } from "@deepseek-ai/dsh-typert-protocol";
52
+ import { rejectPrompt, validateControlRequest } from "./vendor/dsh-subagent/control.ts";
49
53
  import type {
50
54
  SubagentDelivery,
51
55
  SubagentInterruptReceipt,
52
56
  SubagentPromptReceipt,
53
57
  SubagentPromptRequest,
54
58
  SubagentPromptRequestId,
55
- } from './vendor/dsh-subagent/control-types.ts'
59
+ } from "./vendor/dsh-subagent/control-types.ts";
56
60
  import type {
57
61
  ContinuableCreateRequest,
58
62
  ContinuableCreateSpec,
@@ -63,25 +67,37 @@ import type {
63
67
  SubagentProvider,
64
68
  SubagentSendMessageOptions,
65
69
  SubagentStartRequest,
66
- } from './vendor/dsh-subagent/types.ts'
67
- import { SubagentError } from './vendor/dsh-subagent/error.ts'
68
- import { assertSubagentMaxDepth } from './vendor/dsh-subagent/depth.ts'
69
- import { createActivationObserver, createLifecycleEmitter } from './vendor/dsh-subagent/lifecycle.ts'
70
- import type { ActivationObserver, LifecycleEmitter } from './vendor/dsh-subagent/lifecycle.ts'
71
- import SubagentManager from './manager.ts'
72
- import { installDelegationContext } from './delegation-context.ts'
73
- import { listChildren as listSubagentChildren, listDescendants as listSubagentDescendants } from './vendor/dsh-subagent/list-children.ts'
74
- import type { SubagentDescendantListEntry } from './vendor/dsh-subagent/list-children.ts'
75
- import { installSubagentArchiveAdmission } from './vendor/dsh-subagent/archive-admission.ts'
76
- import type { SubagentCatalogEntry } from './vendor/dsh-subagent/projection-types.ts'
77
- import { subagentIdentityProjectionDefinition, subagentTimingProjectionDefinition } from './vendor/dsh-subagent/projection.ts'
78
- import { subagentCatalogProjectionDefinition } from './vendor/dsh-subagent/catalog.ts'
79
- import { deliverSubagentPrompt } from './vendor/dsh-subagent/internal.ts'
70
+ } from "./vendor/dsh-subagent/types.ts";
71
+ import { SubagentError } from "./vendor/dsh-subagent/error.ts";
72
+ import { assertSubagentMaxDepth } from "./vendor/dsh-subagent/depth.ts";
73
+ import {
74
+ createActivationObserver,
75
+ createLifecycleEmitter,
76
+ } from "./vendor/dsh-subagent/lifecycle.ts";
77
+ import type { ActivationObserver, LifecycleEmitter } from "./vendor/dsh-subagent/lifecycle.ts";
78
+ import SubagentManager from "./manager.ts";
79
+ import { installDelegationContext } from "./delegation-context.ts";
80
+ import {
81
+ listChildren as listSubagentChildren,
82
+ listDescendants as listSubagentDescendants,
83
+ } from "./vendor/dsh-subagent/list-children.ts";
84
+ import type { SubagentDescendantListEntry } from "./vendor/dsh-subagent/list-children.ts";
85
+ import { installSubagentArchiveAdmission } from "./vendor/dsh-subagent/archive-admission.ts";
86
+ import type { SubagentCatalogEntry } from "./vendor/dsh-subagent/projection-types.ts";
87
+ import {
88
+ subagentIdentityProjectionDefinition,
89
+ subagentTimingProjectionDefinition,
90
+ } from "./vendor/dsh-subagent/projection.ts";
91
+ import { subagentCatalogProjectionDefinition } from "./vendor/dsh-subagent/catalog.ts";
92
+ import { deliverSubagentPrompt } from "./vendor/dsh-subagent/internal.ts";
80
93
 
81
- export type {} from './vendor/dsh-subagent/catalog.ts'
82
- export * from './vendor/dsh-subagent/out-of-process.ts'
83
- export { AssistantOutputFold, finalAssistantOutput } from './vendor/dsh-subagent/assistant-output.ts'
84
- export { SubagentRunId } from './vendor/dsh-subagent/types.ts'
94
+ export type {} from "./vendor/dsh-subagent/catalog.ts";
95
+ export * from "./vendor/dsh-subagent/out-of-process.ts";
96
+ export {
97
+ AssistantOutputFold,
98
+ finalAssistantOutput,
99
+ } from "./vendor/dsh-subagent/assistant-output.ts";
100
+ export { SubagentRunId } from "./vendor/dsh-subagent/types.ts";
85
101
  export type {
86
102
  ContinuableCreateRequest,
87
103
  ContinuableCreateSpec,
@@ -97,21 +113,21 @@ export type {
97
113
  ResolvedSubagentStartRequest,
98
114
  SubagentStopReason,
99
115
  SubagentStopReasonMap,
100
- } from './vendor/dsh-subagent/types.ts'
116
+ } from "./vendor/dsh-subagent/types.ts";
101
117
  export {
102
118
  foldSubagentDescriptor,
103
119
  snapshotSubagentDescriptor,
104
120
  SUBAGENT_DESCRIPTOR_VERSION,
105
- } from './vendor/dsh-subagent/descriptor.ts'
121
+ } from "./vendor/dsh-subagent/descriptor.ts";
106
122
  export type {
107
123
  ContinuableSubagentDescriptorData,
108
124
  ContinuableSubagentDescriptorInput,
109
125
  OneShotSubagentDescriptorData,
110
126
  SubagentDescriptorData,
111
- } from './vendor/dsh-subagent/descriptor.ts'
112
- export { STRUCTURED_OUTPUT_TOOL } from './vendor/dsh-subagent/structured.ts'
113
- export { SubagentError } from './vendor/dsh-subagent/error.ts'
114
- export { assertSubagentMaxDepth, delegationDepthOf } from './vendor/dsh-subagent/depth.ts'
127
+ } from "./vendor/dsh-subagent/descriptor.ts";
128
+ export { STRUCTURED_OUTPUT_TOOL } from "./vendor/dsh-subagent/structured.ts";
129
+ export { SubagentError } from "./vendor/dsh-subagent/error.ts";
130
+ export { assertSubagentMaxDepth, delegationDepthOf } from "./vendor/dsh-subagent/depth.ts";
115
131
  export {
116
132
  appendDelegatedPolicyOverrides,
117
133
  applyChildComposition,
@@ -121,13 +137,20 @@ export {
121
137
  resolveChildAgentOptions,
122
138
  resolveChildDepth,
123
139
  SubagentDepthError,
124
- } from './vendor/dsh-subagent/child-agent.ts'
125
- export type { ChildComposition, DelegatedPolicyOverrides } from './vendor/dsh-subagent/child-agent.ts'
126
- export type { AgentMessageSource, SubagentSettledMessageSource } from './continuation-messages.ts'
127
- export type * from './vendor/dsh-subagent/control-types.ts'
128
- export type { SubagentDescendantListEntry } from './vendor/dsh-subagent/list-children.ts'
129
- export type { SubagentRunEndInfo, SubagentRunInfo } from './vendor/dsh-subagent/types.ts'
130
- export type { SubagentCatalogEntry, SubagentIdentityProjection, SubagentTimingProjection } from './vendor/dsh-subagent/projection-types.ts'
140
+ } from "./vendor/dsh-subagent/child-agent.ts";
141
+ export type {
142
+ ChildComposition,
143
+ DelegatedPolicyOverrides,
144
+ } from "./vendor/dsh-subagent/child-agent.ts";
145
+ export type { AgentMessageSource, SubagentSettledMessageSource } from "./continuation-messages.ts";
146
+ export type * from "./vendor/dsh-subagent/control-types.ts";
147
+ export type { SubagentDescendantListEntry } from "./vendor/dsh-subagent/list-children.ts";
148
+ export type { SubagentRunEndInfo, SubagentRunInfo } from "./vendor/dsh-subagent/types.ts";
149
+ export type {
150
+ SubagentCatalogEntry,
151
+ SubagentIdentityProjection,
152
+ SubagentTimingProjection,
153
+ } from "./vendor/dsh-subagent/projection-types.ts";
131
154
 
132
155
  /**
133
156
  * Durable attribution of one browser-authored follow-up. The Session
@@ -137,73 +160,94 @@ export type { SubagentCatalogEntry, SubagentIdentityProjection, SubagentTimingPr
137
160
  * Client reconciles its optimistic prompt against.
138
161
  */
139
162
  interface BrowserPromptSource {
140
- readonly kind: 'user'
141
- readonly rpcId: SubagentPromptRequestId
142
- readonly clientTimeZone?: string
163
+ readonly kind: "user";
164
+ readonly rpcId: SubagentPromptRequestId;
165
+ readonly clientTimeZone?: string;
143
166
  /** Caller that submitted this follow-up, written only when it is not the owner; absent means the owner. */
144
- readonly principal?: Principal
167
+ readonly principal?: Principal;
145
168
  }
146
169
 
147
170
  /** Host configuration for continuable subagent capacity. */
148
171
  export interface Config {
149
172
  /** Maximum live children sharing uninterrupted continuable parent links; defaults to 8. */
150
- maxActiveSubagents: Volatile<number>
173
+ maxActiveSubagents: Volatile<number>;
151
174
  /** Default delegation depth for tools without an explicit limit; defaults to 1. */
152
- maxDepth: Volatile<number>
175
+ maxDepth: Volatile<number>;
153
176
  /**
154
177
  * Preset ids the Chinese return guidance is restricted to; empty (default) means no restriction.
155
178
  *
156
179
  * 不配 = 任意 preset 的会话都用本包的中文回报指引(官方四个 shipped preset 也在内,还有还没绑 preset 的会话)。
157
180
  * 要反过来只让某几份 preset 用中文,就在这里列出来。装配面,不是用户面——所以不进设置页(`.hidden()`)。
158
181
  */
159
- localizedReturnGuidancePresets: string[]
182
+ localizedReturnGuidancePresets: string[];
160
183
  }
161
184
 
162
185
  /** Named provider registry with managed activations, durable discovery, and local child messaging. */
163
186
  export class SubagentRuntime extends TypertRemoteService {
164
187
  static Config = z.object({
165
188
  maxDepth: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(1).volatile(),
166
- maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8).volatile(),
189
+ maxActiveSubagents: z
190
+ .number()
191
+ .step(1)
192
+ .min(1)
193
+ .max(Number.MAX_SAFE_INTEGER)
194
+ .default(8)
195
+ .volatile(),
167
196
  localizedReturnGuidancePresets: z.array(z.string()).default([]).hidden(),
168
- })
169
- static inject = ['workingDirectory']
170
- private providers = new Map<string, SubagentProvider>()
171
- private manager: SubagentManager | undefined
197
+ });
198
+ static inject = ["workingDirectory"];
199
+ private providers = new Map<string, SubagentProvider>();
200
+ private manager: SubagentManager | undefined;
172
201
  /**
173
202
  * The contained lifecycle-edge publisher. Built here because scoped dispatch
174
203
  * keys its carrier by this exact service instance, whose own context filter
175
204
  * composes into the carrier.
176
205
  */
177
- private readonly emitLifecycle: LifecycleEmitter
206
+ private readonly emitLifecycle: LifecycleEmitter;
178
207
 
179
- constructor(ctx: Context, private config: Config) {
180
- super(ctx, 'subagents')
208
+ constructor(
209
+ ctx: Context,
210
+ private config: Config,
211
+ ) {
212
+ super(ctx, "subagents");
181
213
  // 模型看到的委派范围说明换成中文(见 `./delegation-context.ts`)。
182
- installDelegationContext(ctx)
183
- this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent))
184
- ctx.inject(['agents'], (childCtx: Context) => {
185
- const manager = new SubagentManager(childCtx, {
186
- startExternal: (name, request) => {
187
- const provider = this.expectProvider(name) as SubagentProvider & Required<Pick<SubagentProvider, 'start'>>
188
- return provider.start(request)
214
+ installDelegationContext(ctx);
215
+ this.emitLifecycle = createLifecycleEmitter(this.ctx, (parent) => scopeTarget(this, parent));
216
+ ctx.inject(["agents"], (childCtx: Context) => {
217
+ const manager = new SubagentManager(
218
+ childCtx,
219
+ {
220
+ startExternal: (name, request) => {
221
+ const provider = this.expectProvider(name) as SubagentProvider &
222
+ Required<Pick<SubagentProvider, "start">>;
223
+ return provider.start(request);
224
+ },
225
+ prepareContinuable: (name, request) => this.prepareContinuable(name, request),
226
+ observeActivation: (provider, childId, parent) =>
227
+ this.observeActivation(provider, childId, parent),
228
+ },
229
+ () => this.config.maxActiveSubagents.get(),
230
+ () => this.config.localizedReturnGuidancePresets,
231
+ );
232
+ this.manager = manager;
233
+ childCtx.effect(
234
+ () => () => {
235
+ /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
236
+ if (this.manager === manager) this.manager = undefined;
189
237
  },
190
- prepareContinuable: (name, request) => this.prepareContinuable(name, request),
191
- observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent),
192
- }, () => this.config.maxActiveSubagents.get(), () => this.config.localizedReturnGuidancePresets)
193
- this.manager = manager
194
- childCtx.effect(() => () => {
195
- /* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
196
- if (this.manager === manager) this.manager = undefined
197
- }, 'subagents.managerBinding()')
198
- })
199
- ctx.inject(['sessionProjections'], (projectionCtx) => {
200
- projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition)
201
- projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition)
202
- projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition)
203
- })
238
+ "subagents.managerBinding()",
239
+ );
240
+ });
241
+ ctx.inject(["sessionProjections"], (projectionCtx) => {
242
+ projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition);
243
+ projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
244
+ projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
245
+ });
204
246
  // Archive admission: this runtime is the owner that knows which live
205
247
  // children descend from a Session and how a parent stops them.
206
- ctx.inject(['agents'], (agentsCtx: Context) => { installSubagentArchiveAdmission(agentsCtx) })
248
+ ctx.inject(["agents"], (agentsCtx: Context) => {
249
+ installSubagentArchiveAdmission(agentsCtx);
250
+ });
207
251
  }
208
252
 
209
253
  /**
@@ -211,12 +255,12 @@ export class SubagentRuntime extends TypertRemoteService {
211
255
  * @param configured - Explicit tool limit, or provider-managed for external delegation.
212
256
  * @returns The numeric limit, or undefined when the provider owns depth enforcement.
213
257
  */
214
- resolveMaxDepth(configured?: number | 'provider-managed'): number | undefined {
215
- if (configured === 'provider-managed') return undefined
216
- if (configured !== undefined) return configured
217
- const depth = this.config.maxDepth.get()
218
- assertSubagentMaxDepth(depth)
219
- return depth
258
+ resolveMaxDepth(configured?: number | "provider-managed"): number | undefined {
259
+ if (configured === "provider-managed") return undefined;
260
+ if (configured !== undefined) return configured;
261
+ const depth = this.config.maxDepth.get();
262
+ assertSubagentMaxDepth(depth);
263
+ return depth;
220
264
  }
221
265
 
222
266
  /**
@@ -224,14 +268,15 @@ export class SubagentRuntime extends TypertRemoteService {
224
268
  * @param spec - local task, reserved child id, and result recipient.
225
269
  * @returns activation with its accepted initial message id.
226
270
  */
227
- startActivation(spec: SubagentActivationSpec & { readonly childId: SessionId }):
228
- Promise<SubagentActivation & { readonly messageId: MessageId }>
271
+ startActivation(
272
+ spec: SubagentActivationSpec & { readonly childId: SessionId },
273
+ ): Promise<SubagentActivation & { readonly messageId: MessageId }>;
229
274
  /**
230
275
  * Start a local or external child.
231
276
  * @param spec - task, backend, and result recipient.
232
277
  * @returns activation with a message id only for local children.
233
278
  */
234
- startActivation(spec: SubagentActivationSpec): Promise<SubagentActivation>
279
+ startActivation(spec: SubagentActivationSpec): Promise<SubagentActivation>;
235
280
  /**
236
281
  * Establish a managed child with backend-specific execution capabilities.
237
282
  * @param spec - task, backend, and result recipient.
@@ -239,20 +284,26 @@ export class SubagentRuntime extends TypertRemoteService {
239
284
  * childId requires a local backend and guarantees an accepted messageId.
240
285
  */
241
286
  async startActivation(spec: SubagentActivationSpec): Promise<SubagentActivation> {
242
- const provider = this.expectProvider(spec.provider)
287
+ const provider = this.expectProvider(spec.provider);
243
288
  if (spec.childId !== undefined && provider.prepareContinuable === undefined) {
244
- throw new SubagentError('reserved child ids require a local backend', 'UNSUPPORTED_CAPABILITY')
289
+ throw new SubagentError(
290
+ "reserved child ids require a local backend",
291
+ "UNSUPPORTED_CAPABILITY",
292
+ );
245
293
  }
246
- assertSubagentMaxDepth(spec.request.maxDepth)
247
- this.assertCapabilities(provider, { ...spec.request, signal: spec.signal })
248
- const manager = this.requireManager()
249
- if (this.ctx.get('agents')?.get(spec.request.parent.id) !== spec.request.parent) {
250
- throw new SubagentError('subagent creation requires the exact live parent agent', 'UNAUTHORIZED')
294
+ assertSubagentMaxDepth(spec.request.maxDepth);
295
+ this.assertCapabilities(provider, { ...spec.request, signal: spec.signal });
296
+ const manager = this.requireManager();
297
+ if (this.ctx.get("agents")?.get(spec.request.parent.id) !== spec.request.parent) {
298
+ throw new SubagentError(
299
+ "subagent creation requires the exact live parent agent",
300
+ "UNAUTHORIZED",
301
+ );
251
302
  }
252
- if (spec.request.outputSchema !== undefined) assertObjectJsonSchema(spec.request.outputSchema)
303
+ if (spec.request.outputSchema !== undefined) assertObjectJsonSchema(spec.request.outputSchema);
253
304
  return provider.prepareContinuable === undefined
254
305
  ? manager.startExternal(spec)
255
- : manager.startLocal(spec)
306
+ : manager.startLocal(spec);
256
307
  }
257
308
 
258
309
  /**
@@ -262,7 +313,7 @@ export class SubagentRuntime extends TypertRemoteService {
262
313
  * @returns whether work was joined; hosts recheck parent idle after true.
263
314
  */
264
315
  async waitForChildren(parent: Agent): Promise<boolean> {
265
- return this.manager?.waitForChildren(parent) ?? false
316
+ return this.manager?.waitForChildren(parent) ?? false;
266
317
  }
267
318
 
268
319
  /**
@@ -285,7 +336,7 @@ export class SubagentRuntime extends TypertRemoteService {
285
336
  content: ContentBlock[],
286
337
  options: SubagentSendMessageOptions,
287
338
  ): Promise<MessageId> {
288
- return this.requireManager().sendMessage(sender, targetId, content, options)
339
+ return this.requireManager().sendMessage(sender, targetId, content, options);
289
340
  }
290
341
 
291
342
  /**
@@ -308,9 +359,9 @@ export class SubagentRuntime extends TypertRemoteService {
308
359
  signal: AbortSignal,
309
360
  delivery: SubagentDelivery,
310
361
  ): Promise<MessageId> {
311
- return delivery === 'steer'
362
+ return delivery === "steer"
312
363
  ? this.requireManager().steerPrompt(parent, childId, content, source, signal)
313
- : this.requireManager().queuePrompt(parent, childId, content, source, signal)
364
+ : this.requireManager().queuePrompt(parent, childId, content, source, signal);
314
365
  }
315
366
 
316
367
  /**
@@ -329,7 +380,7 @@ export class SubagentRuntime extends TypertRemoteService {
329
380
  * live target.
330
381
  */
331
382
  interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void {
332
- this.manager?.interrupt(targetSessionId, authority)
383
+ this.manager?.interrupt(targetSessionId, authority);
333
384
  }
334
385
 
335
386
  /**
@@ -343,10 +394,10 @@ export class SubagentRuntime extends TypertRemoteService {
343
394
  * @throws an aggregate error after all branches settle when any failed.
344
395
  */
345
396
  async drainDescendants(parents: readonly Agent[]): Promise<void> {
346
- const manager = this.manager
397
+ const manager = this.manager;
347
398
  // An absent activation manager cannot own materialized children.
348
- if (manager === undefined) return
349
- await manager.drainDescendants(parents)
399
+ if (manager === undefined) return;
400
+ await manager.drainDescendants(parents);
350
401
  }
351
402
 
352
403
  /**
@@ -360,9 +411,9 @@ export class SubagentRuntime extends TypertRemoteService {
360
411
  * different parent or the supplied parent identity is stale.
361
412
  */
362
413
  async drainChildren(parent: Agent, childIds: readonly SessionId[]): Promise<void> {
363
- const manager = this.manager
364
- if (manager === undefined) return
365
- await manager.drainChildren(parent, childIds)
414
+ const manager = this.manager;
415
+ if (manager === undefined) return;
416
+ await manager.drainChildren(parent, childIds);
366
417
  }
367
418
 
368
419
  /**
@@ -375,7 +426,7 @@ export class SubagentRuntime extends TypertRemoteService {
375
426
  * @throws SessionQueryError when the parent cannot be read or the query is cancelled.
376
427
  */
377
428
  listChildren(parentSessionId: SessionId, signal?: AbortSignal): Promise<SubagentCatalogEntry[]> {
378
- return listSubagentChildren(this.ctx, parentSessionId, signal)
429
+ return listSubagentChildren(this.ctx, parentSessionId, signal);
379
430
  }
380
431
 
381
432
  /**
@@ -394,8 +445,11 @@ export class SubagentRuntime extends TypertRemoteService {
394
445
  * @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
395
446
  * @throws SessionQueryError when the root catalog cannot be read.
396
447
  */
397
- listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise<SubagentDescendantListEntry[]> {
398
- return listSubagentDescendants(this.ctx, rootSessionId, signal)
448
+ listDescendants(
449
+ rootSessionId: SessionId,
450
+ signal?: AbortSignal,
451
+ ): Promise<SubagentDescendantListEntry[]> {
452
+ return listSubagentDescendants(this.ctx, rootSessionId, signal);
399
453
  }
400
454
 
401
455
  /**
@@ -416,45 +470,52 @@ export class SubagentRuntime extends TypertRemoteService {
416
470
  * `subagent/not-resumable`, `subagent/unauthorized`,
417
471
  * `subagent/delivery-unavailable`, `gateway/cancelled`, or `gateway/internal`.
418
472
  */
419
- @Remote('prompt')
420
- async prompt(request: SubagentPromptRequest, signal: AbortSignal): Promise<SubagentPromptReceipt> {
421
- const { parentSessionId, childSessionId, clientTimeZone, delivery } = request
422
- validateControlRequest('subagent.prompt', request)
423
- const canonicalTimeZone = clientTimeZone === undefined
424
- ? undefined
425
- : canonicalClientTimeZone(clientTimeZone)
473
+ @Remote("prompt")
474
+ async prompt(
475
+ request: SubagentPromptRequest,
476
+ signal: AbortSignal,
477
+ ): Promise<SubagentPromptReceipt> {
478
+ const { parentSessionId, childSessionId, clientTimeZone, delivery } = request;
479
+ validateControlRequest("subagent.prompt", request);
480
+ const canonicalTimeZone =
481
+ clientTimeZone === undefined ? undefined : canonicalClientTimeZone(clientTimeZone);
426
482
  if (clientTimeZone !== undefined && canonicalTimeZone === undefined) {
427
483
  throw new RemoteError(
428
- 'subagent/invalid-time-zone',
429
- 'clientTimeZone must be UTC or a valid IANA Area/Location name',
484
+ "subagent/invalid-time-zone",
485
+ "clientTimeZone must be UTC or a valid IANA Area/Location name",
430
486
  { value: clientTimeZone },
431
- )
487
+ );
432
488
  }
433
- const parent = this.ctx.get('agents')?.get(parentSessionId)
489
+ const parent = this.ctx.get("agents")?.get(parentSessionId);
434
490
  if (parent === undefined) {
435
491
  throw new RemoteError(
436
- 'subagent/parent-unavailable',
492
+ "subagent/parent-unavailable",
437
493
  `parent session "${parentSessionId}" is not live`,
438
494
  { parentSessionId },
439
- )
495
+ );
440
496
  }
441
- const principal = principalOf(this.ctx.invocation)
497
+ const principal = principalOf(this.ctx.invocation);
442
498
  const source: BrowserPromptSource = {
443
- kind: 'user',
499
+ kind: "user",
444
500
  rpcId: request.requestId,
445
501
  ...(canonicalTimeZone === undefined ? {} : { clientTimeZone: canonicalTimeZone }),
446
502
  ...(principal === undefined ? {} : { principal }),
447
- }
503
+ };
448
504
  try {
449
505
  // Admission precedes delivery: image parts become durable references
450
506
  // here, so the child inbox only ever accepts Host-persisted attachments.
451
- let content: ContentBlock[]
452
- if (request.content.every((part): part is { readonly type: 'text'; readonly text: string } => part.type === 'text')) {
453
- content = request.content.map(part => ({ type: 'text', text: part.text }))
507
+ let content: ContentBlock[];
508
+ if (
509
+ request.content.every(
510
+ (part): part is { readonly type: "text"; readonly text: string } => part.type === "text",
511
+ )
512
+ ) {
513
+ content = request.content.map((part) => ({ type: "text", text: part.text }));
454
514
  } else {
455
- const attachments = this.ctx.get('attachments')
456
- if (attachments === undefined) throw new Error('subagent image prompt requires an attachment store')
457
- content = await attachments.admitPromptContent(request.content)
515
+ const attachments = this.ctx.get("attachments");
516
+ if (attachments === undefined)
517
+ throw new Error("subagent image prompt requires an attachment store");
518
+ content = await attachments.admitPromptContent(request.content);
458
519
  }
459
520
  return {
460
521
  messageId: await this[deliverSubagentPrompt](
@@ -465,9 +526,9 @@ export class SubagentRuntime extends TypertRemoteService {
465
526
  signal,
466
527
  delivery,
467
528
  ),
468
- }
529
+ };
469
530
  } catch (error: unknown) {
470
- return rejectPrompt(error, childSessionId, signal)
531
+ return rejectPrompt(error, childSessionId, signal);
471
532
  }
472
533
  }
473
534
 
@@ -485,27 +546,27 @@ export class SubagentRuntime extends TypertRemoteService {
485
546
  * `subagent/unauthorized` when the address does not own the live target,
486
547
  * otherwise `gateway/internal`.
487
548
  */
488
- @Remote('interruptByParent')
549
+ @Remote("interruptByParent")
489
550
  interruptByParent(
490
551
  childSessionId: SessionId,
491
552
  parentSessionId: SessionId,
492
- mode: 'continuable',
553
+ mode: "continuable",
493
554
  ): SubagentInterruptReceipt {
494
- validateControlRequest('subagent.interrupt', { childSessionId, parentSessionId, mode })
555
+ validateControlRequest("subagent.interrupt", { childSessionId, parentSessionId, mode });
495
556
  try {
496
- this.interrupt(childSessionId, { kind: 'user', parentSessionId })
557
+ this.interrupt(childSessionId, { kind: "user", parentSessionId });
497
558
  } catch (error: unknown) {
498
- if (error instanceof SubagentError && error.code === 'UNAUTHORIZED') {
559
+ if (error instanceof SubagentError && error.code === "UNAUTHORIZED") {
499
560
  throw new RemoteError(
500
- 'subagent/unauthorized',
501
- 'subagent does not belong to this parent',
561
+ "subagent/unauthorized",
562
+ "subagent does not belong to this parent",
502
563
  { childSessionId },
503
564
  { cause: error },
504
- )
565
+ );
505
566
  }
506
- throw new RemoteError('gateway/internal', 'subagent interrupt failed', {}, { cause: error })
567
+ throw new RemoteError("gateway/internal", "subagent interrupt failed", {}, { cause: error });
507
568
  }
508
- return { accepted: true }
569
+ return { accepted: true };
509
570
  }
510
571
 
511
572
  /**
@@ -517,24 +578,33 @@ export class SubagentRuntime extends TypertRemoteService {
517
578
  * @returns the exact Cordis effect disposer.
518
579
  */
519
580
  registerProvider(provider: SubagentProvider): () => void {
520
- const name = provider.name
581
+ const name = provider.name;
521
582
  if (provider.start === undefined && provider.prepareContinuable === undefined) {
522
- throw new SubagentError(`subagent provider "${name}" must implement start or prepareContinuable`, 'UNSUPPORTED_CAPABILITY')
583
+ throw new SubagentError(
584
+ `subagent provider "${name}" must implement start or prepareContinuable`,
585
+ "UNSUPPORTED_CAPABILITY",
586
+ );
523
587
  }
524
588
  // oxlint-disable-next-line typescript/no-misused-promises -- synchronous disposer
525
- return this.ctx.effect(function* (this: SubagentRuntime) {
526
- if (this.providers.has(name)) {
527
- throw new SubagentError(`a subagent provider named "${name}" is already registered`, 'DUPLICATE_PROVIDER')
528
- }
529
- this.providers.set(name, provider)
530
- yield () => {
531
- this.providers.delete(name)
532
- this.emitLifecycle('subagent/provider-removed', name)
533
- }
534
- // A throwing added-listener unwinds the yielded rollback, matching the
535
- // repository's fail-loud registration semantics.
536
- this.ctx.emit('subagent/provider-added', provider)
537
- }.bind(this), 'subagents.registerProvider()')
589
+ return this.ctx.effect(
590
+ function* (this: SubagentRuntime) {
591
+ if (this.providers.has(name)) {
592
+ throw new SubagentError(
593
+ `a subagent provider named "${name}" is already registered`,
594
+ "DUPLICATE_PROVIDER",
595
+ );
596
+ }
597
+ this.providers.set(name, provider);
598
+ yield () => {
599
+ this.providers.delete(name);
600
+ this.emitLifecycle("subagent/provider-removed", name);
601
+ };
602
+ // A throwing added-listener unwinds the yielded rollback, matching the
603
+ // repository's fail-loud registration semantics.
604
+ this.ctx.emit("subagent/provider-added", provider);
605
+ }.bind(this),
606
+ "subagents.registerProvider()",
607
+ );
538
608
  }
539
609
 
540
610
  /**
@@ -543,7 +613,7 @@ export class SubagentRuntime extends TypertRemoteService {
543
613
  * @returns the provider, or undefined when absent.
544
614
  */
545
615
  getProvider(name: string): SubagentProvider | undefined {
546
- return this.providers.get(name)
616
+ return this.providers.get(name);
547
617
  }
548
618
 
549
619
  /**
@@ -551,7 +621,7 @@ export class SubagentRuntime extends TypertRemoteService {
551
621
  * @returns the registered names.
552
622
  */
553
623
  list(): string[] {
554
- return [...this.providers.keys()]
624
+ return [...this.providers.keys()];
555
625
  }
556
626
 
557
627
  /**
@@ -563,28 +633,29 @@ export class SubagentRuntime extends TypertRemoteService {
563
633
  name: string,
564
634
  request: ContinuableCreateRequest,
565
635
  ): Promise<ContinuableCreateSpec> {
566
- const provider = this.expectProvider(name) as SubagentProvider & Required<Pick<SubagentProvider, 'prepareContinuable'>>
567
- return provider.prepareContinuable(request)
636
+ const provider = this.expectProvider(name) as SubagentProvider &
637
+ Required<Pick<SubagentProvider, "prepareContinuable">>;
638
+ return provider.prepareContinuable(request);
568
639
  }
569
640
 
570
641
  /** Look up a provider for dispatch or fail loud. */
571
642
  private expectProvider(name: string): SubagentProvider {
572
- const provider = this.providers.get(name)
643
+ const provider = this.providers.get(name);
573
644
  if (provider === undefined) {
574
- throw new SubagentError(`no subagent provider registered for "${name}"`, 'NO_PROVIDER')
645
+ throw new SubagentError(`no subagent provider registered for "${name}"`, "NO_PROVIDER");
575
646
  }
576
- return provider
647
+ return provider;
577
648
  }
578
649
 
579
650
  /** Resolve the subagent manager or fail loud. */
580
651
  private requireManager(): SubagentManager {
581
652
  if (this.manager === undefined) {
582
653
  throw new SubagentError(
583
- 'continuable subagents require the agents service',
584
- 'CONTINUATION_UNAVAILABLE',
585
- )
654
+ "continuable subagents require the agents service",
655
+ "CONTINUATION_UNAVAILABLE",
656
+ );
586
657
  }
587
- return this.manager
658
+ return this.manager;
588
659
  }
589
660
 
590
661
  /**
@@ -596,32 +667,34 @@ export class SubagentRuntime extends TypertRemoteService {
596
667
  childId: SessionId,
597
668
  parent: Agent,
598
669
  ): ActivationObserver {
599
- return createActivationObserver(this.emitLifecycle, provider, childId, parent)
670
+ return createActivationObserver(this.emitLifecycle, provider, childId, parent);
600
671
  }
601
672
 
602
673
  /** Reject the first requested capability that the provider lacks. */
603
674
  private assertCapabilities(provider: SubagentProvider, request: SubagentStartRequest): void {
604
- if (request.agentPreset !== undefined && (!provider.capabilities.agentPreset || provider.inheritsParentContext)) {
675
+ if (
676
+ request.agentPreset !== undefined &&
677
+ (!provider.capabilities.agentPreset || provider.inheritsParentContext)
678
+ ) {
605
679
  throw new SubagentError(
606
680
  `subagent provider "${provider.name}" does not support independent agent preset selection`,
607
- 'UNSUPPORTED_CAPABILITY',
608
- )
681
+ "UNSUPPORTED_CAPABILITY",
682
+ );
609
683
  }
610
684
  const needs: { when: boolean; cap: keyof SubagentCapabilities }[] = [
611
- { when: request.agentOptions !== undefined, cap: 'agentOptions' },
612
- { when: request.outputSchema !== undefined, cap: 'outputSchema' },
613
- { when: request.maxDepth !== undefined, cap: 'depthLimit' },
614
- ]
685
+ { when: request.agentOptions !== undefined, cap: "agentOptions" },
686
+ { when: request.outputSchema !== undefined, cap: "outputSchema" },
687
+ { when: request.maxDepth !== undefined, cap: "depthLimit" },
688
+ ];
615
689
  for (const { when, cap } of needs) {
616
690
  if (when && !provider.capabilities[cap]) {
617
691
  throw new SubagentError(
618
692
  `subagent provider "${provider.name}" does not support the "${cap}" capability`,
619
- 'UNSUPPORTED_CAPABILITY',
620
- )
693
+ "UNSUPPORTED_CAPABILITY",
694
+ );
621
695
  }
622
696
  }
623
697
  }
624
-
625
698
  }
626
699
 
627
- export default SubagentRuntime
700
+ export default SubagentRuntime;