@deepseek-ai/dsh-tool-subagent 0.1.5-rc.2 → 0.1.6-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/subagent/tool-subagent/README.md
5
- README.md: 97bb9b143f003c830b68ffae9e25dee588a8fa67
6
- README.zh.md: 1804f8f5da2dcd8fbdd043d247e6c234ea090529
5
+ README.md: a84e6c1ed62ccf15f7477a121c4fbae4d45276f6
6
+ README.zh.md: 4345efbcecf845193231c7faebb992938e550abc
package/README.md CHANGED
@@ -50,7 +50,7 @@ Load the subagent service, an in-process or remote backend, and this tool; then
50
50
  | `agentOptions` | — | Configured child `provider`, `model`, adapter-owned `reasoningEffort`, and positive `maxTokens` defaults; requires provider `agentOptions` support and overlays any provider-owned route defaults |
51
51
  | `persona` | — | Per-child persona; requires the provider's `persona` capability |
52
52
  | `toolFilter` | — | Per-child global-tool restriction; requires the `toolFilter` capability |
53
- | `maxDepth` | `3` | Absolute delegation-depth cap (`0` forbids delegation); `'provider-managed'` sends no cap to an out-of-process provider |
53
+ | `maxDepth` | Host setting (`1`) | Absolute delegation-depth cap (`0` forbids delegation); `'provider-managed'` sends no cap to an out-of-process provider |
54
54
 
55
55
  The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-tool-subagent) is the exhaustive source for every accepted field and its JSDoc.
56
56
 
@@ -60,7 +60,7 @@ Under `one-shot` policy, an omitted `run_in_background` waits in the foreground
60
60
 
61
61
  Under `continuable` policy, an omitted or `true` `run_in_background` starts a durable child and returns `started subagent <childId>` without waiting for a result; the runtime delivers one settlement notice when the child's Activation ends, and the optional `send_message` tool sends it more work. Set `run_in_background: false` to wait for the result in the foreground.
62
62
 
63
- `maxDepth` caps recursion (default `3`; `0` forbids delegation) and requires a provider with the `depthLimit` capability; `'provider-managed'` leaves the budget to an out-of-process provider. `persona` and `toolFilter` configure every child when the provider supports them, and the tool stays visible at the cap — each attempted start checks the calling agent's current depth and rejects with an errored result.
63
+ `maxDepth` caps recursion (`0` forbids delegation); omission reads the current Host `subagent.maxDepth` setting, initially `1`, at each delegation. A numeric depth requires a provider with the `depthLimit` capability; `'provider-managed'` leaves the budget to an out-of-process provider. `persona` and `toolFilter` configure every child when the provider supports them, and the tool stays visible at the cap — each attempted start checks the calling agent's current depth and rejects with an errored result.
64
64
 
65
65
  ### Selecting a child LLM
66
66
 
@@ -80,7 +80,7 @@ This section explains how the tool mirrors provider lifecycle and settles runs;
80
80
 
81
81
  ### Design concept
82
82
 
83
- One instance is one provider plus one tool name. The plugin mirrors provider lifecycle: it registers the tool when the named provider appears and disposes it when the provider leaves, so sibling load order and HMR replacement cannot strand a dangling tool. Direct Agent setup passes its unpublished Session explicitly and awaits installation before publication. A settings-backed standing preset receives each matching Agent from lifecycle events, selects policy from its Session, and installs through its Context. A numeric `maxDepth` or configured LLM selection the provider cannot enforce fails the mount instead of the first delegation. At most one instance in a tool scope may own model selection because `list_subagent_models` has a global name.
83
+ One instance is one provider plus one tool name. The plugin mirrors provider lifecycle: it registers the tool when the named provider appears and disposes it when the provider leaves, so sibling load order and HMR replacement cannot strand a dangling tool. Direct Agent setup passes its unpublished Session explicitly and awaits installation before publication. A settings-backed standing preset receives each matching Agent through `agent/created`, selects policy from its Session, and awaits installation through its Context; installation failure rejects creation. A numeric `maxDepth` or configured LLM selection the provider cannot enforce fails the mount instead of the first delegation. At most one instance in a tool scope may own model selection because `list_subagent_models` has a global name.
84
84
 
85
85
  ### Foreground settlement
86
86
 
@@ -208,7 +208,7 @@ Append-only; newly visible content follows the reusable request prefix and does
208
208
 
209
209
  These limits define what this tool does not return or enforce; they are current package constraints.
210
210
 
211
- - **Background runs expose no result through this tool** — a one-shot task's final output is collected through the generic task surface, and a continuable child's output stays in its own session, read by its subagent id. The settlement notice states how that child ended and carries any final assistant message, but it is not this call's return value and cannot be awaited here.
211
+ - **Background runs expose no result through this tool** — a one-shot task's final output is collected through the generic task surface, and a continuable child's output stays in its own session, read by its subagent id. The settlement notice states how that child ended and carries nonempty text from its final assistant output, but it is not this call's return value and cannot be awaited here.
212
212
  - **Duplicate names across waiting one-shot instances are detected late** (`TODO(subagent-dup-toolname)`) — continuable instances reserve their prompt-section name during plugin application, but preventing provider-registration rollback for waiting one-shot instances requires a registry of intended names.
213
213
  - **Shipped fork tools cannot select a child LLM route** — they inherit the parent's provider and model to keep the copied conversation prefix eligible for KV Cache reuse. Re-enable selection only when route changes preserve reuse or expose a bounded recomputation cost.
214
214
  - **Non-routing child policy is fixed per instance** — another persona, tool filter, or depth cap requires another distinctly named tool. LLM selection requires an enabled per-Session preference and a provider that advertises `agentOptions`; both in-process providers and DSH SDK advertise it, while ACP, Codex, and Claude Code reject it rather than ignore it.
package/README.zh.md CHANGED
@@ -50,7 +50,7 @@ kind: "package-reference"
50
50
  | `agentOptions` | — | 配置的子级 `provider`、`model`、适配器所有的 `reasoningEffort` 与正整数 `maxTokens` 默认值;要求提供方支持 `agentOptions`,并会覆盖提供方持有的路由默认值 |
51
51
  | `persona` | — | 每个子 agent 独立的 persona;要求提供方具备 `persona` 能力 |
52
52
  | `toolFilter` | — | 每个子 agent 独立的全局工具限制;要求提供方具备 `toolFilter` 能力 |
53
- | `maxDepth` | `3` | 绝对委派深度上限(`0` 禁止委派);`'provider-managed'` 不向进程外提供方发送上限 |
53
+ | `maxDepth` | Host 设置(`1`) | 绝对委派深度上限(`0` 禁止委派);`'provider-managed'` 不向进程外提供方发送上限 |
54
54
 
55
55
  生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-tool-subagent)是每个受支持字段及其 JSDoc 的穷尽式真源。
56
56
 
@@ -60,7 +60,7 @@ kind: "package-reference"
60
60
 
61
61
  `continuable` 策略下,省略或为 `true` 的 `run_in_background` 会启动一个持久化子 agent,并返回 `started subagent <childId>`,不等待结果;子 agent 的 Activation 结束时,运行时投递一条结算通知,可选的 `send_message` 工具会向它发送更多工作。把 `run_in_background` 设为 `false` 可在前台等待结果。
62
62
 
63
- `maxDepth` 限制递归深度(默认 `3`;`0` 禁止委派),并要求提供方具备 `depthLimit` 能力;`'provider-managed'` 把预算留给进程外提供方。当提供方支持时,`persona` 与 `toolFilter` 会配置每个子 agent;工具在达到上限时仍然可见——每次尝试启动都会检查调用 agent 的当前深度,被拒绝时返回出错的工具结果。
63
+ `maxDepth` 限制递归深度(`0` 禁止委派);省略时,每次委派读取 Host 当前的 `subagent.maxDepth` 设置,初始值为 `1`。数值深度要求提供方具备 `depthLimit` 能力;`'provider-managed'` 把预算留给进程外提供方。当提供方支持时,`persona` 与 `toolFilter` 会配置每个子 agent;工具在达到上限时仍然可见——每次尝试启动都会检查调用 agent 的当前深度,被拒绝时返回出错的工具结果。
64
64
 
65
65
  ### 选择子级 LLM
66
66
 
@@ -80,7 +80,7 @@ kind: "package-reference"
80
80
 
81
81
  ### 设计理念
82
82
 
83
- 一个实例就是一个提供方加一个工具名称。插件镜像提供方生命周期:具名提供方出现时注册工具,提供方离开时释放工具,因此同级加载顺序与 HMR 替换不会让工具悬空。直接 Agent setup 显式传入尚未发布的 Session,并在发布前等待安装完成。由设置控制的常驻 preset 从生命周期事件接收每个匹配 Agent,从其 Session 选择策略,并通过其 Context 安装。提供方无法执行的数值型 `maxDepth` 或已配置 LLM 选择会在挂载时失败,而不是在首次委派时失败。每个工具作用域内最多一个实例可以拥有模型选择,因为 `list_subagent_models` 使用全局名称。
83
+ 一个实例就是一个提供方加一个工具名称。插件镜像提供方生命周期:具名提供方出现时注册工具,提供方离开时释放工具,因此同级加载顺序与 HMR 替换不会让工具悬空。直接 Agent setup 显式传入尚未发布的 Session,并在发布前等待安装完成。由设置控制的常驻 preset 通过 `agent/created` 接收每个匹配 Agent,从其 Session 选择策略,并等待通过其 Context 发起的安装;安装失败会拒绝创建。提供方无法执行的数值型 `maxDepth` 或已配置 LLM 选择会在挂载时失败,而不是在首次委派时失败。每个工具作用域内最多一个实例可以拥有模型选择,因为 `list_subagent_models` 使用全局名称。
84
84
 
85
85
  ### 前台结算
86
86
 
@@ -177,7 +177,7 @@ Use subagent in the background by default. Start independent delegations togethe
177
177
 
178
178
  #### 模型看到什么
179
179
 
180
- 调用会保留描述与提示词。成功时只包含子 agent 的最终文本;其他结果变为 `Error: <终止原因>`,随后在存在时附上安全的提供方诊断,再附上任何部分 assistant 文本。子 agent 中间步骤不会进入父级。
180
+ 调用会保留描述与提示词。成功时只包含子 agent 的最终文本;其他结果变为 `Error: <stop reason>`,随后在存在时附上安全的提供方诊断,再附上任何部分 assistant 文本。子 agent 中间步骤不会进入父级。
181
181
 
182
182
  #### Token 影响
183
183
 
@@ -208,7 +208,7 @@ Use subagent in the background by default. Start independent delegations togethe
208
208
 
209
209
  这些限制说明本工具不返回或不强制执行什么;它们是当前包约束。
210
210
 
211
- - **后台运行不通过本工具公开结果**——一次性任务的最终输出通过通用 Task 接口收集,可继续子 agent 的输出留在其自身会话中,按其 subagent id 读取。结算通知会说明该子 agent 如何结束,并携带可能存在的最终 assistant 消息,但它不是本次调用的返回值,也无法在此等待。
211
+ - **后台运行不通过本工具公开结果**——一次性任务的最终输出通过通用 Task 接口收集,可继续子 agent 的输出留在其自身会话中,按其 subagent id 读取。结算通知会说明该子 agent 如何结束,并携带其最终 assistant 输出中的非空文本,但它不是本次调用的返回值,也无法在此等待。
212
212
  - **等待中的一次性实例较晚才发现重复名称**(`TODO(subagent-dup-toolname)`)——可继续实例会在插件应用期间预留提示词 section 名称,但若要阻止等待中的一次性实例回滚提供方注册,仍需要一份预期名称注册表。
213
213
  - **随附 fork 工具不能选择子级 LLM 路由**——它们继承父级提供方与模型,使复制的对话前缀仍有资格复用 KV Cache。仅当路由变更能保留复用或公开有界重算成本时,才重新启用选择。
214
214
  - **非路由子 agent 策略按实例固定**——另一个 persona、工具过滤器或深度上限需要另一个名称不同的工具。LLM 选择要求启用逐 Session 偏好,且提供方必须声明 `agentOptions`;两个进程内提供方和 DSH SDK 会声明该能力,而 ACP、Codex 与 Claude Code 会拒绝它,而不是忽略它。
package/lib/index.js CHANGED
@@ -266,7 +266,7 @@ const Config = z.object({
266
266
  allow: z.array(z.string()).default(void 0),
267
267
  deny: z.array(z.string()).default(void 0)
268
268
  }).default(void 0),
269
- maxDepth: z.union([z.natural().max(Number.MAX_SAFE_INTEGER), z.const("provider-managed")]).default(3)
269
+ maxDepth: z.union([z.natural().max(Number.MAX_SAFE_INTEGER), z.const("provider-managed")])
270
270
  });
271
271
  /** Render text blocks from the canonical JSON block array without trusting arbitrary values. */
272
272
  function outputValueText(values) {
@@ -374,7 +374,7 @@ function apply(ctx, config, session) {
374
374
  const modelSelectionCapable = config.modelSelectionSettings === true;
375
375
  ctx.sessionProjections.register(subagentModelSelectionProjectionDefinition);
376
376
  const assertSubagentProviderConfiguration = (subagentProvider) => {
377
- if (typeof config.maxDepth === "number" && !subagentProvider.capabilities.depthLimit) throw new Error(`tool-subagent: provider "${subagentProvider.name}" cannot enforce maxDepth (no depthLimit capability) — set maxDepth: 'provider-managed' to leave the recursion budget to the provider`);
377
+ if (ctx.subagents.resolveMaxDepth(config.maxDepth) !== void 0 && !subagentProvider.capabilities.depthLimit) throw new Error(`tool-subagent: provider "${subagentProvider.name}" cannot enforce maxDepth (no depthLimit capability) — set maxDepth: 'provider-managed' to leave the recursion budget to the provider`);
378
378
  if (config.agentOptions !== void 0 && !subagentProvider.capabilities.agentOptions) throw new Error(`tool-subagent: provider "${subagentProvider.name}" does not support child agentOptions`);
379
379
  if (modelSelectionCapable && !subagentProvider.capabilities.agentOptions) throw new Error(`tool-subagent: provider "${subagentProvider.name}" does not support child model selection`);
380
380
  if (continuable && subagentProvider.prepareContinuable === void 0) throw new Error(`tool-subagent: provider "${subagentProvider.name}" does not support \`backgroundMode: continuable\``);
@@ -505,7 +505,7 @@ function apply(ctx, config, session) {
505
505
  if (runtimeCtx.subagents.getProvider(config.provider) !== subagentProvider) throw new Error(`subagent provider "${config.provider}" changed while resolving the child LLM route; retry the delegation`);
506
506
  }
507
507
  exec.signal.throwIfAborted();
508
- const maxDepth = typeof config.maxDepth === "number" ? config.maxDepth : void 0;
508
+ const maxDepth = runtimeCtx.subagents.resolveMaxDepth(config.maxDepth);
509
509
  const request = {
510
510
  label: args.description,
511
511
  prompt: [{
@@ -616,7 +616,9 @@ function apply(ctx, config, session) {
616
616
  const installing = /* @__PURE__ */ new WeakSet();
617
617
  const belongsToComposition = (candidate) => scopeChainOf(scopeOf(candidate.ctx)).includes(compositionScope);
618
618
  const installScoped = (candidate) => {
619
- if (scopedInstalls.has(candidate) || installing.has(candidate)) return;
619
+ const existing = scopedInstalls.get(candidate);
620
+ if (existing !== void 0) return existing;
621
+ if (installing.has(candidate)) return;
620
622
  installing.add(candidate);
621
623
  let fiber;
622
624
  try {
@@ -632,6 +634,7 @@ function apply(ctx, config, session) {
632
634
  installing.delete(candidate);
633
635
  }
634
636
  scopedInstalls.set(candidate, fiber);
637
+ return fiber;
635
638
  };
636
639
  const removeScoped = (candidate) => {
637
640
  const fiber = scopedInstalls.get(candidate);
@@ -646,8 +649,8 @@ function apply(ctx, config, session) {
646
649
  for (const candidate of agents.list()) if (belongsToComposition(candidate)) installScoped(candidate);
647
650
  else removeScoped(candidate);
648
651
  };
649
- ctx.on("agent/created", ({ agent: created }) => {
650
- installScoped(created);
652
+ ctx.on("agent/created", async ({ agent: created }) => {
653
+ await installScoped(created);
651
654
  });
652
655
  ctx.on("agent/disposed", ({ agent: disposed }) => {
653
656
  removeScoped(disposed);
@@ -60,13 +60,14 @@ export interface Config {
60
60
  deny?: string[];
61
61
  };
62
62
  /**
63
- * Maximum child depth: a non-negative safe integer (default `3`; `0` forbids
64
- * delegation entirely), or `'provider-managed'` to send no cap. A numeric cap
63
+ * Maximum child depth: a non-negative safe integer (`0` forbids delegation),
64
+ * or `'provider-managed'` to send no cap. A numeric cap
65
65
  * requires the provider's `depthLimit` capability (mount fails loud
66
66
  * otherwise). The provider checks the calling agent's current depth at every
67
67
  * start; the tool remains model-visible so runtime policy owns rejection.
68
68
  * `'provider-managed'` is for an out-of-process provider whose recursion
69
- * budget belongs to the child runtime or its own deployment.
69
+ * budget belongs to the child runtime or its own deployment. Omission reads
70
+ * the current Host subagent depth setting (default `1`) at each delegation.
70
71
  */
71
72
  maxDepth?: number | 'provider-managed';
72
73
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-tool-subagent",
3
3
  "description": "Model-facing subagent delegation tool over the ctx.subagents seam",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -37,41 +37,41 @@
37
37
  ],
38
38
  "license": "MIT",
39
39
  "peerDependencies": {
40
- "@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
41
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
42
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
43
- "@deepseek-ai/dsh-session-projection": "^0.1.5-rc.2",
44
- "@deepseek-ai/dsh-scope": "^0.1.5-rc.2",
45
- "@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
46
- "@deepseek-ai/dsh-subagent": "^0.1.5-rc.2",
47
- "@deepseek-ai/dsh-system-prompt": "^0.1.5-rc.2",
48
- "@deepseek-ai/dsh-jobs": "^0.1.5-rc.2",
49
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
40
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
41
+ "@deepseek-ai/dsh-invariants": "^0.1.6-alpha.2",
42
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
43
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
44
+ "@deepseek-ai/dsh-session-projection": "^0.1.6-alpha.2",
45
+ "@deepseek-ai/dsh-settings": "^0.1.6-alpha.2",
46
+ "@deepseek-ai/dsh-subagent": "^0.1.6-alpha.2",
47
+ "@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.2",
48
+ "@deepseek-ai/dsh-jobs": "^0.1.6-alpha.2",
49
+ "@deepseek-ai/dsh-tools": "^0.1.6-alpha.2",
50
50
  "@deepseek-ai/cordis": "^4.0.2",
51
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2"
51
+ "@deepseek-ai/dsh-scope": "^0.1.6-alpha.2"
52
52
  },
53
53
  "dependencies": {
54
54
  "zod": "^4.4.3",
55
55
  "@deepseek-ai/schemastery": "^3.18.2"
56
56
  },
57
57
  "devDependencies": {
58
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
59
+ "@deepseek-ai/dsh-invariants": "^0.1.6-alpha.2",
60
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
61
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
58
62
  "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
59
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
60
- "@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
61
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
62
- "@deepseek-ai/dsh-scope": "^0.1.5-rc.2",
63
- "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.5-rc.2",
64
- "@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.2",
65
- "@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
66
- "@deepseek-ai/dsh-subagent": "^0.1.5-rc.2",
67
- "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.1.5-rc.2",
68
- "@deepseek-ai/dsh-system-prompt": "^0.1.5-rc.2",
69
- "@deepseek-ai/dsh-jobs": "^0.1.5-rc.2",
70
- "@deepseek-ai/dsh-jobs-local": "^0.1.5-rc.2",
71
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
72
- "@deepseek-ai/dsh-tool-jobs": "^0.1.5-rc.2",
73
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
63
+ "@deepseek-ai/dsh-scope": "^0.1.6-alpha.2",
64
+ "@deepseek-ai/dsh-session-persistence": "^0.1.6-alpha.2",
65
+ "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.6-alpha.2",
66
+ "@deepseek-ai/dsh-subagent": "^0.1.6-alpha.2",
67
+ "@deepseek-ai/dsh-settings": "^0.1.6-alpha.2",
68
+ "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.1.6-alpha.2",
69
+ "@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.2",
70
+ "@deepseek-ai/dsh-jobs": "^0.1.6-alpha.2",
71
+ "@deepseek-ai/dsh-jobs-local": "^0.1.6-alpha.2",
72
+ "@deepseek-ai/dsh-tool-jobs": "^0.1.6-alpha.2",
73
+ "@deepseek-ai/dsh-tools": "^0.1.6-alpha.2",
74
74
  "@deepseek-ai/cordis": "^4.0.2",
75
- "@deepseek-ai/dsh-session-projection": "^0.1.5-rc.2"
75
+ "@deepseek-ai/dsh-session-projection": "^0.1.6-alpha.2"
76
76
  }
77
77
  }