@deepseek-ai/dsh-subagent 0.1.6-alpha.1 → 0.1.7-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +21 -6
- package/README.zh.md +21 -6
- package/lib/index.js +386 -254
- package/lib/typert.host.js +89 -103
- package/lib/typert.remote-client.d.ts +1 -3
- package/lib/typert.remote-client.js +23 -69
- 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/continuation-activation.d.ts +17 -1
- package/lib/types/continuation-activation.js +41 -4
- package/lib/types/continuation.d.ts +1 -1
- package/lib/types/continuation.js +2 -2
- 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 +3 -40
- package/lib/types/index.d.ts +43 -39
- package/lib/types/index.js +44 -80
- 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 +60 -51
package/lib/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
1
2
|
import { scopeTarget } from "@deepseek-ai/dsh-scope";
|
|
2
3
|
import { assertObjectJsonSchema } from "@deepseek-ai/dsh-tools";
|
|
3
4
|
import { canonicalClientTimeZone } from "@deepseek-ai/dsh-util-time";
|
|
4
5
|
import { Remote, RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
5
6
|
import { AttachmentError } from "@deepseek-ai/dsh-attachment";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
+
import { z as z$1 } from "zod";
|
|
7
8
|
import { HarnessError, ReasoningEffortId, boundContextSummary, contentHasImage, createUserMessage, errorChain, joinAssistantStreamText } from "@deepseek-ai/dsh-llm";
|
|
8
9
|
import { randomUUID } from "node:crypto";
|
|
9
10
|
import { foldConsumedWork } from "@deepseek-ai/dsh-agent";
|
|
@@ -29,25 +30,23 @@ var SubagentError = class extends HarnessError {
|
|
|
29
30
|
//#endregion
|
|
30
31
|
//#region lib/types/control.js
|
|
31
32
|
/**
|
|
32
|
-
* Browser-facing subagent
|
|
33
|
-
*
|
|
34
|
-
* failure codes the Remote surface answers with.
|
|
33
|
+
* Browser-facing subagent prompt and interrupt request validation plus the
|
|
34
|
+
* stable prompt failure codes returned by the Remote surface.
|
|
35
35
|
*
|
|
36
36
|
* @module @deepseek-ai/dsh-subagent
|
|
37
37
|
*/
|
|
38
|
-
const SESSION_ID_SCHEMA = z.string().min(1);
|
|
38
|
+
const SESSION_ID_SCHEMA = z$1.string().min(1);
|
|
39
39
|
const CONTROL_ID_SCHEMAS = {
|
|
40
|
-
"subagent.
|
|
41
|
-
"subagent.prompt": z.object({
|
|
40
|
+
"subagent.prompt": z$1.object({
|
|
42
41
|
parentSessionId: SESSION_ID_SCHEMA,
|
|
43
42
|
childSessionId: SESSION_ID_SCHEMA,
|
|
44
|
-
mode: z.literal("continuable"),
|
|
45
|
-
delivery: z.enum(["queue", "steer"])
|
|
43
|
+
mode: z$1.literal("continuable"),
|
|
44
|
+
delivery: z$1.enum(["queue", "steer"])
|
|
46
45
|
}),
|
|
47
|
-
"subagent.interrupt": z.object({
|
|
46
|
+
"subagent.interrupt": z$1.object({
|
|
48
47
|
parentSessionId: SESSION_ID_SCHEMA,
|
|
49
48
|
childSessionId: SESSION_ID_SCHEMA,
|
|
50
|
-
mode: z.literal("continuable")
|
|
49
|
+
mode: z$1.literal("continuable")
|
|
51
50
|
})
|
|
52
51
|
};
|
|
53
52
|
/**
|
|
@@ -62,39 +61,6 @@ function validateControlRequest(method, payload) {
|
|
|
62
61
|
if (!parsed.success) throw new RemoteError("gateway/bad-request", `invalid payload for ${method}`, { issues: parsed.error.issues });
|
|
63
62
|
}
|
|
64
63
|
/**
|
|
65
|
-
* Project one durable listing onto the catalog view, replacing each row's
|
|
66
|
-
* store-derived activity with the live Agent driver's status and reporting
|
|
67
|
-
* whether the exact parent Agent is live. Without an Agent registry no driver
|
|
68
|
-
* runs at all, so every row is inactive and the parent is unavailable.
|
|
69
|
-
* @param ctx - Host context that may carry the Agent registry.
|
|
70
|
-
* @param parentSessionId - the listed parent.
|
|
71
|
-
* @param entries - the durable direct-child listing.
|
|
72
|
-
* @returns the catalog view answered to one browser.
|
|
73
|
-
*/
|
|
74
|
-
function catalogView(ctx, parentSessionId, entries) {
|
|
75
|
-
const agents = ctx.get("agents");
|
|
76
|
-
return {
|
|
77
|
-
entries: entries.map((entry) => entry.kind === "child" ? {
|
|
78
|
-
...entry,
|
|
79
|
-
activity: agents?.get(entry.id)?.status === "running" ? "running" : "inactive"
|
|
80
|
-
} : entry),
|
|
81
|
-
parentAvailable: agents?.get(parentSessionId) !== void 0
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Refuse one catalog read while preserving cancellation and a missing
|
|
86
|
-
* projections registry as distinct failures.
|
|
87
|
-
* @param error - the thrown value.
|
|
88
|
-
* @param signal - the caller's cancellation.
|
|
89
|
-
* @returns Never — the refusal is thrown.
|
|
90
|
-
* @throws {RemoteError} always.
|
|
91
|
-
*/
|
|
92
|
-
function rejectCatalogRead(error, signal) {
|
|
93
|
-
if (isCancellation(error, signal)) throw new RemoteError("gateway/cancelled", "subagent catalog read was cancelled", {}, { cause: error });
|
|
94
|
-
if (error instanceof SubagentError && error.code === "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE") throw new RemoteError("subagent/projections-unavailable", "subagent catalog is unavailable: this deployment does not mount the sessionProjections registry (load @deepseek-ai/dsh-session-projection)", {}, { cause: error });
|
|
95
|
-
throw new RemoteError("gateway/internal", "subagent catalog read failed", {}, { cause: error });
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
64
|
* Refuse one continuation prompt without exposing provider detail: admission
|
|
99
65
|
* failures the caller can act on keep their own code, everything else is
|
|
100
66
|
* internal.
|
|
@@ -113,6 +79,7 @@ function rejectPrompt(error, childSessionId, signal) {
|
|
|
113
79
|
case "UNAUTHORIZED": throw new RemoteError("subagent/unauthorized", "subagent does not belong to this parent", { childSessionId }, { cause: error });
|
|
114
80
|
case "DRAINING":
|
|
115
81
|
case "ACTIVATION_CLOSING":
|
|
82
|
+
case "ACTIVATION_LIMIT_REACHED":
|
|
116
83
|
case "CONTINUATION_UNAVAILABLE":
|
|
117
84
|
case "PERSISTENCE_UNAVAILABLE": throw new RemoteError("subagent/delivery-unavailable", "subagent follow-up is temporarily unavailable", { childSessionId }, { cause: error });
|
|
118
85
|
default: break;
|
|
@@ -383,9 +350,10 @@ function epochStopReason(events) {
|
|
|
383
350
|
case "blocked": return "refusal";
|
|
384
351
|
case void 0:
|
|
385
352
|
case "completed": return droppedUnrun ? "aborted" : "completed";
|
|
386
|
-
/* v8 ignore next
|
|
387
|
-
*
|
|
388
|
-
*
|
|
353
|
+
/* v8 ignore next 4 -- `forked` appears only in constructor seed history, while
|
|
354
|
+
* this function reads an epoch-owned suffix. `TurnEndReason` is merge-extensible,
|
|
355
|
+
* so a backend-added variant cannot be listed; treating an unnameable reason as
|
|
356
|
+
* success would report failed work as completed. */
|
|
389
357
|
default: return "error";
|
|
390
358
|
}
|
|
391
359
|
}
|
|
@@ -752,6 +720,19 @@ var SubagentInbox = class {
|
|
|
752
720
|
*
|
|
753
721
|
* @module @deepseek-ai/dsh-subagent/continuation-activation
|
|
754
722
|
*/
|
|
723
|
+
/** Process-local slots shared through uninterrupted continuable parent links. */
|
|
724
|
+
var ActivationPool = class {
|
|
725
|
+
slots = /* @__PURE__ */ new Set();
|
|
726
|
+
/** Reserve before reconstruction; the returned release also tolerates unpublished rollback. */
|
|
727
|
+
reserve(capacity) {
|
|
728
|
+
if (this.slots.size >= capacity) throw new SubagentError(`subagent limit reached (active child limit: ${capacity}); wait for an existing child to finish or complete this work with the current agents`, "ACTIVATION_LIMIT_REACHED");
|
|
729
|
+
const slot = Symbol();
|
|
730
|
+
this.slots.add(slot);
|
|
731
|
+
return () => {
|
|
732
|
+
this.slots.delete(slot);
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
};
|
|
755
736
|
/** Serialize each durable child's delivery, release, and disposal. */
|
|
756
737
|
var ChildLock = class {
|
|
757
738
|
tails = /* @__PURE__ */ new Map();
|
|
@@ -775,8 +756,11 @@ var ChildLock = class {
|
|
|
775
756
|
var ContinuableActivationRegistry = class {
|
|
776
757
|
ctx;
|
|
777
758
|
observeActivation;
|
|
759
|
+
maxActiveSubagents;
|
|
778
760
|
/** Child session id → its live Activation. Process-local, never durable. */
|
|
779
761
|
resident = /* @__PURE__ */ new Map();
|
|
762
|
+
/** Root identities retain their pool across child settlement without retaining dead roots. */
|
|
763
|
+
rootPools = /* @__PURE__ */ new WeakMap();
|
|
780
764
|
/** Materializations admitted before drain, tracked through publication or rollback. */
|
|
781
765
|
materializations = /* @__PURE__ */ new Set();
|
|
782
766
|
/** Per-child serializer shared by delivery, release, and disposal. */
|
|
@@ -796,9 +780,10 @@ var ContinuableActivationRegistry = class {
|
|
|
796
780
|
* @param ctx - context providing Agents, Sessions, and teardown ownership.
|
|
797
781
|
* @param observeActivation - build the lifecycle observer for one residency epoch.
|
|
798
782
|
*/
|
|
799
|
-
constructor(ctx, observeActivation) {
|
|
783
|
+
constructor(ctx, observeActivation, maxActiveSubagents) {
|
|
800
784
|
this.ctx = ctx;
|
|
801
785
|
this.observeActivation = observeActivation;
|
|
786
|
+
this.maxActiveSubagents = maxActiveSubagents;
|
|
802
787
|
const scope = ctx.plugin(function activationOwner() {});
|
|
803
788
|
this.ownerCtx = scope.ctx;
|
|
804
789
|
ctx.on("agent/disposed", ({ agent }) => {
|
|
@@ -979,14 +964,20 @@ var ContinuableActivationRegistry = class {
|
|
|
979
964
|
*/
|
|
980
965
|
materialize(inputs) {
|
|
981
966
|
this.assertAdmitting(inputs.parent);
|
|
982
|
-
|
|
967
|
+
inputs.signal.throwIfAborted();
|
|
983
968
|
const lineage = this.liveLineage(inputs.parent);
|
|
969
|
+
const pool = this.resident.get(inputs.parent.id)?.pool ?? this.rootPool(inputs.parent);
|
|
970
|
+
const releaseSlot = pool.reserve(this.maxActiveSubagents());
|
|
971
|
+
const settled = Promise.withResolvers();
|
|
984
972
|
const materialization = {
|
|
985
973
|
lineage,
|
|
986
974
|
settled: settled.promise
|
|
987
975
|
};
|
|
988
976
|
this.materializations.add(materialization);
|
|
989
|
-
return this.materializeTracked(inputs, lineage).
|
|
977
|
+
return this.materializeTracked(inputs, lineage, pool, releaseSlot).catch((error) => {
|
|
978
|
+
releaseSlot();
|
|
979
|
+
throw error;
|
|
980
|
+
}).finally(() => {
|
|
990
981
|
this.materializations.delete(materialization);
|
|
991
982
|
settled.resolve();
|
|
992
983
|
});
|
|
@@ -1061,8 +1052,17 @@ var ContinuableActivationRegistry = class {
|
|
|
1061
1052
|
const lineage = this.liveLineage(agent);
|
|
1062
1053
|
for (const [root, members] of this.closingScopes) if (members.has(agent) || lineage.includes(root)) return root;
|
|
1063
1054
|
}
|
|
1055
|
+
/** Resolve a root's pool once; descendants inherit their resident parent's pool directly. */
|
|
1056
|
+
rootPool(parent) {
|
|
1057
|
+
let pool = this.rootPools.get(parent);
|
|
1058
|
+
if (pool === void 0) {
|
|
1059
|
+
pool = new ActivationPool();
|
|
1060
|
+
this.rootPools.set(parent, pool);
|
|
1061
|
+
}
|
|
1062
|
+
return pool;
|
|
1063
|
+
}
|
|
1064
1064
|
/** Perform one tracked materialization through publication or rollback. */
|
|
1065
|
-
async materializeTracked(inputs, parentLineage) {
|
|
1065
|
+
async materializeTracked(inputs, parentLineage, pool, releaseSlot) {
|
|
1066
1066
|
const { childId, provider, parent, create } = inputs;
|
|
1067
1067
|
inputs.signal.throwIfAborted();
|
|
1068
1068
|
const setup = (childCtx, child) => {
|
|
@@ -1090,6 +1090,8 @@ var ContinuableActivationRegistry = class {
|
|
|
1090
1090
|
setup
|
|
1091
1091
|
});
|
|
1092
1092
|
const activation = {
|
|
1093
|
+
pool,
|
|
1094
|
+
releaseSlot,
|
|
1093
1095
|
childId,
|
|
1094
1096
|
parentSession: parent.id,
|
|
1095
1097
|
provider,
|
|
@@ -1128,6 +1130,7 @@ var ContinuableActivationRegistry = class {
|
|
|
1128
1130
|
await activation.handle.dispose();
|
|
1129
1131
|
} finally {
|
|
1130
1132
|
this.resident.delete(activation.childId);
|
|
1133
|
+
activation.releaseSlot();
|
|
1131
1134
|
this.releaseOwnership(activation.childId);
|
|
1132
1135
|
}
|
|
1133
1136
|
});
|
|
@@ -1241,6 +1244,7 @@ var ContinuableActivationRegistry = class {
|
|
|
1241
1244
|
if (failures.length === 1) failure = failures[0];
|
|
1242
1245
|
else if (failures.length > 1) failure = new SubagentError(`subagent "${childId}" activation teardown failed at ${failures.length} boundaries: ` + failures.map((item) => errorChain(item)).join("; "), "ACTIVATION_TEARDOWN_FAILED", { cause: new AggregateError(failures) });
|
|
1243
1246
|
this.resident.delete(childId);
|
|
1247
|
+
activation.releaseSlot();
|
|
1244
1248
|
this.notifySettlement(activation, activation.observer.terminal(failure));
|
|
1245
1249
|
this.releaseOwnership(childId);
|
|
1246
1250
|
activation.observer.settle(failure);
|
|
@@ -1432,49 +1436,68 @@ function foldSubagentDescriptor(events) {
|
|
|
1432
1436
|
if (event === void 0) return void 0;
|
|
1433
1437
|
return parseSubagentDescriptor(event.data);
|
|
1434
1438
|
}
|
|
1435
|
-
const sessionIdSchema = z.string();
|
|
1436
|
-
const oneShotCatalogSchema = z.object({
|
|
1437
|
-
version: z.literal(0),
|
|
1439
|
+
const sessionIdSchema = z$1.string();
|
|
1440
|
+
const oneShotCatalogSchema = z$1.object({
|
|
1441
|
+
version: z$1.union([z$1.literal(0), z$1.literal(1)]),
|
|
1438
1442
|
childId: sessionIdSchema,
|
|
1439
|
-
childCreatedAt: z.number().int().nonnegative(),
|
|
1440
|
-
mode: z.literal("one-shot"),
|
|
1441
|
-
label: z.string().optional()
|
|
1443
|
+
childCreatedAt: z$1.number().int().nonnegative(),
|
|
1444
|
+
mode: z$1.literal("one-shot"),
|
|
1445
|
+
label: z$1.string().optional()
|
|
1442
1446
|
}).strict();
|
|
1443
|
-
const continuableCatalogSchema = z.object({
|
|
1444
|
-
version: z.literal(0),
|
|
1447
|
+
const continuableCatalogSchema = z$1.object({
|
|
1448
|
+
version: z$1.union([z$1.literal(0), z$1.literal(1)]),
|
|
1445
1449
|
childId: sessionIdSchema,
|
|
1446
|
-
childCreatedAt: z.number().int().nonnegative(),
|
|
1447
|
-
mode: z.literal("continuable"),
|
|
1448
|
-
label: z.string()
|
|
1450
|
+
childCreatedAt: z$1.number().int().nonnegative(),
|
|
1451
|
+
mode: z$1.literal("continuable"),
|
|
1452
|
+
label: z$1.string()
|
|
1449
1453
|
}).strict();
|
|
1450
|
-
const
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1454
|
+
const unknownCatalogSchema = oneShotCatalogSchema.extend({
|
|
1455
|
+
version: z$1.literal(1),
|
|
1456
|
+
mode: z$1.literal("unknown")
|
|
1457
|
+
});
|
|
1458
|
+
const eventDataSchema = z$1.union([
|
|
1459
|
+
oneShotCatalogSchema,
|
|
1460
|
+
continuableCatalogSchema,
|
|
1461
|
+
unknownCatalogSchema
|
|
1462
|
+
]);
|
|
1463
|
+
const viewSchema = z$1.array(z$1.union([
|
|
1464
|
+
oneShotCatalogSchema.omit({
|
|
1465
|
+
version: true,
|
|
1466
|
+
childId: true,
|
|
1467
|
+
childCreatedAt: true
|
|
1468
|
+
}).extend({
|
|
1469
|
+
id: sessionIdSchema,
|
|
1470
|
+
createdAt: oneShotCatalogSchema.shape.childCreatedAt
|
|
1471
|
+
}),
|
|
1472
|
+
continuableCatalogSchema.omit({
|
|
1473
|
+
version: true,
|
|
1474
|
+
childId: true,
|
|
1475
|
+
childCreatedAt: true
|
|
1476
|
+
}).extend({
|
|
1477
|
+
id: sessionIdSchema,
|
|
1478
|
+
createdAt: continuableCatalogSchema.shape.childCreatedAt
|
|
1479
|
+
}),
|
|
1480
|
+
unknownCatalogSchema.omit({
|
|
1481
|
+
version: true,
|
|
1482
|
+
childId: true,
|
|
1483
|
+
childCreatedAt: true
|
|
1484
|
+
}).extend({
|
|
1485
|
+
id: sessionIdSchema,
|
|
1486
|
+
createdAt: unknownCatalogSchema.shape.childCreatedAt
|
|
1487
|
+
})
|
|
1488
|
+
]));
|
|
1489
|
+
const stateSchema = z$1.object({
|
|
1490
|
+
inheritedEventCount: z$1.number().int().nonnegative(),
|
|
1468
1491
|
head: chunkedListSchema(eventDataSchema).optional()
|
|
1469
1492
|
}).strict();
|
|
1470
1493
|
/**
|
|
1471
|
-
* Materialize
|
|
1494
|
+
* Materialize complete and unknown-mode child identities from parent catalog events.
|
|
1472
1495
|
* @param state - parent catalog fold state.
|
|
1473
1496
|
* @returns current direct-child rows in parent catalog event order.
|
|
1474
1497
|
*/
|
|
1475
1498
|
function subagentCatalogEntries(state) {
|
|
1476
1499
|
const entries = [];
|
|
1477
|
-
for (const data of iterateChunkedList(state.head)) entries.push(data.mode
|
|
1500
|
+
for (const data of iterateChunkedList(state.head)) entries.push(data.mode !== "continuable" ? {
|
|
1478
1501
|
id: data.childId,
|
|
1479
1502
|
createdAt: data.childCreatedAt,
|
|
1480
1503
|
mode: data.mode,
|
|
@@ -1499,7 +1522,7 @@ const subagentCatalogProjectionDefinition = {
|
|
|
1499
1522
|
head: appendChunkedList(state.head, eventDataSchema.parse(event.data))
|
|
1500
1523
|
};
|
|
1501
1524
|
},
|
|
1502
|
-
stateVersion:
|
|
1525
|
+
stateVersion: 3,
|
|
1503
1526
|
wire: {
|
|
1504
1527
|
viewSchema,
|
|
1505
1528
|
view: subagentCatalogEntries
|
|
@@ -1565,7 +1588,7 @@ const deliverSubagentPrompt = Symbol.for("dsh.subagent.deliverPrompt");
|
|
|
1565
1588
|
*
|
|
1566
1589
|
* @module @deepseek-ai/dsh-subagent
|
|
1567
1590
|
*/
|
|
1568
|
-
var __addDisposableResource$
|
|
1591
|
+
var __addDisposableResource$2 = function(env, value, async) {
|
|
1569
1592
|
if (value !== null && value !== void 0) {
|
|
1570
1593
|
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
1571
1594
|
var dispose, inner;
|
|
@@ -1594,7 +1617,7 @@ var __addDisposableResource$1 = function(env, value, async) {
|
|
|
1594
1617
|
} else if (async) env.stack.push({ async: true });
|
|
1595
1618
|
return value;
|
|
1596
1619
|
};
|
|
1597
|
-
var __disposeResources$
|
|
1620
|
+
var __disposeResources$2 = (function(SuppressedError) {
|
|
1598
1621
|
return function(env) {
|
|
1599
1622
|
function fail(e) {
|
|
1600
1623
|
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
@@ -1633,10 +1656,10 @@ var SubagentContinuationManager = class {
|
|
|
1633
1656
|
ctx;
|
|
1634
1657
|
host;
|
|
1635
1658
|
activations;
|
|
1636
|
-
constructor(ctx, host) {
|
|
1659
|
+
constructor(ctx, host, maxActiveSubagents) {
|
|
1637
1660
|
this.ctx = ctx;
|
|
1638
1661
|
this.host = host;
|
|
1639
|
-
this.activations = new ContinuableActivationRegistry(ctx, (provider, childId, parent) => host.observeActivation(provider, childId, parent));
|
|
1662
|
+
this.activations = new ContinuableActivationRegistry(ctx, (provider, childId, parent) => host.observeActivation(provider, childId, parent), maxActiveSubagents);
|
|
1640
1663
|
}
|
|
1641
1664
|
/**
|
|
1642
1665
|
* Start one continuable background child and resolve at initial inbox acceptance.
|
|
@@ -1887,7 +1910,7 @@ var SubagentContinuationManager = class {
|
|
|
1887
1910
|
options.signal.throwIfAborted();
|
|
1888
1911
|
throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error });
|
|
1889
1912
|
}
|
|
1890
|
-
const source = __addDisposableResource$
|
|
1913
|
+
const source = __addDisposableResource$2(env_1, observation, false);
|
|
1891
1914
|
this.activations.assertAdmitting(parent);
|
|
1892
1915
|
this.activations.authorizeLineage(parent, childId, source.header.parentSession);
|
|
1893
1916
|
const descriptor = foldSubagentDescriptor(source.events.slice(source.inheritedEventCount));
|
|
@@ -1919,7 +1942,7 @@ var SubagentContinuationManager = class {
|
|
|
1919
1942
|
env_1.error = e_1;
|
|
1920
1943
|
env_1.hasError = true;
|
|
1921
1944
|
} finally {
|
|
1922
|
-
__disposeResources$
|
|
1945
|
+
__disposeResources$2(env_1);
|
|
1923
1946
|
}
|
|
1924
1947
|
}
|
|
1925
1948
|
/** Admit a materialized child, commit its creation fact, and release it on failure. */
|
|
@@ -1976,24 +1999,15 @@ var SubagentContinuationManager = class {
|
|
|
1976
1999
|
//#endregion
|
|
1977
2000
|
//#region lib/types/list-children.js
|
|
1978
2001
|
/**
|
|
1979
|
-
*
|
|
1980
|
-
*
|
|
1981
|
-
*
|
|
1982
|
-
*
|
|
1983
|
-
*
|
|
1984
|
-
* an unseeded durable projection-cache row, and one shared Session observation
|
|
1985
|
-
* otherwise. A seeded header deliberately lacks its exact inherited cut, so
|
|
1986
|
-
* it takes the body-bearing observation path before classifying an identity.
|
|
1987
|
-
* The projection fold is the single classification
|
|
1988
|
-
* authority — this module parses no descriptor
|
|
1989
|
-
* itself. Absent persistence, enumeration is live-only: a cold child is
|
|
1990
|
-
* unreachable for resume anyway, so its absence is capability absence, not an
|
|
1991
|
-
* error. The module owns no catalog state and does not consult Activation,
|
|
1992
|
-
* Agent-registry, continuation-manager, or provider state.
|
|
2002
|
+
* Direct-child discovery from a parent-owned `subagent/catalog` projection,
|
|
2003
|
+
* plus complete descendant-tree enumeration from the Session corpus. A direct
|
|
2004
|
+
* listing owns one parent observation and reads no child log. Descendant
|
|
2005
|
+
* enumeration retains the complete corpus and the child identity projection
|
|
2006
|
+
* because ordinary Sessions and one-shot children remain traversal nodes.
|
|
1993
2007
|
*
|
|
1994
2008
|
* @module @deepseek-ai/dsh-subagent
|
|
1995
2009
|
*/
|
|
1996
|
-
var __addDisposableResource = function(env, value, async) {
|
|
2010
|
+
var __addDisposableResource$1 = function(env, value, async) {
|
|
1997
2011
|
if (value !== null && value !== void 0) {
|
|
1998
2012
|
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
1999
2013
|
var dispose, inner;
|
|
@@ -2022,7 +2036,7 @@ var __addDisposableResource = function(env, value, async) {
|
|
|
2022
2036
|
} else if (async) env.stack.push({ async: true });
|
|
2023
2037
|
return value;
|
|
2024
2038
|
};
|
|
2025
|
-
var __disposeResources = (function(SuppressedError) {
|
|
2039
|
+
var __disposeResources$1 = (function(SuppressedError) {
|
|
2026
2040
|
return function(env) {
|
|
2027
2041
|
function fail(e) {
|
|
2028
2042
|
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
@@ -2058,37 +2072,43 @@ var __disposeResources = (function(SuppressedError) {
|
|
|
2058
2072
|
*/
|
|
2059
2073
|
const COLD_READ_CONCURRENCY = 4;
|
|
2060
2074
|
/**
|
|
2061
|
-
*
|
|
2062
|
-
*
|
|
2063
|
-
*
|
|
2064
|
-
*
|
|
2065
|
-
*
|
|
2066
|
-
*
|
|
2067
|
-
* @see SubagentRuntime.listChildren for the public cancellation and failure contract.
|
|
2068
|
-
* @param ctx - context carrying the session store, the projection registry,
|
|
2069
|
-
* optional persistence, and the optional projection cache.
|
|
2070
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
2071
|
-
* @param signal - caller-owned cancellation observed around every persistence read.
|
|
2072
|
-
* @returns children and per-child diagnostics ordered by `createdAt`, then id.
|
|
2073
|
-
* @throws {@link SubagentError} when the projection registry or the session
|
|
2074
|
-
* store is not mounted, or the caller cancels the listing.
|
|
2075
|
+
* Read one parent's durable catalog through a live-preferred Session observation.
|
|
2076
|
+
* @param ctx - context carrying the Session query service.
|
|
2077
|
+
* @param parentSessionId - parent whose direct children are requested.
|
|
2078
|
+
* @param signal - cancellation forwarded to the Session observation.
|
|
2079
|
+
* @returns direct-child rows in parent catalog event order.
|
|
2080
|
+
* @throws {@link SubagentError} when query or catalog projection is unavailable.
|
|
2075
2081
|
*/
|
|
2076
2082
|
async function listChildren(ctx, parentSessionId, signal) {
|
|
2077
|
-
const
|
|
2078
|
-
|
|
2083
|
+
const env_1 = {
|
|
2084
|
+
stack: [],
|
|
2085
|
+
error: void 0,
|
|
2086
|
+
hasError: false
|
|
2087
|
+
};
|
|
2088
|
+
try {
|
|
2089
|
+
const query = ctx.get("sessionQuery");
|
|
2090
|
+
if (query === void 0) throw new SubagentError("listing subagents requires the sessionQuery service (load @deepseek-ai/dsh-session-query)", "SUBAGENT_CONTROL_QUERY_UNAVAILABLE");
|
|
2091
|
+
const entries = __addDisposableResource$1(env_1, await query.observeSession(parentSessionId, { ...signal === void 0 ? {} : { signal } }), false).projections?.values.subagentCatalog;
|
|
2092
|
+
if (entries === void 0) throw new SubagentError("listing subagents requires the registered subagentCatalog projection", "SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE");
|
|
2093
|
+
return entries;
|
|
2094
|
+
} catch (e_1) {
|
|
2095
|
+
env_1.error = e_1;
|
|
2096
|
+
env_1.hasError = true;
|
|
2097
|
+
} finally {
|
|
2098
|
+
__disposeResources$1(env_1);
|
|
2099
|
+
}
|
|
2079
2100
|
}
|
|
2080
2101
|
/**
|
|
2081
2102
|
* Enumerate every session-backed subagent below one root in stable pre-order.
|
|
2082
2103
|
* Ordinary sessions and one-shot children remain traversal nodes, so a
|
|
2083
2104
|
* continuable child below either is still discovered. Classification uses the
|
|
2084
|
-
*
|
|
2085
|
-
* resumed.
|
|
2105
|
+
* registered child identity projection; no Agent is loaded or resumed.
|
|
2086
2106
|
* @see SubagentRuntime.listDescendants for the public cancellation and failure contract.
|
|
2087
2107
|
* @param ctx - context carrying the session store, projection registry, and optional persistence/cache.
|
|
2088
2108
|
* @param rootSessionId - session whose complete descendant tree is listed.
|
|
2089
2109
|
* @param signal - caller-owned cancellation observed around every persistence read.
|
|
2090
2110
|
* @returns interpreted subagents with durable direct-parent and root-relative depth.
|
|
2091
|
-
* @throws {@link SubagentError}
|
|
2111
|
+
* @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
|
|
2092
2112
|
*/
|
|
2093
2113
|
async function listDescendants(ctx, rootSessionId, signal) {
|
|
2094
2114
|
const listing = await prepareListing(ctx, signal);
|
|
@@ -2224,7 +2244,7 @@ function compareCorpusRecords(a, b) {
|
|
|
2224
2244
|
* throw — are final, so they report `corrupt`.
|
|
2225
2245
|
*/
|
|
2226
2246
|
async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
2227
|
-
const
|
|
2247
|
+
const env_2 = {
|
|
2228
2248
|
stack: [],
|
|
2229
2249
|
error: void 0,
|
|
2230
2250
|
hasError: false
|
|
@@ -2234,7 +2254,7 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
2234
2254
|
if (cache !== void 0 && !header.isSeeded) {
|
|
2235
2255
|
let cached;
|
|
2236
2256
|
try {
|
|
2237
|
-
cached = cache.cachedSnapshot(header,
|
|
2257
|
+
cached = cache.cachedSnapshot(header, ["subagent"])?.values.subagent;
|
|
2238
2258
|
} catch {
|
|
2239
2259
|
cached = void 0;
|
|
2240
2260
|
}
|
|
@@ -2252,7 +2272,7 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
2252
2272
|
reason: sessionQueryCode(error) === "SESSION_QUERY_CORRUPT_SESSION" || sessionQueryCode(error) === "SESSION_QUERY_SOURCE_CONFLICT" ? "corrupt" : "unavailable"
|
|
2253
2273
|
};
|
|
2254
2274
|
}
|
|
2255
|
-
const ownedObservation = __addDisposableResource(
|
|
2275
|
+
const ownedObservation = __addDisposableResource$1(env_2, observation, false);
|
|
2256
2276
|
assertListingNotCancelled(signal);
|
|
2257
2277
|
if (!sameLifecycle(ownedObservation.header, header)) return {
|
|
2258
2278
|
kind: "diagnostic",
|
|
@@ -2266,11 +2286,11 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
2266
2286
|
reason: "corrupt"
|
|
2267
2287
|
};
|
|
2268
2288
|
return childRow(childId, identity, "inactive", hasChildren);
|
|
2269
|
-
} catch (
|
|
2270
|
-
|
|
2271
|
-
|
|
2289
|
+
} catch (e_2) {
|
|
2290
|
+
env_2.error = e_2;
|
|
2291
|
+
env_2.hasError = true;
|
|
2272
2292
|
} finally {
|
|
2273
|
-
__disposeResources(
|
|
2293
|
+
__disposeResources$1(env_2);
|
|
2274
2294
|
}
|
|
2275
2295
|
}
|
|
2276
2296
|
/** Materialize one served identity as its child row. */
|
|
@@ -2315,6 +2335,159 @@ function sessionQueryCode(error) {
|
|
|
2315
2335
|
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
2316
2336
|
}
|
|
2317
2337
|
//#endregion
|
|
2338
|
+
//#region lib/types/archive-admission.js
|
|
2339
|
+
/**
|
|
2340
|
+
* The `subagent` family of the Workspace registry's archive admission: which
|
|
2341
|
+
* subagent descendants of a Session are still inside a turn, and how they
|
|
2342
|
+
* stop when the Session is archived with its work.
|
|
2343
|
+
*
|
|
2344
|
+
* @module @deepseek-ai/dsh-subagent
|
|
2345
|
+
*/
|
|
2346
|
+
var __addDisposableResource = function(env, value, async) {
|
|
2347
|
+
if (value !== null && value !== void 0) {
|
|
2348
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
2349
|
+
var dispose, inner;
|
|
2350
|
+
if (async) {
|
|
2351
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
2352
|
+
dispose = value[Symbol.asyncDispose];
|
|
2353
|
+
}
|
|
2354
|
+
if (dispose === void 0) {
|
|
2355
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
2356
|
+
dispose = value[Symbol.dispose];
|
|
2357
|
+
if (async) inner = dispose;
|
|
2358
|
+
}
|
|
2359
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
2360
|
+
if (inner) dispose = function() {
|
|
2361
|
+
try {
|
|
2362
|
+
inner.call(this);
|
|
2363
|
+
} catch (e) {
|
|
2364
|
+
return Promise.reject(e);
|
|
2365
|
+
}
|
|
2366
|
+
};
|
|
2367
|
+
env.stack.push({
|
|
2368
|
+
value,
|
|
2369
|
+
dispose,
|
|
2370
|
+
async
|
|
2371
|
+
});
|
|
2372
|
+
} else if (async) env.stack.push({ async: true });
|
|
2373
|
+
return value;
|
|
2374
|
+
};
|
|
2375
|
+
var __disposeResources = (function(SuppressedError) {
|
|
2376
|
+
return function(env) {
|
|
2377
|
+
function fail(e) {
|
|
2378
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
2379
|
+
env.hasError = true;
|
|
2380
|
+
}
|
|
2381
|
+
var r, s = 0;
|
|
2382
|
+
function next() {
|
|
2383
|
+
while (r = env.stack.pop()) try {
|
|
2384
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
2385
|
+
if (r.dispose) {
|
|
2386
|
+
var result = r.dispose.call(r.value);
|
|
2387
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
2388
|
+
fail(e);
|
|
2389
|
+
return next();
|
|
2390
|
+
});
|
|
2391
|
+
} else s |= 1;
|
|
2392
|
+
} catch (e) {
|
|
2393
|
+
fail(e);
|
|
2394
|
+
}
|
|
2395
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
2396
|
+
if (env.hasError) throw env.error;
|
|
2397
|
+
}
|
|
2398
|
+
return next();
|
|
2399
|
+
};
|
|
2400
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
2401
|
+
var e = new Error(message);
|
|
2402
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
2403
|
+
});
|
|
2404
|
+
/**
|
|
2405
|
+
* Answer `workspace/session-activity` with the running subagent descendants of
|
|
2406
|
+
* the asked Session, and `workspace/session-stop` by cancelling each of them
|
|
2407
|
+
* as their parent would. Both listeners live as long as `ctx`'s fiber.
|
|
2408
|
+
* @param ctx - context carrying the Agent registry; the Session query service is optional and only supplies labels.
|
|
2409
|
+
*/
|
|
2410
|
+
function installSubagentArchiveAdmission(ctx) {
|
|
2411
|
+
ctx.on("workspace/session-activity", async ({ sessionId }, next) => {
|
|
2412
|
+
const running = runningDescendants(ctx, sessionId);
|
|
2413
|
+
const rest = await next();
|
|
2414
|
+
if (running.length === 0) return rest;
|
|
2415
|
+
return [{
|
|
2416
|
+
kind: "subagent",
|
|
2417
|
+
items: await Promise.all(running.map((child) => describe(ctx, child)))
|
|
2418
|
+
}, ...rest];
|
|
2419
|
+
});
|
|
2420
|
+
ctx.on("workspace/session-stop", ({ sessionId }) => {
|
|
2421
|
+
for (const child of runningDescendants(ctx, sessionId)) try {
|
|
2422
|
+
child.cancel({ kind: "parent" });
|
|
2423
|
+
} catch (error) {
|
|
2424
|
+
ctx.logger.warn(`subagent: cancelling "${child.id}" for an archived Session failed: ${String(error)}`);
|
|
2425
|
+
}
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
/**
|
|
2429
|
+
* Live subagent descendants inside a turn, by durable lineage: a child whose
|
|
2430
|
+
* header names its parent and carries the subagent origin this package
|
|
2431
|
+
* records, at any depth. A fork shares the lineage field without the origin
|
|
2432
|
+
* and is an independent conversation, so it never holds its source. Lineage
|
|
2433
|
+
* is read as data, so a damaged header chain that loops is visited once.
|
|
2434
|
+
*/
|
|
2435
|
+
function runningDescendants(ctx, rootId) {
|
|
2436
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
2437
|
+
for (const agent of ctx.agents.list()) {
|
|
2438
|
+
const { parentSession, origin } = agent.session.header;
|
|
2439
|
+
if (parentSession === void 0 || origin !== "subagent") continue;
|
|
2440
|
+
const siblings = childrenOf.get(parentSession) ?? [];
|
|
2441
|
+
siblings.push(agent);
|
|
2442
|
+
childrenOf.set(parentSession, siblings);
|
|
2443
|
+
}
|
|
2444
|
+
const running = [];
|
|
2445
|
+
const pending = [rootId];
|
|
2446
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2447
|
+
while (pending.length > 0) {
|
|
2448
|
+
const parentId = pending.shift();
|
|
2449
|
+
if (visited.has(parentId)) continue;
|
|
2450
|
+
visited.add(parentId);
|
|
2451
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
2452
|
+
if (child.status === "running") running.push(child);
|
|
2453
|
+
pending.push(child.id);
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
return running;
|
|
2457
|
+
}
|
|
2458
|
+
/**
|
|
2459
|
+
* The child's activity item: its id, plus the durable creation label its
|
|
2460
|
+
* descriptor carries, read through a live Session observation. Without the
|
|
2461
|
+
* Session query service, or with a descriptor that is absent or unreadable,
|
|
2462
|
+
* the item names the child by id alone.
|
|
2463
|
+
*/
|
|
2464
|
+
async function describe(ctx, child) {
|
|
2465
|
+
const query = ctx.get("sessionQuery");
|
|
2466
|
+
if (query === void 0) return { id: child.id };
|
|
2467
|
+
try {
|
|
2468
|
+
const env_1 = {
|
|
2469
|
+
stack: [],
|
|
2470
|
+
error: void 0,
|
|
2471
|
+
hasError: false
|
|
2472
|
+
};
|
|
2473
|
+
try {
|
|
2474
|
+
const observation = __addDisposableResource(env_1, await query.observeSession(child.id, { projectionMode: "none" }), false);
|
|
2475
|
+
const label = foldSubagentDescriptor(observation.events.slice(observation.inheritedEventCount))?.label;
|
|
2476
|
+
return label === void 0 ? { id: child.id } : {
|
|
2477
|
+
id: child.id,
|
|
2478
|
+
label
|
|
2479
|
+
};
|
|
2480
|
+
} catch (e_1) {
|
|
2481
|
+
env_1.error = e_1;
|
|
2482
|
+
env_1.hasError = true;
|
|
2483
|
+
} finally {
|
|
2484
|
+
__disposeResources(env_1);
|
|
2485
|
+
}
|
|
2486
|
+
} catch {
|
|
2487
|
+
return { id: child.id };
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
//#endregion
|
|
2318
2491
|
//#region lib/types/projection.js
|
|
2319
2492
|
/**
|
|
2320
2493
|
* Pure session projections for subagent identity (mode/label) and active-turn
|
|
@@ -2322,16 +2495,18 @@ function sessionQueryCode(error) {
|
|
|
2322
2495
|
*
|
|
2323
2496
|
* @module @deepseek-ai/dsh-subagent/projection
|
|
2324
2497
|
*/
|
|
2325
|
-
const activeIntervalSchema = z.object({
|
|
2326
|
-
since: z.number().int().nonnegative(),
|
|
2327
|
-
through: z.number().int().nonnegative()
|
|
2498
|
+
const activeIntervalSchema = z$1.object({
|
|
2499
|
+
since: z$1.number().int().nonnegative(),
|
|
2500
|
+
through: z$1.number().int().nonnegative()
|
|
2328
2501
|
}).strict();
|
|
2329
|
-
const projectionSchema = z.object({
|
|
2330
|
-
settledMs: z.number().int().nonnegative(),
|
|
2331
|
-
active: activeIntervalSchema.optional()
|
|
2332
|
-
|
|
2502
|
+
const projectionSchema = z$1.object({
|
|
2503
|
+
settledMs: z$1.number().int().nonnegative(),
|
|
2504
|
+
active: activeIntervalSchema.optional(),
|
|
2505
|
+
lastTurnCompleted: z$1.boolean().optional()
|
|
2506
|
+
}).strict().transform(({ settledMs, active, lastTurnCompleted }) => ({
|
|
2333
2507
|
settledMs,
|
|
2334
|
-
...active === void 0 ? {} : { active }
|
|
2508
|
+
...active === void 0 ? {} : { active },
|
|
2509
|
+
...lastTurnCompleted === void 0 ? {} : { lastTurnCompleted }
|
|
2335
2510
|
}));
|
|
2336
2511
|
/**
|
|
2337
2512
|
* Fold turn boundaries around the child's own durable descriptor.
|
|
@@ -2343,27 +2518,31 @@ const projectionSchema = z.object({
|
|
|
2343
2518
|
*/
|
|
2344
2519
|
const subagentTimingProjectionDefinition = {
|
|
2345
2520
|
key: "subagentTiming",
|
|
2346
|
-
stateSchema: z.object({
|
|
2347
|
-
settledMs: z.number().int().nonnegative(),
|
|
2521
|
+
stateSchema: z$1.object({
|
|
2522
|
+
settledMs: z$1.number().int().nonnegative(),
|
|
2348
2523
|
active: activeIntervalSchema.optional(),
|
|
2349
|
-
pendingTurnStart: z.number().int().nonnegative().optional(),
|
|
2350
|
-
descriptorSeen: z.boolean()
|
|
2524
|
+
pendingTurnStart: z$1.number().int().nonnegative().optional(),
|
|
2525
|
+
descriptorSeen: z$1.boolean(),
|
|
2526
|
+
lastTurnCompleted: z$1.boolean().optional()
|
|
2351
2527
|
}).strict(),
|
|
2352
2528
|
init: () => ({
|
|
2353
2529
|
descriptorSeen: false,
|
|
2354
2530
|
settledMs: 0
|
|
2355
2531
|
}),
|
|
2356
2532
|
apply: (state, event) => {
|
|
2357
|
-
if (event.type === "turn/start")
|
|
2358
|
-
...state
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2533
|
+
if (event.type === "turn/start") {
|
|
2534
|
+
const { lastTurnCompleted: _closed, ...openState } = state;
|
|
2535
|
+
return state.descriptorSeen ? {
|
|
2536
|
+
...openState,
|
|
2537
|
+
active: {
|
|
2538
|
+
since: event.time,
|
|
2539
|
+
through: event.time
|
|
2540
|
+
}
|
|
2541
|
+
} : {
|
|
2542
|
+
...openState,
|
|
2543
|
+
pendingTurnStart: event.time
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2367
2546
|
if (event.type === "subagent/descriptor") {
|
|
2368
2547
|
const activeSince = state.active?.since ?? state.pendingTurnStart;
|
|
2369
2548
|
return {
|
|
@@ -2385,7 +2564,8 @@ const subagentTimingProjectionDefinition = {
|
|
|
2385
2564
|
const { active, ...rest } = state;
|
|
2386
2565
|
return {
|
|
2387
2566
|
...rest,
|
|
2388
|
-
settledMs: state.settledMs + Math.max(0, event.time - active.since)
|
|
2567
|
+
settledMs: state.settledMs + Math.max(0, event.time - active.since),
|
|
2568
|
+
lastTurnCompleted: event.data.reason.kind === "completed"
|
|
2389
2569
|
};
|
|
2390
2570
|
}
|
|
2391
2571
|
if (state.active === void 0) return state;
|
|
@@ -2401,22 +2581,23 @@ const subagentTimingProjectionDefinition = {
|
|
|
2401
2581
|
viewSchema: projectionSchema,
|
|
2402
2582
|
view: (state) => ({
|
|
2403
2583
|
settledMs: state.settledMs,
|
|
2404
|
-
...state.active === void 0 ? {} : { active: state.active }
|
|
2584
|
+
...state.active === void 0 ? {} : { active: state.active },
|
|
2585
|
+
...state.lastTurnCompleted === void 0 ? {} : { lastTurnCompleted: state.lastTurnCompleted }
|
|
2405
2586
|
})
|
|
2406
2587
|
},
|
|
2407
|
-
stateVersion:
|
|
2588
|
+
stateVersion: 3
|
|
2408
2589
|
};
|
|
2409
|
-
const identityValueSchema = z.discriminatedUnion("mode", [z.object({
|
|
2410
|
-
mode: z.literal("one-shot"),
|
|
2411
|
-
label: z.string().optional(),
|
|
2412
|
-
seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
|
|
2413
|
-
}).strict(), z.object({
|
|
2414
|
-
mode: z.literal("continuable"),
|
|
2415
|
-
label: z.string(),
|
|
2416
|
-
seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
|
|
2590
|
+
const identityValueSchema = z$1.discriminatedUnion("mode", [z$1.object({
|
|
2591
|
+
mode: z$1.literal("one-shot"),
|
|
2592
|
+
label: z$1.string().optional(),
|
|
2593
|
+
seq: z$1.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
|
|
2594
|
+
}).strict(), z$1.object({
|
|
2595
|
+
mode: z$1.literal("continuable"),
|
|
2596
|
+
label: z$1.string(),
|
|
2597
|
+
seq: z$1.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
|
|
2417
2598
|
}).strict()]);
|
|
2418
2599
|
const identitySchema = identityValueSchema.nullable();
|
|
2419
|
-
const identityStateSchema = z.object({ identity: identityValueSchema.optional() }).strict();
|
|
2600
|
+
const identityStateSchema = z$1.object({ identity: identityValueSchema.optional() }).strict();
|
|
2420
2601
|
/** Interpret one `subagent/descriptor` event's identity; no value when the payload cannot be trusted. */
|
|
2421
2602
|
function descriptorIdentity(event) {
|
|
2422
2603
|
let descriptor;
|
|
@@ -2679,7 +2860,7 @@ function runOutcome(result) {
|
|
|
2679
2860
|
switch (result.stopReason) {
|
|
2680
2861
|
case "completed": return {
|
|
2681
2862
|
status: "completed",
|
|
2682
|
-
|
|
2863
|
+
result: finalText(result.output)
|
|
2683
2864
|
};
|
|
2684
2865
|
case "aborted": return result.diagnostic === void 0 ? { status: "killed" } : {
|
|
2685
2866
|
status: "failed",
|
|
@@ -2725,36 +2906,6 @@ async function settleRun(run) {
|
|
|
2725
2906
|
}
|
|
2726
2907
|
//#endregion
|
|
2727
2908
|
//#region lib/types/index.js
|
|
2728
|
-
/**
|
|
2729
|
-
* Service Definition for the subagent capability seam (`ctx.subagents`): a named-provider registry plus a
|
|
2730
|
-
* capability-validating asynchronous start API. Providers establish a
|
|
2731
|
-
* child before returning its run, so fulfillment is the single publication and
|
|
2732
|
-
* ownership-transfer boundary.
|
|
2733
|
-
*
|
|
2734
|
-
* Multiple providers coexist: each registers under a unique name and callers
|
|
2735
|
-
* select one by name.
|
|
2736
|
-
*
|
|
2737
|
-
* This package owns the Service Definition role of the capability seam. Service Providers
|
|
2738
|
-
* (`@deepseek-ai/dsh-subagent-spawn-in-process`, `-fork`, `-acp`) and the model-facing
|
|
2739
|
-
* consumer (`@deepseek-ai/dsh-tool-subagent`) are separate packages.
|
|
2740
|
-
*
|
|
2741
|
-
* Public operations express caller intent: `start` returns one published owned
|
|
2742
|
-
* one-shot run, `startContinuable` establishes a durable continuable child, and
|
|
2743
|
-
* `sendMessage` steers between adjacent Agents without exposing whether a child
|
|
2744
|
-
* is resident. Continuable children never become a {@link SubagentRun}: the
|
|
2745
|
-
* continuation manager holds their `AgentHandle` directly and orders every turn
|
|
2746
|
-
* through the child's own inbox, so providers contribute only the detached
|
|
2747
|
-
* creation spec and see no handle, turn, or teardown. Child and descendant
|
|
2748
|
-
* discovery read the live session store and optional session persistence
|
|
2749
|
-
* directly and do not require that continuation runtime.
|
|
2750
|
-
*
|
|
2751
|
-
* Same-process providers are trusted typed collaborators. Requests, provider
|
|
2752
|
-
* descriptors, results, and lifecycle payloads are borrowed immutable values;
|
|
2753
|
-
* serialization and hostile-input validation belong at real process, worker,
|
|
2754
|
-
* persistence, and model boundaries.
|
|
2755
|
-
*
|
|
2756
|
-
* @module @deepseek-ai/dsh-subagent
|
|
2757
|
-
*/
|
|
2758
2909
|
var __runInitializers = function(thisArg, initializers, value) {
|
|
2759
2910
|
var useValue = arguments.length > 2;
|
|
2760
2911
|
for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
@@ -2797,26 +2948,13 @@ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializ
|
|
|
2797
2948
|
let SubagentRuntime = (() => {
|
|
2798
2949
|
let _classSuper = TypertRemoteService;
|
|
2799
2950
|
let _instanceExtraInitializers = [];
|
|
2800
|
-
let _remoteExportList_decorators;
|
|
2801
2951
|
let _prompt_decorators;
|
|
2802
2952
|
let _interruptByParent_decorators;
|
|
2803
2953
|
return class SubagentRuntime extends _classSuper {
|
|
2804
2954
|
static {
|
|
2805
2955
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
2806
|
-
_remoteExportList_decorators = [Remote("list")];
|
|
2807
2956
|
_prompt_decorators = [Remote("prompt")];
|
|
2808
2957
|
_interruptByParent_decorators = [Remote("interruptByParent")];
|
|
2809
|
-
__esDecorate(this, null, _remoteExportList_decorators, {
|
|
2810
|
-
kind: "method",
|
|
2811
|
-
name: "remoteExportList",
|
|
2812
|
-
static: false,
|
|
2813
|
-
private: false,
|
|
2814
|
-
access: {
|
|
2815
|
-
has: (obj) => "remoteExportList" in obj,
|
|
2816
|
-
get: (obj) => obj.remoteExportList
|
|
2817
|
-
},
|
|
2818
|
-
metadata: _metadata
|
|
2819
|
-
}, null, _instanceExtraInitializers);
|
|
2820
2958
|
__esDecorate(this, null, _prompt_decorators, {
|
|
2821
2959
|
kind: "method",
|
|
2822
2960
|
name: "prompt",
|
|
@@ -2846,7 +2984,12 @@ let SubagentRuntime = (() => {
|
|
|
2846
2984
|
value: _metadata
|
|
2847
2985
|
});
|
|
2848
2986
|
}
|
|
2849
|
-
|
|
2987
|
+
config = __runInitializers(this, _instanceExtraInitializers);
|
|
2988
|
+
static Config = z.object({
|
|
2989
|
+
maxDepth: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(1).volatile(),
|
|
2990
|
+
maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8).volatile()
|
|
2991
|
+
});
|
|
2992
|
+
providers = /* @__PURE__ */ new Map();
|
|
2850
2993
|
continuations;
|
|
2851
2994
|
/**
|
|
2852
2995
|
* The contained lifecycle-edge publisher. Built here because scoped dispatch
|
|
@@ -2854,14 +2997,15 @@ let SubagentRuntime = (() => {
|
|
|
2854
2997
|
* composes into the carrier.
|
|
2855
2998
|
*/
|
|
2856
2999
|
emitLifecycle;
|
|
2857
|
-
constructor(ctx) {
|
|
3000
|
+
constructor(ctx, config) {
|
|
2858
3001
|
super(ctx, "subagents");
|
|
3002
|
+
this.config = config;
|
|
2859
3003
|
this.emitLifecycle = createLifecycleEmitter(this.ctx, (parent) => scopeTarget(this, parent));
|
|
2860
3004
|
ctx.inject(["agents"], (childCtx) => {
|
|
2861
3005
|
const manager = new SubagentContinuationManager(childCtx, {
|
|
2862
3006
|
prepareContinuable: (name, request) => this.prepareContinuable(name, request),
|
|
2863
3007
|
observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent)
|
|
2864
|
-
});
|
|
3008
|
+
}, () => this.config.maxActiveSubagents.get());
|
|
2865
3009
|
this.continuations = manager;
|
|
2866
3010
|
childCtx.effect(() => () => {
|
|
2867
3011
|
/* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
|
|
@@ -2869,10 +3013,26 @@ let SubagentRuntime = (() => {
|
|
|
2869
3013
|
}, "subagents.continuationBinding()");
|
|
2870
3014
|
});
|
|
2871
3015
|
ctx.inject(["sessionProjections"], (projectionCtx) => {
|
|
2872
|
-
projectionCtx.sessionProjections
|
|
2873
|
-
|
|
2874
|
-
|
|
3016
|
+
const projections = projectionCtx.sessionProjections;
|
|
3017
|
+
projections.register(subagentCatalogProjectionDefinition);
|
|
3018
|
+
projections.register(subagentTimingProjectionDefinition);
|
|
3019
|
+
projections.register(subagentIdentityProjectionDefinition);
|
|
2875
3020
|
});
|
|
3021
|
+
ctx.inject(["agents"], (agentsCtx) => {
|
|
3022
|
+
installSubagentArchiveAdmission(agentsCtx);
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
3025
|
+
/**
|
|
3026
|
+
* Resolve a delegation tool's depth policy against the current user setting.
|
|
3027
|
+
* @param configured - Explicit tool limit, or provider-managed for external delegation.
|
|
3028
|
+
* @returns The numeric limit, or undefined when the provider owns depth enforcement.
|
|
3029
|
+
*/
|
|
3030
|
+
resolveMaxDepth(configured) {
|
|
3031
|
+
if (configured === "provider-managed") return void 0;
|
|
3032
|
+
if (configured !== void 0) return configured;
|
|
3033
|
+
const depth = this.config.maxDepth.get();
|
|
3034
|
+
assertSubagentMaxDepth(depth);
|
|
3035
|
+
return depth;
|
|
2876
3036
|
}
|
|
2877
3037
|
/**
|
|
2878
3038
|
* Establish one durable continuable child and deliver its initial prompt.
|
|
@@ -2967,21 +3127,13 @@ let SubagentRuntime = (() => {
|
|
|
2967
3127
|
await manager.drainChildren(parent, childIds);
|
|
2968
3128
|
}
|
|
2969
3129
|
/**
|
|
2970
|
-
*
|
|
2971
|
-
*
|
|
2972
|
-
*
|
|
2973
|
-
*
|
|
2974
|
-
*
|
|
2975
|
-
*
|
|
2976
|
-
*
|
|
2977
|
-
* around each await. Read rejections that settle
|
|
2978
|
-
* after an abort become a stable `SubagentError` with code `CANCELLED`.
|
|
2979
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
2980
|
-
* @param signal - caller-owned cancellation forwarded to Session queries
|
|
2981
|
-
* and observed around every read await.
|
|
2982
|
-
* @returns children and per-child diagnostics ordered by `createdAt`, then id.
|
|
2983
|
-
* @throws {@link SubagentError} when the projection registry or the session
|
|
2984
|
-
* store is not mounted, or the caller cancels the listing.
|
|
3130
|
+
* Read the parent's durable direct-child catalog without loading or resuming an Agent.
|
|
3131
|
+
* The service owns and releases the live-preferred Session observation.
|
|
3132
|
+
* @param parentSessionId - parent whose direct children are requested.
|
|
3133
|
+
* @param signal - cancellation forwarded to the Session query.
|
|
3134
|
+
* @returns catalog children in parent event order.
|
|
3135
|
+
* @throws {@link SubagentError} when query or catalog projection is unavailable.
|
|
3136
|
+
* @throws SessionQueryError when the parent cannot be read or the query is cancelled.
|
|
2985
3137
|
*/
|
|
2986
3138
|
listChildren(parentSessionId, signal) {
|
|
2987
3139
|
return listChildren(this.ctx, parentSessionId, signal);
|
|
@@ -2992,40 +3144,19 @@ let SubagentRuntime = (() => {
|
|
|
2992
3144
|
* Agent. Ordinary sessions and one-shot children remain traversal nodes so
|
|
2993
3145
|
* continuable descendants below them are discovered; each returned entry
|
|
2994
3146
|
* adds its durable `parentId` and root-relative `depth`. Identity resolution,
|
|
2995
|
-
* diagnostics, optional persistence, and cancellation
|
|
2996
|
-
* projection
|
|
3147
|
+
* diagnostics, optional persistence, and cancellation use the registered
|
|
3148
|
+
* child identity projection and complete Session corpus.
|
|
2997
3149
|
* @param rootSessionId - session whose complete descendant tree is listed.
|
|
2998
3150
|
* @param signal - caller-owned cancellation forwarded to persistence reads
|
|
2999
3151
|
* and observed around every read await.
|
|
3000
3152
|
* @returns children and per-candidate diagnostics with tree position, in
|
|
3001
3153
|
* stable pre-order.
|
|
3002
|
-
* @throws {@link SubagentError}
|
|
3154
|
+
* @throws {@link SubagentError} when listing dependencies are unavailable or the caller cancels.
|
|
3003
3155
|
*/
|
|
3004
3156
|
listDescendants(rootSessionId, signal) {
|
|
3005
3157
|
return listDescendants(this.ctx, rootSessionId, signal);
|
|
3006
3158
|
}
|
|
3007
3159
|
/**
|
|
3008
|
-
* Remote face of {@link listChildren} for one browser: the durable listing
|
|
3009
|
-
* plus live Agent activity and the delivery-time parent availability hint.
|
|
3010
|
-
* Parent availability is a hint; {@link prompt} performs the authoritative
|
|
3011
|
-
* check. Named apart from the provider-name {@link list}, which owns the
|
|
3012
|
-
* member.
|
|
3013
|
-
* @param parentSessionId - parent session whose direct children are listed.
|
|
3014
|
-
* @param signal - carrier cancellation forwarded to Session queries.
|
|
3015
|
-
* @returns the catalog view for that parent.
|
|
3016
|
-
* @throws {RemoteError} `gateway/bad-request` for an empty parent id,
|
|
3017
|
-
* `gateway/cancelled` for an aborted read, `subagent/projections-unavailable` when
|
|
3018
|
-
* the deployment has no projection registry, otherwise `gateway/internal`.
|
|
3019
|
-
*/
|
|
3020
|
-
async remoteExportList(parentSessionId, signal) {
|
|
3021
|
-
validateControlRequest("subagent.list", { parentSessionId });
|
|
3022
|
-
try {
|
|
3023
|
-
return catalogView(this.ctx, parentSessionId, await this.listChildren(parentSessionId, signal));
|
|
3024
|
-
} catch (error) {
|
|
3025
|
-
return rejectCatalogRead(error, signal);
|
|
3026
|
-
}
|
|
3027
|
-
}
|
|
3028
|
-
/**
|
|
3029
3160
|
* Deliver one browser-authored message to a continuable child through the
|
|
3030
3161
|
* exact live direct parent, retaining the caller-minted request identity and
|
|
3031
3162
|
* validated browser zone on the accepted message. Success identifies the
|
|
@@ -3034,6 +3165,7 @@ let SubagentRuntime = (() => {
|
|
|
3034
3165
|
* nearest step and retains the Agent loop's best-effort fallback semantics.
|
|
3035
3166
|
* Image parts are admitted and persisted through the attachment store
|
|
3036
3167
|
* before delivery, and the child's model must accept image input.
|
|
3168
|
+
* Cold resume at capacity rejects with `subagent/delivery-unavailable`.
|
|
3037
3169
|
* @param request - durable address, delivery, minted identity, content, and optional browser zone.
|
|
3038
3170
|
* @param signal - carrier cancellation, owning the call until inbox acceptance.
|
|
3039
3171
|
* @returns the accepted message's inbox identity.
|