@dexto/agent-management 1.5.8 → 1.6.1

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.
Files changed (139) hide show
  1. package/dist/AgentFactory.cjs +5 -9
  2. package/dist/AgentFactory.d.ts +6 -5
  3. package/dist/AgentFactory.d.ts.map +1 -1
  4. package/dist/AgentFactory.js +5 -9
  5. package/dist/AgentManager.cjs +2 -2
  6. package/dist/AgentManager.d.ts +1 -1
  7. package/dist/AgentManager.d.ts.map +1 -1
  8. package/dist/AgentManager.js +4 -4
  9. package/dist/agent-creation.cjs +95 -0
  10. package/dist/agent-creation.d.ts +15 -0
  11. package/dist/agent-creation.d.ts.map +1 -0
  12. package/dist/agent-creation.js +78 -0
  13. package/dist/config/config-enrichment.cjs +8 -14
  14. package/dist/config/config-enrichment.d.ts +7 -1
  15. package/dist/config/config-enrichment.d.ts.map +1 -1
  16. package/dist/config/config-enrichment.js +8 -14
  17. package/dist/config/config-manager.cjs +4 -4
  18. package/dist/config/config-manager.d.ts +1 -1
  19. package/dist/config/config-manager.d.ts.map +1 -1
  20. package/dist/config/config-manager.js +3 -1
  21. package/dist/config/loader.d.ts +3 -3
  22. package/dist/config/loader.d.ts.map +1 -1
  23. package/dist/images/image-store.cjs +256 -0
  24. package/dist/images/image-store.d.ts +70 -0
  25. package/dist/images/image-store.d.ts.map +1 -0
  26. package/dist/images/image-store.js +210 -0
  27. package/dist/index.cjs +32 -2
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +31 -1
  31. package/dist/plugins/discover-plugins.cjs +15 -31
  32. package/dist/plugins/discover-plugins.d.ts.map +1 -1
  33. package/dist/plugins/discover-plugins.js +15 -31
  34. package/dist/plugins/index.cjs +0 -2
  35. package/dist/plugins/index.d.ts +5 -6
  36. package/dist/plugins/index.d.ts.map +1 -1
  37. package/dist/plugins/index.js +0 -2
  38. package/dist/plugins/list-plugins.cjs +3 -1
  39. package/dist/plugins/list-plugins.d.ts.map +1 -1
  40. package/dist/plugins/list-plugins.js +3 -1
  41. package/dist/plugins/load-plugin.cjs +0 -13
  42. package/dist/plugins/load-plugin.d.ts +3 -5
  43. package/dist/plugins/load-plugin.d.ts.map +1 -1
  44. package/dist/plugins/load-plugin.js +0 -13
  45. package/dist/plugins/schemas.cjs +1 -11
  46. package/dist/plugins/schemas.d.ts +14 -69
  47. package/dist/plugins/schemas.d.ts.map +1 -1
  48. package/dist/plugins/schemas.js +1 -10
  49. package/dist/plugins/types.d.ts +2 -20
  50. package/dist/plugins/types.d.ts.map +1 -1
  51. package/dist/plugins/validate-plugin.cjs +7 -37
  52. package/dist/plugins/validate-plugin.d.ts +6 -24
  53. package/dist/plugins/validate-plugin.d.ts.map +1 -1
  54. package/dist/plugins/validate-plugin.js +8 -38
  55. package/dist/preferences/loader.cjs +21 -6
  56. package/dist/preferences/loader.d.ts +4 -0
  57. package/dist/preferences/loader.d.ts.map +1 -1
  58. package/dist/preferences/loader.js +21 -6
  59. package/dist/preferences/schemas.cjs +5 -1
  60. package/dist/preferences/schemas.d.ts +32 -0
  61. package/dist/preferences/schemas.d.ts.map +1 -1
  62. package/dist/preferences/schemas.js +5 -1
  63. package/dist/registry/registry.d.ts +4 -44
  64. package/dist/registry/registry.d.ts.map +1 -1
  65. package/dist/registry/types.cjs +4 -0
  66. package/dist/registry/types.d.ts +8 -0
  67. package/dist/registry/types.d.ts.map +1 -1
  68. package/dist/registry/types.js +4 -0
  69. package/dist/runtime/AgentPool.d.ts +2 -2
  70. package/dist/runtime/AgentPool.d.ts.map +1 -1
  71. package/dist/runtime/AgentRuntime.cjs +32 -19
  72. package/dist/runtime/AgentRuntime.d.ts +2 -2
  73. package/dist/runtime/AgentRuntime.d.ts.map +1 -1
  74. package/dist/runtime/AgentRuntime.js +32 -19
  75. package/dist/runtime/approval-delegation.cjs +6 -3
  76. package/dist/runtime/approval-delegation.d.ts +3 -2
  77. package/dist/runtime/approval-delegation.d.ts.map +1 -1
  78. package/dist/runtime/approval-delegation.js +6 -3
  79. package/dist/runtime/schemas.cjs +1 -1
  80. package/dist/runtime/schemas.d.ts +1 -1
  81. package/dist/runtime/schemas.js +1 -1
  82. package/dist/runtime/types.d.ts +3 -2
  83. package/dist/runtime/types.d.ts.map +1 -1
  84. package/dist/{tool-provider → tool-factories/agent-spawner}/error-codes.d.ts +1 -1
  85. package/dist/tool-factories/agent-spawner/error-codes.d.ts.map +1 -0
  86. package/dist/{tool-provider → tool-factories/agent-spawner}/errors.d.ts +1 -1
  87. package/dist/tool-factories/agent-spawner/errors.d.ts.map +1 -0
  88. package/dist/tool-factories/agent-spawner/factory.cjs +327 -0
  89. package/dist/tool-factories/agent-spawner/factory.d.ts +4 -0
  90. package/dist/tool-factories/agent-spawner/factory.d.ts.map +1 -0
  91. package/dist/tool-factories/agent-spawner/factory.js +316 -0
  92. package/dist/{tool-provider → tool-factories/agent-spawner}/index.cjs +9 -9
  93. package/dist/{tool-provider → tool-factories/agent-spawner}/index.d.ts +3 -3
  94. package/dist/tool-factories/agent-spawner/index.d.ts.map +1 -0
  95. package/dist/{tool-provider → tool-factories/agent-spawner}/index.js +4 -4
  96. package/dist/tool-factories/agent-spawner/llm-resolution.d.ts.map +1 -0
  97. package/dist/{tool-provider/runtime-service.cjs → tool-factories/agent-spawner/runtime.cjs} +149 -83
  98. package/dist/{tool-provider/runtime-service.d.ts → tool-factories/agent-spawner/runtime.d.ts} +11 -6
  99. package/dist/tool-factories/agent-spawner/runtime.d.ts.map +1 -0
  100. package/dist/{tool-provider/runtime-service.js → tool-factories/agent-spawner/runtime.js} +145 -79
  101. package/dist/{tool-provider → tool-factories/agent-spawner}/schemas.cjs +4 -4
  102. package/dist/{tool-provider → tool-factories/agent-spawner}/schemas.d.ts +5 -5
  103. package/dist/tool-factories/agent-spawner/schemas.d.ts.map +1 -0
  104. package/dist/{tool-provider → tool-factories/agent-spawner}/schemas.js +4 -4
  105. package/dist/{tool-provider → tool-factories/agent-spawner}/spawn-agent-tool.cjs +17 -7
  106. package/dist/tool-factories/agent-spawner/spawn-agent-tool.d.ts +11 -0
  107. package/dist/tool-factories/agent-spawner/spawn-agent-tool.d.ts.map +1 -0
  108. package/dist/{tool-provider → tool-factories/agent-spawner}/spawn-agent-tool.js +17 -7
  109. package/dist/tool-factories/agent-spawner/types.d.ts.map +1 -0
  110. package/dist/utils/path.cjs +10 -1
  111. package/dist/utils/path.d.ts +5 -2
  112. package/dist/utils/path.d.ts.map +1 -1
  113. package/dist/utils/path.js +10 -1
  114. package/dist/writer.d.ts +2 -1
  115. package/dist/writer.d.ts.map +1 -1
  116. package/package.json +6 -4
  117. package/dist/tool-provider/error-codes.d.ts.map +0 -1
  118. package/dist/tool-provider/errors.d.ts.map +0 -1
  119. package/dist/tool-provider/index.d.ts.map +0 -1
  120. package/dist/tool-provider/llm-resolution.d.ts.map +0 -1
  121. package/dist/tool-provider/runtime-service.d.ts.map +0 -1
  122. package/dist/tool-provider/schemas.d.ts.map +0 -1
  123. package/dist/tool-provider/spawn-agent-tool.d.ts +0 -10
  124. package/dist/tool-provider/spawn-agent-tool.d.ts.map +0 -1
  125. package/dist/tool-provider/tool-provider.cjs +0 -197
  126. package/dist/tool-provider/tool-provider.d.ts +0 -30
  127. package/dist/tool-provider/tool-provider.d.ts.map +0 -1
  128. package/dist/tool-provider/tool-provider.js +0 -180
  129. package/dist/tool-provider/types.d.ts.map +0 -1
  130. /package/dist/{tool-provider → tool-factories/agent-spawner}/error-codes.cjs +0 -0
  131. /package/dist/{tool-provider → tool-factories/agent-spawner}/error-codes.js +0 -0
  132. /package/dist/{tool-provider → tool-factories/agent-spawner}/errors.cjs +0 -0
  133. /package/dist/{tool-provider → tool-factories/agent-spawner}/errors.js +0 -0
  134. /package/dist/{tool-provider → tool-factories/agent-spawner}/llm-resolution.cjs +0 -0
  135. /package/dist/{tool-provider → tool-factories/agent-spawner}/llm-resolution.d.ts +0 -0
  136. /package/dist/{tool-provider → tool-factories/agent-spawner}/llm-resolution.js +0 -0
  137. /package/dist/{tool-provider → tool-factories/agent-spawner}/types.cjs +0 -0
  138. /package/dist/{tool-provider → tool-factories/agent-spawner}/types.d.ts +0 -0
  139. /package/dist/{tool-provider → tool-factories/agent-spawner}/types.js +0 -0
@@ -1,13 +1,14 @@
1
+ import { randomUUID } from "crypto";
1
2
  import { DextoRuntimeError, ErrorType } from "@dexto/core";
2
- import { AgentRuntime } from "../runtime/AgentRuntime.js";
3
- import { createDelegatingApprovalHandler } from "../runtime/approval-delegation.js";
4
- import { loadAgentConfig } from "../config/loader.js";
5
- import { getAgentRegistry } from "../registry/registry.js";
6
- import { deriveDisplayName } from "../registry/types.js";
7
- import { resolveBundledScript } from "../utils/path.js";
3
+ import { AgentRuntime } from "../../runtime/AgentRuntime.js";
4
+ import { createDelegatingApprovalHandler } from "../../runtime/approval-delegation.js";
5
+ import { loadAgentConfig } from "../../config/loader.js";
6
+ import { getAgentRegistry } from "../../registry/registry.js";
7
+ import { deriveDisplayName } from "../../registry/types.js";
8
+ import { getDextoPath, resolveBundledScript } from "../../utils/path.js";
8
9
  import * as path from "path";
9
10
  import { resolveSubAgentLLM } from "./llm-resolution.js";
10
- class RuntimeService {
11
+ class AgentSpawnerRuntime {
11
12
  runtime;
12
13
  parentId;
13
14
  parentAgent;
@@ -57,7 +58,7 @@ class RuntimeService {
57
58
  logger
58
59
  });
59
60
  this.logger.debug(
60
- `RuntimeService initialized for parent '${this.parentId}' (maxAgents: ${config.maxConcurrentAgents})`
61
+ `AgentSpawnerRuntime initialized for parent '${this.parentId}' (maxAgents: ${config.maxConcurrentAgents})`
61
62
  );
62
63
  }
63
64
  /**
@@ -131,23 +132,7 @@ class RuntimeService {
131
132
  * @param options.sessionId - Optional session ID for progress events
132
133
  */
133
134
  async fork(options) {
134
- const spawnOptions = {
135
- task: options.task,
136
- instructions: options.instructions
137
- };
138
- if (options.agentId) {
139
- spawnOptions.agentId = options.agentId;
140
- }
141
- if (options.autoApprove !== void 0) {
142
- spawnOptions.autoApprove = options.autoApprove;
143
- }
144
- if (options.toolCallId) {
145
- spawnOptions.toolCallId = options.toolCallId;
146
- }
147
- if (options.sessionId) {
148
- spawnOptions.sessionId = options.sessionId;
149
- }
150
- return this.spawnAndExecute(spawnOptions);
135
+ return this.spawnAndExecute(options);
151
136
  }
152
137
  /**
153
138
  * Set up progress event emission for a sub-agent.
@@ -169,10 +154,12 @@ class RuntimeService {
169
154
  let toolCount = 0;
170
155
  const tokenUsage = { input: 0, output: 0, total: 0 };
171
156
  let currentTool = "";
172
- const subAgentBus = subAgentHandle.agent.agentEventBus;
173
- const parentBus = this.parentAgent.agentEventBus;
174
157
  const emitProgress = (tool, args) => {
175
- parentBus.emit("service:event", {
158
+ const subAgentLogFilePath = this.getSubAgentLogFilePath({
159
+ runtimeAgentId: subAgentHandle.agentId,
160
+ sessionId
161
+ });
162
+ this.parentAgent.emit("service:event", {
176
163
  service: "agent-spawner",
177
164
  event: "progress",
178
165
  toolCallId,
@@ -180,6 +167,8 @@ class RuntimeService {
180
167
  data: {
181
168
  task: input.task,
182
169
  agentId: input.agentId ?? "default",
170
+ runtimeAgentId: subAgentHandle.agentId,
171
+ ...subAgentLogFilePath ? { subAgentLogFilePath } : {},
183
172
  toolsCalled: toolCount,
184
173
  currentTool: tool,
185
174
  currentArgs: args,
@@ -190,15 +179,10 @@ class RuntimeService {
190
179
  const toolCallHandler = (event) => {
191
180
  toolCount++;
192
181
  let displayToolName = event.toolName;
193
- if (displayToolName.startsWith("internal--")) {
194
- displayToolName = displayToolName.replace("internal--", "");
195
- } else if (displayToolName.startsWith("custom--")) {
196
- displayToolName = displayToolName.replace("custom--", "");
197
- } else if (displayToolName.startsWith("mcp--")) {
198
- const parts = displayToolName.split("--");
199
- if (parts.length >= 3) {
200
- displayToolName = parts.slice(2).join("--");
201
- }
182
+ if (displayToolName.startsWith("mcp--")) {
183
+ const trimmed = displayToolName.substring("mcp--".length);
184
+ const parts = trimmed.split("--");
185
+ displayToolName = parts.length >= 2 ? parts.slice(1).join("--") : trimmed;
202
186
  }
203
187
  currentTool = displayToolName;
204
188
  this.logger.debug(
@@ -217,13 +201,51 @@ class RuntimeService {
217
201
  emitProgress(currentTool || "processing");
218
202
  }
219
203
  };
220
- subAgentBus.on("llm:tool-call", toolCallHandler);
221
- subAgentBus.on("llm:response", responseHandler);
204
+ subAgentHandle.agent.on("llm:tool-call", toolCallHandler);
205
+ subAgentHandle.agent.on("llm:response", responseHandler);
222
206
  return () => {
223
- subAgentBus.off("llm:tool-call", toolCallHandler);
224
- subAgentBus.off("llm:response", responseHandler);
207
+ subAgentHandle.agent.off("llm:tool-call", toolCallHandler);
208
+ subAgentHandle.agent.off("llm:response", responseHandler);
225
209
  };
226
210
  }
211
+ /**
212
+ * Ensure spawned agent inherits the parent's workspace context.
213
+ */
214
+ async applyParentWorkspace(agent) {
215
+ let parentWorkspace;
216
+ try {
217
+ parentWorkspace = await this.parentAgent.getWorkspace();
218
+ } catch (error) {
219
+ this.logger.warn(
220
+ `Failed to read parent workspace for sub-agent: ${error instanceof Error ? error.message : String(error)}`
221
+ );
222
+ return;
223
+ }
224
+ if (!parentWorkspace?.path) {
225
+ return;
226
+ }
227
+ try {
228
+ await agent.setWorkspace({
229
+ path: parentWorkspace.path,
230
+ ...parentWorkspace.name ? { name: parentWorkspace.name } : {}
231
+ });
232
+ } catch (error) {
233
+ this.logger.warn(
234
+ `Failed to apply parent workspace to sub-agent: ${error instanceof Error ? error.message : String(error)}`
235
+ );
236
+ }
237
+ }
238
+ getSubAgentLogFilePath(options) {
239
+ const { runtimeAgentId, sessionId } = options;
240
+ if (!sessionId) {
241
+ return null;
242
+ }
243
+ const safeSessionId = sessionId.replace(/[^a-zA-Z0-9._-]/g, "_");
244
+ return getDextoPath(
245
+ "logs",
246
+ path.join(this.parentId, `${safeSessionId}.subagent.${runtimeAgentId}.log`)
247
+ );
248
+ }
227
249
  /**
228
250
  * Check if an error is LLM-related (API errors, credit issues, model not found, etc.)
229
251
  */
@@ -245,7 +267,10 @@ class RuntimeService {
245
267
  let llmMode = "subagent";
246
268
  let cleanupProgressTracking;
247
269
  try {
248
- const buildOptions = {};
270
+ const buildOptions = {
271
+ // Pre-generate the runtime agentId so we can deterministically route logs.
272
+ runtimeAgentId: `agent-${randomUUID().slice(0, 8)}`
273
+ };
249
274
  if (input.agentId !== void 0) {
250
275
  buildOptions.agentId = input.agentId;
251
276
  }
@@ -256,6 +281,7 @@ class RuntimeService {
256
281
  let handle;
257
282
  try {
258
283
  handle = await this.runtime.spawnAgent({
284
+ agentId: buildOptions.runtimeAgentId,
259
285
  agentConfig: subAgentConfig,
260
286
  ephemeral: true,
261
287
  group: this.parentId,
@@ -270,6 +296,7 @@ class RuntimeService {
270
296
  const delegatingHandler = createDelegatingApprovalHandler(
271
297
  this.parentAgent.services.approvalManager,
272
298
  agent.config.agentId ?? "unknown",
299
+ sessionId,
273
300
  this.logger
274
301
  );
275
302
  agent.setApprovalHandler(delegatingHandler);
@@ -277,6 +304,7 @@ class RuntimeService {
277
304
  }
278
305
  });
279
306
  spawnedAgentId = handle.agentId;
307
+ await this.applyParentWorkspace(handle.agent);
280
308
  } catch (spawnError) {
281
309
  const isLlmError = this.isLLMError(spawnError);
282
310
  if (isLlmError && input.agentId && llmMode === "subagent") {
@@ -288,6 +316,7 @@ class RuntimeService {
288
316
  buildOptions.inheritLlm = true;
289
317
  subAgentConfig = await this.buildSubAgentConfig(buildOptions, sessionId);
290
318
  handle = await this.runtime.spawnAgent({
319
+ agentId: buildOptions.runtimeAgentId,
291
320
  agentConfig: subAgentConfig,
292
321
  ephemeral: true,
293
322
  group: this.parentId,
@@ -304,6 +333,7 @@ class RuntimeService {
304
333
  const delegatingHandler = createDelegatingApprovalHandler(
305
334
  this.parentAgent.services.approvalManager,
306
335
  agent.config.agentId ?? "unknown",
336
+ sessionId,
307
337
  this.logger
308
338
  );
309
339
  agent.setApprovalHandler(delegatingHandler);
@@ -311,6 +341,7 @@ class RuntimeService {
311
341
  }
312
342
  });
313
343
  spawnedAgentId = handle.agentId;
344
+ await this.applyParentWorkspace(handle.agent);
314
345
  } else {
315
346
  throw spawnError;
316
347
  }
@@ -318,6 +349,23 @@ class RuntimeService {
318
349
  this.logger.info(
319
350
  `Spawned sub-agent '${spawnedAgentId}' for task: ${input.task}${autoApprove ? " (auto-approve)" : ""}${llmMode === "parent" ? " (using parent LLM)" : ""}`
320
351
  );
352
+ const subAgentLogFilePath = this.getSubAgentLogFilePath(
353
+ sessionId ? { runtimeAgentId: buildOptions.runtimeAgentId, sessionId } : { runtimeAgentId: buildOptions.runtimeAgentId }
354
+ );
355
+ if (subAgentLogFilePath) {
356
+ this.logger.info(`Sub-agent logs: ${subAgentLogFilePath}`);
357
+ }
358
+ if (sessionId) {
359
+ const parentSession = await this.parentAgent.getSession(sessionId);
360
+ if (parentSession) {
361
+ parentSession.logger.info("Sub-agent spawned", {
362
+ runtimeAgentId: spawnedAgentId,
363
+ registryAgentId: input.agentId ?? "default",
364
+ task: input.task,
365
+ ...subAgentLogFilePath ? { subAgentLogFilePath } : {}
366
+ });
367
+ }
368
+ }
321
369
  cleanupProgressTracking = this.setupProgressTracking(
322
370
  handle,
323
371
  input,
@@ -351,6 +399,7 @@ class RuntimeService {
351
399
  buildOptions.inheritLlm = true;
352
400
  subAgentConfig = await this.buildSubAgentConfig(buildOptions, sessionId);
353
401
  handle = await this.runtime.spawnAgent({
402
+ agentId: buildOptions.runtimeAgentId,
354
403
  agentConfig: subAgentConfig,
355
404
  ephemeral: true,
356
405
  group: this.parentId,
@@ -367,6 +416,7 @@ class RuntimeService {
367
416
  const delegatingHandler = createDelegatingApprovalHandler(
368
417
  this.parentAgent.services.approvalManager,
369
418
  agent.config.agentId ?? "unknown",
419
+ sessionId,
370
420
  this.logger
371
421
  );
372
422
  agent.setApprovalHandler(delegatingHandler);
@@ -374,6 +424,7 @@ class RuntimeService {
374
424
  }
375
425
  });
376
426
  spawnedAgentId = handle.agentId;
427
+ await this.applyParentWorkspace(handle.agent);
377
428
  this.logger.info(
378
429
  `Re-spawned sub-agent '${spawnedAgentId}' for task: ${input.task} (using parent LLM)`
379
430
  );
@@ -433,13 +484,49 @@ class RuntimeService {
433
484
  * @param sessionId - Optional session ID to get session-specific LLM config
434
485
  */
435
486
  async buildSubAgentConfig(options, sessionId) {
436
- const { agentId, inheritLlm, autoApprove } = options;
437
- const parentConfig = this.parentAgent.config;
487
+ const { agentId, inheritLlm, autoApprove, runtimeAgentId } = options;
488
+ const parentSettings = this.parentAgent.config;
438
489
  const currentParentLLM = this.parentAgent.getCurrentLLMConfig(sessionId);
439
490
  this.logger.debug(
440
- `[RuntimeService] Building sub-agent config with LLM: ${currentParentLLM.provider}/${currentParentLLM.model}` + (sessionId ? ` (sessionId: ${sessionId})` : " (no sessionId)")
491
+ `[AgentSpawnerRuntime] Building sub-agent config with LLM: ${currentParentLLM.provider}/${currentParentLLM.model}` + (sessionId ? ` (sessionId: ${sessionId})` : " (no sessionId)")
441
492
  );
442
- const toolConfirmationMode = autoApprove ? "auto-approve" : "manual";
493
+ const permissionsMode = autoApprove ? "auto-approve" : "manual";
494
+ const parentToolPolicies = parentSettings.permissions?.toolPolicies;
495
+ const mergeToolPolicies = (subAgentPolicies) => {
496
+ const alwaysAllow = [
497
+ ...parentToolPolicies?.alwaysAllow ?? [],
498
+ ...subAgentPolicies?.alwaysAllow ?? []
499
+ ];
500
+ const alwaysDeny = [
501
+ ...parentToolPolicies?.alwaysDeny ?? [],
502
+ ...subAgentPolicies?.alwaysDeny ?? []
503
+ ];
504
+ return {
505
+ alwaysAllow: Array.from(new Set(alwaysAllow)),
506
+ alwaysDeny: Array.from(new Set(alwaysDeny))
507
+ };
508
+ };
509
+ const inheritedLoggerConfig = await (async () => {
510
+ if (!sessionId) {
511
+ return void 0;
512
+ }
513
+ const session = await this.parentAgent.getSession(sessionId);
514
+ if (!session) {
515
+ return void 0;
516
+ }
517
+ const parentSessionLogPath = session.logger.getLogFilePath();
518
+ if (!parentSessionLogPath) {
519
+ return void 0;
520
+ }
521
+ const subAgentLogFilePath = this.getSubAgentLogFilePath({ runtimeAgentId, sessionId });
522
+ if (!subAgentLogFilePath) {
523
+ return void 0;
524
+ }
525
+ return {
526
+ level: session.logger.getLevel(),
527
+ transports: [{ type: "file", path: subAgentLogFilePath }]
528
+ };
529
+ })();
443
530
  if (agentId) {
444
531
  let configPath = null;
445
532
  try {
@@ -477,22 +564,15 @@ class RuntimeService {
477
564
  this.logger.debug(`Sub-agent LLM resolution: ${resolution.reason}`);
478
565
  llmConfig = resolution.llm;
479
566
  }
480
- const filteredCustomTools = loadedConfig.customTools ? loadedConfig.customTools.filter(
481
- (tool) => typeof tool === "object" && tool !== null && "type" in tool && tool.type !== "agent-spawner"
482
- ) : void 0;
483
567
  return {
484
568
  ...loadedConfig,
485
569
  llm: llmConfig,
486
- toolConfirmation: {
487
- ...loadedConfig.toolConfirmation,
488
- mode: toolConfirmationMode
570
+ permissions: {
571
+ ...loadedConfig.permissions,
572
+ mode: permissionsMode,
573
+ toolPolicies: mergeToolPolicies(loadedConfig.permissions?.toolPolicies)
489
574
  },
490
- customTools: filteredCustomTools,
491
- // Suppress sub-agent console logs entirely using silent transport
492
- logger: {
493
- level: "error",
494
- transports: [{ type: "silent" }]
495
- }
575
+ ...inheritedLoggerConfig !== void 0 && { logger: inheritedLoggerConfig }
496
576
  };
497
577
  }
498
578
  this.logger.warn(
@@ -503,27 +583,13 @@ class RuntimeService {
503
583
  llm: { ...currentParentLLM },
504
584
  // Default system prompt for sub-agents
505
585
  systemPrompt: "You are a helpful sub-agent. Complete the task given to you efficiently and concisely.",
506
- toolConfirmation: {
507
- mode: toolConfirmationMode
586
+ permissions: {
587
+ mode: permissionsMode,
588
+ toolPolicies: mergeToolPolicies(void 0)
508
589
  },
509
590
  // Inherit MCP servers from parent so subagent has tool access
510
- mcpServers: parentConfig.mcpServers ? { ...parentConfig.mcpServers } : {},
511
- // Inherit internal tools from parent, excluding tools that don't work in subagent context
512
- // - ask_user: Subagents can't interact with the user directly
513
- // - invoke_skill: Avoid nested skill invocations for simplicity
514
- internalTools: parentConfig.internalTools ? parentConfig.internalTools.filter(
515
- (tool) => tool !== "ask_user" && tool !== "invoke_skill"
516
- ) : [],
517
- // Inherit custom tools from parent, excluding agent-spawner to prevent nested spawning (depth=1 limit)
518
- // - agent-spawner: Sub-agents should not spawn their own sub-agents
519
- customTools: parentConfig.customTools ? parentConfig.customTools.filter(
520
- (tool) => typeof tool === "object" && tool !== null && "type" in tool && tool.type !== "agent-spawner"
521
- ) : [],
522
- // Suppress sub-agent console logs entirely using silent transport
523
- logger: {
524
- level: "error",
525
- transports: [{ type: "silent" }]
526
- }
591
+ mcpServers: parentSettings.mcpServers ? { ...parentSettings.mcpServers } : {},
592
+ ...inheritedLoggerConfig !== void 0 && { logger: inheritedLoggerConfig }
527
593
  };
528
594
  return config;
529
595
  }
@@ -559,10 +625,10 @@ class RuntimeService {
559
625
  * Clean up all sub-agents (called when parent stops)
560
626
  */
561
627
  async cleanup() {
562
- this.logger.debug(`Cleaning up RuntimeService for parent '${this.parentId}'`);
628
+ this.logger.debug(`Cleaning up AgentSpawnerRuntime for parent '${this.parentId}'`);
563
629
  await this.runtime.stopAll({ group: this.parentId });
564
630
  }
565
631
  }
566
632
  export {
567
- RuntimeService
633
+ AgentSpawnerRuntime
568
634
  };
@@ -24,12 +24,12 @@ __export(schemas_exports, {
24
24
  module.exports = __toCommonJS(schemas_exports);
25
25
  var import_zod = require("zod");
26
26
  const AgentSpawnerConfigSchema = import_zod.z.object({
27
- /** Type discriminator for the provider */
27
+ /** Type discriminator for the factory */
28
28
  type: import_zod.z.literal("agent-spawner"),
29
29
  /** Maximum concurrent sub-agents this parent can spawn (default: 5) */
30
30
  maxConcurrentAgents: import_zod.z.number().int().positive().default(5).describe("Maximum concurrent sub-agents"),
31
- /** Default timeout for task execution in milliseconds (default: 300000 = 5 min) */
32
- defaultTimeout: import_zod.z.number().int().positive().default(3e5).describe("Default task timeout in milliseconds"),
31
+ /** Default timeout for task execution in milliseconds (default: 3600000 = 1 hour) */
32
+ defaultTimeout: import_zod.z.number().int().nonnegative().default(36e5).describe("Default task timeout in milliseconds (0 = no timeout)"),
33
33
  /** Whether spawning is enabled (default: true) */
34
34
  allowSpawning: import_zod.z.boolean().default(true).describe("Whether agent spawning is enabled"),
35
35
  /**
@@ -57,7 +57,7 @@ const AgentSpawnerConfigSchema = import_zod.z.object({
57
57
  * ```
58
58
  */
59
59
  autoApproveAgents: import_zod.z.array(import_zod.z.string().min(1)).optional().describe("Agent IDs that should have tools auto-approved (read-only agents)")
60
- }).strict().describe("Configuration for the agent spawner tool provider");
60
+ }).strict().describe("Configuration for the agent spawner tools factory");
61
61
  const SpawnAgentInputSchema = import_zod.z.object({
62
62
  /** Short task description (shown in UI/logs) */
63
63
  task: import_zod.z.string().min(1).describe("Short task description for UI/logs"),
@@ -1,18 +1,18 @@
1
1
  /**
2
- * Agent Spawner Tool Provider Schemas
2
+ * Agent Spawner Tools Factory Schemas
3
3
  *
4
- * Zod schemas for the agent spawner tool provider configuration and inputs.
4
+ * Zod schemas for the agent spawner tools factory configuration and inputs.
5
5
  */
6
6
  import { z } from 'zod';
7
7
  /**
8
- * Configuration schema for the agent spawner tool provider
8
+ * Configuration schema for the agent spawner tools factory.
9
9
  */
10
10
  export declare const AgentSpawnerConfigSchema: z.ZodObject<{
11
- /** Type discriminator for the provider */
11
+ /** Type discriminator for the factory */
12
12
  type: z.ZodLiteral<"agent-spawner">;
13
13
  /** Maximum concurrent sub-agents this parent can spawn (default: 5) */
14
14
  maxConcurrentAgents: z.ZodDefault<z.ZodNumber>;
15
- /** Default timeout for task execution in milliseconds (default: 300000 = 5 min) */
15
+ /** Default timeout for task execution in milliseconds (default: 3600000 = 1 hour) */
16
16
  defaultTimeout: z.ZodDefault<z.ZodNumber>;
17
17
  /** Whether spawning is enabled (default: true) */
18
18
  allowSpawning: z.ZodDefault<z.ZodBoolean>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/agent-spawner/schemas.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;GAEG;AACH,eAAO,MAAM,wBAAwB;IAE7B,yCAAyC;;IAGzC,uEAAuE;;IAQvE,qFAAqF;;IAQrF,kDAAkD;;IAGlD;;;;;;;;;;OAUG;;IAMH;;;;;;;;;;;OAWG;;;;;;;;;;;;;;;;EAOuD,CAAC;AAEnE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAM3E;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;IAE1B,gDAAgD;;IAGhD,8CAA8C;;IAM9C,qFAAqF;;;;;;;;;;EAGhF,CAAC;AAEd,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -1,11 +1,11 @@
1
1
  import { z } from "zod";
2
2
  const AgentSpawnerConfigSchema = z.object({
3
- /** Type discriminator for the provider */
3
+ /** Type discriminator for the factory */
4
4
  type: z.literal("agent-spawner"),
5
5
  /** Maximum concurrent sub-agents this parent can spawn (default: 5) */
6
6
  maxConcurrentAgents: z.number().int().positive().default(5).describe("Maximum concurrent sub-agents"),
7
- /** Default timeout for task execution in milliseconds (default: 300000 = 5 min) */
8
- defaultTimeout: z.number().int().positive().default(3e5).describe("Default task timeout in milliseconds"),
7
+ /** Default timeout for task execution in milliseconds (default: 3600000 = 1 hour) */
8
+ defaultTimeout: z.number().int().nonnegative().default(36e5).describe("Default task timeout in milliseconds (0 = no timeout)"),
9
9
  /** Whether spawning is enabled (default: true) */
10
10
  allowSpawning: z.boolean().default(true).describe("Whether agent spawning is enabled"),
11
11
  /**
@@ -33,7 +33,7 @@ const AgentSpawnerConfigSchema = z.object({
33
33
  * ```
34
34
  */
35
35
  autoApproveAgents: z.array(z.string().min(1)).optional().describe("Agent IDs that should have tools auto-approved (read-only agents)")
36
- }).strict().describe("Configuration for the agent spawner tool provider");
36
+ }).strict().describe("Configuration for the agent spawner tools factory");
37
37
  const SpawnAgentInputSchema = z.object({
38
38
  /** Short task description (shown in UI/logs) */
39
39
  task: z.string().min(1).describe("Short task description for UI/logs"),
@@ -21,6 +21,7 @@ __export(spawn_agent_tool_exports, {
21
21
  createSpawnAgentTool: () => createSpawnAgentTool
22
22
  });
23
23
  module.exports = __toCommonJS(spawn_agent_tool_exports);
24
+ var import_core = require("@dexto/core");
24
25
  var import_schemas = require("./schemas.js");
25
26
  function buildDescription(service) {
26
27
  const availableAgents = service.getAvailableAgents();
@@ -57,21 +58,30 @@ ${agentsList}
57
58
  function createSpawnAgentTool(service) {
58
59
  return {
59
60
  id: "spawn_agent",
61
+ aliases: ["task"],
60
62
  description: buildDescription(service),
63
+ presentation: {
64
+ describeHeader: (input) => {
65
+ const agentLabel = input.agentId ? input.agentId.replace(/-agent$/, "") : null;
66
+ const title = agentLabel ? agentLabel.charAt(0).toUpperCase() + agentLabel.slice(1) : "Agent";
67
+ const task = typeof input.task === "string" ? input.task : "";
68
+ const argsText = task ? (0, import_core.truncateForHeader)(task, 120) : void 0;
69
+ return (0, import_core.createLocalToolCallHeader)({ title, ...argsText ? { argsText } : {} });
70
+ }
71
+ },
61
72
  inputSchema: import_schemas.SpawnAgentInputSchema,
62
73
  execute: async (input, context) => {
63
- const validatedInput = input;
64
74
  const options = {
65
- task: validatedInput.task,
66
- instructions: validatedInput.instructions
75
+ task: input.task,
76
+ instructions: input.instructions
67
77
  };
68
- if (validatedInput.agentId !== void 0) {
69
- options.agentId = validatedInput.agentId;
78
+ if (input.agentId !== void 0) {
79
+ options.agentId = input.agentId;
70
80
  }
71
- if (context?.toolCallId !== void 0) {
81
+ if (context.toolCallId !== void 0) {
72
82
  options.toolCallId = context.toolCallId;
73
83
  }
74
- if (context?.sessionId !== void 0) {
84
+ if (context.sessionId !== void 0) {
75
85
  options.sessionId = context.sessionId;
76
86
  }
77
87
  const result = await service.spawnAndExecute(options);
@@ -0,0 +1,11 @@
1
+ /**
2
+ * spawn_agent Tool
3
+ *
4
+ * Spawns a sub-agent to handle a specific task.
5
+ * The sub-agent will execute the task and return the result.
6
+ */
7
+ import type { Tool } from '@dexto/core';
8
+ import { SpawnAgentInputSchema } from './schemas.js';
9
+ import type { AgentSpawnerRuntime } from './runtime.js';
10
+ export declare function createSpawnAgentTool(service: AgentSpawnerRuntime): Tool<typeof SpawnAgentInputSchema>;
11
+ //# sourceMappingURL=spawn-agent-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn-agent-tool.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/agent-spawner/spawn-agent-tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAwB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AA4CxD,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,mBAAmB,GAC7B,IAAI,CAAC,OAAO,qBAAqB,CAAC,CAuDpC"}
@@ -1,3 +1,4 @@
1
+ import { createLocalToolCallHeader, truncateForHeader } from "@dexto/core";
1
2
  import { SpawnAgentInputSchema } from "./schemas.js";
2
3
  function buildDescription(service) {
3
4
  const availableAgents = service.getAvailableAgents();
@@ -34,21 +35,30 @@ ${agentsList}
34
35
  function createSpawnAgentTool(service) {
35
36
  return {
36
37
  id: "spawn_agent",
38
+ aliases: ["task"],
37
39
  description: buildDescription(service),
40
+ presentation: {
41
+ describeHeader: (input) => {
42
+ const agentLabel = input.agentId ? input.agentId.replace(/-agent$/, "") : null;
43
+ const title = agentLabel ? agentLabel.charAt(0).toUpperCase() + agentLabel.slice(1) : "Agent";
44
+ const task = typeof input.task === "string" ? input.task : "";
45
+ const argsText = task ? truncateForHeader(task, 120) : void 0;
46
+ return createLocalToolCallHeader({ title, ...argsText ? { argsText } : {} });
47
+ }
48
+ },
38
49
  inputSchema: SpawnAgentInputSchema,
39
50
  execute: async (input, context) => {
40
- const validatedInput = input;
41
51
  const options = {
42
- task: validatedInput.task,
43
- instructions: validatedInput.instructions
52
+ task: input.task,
53
+ instructions: input.instructions
44
54
  };
45
- if (validatedInput.agentId !== void 0) {
46
- options.agentId = validatedInput.agentId;
55
+ if (input.agentId !== void 0) {
56
+ options.agentId = input.agentId;
47
57
  }
48
- if (context?.toolCallId !== void 0) {
58
+ if (context.toolCallId !== void 0) {
49
59
  options.toolCallId = context.toolCallId;
50
60
  }
51
- if (context?.sessionId !== void 0) {
61
+ if (context.sessionId !== void 0) {
52
62
  options.sessionId = context.sessionId;
53
63
  }
54
64
  const result = await service.spawnAndExecute(options);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/agent-spawner/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IAEjB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -83,6 +83,15 @@ function getDextoPath(type, filename, startPath) {
83
83
  return filename ? path.join(basePath, filename) : basePath;
84
84
  }
85
85
  function getDextoGlobalPath(type, filename) {
86
+ const isDevMode = process.env.DEXTO_DEV_MODE === "true";
87
+ if (isDevMode && (0, import_execution_context.getExecutionContext)() === "dexto-source") {
88
+ const sourceRoot = (0, import_execution_context.findDextoSourceRoot)();
89
+ if (!sourceRoot) {
90
+ throw new Error("Not in dexto source context");
91
+ }
92
+ const devBasePath = path.join(sourceRoot, ".dexto", type);
93
+ return filename ? path.join(devBasePath, filename) : devBasePath;
94
+ }
86
95
  const basePath = path.join((0, import_os.homedir)(), ".dexto", type);
87
96
  return filename ? path.join(basePath, filename) : basePath;
88
97
  }
@@ -151,7 +160,7 @@ function resolveBundledScript(scriptPath) {
151
160
  );
152
161
  }
153
162
  async function ensureDextoGlobalDirectory() {
154
- const dextoDir = path.join((0, import_os.homedir)(), ".dexto");
163
+ const dextoDir = getDextoGlobalPath("");
155
164
  try {
156
165
  await import_fs2.promises.mkdir(dextoDir, { recursive: true });
157
166
  } catch (error) {
@@ -12,8 +12,11 @@
12
12
  */
13
13
  export declare function getDextoPath(type: string, filename?: string, startPath?: string): string;
14
14
  /**
15
- * Global path resolver that ALWAYS returns paths in the user's home directory
16
- * Used for agent registry and other global-only resources that should not be project-relative
15
+ * Global path resolver for user-global resources that should not be project-relative.
16
+ *
17
+ * Dev mode support:
18
+ * - dexto-source + DEXTO_DEV_MODE=true: Use repo-local `.dexto` (isolated testing)
19
+ * - otherwise: Use global `~/.dexto` (user experience)
17
20
  * @param type Path type (agents, cache, etc.)
18
21
  * @param filename Optional filename to append
19
22
  * @returns Absolute path to the global location (~/.dexto/...)
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCxF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAI1E;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW3C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAKhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwD/D;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,CAkCzE"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCxF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1E;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW3C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAKhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwD/D;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,CAkCzE"}
@@ -46,6 +46,15 @@ function getDextoPath(type, filename, startPath) {
46
46
  return filename ? path.join(basePath, filename) : basePath;
47
47
  }
48
48
  function getDextoGlobalPath(type, filename) {
49
+ const isDevMode = process.env.DEXTO_DEV_MODE === "true";
50
+ if (isDevMode && getExecutionContext() === "dexto-source") {
51
+ const sourceRoot = findDextoSourceRoot();
52
+ if (!sourceRoot) {
53
+ throw new Error("Not in dexto source context");
54
+ }
55
+ const devBasePath = path.join(sourceRoot, ".dexto", type);
56
+ return filename ? path.join(devBasePath, filename) : devBasePath;
57
+ }
49
58
  const basePath = path.join(homedir(), ".dexto", type);
50
59
  return filename ? path.join(basePath, filename) : basePath;
51
60
  }
@@ -114,7 +123,7 @@ function resolveBundledScript(scriptPath) {
114
123
  );
115
124
  }
116
125
  async function ensureDextoGlobalDirectory() {
117
- const dextoDir = path.join(homedir(), ".dexto");
126
+ const dextoDir = getDextoGlobalPath("");
118
127
  try {
119
128
  await fs.mkdir(dextoDir, { recursive: true });
120
129
  } catch (error) {
package/dist/writer.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { LLMProvider, AgentConfig } from '@dexto/core';
1
+ import type { AgentConfig } from '@dexto/agent-config';
2
+ import type { LLMProvider } from '@dexto/core';
2
3
  import { type GlobalPreferences } from './preferences/schemas.js';
3
4
  export interface LLMOverrides {
4
5
  provider?: LLMProvider;