@dexto/core 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 (217) hide show
  1. package/dist/agent/DextoAgent.cjs +189 -30
  2. package/dist/agent/DextoAgent.d.ts +44 -9
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +190 -31
  5. package/dist/agent/schemas.cjs +5 -0
  6. package/dist/agent/schemas.d.ts +456 -66
  7. package/dist/agent/schemas.d.ts.map +1 -1
  8. package/dist/agent/schemas.js +5 -0
  9. package/dist/context/manager.cjs +1 -1
  10. package/dist/context/manager.js +1 -1
  11. package/dist/context/utils.cjs +90 -17
  12. package/dist/context/utils.d.ts.map +1 -1
  13. package/dist/context/utils.js +90 -17
  14. package/dist/errors/types.cjs +2 -1
  15. package/dist/errors/types.d.ts +2 -1
  16. package/dist/errors/types.d.ts.map +1 -1
  17. package/dist/errors/types.js +2 -1
  18. package/dist/events/index.cjs +4 -1
  19. package/dist/events/index.d.ts +37 -2
  20. package/dist/events/index.d.ts.map +1 -1
  21. package/dist/events/index.js +4 -1
  22. package/dist/image/types.d.ts +15 -0
  23. package/dist/image/types.d.ts.map +1 -1
  24. package/dist/index.browser.d.ts +1 -1
  25. package/dist/index.browser.d.ts.map +1 -1
  26. package/dist/llm/curation-config.cjs +82 -0
  27. package/dist/llm/curation-config.d.ts +13 -0
  28. package/dist/llm/curation-config.d.ts.map +1 -0
  29. package/dist/llm/curation-config.js +59 -0
  30. package/dist/llm/curation.cjs +57 -0
  31. package/dist/llm/curation.d.ts +16 -0
  32. package/dist/llm/curation.d.ts.map +1 -0
  33. package/dist/llm/curation.js +34 -0
  34. package/dist/llm/error-codes.cjs +1 -0
  35. package/dist/llm/error-codes.d.ts +1 -0
  36. package/dist/llm/error-codes.d.ts.map +1 -1
  37. package/dist/llm/error-codes.js +1 -0
  38. package/dist/llm/errors.cjs +16 -1
  39. package/dist/llm/errors.d.ts +15 -8
  40. package/dist/llm/errors.d.ts.map +1 -1
  41. package/dist/llm/errors.js +16 -1
  42. package/dist/llm/executor/provider-options.cjs +1 -1
  43. package/dist/llm/executor/provider-options.js +1 -1
  44. package/dist/llm/executor/turn-executor.cjs +35 -2
  45. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  46. package/dist/llm/executor/turn-executor.js +35 -2
  47. package/dist/llm/index.cjs +14 -3
  48. package/dist/llm/index.d.ts +3 -1
  49. package/dist/llm/index.d.ts.map +1 -1
  50. package/dist/llm/index.js +13 -2
  51. package/dist/llm/registry/auto-update.cjs +263 -0
  52. package/dist/llm/registry/auto-update.d.ts +27 -0
  53. package/dist/llm/registry/auto-update.d.ts.map +1 -0
  54. package/dist/llm/registry/auto-update.js +227 -0
  55. package/dist/llm/registry/index.cjs +806 -0
  56. package/dist/llm/{registry.d.ts → registry/index.d.ts} +67 -13
  57. package/dist/llm/registry/index.d.ts.map +1 -0
  58. package/dist/llm/registry/index.js +756 -0
  59. package/dist/llm/registry/models.generated.cjs +4861 -0
  60. package/dist/llm/registry/models.generated.d.ts +431 -0
  61. package/dist/llm/registry/models.generated.d.ts.map +1 -0
  62. package/dist/llm/registry/models.generated.js +4838 -0
  63. package/dist/llm/registry/models.manual.cjs +44 -0
  64. package/dist/llm/registry/models.manual.d.ts +22 -0
  65. package/dist/llm/registry/models.manual.d.ts.map +1 -0
  66. package/dist/llm/registry/models.manual.js +21 -0
  67. package/dist/llm/registry/sync.cjs +354 -0
  68. package/dist/llm/registry/sync.d.ts +41 -0
  69. package/dist/llm/registry/sync.d.ts.map +1 -0
  70. package/dist/llm/registry/sync.js +328 -0
  71. package/dist/llm/resolver.cjs +29 -7
  72. package/dist/llm/resolver.d.ts +1 -1
  73. package/dist/llm/resolver.d.ts.map +1 -1
  74. package/dist/llm/resolver.js +31 -8
  75. package/dist/llm/schemas.cjs +13 -1
  76. package/dist/llm/schemas.d.ts +59 -59
  77. package/dist/llm/schemas.d.ts.map +1 -1
  78. package/dist/llm/schemas.js +14 -1
  79. package/dist/llm/services/factory.cjs +43 -27
  80. package/dist/llm/services/factory.d.ts +20 -1
  81. package/dist/llm/services/factory.d.ts.map +1 -1
  82. package/dist/llm/services/factory.js +44 -28
  83. package/dist/llm/services/test-utils.integration.cjs +5 -1
  84. package/dist/llm/services/test-utils.integration.d.ts.map +1 -1
  85. package/dist/llm/services/test-utils.integration.js +5 -1
  86. package/dist/llm/services/vercel.cjs +4 -1
  87. package/dist/llm/services/vercel.d.ts +1 -0
  88. package/dist/llm/services/vercel.d.ts.map +1 -1
  89. package/dist/llm/services/vercel.js +4 -1
  90. package/dist/llm/types.cjs +5 -2
  91. package/dist/llm/types.d.ts +1 -1
  92. package/dist/llm/types.d.ts.map +1 -1
  93. package/dist/llm/types.js +5 -2
  94. package/dist/llm/validation.cjs +1 -1
  95. package/dist/llm/validation.js +1 -1
  96. package/dist/logger/v2/dexto-logger.cjs +4 -0
  97. package/dist/logger/v2/dexto-logger.d.ts +3 -0
  98. package/dist/logger/v2/dexto-logger.d.ts.map +1 -1
  99. package/dist/logger/v2/dexto-logger.js +4 -0
  100. package/dist/logger/v2/types.d.ts +2 -0
  101. package/dist/logger/v2/types.d.ts.map +1 -1
  102. package/dist/mcp/error-codes.cjs +1 -0
  103. package/dist/mcp/error-codes.d.ts +1 -0
  104. package/dist/mcp/error-codes.d.ts.map +1 -1
  105. package/dist/mcp/error-codes.js +1 -0
  106. package/dist/mcp/errors.cjs +13 -0
  107. package/dist/mcp/errors.d.ts +7 -0
  108. package/dist/mcp/errors.d.ts.map +1 -1
  109. package/dist/mcp/errors.js +13 -0
  110. package/dist/mcp/manager.cjs +46 -4
  111. package/dist/mcp/manager.d.ts +10 -2
  112. package/dist/mcp/manager.d.ts.map +1 -1
  113. package/dist/mcp/manager.js +46 -4
  114. package/dist/mcp/mcp-client.cjs +89 -5
  115. package/dist/mcp/mcp-client.d.ts +5 -1
  116. package/dist/mcp/mcp-client.d.ts.map +1 -1
  117. package/dist/mcp/mcp-client.js +89 -5
  118. package/dist/mcp/schemas.cjs +6 -1
  119. package/dist/mcp/schemas.d.ts +1 -1
  120. package/dist/mcp/schemas.d.ts.map +1 -1
  121. package/dist/mcp/schemas.js +6 -1
  122. package/dist/mcp/types.d.ts +5 -0
  123. package/dist/mcp/types.d.ts.map +1 -1
  124. package/dist/prompts/index.d.ts +1 -1
  125. package/dist/prompts/index.d.ts.map +1 -1
  126. package/dist/prompts/prompt-manager.cjs +90 -4
  127. package/dist/prompts/prompt-manager.d.ts +16 -6
  128. package/dist/prompts/prompt-manager.d.ts.map +1 -1
  129. package/dist/prompts/prompt-manager.js +90 -4
  130. package/dist/prompts/providers/config-prompt-provider.cjs +104 -10
  131. package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -1
  132. package/dist/prompts/providers/config-prompt-provider.js +105 -11
  133. package/dist/prompts/providers/custom-prompt-provider.cjs +1 -0
  134. package/dist/prompts/providers/custom-prompt-provider.d.ts.map +1 -1
  135. package/dist/prompts/providers/custom-prompt-provider.js +1 -0
  136. package/dist/prompts/providers/mcp-prompt-provider.cjs +1 -0
  137. package/dist/prompts/providers/mcp-prompt-provider.d.ts.map +1 -1
  138. package/dist/prompts/providers/mcp-prompt-provider.js +1 -0
  139. package/dist/prompts/schemas.cjs +28 -2
  140. package/dist/prompts/schemas.d.ts +130 -0
  141. package/dist/prompts/schemas.d.ts.map +1 -1
  142. package/dist/prompts/schemas.js +28 -2
  143. package/dist/prompts/types.d.ts +55 -3
  144. package/dist/prompts/types.d.ts.map +1 -1
  145. package/dist/resources/handlers/filesystem-handler.cjs +25 -0
  146. package/dist/resources/handlers/filesystem-handler.d.ts +1 -0
  147. package/dist/resources/handlers/filesystem-handler.d.ts.map +1 -1
  148. package/dist/resources/handlers/filesystem-handler.js +25 -0
  149. package/dist/session/chat-session.cjs +1 -1
  150. package/dist/session/chat-session.d.ts +1 -1
  151. package/dist/session/chat-session.d.ts.map +1 -1
  152. package/dist/session/chat-session.js +1 -1
  153. package/dist/session/index.d.ts +1 -1
  154. package/dist/session/index.d.ts.map +1 -1
  155. package/dist/session/message-queue.cjs +29 -5
  156. package/dist/session/message-queue.d.ts +3 -1
  157. package/dist/session/message-queue.d.ts.map +1 -1
  158. package/dist/session/message-queue.js +29 -5
  159. package/dist/session/session-manager.cjs +84 -3
  160. package/dist/session/session-manager.d.ts +12 -0
  161. package/dist/session/session-manager.d.ts.map +1 -1
  162. package/dist/session/session-manager.js +74 -3
  163. package/dist/session/types.d.ts +1 -0
  164. package/dist/session/types.d.ts.map +1 -1
  165. package/dist/systemPrompt/contributors.cjs +42 -0
  166. package/dist/systemPrompt/contributors.d.ts +13 -0
  167. package/dist/systemPrompt/contributors.d.ts.map +1 -1
  168. package/dist/systemPrompt/contributors.js +41 -0
  169. package/dist/tools/errors.cjs +7 -3
  170. package/dist/tools/errors.d.ts +5 -1
  171. package/dist/tools/errors.d.ts.map +1 -1
  172. package/dist/tools/errors.js +7 -3
  173. package/dist/tools/internal-tools/constants.cjs +2 -1
  174. package/dist/tools/internal-tools/constants.d.ts +1 -1
  175. package/dist/tools/internal-tools/constants.d.ts.map +1 -1
  176. package/dist/tools/internal-tools/constants.js +2 -1
  177. package/dist/tools/internal-tools/implementations/invoke-skill-tool.cjs +140 -0
  178. package/dist/tools/internal-tools/implementations/invoke-skill-tool.d.ts +24 -0
  179. package/dist/tools/internal-tools/implementations/invoke-skill-tool.d.ts.map +1 -0
  180. package/dist/tools/internal-tools/implementations/invoke-skill-tool.js +117 -0
  181. package/dist/tools/internal-tools/provider.cjs +15 -0
  182. package/dist/tools/internal-tools/provider.d.ts +15 -1
  183. package/dist/tools/internal-tools/provider.d.ts.map +1 -1
  184. package/dist/tools/internal-tools/provider.js +15 -0
  185. package/dist/tools/internal-tools/registry.cjs +6 -0
  186. package/dist/tools/internal-tools/registry.d.ts +35 -1
  187. package/dist/tools/internal-tools/registry.d.ts.map +1 -1
  188. package/dist/tools/internal-tools/registry.js +6 -0
  189. package/dist/tools/schemas.d.ts +1 -1
  190. package/dist/tools/schemas.d.ts.map +1 -1
  191. package/dist/tools/tool-call-metadata.cjs +75 -0
  192. package/dist/tools/tool-call-metadata.d.ts +16 -0
  193. package/dist/tools/tool-call-metadata.d.ts.map +1 -0
  194. package/dist/tools/tool-call-metadata.js +51 -0
  195. package/dist/tools/tool-manager.cjs +481 -103
  196. package/dist/tools/tool-manager.d.ts +131 -9
  197. package/dist/tools/tool-manager.d.ts.map +1 -1
  198. package/dist/tools/tool-manager.js +482 -104
  199. package/dist/utils/api-key-resolver.cjs +5 -2
  200. package/dist/utils/api-key-resolver.d.ts.map +1 -1
  201. package/dist/utils/api-key-resolver.js +5 -2
  202. package/dist/utils/env.cjs +49 -0
  203. package/dist/utils/env.d.ts +4 -0
  204. package/dist/utils/env.d.ts.map +1 -0
  205. package/dist/utils/env.js +24 -0
  206. package/dist/utils/index.cjs +3 -1
  207. package/dist/utils/index.d.ts +1 -0
  208. package/dist/utils/index.d.ts.map +1 -1
  209. package/dist/utils/index.js +1 -0
  210. package/dist/utils/service-initializer.cjs +25 -7
  211. package/dist/utils/service-initializer.d.ts +24 -1
  212. package/dist/utils/service-initializer.d.ts.map +1 -1
  213. package/dist/utils/service-initializer.js +25 -7
  214. package/package.json +6 -2
  215. package/dist/llm/registry.cjs +0 -1631
  216. package/dist/llm/registry.d.ts.map +0 -1
  217. package/dist/llm/registry.js +0 -1586
@@ -73,7 +73,9 @@ var import_errors2 = require("../errors/index.js");
73
73
  var import_types2 = require("../logger/v2/types.js");
74
74
  var import_types3 = require("../approval/types.js");
75
75
  var import_decorators = require("../telemetry/decorators.js");
76
+ var import_tool_call_metadata = require("./tool-call-metadata.js");
76
77
  var import_bash_pattern_utils = require("./bash-pattern-utils.js");
78
+ var import_env = require("../utils/env.js");
77
79
  var _ToolManager_decorators, _init;
78
80
  _ToolManager_decorators = [(0, import_decorators.InstrumentClass)({
79
81
  prefix: "tool",
@@ -104,6 +106,14 @@ let _ToolManager = class _ToolManager {
104
106
  toolsCache = {};
105
107
  cacheValid = false;
106
108
  logger;
109
+ // Session-level auto-approve tools for skills
110
+ // When a skill with allowedTools is invoked, those tools are auto-approved (skip confirmation)
111
+ // This is ADDITIVE - other tools are NOT blocked, they just go through normal approval flow
112
+ sessionAutoApproveTools = /* @__PURE__ */ new Map();
113
+ // Session-level auto-approve tools set by users (UI)
114
+ sessionUserAutoApproveTools = /* @__PURE__ */ new Map();
115
+ sessionDisabledTools = /* @__PURE__ */ new Map();
116
+ globalDisabledTools = [];
107
117
  constructor(mcpManager, approvalManager, allowedToolsProvider, approvalMode, agentEventBus, toolPolicies, options, logger) {
108
118
  this.mcpManager = mcpManager;
109
119
  this.approvalManager = approvalManager;
@@ -155,6 +165,204 @@ let _ToolManager = class _ToolManager {
155
165
  this.logger.debug("Agent reference configured for custom tools");
156
166
  }
157
167
  }
168
+ /**
169
+ * Set prompt manager for invoke_skill tool (called after construction to avoid circular dependencies)
170
+ * Must be called before initialize() if invoke_skill tool is enabled
171
+ */
172
+ setPromptManager(promptManager) {
173
+ if (this.internalToolsProvider) {
174
+ this.internalToolsProvider.setPromptManager(promptManager);
175
+ this.logger.debug("PromptManager reference configured for invoke_skill tool");
176
+ }
177
+ }
178
+ /**
179
+ * Set task forker for context:fork skill execution (late-binding)
180
+ * Called by agent-spawner custom tool provider after RuntimeService is created.
181
+ * This enables invoke_skill to fork execution to an isolated subagent.
182
+ */
183
+ setTaskForker(taskForker) {
184
+ if (this.internalToolsProvider) {
185
+ this.internalToolsProvider.setTaskForker(taskForker);
186
+ this.logger.debug(
187
+ "TaskForker reference configured for invoke_skill (context:fork support)"
188
+ );
189
+ }
190
+ }
191
+ // ============= SESSION AUTO-APPROVE TOOLS =============
192
+ /**
193
+ * Set session-level auto-approve tools.
194
+ * When set, these tools will skip confirmation prompts for this session.
195
+ * This is ADDITIVE - other tools are NOT blocked, they just go through normal approval flow.
196
+ *
197
+ * @param sessionId The session ID
198
+ * @param autoApproveTools Array of tool names to auto-approve (e.g., ['custom--bash_exec', 'custom--read_file'])
199
+ */
200
+ setSessionAutoApproveTools(sessionId, autoApproveTools) {
201
+ if (autoApproveTools.length === 0) {
202
+ this.clearSessionAutoApproveTools(sessionId);
203
+ return;
204
+ }
205
+ this.sessionAutoApproveTools.set(sessionId, autoApproveTools);
206
+ this.logger.info(
207
+ `Session auto-approve tools set for '${sessionId}': ${autoApproveTools.length} tools`
208
+ );
209
+ this.logger.debug(`Auto-approve tools: ${autoApproveTools.join(", ")}`);
210
+ }
211
+ /**
212
+ * Set session-level auto-approve tools chosen by the user.
213
+ */
214
+ setSessionUserAutoApproveTools(sessionId, autoApproveTools) {
215
+ if (autoApproveTools.length === 0) {
216
+ this.clearSessionUserAutoApproveTools(sessionId);
217
+ return;
218
+ }
219
+ this.sessionUserAutoApproveTools.set(sessionId, autoApproveTools);
220
+ this.logger.info(
221
+ `Session user auto-approve tools set for '${sessionId}': ${autoApproveTools.length} tools`
222
+ );
223
+ this.logger.debug(`User auto-approve tools: ${autoApproveTools.join(", ")}`);
224
+ }
225
+ /**
226
+ * Clear session-level auto-approve tools chosen by the user.
227
+ */
228
+ clearSessionUserAutoApproveTools(sessionId) {
229
+ const hadAutoApprove = this.sessionUserAutoApproveTools.has(sessionId);
230
+ this.sessionUserAutoApproveTools.delete(sessionId);
231
+ if (hadAutoApprove) {
232
+ this.logger.info(`Session user auto-approve tools cleared for '${sessionId}'`);
233
+ }
234
+ }
235
+ /**
236
+ * Clear session-level auto-approve tools.
237
+ * Call this when the session ends or when the skill completes.
238
+ *
239
+ * @param sessionId The session ID to clear auto-approve tools for
240
+ */
241
+ clearSessionAutoApproveTools(sessionId) {
242
+ const hadAutoApprove = this.sessionAutoApproveTools.has(sessionId);
243
+ this.sessionAutoApproveTools.delete(sessionId);
244
+ if (hadAutoApprove) {
245
+ this.logger.info(`Session auto-approve tools cleared for '${sessionId}'`);
246
+ }
247
+ }
248
+ hasSessionUserAutoApproveTools(sessionId) {
249
+ return this.sessionUserAutoApproveTools.has(sessionId);
250
+ }
251
+ // ============= ENABLED/DISABLED TOOLS =============
252
+ /**
253
+ * Set global disabled tools (agent-level preferences).
254
+ */
255
+ setGlobalDisabledTools(toolNames) {
256
+ this.globalDisabledTools = [...toolNames];
257
+ this.logger.info("Global disabled tools updated", {
258
+ count: toolNames.length
259
+ });
260
+ this.agentEventBus.emit("tools:enabled-updated", {
261
+ scope: "global",
262
+ disabledTools: [...this.globalDisabledTools]
263
+ });
264
+ }
265
+ getGlobalDisabledTools() {
266
+ return [...this.globalDisabledTools];
267
+ }
268
+ /**
269
+ * Set session-level disabled tools (overrides global list).
270
+ */
271
+ setSessionDisabledTools(sessionId, toolNames) {
272
+ if (toolNames.length === 0) {
273
+ this.clearSessionDisabledTools(sessionId);
274
+ return;
275
+ }
276
+ this.sessionDisabledTools.set(sessionId, [...toolNames]);
277
+ this.logger.info("Session disabled tools updated", {
278
+ sessionId,
279
+ count: toolNames.length
280
+ });
281
+ this.agentEventBus.emit("tools:enabled-updated", {
282
+ scope: "session",
283
+ sessionId,
284
+ disabledTools: [...toolNames]
285
+ });
286
+ }
287
+ /**
288
+ * Clear session-level disabled tools.
289
+ */
290
+ clearSessionDisabledTools(sessionId) {
291
+ const hadOverrides = this.sessionDisabledTools.has(sessionId);
292
+ this.sessionDisabledTools.delete(sessionId);
293
+ if (hadOverrides) {
294
+ this.logger.info("Session disabled tools cleared", { sessionId });
295
+ }
296
+ }
297
+ /**
298
+ * Get disabled tools for a session (session override wins).
299
+ */
300
+ getDisabledTools(sessionId) {
301
+ if (sessionId && this.sessionDisabledTools.has(sessionId)) {
302
+ return this.sessionDisabledTools.get(sessionId) ?? [];
303
+ }
304
+ return this.globalDisabledTools;
305
+ }
306
+ /**
307
+ * Filter a tool set based on disabled tools for a session.
308
+ */
309
+ filterToolsForSession(toolSet, sessionId) {
310
+ const disabled = new Set(this.getDisabledTools(sessionId));
311
+ if (disabled.size === 0) {
312
+ return toolSet;
313
+ }
314
+ return Object.fromEntries(
315
+ Object.entries(toolSet).filter(([toolName]) => !disabled.has(toolName))
316
+ );
317
+ }
318
+ /**
319
+ * Check if a session has auto-approve tools set.
320
+ *
321
+ * @param sessionId The session ID to check
322
+ * @returns true if the session has auto-approve tools
323
+ */
324
+ hasSessionAutoApproveTools(sessionId) {
325
+ return this.sessionAutoApproveTools.has(sessionId);
326
+ }
327
+ /**
328
+ * Get the auto-approve tools for a session (skill-provided list).
329
+ *
330
+ * @param sessionId The session ID to check
331
+ * @returns Array of auto-approve tool names, or undefined if none set
332
+ */
333
+ getSessionAutoApproveTools(sessionId) {
334
+ return this.sessionAutoApproveTools.get(sessionId);
335
+ }
336
+ /**
337
+ * Get the user auto-approve tools for a session.
338
+ */
339
+ getSessionUserAutoApproveTools(sessionId) {
340
+ return this.sessionUserAutoApproveTools.get(sessionId);
341
+ }
342
+ /**
343
+ * Combined auto-approve list for a session.
344
+ */
345
+ getCombinedSessionAutoApproveTools(sessionId) {
346
+ return [
347
+ ...this.sessionAutoApproveTools.get(sessionId) ?? [],
348
+ ...this.sessionUserAutoApproveTools.get(sessionId) ?? []
349
+ ];
350
+ }
351
+ /**
352
+ * Check if a tool should be auto-approved for a session.
353
+ * Returns true if the tool is in the session's auto-approve list.
354
+ *
355
+ * @param sessionId The session ID
356
+ * @param toolName The tool name to check
357
+ * @returns true if the tool should be auto-approved
358
+ */
359
+ isToolAutoApprovedForSession(sessionId, toolName) {
360
+ const autoApproveTools = this.getCombinedSessionAutoApproveTools(sessionId);
361
+ if (autoApproveTools.length === 0) {
362
+ return false;
363
+ }
364
+ return autoApproveTools.some((pattern) => this.matchesToolPolicy(toolName, pattern));
365
+ }
158
366
  /**
159
367
  * Invalidate the tools cache when tool sources change
160
368
  */
@@ -180,6 +388,14 @@ let _ToolManager = class _ToolManager {
180
388
  );
181
389
  this.invalidateCache();
182
390
  });
391
+ this.agentEventBus.on("run:complete", (payload) => {
392
+ if (this.hasSessionAutoApproveTools(payload.sessionId)) {
393
+ this.logger.debug(
394
+ `\u{1F513} Run complete, clearing session auto-approve tools for '${payload.sessionId}'`
395
+ );
396
+ this.clearSessionAutoApproveTools(payload.sessionId);
397
+ }
398
+ });
183
399
  }
184
400
  // ==================== Bash Pattern Approval Helpers ====================
185
401
  /**
@@ -339,7 +555,8 @@ let _ToolManager = class _ToolManager {
339
555
  allTools[qualifiedName] = {
340
556
  ...toolDef,
341
557
  name: qualifiedName,
342
- description: `${toolDef.description || "No description provided"} (internal tool)`
558
+ description: `${toolDef.description || "No description provided"} (internal tool)`,
559
+ parameters: (0, import_tool_call_metadata.wrapToolParametersSchema)(toolDef.parameters)
343
560
  };
344
561
  }
345
562
  for (const [toolName, toolDef] of Object.entries(customTools)) {
@@ -347,7 +564,8 @@ let _ToolManager = class _ToolManager {
347
564
  allTools[qualifiedName] = {
348
565
  ...toolDef,
349
566
  name: qualifiedName,
350
- description: `${toolDef.description || "No description provided"} (custom tool)`
567
+ description: `${toolDef.description || "No description provided"} (custom tool)`,
568
+ parameters: (0, import_tool_call_metadata.wrapToolParametersSchema)(toolDef.parameters)
351
569
  };
352
570
  }
353
571
  for (const [toolName, toolDef] of Object.entries(mcpTools)) {
@@ -355,7 +573,8 @@ let _ToolManager = class _ToolManager {
355
573
  allTools[qualifiedName] = {
356
574
  ...toolDef,
357
575
  name: qualifiedName,
358
- description: `${toolDef.description || "No description provided"} (via MCP servers)`
576
+ description: `${toolDef.description || "No description provided"} (via MCP servers)`,
577
+ parameters: (0, import_tool_call_metadata.wrapToolParametersSchema)(toolDef.parameters)
359
578
  };
360
579
  }
361
580
  const totalTools = Object.keys(allTools).length;
@@ -391,21 +610,25 @@ let _ToolManager = class _ToolManager {
391
610
  * @param abortSignal Optional abort signal for cancellation support
392
611
  */
393
612
  async executeTool(toolName, args, toolCallId, sessionId, abortSignal) {
613
+ const { toolArgs: rawToolArgs, meta } = (0, import_tool_call_metadata.extractToolCallMeta)(args);
614
+ let toolArgs = rawToolArgs;
615
+ const backgroundTasksEnabled = (0, import_env.isBackgroundTasksEnabled)();
394
616
  this.logger.debug(`\u{1F527} Tool execution requested: '${toolName}' (toolCallId: ${toolCallId})`);
395
- this.logger.debug(`Tool args: ${JSON.stringify(args, null, 2)}`);
617
+ this.logger.debug(`Tool args: ${JSON.stringify(toolArgs, null, 2)}`);
396
618
  if (sessionId) {
397
619
  this.agentEventBus.emit("llm:tool-call", {
398
620
  toolName,
399
- args,
621
+ args: toolArgs,
400
622
  callId: toolCallId,
401
623
  sessionId
402
624
  });
403
625
  }
404
626
  const { requireApproval, approvalStatus } = await this.handleToolApproval(
405
627
  toolName,
406
- args,
628
+ toolArgs,
407
629
  toolCallId,
408
- sessionId
630
+ sessionId,
631
+ meta.callDescription
409
632
  );
410
633
  this.logger.debug(`\u2705 Tool execution approved: ${toolName}`);
411
634
  this.logger.info(
@@ -422,7 +645,7 @@ let _ToolManager = class _ToolManager {
422
645
  if (this.pluginManager && this.sessionManager && this.stateManager) {
423
646
  const beforePayload = {
424
647
  toolName,
425
- args,
648
+ args: toolArgs,
426
649
  ...sessionId !== void 0 && { sessionId }
427
650
  };
428
651
  const modifiedPayload = await this.pluginManager.executePlugins(
@@ -436,10 +659,21 @@ let _ToolManager = class _ToolManager {
436
659
  ...sessionId !== void 0 && { sessionId }
437
660
  }
438
661
  );
439
- args = modifiedPayload.args;
662
+ toolArgs = modifiedPayload.args;
440
663
  }
441
664
  try {
442
665
  let result;
666
+ const registerBackgroundTask = (promise, description) => {
667
+ const fallbackId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
668
+ return {
669
+ result: {
670
+ taskId: toolCallId ?? fallbackId,
671
+ status: "running",
672
+ description
673
+ },
674
+ promise
675
+ };
676
+ };
443
677
  if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
444
678
  this.logger.debug(`\u{1F527} Detected MCP tool: '${toolName}'`);
445
679
  const actualToolName = toolName.substring(_ToolManager.MCP_TOOL_PREFIX.length);
@@ -447,7 +681,34 @@ let _ToolManager = class _ToolManager {
447
681
  throw import_errors.ToolError.invalidName(toolName, "tool name cannot be empty after prefix");
448
682
  }
449
683
  this.logger.debug(`\u{1F3AF} MCP routing: '${toolName}' -> '${actualToolName}'`);
450
- result = await this.mcpManager.executeTool(actualToolName, args, sessionId);
684
+ const runInBackground = backgroundTasksEnabled && meta.runInBackground === true && sessionId !== void 0;
685
+ if (meta.runInBackground === true && !backgroundTasksEnabled) {
686
+ this.logger.debug(
687
+ "Background tool execution disabled; running synchronously instead.",
688
+ { toolName }
689
+ );
690
+ }
691
+ if (runInBackground) {
692
+ const backgroundSessionId = sessionId;
693
+ const { result: backgroundResult, promise } = registerBackgroundTask(
694
+ this.mcpManager.executeTool(actualToolName, toolArgs, backgroundSessionId),
695
+ `MCP tool ${actualToolName}`
696
+ );
697
+ this.agentEventBus.emit("tool:background", {
698
+ toolName,
699
+ toolCallId: backgroundResult.taskId,
700
+ sessionId: backgroundSessionId,
701
+ description: backgroundResult.description,
702
+ promise,
703
+ ...meta.timeoutMs !== void 0 && { timeoutMs: meta.timeoutMs },
704
+ ...meta.notifyOnComplete !== void 0 && {
705
+ notifyOnComplete: meta.notifyOnComplete
706
+ }
707
+ });
708
+ result = backgroundResult;
709
+ } else {
710
+ result = await this.mcpManager.executeTool(actualToolName, toolArgs, sessionId);
711
+ }
451
712
  } else if (toolName.startsWith(_ToolManager.INTERNAL_TOOL_PREFIX)) {
452
713
  this.logger.debug(`\u{1F527} Detected internal tool: '${toolName}'`);
453
714
  const actualToolName = toolName.substring(_ToolManager.INTERNAL_TOOL_PREFIX.length);
@@ -458,13 +719,46 @@ let _ToolManager = class _ToolManager {
458
719
  throw import_errors.ToolError.internalToolsNotInitialized(toolName);
459
720
  }
460
721
  this.logger.debug(`\u{1F3AF} Internal routing: '${toolName}' -> '${actualToolName}'`);
461
- result = await this.internalToolsProvider.executeTool(
462
- actualToolName,
463
- args,
464
- sessionId,
465
- abortSignal,
466
- toolCallId
467
- );
722
+ const runInBackground = backgroundTasksEnabled && meta.runInBackground === true && sessionId !== void 0;
723
+ if (meta.runInBackground === true && !backgroundTasksEnabled) {
724
+ this.logger.debug(
725
+ "Background tool execution disabled; running synchronously instead.",
726
+ { toolName }
727
+ );
728
+ }
729
+ if (runInBackground) {
730
+ const backgroundSessionId = sessionId;
731
+ const { result: backgroundResult, promise } = registerBackgroundTask(
732
+ this.internalToolsProvider.executeTool(
733
+ actualToolName,
734
+ toolArgs,
735
+ backgroundSessionId,
736
+ abortSignal,
737
+ toolCallId
738
+ ),
739
+ `Internal tool ${actualToolName}`
740
+ );
741
+ this.agentEventBus.emit("tool:background", {
742
+ toolName,
743
+ toolCallId: backgroundResult.taskId,
744
+ sessionId: backgroundSessionId,
745
+ description: backgroundResult.description,
746
+ promise,
747
+ ...meta.timeoutMs !== void 0 && { timeoutMs: meta.timeoutMs },
748
+ ...meta.notifyOnComplete !== void 0 && {
749
+ notifyOnComplete: meta.notifyOnComplete
750
+ }
751
+ });
752
+ result = backgroundResult;
753
+ } else {
754
+ result = await this.internalToolsProvider.executeTool(
755
+ actualToolName,
756
+ toolArgs,
757
+ sessionId,
758
+ abortSignal,
759
+ toolCallId
760
+ );
761
+ }
468
762
  } else if (toolName.startsWith(_ToolManager.CUSTOM_TOOL_PREFIX)) {
469
763
  this.logger.debug(`\u{1F527} Detected custom tool: '${toolName}'`);
470
764
  const actualToolName = toolName.substring(_ToolManager.CUSTOM_TOOL_PREFIX.length);
@@ -475,13 +769,46 @@ let _ToolManager = class _ToolManager {
475
769
  throw import_errors.ToolError.internalToolsNotInitialized(toolName);
476
770
  }
477
771
  this.logger.debug(`\u{1F3AF} Custom routing: '${toolName}' -> '${actualToolName}'`);
478
- result = await this.internalToolsProvider.executeTool(
479
- actualToolName,
480
- args,
481
- sessionId,
482
- abortSignal,
483
- toolCallId
484
- );
772
+ const runInBackground = backgroundTasksEnabled && meta.runInBackground === true && sessionId !== void 0;
773
+ if (meta.runInBackground === true && !backgroundTasksEnabled) {
774
+ this.logger.debug(
775
+ "Background tool execution disabled; running synchronously instead.",
776
+ { toolName }
777
+ );
778
+ }
779
+ if (runInBackground) {
780
+ const backgroundSessionId = sessionId;
781
+ const { result: backgroundResult, promise } = registerBackgroundTask(
782
+ this.internalToolsProvider.executeTool(
783
+ actualToolName,
784
+ toolArgs,
785
+ backgroundSessionId,
786
+ abortSignal,
787
+ toolCallId
788
+ ),
789
+ `Custom tool ${actualToolName}`
790
+ );
791
+ this.agentEventBus.emit("tool:background", {
792
+ toolName,
793
+ toolCallId: backgroundResult.taskId,
794
+ sessionId: backgroundSessionId,
795
+ description: backgroundResult.description,
796
+ promise,
797
+ ...meta.timeoutMs !== void 0 && { timeoutMs: meta.timeoutMs },
798
+ ...meta.notifyOnComplete !== void 0 && {
799
+ notifyOnComplete: meta.notifyOnComplete
800
+ }
801
+ });
802
+ result = backgroundResult;
803
+ } else {
804
+ result = await this.internalToolsProvider.executeTool(
805
+ actualToolName,
806
+ toolArgs,
807
+ sessionId,
808
+ abortSignal,
809
+ toolCallId
810
+ );
811
+ }
485
812
  } else {
486
813
  this.logger.debug(`\u{1F527} Detected tool without proper prefix: '${toolName}'`);
487
814
  const stats = await this.getToolStats();
@@ -731,21 +1058,34 @@ let _ToolManager = class _ToolManager {
731
1058
  throw import_errors.ToolError.executionDenied(toolName, sessionId);
732
1059
  }
733
1060
  /**
734
- * Handle tool approval/confirmation flow
735
- * Checks allowed list, manages approval modes (manual, auto-approve, auto-deny),
736
- * and handles remember choice logic
1061
+ * Handle tool approval flow. Checks various precedence levels to determine
1062
+ * if a tool should be auto-approved, denied, or requires manual approval.
1063
+ */
1064
+ async handleToolApproval(toolName, args, toolCallId, sessionId, callDescription) {
1065
+ const quickResult = await this.tryQuickApprovalResolution(toolName, args, sessionId);
1066
+ if (quickResult !== null) {
1067
+ return quickResult;
1068
+ }
1069
+ return this.requestManualApproval(toolName, args, toolCallId, sessionId, callDescription);
1070
+ }
1071
+ /**
1072
+ * Try to resolve tool approval quickly based on policies and cached permissions.
1073
+ * Returns null if manual approval is needed.
737
1074
  *
738
- * @param toolName The fully qualified tool name
739
- * @param args The arguments for the tool
740
- * @param toolCallId The unique tool call ID for tracking parallel tool calls
741
- * @param sessionId Optional session ID for context
1075
+ * Precedence order (highest to lowest):
1076
+ * 1. Static deny list (security - always blocks)
1077
+ * 2. Custom approval override (tool-specific approval flows)
1078
+ * 3. Session auto-approve (skill allowed-tools)
1079
+ * 4. Static allow list
1080
+ * 5. Dynamic "remembered" allowed list
1081
+ * 6. Bash command patterns
1082
+ * 7. Approval mode (auto-approve/auto-deny)
742
1083
  */
743
- async handleToolApproval(toolName, args, toolCallId, sessionId) {
1084
+ async tryQuickApprovalResolution(toolName, args, sessionId) {
744
1085
  if (this.isInAlwaysDenyList(toolName)) {
745
1086
  this.logger.info(
746
1087
  `Tool '${toolName}' is in static deny list \u2013 blocking execution (session: ${sessionId ?? "global"})`
747
1088
  );
748
- this.logger.debug(`\u{1F6AB} Tool execution blocked by policy: ${toolName}`);
749
1089
  throw import_errors.ToolError.executionDenied(toolName, sessionId);
750
1090
  }
751
1091
  const customApprovalResult = await this.checkCustomApprovalOverride(
@@ -756,25 +1096,29 @@ let _ToolManager = class _ToolManager {
756
1096
  if (customApprovalResult.handled) {
757
1097
  return { requireApproval: true, approvalStatus: "approved" };
758
1098
  }
1099
+ if (sessionId && this.isToolAutoApprovedForSession(sessionId, toolName)) {
1100
+ this.logger.info(
1101
+ `Tool '${toolName}' is in session's auto-approve list \u2013 skipping confirmation (session: ${sessionId})`
1102
+ );
1103
+ return { requireApproval: false };
1104
+ }
759
1105
  if (this.isInAlwaysAllowList(toolName)) {
760
1106
  this.logger.info(
761
1107
  `Tool '${toolName}' is in static allow list \u2013 skipping confirmation (session: ${sessionId ?? "global"})`
762
1108
  );
763
1109
  return { requireApproval: false };
764
1110
  }
765
- const isAllowed = await this.allowedToolsProvider.isToolAllowed(toolName, sessionId);
766
- if (isAllowed) {
1111
+ if (await this.allowedToolsProvider.isToolAllowed(toolName, sessionId)) {
767
1112
  this.logger.info(
768
1113
  `Tool '${toolName}' already allowed for session '${sessionId ?? "global"}' \u2013 skipping confirmation.`
769
1114
  );
770
1115
  return { requireApproval: false };
771
1116
  }
772
- let bashPatternResult;
773
1117
  if (this.isBashTool(toolName)) {
774
1118
  const command = args.command;
775
1119
  if (command) {
776
- bashPatternResult = this.checkBashPatternApproval(command);
777
- if (bashPatternResult.approved) {
1120
+ const bashResult = this.checkBashPatternApproval(command);
1121
+ if (bashResult.approved) {
778
1122
  this.logger.info(
779
1123
  `Bash command '${command}' matched approved pattern \u2013 skipping confirmation.`
780
1124
  );
@@ -790,79 +1134,38 @@ let _ToolManager = class _ToolManager {
790
1134
  this.logger.debug(`\u{1F6AB} Auto-denying tool execution: ${toolName}`);
791
1135
  throw import_errors.ToolError.executionDenied(toolName, sessionId);
792
1136
  }
1137
+ return null;
1138
+ }
1139
+ /**
1140
+ * Request manual approval from the user for a tool execution.
1141
+ * Generates preview, sends approval request, and handles the response.
1142
+ */
1143
+ async requestManualApproval(toolName, args, toolCallId, sessionId, callDescription) {
793
1144
  this.logger.info(
794
1145
  `Tool confirmation requested for ${toolName}, sessionId: ${sessionId ?? "global"}`
795
1146
  );
796
1147
  try {
797
- let displayPreview;
798
- const actualToolName = toolName.replace(/^internal--/, "").replace(/^custom--/, "");
799
- const internalTool = this.internalToolsProvider?.getTool(actualToolName);
800
- if (internalTool?.generatePreview) {
801
- try {
802
- const context = { sessionId, toolCallId };
803
- const preview = await internalTool.generatePreview(args, context);
804
- displayPreview = preview ?? void 0;
805
- this.logger.debug(`Generated preview for ${toolName}`);
806
- } catch (previewError) {
807
- if (previewError instanceof import_errors2.DextoRuntimeError && previewError.code === import_error_codes.ToolErrorCode.VALIDATION_FAILED) {
808
- this.logger.debug(
809
- `Validation failed for ${toolName}: ${previewError.message}`
810
- );
811
- throw previewError;
812
- }
813
- this.logger.debug(
814
- `Preview generation failed for ${toolName}: ${previewError instanceof Error ? previewError.message : String(previewError)}`
815
- );
816
- }
817
- }
818
- const requestData = {
1148
+ const displayPreview = await this.generateToolPreview(
819
1149
  toolName,
1150
+ args,
820
1151
  toolCallId,
821
- args
822
- };
823
- if (sessionId !== void 0) {
824
- requestData.sessionId = sessionId;
825
- }
826
- if (displayPreview !== void 0) {
827
- requestData.displayPreview = displayPreview;
828
- }
829
- if (bashPatternResult?.suggestedPatterns && bashPatternResult.suggestedPatterns.length > 0) {
830
- requestData.suggestedPatterns = bashPatternResult.suggestedPatterns;
831
- }
832
- const response = await this.approvalManager.requestToolConfirmation(requestData);
1152
+ sessionId
1153
+ );
1154
+ const suggestedPatterns = this.getBashSuggestedPatterns(toolName, args);
1155
+ const response = await this.approvalManager.requestToolConfirmation({
1156
+ toolName,
1157
+ toolCallId,
1158
+ args,
1159
+ ...callDescription !== void 0 && { description: callDescription },
1160
+ ...sessionId !== void 0 && { sessionId },
1161
+ ...displayPreview !== void 0 && { displayPreview },
1162
+ ...suggestedPatterns !== void 0 && { suggestedPatterns }
1163
+ });
833
1164
  if (response.status === import_types3.ApprovalStatus.APPROVED && response.data) {
834
- const rememberChoice = "rememberChoice" in response.data ? response.data.rememberChoice : false;
835
- const rememberPattern = "rememberPattern" in response.data ? response.data.rememberPattern : void 0;
836
- if (rememberChoice) {
837
- const allowSessionId = sessionId ?? response.sessionId;
838
- await this.allowedToolsProvider.allowTool(toolName, allowSessionId);
839
- this.logger.info(
840
- `Tool '${toolName}' added to allowed tools for session '${allowSessionId ?? "global"}' (remember choice selected)`
841
- );
842
- this.autoApprovePendingToolRequests(toolName, allowSessionId);
843
- } else if (rememberPattern && typeof rememberPattern === "string" && this.isBashTool(toolName)) {
844
- this.approvalManager.addBashPattern(rememberPattern);
845
- this.logger.info(
846
- `Bash pattern '${rememberPattern}' added for session approval`
847
- );
848
- this.autoApprovePendingBashRequests(rememberPattern, sessionId);
849
- }
1165
+ await this.handleRememberChoice(toolName, response, sessionId);
850
1166
  }
851
- const approved = response.status === import_types3.ApprovalStatus.APPROVED;
852
- if (!approved) {
853
- if (response.status === import_types3.ApprovalStatus.CANCELLED && response.reason === "timeout") {
854
- this.logger.info(
855
- `Tool confirmation timed out for ${toolName}, sessionId: ${sessionId ?? "global"}`
856
- );
857
- this.logger.debug(`\u23F1\uFE0F Tool execution timed out: ${toolName}`);
858
- const timeoutMs = response.timeoutMs ?? 0;
859
- throw import_errors.ToolError.executionTimeout(toolName, timeoutMs, sessionId);
860
- }
861
- this.logger.info(
862
- `Tool confirmation denied for ${toolName}, sessionId: ${sessionId ?? "global"}, reason: ${response.reason ?? "unknown"}`
863
- );
864
- this.logger.debug(`\u{1F6AB} Tool execution denied: ${toolName}`);
865
- throw import_errors.ToolError.executionDenied(toolName, sessionId);
1167
+ if (response.status !== import_types3.ApprovalStatus.APPROVED) {
1168
+ this.handleApprovalDenied(toolName, response, sessionId);
866
1169
  }
867
1170
  this.logger.info(
868
1171
  `Tool confirmation approved for ${toolName}, sessionId: ${sessionId ?? "global"}`
@@ -875,6 +1178,81 @@ let _ToolManager = class _ToolManager {
875
1178
  throw error;
876
1179
  }
877
1180
  }
1181
+ /**
1182
+ * Generate a preview for the tool approval UI if the tool supports it.
1183
+ */
1184
+ async generateToolPreview(toolName, args, toolCallId, sessionId) {
1185
+ const actualToolName = toolName.replace(/^internal--/, "").replace(/^custom--/, "");
1186
+ const internalTool = this.internalToolsProvider?.getTool(actualToolName);
1187
+ if (!internalTool?.generatePreview) {
1188
+ return void 0;
1189
+ }
1190
+ try {
1191
+ const context = { sessionId, toolCallId };
1192
+ const preview = await internalTool.generatePreview(args, context);
1193
+ this.logger.debug(`Generated preview for ${toolName}`);
1194
+ return preview ?? void 0;
1195
+ } catch (previewError) {
1196
+ if (previewError instanceof import_errors2.DextoRuntimeError && previewError.code === import_error_codes.ToolErrorCode.VALIDATION_FAILED) {
1197
+ this.logger.debug(`Validation failed for ${toolName}: ${previewError.message}`);
1198
+ throw previewError;
1199
+ }
1200
+ this.logger.debug(
1201
+ `Preview generation failed for ${toolName}: ${previewError instanceof Error ? previewError.message : String(previewError)}`
1202
+ );
1203
+ return void 0;
1204
+ }
1205
+ }
1206
+ /**
1207
+ * Get suggested bash patterns for the approval UI.
1208
+ */
1209
+ getBashSuggestedPatterns(toolName, args) {
1210
+ if (!this.isBashTool(toolName)) {
1211
+ return void 0;
1212
+ }
1213
+ const command = args.command;
1214
+ if (!command) {
1215
+ return void 0;
1216
+ }
1217
+ const result = this.checkBashPatternApproval(command);
1218
+ return result.suggestedPatterns?.length ? result.suggestedPatterns : void 0;
1219
+ }
1220
+ /**
1221
+ * Handle "remember choice" or "remember pattern" when user approves a tool.
1222
+ */
1223
+ async handleRememberChoice(toolName, response, sessionId) {
1224
+ const data = response.data;
1225
+ if (!data) return;
1226
+ const rememberChoice = data.rememberChoice;
1227
+ const rememberPattern = data.rememberPattern;
1228
+ if (rememberChoice) {
1229
+ const allowSessionId = sessionId ?? response.sessionId;
1230
+ await this.allowedToolsProvider.allowTool(toolName, allowSessionId);
1231
+ this.logger.info(
1232
+ `Tool '${toolName}' added to allowed tools for session '${allowSessionId ?? "global"}' (remember choice selected)`
1233
+ );
1234
+ this.autoApprovePendingToolRequests(toolName, allowSessionId);
1235
+ } else if (rememberPattern && this.isBashTool(toolName)) {
1236
+ this.approvalManager.addBashPattern(rememberPattern);
1237
+ this.logger.info(`Bash pattern '${rememberPattern}' added for session approval`);
1238
+ this.autoApprovePendingBashRequests(rememberPattern, sessionId);
1239
+ }
1240
+ }
1241
+ /**
1242
+ * Handle approval denied/timeout - throws appropriate error.
1243
+ */
1244
+ handleApprovalDenied(toolName, response, sessionId) {
1245
+ if (response.status === import_types3.ApprovalStatus.CANCELLED && response.reason === import_types3.DenialReason.TIMEOUT) {
1246
+ this.logger.info(
1247
+ `Tool confirmation timed out for ${toolName}, sessionId: ${sessionId ?? "global"}`
1248
+ );
1249
+ throw import_errors.ToolError.executionTimeout(toolName, response.timeoutMs ?? 0, sessionId);
1250
+ }
1251
+ this.logger.info(
1252
+ `Tool confirmation denied for ${toolName}, sessionId: ${sessionId ?? "global"}, reason: ${response.reason ?? "unknown"}`
1253
+ );
1254
+ throw import_errors.ToolError.executionDenied(toolName, sessionId, response.message);
1255
+ }
878
1256
  /**
879
1257
  * Refresh tool discovery (call when MCP servers change)
880
1258
  * Refreshes both MCPManager's cache (server capabilities) and ToolManager's cache (combined tools)