@deepseek-ai/dsh-subagent 0.1.2-alpha.2 → 0.1.2-alpha.4
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 +12 -11
- package/README.zh.md +12 -11
- package/lib/index.js +238 -324
- package/lib/typert.host.js +52 -157
- package/lib/typert.remote-client.js +8 -91
- package/lib/types/child-agent.d.ts +2 -2
- package/lib/types/child-agent.js +3 -3
- package/lib/types/continuation.d.ts +50 -69
- package/lib/types/continuation.js +173 -105
- package/lib/types/control-types.d.ts +11 -27
- package/lib/types/control.d.ts +1 -17
- package/lib/types/control.js +6 -24
- package/lib/types/descriptor-seed.d.ts +1 -1
- package/lib/types/descriptor-seed.js +1 -1
- package/lib/types/index.d.ts +32 -43
- package/lib/types/index.js +51 -50
- package/lib/types/internal.d.ts +46 -0
- package/lib/types/internal.js +45 -0
- package/lib/types/lifecycle.js +4 -3
- package/lib/types/list-children.d.ts +6 -5
- package/lib/types/list-children.js +23 -22
- package/lib/types/projection-types.d.ts +4 -3
- package/lib/types/projection.js +3 -2
- package/package.json +48 -44
- package/lib/types/activation-setup-registry.d.ts +0 -57
- package/lib/types/activation-setup-registry.js +0 -148
package/lib/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { AttachmentError, admitPromptContent } from "@deepseek-ai/dsh-attachment";
|
|
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 { z } from "zod";
|
|
6
|
-
import { HarnessError, ReasoningEffortId, boundContextSummary, createUserMessage, errorChain } from "@deepseek-ai/dsh-llm";
|
|
7
|
+
import { HarnessError, ReasoningEffortId, boundContextSummary, contentHasImage, createUserMessage, errorChain } from "@deepseek-ai/dsh-llm";
|
|
7
8
|
import { randomUUID } from "node:crypto";
|
|
8
9
|
import { foldConsumedWork } from "@deepseek-ai/dsh-agent";
|
|
10
|
+
import { Session, SessionLogOffset, SessionSeq } from "@deepseek-ai/dsh-session";
|
|
9
11
|
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
10
12
|
import { snapshotJsonValue } from "@deepseek-ai/dsh-util-values";
|
|
11
|
-
import { Session } from "@deepseek-ai/dsh-session";
|
|
12
13
|
import { accessSync, constants, statSync } from "node:fs";
|
|
13
14
|
import { isAbsolute, resolve } from "node:path";
|
|
14
15
|
//#region lib/types/error.js
|
|
@@ -59,31 +60,6 @@ function validateControlRequest(method, payload) {
|
|
|
59
60
|
if (!parsed.success) throw new RemoteError("gateway/bad-request", `invalid payload for ${method}`, { issues: parsed.error.issues });
|
|
60
61
|
}
|
|
61
62
|
/**
|
|
62
|
-
* Admit the content one continuation may deliver, refusing every image.
|
|
63
|
-
*
|
|
64
|
-
* The blocks become the child's user message verbatim, and this surface admits
|
|
65
|
-
* no attachment: nothing here registers encoded bytes with the attachment
|
|
66
|
-
* service, so an image would reach the child as a reference nothing resolves.
|
|
67
|
-
* The wire accepts the encoded upload so this refusal — not a Client that
|
|
68
|
-
* strips the block — is what the caller is answered with. Other block types
|
|
69
|
-
* still cross unnarrowed.
|
|
70
|
-
* @param childSessionId - the addressed child, named by the refusal.
|
|
71
|
-
* @param content - blocks the caller asked to deliver.
|
|
72
|
-
* @returns the admitted blocks, in order, as the durable content vocabulary.
|
|
73
|
-
* @throws {RemoteError} `subagent/attachment-unsupported` when any block is an image.
|
|
74
|
-
*/
|
|
75
|
-
function admitPromptContent(childSessionId, content) {
|
|
76
|
-
const admitted = [];
|
|
77
|
-
for (const block of content) {
|
|
78
|
-
if (block.type === "image") throw new RemoteError("subagent/attachment-unsupported", "subagent continuation does not accept images", {
|
|
79
|
-
childSessionId,
|
|
80
|
-
reason: "SUBAGENT_IMAGE_UNSUPPORTED"
|
|
81
|
-
});
|
|
82
|
-
admitted.push(block);
|
|
83
|
-
}
|
|
84
|
-
return admitted;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
63
|
* Project one durable listing onto the catalog view, replacing each row's
|
|
88
64
|
* store-derived activity with the live Agent driver's status and reporting
|
|
89
65
|
* whether the exact parent Agent is live. Without an Agent registry no driver
|
|
@@ -128,7 +104,9 @@ function rejectCatalogRead(error, signal) {
|
|
|
128
104
|
*/
|
|
129
105
|
function rejectPrompt(error, childSessionId, signal) {
|
|
130
106
|
if (isCancellation(error, signal)) throw new RemoteError("gateway/cancelled", "subagent prompt was cancelled", {}, { cause: error });
|
|
107
|
+
if (error instanceof AttachmentError) throw new RemoteError("subagent/attachment-invalid", error.message, { reason: error.code }, { cause: error });
|
|
131
108
|
if (error instanceof SubagentError) switch (error.code) {
|
|
109
|
+
case "MODEL_DOES_NOT_SUPPORT_IMAGES": throw new RemoteError("subagent/attachment-invalid", error.message, { reason: error.code }, { cause: error });
|
|
132
110
|
case "NOT_RESUMABLE": throw new RemoteError("subagent/not-resumable", "subagent cannot be resumed", { childSessionId }, { cause: error });
|
|
133
111
|
case "UNAUTHORIZED": throw new RemoteError("subagent/unauthorized", "subagent does not belong to this parent", { childSessionId }, { cause: error });
|
|
134
112
|
case "DRAINING":
|
|
@@ -349,16 +327,16 @@ function createActivationObserver(emit, provider, childId, parent) {
|
|
|
349
327
|
id: childId,
|
|
350
328
|
local: true
|
|
351
329
|
};
|
|
352
|
-
let boundary = 0;
|
|
330
|
+
let boundary = SessionLogOffset(0);
|
|
353
331
|
let captured = { stopReason: "completed" };
|
|
354
332
|
const terminal = (failure) => failure === void 0 ? captured : { stopReason: "error" };
|
|
355
333
|
return {
|
|
356
334
|
start: (child) => {
|
|
357
|
-
boundary = child.session.
|
|
335
|
+
boundary = child.session.seq;
|
|
358
336
|
emit("subagent/start", identity, parent);
|
|
359
337
|
},
|
|
360
338
|
capture: (child) => {
|
|
361
|
-
const own = child.session.
|
|
339
|
+
const own = child.session.snapshotEvents(boundary);
|
|
362
340
|
const output = finalAssistantOutput(own);
|
|
363
341
|
captured = {
|
|
364
342
|
stopReason: epochStopReason(own),
|
|
@@ -675,19 +653,19 @@ function resolveChildAgentOptions(parent, requested, childDepth) {
|
|
|
675
653
|
* child never had.
|
|
676
654
|
* @param parent - the delegating parent agent.
|
|
677
655
|
* @param childDepth - the resolved delegation depth to persist.
|
|
678
|
-
* @param
|
|
656
|
+
* @param isSeeded - whether this child inherits a parent-log prefix, including an explicitly empty one.
|
|
679
657
|
* @returns the `meta` for `ctx.agents.create()`.
|
|
680
658
|
*/
|
|
681
|
-
function childSessionMeta(parent, childDepth,
|
|
659
|
+
function childSessionMeta(parent, childDepth, isSeeded) {
|
|
682
660
|
const parentHeader = parent.session.header;
|
|
683
661
|
const agentPreset = parent.ctx.get("agentPresets")?.composedPreset(parent.ctx);
|
|
684
662
|
return {
|
|
685
663
|
...parentHeader.cwd !== void 0 ? { cwd: parentHeader.cwd } : {},
|
|
686
664
|
...agentPreset === void 0 ? {} : { agentPreset },
|
|
687
665
|
parentSession: parentHeader.id,
|
|
666
|
+
isSeeded,
|
|
688
667
|
origin: "subagent",
|
|
689
|
-
delegationDepth: childDepth
|
|
690
|
-
...lineageSeedLength > 0 ? { seedLength: lineageSeedLength } : {}
|
|
668
|
+
delegationDepth: childDepth
|
|
691
669
|
};
|
|
692
670
|
}
|
|
693
671
|
/**
|
|
@@ -789,9 +767,32 @@ function appendDelegatedPolicyOverrides(childSession, overrides) {
|
|
|
789
767
|
function seedDescriptorTurn(childId, seed, descriptor) {
|
|
790
768
|
const staged = Session.create(childId, seed);
|
|
791
769
|
staged.append("subagent/descriptor", descriptor);
|
|
792
|
-
return
|
|
770
|
+
return staged.snapshotEvents();
|
|
793
771
|
}
|
|
794
772
|
//#endregion
|
|
773
|
+
//#region lib/types/internal.js
|
|
774
|
+
/**
|
|
775
|
+
* Continuation integration markers and host adapters outside the public
|
|
776
|
+
* Service Definition and model-facing Agent messaging contract.
|
|
777
|
+
* @module @deepseek-ai/dsh-subagent/internal
|
|
778
|
+
*/
|
|
779
|
+
/** Process-stable identity carried only by the standard adjacent-Agent messaging tool. */
|
|
780
|
+
const adjacentAgentSendMessageTool = Symbol.for("dsh.subagent.adjacentAgentSendMessageTool");
|
|
781
|
+
/**
|
|
782
|
+
* Test whether one visible definition is the standard adjacent-Agent messaging tool.
|
|
783
|
+
* @param definition - the scope-resolved `send_message` candidate.
|
|
784
|
+
* @returns whether the definition carries the internal standard-tool identity.
|
|
785
|
+
*/
|
|
786
|
+
function isAdjacentAgentSendMessageTool(definition) {
|
|
787
|
+
return definition !== void 0 && definition[adjacentAgentSendMessageTool] === true;
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Process-stable symbol-keyed Queue delivery shared by the bundled runtime
|
|
791
|
+
* entry and this unbundled internal subpath.
|
|
792
|
+
* @internal
|
|
793
|
+
*/
|
|
794
|
+
const queueSubagentPrompt = Symbol.for("dsh.subagent.queuePrompt");
|
|
795
|
+
//#endregion
|
|
795
796
|
//#region lib/types/continuation.js
|
|
796
797
|
/**
|
|
797
798
|
* Internal continuable-subagent manager: stable child ids, descriptor
|
|
@@ -883,6 +884,32 @@ var __disposeResources$1 = (function(SuppressedError) {
|
|
|
883
884
|
function disposalOf(activation) {
|
|
884
885
|
return activation.disposal;
|
|
885
886
|
}
|
|
887
|
+
/** Build durable attribution for one adjacent-Agent message. */
|
|
888
|
+
function agentMessageSource(sender) {
|
|
889
|
+
return {
|
|
890
|
+
kind: "agent-message",
|
|
891
|
+
form: "relay",
|
|
892
|
+
senderSessionId: sender.id
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
/** Build the model-visible and durable representation of one adjacent-Agent message. */
|
|
896
|
+
function agentMessage(sender, content) {
|
|
897
|
+
return createUserMessage({
|
|
898
|
+
content: [{
|
|
899
|
+
type: "text",
|
|
900
|
+
text: `Agent ${sender.id} sent a message:`
|
|
901
|
+
}, ...content],
|
|
902
|
+
source: agentMessageSource(sender)
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
/** Append adjacent-Agent return guidance to a continuable child's initial task. */
|
|
906
|
+
function continuableInitialPrompt(parentId, prompt) {
|
|
907
|
+
const encodedParentId = JSON.stringify(parentId);
|
|
908
|
+
return [...prompt, {
|
|
909
|
+
type: "text",
|
|
910
|
+
text: `Your parent agent id is ${encodedParentId}. Before you finish, send your result to that agent with send_message({ agent_id: ${encodedParentId}, message: "<self-contained result>" }). The parent shares your workspace but does not automatically receive your transcript, tool output, or reasoning. Send earlier messages as well when a finding changes what the parent should do next; sending a message does not end your turn.`
|
|
911
|
+
}];
|
|
912
|
+
}
|
|
886
913
|
/**
|
|
887
914
|
* One line telling a parent that a background child is finished and why, in
|
|
888
915
|
* the parent's own task vocabulary.
|
|
@@ -932,7 +959,6 @@ var ChildLock = class {
|
|
|
932
959
|
var SubagentContinuationManager = class {
|
|
933
960
|
ctx;
|
|
934
961
|
host;
|
|
935
|
-
setupRegistry;
|
|
936
962
|
/** Child session id → its live Activation. Process-local, never durable. */
|
|
937
963
|
activations = /* @__PURE__ */ new Map();
|
|
938
964
|
/** Materializations admitted before drain, tracked through publication or rollback. */
|
|
@@ -948,10 +974,9 @@ var SubagentContinuationManager = class {
|
|
|
948
974
|
*/
|
|
949
975
|
closingScopes = /* @__PURE__ */ new Map();
|
|
950
976
|
draining = false;
|
|
951
|
-
constructor(ctx, host
|
|
977
|
+
constructor(ctx, host) {
|
|
952
978
|
this.ctx = ctx;
|
|
953
979
|
this.host = host;
|
|
954
|
-
this.setupRegistry = setupRegistry;
|
|
955
980
|
const scope = ctx.plugin(function activationOwner() {});
|
|
956
981
|
this.ownerCtx = scope.ctx;
|
|
957
982
|
ctx.on("agent/disposed", ({ agent }) => {
|
|
@@ -1008,7 +1033,7 @@ var SubagentContinuationManager = class {
|
|
|
1008
1033
|
});
|
|
1009
1034
|
spec.signal.throwIfAborted();
|
|
1010
1035
|
this.assertAdmitting(parent);
|
|
1011
|
-
const
|
|
1036
|
+
const inheritedEventCount = SessionLogOffset(prepared.seed?.length ?? 0);
|
|
1012
1037
|
const seed = seedDescriptorTurn(childId, prepared.seed, descriptor);
|
|
1013
1038
|
return {
|
|
1014
1039
|
childId,
|
|
@@ -1029,7 +1054,8 @@ var SubagentContinuationManager = class {
|
|
|
1029
1054
|
parent,
|
|
1030
1055
|
create: {
|
|
1031
1056
|
seed,
|
|
1032
|
-
meta: childSessionMeta(parent, childDepth,
|
|
1057
|
+
meta: childSessionMeta(parent, childDepth, prepared.seed !== void 0),
|
|
1058
|
+
inheritedEventCount,
|
|
1033
1059
|
delegatedPolicies
|
|
1034
1060
|
},
|
|
1035
1061
|
agentOptions,
|
|
@@ -1039,7 +1065,11 @@ var SubagentContinuationManager = class {
|
|
|
1039
1065
|
},
|
|
1040
1066
|
signal: spec.signal
|
|
1041
1067
|
});
|
|
1042
|
-
return this.submitMaterialized(activation,
|
|
1068
|
+
return this.submitMaterialized(activation, isAdjacentAgentSendMessageTool(this.ctx.get("tools")?.get("send_message", activation.handle.agent)) ? continuableInitialPrompt(parent.id, request.prompt) : request.prompt, {
|
|
1069
|
+
source: { kind: "user" },
|
|
1070
|
+
signal: spec.signal,
|
|
1071
|
+
delivery: "queue"
|
|
1072
|
+
}, parent);
|
|
1043
1073
|
})
|
|
1044
1074
|
};
|
|
1045
1075
|
}
|
|
@@ -1048,34 +1078,69 @@ var SubagentContinuationManager = class {
|
|
|
1048
1078
|
if (this.ctx.agents.get(childId) !== void 0 || this.ctx.get("sessions")?.get(childId) !== void 0) throw new SubagentError(`subagent "${childId}" already exists`, "DUPLICATE_CHILD");
|
|
1049
1079
|
}
|
|
1050
1080
|
/**
|
|
1051
|
-
* Deliver one
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
* @param parent - the exact live direct parent authorizing this delivery.
|
|
1061
|
-
* @param childId - the durable child session id.
|
|
1062
|
-
* @param content - the user-role content to deliver.
|
|
1063
|
-
* @param options - the message source fields and caller cancellation.
|
|
1081
|
+
* Deliver one model-authored message to a direct continuable child or to the
|
|
1082
|
+
* sender's direct parent. Both directions use Steer: a running target admits
|
|
1083
|
+
* the message at its nearest step boundary, while an idle target starts a
|
|
1084
|
+
* turn. A missing direct child cold-resumes through the ordinary continuation
|
|
1085
|
+
* lifecycle. The caller signal owns the operation only until inbox acceptance.
|
|
1086
|
+
* @param sender - exact live Agent authorizing and originating the message.
|
|
1087
|
+
* @param targetId - durable direct-parent or direct-child session id.
|
|
1088
|
+
* @param content - model-authored content to deliver.
|
|
1089
|
+
* @param options - caller cancellation before acceptance.
|
|
1064
1090
|
* @returns the accepted message's inbox id.
|
|
1065
|
-
* @throws when
|
|
1091
|
+
* @throws when adjacency, availability, or admission rejects delivery.
|
|
1066
1092
|
*/
|
|
1067
|
-
async
|
|
1093
|
+
async sendMessage(sender, targetId, content, options) {
|
|
1094
|
+
if (this.ctx.agents.get(sender.id) !== sender) throw new SubagentError("message delivery requires the exact live sender agent", "UNAUTHORIZED");
|
|
1095
|
+
this.assertAdmitting(sender);
|
|
1096
|
+
const senderActivation = this.activations.get(sender.id);
|
|
1097
|
+
if (senderActivation !== void 0 && senderActivation.handle.agent === sender && senderActivation.parentSession === targetId) {
|
|
1098
|
+
options.signal.throwIfAborted();
|
|
1099
|
+
return this.sendToParent(senderActivation, sender, content);
|
|
1100
|
+
}
|
|
1101
|
+
if (sender.session.header.parentSession === targetId) throw new SubagentError(`agent "${sender.id}" is not a resident continuable child and cannot send to parent "${targetId}"`, "UNAUTHORIZED");
|
|
1102
|
+
return this.deliverToChild(sender, targetId, content, {
|
|
1103
|
+
signal: options.signal,
|
|
1104
|
+
delivery: "steer"
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Queue one human-authored prompt as a distinct direct-child turn.
|
|
1109
|
+
* @param parent - exact live direct parent authorizing delivery.
|
|
1110
|
+
* @param childId - durable direct-child session id.
|
|
1111
|
+
* @param content - human-authored content to deliver.
|
|
1112
|
+
* @param source - durable host-protocol provenance.
|
|
1113
|
+
* @param signal - caller cancellation before inbox acceptance.
|
|
1114
|
+
* @returns the accepted message's inbox id.
|
|
1115
|
+
*/
|
|
1116
|
+
async queuePrompt(parent, childId, content, source, signal) {
|
|
1117
|
+
return this.deliverToChild(parent, childId, content, {
|
|
1118
|
+
source,
|
|
1119
|
+
signal,
|
|
1120
|
+
delivery: "queue"
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
/** Route one parent-originated delivery through residency and cold resume. */
|
|
1124
|
+
async deliverToChild(parent, childId, content, options) {
|
|
1068
1125
|
this.assertAdmitting(parent);
|
|
1069
1126
|
while (true) {
|
|
1070
1127
|
const live = await this.locks.run(childId, async () => {
|
|
1071
1128
|
const activation = this.activations.get(childId);
|
|
1072
1129
|
if (activation === void 0) return this.coldResume(parent, childId, content, options);
|
|
1130
|
+
const disposal = activation.disposal;
|
|
1073
1131
|
/* v8 ignore next 3 -- the send-versus-dispose cutoff: reaching this arm needs a
|
|
1074
1132
|
* delivery to observe the transaction inside the same critical section that opened it,
|
|
1075
1133
|
* which no test can schedule deterministically. The behavior is covered end-to-end by
|
|
1076
1134
|
* "cold-resumes a delivery that lost the race with final disposal". */
|
|
1077
|
-
if (
|
|
1078
|
-
|
|
1135
|
+
if (disposal !== void 0) return disposal.then(() => void 0, () => void 0);
|
|
1136
|
+
if (contentHasImage(content)) {
|
|
1137
|
+
await this.assertImageCapable(activation.handle.agent, options.signal);
|
|
1138
|
+
if (activation.disposal !== void 0) {
|
|
1139
|
+
await Promise.allSettled([activation.disposal]);
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return this.submitAdmitted(activation, content, options, parent);
|
|
1079
1144
|
});
|
|
1080
1145
|
/* v8 ignore start -- only the lost-cutoff arm above returns undefined, so only that
|
|
1081
1146
|
* race reaches the retry below, which then cold-resumes a new Activation. */
|
|
@@ -1119,59 +1184,17 @@ var SubagentContinuationManager = class {
|
|
|
1119
1184
|
if (activation.disposal !== void 0) return;
|
|
1120
1185
|
activation.handle.agent.cancel(authority.kind === "user" ? { kind: "user" } : { kind: "parent" }, { keepInbox: true });
|
|
1121
1186
|
}
|
|
1122
|
-
/**
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
* live, or continuation admission is closing.
|
|
1133
|
-
*/
|
|
1134
|
-
async reportFrom(child, content, options) {
|
|
1135
|
-
options.signal.throwIfAborted();
|
|
1136
|
-
this.assertAdmitting(child);
|
|
1137
|
-
const activation = this.authorizeReporter(child);
|
|
1138
|
-
const parent = this.resolveReportParent(child);
|
|
1139
|
-
return this.deliverReport(activation, parent, content, options.delivery);
|
|
1140
|
-
}
|
|
1141
|
-
/** Authorize only the exact Agent of one resident Activation. */
|
|
1142
|
-
authorizeReporter(child) {
|
|
1143
|
-
const activation = this.activations.get(child.id);
|
|
1144
|
-
if (activation === void 0 || activation.handle.agent !== child) throw new SubagentError(`agent "${child.id}" is not a live continuable subagent and cannot report`, "UNAUTHORIZED");
|
|
1145
|
-
/* v8 ignore next 6 -- only a synchronous re-entrant disposer can open this
|
|
1146
|
-
* transaction between exact-agent authorization and this no-await cutoff. */
|
|
1147
|
-
if (activation.disposal !== void 0) throw new SubagentError(`subagent "${child.id}" activation is being disposed; the report was not delivered`, "ACTIVATION_CLOSING");
|
|
1148
|
-
return activation;
|
|
1149
|
-
}
|
|
1150
|
-
/** Resolve the reporting child's live direct parent from durable lineage. */
|
|
1151
|
-
resolveReportParent(child) {
|
|
1152
|
-
const parentId = child.session.header.parentSession;
|
|
1153
|
-
/* v8 ignore next -- every continuation-managed child has direct-parent metadata. */
|
|
1154
|
-
const parent = parentId === void 0 ? void 0 : this.ctx.agents.get(parentId);
|
|
1155
|
-
if (parent === void 0) throw new SubagentError("direct parent is not live; report was not delivered", "PARENT_UNAVAILABLE");
|
|
1156
|
-
return parent;
|
|
1157
|
-
}
|
|
1158
|
-
/** Deliver one framed report through the selected parent scheduling preset. */
|
|
1159
|
-
deliverReport(activation, parent, content, delivery) {
|
|
1160
|
-
const message = createUserMessage({
|
|
1161
|
-
content: [{
|
|
1162
|
-
type: "text",
|
|
1163
|
-
text: `Background subagent ${activation.childId} reported:`
|
|
1164
|
-
}, ...content],
|
|
1165
|
-
source: {
|
|
1166
|
-
kind: "subagent-report",
|
|
1167
|
-
form: "relay",
|
|
1168
|
-
senderSessionId: activation.childId
|
|
1169
|
-
}
|
|
1170
|
-
});
|
|
1171
|
-
if (delivery === "next-step") this.sendWaking(parent, message, () => {
|
|
1172
|
-
this.sendReport(parent, message, delivery);
|
|
1187
|
+
/** Deliver one resident continuable child's message to its live direct parent. */
|
|
1188
|
+
sendToParent(activation, sender, content) {
|
|
1189
|
+
/* v8 ignore next 6 -- only synchronous re-entrant teardown can open this
|
|
1190
|
+
* transaction between exact-agent authorization and this no-await span. */
|
|
1191
|
+
if (activation.disposal !== void 0) throw new SubagentError(`subagent "${sender.id}" activation is being disposed; the message was not delivered`, "ACTIVATION_CLOSING");
|
|
1192
|
+
const parent = this.ctx.agents.get(activation.parentSession);
|
|
1193
|
+
if (parent === void 0) throw new SubagentError("direct parent is not live; the message was not delivered", "PARENT_UNAVAILABLE");
|
|
1194
|
+
const message = agentMessage(sender, content);
|
|
1195
|
+
this.sendWaking(parent, message, () => {
|
|
1196
|
+
this.sendAgentMessage(parent, message);
|
|
1173
1197
|
});
|
|
1174
|
-
else this.sendReport(parent, message, delivery);
|
|
1175
1198
|
return message.id;
|
|
1176
1199
|
}
|
|
1177
1200
|
/**
|
|
@@ -1188,13 +1211,12 @@ var SubagentContinuationManager = class {
|
|
|
1188
1211
|
if (parentActivation !== void 0 && parentActivation.handle.agent === parent) this.admitWaking(parentActivation, message.id, send);
|
|
1189
1212
|
else send();
|
|
1190
1213
|
}
|
|
1191
|
-
/** Send one
|
|
1192
|
-
|
|
1214
|
+
/** Send one Agent message while translating only the target's own rejection. */
|
|
1215
|
+
sendAgentMessage(parent, message) {
|
|
1193
1216
|
try {
|
|
1194
|
-
|
|
1195
|
-
else parent.inject(message);
|
|
1217
|
+
parent.steer(message);
|
|
1196
1218
|
} catch (error) {
|
|
1197
|
-
throw new SubagentError("direct parent is not live;
|
|
1219
|
+
throw new SubagentError("direct parent is not live; the message was not delivered", "PARENT_UNAVAILABLE", { cause: error });
|
|
1198
1220
|
}
|
|
1199
1221
|
}
|
|
1200
1222
|
/**
|
|
@@ -1371,8 +1393,8 @@ var SubagentContinuationManager = class {
|
|
|
1371
1393
|
const source = __addDisposableResource$1(env_1, observation, false);
|
|
1372
1394
|
this.assertAdmitting(parent);
|
|
1373
1395
|
this.authorizeLineage(parent, childId, source.header.parentSession);
|
|
1374
|
-
const descriptor = foldSubagentDescriptor(source.events.slice(source.
|
|
1375
|
-
if (descriptor === void 0 || descriptor.mode !== "continuable") throw new SubagentError(`subagent "${childId}" has no supported continuation state and cannot be resumed;
|
|
1396
|
+
const descriptor = foldSubagentDescriptor(source.events.slice(source.inheritedEventCount));
|
|
1397
|
+
if (descriptor === void 0 || descriptor.mode !== "continuable") throw new SubagentError(`subagent "${childId}" has no supported continuation state and cannot be resumed; choose a different target`, "NOT_RESUMABLE");
|
|
1376
1398
|
let activation;
|
|
1377
1399
|
try {
|
|
1378
1400
|
activation = await this.materialize({
|
|
@@ -1395,7 +1417,7 @@ var SubagentContinuationManager = class {
|
|
|
1395
1417
|
if (error instanceof SubagentError) throw error;
|
|
1396
1418
|
throw new SubagentError(`subagent "${childId}" is unavailable`, "NOT_RESUMABLE", { cause: error });
|
|
1397
1419
|
}
|
|
1398
|
-
return await this.submitMaterialized(activation, content, options
|
|
1420
|
+
return await this.submitMaterialized(activation, content, options, parent);
|
|
1399
1421
|
} catch (e_1) {
|
|
1400
1422
|
env_1.error = e_1;
|
|
1401
1423
|
env_1.hasError = true;
|
|
@@ -1407,14 +1429,17 @@ var SubagentContinuationManager = class {
|
|
|
1407
1429
|
* Submit to a freshly materialized Activation or roll it back completely.
|
|
1408
1430
|
* @param activation - the just-published Activation to admit or release.
|
|
1409
1431
|
* @param content - the initial or resumed message content.
|
|
1410
|
-
* @param
|
|
1432
|
+
* @param options - durable source, scheduling, and pre-acceptance cancellation.
|
|
1411
1433
|
* @param parent - the live direct parent authorizing admission.
|
|
1412
|
-
* @param signal - caller cancellation owning admission until acceptance.
|
|
1413
1434
|
* @returns the accepted inbox message id.
|
|
1414
1435
|
*/
|
|
1415
|
-
async submitMaterialized(activation, content,
|
|
1436
|
+
async submitMaterialized(activation, content, options, parent) {
|
|
1416
1437
|
try {
|
|
1417
|
-
|
|
1438
|
+
if (contentHasImage(content)) {
|
|
1439
|
+
await this.assertImageCapable(activation.handle.agent, options.signal);
|
|
1440
|
+
if (activation.disposal !== void 0) throw new SubagentError(`subagent "${activation.childId}" is closing`, "ACTIVATION_CLOSING");
|
|
1441
|
+
}
|
|
1442
|
+
return this.submitAdmitted(activation, content, options, parent);
|
|
1418
1443
|
} catch (error) {
|
|
1419
1444
|
/* v8 ignore next -- rollback disposal failures must not mask the
|
|
1420
1445
|
* pre-acceptance signal, drain, or lifecycle failure. */
|
|
@@ -1423,6 +1448,28 @@ var SubagentContinuationManager = class {
|
|
|
1423
1448
|
}
|
|
1424
1449
|
}
|
|
1425
1450
|
/**
|
|
1451
|
+
* Refuse image content addressed to a child whose model accepts text only.
|
|
1452
|
+
* Callers guard with `contentHasImage`, so text-only delivery never awaits.
|
|
1453
|
+
* The check runs inside the per-child delivery lock, before the message
|
|
1454
|
+
* exists, so a rejection leaves no partial user message. When the child's
|
|
1455
|
+
* route is not fixed by its options (a request-waterfall listener owns it)
|
|
1456
|
+
* or no LLM registry is composed, delivery proceeds and the LLM layer's
|
|
1457
|
+
* text-only projection replaces each image with its stable placeholder.
|
|
1458
|
+
* @param agent - the live or freshly materialized child agent.
|
|
1459
|
+
* @param signal - caller cancellation bounding the model-info read.
|
|
1460
|
+
* @throws {SubagentError} `MODEL_DOES_NOT_SUPPORT_IMAGES` when the child's resolved model declines image input.
|
|
1461
|
+
*/
|
|
1462
|
+
async assertImageCapable(agent, signal) {
|
|
1463
|
+
const { provider, model } = agent.options;
|
|
1464
|
+
if (provider === void 0 || model === void 0) return;
|
|
1465
|
+
const llm = this.ctx.get("llm");
|
|
1466
|
+
/* v8 ignore next -- a deployment without the LLM registry serves no model
|
|
1467
|
+
* to refuse against; delivery then defers to the text-only projection. */
|
|
1468
|
+
if (llm === void 0) return;
|
|
1469
|
+
const info = await llm.resolveModelInfo(provider, model, signal);
|
|
1470
|
+
if (info.inputModalities !== void 0 && !info.inputModalities.includes("image")) throw new SubagentError(`Model "${model}" does not support image input.`, "MODEL_DOES_NOT_SUPPORT_IMAGES");
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1426
1473
|
* Create or resume the child Agent through the private activation-owner
|
|
1427
1474
|
* scope, install the handle in a fresh Activation, and register ownership on
|
|
1428
1475
|
* a continuation-managed parent. Rejection leaves no Activation, no handle,
|
|
@@ -1453,7 +1500,6 @@ var SubagentContinuationManager = class {
|
|
|
1453
1500
|
const setup = (childCtx) => {
|
|
1454
1501
|
if (create !== void 0) appendDelegatedPolicyOverrides(childCtx.agent.session, create.delegatedPolicies);
|
|
1455
1502
|
applyChildComposition(childCtx, parent, inputs.composition);
|
|
1456
|
-
return this.setupRegistry.apply(childCtx);
|
|
1457
1503
|
};
|
|
1458
1504
|
const observer = this.host.observeActivation(provider, childId, parent);
|
|
1459
1505
|
const handle = create === void 0 ? await this.ownerCtx.agents.resume({
|
|
@@ -1465,6 +1511,7 @@ var SubagentContinuationManager = class {
|
|
|
1465
1511
|
sessionId: childId,
|
|
1466
1512
|
meta: create.meta,
|
|
1467
1513
|
seed: create.seed,
|
|
1514
|
+
inheritedEventCount: create.inheritedEventCount,
|
|
1468
1515
|
agentOptions: inputs.agentOptions,
|
|
1469
1516
|
signal: inputs.signal,
|
|
1470
1517
|
setup
|
|
@@ -1546,14 +1593,15 @@ var SubagentContinuationManager = class {
|
|
|
1546
1593
|
* inbox id. Acceptance is the operation's success boundary; the manager owns
|
|
1547
1594
|
* the Activation independently afterwards.
|
|
1548
1595
|
*/
|
|
1549
|
-
submit(activation, content,
|
|
1596
|
+
submit(activation, content, options, parent) {
|
|
1550
1597
|
this.acquireOwnership(parent, activation.childId);
|
|
1551
|
-
const message = createUserMessage({
|
|
1598
|
+
const message = options.delivery === "steer" ? agentMessage(parent, content) : createUserMessage({
|
|
1552
1599
|
content,
|
|
1553
|
-
source
|
|
1600
|
+
source: options.source
|
|
1554
1601
|
});
|
|
1555
1602
|
const accepted = this.admitWaking(activation, message.id, () => {
|
|
1556
|
-
activation.handle.agent.
|
|
1603
|
+
if (options.delivery === "steer") activation.handle.agent.steer(message);
|
|
1604
|
+
else activation.handle.agent.followup(message);
|
|
1557
1605
|
});
|
|
1558
1606
|
activation.announced = true;
|
|
1559
1607
|
return accepted;
|
|
@@ -1581,14 +1629,14 @@ var SubagentContinuationManager = class {
|
|
|
1581
1629
|
* manager drain, or Activation disposal that wins before this synchronous
|
|
1582
1630
|
* span rejects without inbox acceptance.
|
|
1583
1631
|
*/
|
|
1584
|
-
submitAdmitted(activation, content,
|
|
1585
|
-
signal.throwIfAborted();
|
|
1632
|
+
submitAdmitted(activation, content, options, parent) {
|
|
1633
|
+
options.signal.throwIfAborted();
|
|
1586
1634
|
this.assertAdmitting(parent);
|
|
1587
1635
|
/* v8 ignore next 6 -- only a synchronous re-entrant disposer can change
|
|
1588
1636
|
* this field between the caller's live check and this no-await boundary. */
|
|
1589
1637
|
if (disposalOf(activation) !== void 0) throw new SubagentError(`subagent "${activation.childId}" activation is being disposed; the message was not accepted`, "ACTIVATION_CLOSING");
|
|
1590
1638
|
this.authorizeLineage(parent, activation.childId, activation.handle.agent.session.header.parentSession);
|
|
1591
|
-
return this.submit(activation, content,
|
|
1639
|
+
return this.submit(activation, content, options, parent);
|
|
1592
1640
|
}
|
|
1593
1641
|
/**
|
|
1594
1642
|
* Authorize one operation against the durable direct-parent lineage. Other
|
|
@@ -1774,134 +1822,6 @@ var SubagentContinuationManager = class {
|
|
|
1774
1822
|
}
|
|
1775
1823
|
};
|
|
1776
1824
|
//#endregion
|
|
1777
|
-
//#region lib/types/activation-setup-registry.js
|
|
1778
|
-
/**
|
|
1779
|
-
* Internal registry of deployment capabilities composed into every continuable
|
|
1780
|
-
* child's unpublished creation context.
|
|
1781
|
-
*
|
|
1782
|
-
* A contribution grants a child-scoped capability without teaching the
|
|
1783
|
-
* continuation manager which capabilities exist. The manager owns residency;
|
|
1784
|
-
* this registry owns the join between plugin lifetime, unpublished setup, and
|
|
1785
|
-
* Activation disposal, so no installation outlives either owner and no removed
|
|
1786
|
-
* contribution can be installed after revocation reports completion.
|
|
1787
|
-
*
|
|
1788
|
-
* @module @deepseek-ai/dsh-subagent/activation-setup-registry
|
|
1789
|
-
*/
|
|
1790
|
-
/** Re-read mutable removal state after a contribution may have revoked itself. */
|
|
1791
|
-
function isRemoved(registration) {
|
|
1792
|
-
return registration.removed;
|
|
1793
|
-
}
|
|
1794
|
-
/**
|
|
1795
|
-
* Owns continuable-child setup registrations, installations, rollback, child
|
|
1796
|
-
* cleanup, and immediate live revocation.
|
|
1797
|
-
*/
|
|
1798
|
-
var SubagentActivationSetupRegistry = class {
|
|
1799
|
-
/** Live contributions in installation order. */
|
|
1800
|
-
registrations = /* @__PURE__ */ new Set();
|
|
1801
|
-
/** Child context to its live installations. */
|
|
1802
|
-
byChild = /* @__PURE__ */ new Map();
|
|
1803
|
-
/**
|
|
1804
|
-
* Register one contribution.
|
|
1805
|
-
* @param contribution - synchronous child-scope installer.
|
|
1806
|
-
* @returns an idempotent registration undo.
|
|
1807
|
-
* @throws after attempting every installation when any disposer fails.
|
|
1808
|
-
*/
|
|
1809
|
-
register(contribution) {
|
|
1810
|
-
const registration = {
|
|
1811
|
-
contribution,
|
|
1812
|
-
removed: false,
|
|
1813
|
-
installations: /* @__PURE__ */ new Set()
|
|
1814
|
-
};
|
|
1815
|
-
this.registrations.add(registration);
|
|
1816
|
-
return () => {
|
|
1817
|
-
if (registration.removed) return;
|
|
1818
|
-
registration.removed = true;
|
|
1819
|
-
this.registrations.delete(registration);
|
|
1820
|
-
this.releaseAll([...registration.installations], "contribution removal");
|
|
1821
|
-
};
|
|
1822
|
-
}
|
|
1823
|
-
/**
|
|
1824
|
-
* Install every live contribution into one unpublished child context.
|
|
1825
|
-
* @param childCtx - the child's unpublished scoped context.
|
|
1826
|
-
* @returns the provisioning commit consumed at Agent publication.
|
|
1827
|
-
*/
|
|
1828
|
-
apply(childCtx) {
|
|
1829
|
-
const state = {
|
|
1830
|
-
installations: [],
|
|
1831
|
-
invalidated: false
|
|
1832
|
-
};
|
|
1833
|
-
try {
|
|
1834
|
-
for (const registration of [...this.registrations]) {
|
|
1835
|
-
/* v8 ignore next -- only a synchronous re-entrant revocation of an
|
|
1836
|
-
* already-snapshotted registration reaches this guard. */
|
|
1837
|
-
if (registration.removed) continue;
|
|
1838
|
-
const installation = {
|
|
1839
|
-
registration,
|
|
1840
|
-
childCtx,
|
|
1841
|
-
dispose: registration.contribution(childCtx),
|
|
1842
|
-
released: false,
|
|
1843
|
-
transaction: state
|
|
1844
|
-
};
|
|
1845
|
-
registration.installations.add(installation);
|
|
1846
|
-
state.installations.push(installation);
|
|
1847
|
-
let indexed = this.byChild.get(childCtx);
|
|
1848
|
-
if (indexed === void 0) {
|
|
1849
|
-
indexed = /* @__PURE__ */ new Set();
|
|
1850
|
-
this.byChild.set(childCtx, indexed);
|
|
1851
|
-
}
|
|
1852
|
-
indexed.add(installation);
|
|
1853
|
-
if (isRemoved(registration)) this.release(installation);
|
|
1854
|
-
}
|
|
1855
|
-
} catch (error) {
|
|
1856
|
-
try {
|
|
1857
|
-
this.releaseAll([...state.installations], "setup rollback");
|
|
1858
|
-
} catch (releaseFailure) {}
|
|
1859
|
-
throw error;
|
|
1860
|
-
}
|
|
1861
|
-
childCtx.effect(() => () => {
|
|
1862
|
-
this.releaseChild(childCtx);
|
|
1863
|
-
}, "subagents.activationSetup()");
|
|
1864
|
-
return { commit: () => {
|
|
1865
|
-
if (state.invalidated) throw new SubagentError("a continuable-subagent setup contribution was revoked while this child was being built; the child was not established", "ACTIVATION_SETUP_REVOKED");
|
|
1866
|
-
for (const installation of state.installations) installation.transaction = void 0;
|
|
1867
|
-
} };
|
|
1868
|
-
}
|
|
1869
|
-
/** Release every remaining installation owned by one disposed child scope. */
|
|
1870
|
-
releaseChild(childCtx) {
|
|
1871
|
-
const indexed = this.byChild.get(childCtx) ?? [];
|
|
1872
|
-
this.releaseAll([...indexed], "child scope disposal");
|
|
1873
|
-
}
|
|
1874
|
-
/**
|
|
1875
|
-
* Release a batch completely before reporting disposer failures.
|
|
1876
|
-
* @param installations - records to release.
|
|
1877
|
-
* @param during - operation name for diagnostics.
|
|
1878
|
-
*/
|
|
1879
|
-
releaseAll(installations, during) {
|
|
1880
|
-
const failures = [];
|
|
1881
|
-
for (const installation of installations) try {
|
|
1882
|
-
this.release(installation);
|
|
1883
|
-
} catch (error) {
|
|
1884
|
-
failures.push(error);
|
|
1885
|
-
}
|
|
1886
|
-
if (failures.length === 0) return;
|
|
1887
|
-
throw new SubagentError(`continuable-subagent setup ${during} failed to release ${failures.length} installation(s): ` + failures.map((failure) => errorChain(failure)).join("; "), "ACTIVATION_SETUP_RELEASE_FAILED");
|
|
1888
|
-
}
|
|
1889
|
-
/** Drop one installation from both indices and dispose it exactly once. */
|
|
1890
|
-
release(installation) {
|
|
1891
|
-
if (installation.released) return;
|
|
1892
|
-
installation.released = true;
|
|
1893
|
-
installation.registration.installations.delete(installation);
|
|
1894
|
-
const indexed = this.byChild.get(installation.childCtx);
|
|
1895
|
-
/* v8 ignore next 4 -- every live installation is indexed until this method removes it. */
|
|
1896
|
-
if (indexed !== void 0) {
|
|
1897
|
-
indexed.delete(installation);
|
|
1898
|
-
if (indexed.size === 0) this.byChild.delete(installation.childCtx);
|
|
1899
|
-
}
|
|
1900
|
-
if (installation.transaction !== void 0) installation.transaction.invalidated = true;
|
|
1901
|
-
installation.dispose();
|
|
1902
|
-
}
|
|
1903
|
-
};
|
|
1904
|
-
//#endregion
|
|
1905
1825
|
//#region lib/types/list-children.js
|
|
1906
1826
|
/**
|
|
1907
1827
|
* Read-only enumeration of durable subagent children and descendant trees
|
|
@@ -1909,9 +1829,10 @@ var SubagentActivationSetupRegistry = class {
|
|
|
1909
1829
|
* corpus; each child's mode/label is the registered `subagent` projection
|
|
1910
1830
|
* unit's value, resolved
|
|
1911
1831
|
* down a three-rung ladder: the registry's watermark cache for a live child,
|
|
1912
|
-
*
|
|
1913
|
-
*
|
|
1914
|
-
*
|
|
1832
|
+
* an unseeded durable projection-cache row, and one shared Session observation
|
|
1833
|
+
* otherwise. A seeded header deliberately lacks its exact inherited cut, so
|
|
1834
|
+
* it takes the body-bearing observation path before classifying an identity.
|
|
1835
|
+
* The projection fold is the single classification
|
|
1915
1836
|
* authority — this module parses no descriptor
|
|
1916
1837
|
* itself. Absent persistence, enumeration is live-only: a cold child is
|
|
1917
1838
|
* unreachable for resume anyway, so its absence is capability absence, not an
|
|
@@ -1989,8 +1910,8 @@ const COLD_READ_CONCURRENCY = 4;
|
|
|
1989
1910
|
* live-preferred merge of `ctx.sessions` and optional session persistence,
|
|
1990
1911
|
* serving each identity from the `subagent` projection unit: the registry's
|
|
1991
1912
|
* watermark snapshot for a live child; for a cold one, a durable
|
|
1992
|
-
* projection-cache read
|
|
1993
|
-
*
|
|
1913
|
+
* projection-cache read for an unseeded lifecycle, else one bounded-concurrency
|
|
1914
|
+
* shared Session observation carrying the exact inherited cut.
|
|
1994
1915
|
* @see SubagentRuntime.listChildren for the public cancellation and failure contract.
|
|
1995
1916
|
* @param ctx - context carrying the session store, the projection registry,
|
|
1996
1917
|
* optional persistence, and the optional projection cache.
|
|
@@ -2093,7 +2014,7 @@ async function resolveCandidateRows(candidates, listing, signal) {
|
|
|
2093
2014
|
};
|
|
2094
2015
|
return;
|
|
2095
2016
|
}
|
|
2096
|
-
if (identity === void 0 || identity === null || identity.seq
|
|
2017
|
+
if (identity === void 0 || identity === null || !candidate.live.isOwnSeq(identity.seq)) return;
|
|
2097
2018
|
rows[index] = childRow(childId, identity, "running", subagentParents.has(childId));
|
|
2098
2019
|
});
|
|
2099
2020
|
if (coldReads.length > 0) {
|
|
@@ -2143,9 +2064,8 @@ function compareCorpusRecords(a, b) {
|
|
|
2143
2064
|
return a.header.createdAt - b.header.createdAt || a.header.id.localeCompare(b.header.id);
|
|
2144
2065
|
}
|
|
2145
2066
|
/**
|
|
2146
|
-
* Resolve one cold candidate down the remaining ladder:
|
|
2147
|
-
* projection-cache row
|
|
2148
|
-
* otherwise one shared Session observation. An absent or transiently failed
|
|
2067
|
+
* Resolve one cold candidate down the remaining ladder: an unseeded durable
|
|
2068
|
+
* projection-cache row, otherwise one shared Session observation. An absent or transiently failed
|
|
2149
2069
|
* observation is one `unavailable` row retried on the next listing; an observation
|
|
2150
2070
|
* source naming another lifecycle, and a
|
|
2151
2071
|
* settled log the fold cannot identify — or that makes any registered unit
|
|
@@ -2159,14 +2079,14 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
2159
2079
|
};
|
|
2160
2080
|
try {
|
|
2161
2081
|
const childId = header.id;
|
|
2162
|
-
if (cache !== void 0) {
|
|
2082
|
+
if (cache !== void 0 && !header.isSeeded) {
|
|
2163
2083
|
let cached;
|
|
2164
2084
|
try {
|
|
2165
|
-
cached = cache.cachedSnapshot(header, ["subagent"])?.values.subagent;
|
|
2085
|
+
cached = cache.cachedSnapshot(header, SessionLogOffset(0), ["subagent"])?.values.subagent;
|
|
2166
2086
|
} catch {
|
|
2167
2087
|
cached = void 0;
|
|
2168
2088
|
}
|
|
2169
|
-
if (cached !== void 0 && cached !== null
|
|
2089
|
+
if (cached !== void 0 && cached !== null) return childRow(childId, cached, "inactive", hasChildren);
|
|
2170
2090
|
}
|
|
2171
2091
|
assertListingNotCancelled(signal);
|
|
2172
2092
|
let observation;
|
|
@@ -2188,7 +2108,7 @@ async function resolveColdIdentity(query, cache, header, hasChildren, signal) {
|
|
|
2188
2108
|
reason: "corrupt"
|
|
2189
2109
|
};
|
|
2190
2110
|
const identity = ownedObservation.projections?.values.subagent;
|
|
2191
|
-
if (identity === void 0 || identity === null || identity.seq <
|
|
2111
|
+
if (identity === void 0 || identity === null || identity.seq < ownedObservation.inheritedEventCount) return {
|
|
2192
2112
|
kind: "diagnostic",
|
|
2193
2113
|
id: childId,
|
|
2194
2114
|
reason: "corrupt"
|
|
@@ -2226,7 +2146,7 @@ const LIFECYCLE_WITNESS_KEYS = [
|
|
|
2226
2146
|
"createdAt",
|
|
2227
2147
|
"cwd",
|
|
2228
2148
|
"parentSession",
|
|
2229
|
-
"
|
|
2149
|
+
"isSeeded",
|
|
2230
2150
|
"delegationDepth",
|
|
2231
2151
|
"origin",
|
|
2232
2152
|
"agentPreset"
|
|
@@ -2337,11 +2257,11 @@ const subagentTimingProjectionDefinition = {
|
|
|
2337
2257
|
const identityValueSchema = z.discriminatedUnion("mode", [z.object({
|
|
2338
2258
|
mode: z.literal("one-shot"),
|
|
2339
2259
|
label: z.string().optional(),
|
|
2340
|
-
seq: z.number().int().nonnegative()
|
|
2260
|
+
seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
|
|
2341
2261
|
}).strict(), z.object({
|
|
2342
2262
|
mode: z.literal("continuable"),
|
|
2343
2263
|
label: z.string(),
|
|
2344
|
-
seq: z.number().int().nonnegative()
|
|
2264
|
+
seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq)
|
|
2345
2265
|
}).strict()]);
|
|
2346
2266
|
const identitySchema = identityValueSchema.nullable();
|
|
2347
2267
|
const identityStateSchema = z.object({ identity: identityValueSchema.optional() }).strict();
|
|
@@ -2668,8 +2588,8 @@ async function settleRun(run) {
|
|
|
2668
2588
|
*
|
|
2669
2589
|
* Public operations express caller intent: `start` returns one published owned
|
|
2670
2590
|
* one-shot run, `startContinuable` establishes a durable continuable child, and
|
|
2671
|
-
* `
|
|
2672
|
-
* resident. Continuable children never become a {@link SubagentRun}: the
|
|
2591
|
+
* `sendMessage` steers between adjacent Agents without exposing whether a child
|
|
2592
|
+
* is resident. Continuable children never become a {@link SubagentRun}: the
|
|
2673
2593
|
* continuation manager holds their `AgentHandle` directly and orders every turn
|
|
2674
2594
|
* through the child's own inbox, so providers contribute only the detached
|
|
2675
2595
|
* creation spec and see no handle, turn, or teardown. Child and descendant
|
|
@@ -2776,8 +2696,6 @@ let SubagentRuntime = (() => {
|
|
|
2776
2696
|
}
|
|
2777
2697
|
providers = (__runInitializers(this, _instanceExtraInitializers), /* @__PURE__ */ new Map());
|
|
2778
2698
|
continuations;
|
|
2779
|
-
/** Deployment contributions composed into unpublished continuable children. */
|
|
2780
|
-
setupRegistry = new SubagentActivationSetupRegistry();
|
|
2781
2699
|
/**
|
|
2782
2700
|
* The contained lifecycle-edge publisher. Built here because scoped dispatch
|
|
2783
2701
|
* keys its carrier by this exact service instance, whose own context filter
|
|
@@ -2791,7 +2709,7 @@ let SubagentRuntime = (() => {
|
|
|
2791
2709
|
const manager = new SubagentContinuationManager(childCtx, {
|
|
2792
2710
|
prepareContinuable: (name, request) => this.prepareContinuable(name, request),
|
|
2793
2711
|
observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent)
|
|
2794
|
-
}
|
|
2712
|
+
});
|
|
2795
2713
|
this.continuations = manager;
|
|
2796
2714
|
childCtx.effect(() => () => {
|
|
2797
2715
|
/* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
|
|
@@ -2816,22 +2734,35 @@ let SubagentRuntime = (() => {
|
|
|
2816
2734
|
return this.requireContinuations().startContinuable(spec);
|
|
2817
2735
|
}
|
|
2818
2736
|
/**
|
|
2819
|
-
*
|
|
2820
|
-
*
|
|
2821
|
-
*
|
|
2822
|
-
*
|
|
2823
|
-
*
|
|
2824
|
-
* @param
|
|
2825
|
-
* @param
|
|
2826
|
-
* @param content -
|
|
2827
|
-
* @param options -
|
|
2828
|
-
* operation only before inbox acceptance.
|
|
2737
|
+
* Steer one model-authored message to the sender's direct parent or direct
|
|
2738
|
+
* continuable child. A running target admits it at the nearest step boundary;
|
|
2739
|
+
* an idle target starts a turn, and an absent direct child cold-resumes from
|
|
2740
|
+
* persistence. The service derives durable sender attribution from the exact
|
|
2741
|
+
* live sender. Caller cancellation stops only pre-acceptance work.
|
|
2742
|
+
* @param sender - exact live Agent authorizing and originating the message.
|
|
2743
|
+
* @param targetId - durable direct-parent or direct-child session id.
|
|
2744
|
+
* @param content - model-authored content to deliver.
|
|
2745
|
+
* @param options - caller cancellation before inbox acceptance.
|
|
2829
2746
|
* @returns the accepted message's inbox id.
|
|
2830
|
-
* @throws when continuation services are unavailable,
|
|
2831
|
-
*
|
|
2747
|
+
* @throws when continuation services are unavailable, adjacency is rejected,
|
|
2748
|
+
* or the message was not admitted.
|
|
2832
2749
|
*/
|
|
2833
|
-
async
|
|
2834
|
-
return this.requireContinuations().
|
|
2750
|
+
async sendMessage(sender, targetId, content, options) {
|
|
2751
|
+
return this.requireContinuations().sendMessage(sender, targetId, content, options);
|
|
2752
|
+
}
|
|
2753
|
+
/**
|
|
2754
|
+
* Queue one host-protocol message as a distinct direct-child turn.
|
|
2755
|
+
* Symbol-keyed so host adapters can preserve their own provenance without
|
|
2756
|
+
* widening the public Service Definition or impersonating an Agent sender.
|
|
2757
|
+
* @param parent - exact live direct parent authorizing delivery.
|
|
2758
|
+
* @param childId - durable direct-child session id.
|
|
2759
|
+
* @param content - host-authored content to deliver.
|
|
2760
|
+
* @param source - durable host-protocol provenance.
|
|
2761
|
+
* @param signal - caller cancellation before inbox acceptance.
|
|
2762
|
+
* @returns the accepted message's inbox id.
|
|
2763
|
+
*/
|
|
2764
|
+
[queueSubagentPrompt](parent, childId, content, source, signal) {
|
|
2765
|
+
return this.requireContinuations().queuePrompt(parent, childId, content, source, signal);
|
|
2835
2766
|
}
|
|
2836
2767
|
/**
|
|
2837
2768
|
* Interrupt one live continuable child's current turn under a human parent
|
|
@@ -2852,31 +2783,6 @@ let SubagentRuntime = (() => {
|
|
|
2852
2783
|
this.continuations?.interrupt(targetSessionId, authority);
|
|
2853
2784
|
}
|
|
2854
2785
|
/**
|
|
2855
|
-
* Deliver selected content from one live continuable child to its durable
|
|
2856
|
-
* direct parent. The child is the authority credential; callers cannot name a
|
|
2857
|
-
* recipient. Reporting does not conclude the child's turn or Activation.
|
|
2858
|
-
* @param child - exact live reporting child.
|
|
2859
|
-
* @param content - selected model-facing content.
|
|
2860
|
-
* @param options - parent scheduling and pre-acceptance cancellation.
|
|
2861
|
-
* @returns the stable identity of the parent-accepted message.
|
|
2862
|
-
* @throws when continuation services are unavailable, sender authorization
|
|
2863
|
-
* fails, or the direct parent is not live.
|
|
2864
|
-
*/
|
|
2865
|
-
async reportFrom(child, content, options) {
|
|
2866
|
-
return this.requireContinuations().reportFrom(child, content, options);
|
|
2867
|
-
}
|
|
2868
|
-
/**
|
|
2869
|
-
* Compose one deployment capability into every continuable child's
|
|
2870
|
-
* unpublished creation context on fresh creation and cold resume. Grants wait
|
|
2871
|
-
* for the next Activation; removing the contribution revokes every resident
|
|
2872
|
-
* installation immediately.
|
|
2873
|
-
* @param contribution - synchronous child-scope installer.
|
|
2874
|
-
* @returns the exact Cordis effect disposer.
|
|
2875
|
-
*/
|
|
2876
|
-
registerContinuableSetup(contribution) {
|
|
2877
|
-
return this.ctx.effect(() => this.setupRegistry.register(contribution), "subagents.registerContinuableSetup()");
|
|
2878
|
-
}
|
|
2879
|
-
/**
|
|
2880
2786
|
* Close continuable admission below exact live parent Agents, stop only their
|
|
2881
2787
|
* visible descendant Activations synchronously, then await admitted scoped
|
|
2882
2788
|
* materializations and release those forests child-first. The scoped cutoff
|
|
@@ -2971,10 +2877,12 @@ let SubagentRuntime = (() => {
|
|
|
2971
2877
|
* validated browser zone on the accepted message. Success identifies the
|
|
2972
2878
|
* message the child's FIFO inbox accepted; later execution is independent of
|
|
2973
2879
|
* this call.
|
|
2880
|
+
* Image parts are admitted and persisted through the attachment store
|
|
2881
|
+
* before delivery, and the child's model must accept image input.
|
|
2974
2882
|
* @param request - durable address, minted identity, content, and optional browser zone.
|
|
2975
2883
|
* @param signal - carrier cancellation, owning the call until inbox acceptance.
|
|
2976
2884
|
* @returns the accepted message's inbox identity.
|
|
2977
|
-
* @throws {RemoteError} `gateway/bad-request`, `subagent/attachment-
|
|
2885
|
+
* @throws {RemoteError} `gateway/bad-request`, `subagent/attachment-invalid`,
|
|
2978
2886
|
* `subagent/invalid-time-zone`, `subagent/parent-unavailable`,
|
|
2979
2887
|
* `subagent/not-resumable`, `subagent/unauthorized`,
|
|
2980
2888
|
* `subagent/delivery-unavailable`, `gateway/cancelled`, or `gateway/internal`.
|
|
@@ -2982,7 +2890,6 @@ let SubagentRuntime = (() => {
|
|
|
2982
2890
|
async prompt(request, signal) {
|
|
2983
2891
|
const { parentSessionId, childSessionId, clientTimeZone } = request;
|
|
2984
2892
|
validateControlRequest("subagent.prompt", request);
|
|
2985
|
-
const content = admitPromptContent(childSessionId, request.content);
|
|
2986
2893
|
const canonicalTimeZone = clientTimeZone === void 0 ? void 0 : canonicalClientTimeZone(clientTimeZone);
|
|
2987
2894
|
if (clientTimeZone !== void 0 && canonicalTimeZone === void 0) throw new RemoteError("subagent/invalid-time-zone", "clientTimeZone must be UTC or a valid IANA Area/Location name", { value: clientTimeZone });
|
|
2988
2895
|
const parent = this.ctx.get("agents")?.get(parentSessionId);
|
|
@@ -2993,10 +2900,17 @@ let SubagentRuntime = (() => {
|
|
|
2993
2900
|
...canonicalTimeZone === void 0 ? {} : { clientTimeZone: canonicalTimeZone }
|
|
2994
2901
|
};
|
|
2995
2902
|
try {
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
2903
|
+
let content;
|
|
2904
|
+
if (request.content.every((part) => part.type === "text")) content = request.content.map((part) => ({
|
|
2905
|
+
type: "text",
|
|
2906
|
+
text: part.text
|
|
2907
|
+
}));
|
|
2908
|
+
else {
|
|
2909
|
+
const attachments = this.ctx.get("attachments");
|
|
2910
|
+
if (attachments === void 0) throw new Error("subagent image prompt requires an attachment store");
|
|
2911
|
+
content = await admitPromptContent(attachments, request.content);
|
|
2912
|
+
}
|
|
2913
|
+
return { messageId: await this[queueSubagentPrompt](parent, childSessionId, content, source, signal) };
|
|
3000
2914
|
} catch (error) {
|
|
3001
2915
|
return rejectPrompt(error, childSessionId, signal);
|
|
3002
2916
|
}
|