@qilin-agent/tool-subagent 3.1.3 → 3.1.5

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
@@ -5,117 +5,117 @@
5
5
  /:
6
6
  en: c6db6e2344a91be8
7
7
  zh: 4febc8331d506a22
8
- /qilin-tool-subagent:
9
- en: 124c70502cce9bc1
10
- zh: 4b4a0dcec9b86bbe
11
- /qilin-tool-subagent/summary:
8
+ /qilin-agent-tool-subagent:
9
+ en: d64c585d315ee220
10
+ zh: 72cf6607cdf6d31a
11
+ /qilin-agent-tool-subagent/summary:
12
12
  en: 04da983479776bfa
13
13
  zh: 17b955b0390dc448
14
- /qilin-tool-subagent/table-of-contents:
14
+ /qilin-agent-tool-subagent/table-of-contents:
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
17
- /qilin-tool-subagent/use-this-package:
18
- en: 3248a28bba2ef809
19
- zh: 807cc32c49fcb0cb
20
- /qilin-tool-subagent/use-this-package/minimal-configuration:
21
- en: 0dcc3c461eea237d
22
- zh: 5684463df5efbba6
23
- /qilin-tool-subagent/use-this-package/foreground-and-background-modes:
17
+ /qilin-agent-tool-subagent/use-this-package:
18
+ en: 93f1701f5209ecb5
19
+ zh: 6310fd012400aead
20
+ /qilin-agent-tool-subagent/use-this-package/minimal-configuration:
21
+ en: 00a36ae48c406e0c
22
+ zh: 4b6082f6a4592492
23
+ /qilin-agent-tool-subagent/use-this-package/foreground-and-background-modes:
24
24
  en: 8e7319bc2887ae5c
25
25
  zh: 87d5abdfbe7562df
26
- /qilin-tool-subagent/use-this-package/selecting-a-child-llm:
26
+ /qilin-agent-tool-subagent/use-this-package/selecting-a-child-llm:
27
27
  en: 484bf4ed5996539f
28
28
  zh: dcb461e031d435c4
29
- /qilin-tool-subagent/understand-the-implementation:
29
+ /qilin-agent-tool-subagent/understand-the-implementation:
30
30
  en: 6ce5f749256a7e6c
31
31
  zh: a4f2adb04a70d9cf
32
- /qilin-tool-subagent/understand-the-implementation/design-concept:
32
+ /qilin-agent-tool-subagent/understand-the-implementation/design-concept:
33
33
  en: 5ceacfed4ea0c648
34
34
  zh: 005284534923d854
35
- /qilin-tool-subagent/understand-the-implementation/foreground-settlement:
35
+ /qilin-agent-tool-subagent/understand-the-implementation/foreground-settlement:
36
36
  en: ccb36af6884ec89f
37
37
  zh: 41e9aa6d3cd75a41
38
- /qilin-tool-subagent/understand-the-implementation/background-routes:
38
+ /qilin-agent-tool-subagent/understand-the-implementation/background-routes:
39
39
  en: dfd6306019a63bea
40
40
  zh: 5055b66e19885e8d
41
- /qilin-tool-subagent/understand-the-implementation/context-sensitive-wording:
41
+ /qilin-agent-tool-subagent/understand-the-implementation/context-sensitive-wording:
42
42
  en: 1733728ac5aa6bb0
43
43
  zh: 341ffc6e21a289af
44
- /qilin-tool-subagent/understand-the-implementation/source-map:
44
+ /qilin-agent-tool-subagent/understand-the-implementation/source-map:
45
45
  en: 1f52c5f5c7caf04a
46
46
  zh: dba288fd0cf51e5d
47
- /qilin-tool-subagent/further-exploration:
48
- en: 4d76f17d7ff95960
49
- zh: 9d6eecba80c5912a
50
- /qilin-tool-subagent/model-experience:
47
+ /qilin-agent-tool-subagent/further-exploration:
48
+ en: 089b32fdb70fbf87
49
+ zh: 18c873bfec2611f5
50
+ /qilin-agent-tool-subagent/model-experience:
51
51
  en: 215e7ba838619b7b
52
52
  zh: a311da3843709f90
53
- /qilin-tool-subagent/model-experience/tool-schema:
53
+ /qilin-agent-tool-subagent/model-experience/tool-schema:
54
54
  en: e4c7376d4f29dbd5
55
55
  zh: 6b7a9eaf69c9ea53
56
- /qilin-tool-subagent/model-experience/tool-schema/what-the-model-sees:
57
- en: 5139cb3de9c8d0e3
58
- zh: 5e7baea85692f1f9
59
- /qilin-tool-subagent/model-experience/tool-schema/token-effect:
56
+ /qilin-agent-tool-subagent/model-experience/tool-schema/what-the-model-sees:
57
+ en: 8fc9f31c6b1d3d40
58
+ zh: 55e3fb12fba0be26
59
+ /qilin-agent-tool-subagent/model-experience/tool-schema/token-effect:
60
60
  en: 1aa53b7a4c24cc25
61
61
  zh: bebd5c5ce6443259
62
- /qilin-tool-subagent/model-experience/tool-schema/kv-cache-effect:
62
+ /qilin-agent-tool-subagent/model-experience/tool-schema/kv-cache-effect:
63
63
  en: 46f736c6c389052a
64
64
  zh: a7765541030e9104
65
- /qilin-tool-subagent/model-experience/model-selection-and-discovery:
65
+ /qilin-agent-tool-subagent/model-experience/model-selection-and-discovery:
66
66
  en: a4ca31b9cbacda6b
67
67
  zh: 91ac3e0784a14697
68
- /qilin-tool-subagent/model-experience/model-selection-and-discovery/what-the-model-sees:
68
+ /qilin-agent-tool-subagent/model-experience/model-selection-and-discovery/what-the-model-sees:
69
69
  en: 1c9dd328eaf96683
70
70
  zh: 3be88d3b00f51cfa
71
- /qilin-tool-subagent/model-experience/model-selection-and-discovery/token-effect:
71
+ /qilin-agent-tool-subagent/model-experience/model-selection-and-discovery/token-effect:
72
72
  en: 8137e72f630f0190
73
73
  zh: 73b1d9374b6cbccd
74
- /qilin-tool-subagent/model-experience/model-selection-and-discovery/kv-cache-effect:
74
+ /qilin-agent-tool-subagent/model-experience/model-selection-and-discovery/kv-cache-effect:
75
75
  en: 7dc47a34d5574fbd
76
76
  zh: bd7bd2a4da2f8ae2
77
- /qilin-tool-subagent/model-experience/system-prompt:
77
+ /qilin-agent-tool-subagent/model-experience/system-prompt:
78
78
  en: cf78b9dd5596495f
79
79
  zh: bd44560f8c2435e8
80
- /qilin-tool-subagent/model-experience/system-prompt/what-the-model-sees:
80
+ /qilin-agent-tool-subagent/model-experience/system-prompt/what-the-model-sees:
81
81
  en: 875f8a89292dde21
82
82
  zh: 670f911b0a149690
83
- /qilin-tool-subagent/model-experience/system-prompt/what-the-model-sees/tool-guidance-section:
83
+ /qilin-agent-tool-subagent/model-experience/system-prompt/what-the-model-sees/tool-guidance-section:
84
84
  en: 82b3cd08b3961c98
85
85
  zh: bdc2a34bcea16cac
86
- /qilin-tool-subagent/model-experience/system-prompt/token-effect:
86
+ /qilin-agent-tool-subagent/model-experience/system-prompt/token-effect:
87
87
  en: ed03868e8f551001
88
88
  zh: 53c10b979a48cf9b
89
- /qilin-tool-subagent/model-experience/system-prompt/kv-cache-effect:
89
+ /qilin-agent-tool-subagent/model-experience/system-prompt/kv-cache-effect:
90
90
  en: 5f2491d0ee8f440c
91
91
  zh: 14c06b9fe7096e09
92
- /qilin-tool-subagent/model-experience/foreground-result:
92
+ /qilin-agent-tool-subagent/model-experience/foreground-result:
93
93
  en: d83f1f25a3719c54
94
94
  zh: 445ca808e28dc936
95
- /qilin-tool-subagent/model-experience/foreground-result/what-the-model-sees:
95
+ /qilin-agent-tool-subagent/model-experience/foreground-result/what-the-model-sees:
96
96
  en: 7e5d19839fa69495
97
97
  zh: 0e7ff0d92571ec60
98
- /qilin-tool-subagent/model-experience/foreground-result/token-effect:
98
+ /qilin-agent-tool-subagent/model-experience/foreground-result/token-effect:
99
99
  en: 995810727b29f85f
100
100
  zh: 4ede7b437091d6ee
101
- /qilin-tool-subagent/model-experience/foreground-result/kv-cache-effect:
101
+ /qilin-agent-tool-subagent/model-experience/foreground-result/kv-cache-effect:
102
102
  en: f5d5f97a153f7c70
103
103
  zh: 3d6bc05b9eadfbc2
104
- /qilin-tool-subagent/model-experience/background-result:
104
+ /qilin-agent-tool-subagent/model-experience/background-result:
105
105
  en: 3f23f9211197b0b9
106
106
  zh: 8cff3c78249b66ff
107
- /qilin-tool-subagent/model-experience/background-result/what-the-model-sees:
107
+ /qilin-agent-tool-subagent/model-experience/background-result/what-the-model-sees:
108
108
  en: d2ba2d8a3e88478d
109
109
  zh: dee910d1d271f75c
110
- /qilin-tool-subagent/model-experience/background-result/token-effect:
110
+ /qilin-agent-tool-subagent/model-experience/background-result/token-effect:
111
111
  en: 3c67cdb1cbf53647
112
112
  zh: bfed5f2945a79c9d
113
- /qilin-tool-subagent/model-experience/background-result/kv-cache-effect:
113
+ /qilin-agent-tool-subagent/model-experience/background-result/kv-cache-effect:
114
114
  en: f5d5f97a153f7c70
115
115
  zh: 3d6bc05b9eadfbc2
116
- /qilin-tool-subagent/known-limitations-and-deferred-work:
116
+ /qilin-agent-tool-subagent/known-limitations-and-deferred-work:
117
117
  en: 8482d967fe854d08
118
118
  zh: 4e1457ae659f4f28
119
- /qilin-tool-subagent/known-limitations-and-deferred-work/dev-note:
119
+ /qilin-agent-tool-subagent/known-limitations-and-deferred-work/dev-note:
120
120
  en: e67f633dc6fe7773
121
121
  zh: 3bb0c20c93f16f98
package/README.md CHANGED
@@ -25,6 +25,8 @@ Use this package to give an agent a named tool that delegates work to a configur
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
+ The optional `cwd` argument selects the child's initial working directory. Relative paths resolve against the caller's current directory; omission inherits it. Existing children retain their own directories when the caller changes directory.
29
+
28
30
  Mount one instance per delegation target, each with a distinct `toolName`. The tool exists exactly while its provider does, so sibling load order and provider reloads never strand it.
29
31
 
30
32
  ### Minimal configuration
package/README.zh.md CHANGED
@@ -25,6 +25,8 @@ kind: "package-reference"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
+ 可选参数 `cwd` 选择子级的初始工作目录。相对路径以调用者当前目录解析;省略时继承该目录。调用者切换目录时,已有子级保留自己的目录。
29
+
28
30
  每个委派目标挂载一个实例,且每个实例的 `toolName` 必须不同。工具与其提供方同时存在、同时消失,因此同级加载顺序与提供方重新加载都不会让工具悬空。
29
31
 
30
32
  ### 最小配置
package/lib/index.js CHANGED
@@ -2,7 +2,7 @@ import z from "@qilin-agent/schemastery";
2
2
  import { scopeChainOf, scopeOf } from "@qilin-agent/scope";
3
3
  import { defineTool } from "@qilin-agent/tools";
4
4
  import { SessionSeq } from "@qilin-agent/session";
5
- import { assertSubagentMaxDepth, parentAgentOptionsForDelegation, settleRun } from "@qilin-agent/subagent";
5
+ import { assertSubagentMaxDepth, parentAgentOptionsForDelegation } from "@qilin-agent/subagent";
6
6
  import { ReasoningEffortId } from "@qilin-agent/llm";
7
7
  import { z as z$1 } from "zod";
8
8
  z.object({
@@ -236,10 +236,8 @@ function recordSubagentModelSelection(projections, session, allowedModels) {
236
236
  /**
237
237
  * Model-facing delegation through one configured `ctx.subagents` provider.
238
238
  * Provider lifecycle controls tool registration and context-sensitive schema
239
- * wording. Foreground calls always dispose the run after collection.
240
- * Background policy is selected by this plugin's configuration: one-shot
241
- * calls own a plain Task, while continuable calls use
242
- * `ctx.subagents.startContinuable()`.
239
+ * wording. Every delegation starts a managed activation and returns its child
240
+ * id; the subagent runtime owns result delivery and resource cleanup.
243
241
  * @module @qilin-agent/tool-subagent
244
242
  */
245
243
  const name = "tool-subagent";
@@ -249,12 +247,11 @@ const inject = [
249
247
  "systemPrompt",
250
248
  "sessionProjections"
251
249
  ];
250
+ const delegationTools = /* @__PURE__ */ new Set();
252
251
  const Config = z.object({
253
252
  provider: z.string().required(),
254
253
  toolName: z.string().default("subagent"),
255
254
  modelSelectionSettings: z.boolean().default(false),
256
- enableRunInBackground: z.boolean().default(true),
257
- backgroundMode: z.union(["one-shot", "continuable"]).default("one-shot"),
258
255
  agentOptions: z.object({
259
256
  provider: z.string(),
260
257
  model: z.string(),
@@ -268,67 +265,6 @@ const Config = z.object({
268
265
  }).default(void 0),
269
266
  maxDepth: z.union([z.natural().max(Number.MAX_SAFE_INTEGER), z.const("provider-managed")])
270
267
  });
271
- /** Render text blocks from the canonical JSON block array without trusting arbitrary values. */
272
- function outputValueText(values) {
273
- return values.filter((value) => typeof value === "object" && value !== null && !Array.isArray(value) && value.type === "text" && typeof value.text === "string").map((value) => value.text).join("");
274
- }
275
- /** Settle pending startup without rejecting the task producer contract. */
276
- async function settleStart(start, signal) {
277
- try {
278
- return await settleRun(await start);
279
- } catch (error) {
280
- return signal.aborted && !(error instanceof AggregateError) ? { status: "killed" } : {
281
- status: "failed",
282
- detail: String(error)
283
- };
284
- }
285
- }
286
- /** A non-`completed` stop reason means the child did not finish cleanly. */
287
- function stopReasonError(result) {
288
- switch (result.stopReason) {
289
- case "completed": return;
290
- case "aborted": return "subagent run was cancelled";
291
- case "error": return "subagent run failed";
292
- case "max-tokens": return "subagent run hit its token limit before finishing";
293
- case "refusal": return "subagent declined the task";
294
- default: return `subagent run ended abnormally (${String(result.stopReason)})`;
295
- }
296
- }
297
- /**
298
- * Append provider-authored failure detail and the child's preserved partial
299
- * answer to a stop-reason error, keeping diagnostic text separate from the
300
- * child's assistant output.
301
- * @param error - the stop-reason headline.
302
- * @param result - the child's terminal result.
303
- * @returns the headline, diagnostic, and partial text that are present.
304
- */
305
- function withDiagnosticAndPartialText(error, result) {
306
- const diagnostic = result.diagnostic === void 0 ? "" : `\nDiagnostic: ${result.diagnostic}`;
307
- const text = result.output.filter((block) => block.type === "text").map((block) => block.text).join("");
308
- return `${error}${diagnostic}${text.length === 0 ? "" : `\nPartial output before the run ended:\n${text}`}`;
309
- }
310
- /**
311
- * Collect and release one foreground run without letting disposal replace an
312
- * independent result failure.
313
- */
314
- async function settleForegroundRun(run) {
315
- const [execution] = await Promise.allSettled([run.result.then((result) => {
316
- const error = stopReasonError(result);
317
- if (error !== void 0) throw new Error(withDiagnosticAndPartialText(error, result));
318
- return {
319
- kind: "foreground",
320
- runId: run.id,
321
- output: result.output
322
- };
323
- })]);
324
- const [disposal] = await Promise.allSettled([Promise.resolve().then(() => run.dispose())]);
325
- if (execution.status === "rejected") {
326
- if (disposal.status === "rejected") throw new AggregateError([execution.reason, disposal.reason], `subagent run failed: ${String(execution.reason)}; dispose failed: ${String(disposal.reason)}`);
327
- throw execution.reason;
328
- }
329
- if (disposal.status === "rejected") throw disposal.reason;
330
- return execution.value;
331
- }
332
268
  /**
333
269
  * Model-facing wording from the provider's conversation-history descriptor
334
270
  * ({@link SubagentProvider.inheritsParentContext}).
@@ -347,18 +283,10 @@ function providerWording(inheritsConversation) {
347
283
  promptDescription: "The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new."
348
284
  };
349
285
  return {
350
- description: "Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation.",
286
+ description: "Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps.",
351
287
  promptDescription: "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
352
288
  };
353
289
  }
354
- /** Resolve the model's optional scheduling request into one execution route. */
355
- function resolveDelegationRun(request, options) {
356
- if (!options.backgroundEnabled) {
357
- if (request.run_in_background === true) throw new Error("run_in_background is disabled for this tool instance (enableRunInBackground: false)");
358
- return { runInBackground: false };
359
- }
360
- return { runInBackground: request.run_in_background ?? options.continuable };
361
- }
362
290
  /**
363
291
  * Install one delegation-tool composition.
364
292
  * @param ctx - Context that owns the registrations.
@@ -368,8 +296,6 @@ function resolveDelegationRun(request, options) {
368
296
  function apply(ctx, config, session) {
369
297
  if (config.maxDepth !== "provider-managed") assertSubagentMaxDepth(config.maxDepth);
370
298
  if (config.toolFilter !== void 0 && config.toolFilter.allow === void 0 && config.toolFilter.deny === void 0) throw new Error("tool-subagent: `toolFilter` is configured but names neither `allow` nor `deny` — remove the key or fill the filter");
371
- const backgroundEnabled = config.enableRunInBackground !== false;
372
- const continuable = (config.backgroundMode ?? "one-shot") === "continuable";
373
299
  const toolName = config.toolName ?? "subagent";
374
300
  const modelSelectionCapable = config.modelSelectionSettings === true;
375
301
  ctx.sessionProjections.register(subagentModelSelectionProjectionDefinition);
@@ -377,7 +303,6 @@ function apply(ctx, config, session) {
377
303
  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
304
  if (config.agentOptions !== void 0 && !subagentProvider.capabilities.agentOptions) throw new Error(`tool-subagent: provider "${subagentProvider.name}" does not support child agentOptions`);
379
305
  if (modelSelectionCapable && !subagentProvider.capabilities.agentOptions) throw new Error(`tool-subagent: provider "${subagentProvider.name}" does not support child model selection`);
380
- if (continuable && subagentProvider.prepareContinuable === void 0) throw new Error(`tool-subagent: provider "${subagentProvider.name}" does not support \`backgroundMode: continuable\``);
381
306
  };
382
307
  ctx.on("subagent/provider-added", (subagentProvider) => {
383
308
  if (subagentProvider.name === config.provider) assertSubagentProviderConfiguration(subagentProvider);
@@ -393,173 +318,114 @@ function apply(ctx, config, session) {
393
318
  const wording = providerWording(subagentProvider.inheritsParentContext);
394
319
  const providerRouteDefaults = subagentProvider.agentRouteDefaults;
395
320
  const choiceDescription = !modelSelectionEnabled ? "" : (providerRouteDefaults !== void 0 ? " Child LLM selection is optional. Omit `provider`, `model`, and `reasoning_effort` to use configured child defaults and this provider's route defaults. Supply `provider` and `model` together after using `list_subagent_models` to inspect advertised routes and efforts. Changing the effective route without naming an effort uses the selected model's default effort." : " Child LLM selection is optional. Omit `provider`, `model`, and `reasoning_effort` to use configured child defaults and inherit compatible missing values from the parent Agent. Supply `provider` and `model` together after using `list_subagent_models` to inspect advertised routes and efforts. Changing the effective route without naming an effort uses the selected model's default effort.") + (subagentProvider.inheritsParentContext ? " Changing the route can prevent provider-side reuse of the inherited conversation prefix." : "");
396
- mounted = {
397
- subagentProvider,
398
- disposeTool: runtimeCtx.tools.register(defineTool({
399
- name: toolName,
400
- description: wording.description + (backgroundEnabled ? continuable ? " This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` steers the child's nearest step while it is running and starts or resumes a turn while it is inactive. Set `run_in_background: false` only when your next action depends on receiving the result." : " This call waits for the result by default. Set `run_in_background: true` to return a job id; collect with `job_output` and stop with `job_kill`." : " This call waits for the subagent and returns its result.") + choiceDescription,
401
- parameters: {
402
- description: {
321
+ const definition = defineTool({
322
+ name: toolName,
323
+ description: wording.description + " This tool starts an independently managed subagent and immediately returns its id. The runtime notifies you when it finishes." + (subagentProvider.prepareContinuable !== void 0 ? " The child reports results with `send_message`; use `send_message` to steer it while running or continue its conversation after it finishes." : " The completion notice includes its final answer. This backend does not accept follow-up messages.") + choiceDescription,
324
+ parameters: {
325
+ cwd: {
326
+ type: "string",
327
+ description: "Initial child working directory. Relative paths use your current directory; omitted inherits it. Later directory changes in either agent are independent."
328
+ },
329
+ description: {
330
+ type: "string",
331
+ required: true,
332
+ description: "A short (3-5 word) description of the delegated task, for display."
333
+ },
334
+ prompt: {
335
+ type: "string",
336
+ required: true,
337
+ description: wording.promptDescription
338
+ },
339
+ ...modelSelectionEnabled ? {
340
+ provider: {
403
341
  type: "string",
404
- required: true,
405
- description: "A short (3-5 word) description of the delegated task, for display."
342
+ description: providerRouteDefaults !== void 0 ? "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or this provider's route defaults." : "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or inherit the parent route."
406
343
  },
407
- prompt: {
344
+ model: {
408
345
  type: "string",
409
- required: true,
410
- description: wording.promptDescription
346
+ description: providerRouteDefaults !== void 0 ? "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or this provider's route defaults." : "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or inherit the parent route."
411
347
  },
412
- ...modelSelectionEnabled ? {
413
- provider: {
414
- type: "string",
415
- description: providerRouteDefaults !== void 0 ? "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or this provider's route defaults." : "LLM provider route for the child. Supply together with model; omit both to use configured child defaults or inherit the parent route."
416
- },
417
- model: {
348
+ reasoning_effort: {
349
+ type: "string",
350
+ description: providerRouteDefaults !== void 0 ? "Adapter-owned reasoning effort for the effective child route. Omit to use a compatible configured effort or the selected model's default." : "Adapter-owned reasoning effort for the effective child route. Omit to inherit a compatible configured/parent effort or use a newly selected model's default."
351
+ }
352
+ } : {}
353
+ },
354
+ output: {
355
+ schema: {
356
+ type: "object",
357
+ additionalProperties: false,
358
+ properties: {
359
+ kind: {
418
360
  type: "string",
419
- description: providerRouteDefaults !== void 0 ? "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or this provider's route defaults." : "Model id interpreted by provider. Supply together with provider; omit both to use configured child defaults or inherit the parent route."
361
+ required: true,
362
+ const: "activation"
420
363
  },
421
- reasoning_effort: {
364
+ subagentId: {
422
365
  type: "string",
423
- description: providerRouteDefaults !== void 0 ? "Adapter-owned reasoning effort for the effective child route. Omit to use a compatible configured effort or the selected model's default." : "Adapter-owned reasoning effort for the effective child route. Omit to inherit a compatible configured/parent effort or use a newly selected model's default."
366
+ required: true
424
367
  }
425
- } : {},
426
- ...backgroundEnabled ? { run_in_background: {
427
- type: "boolean",
428
- description: continuable ? "Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it." : "Whether to run as a background job and return its id. Defaults to false; collect with job_output or stop with job_kill."
429
- } } : {}
368
+ }
430
369
  },
431
- output: {
432
- schema: { oneOf: [
433
- {
434
- type: "object",
435
- additionalProperties: false,
436
- properties: {
437
- kind: {
438
- type: "string",
439
- required: true,
440
- const: "background"
441
- },
442
- jobId: {
443
- type: "string",
444
- required: true
445
- }
446
- }
447
- },
448
- {
449
- type: "object",
450
- additionalProperties: false,
451
- properties: {
452
- kind: {
453
- type: "string",
454
- required: true,
455
- const: "continuable"
456
- },
457
- subagentId: {
458
- type: "string",
459
- required: true
460
- }
461
- }
462
- },
463
- {
464
- type: "object",
465
- additionalProperties: false,
466
- properties: {
467
- kind: {
468
- type: "string",
469
- required: true,
470
- const: "foreground"
471
- },
472
- runId: {
473
- type: "string",
474
- required: true
475
- },
476
- output: {
477
- type: "array",
478
- required: true,
479
- items: { type: "json" }
480
- }
481
- }
482
- }
483
- ] },
484
- render: (_args, value) => [{
370
+ render: (_args, value) => [{
371
+ type: "text",
372
+ text: `started subagent ${value.subagentId}`
373
+ }]
374
+ },
375
+ isConcurrencySafe: () => true,
376
+ async execute(args, exec) {
377
+ const parent = exec.agent;
378
+ if (!parent) throw new Error("subagent tool requires a calling agent (exec.agent was undefined)");
379
+ const modelRequest = args;
380
+ const parentOptions = parentAgentOptionsForDelegation(parent);
381
+ const requiresRoutePreflight = hasDelegationModelRequest(modelRequest) || hasConfiguredLlmSelection(config.agentOptions);
382
+ const requestedChildAgentOptions = requestedAgentOptions(parentOptions, requiresRoutePreflight && providerRouteDefaults !== void 0 ? {
383
+ ...providerRouteDefaults,
384
+ ...config.agentOptions
385
+ } : config.agentOptions, modelRequest, modelSelectionEnabled);
386
+ assertAllowedModelSelection(modelSelectionPolicy, parentOptions, requestedChildAgentOptions, modelRequest);
387
+ if (requiresRoutePreflight) {
388
+ const llm = runtimeCtx.get("llm");
389
+ if (llm === void 0) throw new Error("cannot resolve the selected child LLM route because the `llm` service is unavailable");
390
+ await preflightChildLlmRoute(llm, parentOptions, requestedChildAgentOptions, exec.signal, providerRouteDefaults === void 0);
391
+ if (runtimeCtx.subagents.getProvider(config.provider) !== subagentProvider) throw new Error(`subagent provider "${config.provider}" changed while resolving the child LLM route; retry the delegation`);
392
+ }
393
+ exec.signal.throwIfAborted();
394
+ const maxDepth = runtimeCtx.subagents.resolveMaxDepth(config.maxDepth);
395
+ const request = {
396
+ ...args.cwd === void 0 ? {} : { cwd: args.cwd },
397
+ prompt: [{
485
398
  type: "text",
486
- text: value.kind === "background" ? `started background subagent job ${value.jobId}` : value.kind === "continuable" ? `started subagent ${value.subagentId}` : outputValueText(value.output)
487
- }]
488
- },
489
- isConcurrencySafe: () => true,
490
- async execute(args, exec) {
491
- const parent = exec.agent;
492
- if (!parent) throw new Error("subagent tool requires a calling agent (exec.agent was undefined)");
493
- const modelRequest = args;
494
- const parentOptions = parentAgentOptionsForDelegation(parent);
495
- const requiresRoutePreflight = hasDelegationModelRequest(modelRequest) || hasConfiguredLlmSelection(config.agentOptions);
496
- const requestedChildAgentOptions = requestedAgentOptions(parentOptions, requiresRoutePreflight && providerRouteDefaults !== void 0 ? {
497
- ...providerRouteDefaults,
498
- ...config.agentOptions
499
- } : config.agentOptions, modelRequest, modelSelectionEnabled);
500
- assertAllowedModelSelection(modelSelectionPolicy, parentOptions, requestedChildAgentOptions, modelRequest);
501
- if (requiresRoutePreflight) {
502
- const llm = runtimeCtx.get("llm");
503
- if (llm === void 0) throw new Error("cannot resolve the selected child LLM route because the `llm` service is unavailable");
504
- await preflightChildLlmRoute(llm, parentOptions, requestedChildAgentOptions, exec.signal, providerRouteDefaults === void 0);
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
- }
507
- exec.signal.throwIfAborted();
508
- const maxDepth = runtimeCtx.subagents.resolveMaxDepth(config.maxDepth);
509
- const request = {
399
+ text: args.prompt
400
+ }],
401
+ parent,
402
+ ...requestedChildAgentOptions !== void 0 ? { agentOptions: requestedChildAgentOptions } : {},
403
+ ...config.persona !== void 0 ? { persona: config.persona } : {},
404
+ ...config.toolFilter !== void 0 ? { toolFilter: config.toolFilter } : {},
405
+ ...maxDepth !== void 0 ? { maxDepth } : {}
406
+ };
407
+ return {
408
+ kind: "activation",
409
+ subagentId: (await runtimeCtx.subagents.startActivation({
410
+ provider: config.provider,
510
411
  label: args.description,
511
- prompt: [{
512
- type: "text",
513
- text: args.prompt
514
- }],
515
- parent,
516
- ...requestedChildAgentOptions !== void 0 ? { agentOptions: requestedChildAgentOptions } : {},
517
- ...config.persona !== void 0 ? { persona: config.persona } : {},
518
- ...config.toolFilter !== void 0 ? { toolFilter: config.toolFilter } : {},
519
- ...maxDepth !== void 0 ? { maxDepth } : {}
520
- };
521
- if (resolveDelegationRun(args, {
522
- backgroundEnabled,
523
- continuable
524
- }).runInBackground) {
525
- if (continuable) return {
526
- kind: "continuable",
527
- subagentId: (await runtimeCtx.subagents.startContinuable({
528
- provider: config.provider,
529
- label: args.description,
530
- request,
531
- signal: exec.signal
532
- })).childId
533
- };
534
- const jobs = runtimeCtx.get("jobs");
535
- if (jobs === void 0) throw new Error("background jobs unavailable: load @qilin-agent/jobs and @qilin-agent/tool-jobs");
536
- return {
537
- kind: "background",
538
- jobId: jobs.start({
539
- kind: "subagent",
540
- label: args.description,
541
- owner: parent.id,
542
- run: () => {
543
- const controller = new AbortController();
544
- return {
545
- cancel: (reason) => {
546
- controller.abort(reason ?? "background subagent task killed");
547
- },
548
- done: settleStart(runtimeCtx.subagents.start(config.provider, {
549
- ...request,
550
- signal: controller.signal
551
- }), controller.signal)
552
- };
553
- }
554
- })
555
- };
556
- }
557
- return settleForegroundRun(await runtimeCtx.subagents.start(config.provider, {
558
- ...request,
559
- signal: exec.signal
560
- }));
561
- }
562
- }))
412
+ request,
413
+ signal: exec.signal,
414
+ delivery: "parent"
415
+ })).childId
416
+ };
417
+ }
418
+ });
419
+ mounted = {
420
+ subagentProvider,
421
+ disposeTool: runtimeCtx.effect(() => {
422
+ const unregister = runtimeCtx.tools.register(definition);
423
+ delegationTools.add(definition);
424
+ return () => {
425
+ delegationTools.delete(definition);
426
+ unregister();
427
+ };
428
+ })
563
429
  };
564
430
  };
565
431
  runtimeCtx.on("subagent/provider-added", (subagentProvider) => {
@@ -573,10 +439,15 @@ function apply(ctx, config, session) {
573
439
  const present = runtimeCtx.subagents.getProvider(config.provider);
574
440
  if (present !== void 0) mount(present);
575
441
  else runtimeCtx.logger.info(`subagent provider "${config.provider}" not registered yet; the "${config.toolName ?? "subagent"}" tool will register when it appears`);
576
- if (backgroundEnabled && continuable) runtimeCtx.systemPrompt.section({
442
+ runtimeCtx.systemPrompt.section({
577
443
  name: `tool:${toolName}`,
578
444
  order: runtimeCtx.systemPrompt.getSectionOrder("TOOL_SUBAGENT"),
579
- text: (context) => mounted === void 0 || runtimeCtx.tools.get(toolName, context.scope) === void 0 ? "" : `Use ${toolName} in the background by default. Start independent delegations together in one assistant message and continue useful work while they run. Set \`run_in_background: false\` only when your next action depends on that subagent's result. When a background run settles, the runtime sends you a notice containing its outcome and any final assistant message.`
445
+ text: (context) => {
446
+ if (mounted === void 0) return "";
447
+ const visible = [...delegationTools].filter((tool) => runtimeCtx.tools.get(tool.name, context.scope) === tool).map((tool) => tool.name).sort();
448
+ if (visible[0] !== toolName) return "";
449
+ return `Start independent delegations with ${visible.map((name) => `\`${name}\``).join(" or ")} together in one assistant message and continue useful work while they run.`;
450
+ }
580
451
  });
581
452
  };
582
453
  if (config.modelSelectionSettings !== true) {
@@ -37,58 +37,32 @@ function assertAllowedModelRoutes(routes) {
37
37
  }
38
38
  //#endregion
39
39
  //#region lib/types/model-selection-settings.js
40
- /** Host-owned opt-in setting for model-selectable subagent delegation. */
41
- /** User-settings section for model-selectable subagent delegation. */
42
- const SUBAGENT_MODEL_SELECTION_SETTINGS_NAMESPACE = "subagent-model-selection";
43
- /** Schema served to settings clients for the opt-in preference. */
44
- const SUBAGENT_MODEL_SELECTION_SETTINGS_SCHEMA = z.object({
45
- enabled: z.boolean().default(false),
46
- allowedModels: z.array(AllowedModelRouteSchema).default([])
47
- });
48
40
  /** Singleton settings owner read when delegation tools are composed for a Session. */
49
41
  var SubagentModelSelectionConfig = class extends Service {
42
+ config;
50
43
  static Config = z.object({
51
- enabled: z.boolean().default(false),
52
- allowedModels: z.array(AllowedModelRouteSchema).default([])
44
+ enabled: z.boolean().default(false).volatile(),
45
+ allowedModels: z.array(AllowedModelRouteSchema).default([]).volatile()
53
46
  });
54
- source;
55
- constructor(ctx, config = {}) {
47
+ constructor(ctx, config) {
56
48
  super(ctx, "subagentModelSelection");
57
- /* v8 ignore next */
58
- const entry = {
59
- enabled: config.enabled ?? false,
60
- allowedModels: config.allowedModels ?? []
61
- };
62
- this.validate(entry);
63
- this.source = () => entry;
64
- ctx.inject(["settings"], (settingsCtx) => {
65
- settingsCtx.settings.installSection(ctx, SUBAGENT_MODEL_SELECTION_SETTINGS_NAMESPACE, SUBAGENT_MODEL_SELECTION_SETTINGS_SCHEMA, entry, {
66
- setSource: (source) => {
67
- this.source = source;
68
- },
69
- validate: (value) => {
70
- this.validate(value);
71
- },
72
- onChange: () => {}
73
- });
74
- });
49
+ this.config = config;
75
50
  }
76
51
  /**
77
52
  * Read a detached selection preference for the next eligible Session composition.
78
53
  * @returns the enabled state and exact allowed routes.
79
54
  */
80
55
  current() {
81
- const current = this.source();
56
+ const enabled = this.config.enabled.get();
57
+ const allowedModels = this.config.allowedModels.get();
58
+ assertAllowedModelRoutes(allowedModels);
59
+ if (enabled && allowedModels.length === 0) throw new Error("enabled subagent model selection requires at least one allowed model");
82
60
  return {
83
- enabled: current.enabled,
84
- allowedModels: current.allowedModels.map((route) => ({ ...route }))
61
+ enabled,
62
+ allowedModels: allowedModels.map((route) => ({ ...route }))
85
63
  };
86
64
  }
87
- validate(value) {
88
- assertAllowedModelRoutes(value.allowedModels);
89
- if (value.enabled && value.allowedModels.length === 0) throw new Error("enabled subagent model selection requires at least one allowed model");
90
- }
91
65
  };
92
66
  const name = "subagent-model-selection-settings";
93
67
  //#endregion
94
- export { SUBAGENT_MODEL_SELECTION_SETTINGS_NAMESPACE, SUBAGENT_MODEL_SELECTION_SETTINGS_SCHEMA, SubagentModelSelectionConfig, SubagentModelSelectionConfig as default, name };
68
+ export { SubagentModelSelectionConfig, SubagentModelSelectionConfig as default, name };
@@ -1,10 +1,8 @@
1
1
  /**
2
2
  * Model-facing delegation through one configured `ctx.subagents` provider.
3
3
  * Provider lifecycle controls tool registration and context-sensitive schema
4
- * wording. Foreground calls always dispose the run after collection.
5
- * Background policy is selected by this plugin's configuration: one-shot
6
- * calls own a plain Task, while continuable calls use
7
- * `ctx.subagents.startContinuable()`.
4
+ * wording. Every delegation starts a managed activation and returns its child
5
+ * id; the subagent runtime owns result delivery and resource cleanup.
8
6
  * @module @qilin-agent/tool-subagent
9
7
  */
10
8
  import type { Context } from '@qilin-agent/kylin';
@@ -27,18 +25,6 @@ export interface Config {
27
25
  * Session and inherit that decision in its child Sessions.
28
26
  */
29
27
  modelSelectionSettings?: boolean;
30
- /**
31
- * Expose `run_in_background` (default true). Disabled instances omit the
32
- * parameter and reject forced background calls.
33
- */
34
- enableRunInBackground?: boolean;
35
- /**
36
- * Background execution policy (default `one-shot`). `one-shot` defaults calls
37
- * to foreground; `continuable` defaults them to background, requires a provider
38
- * with the `prepareContinuable` capability, and returns the durable child id.
39
- * Follow-up adapters remain independently optional.
40
- */
41
- backgroundMode?: 'one-shot' | 'continuable';
42
28
  /**
43
29
  * Agent options applied to every child; omitted fields use child-loop defaults.
44
30
  */
@@ -1,4 +1,5 @@
1
1
  /** Host-owned opt-in setting for model-selectable subagent delegation. */
2
+ import type { Volatile } from '@qilin-agent/kylin';
2
3
  import { Context, Service } from '@qilin-agent/kylin';
3
4
  import z from '@qilin-agent/schemastery';
4
5
  import { type AllowedModelRoute } from './model-selection.ts';
@@ -8,8 +9,6 @@ declare module '@qilin-agent/kylin' {
8
9
  subagentModelSelection: SubagentModelSelectionConfig;
9
10
  }
10
11
  }
11
- /** User-settings section for model-selectable subagent delegation. */
12
- export declare const SUBAGENT_MODEL_SELECTION_SETTINGS_NAMESPACE = "subagent-model-selection";
13
12
  /** Stored user preference; the shipped composition defaults it off. */
14
13
  export interface SubagentModelSelectionSettings {
15
14
  /** Whether newly composed top-level Sessions receive model selection. */
@@ -17,26 +16,29 @@ export interface SubagentModelSelectionSettings {
17
16
  /** Exact child LLM routes offered to newly composed top-level Sessions. */
18
17
  allowedModels: AllowedModelRoute[];
19
18
  }
20
- /** Schema served to settings clients for the opt-in preference. */
21
- export declare const SUBAGENT_MODEL_SELECTION_SETTINGS_SCHEMA: z<SubagentModelSelectionSettings>;
22
19
  /** Optional deployment base for the preference. */
23
20
  export interface Config {
24
21
  /** Initial enabled state inherited when the user document does not override it. */
25
- enabled?: boolean;
22
+ enabled: Volatile<boolean>;
26
23
  /** Initial route list inherited when the user document does not override it. */
27
- allowedModels?: AllowedModelRoute[];
24
+ allowedModels: Volatile<AllowedModelRoute[]>;
28
25
  }
29
26
  /** Singleton settings owner read when delegation tools are composed for a Session. */
30
27
  export declare class SubagentModelSelectionConfig extends Service {
31
- static Config: z<Config>;
32
- private source;
33
- constructor(ctx: Context, config?: Config);
28
+ private config;
29
+ static Config: z<Schemastery.ObjectS<NoInfer<{
30
+ enabled: z<boolean, boolean, "volatile-defined">;
31
+ allowedModels: z<NoInfer<AllowedModelRoute[]>, NoInfer<AllowedModelRoute[]>, "volatile-defined">;
32
+ }>>, Schemastery.ObjectT<NoInfer<{
33
+ enabled: z<boolean, boolean, "volatile-defined">;
34
+ allowedModels: z<NoInfer<AllowedModelRoute[]>, NoInfer<AllowedModelRoute[]>, "volatile-defined">;
35
+ }>>, "plain">;
36
+ constructor(ctx: Context, config: Config);
34
37
  /**
35
38
  * Read a detached selection preference for the next eligible Session composition.
36
39
  * @returns the enabled state and exact allowed routes.
37
40
  */
38
41
  current(): SubagentModelSelectionSettings;
39
- private validate;
40
42
  }
41
43
  export declare const name = "subagent-model-selection-settings";
42
44
  export default SubagentModelSelectionConfig;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilin-agent/tool-subagent",
3
3
  "description": "Model-facing subagent delegation tool over the ctx.subagents seam",
4
- "version": "3.1.3",
4
+ "version": "3.1.5",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -35,17 +35,17 @@
35
35
  ],
36
36
  "license": "MIT",
37
37
  "peerDependencies": {
38
- "@qilin-agent/agent": "3.1.3",
39
- "@qilin-agent/session": "3.1.3",
40
- "@qilin-agent/llm": "3.1.3",
41
- "@qilin-agent/session-projection": "3.1.3",
42
- "@qilin-agent/settings": "3.1.3",
43
- "@qilin-agent/scope": "3.1.3",
44
- "@qilin-agent/subagent": "3.1.3",
45
- "@qilin-agent/jobs": "3.1.3",
46
- "@qilin-agent/tools": "3.1.3",
38
+ "@qilin-agent/agent": "3.1.5",
39
+ "@qilin-agent/llm": "3.1.5",
40
+ "@qilin-agent/session": "3.1.5",
41
+ "@qilin-agent/session-projection": "3.1.5",
42
+ "@qilin-agent/settings": "3.1.5",
43
+ "@qilin-agent/subagent": "3.1.5",
44
+ "@qilin-agent/system-prompt": "3.1.5",
45
+ "@qilin-agent/scope": "3.1.5",
47
46
  "@qilin-agent/kylin": "~4.0.3",
48
- "@qilin-agent/system-prompt": "3.1.3"
47
+ "@qilin-agent/tools": "3.1.5",
48
+ "@qilin-agent/jobs": "3.1.5"
49
49
  },
50
50
  "dependencies": {
51
51
  "zod": "^4.4.3",
@@ -53,21 +53,21 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@qilin-agent/kylin-plugin-loader": "~1.0.4",
56
- "@qilin-agent/agent": "3.1.3",
57
- "@qilin-agent/llm": "3.1.3",
58
- "@qilin-agent/session": "3.1.3",
59
- "@qilin-agent/scope": "3.1.3",
60
- "@qilin-agent/session-persistence": "3.1.3",
61
- "@qilin-agent/settings": "3.1.3",
62
- "@qilin-agent/session-persistence-jsonl": "3.1.3",
63
- "@qilin-agent/subagent-spawn-in-process": "3.1.3",
64
- "@qilin-agent/jobs": "3.1.3",
65
- "@qilin-agent/system-prompt": "3.1.3",
66
- "@qilin-agent/subagent": "3.1.3",
67
- "@qilin-agent/jobs-local": "3.1.3",
68
- "@qilin-agent/tools": "3.1.3",
56
+ "@qilin-agent/llm": "3.1.5",
57
+ "@qilin-agent/session": "3.1.5",
58
+ "@qilin-agent/scope": "3.1.5",
59
+ "@qilin-agent/agent": "3.1.5",
60
+ "@qilin-agent/session-persistence-jsonl": "3.1.5",
61
+ "@qilin-agent/settings": "3.1.5",
62
+ "@qilin-agent/system-prompt": "3.1.5",
63
+ "@qilin-agent/session-persistence": "3.1.5",
64
+ "@qilin-agent/subagent-spawn-in-process": "3.1.5",
65
+ "@qilin-agent/tool-jobs": "3.1.5",
66
+ "@qilin-agent/jobs-local": "3.1.5",
67
+ "@qilin-agent/subagent": "3.1.5",
68
+ "@qilin-agent/jobs": "3.1.5",
69
+ "@qilin-agent/tools": "3.1.5",
69
70
  "@qilin-agent/kylin": "~4.0.3",
70
- "@qilin-agent/session-projection": "3.1.3",
71
- "@qilin-agent/tool-jobs": "3.1.3"
71
+ "@qilin-agent/session-projection": "3.1.5"
72
72
  }
73
73
  }