@deepseek-ai/dsh-subagent 0.1.6-alpha.2 → 0.1.7-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +9 -6
- package/README.zh.md +9 -6
- package/lib/index.js +294 -228
- package/lib/typert.host.js +60 -89
- package/lib/typert.remote-client.d.ts +1 -3
- package/lib/typert.remote-client.js +2 -56
- package/lib/types/archive-admission.d.ts +16 -0
- package/lib/types/archive-admission.js +151 -0
- package/lib/types/assistant-output.d.ts +2 -2
- package/lib/types/catalog.d.ts +17 -10
- package/lib/types/catalog.js +12 -6
- package/lib/types/control-types.d.ts +29 -36
- package/lib/types/control-types.js +2 -3
- package/lib/types/control.d.ts +2 -28
- package/lib/types/control.js +2 -40
- package/lib/types/index.d.ts +29 -42
- package/lib/types/index.js +29 -91
- package/lib/types/lifecycle.d.ts +1 -1
- package/lib/types/lifecycle.js +4 -3
- package/lib/types/list-children.d.ts +15 -32
- package/lib/types/list-children.js +45 -49
- package/lib/types/out-of-process.d.ts +1 -1
- package/lib/types/projection-types.d.ts +9 -1
- package/lib/types/projection.d.ts +5 -0
- package/lib/types/projection.js +10 -4
- package/lib/types/run-settlement.js +1 -1
- package/lib/types/types.d.ts +2 -2
- package/package.json +57 -54
package/lib/types/index.js
CHANGED
|
@@ -1,33 +1,3 @@
|
|
|
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
|
-
* Multiple providers coexist: each registers under a unique name and callers
|
|
8
|
-
* select one by name.
|
|
9
|
-
*
|
|
10
|
-
* This package owns the Service Definition role of the capability seam. Service Providers
|
|
11
|
-
* (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing
|
|
12
|
-
* consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages.
|
|
13
|
-
*
|
|
14
|
-
* Public operations express caller intent: `start` returns one published owned
|
|
15
|
-
* one-shot run, `startContinuable` establishes a durable continuable child, and
|
|
16
|
-
* `sendMessage` steers between adjacent Agents without exposing whether a child
|
|
17
|
-
* is resident. Continuable children never become a {@link SubagentRun}: the
|
|
18
|
-
* continuation manager holds their `AgentHandle` directly and orders every turn
|
|
19
|
-
* through the child's own inbox, so providers contribute only the detached
|
|
20
|
-
* creation spec and see no handle, turn, or teardown. Child and descendant
|
|
21
|
-
* discovery read the live session store and optional session persistence
|
|
22
|
-
* directly and do not require that continuation runtime.
|
|
23
|
-
*
|
|
24
|
-
* Same-process providers are trusted typed collaborators. Requests, provider
|
|
25
|
-
* descriptors, results, and lifecycle payloads are borrowed immutable values;
|
|
26
|
-
* serialization and hostile-input validation belong at real process, worker,
|
|
27
|
-
* persistence, and model boundaries.
|
|
28
|
-
*
|
|
29
|
-
* @module @deepseek-ai/dsh-subagent
|
|
30
|
-
*/
|
|
31
1
|
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
32
2
|
var useValue = arguments.length > 2;
|
|
33
3
|
for (var i = 0; i < initializers.length; i++) {
|
|
@@ -67,12 +37,13 @@ import { scopeTarget } from '@deepseek-ai/dsh-scope';
|
|
|
67
37
|
import { assertObjectJsonSchema } from '@deepseek-ai/dsh-tools';
|
|
68
38
|
import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time';
|
|
69
39
|
import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
70
|
-
import {
|
|
40
|
+
import { rejectPrompt, validateControlRequest, } from "./control.js";
|
|
71
41
|
import { SubagentError } from "./error.js";
|
|
72
42
|
import { assertSubagentMaxDepth } from "./depth.js";
|
|
73
43
|
import { createActivationObserver, createLifecycleEmitter, observeRun } from "./lifecycle.js";
|
|
74
44
|
import SubagentContinuationManager from "./continuation.js";
|
|
75
45
|
import { listChildren as listSubagentChildren, listDescendants as listSubagentDescendants } from "./list-children.js";
|
|
46
|
+
import { installSubagentArchiveAdmission } from "./archive-admission.js";
|
|
76
47
|
import { snapshotSubagentDescriptor } from "./descriptor.js";
|
|
77
48
|
import { subagentIdentityProjectionDefinition, subagentTimingProjectionDefinition } from "./projection.js";
|
|
78
49
|
import { establishCatalogChild, subagentCatalogProjectionDefinition } from "./catalog.js";
|
|
@@ -89,25 +60,22 @@ export { appendDelegatedPolicyOverrides, applyChildComposition, captureDelegated
|
|
|
89
60
|
let SubagentRuntime = (() => {
|
|
90
61
|
let _classSuper = TypertRemoteService;
|
|
91
62
|
let _instanceExtraInitializers = [];
|
|
92
|
-
let _remoteExportList_decorators;
|
|
93
63
|
let _prompt_decorators;
|
|
94
64
|
let _interruptByParent_decorators;
|
|
95
65
|
return class SubagentRuntime extends _classSuper {
|
|
96
66
|
static {
|
|
97
67
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
98
|
-
_remoteExportList_decorators = [Remote('list')];
|
|
99
68
|
_prompt_decorators = [Remote('prompt')];
|
|
100
69
|
_interruptByParent_decorators = [Remote('interruptByParent')];
|
|
101
|
-
__esDecorate(this, null, _remoteExportList_decorators, { kind: "method", name: "remoteExportList", static: false, private: false, access: { has: obj => "remoteExportList" in obj, get: obj => obj.remoteExportList }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
102
70
|
__esDecorate(this, null, _prompt_decorators, { kind: "method", name: "prompt", static: false, private: false, access: { has: obj => "prompt" in obj, get: obj => obj.prompt }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
103
71
|
__esDecorate(this, null, _interruptByParent_decorators, { kind: "method", name: "interruptByParent", static: false, private: false, access: { has: obj => "interruptByParent" in obj, get: obj => obj.interruptByParent }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
104
72
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
105
73
|
}
|
|
74
|
+
config = __runInitializers(this, _instanceExtraInitializers);
|
|
106
75
|
static Config = z.object({
|
|
107
|
-
maxDepth: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(1),
|
|
108
|
-
maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8),
|
|
76
|
+
maxDepth: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(1).volatile(),
|
|
77
|
+
maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8).volatile(),
|
|
109
78
|
});
|
|
110
|
-
settingsSource = __runInitializers(this, _instanceExtraInitializers);
|
|
111
79
|
providers = new Map();
|
|
112
80
|
continuations;
|
|
113
81
|
/**
|
|
@@ -118,21 +86,13 @@ let SubagentRuntime = (() => {
|
|
|
118
86
|
emitLifecycle;
|
|
119
87
|
constructor(ctx, config) {
|
|
120
88
|
super(ctx, 'subagents');
|
|
121
|
-
|
|
122
|
-
this.settingsSource = () => config;
|
|
123
|
-
ctx.inject(['settings'], (settingsCtx) => {
|
|
124
|
-
settingsCtx.settings.installSection(ctx, 'subagent', SubagentRuntime.Config, config, {
|
|
125
|
-
validate: (value) => { assertSubagentMaxDepth(value.maxDepth); },
|
|
126
|
-
setSource: (source) => { this.settingsSource = source; },
|
|
127
|
-
onChange: () => { },
|
|
128
|
-
});
|
|
129
|
-
});
|
|
89
|
+
this.config = config;
|
|
130
90
|
this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent));
|
|
131
91
|
ctx.inject(['agents'], (childCtx) => {
|
|
132
92
|
const manager = new SubagentContinuationManager(childCtx, {
|
|
133
93
|
prepareContinuable: (name, request) => this.prepareContinuable(name, request),
|
|
134
94
|
observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent),
|
|
135
|
-
}, () => this.
|
|
95
|
+
}, () => this.config.maxActiveSubagents.get());
|
|
136
96
|
this.continuations = manager;
|
|
137
97
|
childCtx.effect(() => () => {
|
|
138
98
|
/* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
|
|
@@ -141,10 +101,14 @@ let SubagentRuntime = (() => {
|
|
|
141
101
|
}, 'subagents.continuationBinding()');
|
|
142
102
|
});
|
|
143
103
|
ctx.inject(['sessionProjections'], (projectionCtx) => {
|
|
144
|
-
projectionCtx.sessionProjections
|
|
145
|
-
|
|
146
|
-
|
|
104
|
+
const projections = projectionCtx.sessionProjections;
|
|
105
|
+
projections.register(subagentCatalogProjectionDefinition);
|
|
106
|
+
projections.register(subagentTimingProjectionDefinition);
|
|
107
|
+
projections.register(subagentIdentityProjectionDefinition);
|
|
147
108
|
});
|
|
109
|
+
// Archive admission: this runtime is the owner that knows which live
|
|
110
|
+
// children descend from a Session and how a parent stops them.
|
|
111
|
+
ctx.inject(['agents'], (agentsCtx) => { installSubagentArchiveAdmission(agentsCtx); });
|
|
148
112
|
}
|
|
149
113
|
/**
|
|
150
114
|
* Resolve a delegation tool's depth policy against the current user setting.
|
|
@@ -154,7 +118,11 @@ let SubagentRuntime = (() => {
|
|
|
154
118
|
resolveMaxDepth(configured) {
|
|
155
119
|
if (configured === 'provider-managed')
|
|
156
120
|
return undefined;
|
|
157
|
-
|
|
121
|
+
if (configured !== undefined)
|
|
122
|
+
return configured;
|
|
123
|
+
const depth = this.config.maxDepth.get();
|
|
124
|
+
assertSubagentMaxDepth(depth);
|
|
125
|
+
return depth;
|
|
158
126
|
}
|
|
159
127
|
/**
|
|
160
128
|
* Establish one durable continuable child and deliver its initial prompt.
|
|
@@ -254,21 +222,13 @@ let SubagentRuntime = (() => {
|
|
|
254
222
|
await manager.drainChildren(parent, childIds);
|
|
255
223
|
}
|
|
256
224
|
/**
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
* around each await. Read rejections that settle
|
|
265
|
-
* after an abort become a stable `SubagentError` with code `CANCELLED`.
|
|
266
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
267
|
-
* @param signal - caller-owned cancellation forwarded to Session queries
|
|
268
|
-
* and observed around every read await.
|
|
269
|
-
* @returns children and per-child diagnostics ordered by `createdAt`, then id.
|
|
270
|
-
* @throws {@link SubagentError} when the projection registry or the session
|
|
271
|
-
* store is not mounted, or the caller cancels the listing.
|
|
225
|
+
* Read the parent's durable direct-child catalog without loading or resuming an Agent.
|
|
226
|
+
* The service owns and releases the live-preferred Session observation.
|
|
227
|
+
* @param parentSessionId - parent whose direct children are requested.
|
|
228
|
+
* @param signal - cancellation forwarded to the Session query.
|
|
229
|
+
* @returns catalog children in parent event order.
|
|
230
|
+
* @throws {@link SubagentError} when query or catalog projection is unavailable.
|
|
231
|
+
* @throws SessionQueryError when the parent cannot be read or the query is cancelled.
|
|
272
232
|
*/
|
|
273
233
|
listChildren(parentSessionId, signal) {
|
|
274
234
|
return listSubagentChildren(this.ctx, parentSessionId, signal);
|
|
@@ -279,40 +239,18 @@ let SubagentRuntime = (() => {
|
|
|
279
239
|
* Agent. Ordinary sessions and one-shot children remain traversal nodes so
|
|
280
240
|
* continuable descendants below them are discovered; each returned entry
|
|
281
241
|
* adds its durable `parentId` and root-relative `depth`. Identity resolution,
|
|
282
|
-
* diagnostics, optional persistence, and cancellation
|
|
283
|
-
* projection
|
|
242
|
+
* diagnostics, optional persistence, and cancellation use the registered
|
|
243
|
+
* child identity projection and complete Session corpus.
|
|
284
244
|
* @param rootSessionId - session whose complete descendant tree is listed.
|
|
285
245
|
* @param signal - caller-owned cancellation forwarded to persistence reads
|
|
286
246
|
* and observed around every read await.
|
|
287
247
|
* @returns children and per-candidate diagnostics with tree position, in
|
|
288
248
|
* stable pre-order.
|
|
289
|
-
* @throws {@link SubagentError}
|
|
249
|
+
* @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
|
|
290
250
|
*/
|
|
291
251
|
listDescendants(rootSessionId, signal) {
|
|
292
252
|
return listSubagentDescendants(this.ctx, rootSessionId, signal);
|
|
293
253
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Remote face of {@link listChildren} for one browser: the durable listing
|
|
296
|
-
* plus live Agent activity and the delivery-time parent availability hint.
|
|
297
|
-
* Parent availability is a hint; {@link prompt} performs the authoritative
|
|
298
|
-
* check. Named apart from the provider-name {@link list}, which owns the
|
|
299
|
-
* member.
|
|
300
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
301
|
-
* @param signal - carrier cancellation forwarded to Session queries.
|
|
302
|
-
* @returns the catalog view for that parent.
|
|
303
|
-
* @throws {RemoteError} `gateway/bad-request` for an empty parent id,
|
|
304
|
-
* `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when
|
|
305
|
-
* the deployment has no projection registry, otherwise `gateway/internal`.
|
|
306
|
-
*/
|
|
307
|
-
async remoteExportList(parentSessionId, signal) {
|
|
308
|
-
validateControlRequest('subagent.list', { parentSessionId });
|
|
309
|
-
try {
|
|
310
|
-
return catalogView(this.ctx, parentSessionId, await this.listChildren(parentSessionId, signal));
|
|
311
|
-
}
|
|
312
|
-
catch (error) {
|
|
313
|
-
return rejectCatalogRead(error, signal);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
254
|
/**
|
|
317
255
|
* Deliver one browser-authored message to a continuable child through the
|
|
318
256
|
* exact live direct parent, retaining the caller-minted request identity and
|
package/lib/types/lifecycle.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export interface ActivationTerminal {
|
|
|
26
26
|
/** Why this epoch's last ordinary turn ended, or `error` when teardown failed. */
|
|
27
27
|
readonly stopReason: SubagentResult['stopReason'];
|
|
28
28
|
/** The epoch's final assistant content, absent when it produced none or failed. */
|
|
29
|
-
readonly output?: ContentBlock[];
|
|
29
|
+
readonly output?: readonly ContentBlock[];
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Lifecycle observer for one Activation's residency epoch, so continuable
|
package/lib/types/lifecycle.js
CHANGED
|
@@ -160,9 +160,10 @@ function epochStopReason(events) {
|
|
|
160
160
|
case undefined:
|
|
161
161
|
case 'completed':
|
|
162
162
|
return droppedUnrun ? 'aborted' : 'completed';
|
|
163
|
-
/* v8 ignore next
|
|
164
|
-
*
|
|
165
|
-
*
|
|
163
|
+
/* v8 ignore next 4 -- `forked` appears only in constructor seed history, while
|
|
164
|
+
* this function reads an epoch-owned suffix. `TurnEndReason` is merge-extensible,
|
|
165
|
+
* so a backend-added variant cannot be listed; treating an unnameable reason as
|
|
166
|
+
* success would report failed work as completed. */
|
|
166
167
|
default:
|
|
167
168
|
return 'error';
|
|
168
169
|
}
|
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* an unseeded durable projection-cache row, and one shared Session observation
|
|
8
|
-
* otherwise. A seeded header deliberately lacks its exact inherited cut, so
|
|
9
|
-
* it takes the body-bearing observation path before classifying an identity.
|
|
10
|
-
* The projection fold is the single classification
|
|
11
|
-
* authority — this module parses no descriptor
|
|
12
|
-
* itself. Absent persistence, enumeration is live-only: a cold child is
|
|
13
|
-
* unreachable for resume anyway, so its absence is capability absence, not an
|
|
14
|
-
* error. The module owns no catalog state and does not consult Activation,
|
|
15
|
-
* Agent-registry, continuation-manager, or provider state.
|
|
2
|
+
* Direct-child discovery from a parent-owned `subagent/catalog` projection,
|
|
3
|
+
* plus complete descendant-tree enumeration from the Session corpus. A direct
|
|
4
|
+
* listing owns one parent observation and reads no child log. Descendant
|
|
5
|
+
* enumeration retains the complete corpus and the child identity projection
|
|
6
|
+
* because ordinary Sessions and one-shot children remain traversal nodes.
|
|
16
7
|
*
|
|
17
8
|
* @module @deepseek-ai/dsh-subagent
|
|
18
9
|
*/
|
|
19
10
|
import type { Context } from '@deepseek-ai/cordis';
|
|
20
11
|
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
21
12
|
import type { SubagentListEntry } from './control-types.ts';
|
|
13
|
+
import type { SubagentCatalogEntry } from './projection-types.ts';
|
|
22
14
|
export type { SubagentListEntry } from './control-types.ts';
|
|
23
15
|
/**
|
|
24
16
|
* One entry of a descendant listing: the interpreted subagent facts plus its
|
|
@@ -32,34 +24,25 @@ export type SubagentDescendantListEntry = SubagentListEntry & {
|
|
|
32
24
|
readonly depth: number;
|
|
33
25
|
};
|
|
34
26
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @see SubagentRuntime.listChildren for the public cancellation and failure contract.
|
|
42
|
-
* @param ctx - context carrying the session store, the projection registry,
|
|
43
|
-
* optional persistence, and the optional projection cache.
|
|
44
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
45
|
-
* @param signal - caller-owned cancellation observed around every persistence read.
|
|
46
|
-
* @returns children and per-child diagnostics ordered by `createdAt`, then id.
|
|
47
|
-
* @throws {@link SubagentError} when the projection registry or the session
|
|
48
|
-
* store is not mounted, or the caller cancels the listing.
|
|
27
|
+
* Read one parent's durable catalog through a live-preferred Session observation.
|
|
28
|
+
* @param ctx - context carrying the Session query service.
|
|
29
|
+
* @param parentSessionId - parent whose direct children are requested.
|
|
30
|
+
* @param signal - cancellation forwarded to the Session observation.
|
|
31
|
+
* @returns direct-child rows in parent catalog event order.
|
|
32
|
+
* @throws {@link SubagentError} when query or catalog projection is unavailable.
|
|
49
33
|
*/
|
|
50
|
-
export declare function listChildren(ctx: Context, parentSessionId: SessionId, signal?: AbortSignal): Promise<
|
|
34
|
+
export declare function listChildren(ctx: Context, parentSessionId: SessionId, signal?: AbortSignal): Promise<SubagentCatalogEntry[]>;
|
|
51
35
|
/**
|
|
52
36
|
* Enumerate every session-backed subagent below one root in stable pre-order.
|
|
53
37
|
* Ordinary sessions and one-shot children remain traversal nodes, so a
|
|
54
38
|
* continuable child below either is still discovered. Classification uses the
|
|
55
|
-
*
|
|
56
|
-
* resumed.
|
|
39
|
+
* registered child identity projection; no Agent is loaded or resumed.
|
|
57
40
|
* @see SubagentRuntime.listDescendants for the public cancellation and failure contract.
|
|
58
41
|
* @param ctx - context carrying the session store, projection registry, and optional persistence/cache.
|
|
59
42
|
* @param rootSessionId - session whose complete descendant tree is listed.
|
|
60
43
|
* @param signal - caller-owned cancellation observed around every persistence read.
|
|
61
44
|
* @returns interpreted subagents with durable direct-parent and root-relative depth.
|
|
62
|
-
* @throws {@link SubagentError}
|
|
45
|
+
* @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
|
|
63
46
|
*/
|
|
64
47
|
export declare function listDescendants(ctx: Context, rootSessionId: SessionId, signal?: AbortSignal): Promise<SubagentDescendantListEntry[]>;
|
|
65
48
|
//# sourceMappingURL=list-children.d.ts.map
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* an unseeded durable projection-cache row, and one shared Session observation
|
|
8
|
-
* otherwise. A seeded header deliberately lacks its exact inherited cut, so
|
|
9
|
-
* it takes the body-bearing observation path before classifying an identity.
|
|
10
|
-
* The projection fold is the single classification
|
|
11
|
-
* authority — this module parses no descriptor
|
|
12
|
-
* itself. Absent persistence, enumeration is live-only: a cold child is
|
|
13
|
-
* unreachable for resume anyway, so its absence is capability absence, not an
|
|
14
|
-
* error. The module owns no catalog state and does not consult Activation,
|
|
15
|
-
* Agent-registry, continuation-manager, or provider state.
|
|
2
|
+
* Direct-child discovery from a parent-owned `subagent/catalog` projection,
|
|
3
|
+
* plus complete descendant-tree enumeration from the Session corpus. A direct
|
|
4
|
+
* listing owns one parent observation and reads no child log. Descendant
|
|
5
|
+
* enumeration retains the complete corpus and the child identity projection
|
|
6
|
+
* because ordinary Sessions and one-shot children remain traversal nodes.
|
|
16
7
|
*
|
|
17
8
|
* @module @deepseek-ai/dsh-subagent
|
|
18
9
|
*/
|
|
@@ -68,7 +59,6 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
68
59
|
var e = new Error(message);
|
|
69
60
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
70
61
|
});
|
|
71
|
-
import { SessionLogOffset } from '@deepseek-ai/dsh-session';
|
|
72
62
|
import { SubagentError } from "./error.js";
|
|
73
63
|
/**
|
|
74
64
|
* Concurrent cold observations per explicit catalog listing. Current Session
|
|
@@ -77,42 +67,48 @@ import { SubagentError } from "./error.js";
|
|
|
77
67
|
*/
|
|
78
68
|
const COLD_READ_CONCURRENCY = 4;
|
|
79
69
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* @see SubagentRuntime.listChildren for the public cancellation and failure contract.
|
|
87
|
-
* @param ctx - context carrying the session store, the projection registry,
|
|
88
|
-
* optional persistence, and the optional projection cache.
|
|
89
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
90
|
-
* @param signal - caller-owned cancellation observed around every persistence read.
|
|
91
|
-
* @returns children and per-child diagnostics ordered by `createdAt`, then id.
|
|
92
|
-
* @throws {@link SubagentError} when the projection registry or the session
|
|
93
|
-
* store is not mounted, or the caller cancels the listing.
|
|
70
|
+
* Read one parent's durable catalog through a live-preferred Session observation.
|
|
71
|
+
* @param ctx - context carrying the Session query service.
|
|
72
|
+
* @param parentSessionId - parent whose direct children are requested.
|
|
73
|
+
* @param signal - cancellation forwarded to the Session observation.
|
|
74
|
+
* @returns direct-child rows in parent catalog event order.
|
|
75
|
+
* @throws {@link SubagentError} when query or catalog projection is unavailable.
|
|
94
76
|
*/
|
|
95
77
|
export async function listChildren(ctx, parentSessionId, signal) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
78
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
79
|
+
try {
|
|
80
|
+
const query = ctx.get('sessionQuery');
|
|
81
|
+
if (query === undefined) {
|
|
82
|
+
throw new SubagentError('listing subagents requires the sessionQuery service (load @deepseek-ai/dsh-session-query)', 'SUBAGENT_CONTROL_QUERY_UNAVAILABLE');
|
|
83
|
+
}
|
|
84
|
+
const parent = __addDisposableResource(env_1, await query.observeSession(parentSessionId, {
|
|
85
|
+
...signal === undefined ? {} : { signal },
|
|
86
|
+
}), false);
|
|
87
|
+
const entries = parent.projections?.values.subagentCatalog;
|
|
88
|
+
if (entries === undefined) {
|
|
89
|
+
throw new SubagentError('listing subagents requires the registered subagentCatalog projection', 'SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE');
|
|
90
|
+
}
|
|
91
|
+
return entries;
|
|
92
|
+
}
|
|
93
|
+
catch (e_1) {
|
|
94
|
+
env_1.error = e_1;
|
|
95
|
+
env_1.hasError = true;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
__disposeResources(env_1);
|
|
99
|
+
}
|
|
103
100
|
}
|
|
104
101
|
/**
|
|
105
102
|
* Enumerate every session-backed subagent below one root in stable pre-order.
|
|
106
103
|
* Ordinary sessions and one-shot children remain traversal nodes, so a
|
|
107
104
|
* continuable child below either is still discovered. Classification uses the
|
|
108
|
-
*
|
|
109
|
-
* resumed.
|
|
105
|
+
* registered child identity projection; no Agent is loaded or resumed.
|
|
110
106
|
* @see SubagentRuntime.listDescendants for the public cancellation and failure contract.
|
|
111
107
|
* @param ctx - context carrying the session store, projection registry, and optional persistence/cache.
|
|
112
108
|
* @param rootSessionId - session whose complete descendant tree is listed.
|
|
113
109
|
* @param signal - caller-owned cancellation observed around every persistence read.
|
|
114
110
|
* @returns interpreted subagents with durable direct-parent and root-relative depth.
|
|
115
|
-
* @throws {@link SubagentError}
|
|
111
|
+
* @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
|
|
116
112
|
*/
|
|
117
113
|
export async function listDescendants(ctx, rootSessionId, signal) {
|
|
118
114
|
const listing = await prepareListing(ctx, signal);
|
|
@@ -271,17 +267,17 @@ function compareCorpusRecords(a, b) {
|
|
|
271
267
|
* throw — are final, so they report `corrupt`.
|
|
272
268
|
*/
|
|
273
269
|
async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
274
|
-
const
|
|
270
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
275
271
|
try {
|
|
276
272
|
const childId = header.id;
|
|
277
273
|
// A header deliberately exposes only whether a fork cut exists, not its
|
|
278
|
-
// integer. An unseeded lifecycle has the exact cut 0
|
|
279
|
-
//
|
|
280
|
-
// classified as inherited or owned.
|
|
274
|
+
// integer. An unseeded lifecycle has the exact cut 0, so its cached
|
|
275
|
+
// descriptor is owned at every valid seq; a seeded lifecycle must read the
|
|
276
|
+
// body before an identity seq can be classified as inherited or owned.
|
|
281
277
|
if (cache !== undefined && !header.isSeeded) {
|
|
282
278
|
let cached;
|
|
283
279
|
try {
|
|
284
|
-
cached = cache.cachedSnapshot(header,
|
|
280
|
+
cached = cache.cachedSnapshot(header, ['subagent'])?.values.subagent;
|
|
285
281
|
}
|
|
286
282
|
catch {
|
|
287
283
|
// Unlike the preparation fold below, a throwing cache read renders no
|
|
@@ -317,7 +313,7 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
317
313
|
: 'unavailable',
|
|
318
314
|
};
|
|
319
315
|
}
|
|
320
|
-
const ownedObservation = __addDisposableResource(
|
|
316
|
+
const ownedObservation = __addDisposableResource(env_2, observation, false);
|
|
321
317
|
assertListingNotCancelled(signal);
|
|
322
318
|
// A session id names a slot, not a lifecycle: a child deleted and
|
|
323
319
|
// re-published under another owner between the enumeration and this read
|
|
@@ -332,12 +328,12 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
332
328
|
}
|
|
333
329
|
return childRow(childId, identity, 'inactive', hasChildren);
|
|
334
330
|
}
|
|
335
|
-
catch (
|
|
336
|
-
|
|
337
|
-
|
|
331
|
+
catch (e_2) {
|
|
332
|
+
env_2.error = e_2;
|
|
333
|
+
env_2.hasError = true;
|
|
338
334
|
}
|
|
339
335
|
finally {
|
|
340
|
-
__disposeResources(
|
|
336
|
+
__disposeResources(env_2);
|
|
341
337
|
}
|
|
342
338
|
}
|
|
343
339
|
/** Materialize one served identity as its child row. */
|
|
@@ -68,7 +68,7 @@ export interface RunResultSettlement {
|
|
|
68
68
|
/** The turn attempt (typically racing local cancellation); returns the terminal result. */
|
|
69
69
|
attempt: () => Promise<SubagentResult>;
|
|
70
70
|
/** Snapshot the provider exposes when cancellation or failure wins settlement. */
|
|
71
|
-
collectOutput: () => ContentBlock[];
|
|
71
|
+
collectOutput: () => readonly ContentBlock[];
|
|
72
72
|
/** Snapshot safe provider-authored detail when a failure wins settlement. */
|
|
73
73
|
collectDiagnostic?: (() => string | undefined) | undefined;
|
|
74
74
|
/** Whether local cancellation settled before the attempt's outcome is observed. */
|
|
@@ -14,6 +14,9 @@ export type SubagentCatalogEntry = {
|
|
|
14
14
|
} | {
|
|
15
15
|
readonly mode: 'continuable';
|
|
16
16
|
readonly label: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly mode: 'unknown';
|
|
19
|
+
readonly label?: string;
|
|
17
20
|
});
|
|
18
21
|
/** Durable active-turn timing for one descriptor-backed child session. */
|
|
19
22
|
export interface SubagentTimingProjection {
|
|
@@ -26,6 +29,11 @@ export interface SubagentTimingProjection {
|
|
|
26
29
|
/** Latest event time folded into this projection cut. */
|
|
27
30
|
through: number;
|
|
28
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Whether the latest closed turn after the child's own descriptor completed
|
|
34
|
+
* normally; absent while a turn is open or before one closes.
|
|
35
|
+
*/
|
|
36
|
+
lastTurnCompleted?: boolean;
|
|
29
37
|
}
|
|
30
38
|
/**
|
|
31
39
|
* Durable identity of one descriptor-backed subagent session: lifecycle mode
|
|
@@ -57,7 +65,7 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
|
57
65
|
interface SessionProjectionMap {
|
|
58
66
|
/** Direct children in parent catalog event order, excluding fork-inherited facts. */
|
|
59
67
|
subagentCatalog: SubagentCatalogEntry[];
|
|
60
|
-
/** Active-turn duration for a descriptor-backed subagent session. */
|
|
68
|
+
/** Active-turn duration and latest closed-turn completion for a descriptor-backed subagent session. */
|
|
61
69
|
subagentTiming: SubagentTimingProjection;
|
|
62
70
|
/**
|
|
63
71
|
* Identity of a descriptor-backed subagent session. `null` ⟺ no valid
|
|
@@ -20,6 +20,8 @@ export interface TimingState {
|
|
|
20
20
|
pendingTurnStart?: number | undefined;
|
|
21
21
|
/** Whether the fold has crossed a descriptor in this logical log. */
|
|
22
22
|
descriptorSeen: boolean;
|
|
23
|
+
/** Whether the latest closed post-descriptor turn completed normally; absent while a turn is open or before one closes. */
|
|
24
|
+
lastTurnCompleted?: boolean | undefined;
|
|
23
25
|
}
|
|
24
26
|
declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
25
27
|
interface SessionProjectionStateMap {
|
|
@@ -52,10 +54,13 @@ export declare const subagentTimingProjectionDefinition: {
|
|
|
52
54
|
} | undefined;
|
|
53
55
|
/** Whether the fold has crossed a descriptor in this logical log. */
|
|
54
56
|
descriptorSeen: boolean;
|
|
57
|
+
/** Whether the latest closed post-descriptor turn completed normally; absent while a turn is open or before one closes. */
|
|
58
|
+
lastTurnCompleted?: boolean | undefined;
|
|
55
59
|
};
|
|
56
60
|
wire: {
|
|
57
61
|
viewSchema: z.ZodType<SubagentTimingProjection, unknown, z.core.$ZodTypeInternals<SubagentTimingProjection, unknown>>;
|
|
58
62
|
view: (state: NoInfer<TimingState>) => {
|
|
63
|
+
lastTurnCompleted?: boolean;
|
|
59
64
|
active?: {
|
|
60
65
|
since: number;
|
|
61
66
|
through: number;
|
package/lib/types/projection.js
CHANGED
|
@@ -14,15 +14,18 @@ const activeIntervalSchema = z.object({
|
|
|
14
14
|
const projectionSchema = z.object({
|
|
15
15
|
settledMs: z.number().int().nonnegative(),
|
|
16
16
|
active: activeIntervalSchema.optional(),
|
|
17
|
-
|
|
17
|
+
lastTurnCompleted: z.boolean().optional(),
|
|
18
|
+
}).strict().transform(({ settledMs, active, lastTurnCompleted }) => ({
|
|
18
19
|
settledMs,
|
|
19
20
|
...active === undefined ? {} : { active },
|
|
21
|
+
...lastTurnCompleted === undefined ? {} : { lastTurnCompleted },
|
|
20
22
|
}));
|
|
21
23
|
const timingStateSchema = z.object({
|
|
22
24
|
settledMs: z.number().int().nonnegative(),
|
|
23
25
|
active: activeIntervalSchema.optional(),
|
|
24
26
|
pendingTurnStart: z.number().int().nonnegative().optional(),
|
|
25
27
|
descriptorSeen: z.boolean(),
|
|
28
|
+
lastTurnCompleted: z.boolean().optional(),
|
|
26
29
|
}).strict();
|
|
27
30
|
/**
|
|
28
31
|
* Fold turn boundaries around the child's own durable descriptor.
|
|
@@ -38,9 +41,10 @@ export const subagentTimingProjectionDefinition = {
|
|
|
38
41
|
init: () => ({ descriptorSeen: false, settledMs: 0 }),
|
|
39
42
|
apply: (state, event) => {
|
|
40
43
|
if (event.type === 'turn/start') {
|
|
44
|
+
const { lastTurnCompleted: _closed, ...openState } = state;
|
|
41
45
|
return state.descriptorSeen
|
|
42
|
-
? { ...
|
|
43
|
-
: { ...
|
|
46
|
+
? { ...openState, active: { since: event.time, through: event.time } }
|
|
47
|
+
: { ...openState, pendingTurnStart: event.time };
|
|
44
48
|
}
|
|
45
49
|
if (event.type === 'subagent/descriptor') {
|
|
46
50
|
const activeSince = state.active?.since ?? state.pendingTurnStart;
|
|
@@ -65,6 +69,7 @@ export const subagentTimingProjectionDefinition = {
|
|
|
65
69
|
return {
|
|
66
70
|
...rest,
|
|
67
71
|
settledMs: state.settledMs + Math.max(0, event.time - active.since),
|
|
72
|
+
lastTurnCompleted: event.data.reason.kind === 'completed',
|
|
68
73
|
};
|
|
69
74
|
}
|
|
70
75
|
if (state.active === undefined)
|
|
@@ -76,9 +81,10 @@ export const subagentTimingProjectionDefinition = {
|
|
|
76
81
|
view: state => ({
|
|
77
82
|
settledMs: state.settledMs,
|
|
78
83
|
...(state.active === undefined ? {} : { active: state.active }),
|
|
84
|
+
...(state.lastTurnCompleted === undefined ? {} : { lastTurnCompleted: state.lastTurnCompleted }),
|
|
79
85
|
}),
|
|
80
86
|
},
|
|
81
|
-
stateVersion:
|
|
87
|
+
stateVersion: 3,
|
|
82
88
|
};
|
|
83
89
|
// The cast bridges only the optional-label arm: Zod's optional output
|
|
84
90
|
// includes explicit `undefined`, which exactOptionalPropertyTypes excludes
|
|
@@ -30,7 +30,7 @@ function failureDetail(result) {
|
|
|
30
30
|
function runOutcome(result) {
|
|
31
31
|
switch (result.stopReason) {
|
|
32
32
|
case 'completed':
|
|
33
|
-
return { status: 'completed',
|
|
33
|
+
return { status: 'completed', result: finalText(result.output) };
|
|
34
34
|
case 'aborted':
|
|
35
35
|
return result.diagnostic === undefined
|
|
36
36
|
? { status: 'killed' }
|
package/lib/types/types.d.ts
CHANGED
|
@@ -106,7 +106,7 @@ export interface SubagentRunEndInfo {
|
|
|
106
106
|
* {@link SubagentResult.output}; absent on infrastructure rejection or when
|
|
107
107
|
* the child produced none.
|
|
108
108
|
*/
|
|
109
|
-
readonly lastAssistantMessage?: ContentBlock[];
|
|
109
|
+
readonly lastAssistantMessage?: readonly ContentBlock[];
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
112
|
* Which START-TIME features a provider supports. Checked by the service before delegating to
|
|
@@ -260,7 +260,7 @@ export interface SubagentResult {
|
|
|
260
260
|
* are skipped. Without a non-empty message, the output is its accumulated
|
|
261
261
|
* assistant text stream, or `[]` when the child produced neither.
|
|
262
262
|
*/
|
|
263
|
-
readonly output: ContentBlock[];
|
|
263
|
+
readonly output: readonly ContentBlock[];
|
|
264
264
|
/**
|
|
265
265
|
* The structured result after a requested `outputSchema` was successfully
|
|
266
266
|
* satisfied. Requesting a schema does not guarantee presence: a provider can
|