@morlay/dsh-subagent 0.0.10 → 0.0.11-alpha.0

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/dist/index.mjs CHANGED
@@ -14,7 +14,7 @@ import { SessionLogOffset, SessionSeq } from "@deepseek-ai/dsh-session";
14
14
  import { assertNever, snapshotJsonValue } from "@deepseek-ai/dsh-util-values";
15
15
  import { appendChunkedList, chunkedListSchema, iterateChunkedList } from "@deepseek-ai/dsh-chunked-list";
16
16
  import { accessSync, constants, statSync } from "node:fs";
17
- //#region src/vendor/dsh-subagent/error.ts
17
+ // src/vendor/dsh-subagent/error.ts
18
18
  /**
19
19
  * Typed failures shared by subagent service and provider operations.
20
20
  *
@@ -27,8 +27,7 @@ var SubagentError = class extends HarnessError {
27
27
  this.name = "SubagentError";
28
28
  }
29
29
  };
30
- //#endregion
31
- //#region src/vendor/dsh-subagent/control.ts
30
+ // src/vendor/dsh-subagent/control.ts
32
31
  /**
33
32
  * Browser-facing subagent prompt and interrupt request validation plus the
34
33
  * stable prompt failure codes returned by the Remote surface.
@@ -88,8 +87,7 @@ function rejectPrompt(error, childSessionId, signal) {
88
87
  function isCancellation(error, signal) {
89
88
  return signal.aborted || error instanceof SubagentError && error.code === "CANCELLED";
90
89
  }
91
- //#endregion
92
- //#region src/vendor/dsh-subagent/depth.ts
90
+ // src/vendor/dsh-subagent/depth.ts
93
91
  /**
94
92
  * Read an agent's delegation depth, treating absence as top-level depth zero.
95
93
  * The persisted session header is authoritative and monotone: runtime
@@ -112,8 +110,7 @@ function delegationDepthOf(agent) {
112
110
  function assertSubagentMaxDepth(maxDepth) {
113
111
  if (maxDepth !== void 0 && (typeof maxDepth !== "number" || !Number.isSafeInteger(maxDepth) || maxDepth < 0 || Object.is(maxDepth, -0))) throw new TypeError("subagent maxDepth must be a non-negative safe integer");
114
112
  }
115
- //#endregion
116
- //#region src/vendor/dsh-subagent/types.ts
113
+ // src/vendor/dsh-subagent/types.ts
117
114
  /**
118
115
  * Brand a string as a {@link SubagentRunId}.
119
116
  * @param id - the raw run id.
@@ -122,8 +119,7 @@ function assertSubagentMaxDepth(maxDepth) {
122
119
  function SubagentRunId(id) {
123
120
  return id;
124
121
  }
125
- //#endregion
126
- //#region src/vendor/dsh-subagent/lifecycle.ts
122
+ // src/vendor/dsh-subagent/lifecycle.ts
127
123
  /**
128
124
  * Lifecycle-edge publication for managed subagent activations.
129
125
  *
@@ -228,8 +224,7 @@ function renderThrown(value) {
228
224
  return "<unrenderable thrown value>";
229
225
  }
230
226
  }
231
- //#endregion
232
- //#region src/vendor/dsh-subagent/child-agent.ts
227
+ // src/vendor/dsh-subagent/child-agent.ts
233
228
  /** Thrown when starting a child would exceed the requested depth cap. */
234
229
  var SubagentDepthError = class extends Error {
235
230
  attemptedDepth;
@@ -390,11 +385,11 @@ function captureDelegatedPolicyOverrides(parent) {
390
385
  }
391
386
  /**
392
387
  * Append the captured delegation policy onto the child's own log as
393
- * `source: 'delegation'` events inside the unpublished creation window, so the
388
+ * `source: 'delegation'` events after Session announcement and before Agent registration, so the
394
389
  * child's effective policy is reconstructable from its log alone. Appends land
395
390
  * after any fork seed, so fresh policy wins stale seed state; later child
396
391
  * switches still win over these events.
397
- * @param childSession - the unpublished child's session.
392
+ * @param childSession - the child's announced, writable Session.
398
393
  * @param overrides - the policy captured at delegation.
399
394
  */
400
395
  function appendDelegatedPolicyOverrides(childSession, overrides) {
@@ -408,8 +403,7 @@ function appendDelegatedPolicyOverrides(childSession, overrides) {
408
403
  });
409
404
  if (overrides.permissionPreset !== void 0) childSession.append("permission/preset", { preset: overrides.permissionPreset });
410
405
  }
411
- //#endregion
412
- //#region src/continuation-messages.ts
406
+ // src/continuation-messages.ts
413
407
  /** Build durable attribution for one adjacent-Agent message. */
414
408
  function agentMessageSource(sender) {
415
409
  return {
@@ -489,9 +483,11 @@ function settlementSummary(childId, stopReason, continuable) {
489
483
  * @param childId - durable child session id named in the notice.
490
484
  * @param terminal - recorded terminal state for the settled Activation.
491
485
  * @param continuable - whether the child can accept another task.
486
+ * @param omitClosingText - replace the closing text with a note that the child
487
+ * already reported to its parent; the parent should not read the result twice.
492
488
  * @returns the durable user-message representation delivered to the parent.
493
489
  */
494
- function createSettlementMessage(childId, terminal, continuable = true) {
490
+ function createSettlementMessage(childId, terminal, continuable = true, omitClosingText = false) {
495
491
  const summary = settlementSummary(childId, terminal.stopReason, continuable);
496
492
  const closingText = terminal.output.flatMap((block) => block.type === "text" && block.text.length > 0 ? [block] : []);
497
493
  return createUserMessage({
@@ -500,7 +496,10 @@ function createSettlementMessage(childId, terminal, continuable = true) {
500
496
  type: "text",
501
497
  text: summary
502
498
  },
503
- ...closingText.length === 0 ? [{
499
+ ...omitClosingText ? [{
500
+ type: "text",
501
+ text: "It sent you a message just before finishing, so its closing message is omitted."
502
+ }] : closingText.length === 0 ? [{
504
503
  type: "text",
505
504
  text: "It left no closing message."
506
505
  }] : [{
@@ -524,8 +523,7 @@ function createSettlementMessage(childId, terminal, continuable = true) {
524
523
  }
525
524
  });
526
525
  }
527
- //#endregion
528
- //#region src/vendor/dsh-subagent/continuation-messages.ts
526
+ // src/vendor/dsh-subagent/continuation-messages.ts
529
527
  /**
530
528
  * Append adjacent-Agent return guidance to a continuable child's initial task.
531
529
  * @param parentId - durable parent session id named in the guidance.
@@ -539,8 +537,7 @@ function withContinuableReturnGuidance(parentId, prompt) {
539
537
  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.`
540
538
  }];
541
539
  }
542
- //#endregion
543
- //#region src/vendor/dsh-subagent/descriptor.ts
540
+ // src/vendor/dsh-subagent/descriptor.ts
544
541
  /**
545
542
  * The durable subagent-child descriptor: the versioned, model-hidden
546
543
  * `subagent/descriptor` session event that identifies every session-backed
@@ -835,8 +832,7 @@ function establishExternalCatalogChild(parent, childId, label) {
835
832
  label
836
833
  });
837
834
  }
838
- //#endregion
839
- //#region src/vendor/dsh-subagent/internal.ts
835
+ // src/vendor/dsh-subagent/internal.ts
840
836
  /** Process-stable identity carried only by the standard adjacent-Agent messaging tool. */
841
837
  const adjacentAgentSendMessageTool = Symbol.for("dsh.subagent.adjacentAgentSendMessageTool");
842
838
  /**
@@ -853,8 +849,7 @@ function isAdjacentAgentSendMessageTool(definition) {
853
849
  * @internal
854
850
  */
855
851
  const deliverSubagentPrompt = Symbol.for("dsh.subagent.deliverPrompt");
856
- //#endregion
857
- //#region src/vendor/dsh-subagent/structured.ts
852
+ // src/vendor/dsh-subagent/structured.ts
858
853
  /** The model-facing tool name a structured child must call to finish. */
859
854
  const STRUCTURED_OUTPUT_TOOL = "structured_output";
860
855
  /**
@@ -950,8 +945,7 @@ function attachStructuredRuntime(childCtx, schema, canComplete) {
950
945
  acceptsInput: () => staged.size === 0 && pending === void 0 && captured === void 0
951
946
  };
952
947
  }
953
- //#endregion
954
- //#region src/vendor/dsh-subagent/assistant-output.ts
948
+ // src/vendor/dsh-subagent/assistant-output.ts
955
949
  /**
956
950
  * Canonical selection of a child's final assistant output. Backend run results
957
951
  * and `subagent/end.lastAssistantMessage` apply the same rule: select the last
@@ -1016,8 +1010,7 @@ function finalAssistantOutput(events) {
1016
1010
  for (const event of events) fold.push(event);
1017
1011
  return fold.collect();
1018
1012
  }
1019
- //#endregion
1020
- //#region src/vendor/dsh-subagent/activation.ts
1013
+ // src/vendor/dsh-subagent/activation.ts
1021
1014
  /** Process-local slots shared through uninterrupted continuable parent links. */
1022
1015
  var ActivationPool = class {
1023
1016
  slots = /* @__PURE__ */ new Set();
@@ -1119,8 +1112,7 @@ var ChildLock = class {
1119
1112
  return result;
1120
1113
  }
1121
1114
  };
1122
- //#endregion
1123
- //#region src/manager.ts
1115
+ // src/manager.ts
1124
1116
  /**
1125
1117
  * Owns subagent startup, message admission, cold resume, and execution lifetimes.
1126
1118
  * One child lock orders input acceptance and closure; one activation map owns
@@ -1770,7 +1762,8 @@ var SubagentManager = class {
1770
1762
  outputStart: handle.agent.session.seq,
1771
1763
  structured,
1772
1764
  failureAt: void 0,
1773
- poke: Promise.withResolvers()
1765
+ poke: Promise.withResolvers(),
1766
+ omitClosingText: false
1774
1767
  };
1775
1768
  }
1776
1769
  const observer = this.host.observeActivation(provider, childId, parent);
@@ -1801,8 +1794,14 @@ var SubagentManager = class {
1801
1794
  if (activation.kind === "local") {
1802
1795
  observeLocalFailure(activation, wakeSettlement);
1803
1796
  activation.handle.agent.ctx.on("agent/inbox/inserted", wakeSettlement);
1804
- activation.handle.agent.ctx.on("agent/inbox/claimed", wakeSettlement);
1797
+ activation.handle.agent.ctx.on("agent/inbox/claimed", () => {
1798
+ activation.omitClosingText = false;
1799
+ wakeSettlement();
1800
+ });
1805
1801
  activation.handle.agent.ctx.on("agent/inbox/discarded", wakeSettlement);
1802
+ activation.handle.agent.ctx.on("session/event", (_session, event) => {
1803
+ if (event.type === "tool/call") activation.omitClosingText = false;
1804
+ });
1806
1805
  }
1807
1806
  observer.start(activationAgent(activation));
1808
1807
  } catch (error) {
@@ -1992,7 +1991,7 @@ var SubagentManager = class {
1992
1991
  try {
1993
1992
  const parent = this.ctx.agents.get(activation.parent.id);
1994
1993
  if (parent !== activation.parent) return;
1995
- const message = createSettlementMessage(activation.childId, terminal, activationAgent(activation) !== void 0);
1994
+ const message = createSettlementMessage(activation.childId, terminal, activationAgent(activation) !== void 0, activation.kind === "local" && activation.omitClosingText);
1996
1995
  if (this.closingTeardownFor(parent) !== void 0) {
1997
1996
  parent.inject(message);
1998
1997
  return;
@@ -2066,6 +2065,7 @@ var SubagentManager = class {
2066
2065
  if (parent !== activation.parent) throw new SubagentError("direct parent is not live; the message was not delivered", "PARENT_UNAVAILABLE");
2067
2066
  const message = createAgentMessage(sender, content);
2068
2067
  this.sendAgentMessage(parent, message);
2068
+ activation.omitClosingText = true;
2069
2069
  return message.id;
2070
2070
  }
2071
2071
  /** Send one Agent message while translating only the target's own rejection. */
@@ -2207,8 +2207,7 @@ function installDelegationContext(ctx) {
2207
2207
  };
2208
2208
  });
2209
2209
  }
2210
- //#endregion
2211
- //#region src/vendor/dsh-subagent/list-children.ts
2210
+ // src/vendor/dsh-subagent/list-children.ts
2212
2211
  /**
2213
2212
  * Read one parent's durable catalog through a live-preferred Session observation.
2214
2213
  * @param ctx - context carrying the Session query service.
@@ -2304,8 +2303,7 @@ async function listDescendants(ctx, rootSessionId, signal) {
2304
2303
  function assertListingNotCancelled(signal) {
2305
2304
  if (signal?.aborted) throw new SubagentError("subagent listing was cancelled", "CANCELLED");
2306
2305
  }
2307
- //#endregion
2308
- //#region src/vendor/dsh-subagent/archive-admission.ts
2306
+ // src/vendor/dsh-subagent/archive-admission.ts
2309
2307
  /**
2310
2308
  * Answer `workspace/session-activity` with the running subagent descendants of
2311
2309
  * the asked Session, and `workspace/session-stop` by cancelling each of them
@@ -2380,8 +2378,7 @@ async function describe(ctx, child) {
2380
2378
  return { id: child.id };
2381
2379
  }
2382
2380
  }
2383
- //#endregion
2384
- //#region src/vendor/dsh-subagent/projection.ts
2381
+ // src/vendor/dsh-subagent/projection.ts
2385
2382
  /**
2386
2383
  * Pure session projections for subagent identity (mode/label) and active-turn
2387
2384
  * duration.
@@ -2536,8 +2533,7 @@ const subagentIdentityProjectionDefinition = {
2536
2533
  },
2537
2534
  stateVersion: 2
2538
2535
  };
2539
- //#endregion
2540
- //#region src/vendor/dsh-subagent/out-of-process.ts
2536
+ // src/vendor/dsh-subagent/out-of-process.ts
2541
2537
  /**
2542
2538
  * Provider-side vocabulary for OUT-OF-PROCESS subagent backends — the pieces
2543
2539
  * that enforce this seam's own contracts around a child in another process:
@@ -2688,8 +2684,7 @@ function subprocessRunHandle(parts) {
2688
2684
  }
2689
2685
  };
2690
2686
  }
2691
- //#endregion
2692
- //#region src/index.ts
2687
+ // src/index.ts
2693
2688
  var __create = Object.create;
2694
2689
  var __defProp = Object.defineProperty;
2695
2690
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -2805,10 +2800,10 @@ var SubagentRuntime = class extends (_b = TypertRemoteService) {
2805
2800
  if (this.manager === manager) this.manager = void 0;
2806
2801
  }, "subagents.managerBinding()");
2807
2802
  });
2808
- ctx.inject(["sessionProjections"], (projectionCtx) => {
2809
- projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition);
2810
- projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
2811
- projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
2803
+ ctx.inject(["sessionProjections"], async (projectionCtx) => {
2804
+ await projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition);
2805
+ await projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
2806
+ await projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
2812
2807
  });
2813
2808
  ctx.inject(["agents"], (agentsCtx) => {
2814
2809
  installSubagentArchiveAdmission(agentsCtx);
@@ -3105,5 +3100,4 @@ __publicField(SubagentRuntime, "Config", z.object({
3105
3100
  localizedReturnGuidancePresets: z.array(z.string()).default([]).hidden()
3106
3101
  }));
3107
3102
  __publicField(SubagentRuntime, "inject", ["workingDirectory"]);
3108
- //#endregion
3109
3103
  export { AssistantOutputFold, NO_START_CAPABILITIES, STRUCTURED_OUTPUT_TOOL, SUBAGENT_DESCRIPTOR_VERSION, SubagentDepthError, SubagentError, SubagentRunId, SubagentRuntime, SubagentRuntime as default, appendDelegatedPolicyOverrides, applyChildComposition, assertPositiveFinite, assertSubagentMaxDepth, assertUsableCwd, captureDelegatedPolicyOverrides, childSessionMeta, delegationDepthOf, finalAssistantOutput, foldSubagentDescriptor, parentAgentOptionsForDelegation, resolveChildAgentOptions, resolveChildDepth, settleRunResult, snapshotSubagentDescriptor, subprocessRunHandle };
package/dist/rows.d.mts CHANGED
@@ -1,4 +1,3 @@
1
- //#region src/rows.d.ts
2
1
  export interface PatchRow {
3
2
  readonly id?: string;
4
3
  readonly disabled?: boolean;
@@ -12,5 +11,4 @@ export interface RowEntry {
12
11
  export interface SubagentRowsOptions {
13
12
  readonly localizedReturnGuidancePresets?: readonly string[];
14
13
  }
15
- export declare function subagentRows(options?: SubagentRowsOptions): readonly PatchRow[];
16
- //#endregion
14
+ export declare function subagentRows(options?: SubagentRowsOptions): readonly PatchRow[];
package/dist/rows.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/rows.ts
1
+ // src/rows.ts
2
2
  function subagentRows(options = {}) {
3
3
  const presets = options.localizedReturnGuidancePresets;
4
4
  return [{ insert: [{
@@ -7,5 +7,4 @@ function subagentRows(options = {}) {
7
7
  ...presets === void 0 ? {} : { config: { localizedReturnGuidancePresets: [...presets] } }
8
8
  }] }];
9
9
  }
10
- //#endregion
11
10
  export { subagentRows };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morlay/dsh-subagent",
3
- "version": "0.0.10",
3
+ "version": "0.0.11-alpha.0",
4
4
  "description": "Thin-shell fork of @deepseek-ai/dsh-subagent: takes over the official `subagent` row for two wording changes — the continuable child's return guidance in Chinese wording and the child's Chinese delegation-scope runtime context (`subagent:delegation`) — plus the row-id reuse (same `subagent` id, so the official settings card stays); everything not intentionally changed is imported from the vendored upstream source.",
5
5
  "keywords": [
6
6
  "dsh",
@@ -34,37 +34,37 @@
34
34
  "./locale/*.json": "./locale/*.json"
35
35
  },
36
36
  "dependencies": {
37
- "@deepseek-ai/dsh-brand": "^0.2.1-rc.1",
38
- "@deepseek-ai/schemastery": "~3.18.5"
37
+ "@deepseek-ai/dsh-brand": "^0.2.2-alpha.2",
38
+ "@deepseek-ai/schemastery": "~3.18.6-alpha.1"
39
39
  },
40
40
  "devDependencies": {
41
- "@deepseek-ai/dsh-agent-loop": "^0.2.1-rc.1",
42
- "@deepseek-ai/dsh-agent-loop-testkit": "^0.2.1-rc.1",
43
- "@deepseek-ai/dsh-chunked-list": "^0.2.1-rc.1",
44
- "@deepseek-ai/dsh-session-persistence-jsonl": "^0.2.1-rc.1",
45
- "@deepseek-ai/dsh-subagent-fork-in-process": "^0.2.1-rc.1",
46
- "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.2.1-rc.1",
47
- "@deepseek-ai/dsh-tool-subagent-control": "^0.2.1-rc.1",
48
- "@deepseek-ai/dsh-util-values": "^0.2.1-rc.1",
49
- "@deepseek-ai/schemastery": "~3.18.5",
41
+ "@deepseek-ai/dsh-agent-loop": "^0.2.2-alpha.2",
42
+ "@deepseek-ai/dsh-agent-loop-testkit": "^0.2.2-alpha.2",
43
+ "@deepseek-ai/dsh-chunked-list": "^0.2.2-alpha.2",
44
+ "@deepseek-ai/dsh-session-persistence-jsonl": "^0.2.2-alpha.2",
45
+ "@deepseek-ai/dsh-subagent-fork-in-process": "^0.2.2-alpha.2",
46
+ "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.2.2-alpha.2",
47
+ "@deepseek-ai/dsh-tool-subagent-control": "^0.2.2-alpha.2",
48
+ "@deepseek-ai/dsh-util-values": "^0.2.2-alpha.2",
49
+ "@deepseek-ai/schemastery": "~3.18.6-alpha.1",
50
50
  "zod": "^4.4.3"
51
51
  },
52
52
  "peerDependencies": {
53
- "@deepseek-ai/cordis": "~4.0.5",
54
- "@deepseek-ai/dsh-agent": "^0.2.1-rc.1",
55
- "@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-rc.1",
56
- "@deepseek-ai/dsh-attachment": "^0.2.1-rc.1",
57
- "@deepseek-ai/dsh-llm": "^0.2.1-rc.1",
58
- "@deepseek-ai/dsh-scope": "^0.2.1-rc.1",
59
- "@deepseek-ai/dsh-session": "^0.2.1-rc.1",
60
- "@deepseek-ai/dsh-session-persistence": "^0.2.1-rc.1",
61
- "@deepseek-ai/dsh-session-query": "^0.2.1-rc.1",
62
- "@deepseek-ai/dsh-subagent": "^0.2.1-rc.1",
63
- "@deepseek-ai/dsh-system-prompt": "^0.2.1-rc.1",
64
- "@deepseek-ai/dsh-tools": "^0.2.1-rc.1",
65
- "@deepseek-ai/dsh-typert-protocol": "^0.2.1-rc.1",
66
- "@deepseek-ai/dsh-util-time": "^0.2.1-rc.1",
67
- "@deepseek-ai/dsh-working-directory": "^0.2.1-rc.1"
53
+ "@deepseek-ai/cordis": "~4.0.6-alpha.1",
54
+ "@deepseek-ai/dsh-agent": "^0.2.2-alpha.2",
55
+ "@deepseek-ai/dsh-agent-preset-registry": "^0.2.2-alpha.2",
56
+ "@deepseek-ai/dsh-attachment": "^0.2.2-alpha.2",
57
+ "@deepseek-ai/dsh-llm": "^0.2.2-alpha.2",
58
+ "@deepseek-ai/dsh-scope": "^0.2.2-alpha.2",
59
+ "@deepseek-ai/dsh-session": "^0.2.2-alpha.2",
60
+ "@deepseek-ai/dsh-session-persistence": "^0.2.2-alpha.2",
61
+ "@deepseek-ai/dsh-session-query": "^0.2.2-alpha.2",
62
+ "@deepseek-ai/dsh-subagent": "^0.2.2-alpha.2",
63
+ "@deepseek-ai/dsh-system-prompt": "^0.2.2-alpha.2",
64
+ "@deepseek-ai/dsh-tools": "^0.2.2-alpha.2",
65
+ "@deepseek-ai/dsh-typert-protocol": "^0.2.2-alpha.2",
66
+ "@deepseek-ai/dsh-util-time": "^0.2.2-alpha.2",
67
+ "@deepseek-ai/dsh-working-directory": "^0.2.2-alpha.2"
68
68
  },
69
69
  "peerDependenciesMeta": {
70
70
  "@deepseek-ai/dsh-session-persistence": {
@@ -75,7 +75,7 @@
75
75
  }
76
76
  },
77
77
  "engines": {
78
- "dsh": ">= 0.2.1-rc.1 < 0.2.2"
78
+ "dsh": ">= 0.2.2-alpha.2 < 0.2.3"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "pnpm exec tsdown"
@@ -152,12 +152,15 @@ function settlementSummary(
152
152
  * @param childId - durable child session id named in the notice.
153
153
  * @param terminal - recorded terminal state for the settled Activation.
154
154
  * @param continuable - whether the child can accept another task.
155
+ * @param omitClosingText - replace the closing text with a note that the child
156
+ * already reported to its parent; the parent should not read the result twice.
155
157
  * @returns the durable user-message representation delivered to the parent.
156
158
  */
157
159
  export function createSettlementMessage(
158
160
  childId: SessionId,
159
161
  terminal: SubagentResult,
160
162
  continuable = true,
163
+ omitClosingText = false,
161
164
  ): ReturnType<typeof createUserMessage> {
162
165
  const summary = settlementSummary(childId, terminal.stopReason, continuable);
163
166
  // Parent providers receive this notice as a user message and may reject
@@ -169,9 +172,11 @@ export function createSettlementMessage(
169
172
  return createUserMessage({
170
173
  content: [
171
174
  { type: "text" as const, text: summary },
172
- ...(closingText.length === 0
173
- ? [{ type: "text" as const, text: "It left no closing message." }]
174
- : [{ type: "text" as const, text: "Its closing message:" }, ...closingText]),
175
+ ...(omitClosingText
176
+ ? [{ type: "text" as const, text: "It sent you a message just before finishing, so its closing message is omitted." }]
177
+ : closingText.length === 0
178
+ ? [{ type: "text" as const, text: "It left no closing message." }]
179
+ : [{ type: "text" as const, text: "Its closing message:" }, ...closingText]),
175
180
  ...(terminal.structured !== undefined
176
181
  ? [
177
182
  {
package/src/index.ts CHANGED
@@ -238,10 +238,11 @@ export class SubagentRuntime extends TypertRemoteService {
238
238
  "subagents.managerBinding()",
239
239
  );
240
240
  });
241
- ctx.inject(["sessionProjections"], (projectionCtx) => {
242
- projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition);
243
- projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
244
- projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
241
+ ctx.inject(["sessionProjections"], async (projectionCtx) => {
242
+ // 上游 0.2.1-rc.2 起 `register()` 是异步的(句柄随注册一起交付),注册面要 await。
243
+ await projectionCtx.sessionProjections.register(subagentCatalogProjectionDefinition);
244
+ await projectionCtx.sessionProjections.register(subagentTimingProjectionDefinition);
245
+ await projectionCtx.sessionProjections.register(subagentIdentityProjectionDefinition);
245
246
  });
246
247
  // Archive admission: this runtime is the owner that knows which live
247
248
  // children descend from a Session and how a parent stops them.
package/src/manager.ts CHANGED
@@ -1068,6 +1068,9 @@ export class SubagentManager {
1068
1068
  structured,
1069
1069
  failureAt: undefined,
1070
1070
  poke: Promise.withResolvers<void>(),
1071
+ // 子代理的收尾文本是否该省略(上游 0.2.1-rc.2 的 `omitClosingText`):最后一条给直接父代理的
1072
+ // 消息已经交代了结果、之后又没有认领新输入时,结算消息不再重复贴一遍关闭文本。
1073
+ omitClosingText: false,
1071
1074
  };
1072
1075
  }
1073
1076
  const observer = this.host.observeActivation(provider, childId, parent);
@@ -1102,8 +1105,16 @@ export class SubagentManager {
1102
1105
  if (activation.kind === "local") {
1103
1106
  observeLocalFailure(activation, wakeSettlement);
1104
1107
  activation.handle.agent.ctx.on("agent/inbox/inserted", wakeSettlement);
1105
- activation.handle.agent.ctx.on("agent/inbox/claimed", wakeSettlement);
1108
+ activation.handle.agent.ctx.on("agent/inbox/claimed", () => {
1109
+ // 认领了新输入 = 关闭文本可能报告子代理最后那条消息没有的工作。
1110
+ activation.omitClosingText = false;
1111
+ wakeSettlement();
1112
+ });
1106
1113
  activation.handle.agent.ctx.on("agent/inbox/discarded", wakeSettlement);
1114
+ // 那条消息之后又落了工具调用,也作废"省略关闭文本"的判断。
1115
+ activation.handle.agent.ctx.on("session/event", (_session, event) => {
1116
+ if (event.type === "tool/call") activation.omitClosingText = false;
1117
+ });
1107
1118
  }
1108
1119
  observer.start(activationAgent(activation));
1109
1120
  } catch (error: unknown) {
@@ -1367,6 +1378,7 @@ export class SubagentManager {
1367
1378
  activation.childId,
1368
1379
  terminal,
1369
1380
  activationAgent(activation) !== undefined,
1381
+ activation.kind === "local" && activation.omitClosingText,
1370
1382
  );
1371
1383
  if (this.closingTeardownFor(parent) !== undefined) {
1372
1384
  parent.inject(message);
@@ -1463,7 +1475,7 @@ export class SubagentManager {
1463
1475
  }
1464
1476
 
1465
1477
  /** Deliver one resident continuable child's message to its live direct parent. */
1466
- private sendToParent(activation: Activation, sender: Agent, content: ContentBlock[]): MessageId {
1478
+ private sendToParent(activation: LocalActivation, sender: Agent, content: ContentBlock[]): MessageId {
1467
1479
  /* v8 ignore next 6 -- only synchronous re-entrant teardown can open this
1468
1480
  * transaction between exact-agent authorization and this no-await span. */
1469
1481
  if (activation.closing !== undefined) {
@@ -1481,6 +1493,8 @@ export class SubagentManager {
1481
1493
  }
1482
1494
  const message = createAgentMessage(sender, content);
1483
1495
  this.sendAgentMessage(parent, message);
1496
+ // 这条就是"给直接父代理的收尾交代":结算消息不必再贴一遍关闭文本。
1497
+ activation.omitClosingText = true;
1484
1498
  return message.id;
1485
1499
  }
1486
1500