@dexto/agent-management 1.5.6 → 1.5.8

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 (140) hide show
  1. package/dist/config/config-enrichment.cjs +72 -21
  2. package/dist/config/config-enrichment.d.ts +10 -2
  3. package/dist/config/config-enrichment.d.ts.map +1 -1
  4. package/dist/config/config-enrichment.js +76 -21
  5. package/dist/config/discover-prompts.cjs +1 -1
  6. package/dist/config/discover-prompts.d.ts +11 -11
  7. package/dist/config/discover-prompts.d.ts.map +1 -1
  8. package/dist/config/discover-prompts.js +1 -1
  9. package/dist/config/loader.cjs +31 -13
  10. package/dist/config/loader.d.ts.map +1 -1
  11. package/dist/config/loader.js +31 -13
  12. package/dist/index.cjs +76 -0
  13. package/dist/index.d.ts +5 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +78 -0
  16. package/dist/models/custom-models.cjs +2 -1
  17. package/dist/models/custom-models.d.ts +7 -6
  18. package/dist/models/custom-models.d.ts.map +1 -1
  19. package/dist/models/custom-models.js +2 -1
  20. package/dist/plugins/discover-plugins.cjs +176 -0
  21. package/dist/plugins/discover-plugins.d.ts +39 -0
  22. package/dist/plugins/discover-plugins.d.ts.map +1 -0
  23. package/dist/plugins/discover-plugins.js +140 -0
  24. package/dist/plugins/discover-skills.cjs +93 -0
  25. package/dist/plugins/discover-skills.d.ts +49 -0
  26. package/dist/plugins/discover-skills.d.ts.map +1 -0
  27. package/dist/plugins/discover-skills.js +58 -0
  28. package/dist/plugins/error-codes.cjs +47 -0
  29. package/dist/plugins/error-codes.d.ts +24 -0
  30. package/dist/plugins/error-codes.d.ts.map +1 -0
  31. package/dist/plugins/error-codes.js +23 -0
  32. package/dist/plugins/errors.cjs +197 -0
  33. package/dist/plugins/errors.d.ts +68 -0
  34. package/dist/plugins/errors.d.ts.map +1 -0
  35. package/dist/plugins/errors.js +173 -0
  36. package/dist/plugins/index.cjs +144 -0
  37. package/dist/plugins/index.d.ts +23 -0
  38. package/dist/plugins/index.d.ts.map +1 -0
  39. package/dist/plugins/index.js +115 -0
  40. package/dist/plugins/install-plugin.cjs +211 -0
  41. package/dist/plugins/install-plugin.d.ts +47 -0
  42. package/dist/plugins/install-plugin.d.ts.map +1 -0
  43. package/dist/plugins/install-plugin.js +173 -0
  44. package/dist/plugins/list-plugins.cjs +134 -0
  45. package/dist/plugins/list-plugins.d.ts +26 -0
  46. package/dist/plugins/list-plugins.d.ts.map +1 -0
  47. package/dist/plugins/list-plugins.js +99 -0
  48. package/dist/plugins/load-plugin.cjs +197 -0
  49. package/dist/plugins/load-plugin.d.ts +20 -0
  50. package/dist/plugins/load-plugin.d.ts.map +1 -0
  51. package/dist/plugins/load-plugin.js +163 -0
  52. package/dist/plugins/marketplace/error-codes.cjs +45 -0
  53. package/dist/plugins/marketplace/error-codes.d.ts +21 -0
  54. package/dist/plugins/marketplace/error-codes.d.ts.map +1 -0
  55. package/dist/plugins/marketplace/error-codes.js +21 -0
  56. package/dist/plugins/marketplace/errors.cjs +188 -0
  57. package/dist/plugins/marketplace/errors.d.ts +64 -0
  58. package/dist/plugins/marketplace/errors.d.ts.map +1 -0
  59. package/dist/plugins/marketplace/errors.js +164 -0
  60. package/dist/plugins/marketplace/index.cjs +95 -0
  61. package/dist/plugins/marketplace/index.d.ts +14 -0
  62. package/dist/plugins/marketplace/index.d.ts.map +1 -0
  63. package/dist/plugins/marketplace/index.js +74 -0
  64. package/dist/plugins/marketplace/install-from-marketplace.cjs +152 -0
  65. package/dist/plugins/marketplace/install-from-marketplace.d.ts +25 -0
  66. package/dist/plugins/marketplace/install-from-marketplace.d.ts.map +1 -0
  67. package/dist/plugins/marketplace/install-from-marketplace.js +120 -0
  68. package/dist/plugins/marketplace/operations.cjs +374 -0
  69. package/dist/plugins/marketplace/operations.d.ts +43 -0
  70. package/dist/plugins/marketplace/operations.d.ts.map +1 -0
  71. package/dist/plugins/marketplace/operations.js +339 -0
  72. package/dist/plugins/marketplace/registry.cjs +166 -0
  73. package/dist/plugins/marketplace/registry.d.ts +72 -0
  74. package/dist/plugins/marketplace/registry.d.ts.map +1 -0
  75. package/dist/plugins/marketplace/registry.js +119 -0
  76. package/dist/plugins/marketplace/schemas.cjs +79 -0
  77. package/dist/plugins/marketplace/schemas.d.ts +260 -0
  78. package/dist/plugins/marketplace/schemas.d.ts.map +1 -0
  79. package/dist/plugins/marketplace/schemas.js +49 -0
  80. package/dist/plugins/marketplace/types.cjs +16 -0
  81. package/dist/plugins/marketplace/types.d.ts +156 -0
  82. package/dist/plugins/marketplace/types.d.ts.map +1 -0
  83. package/dist/plugins/marketplace/types.js +0 -0
  84. package/dist/plugins/schemas.cjs +74 -0
  85. package/dist/plugins/schemas.d.ts +262 -0
  86. package/dist/plugins/schemas.d.ts.map +1 -0
  87. package/dist/plugins/schemas.js +46 -0
  88. package/dist/plugins/types.cjs +16 -0
  89. package/dist/plugins/types.d.ts +186 -0
  90. package/dist/plugins/types.d.ts.map +1 -0
  91. package/dist/plugins/types.js +0 -0
  92. package/dist/plugins/uninstall-plugin.cjs +133 -0
  93. package/dist/plugins/uninstall-plugin.d.ts +24 -0
  94. package/dist/plugins/uninstall-plugin.d.ts.map +1 -0
  95. package/dist/plugins/uninstall-plugin.js +99 -0
  96. package/dist/plugins/validate-plugin.cjs +180 -0
  97. package/dist/plugins/validate-plugin.d.ts +53 -0
  98. package/dist/plugins/validate-plugin.d.ts.map +1 -0
  99. package/dist/plugins/validate-plugin.js +145 -0
  100. package/dist/preferences/errors.cjs +11 -0
  101. package/dist/preferences/errors.d.ts +1 -0
  102. package/dist/preferences/errors.d.ts.map +1 -1
  103. package/dist/preferences/errors.js +11 -0
  104. package/dist/preferences/loader.cjs +119 -6
  105. package/dist/preferences/loader.d.ts +21 -1
  106. package/dist/preferences/loader.d.ts.map +1 -1
  107. package/dist/preferences/loader.js +102 -1
  108. package/dist/preferences/schemas.cjs +12 -0
  109. package/dist/preferences/schemas.d.ts +38 -12
  110. package/dist/preferences/schemas.d.ts.map +1 -1
  111. package/dist/preferences/schemas.js +10 -0
  112. package/dist/runtime/AgentRuntime.cjs +1 -2
  113. package/dist/runtime/AgentRuntime.d.ts.map +1 -1
  114. package/dist/runtime/AgentRuntime.js +1 -2
  115. package/dist/tool-provider/llm-resolution.cjs +74 -0
  116. package/dist/tool-provider/llm-resolution.d.ts +51 -0
  117. package/dist/tool-provider/llm-resolution.d.ts.map +1 -0
  118. package/dist/tool-provider/llm-resolution.js +50 -0
  119. package/dist/tool-provider/runtime-service.cjs +246 -34
  120. package/dist/tool-provider/runtime-service.d.ts +34 -2
  121. package/dist/tool-provider/runtime-service.d.ts.map +1 -1
  122. package/dist/tool-provider/runtime-service.js +236 -34
  123. package/dist/tool-provider/tool-provider.cjs +154 -1
  124. package/dist/tool-provider/tool-provider.d.ts +7 -1
  125. package/dist/tool-provider/tool-provider.d.ts.map +1 -1
  126. package/dist/tool-provider/tool-provider.js +161 -1
  127. package/dist/tool-provider/types.d.ts +2 -0
  128. package/dist/tool-provider/types.d.ts.map +1 -1
  129. package/dist/utils/api-key-resolver.cjs +5 -2
  130. package/dist/utils/api-key-resolver.d.ts.map +1 -1
  131. package/dist/utils/api-key-resolver.js +5 -2
  132. package/dist/utils/dexto-auth.cjs +83 -0
  133. package/dist/utils/dexto-auth.d.ts +23 -0
  134. package/dist/utils/dexto-auth.d.ts.map +1 -0
  135. package/dist/utils/dexto-auth.js +57 -0
  136. package/dist/utils/feature-flags.cjs +32 -0
  137. package/dist/utils/feature-flags.d.ts +21 -0
  138. package/dist/utils/feature-flags.d.ts.map +1 -0
  139. package/dist/utils/feature-flags.js +8 -0
  140. package/package.json +3 -2
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var llm_resolution_exports = {};
20
+ __export(llm_resolution_exports, {
21
+ resolveSubAgentLLM: () => resolveSubAgentLLM
22
+ });
23
+ module.exports = __toCommonJS(llm_resolution_exports);
24
+ var import_core = require("@dexto/core");
25
+ function resolveSubAgentLLM(options) {
26
+ const { subAgentLLM, parentLLM, subAgentId } = options;
27
+ const agentLabel = subAgentId ? `'${subAgentId}'` : "sub-agent";
28
+ const subAgentProvider = subAgentLLM.provider;
29
+ const subAgentModel = subAgentLLM.model;
30
+ const parentProvider = parentLLM.provider;
31
+ if ((0, import_core.hasAllRegistryModelsSupport)(parentProvider)) {
32
+ try {
33
+ const transformedModel = (0, import_core.transformModelNameForProvider)(
34
+ subAgentModel,
35
+ subAgentProvider,
36
+ parentProvider
37
+ );
38
+ return {
39
+ llm: {
40
+ ...subAgentLLM,
41
+ provider: parentProvider,
42
+ model: transformedModel,
43
+ apiKey: parentLLM.apiKey,
44
+ baseURL: parentLLM.baseURL
45
+ },
46
+ resolution: "gateway-transform",
47
+ reason: `${agentLabel} using ${parentProvider} gateway with model ${transformedModel} (transformed from ${subAgentProvider}/${subAgentModel})`
48
+ };
49
+ } catch {
50
+ }
51
+ }
52
+ if (parentProvider === subAgentProvider) {
53
+ return {
54
+ llm: {
55
+ ...subAgentLLM,
56
+ apiKey: parentLLM.apiKey,
57
+ // Use parent's credentials
58
+ baseURL: parentLLM.baseURL
59
+ // Inherit custom endpoint (e.g., Azure OpenAI)
60
+ },
61
+ resolution: "same-provider",
62
+ reason: `${agentLabel} using ${subAgentProvider}/${subAgentModel} with parent's credentials`
63
+ };
64
+ }
65
+ return {
66
+ llm: parentLLM,
67
+ resolution: "parent-fallback",
68
+ reason: `${agentLabel} cannot use ${subAgentProvider}/${subAgentModel} with parent's ${parentProvider} provider. Falling back to parent's LLM config. Tip: Use 'dexto login' for Dexto Nova Credits which supports all models.`
69
+ };
70
+ }
71
+ // Annotate the CommonJS export names for ESM import in node:
72
+ 0 && (module.exports = {
73
+ resolveSubAgentLLM
74
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Sub-agent LLM resolution logic
3
+ *
4
+ * When a parent agent spawns a sub-agent (e.g., coding-agent spawns explore-agent),
5
+ * this module determines which LLM configuration the sub-agent should use.
6
+ *
7
+ * Resolution priority:
8
+ * 1. If parent's provider can serve sub-agent's model (dexto-nova/openrouter/same provider)
9
+ * → Use parent's provider + sub-agent's model (transformed if needed)
10
+ * 2. If incompatible providers
11
+ * → Fall back to parent's full LLM config (with warning)
12
+ *
13
+ * Future enhancement (when .local.yml is implemented):
14
+ * 0. Check sub-agent's .local.yml for LLM override (highest priority)
15
+ */
16
+ import type { LLMConfig } from '@dexto/core';
17
+ /**
18
+ * Result of resolving a sub-agent's LLM configuration
19
+ */
20
+ export interface SubAgentLLMResolution {
21
+ /** The resolved LLM configuration to use */
22
+ llm: LLMConfig;
23
+ /** How the resolution was determined */
24
+ resolution: 'gateway-transform' | 'same-provider' | 'parent-fallback';
25
+ /** Human-readable explanation for debugging */
26
+ reason: string;
27
+ }
28
+ export interface ResolveSubAgentLLMOptions {
29
+ /** The sub-agent's bundled LLM configuration */
30
+ subAgentLLM: LLMConfig;
31
+ /** The parent agent's LLM configuration (already has preferences applied) */
32
+ parentLLM: LLMConfig;
33
+ /** Sub-agent ID for logging purposes */
34
+ subAgentId?: string;
35
+ }
36
+ /**
37
+ * Resolves which LLM configuration a sub-agent should use.
38
+ *
39
+ * The goal is to use the sub-agent's intended model (e.g., Haiku for explore-agent)
40
+ * when possible, while leveraging the parent's provider/credentials.
41
+ *
42
+ * @example
43
+ * // Parent uses dexto-nova, sub-agent wants anthropic/haiku
44
+ * resolveSubAgentLLM({
45
+ * subAgentLLM: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001', apiKey: '$ANTHROPIC_API_KEY' },
46
+ * parentLLM: { provider: 'dexto-nova', model: 'anthropic/claude-sonnet-4', apiKey: '$DEXTO_API_KEY' }
47
+ * })
48
+ * // Returns: { provider: 'dexto-nova', model: 'anthropic/claude-haiku-4.5', apiKey: '$DEXTO_API_KEY' }
49
+ */
50
+ export declare function resolveSubAgentLLM(options: ResolveSubAgentLLMOptions): SubAgentLLMResolution;
51
+ //# sourceMappingURL=llm-resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-resolution.d.ts","sourceRoot":"","sources":["../../src/tool-provider/llm-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,4CAA4C;IAC5C,GAAG,EAAE,SAAS,CAAC;IACf,wCAAwC;IACxC,UAAU,EACJ,mBAAmB,GACnB,eAAe,GACf,iBAAiB,CAAC;IACxB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACtC,gDAAgD;IAChD,WAAW,EAAE,SAAS,CAAC;IACvB,6EAA6E;IAC7E,SAAS,EAAE,SAAS,CAAC;IACrB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,qBAAqB,CAmE5F"}
@@ -0,0 +1,50 @@
1
+ import { hasAllRegistryModelsSupport, transformModelNameForProvider } from "@dexto/core";
2
+ function resolveSubAgentLLM(options) {
3
+ const { subAgentLLM, parentLLM, subAgentId } = options;
4
+ const agentLabel = subAgentId ? `'${subAgentId}'` : "sub-agent";
5
+ const subAgentProvider = subAgentLLM.provider;
6
+ const subAgentModel = subAgentLLM.model;
7
+ const parentProvider = parentLLM.provider;
8
+ if (hasAllRegistryModelsSupport(parentProvider)) {
9
+ try {
10
+ const transformedModel = transformModelNameForProvider(
11
+ subAgentModel,
12
+ subAgentProvider,
13
+ parentProvider
14
+ );
15
+ return {
16
+ llm: {
17
+ ...subAgentLLM,
18
+ provider: parentProvider,
19
+ model: transformedModel,
20
+ apiKey: parentLLM.apiKey,
21
+ baseURL: parentLLM.baseURL
22
+ },
23
+ resolution: "gateway-transform",
24
+ reason: `${agentLabel} using ${parentProvider} gateway with model ${transformedModel} (transformed from ${subAgentProvider}/${subAgentModel})`
25
+ };
26
+ } catch {
27
+ }
28
+ }
29
+ if (parentProvider === subAgentProvider) {
30
+ return {
31
+ llm: {
32
+ ...subAgentLLM,
33
+ apiKey: parentLLM.apiKey,
34
+ // Use parent's credentials
35
+ baseURL: parentLLM.baseURL
36
+ // Inherit custom endpoint (e.g., Azure OpenAI)
37
+ },
38
+ resolution: "same-provider",
39
+ reason: `${agentLabel} using ${subAgentProvider}/${subAgentModel} with parent's credentials`
40
+ };
41
+ }
42
+ return {
43
+ llm: parentLLM,
44
+ resolution: "parent-fallback",
45
+ reason: `${agentLabel} cannot use ${subAgentProvider}/${subAgentModel} with parent's ${parentProvider} provider. Falling back to parent's LLM config. Tip: Use 'dexto login' for Dexto Nova Credits which supports all models.`
46
+ };
47
+ }
48
+ export {
49
+ resolveSubAgentLLM
50
+ };
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,22 +17,66 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var runtime_service_exports = {};
20
30
  __export(runtime_service_exports, {
21
31
  RuntimeService: () => RuntimeService
22
32
  });
23
33
  module.exports = __toCommonJS(runtime_service_exports);
34
+ var import_core = require("@dexto/core");
24
35
  var import_AgentRuntime = require("../runtime/AgentRuntime.js");
25
36
  var import_approval_delegation = require("../runtime/approval-delegation.js");
26
37
  var import_loader = require("../config/loader.js");
27
38
  var import_registry = require("../registry/registry.js");
39
+ var import_types = require("../registry/types.js");
40
+ var import_path = require("../utils/path.js");
41
+ var path = __toESM(require("path"), 1);
42
+ var import_llm_resolution = require("./llm-resolution.js");
28
43
  class RuntimeService {
29
44
  runtime;
30
45
  parentId;
31
46
  parentAgent;
32
47
  config;
33
48
  logger;
49
+ resolveBundledAgentConfig(agentId) {
50
+ const baseDir = "agents";
51
+ const normalizedPath = path.relative(baseDir, path.join(baseDir, agentId));
52
+ if (normalizedPath.startsWith("..") || path.isAbsolute(normalizedPath)) {
53
+ return null;
54
+ }
55
+ const candidates = [
56
+ `agents/${agentId}/${agentId}.yml`,
57
+ `agents/${agentId}/${agentId}.yaml`,
58
+ `agents/${agentId}.yml`,
59
+ `agents/${agentId}.yaml`
60
+ ];
61
+ for (const candidate of candidates) {
62
+ try {
63
+ return (0, import_path.resolveBundledScript)(candidate);
64
+ } catch {
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ createFallbackRegistryEntry(agentId) {
70
+ return {
71
+ id: agentId,
72
+ name: (0, import_types.deriveDisplayName)(agentId),
73
+ description: "Agent specified in config (registry entry not found)",
74
+ author: "unknown",
75
+ tags: [],
76
+ source: agentId,
77
+ type: "custom"
78
+ };
79
+ }
34
80
  constructor(parentAgent, config, logger) {
35
81
  this.parentAgent = parentAgent;
36
82
  this.config = config;
@@ -69,6 +115,7 @@ class RuntimeService {
69
115
  * @param input.task - Short task description (for logging/UI)
70
116
  * @param input.instructions - Full prompt sent to sub-agent
71
117
  * @param input.agentId - Optional agent ID from registry
118
+ * @param input.autoApprove - Optional override for auto-approve (used by fork skills)
72
119
  * @param input.timeout - Optional task timeout in milliseconds
73
120
  * @param input.toolCallId - Optional tool call ID for progress events
74
121
  * @param input.sessionId - Optional session ID for progress events
@@ -95,10 +142,7 @@ class RuntimeService {
95
142
  }
96
143
  }
97
144
  const timeout = input.timeout ?? this.config.defaultTimeout;
98
- let autoApprove = false;
99
- if (input.agentId && this.config.autoApproveAgents) {
100
- autoApprove = this.config.autoApproveAgents.includes(input.agentId);
101
- }
145
+ const autoApprove = input.autoApprove !== void 0 ? input.autoApprove : !!(input.agentId && this.config.autoApproveAgents?.includes(input.agentId));
102
146
  const result = await this.trySpawnWithFallback(
103
147
  input,
104
148
  timeout,
@@ -108,6 +152,36 @@ class RuntimeService {
108
152
  );
109
153
  return result;
110
154
  }
155
+ /**
156
+ * Fork execution to an isolated subagent.
157
+ * Implements TaskForker interface for use by invoke_skill when context: fork is set.
158
+ *
159
+ * @param options.task - Short description for UI/logs
160
+ * @param options.instructions - Full instructions for the subagent
161
+ * @param options.agentId - Optional agent ID from registry to use for execution
162
+ * @param options.autoApprove - Auto-approve tool calls (default: true for fork skills)
163
+ * @param options.toolCallId - Optional tool call ID for progress events
164
+ * @param options.sessionId - Optional session ID for progress events
165
+ */
166
+ async fork(options) {
167
+ const spawnOptions = {
168
+ task: options.task,
169
+ instructions: options.instructions
170
+ };
171
+ if (options.agentId) {
172
+ spawnOptions.agentId = options.agentId;
173
+ }
174
+ if (options.autoApprove !== void 0) {
175
+ spawnOptions.autoApprove = options.autoApprove;
176
+ }
177
+ if (options.toolCallId) {
178
+ spawnOptions.toolCallId = options.toolCallId;
179
+ }
180
+ if (options.sessionId) {
181
+ spawnOptions.sessionId = options.sessionId;
182
+ }
183
+ return this.spawnAndExecute(spawnOptions);
184
+ }
111
185
  /**
112
186
  * Set up progress event emission for a sub-agent.
113
187
  * Subscribes to llm:tool-call and llm:response events and emits service:event with progress data.
@@ -183,12 +257,25 @@ class RuntimeService {
183
257
  subAgentBus.off("llm:response", responseHandler);
184
258
  };
185
259
  }
260
+ /**
261
+ * Check if an error is LLM-related (API errors, credit issues, model not found, etc.)
262
+ */
263
+ isLLMError(error) {
264
+ if (error instanceof import_core.DextoRuntimeError) {
265
+ if (error.scope === "llm") return true;
266
+ if (error.type === import_core.ErrorType.PAYMENT_REQUIRED || error.type === import_core.ErrorType.FORBIDDEN) {
267
+ return true;
268
+ }
269
+ }
270
+ const msg = error instanceof Error ? error.message : String(error);
271
+ return msg.includes("model") || msg.includes("provider") || msg.includes("rate limit") || msg.includes("quota");
272
+ }
186
273
  /**
187
274
  * Try to spawn agent, falling back to parent's LLM config if the sub-agent's config fails
188
275
  */
189
276
  async trySpawnWithFallback(input, timeout, autoApprove, toolCallId, sessionId) {
190
277
  let spawnedAgentId;
191
- let usedFallback = false;
278
+ let llmMode = "subagent";
192
279
  let cleanupProgressTracking;
193
280
  try {
194
281
  const buildOptions = {};
@@ -198,7 +285,7 @@ class RuntimeService {
198
285
  if (autoApprove) {
199
286
  buildOptions.autoApprove = autoApprove;
200
287
  }
201
- let subAgentConfig = await this.buildSubAgentConfig(buildOptions);
288
+ let subAgentConfig = await this.buildSubAgentConfig(buildOptions, sessionId);
202
289
  let handle;
203
290
  try {
204
291
  handle = await this.runtime.spawnAgent({
@@ -224,15 +311,15 @@ class RuntimeService {
224
311
  });
225
312
  spawnedAgentId = handle.agentId;
226
313
  } catch (spawnError) {
227
- const errorMsg = spawnError instanceof Error ? spawnError.message : String(spawnError);
228
- const isLlmError = errorMsg.includes("Model") || errorMsg.includes("model") || errorMsg.includes("API") || errorMsg.includes("apiKey") || errorMsg.includes("provider");
229
- if (isLlmError && input.agentId) {
314
+ const isLlmError = this.isLLMError(spawnError);
315
+ if (isLlmError && input.agentId && llmMode === "subagent") {
316
+ const errorMsg = spawnError instanceof Error ? spawnError.message : String(spawnError);
230
317
  this.logger.warn(
231
- `Sub-agent LLM config failed: ${errorMsg}. Falling back to parent's LLM config.`
318
+ `Sub-agent '${input.agentId}' LLM config failed: ${errorMsg}. Falling back to parent's full LLM config.`
232
319
  );
233
- usedFallback = true;
320
+ llmMode = "parent";
234
321
  buildOptions.inheritLlm = true;
235
- subAgentConfig = await this.buildSubAgentConfig(buildOptions);
322
+ subAgentConfig = await this.buildSubAgentConfig(buildOptions, sessionId);
236
323
  handle = await this.runtime.spawnAgent({
237
324
  agentConfig: subAgentConfig,
238
325
  ephemeral: true,
@@ -241,7 +328,8 @@ class RuntimeService {
241
328
  parentId: this.parentId,
242
329
  task: input.task,
243
330
  autoApprove,
244
- usedLlmFallback: true,
331
+ llmMode: "parent",
332
+ fallbackStage: "spawn",
245
333
  spawnedAt: (/* @__PURE__ */ new Date()).toISOString()
246
334
  },
247
335
  onBeforeStart: (agent) => {
@@ -261,7 +349,7 @@ class RuntimeService {
261
349
  }
262
350
  }
263
351
  this.logger.info(
264
- `Spawned sub-agent '${spawnedAgentId}' for task: ${input.task}${autoApprove ? " (auto-approve)" : ""}${usedFallback ? " (using parent LLM)" : ""}`
352
+ `Spawned sub-agent '${spawnedAgentId}' for task: ${input.task}${autoApprove ? " (auto-approve)" : ""}${llmMode === "parent" ? " (using parent LLM)" : ""}`
265
353
  );
266
354
  cleanupProgressTracking = this.setupProgressTracking(
267
355
  handle,
@@ -269,11 +357,74 @@ class RuntimeService {
269
357
  toolCallId,
270
358
  sessionId
271
359
  );
272
- const result = await this.runtime.executeTask(
273
- spawnedAgentId,
274
- input.instructions,
275
- timeout
276
- );
360
+ let result;
361
+ try {
362
+ result = await this.runtime.executeTask(
363
+ spawnedAgentId,
364
+ input.instructions,
365
+ timeout
366
+ );
367
+ } catch (execError) {
368
+ const isLlmExecError = this.isLLMError(execError);
369
+ if (llmMode === "parent") {
370
+ throw execError;
371
+ }
372
+ if (isLlmExecError && input.agentId && llmMode === "subagent") {
373
+ this.logger.warn(
374
+ `Sub-agent '${input.agentId}' LLM error during execution: ${execError instanceof Error ? execError.message : String(execError)}. Retrying with parent's full LLM config.`
375
+ );
376
+ try {
377
+ await this.runtime.stopAgent(spawnedAgentId);
378
+ } catch {
379
+ }
380
+ if (cleanupProgressTracking) {
381
+ cleanupProgressTracking();
382
+ }
383
+ llmMode = "parent";
384
+ buildOptions.inheritLlm = true;
385
+ subAgentConfig = await this.buildSubAgentConfig(buildOptions, sessionId);
386
+ handle = await this.runtime.spawnAgent({
387
+ agentConfig: subAgentConfig,
388
+ ephemeral: true,
389
+ group: this.parentId,
390
+ metadata: {
391
+ parentId: this.parentId,
392
+ task: input.task,
393
+ autoApprove,
394
+ llmMode: "parent",
395
+ fallbackStage: "execution",
396
+ spawnedAt: (/* @__PURE__ */ new Date()).toISOString()
397
+ },
398
+ onBeforeStart: (agent) => {
399
+ if (!autoApprove) {
400
+ const delegatingHandler = (0, import_approval_delegation.createDelegatingApprovalHandler)(
401
+ this.parentAgent.services.approvalManager,
402
+ agent.config.agentId ?? "unknown",
403
+ this.logger
404
+ );
405
+ agent.setApprovalHandler(delegatingHandler);
406
+ }
407
+ }
408
+ });
409
+ spawnedAgentId = handle.agentId;
410
+ this.logger.info(
411
+ `Re-spawned sub-agent '${spawnedAgentId}' for task: ${input.task} (using parent LLM)`
412
+ );
413
+ cleanupProgressTracking = this.setupProgressTracking(
414
+ handle,
415
+ input,
416
+ toolCallId,
417
+ sessionId
418
+ );
419
+ result = await this.runtime.executeTask(
420
+ spawnedAgentId,
421
+ input.instructions,
422
+ timeout
423
+ );
424
+ } else {
425
+ throw execError;
426
+ }
427
+ }
277
428
  const output = {
278
429
  success: result.success
279
430
  };
@@ -283,6 +434,9 @@ class RuntimeService {
283
434
  if (result.error !== void 0) {
284
435
  output.error = result.error;
285
436
  }
437
+ if (llmMode === "parent") {
438
+ output.warning = `Sub-agent '${input.agentId}' used fallback LLM (parent's full config) due to an error with its configured model.`;
439
+ }
286
440
  return output;
287
441
  } catch (error) {
288
442
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -309,24 +463,56 @@ class RuntimeService {
309
463
  * @param options.agentId - Agent ID from registry
310
464
  * @param options.inheritLlm - Use parent's LLM config instead of sub-agent's
311
465
  * @param options.autoApprove - Auto-approve all tool calls
466
+ * @param sessionId - Optional session ID to get session-specific LLM config
312
467
  */
313
- async buildSubAgentConfig(options) {
468
+ async buildSubAgentConfig(options, sessionId) {
314
469
  const { agentId, inheritLlm, autoApprove } = options;
315
470
  const parentConfig = this.parentAgent.config;
471
+ const currentParentLLM = this.parentAgent.getCurrentLLMConfig(sessionId);
472
+ this.logger.debug(
473
+ `[RuntimeService] Building sub-agent config with LLM: ${currentParentLLM.provider}/${currentParentLLM.model}` + (sessionId ? ` (sessionId: ${sessionId})` : " (no sessionId)")
474
+ );
316
475
  const toolConfirmationMode = autoApprove ? "auto-approve" : "manual";
317
476
  if (agentId) {
318
- const registry = (0, import_registry.getAgentRegistry)();
319
- if (!registry.hasAgent(agentId)) {
320
- this.logger.warn(`Agent '${agentId}' not found in registry. Using default config.`);
321
- } else {
322
- const configPath = await registry.resolveAgent(agentId);
323
- this.logger.debug(`Loading agent config from registry: ${configPath}`);
477
+ let configPath = null;
478
+ try {
479
+ const registry = (0, import_registry.getAgentRegistry)();
480
+ if (!registry.hasAgent(agentId)) {
481
+ this.logger.warn(
482
+ `Agent '${agentId}' not found in registry. Trying bundled config paths.`
483
+ );
484
+ } else {
485
+ configPath = await registry.resolveAgent(agentId);
486
+ }
487
+ } catch (error) {
488
+ this.logger.warn(
489
+ `Failed to load agent registry for '${agentId}'. Trying bundled config paths. (${error instanceof Error ? error.message : String(error)})`
490
+ );
491
+ }
492
+ if (!configPath) {
493
+ configPath = this.resolveBundledAgentConfig(agentId);
494
+ }
495
+ if (configPath) {
496
+ this.logger.debug(`Loading agent config from registry/bundled path: ${configPath}`);
324
497
  const loadedConfig = await (0, import_loader.loadAgentConfig)(configPath, this.logger);
325
498
  let llmConfig = loadedConfig.llm;
326
499
  if (inheritLlm) {
327
- this.logger.debug("Using parent LLM config (inheritLlm=true)");
328
- llmConfig = { ...parentConfig.llm };
500
+ this.logger.debug(
501
+ `Sub-agent '${agentId}' using parent LLM config (inheritLlm=true)`
502
+ );
503
+ llmConfig = { ...currentParentLLM };
504
+ } else {
505
+ const resolution = (0, import_llm_resolution.resolveSubAgentLLM)({
506
+ subAgentLLM: loadedConfig.llm,
507
+ parentLLM: currentParentLLM,
508
+ subAgentId: agentId
509
+ });
510
+ this.logger.debug(`Sub-agent LLM resolution: ${resolution.reason}`);
511
+ llmConfig = resolution.llm;
329
512
  }
513
+ const filteredCustomTools = loadedConfig.customTools ? loadedConfig.customTools.filter(
514
+ (tool) => typeof tool === "object" && tool !== null && "type" in tool && tool.type !== "agent-spawner"
515
+ ) : void 0;
330
516
  return {
331
517
  ...loadedConfig,
332
518
  llm: llmConfig,
@@ -334,6 +520,7 @@ class RuntimeService {
334
520
  ...loadedConfig.toolConfirmation,
335
521
  mode: toolConfirmationMode
336
522
  },
523
+ customTools: filteredCustomTools,
337
524
  // Suppress sub-agent console logs entirely using silent transport
338
525
  logger: {
339
526
  level: "error",
@@ -341,14 +528,30 @@ class RuntimeService {
341
528
  }
342
529
  };
343
530
  }
531
+ this.logger.warn(
532
+ `Agent '${agentId}' not found in registry or bundled paths. Using default config.`
533
+ );
344
534
  }
345
535
  const config = {
346
- llm: { ...parentConfig.llm },
536
+ llm: { ...currentParentLLM },
347
537
  // Default system prompt for sub-agents
348
538
  systemPrompt: "You are a helpful sub-agent. Complete the task given to you efficiently and concisely.",
349
539
  toolConfirmation: {
350
540
  mode: toolConfirmationMode
351
541
  },
542
+ // Inherit MCP servers from parent so subagent has tool access
543
+ mcpServers: parentConfig.mcpServers ? { ...parentConfig.mcpServers } : {},
544
+ // Inherit internal tools from parent, excluding tools that don't work in subagent context
545
+ // - ask_user: Subagents can't interact with the user directly
546
+ // - invoke_skill: Avoid nested skill invocations for simplicity
547
+ internalTools: parentConfig.internalTools ? parentConfig.internalTools.filter(
548
+ (tool) => tool !== "ask_user" && tool !== "invoke_skill"
549
+ ) : [],
550
+ // Inherit custom tools from parent, excluding agent-spawner to prevent nested spawning (depth=1 limit)
551
+ // - agent-spawner: Sub-agents should not spawn their own sub-agents
552
+ customTools: parentConfig.customTools ? parentConfig.customTools.filter(
553
+ (tool) => typeof tool === "object" && tool !== null && "type" in tool && tool.type !== "agent-spawner"
554
+ ) : [],
352
555
  // Suppress sub-agent console logs entirely using silent transport
353
556
  logger: {
354
557
  level: "error",
@@ -362,15 +565,24 @@ class RuntimeService {
362
565
  * Returns agent metadata from registry, filtered by allowedAgents if configured.
363
566
  */
364
567
  getAvailableAgents() {
365
- const registry = (0, import_registry.getAgentRegistry)();
366
- const allAgents = registry.getAvailableAgents();
568
+ let allAgents;
569
+ try {
570
+ const registry = (0, import_registry.getAgentRegistry)();
571
+ allAgents = registry.getAvailableAgents();
572
+ } catch (error) {
573
+ this.logger.warn(
574
+ `Failed to load agent registry for spawn_agent description: ${error instanceof Error ? error.message : String(error)}`
575
+ );
576
+ if (this.config.allowedAgents && this.config.allowedAgents.length > 0) {
577
+ return this.config.allowedAgents.map((id) => this.createFallbackRegistryEntry(id));
578
+ }
579
+ return [];
580
+ }
367
581
  if (this.config.allowedAgents && this.config.allowedAgents.length > 0) {
368
582
  const result = [];
369
583
  for (const id of this.config.allowedAgents) {
370
584
  const agent = allAgents[id];
371
- if (agent) {
372
- result.push(agent);
373
- }
585
+ result.push(agent ?? this.createFallbackRegistryEntry(id));
374
586
  }
375
587
  return result;
376
588
  }