@morlay/dsh-subagent 0.0.9 → 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.9",
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"
@@ -4,19 +4,19 @@
4
4
  * @module @deepseek-ai/dsh-subagent/continuation-messages
5
5
  */
6
6
 
7
- import type { Agent } from '@deepseek-ai/dsh-agent'
8
- import { boundContextSummary, createUserMessage } from '@deepseek-ai/dsh-llm'
9
- import type { ContentBlock } from '@deepseek-ai/dsh-llm'
10
- import type { SessionId } from '@deepseek-ai/dsh-session'
11
- import type { SubagentResult } from './vendor/dsh-subagent/types.ts'
7
+ import type { Agent } from "@deepseek-ai/dsh-agent";
8
+ import { boundContextSummary, createUserMessage } from "@deepseek-ai/dsh-llm";
9
+ import type { ContentBlock } from "@deepseek-ai/dsh-llm";
10
+ import type { SessionId } from "@deepseek-ai/dsh-session";
11
+ import type { SubagentResult } from "./vendor/dsh-subagent/types.ts";
12
12
 
13
13
  /** Durable attribution for one model-authored message between Agents. */
14
14
  export interface AgentMessageSource {
15
- readonly kind: 'agent-message'
15
+ readonly kind: "agent-message";
16
16
  /** A message another agent addressed to this one (`relay` context form). */
17
- readonly form: 'relay'
17
+ readonly form: "relay";
18
18
  /** Session id of the Agent whose tool call produced the message. */
19
- readonly senderSessionId: SessionId
19
+ readonly senderSessionId: SessionId;
20
20
  }
21
21
 
22
22
  /**
@@ -27,29 +27,29 @@ export interface AgentMessageSource {
27
27
  * transcript that merged them would credit the child with words it never wrote.
28
28
  */
29
29
  export interface SubagentSettledMessageSource {
30
- readonly kind: 'subagent-settled'
30
+ readonly kind: "subagent-settled";
31
31
  /** A runtime account shown without expanding the row (`notice` context form). */
32
- readonly form: 'notice'
32
+ readonly form: "notice";
33
33
  /** One-line account of how the child ended. */
34
- readonly summary: string
34
+ readonly summary: string;
35
35
  /** Session id of the child that settled. */
36
- readonly senderSessionId: SessionId
36
+ readonly senderSessionId: SessionId;
37
37
  }
38
38
 
39
- declare module '@deepseek-ai/dsh-llm' {
39
+ declare module "@deepseek-ai/dsh-llm" {
40
40
  interface MessageSourceMap {
41
- 'agent-message': AgentMessageSource
42
- 'subagent-settled': SubagentSettledMessageSource
41
+ "agent-message": AgentMessageSource;
42
+ "subagent-settled": SubagentSettledMessageSource;
43
43
  }
44
44
  }
45
45
 
46
46
  /** Build durable attribution for one adjacent-Agent message. */
47
47
  function agentMessageSource(sender: Agent): AgentMessageSource {
48
48
  return {
49
- kind: 'agent-message',
50
- form: 'relay',
49
+ kind: "agent-message",
50
+ form: "relay",
51
51
  senderSessionId: sender.id,
52
- }
52
+ };
53
53
  }
54
54
 
55
55
  /**
@@ -63,12 +63,9 @@ export function createAgentMessage(
63
63
  content: ContentBlock[],
64
64
  ): ReturnType<typeof createUserMessage> {
65
65
  return createUserMessage({
66
- content: [
67
- { type: 'text' as const, text: `Agent ${sender.id} sent a message: ` },
68
- ...content,
69
- ],
66
+ content: [{ type: "text" as const, text: `Agent ${sender.id} sent a message: ` }, ...content],
70
67
  source: agentMessageSource(sender),
71
- })
68
+ });
72
69
  }
73
70
 
74
71
  /**
@@ -87,8 +84,8 @@ export function localizedReturnGuidance(
87
84
  composedPreset: string | undefined,
88
85
  configured: readonly string[],
89
86
  ): boolean {
90
- if (configured.length === 0) return true
91
- return composedPreset !== undefined && configured.includes(composedPreset)
87
+ if (configured.length === 0) return true;
88
+ return composedPreset !== undefined && configured.includes(composedPreset);
92
89
  }
93
90
  /**
94
91
  * Append adjacent-Agent return guidance to a continuable child's initial task.
@@ -100,16 +97,17 @@ export function withContinuableReturnGuidance(
100
97
  parentId: SessionId,
101
98
  prompt: ContentBlock[],
102
99
  ): ContentBlock[] {
103
- const encodedParentId = JSON.stringify(parentId)
100
+ const encodedParentId = JSON.stringify(parentId);
104
101
  return [
105
102
  ...prompt,
106
103
  {
107
- type: 'text',
108
- text: `你的父智能体 id 是 ${encodedParentId}。完成前用 send_message({ agent_id: ${encodedParentId}, `
109
- + 'message: "<自包含的结论>" }) 把结果发给它。父智能体与你共享工作区,但不会自动收到你的对话、'
110
- + '工具输出与推理过程。发现会改变父智能体下一步行动的事情时也尽早再发一条;发消息不会结束你的回合。',
104
+ type: "text",
105
+ text:
106
+ `你的父智能体 id 是 ${encodedParentId}。完成前用 send_message({ agent_id: ${encodedParentId}, ` +
107
+ 'message: "<自包含的结论>" }) 把结果发给它。父智能体与你共享工作区,但不会自动收到你的对话、' +
108
+ "工具输出与推理过程。发现会改变父智能体下一步行动的事情时也尽早再发一条;发消息不会结束你的回合。",
111
109
  },
112
- ]
110
+ ];
113
111
  }
114
112
 
115
113
  /**
@@ -120,28 +118,32 @@ export function withContinuableReturnGuidance(
120
118
  * @param continuable - whether the child accepts a later message.
121
119
  * @returns the model-facing opening line of the settlement notice.
122
120
  */
123
- function settlementSummary(childId: SessionId, stopReason: SubagentResult['stopReason'], continuable: boolean): string {
124
- const subject = `Background subagent ${childId}`
121
+ function settlementSummary(
122
+ childId: SessionId,
123
+ stopReason: SubagentResult["stopReason"],
124
+ continuable: boolean,
125
+ ): string {
126
+ const subject = `Background subagent ${childId}`;
125
127
  switch (stopReason) {
126
- case 'completed':
128
+ case "completed":
127
129
  return continuable
128
130
  ? `${subject} finished and will do no further work unless you send it more.`
129
- : `${subject} finished. It cannot receive follow-up messages.`
130
- case 'aborted':
131
- return `${subject} was stopped before it finished.`
132
- case 'max-tokens':
133
- return `${subject} ran out of room before it finished.`
131
+ : `${subject} finished. It cannot receive follow-up messages.`;
132
+ case "aborted":
133
+ return `${subject} was stopped before it finished.`;
134
+ case "max-tokens":
135
+ return `${subject} ran out of room before it finished.`;
134
136
  // A pre-step rejection — a hook deny, a policy plugin — discarded input
135
137
  // the child had claimed, so the parent must not treat the task as done.
136
- case 'refusal':
137
- return `${subject} declined the task.`
138
- case 'error':
139
- return `${subject} failed before it finished.`
138
+ case "refusal":
139
+ return `${subject} declined the task.`;
140
+ case "error":
141
+ return `${subject} failed before it finished.`;
140
142
  /* v8 ignore next 4 -- `SubagentResult['stopReason']` is merge-extensible, so this arm
141
143
  * needs a backend that adds a variant; an unnameable ending is reported as unfinished
142
144
  * rather than silently as success. */
143
145
  default:
144
- return `${subject} ended abnormally (${String(stopReason)}) before it finished.`
146
+ return `${subject} ended abnormally (${String(stopReason)}) before it finished.`;
145
147
  }
146
148
  }
147
149
 
@@ -150,36 +152,48 @@ function settlementSummary(childId: SessionId, stopReason: SubagentResult['stopR
150
152
  * @param childId - durable child session id named in the notice.
151
153
  * @param terminal - recorded terminal state for the settled Activation.
152
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.
153
157
  * @returns the durable user-message representation delivered to the parent.
154
158
  */
155
159
  export function createSettlementMessage(
156
160
  childId: SessionId,
157
161
  terminal: SubagentResult,
158
162
  continuable = true,
163
+ omitClosingText = false,
159
164
  ): ReturnType<typeof createUserMessage> {
160
- const summary = settlementSummary(childId, terminal.stopReason, continuable)
165
+ const summary = settlementSummary(childId, terminal.stopReason, continuable);
161
166
  // Parent providers receive this notice as a user message and may reject
162
167
  // nontext assistant blocks. Keep this conversion local so SDK/UI consumers
163
168
  // retain the complete child output.
164
- const closingText = terminal.output.flatMap(block =>
165
- block.type === 'text' && block.text.length > 0 ? [block] : [],
166
- )
169
+ const closingText = terminal.output.flatMap((block) =>
170
+ block.type === "text" && block.text.length > 0 ? [block] : [],
171
+ );
167
172
  return createUserMessage({
168
173
  content: [
169
- { type: 'text' as const, text: summary },
170
- ...closingText.length === 0
171
- ? [{ type: 'text' as const, text: 'It left no closing message.' }]
172
- : [{ type: 'text' as const, text: 'Its closing message:' }, ...closingText],
173
- ...terminal.structured !== undefined
174
- ? [{ type: 'text' as const, text: `Structured result: ${JSON.stringify(terminal.structured)}` }] : [],
175
- ...terminal.diagnostic !== undefined
176
- ? [{ type: 'text' as const, text: terminal.diagnostic }] : [],
174
+ { type: "text" as const, text: summary },
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]),
180
+ ...(terminal.structured !== undefined
181
+ ? [
182
+ {
183
+ type: "text" as const,
184
+ text: `Structured result: ${JSON.stringify(terminal.structured)}`,
185
+ },
186
+ ]
187
+ : []),
188
+ ...(terminal.diagnostic !== undefined
189
+ ? [{ type: "text" as const, text: terminal.diagnostic }]
190
+ : []),
177
191
  ],
178
192
  source: {
179
- kind: 'subagent-settled' as const,
180
- form: 'notice' as const,
193
+ kind: "subagent-settled" as const,
194
+ form: "notice" as const,
181
195
  summary: boundContextSummary(summary),
182
196
  senderSessionId: childId,
183
197
  },
184
- })
198
+ });
185
199
  }