@dexto/core 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/dist/agent/DextoAgent.cjs +79 -5
  2. package/dist/agent/DextoAgent.d.ts +24 -2
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +79 -5
  5. package/dist/agent/agent-options.d.ts +6 -1
  6. package/dist/agent/agent-options.d.ts.map +1 -1
  7. package/dist/agent/schemas.d.ts +18 -18
  8. package/dist/approval/manager.cjs +87 -27
  9. package/dist/approval/manager.d.ts +10 -1
  10. package/dist/approval/manager.d.ts.map +1 -1
  11. package/dist/approval/manager.js +87 -27
  12. package/dist/approval/schemas.cjs +22 -8
  13. package/dist/approval/schemas.d.ts +276 -102
  14. package/dist/approval/schemas.d.ts.map +1 -1
  15. package/dist/approval/schemas.js +22 -8
  16. package/dist/context/manager.cjs +2 -2
  17. package/dist/context/manager.d.ts +2 -1
  18. package/dist/context/manager.d.ts.map +1 -1
  19. package/dist/context/manager.js +2 -2
  20. package/dist/context/types.d.ts +3 -2
  21. package/dist/context/types.d.ts.map +1 -1
  22. package/dist/events/index.d.ts +26 -13
  23. package/dist/events/index.d.ts.map +1 -1
  24. package/dist/hooks/index.d.ts +1 -1
  25. package/dist/hooks/index.d.ts.map +1 -1
  26. package/dist/hooks/types.d.ts +1 -22
  27. package/dist/hooks/types.d.ts.map +1 -1
  28. package/dist/llm/executor/provider-options.cjs +223 -28
  29. package/dist/llm/executor/provider-options.d.ts +3 -37
  30. package/dist/llm/executor/provider-options.d.ts.map +1 -1
  31. package/dist/llm/executor/provider-options.js +227 -27
  32. package/dist/llm/executor/stream-processor.cjs +57 -34
  33. package/dist/llm/executor/stream-processor.d.ts +12 -4
  34. package/dist/llm/executor/stream-processor.d.ts.map +1 -1
  35. package/dist/llm/executor/stream-processor.js +55 -32
  36. package/dist/llm/executor/turn-executor.cjs +66 -44
  37. package/dist/llm/executor/turn-executor.d.ts +3 -3
  38. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  39. package/dist/llm/executor/turn-executor.js +56 -34
  40. package/dist/llm/formatters/vercel.cjs +15 -3
  41. package/dist/llm/formatters/vercel.d.ts +1 -0
  42. package/dist/llm/formatters/vercel.d.ts.map +1 -1
  43. package/dist/llm/formatters/vercel.js +15 -3
  44. package/dist/llm/index.cjs +8 -0
  45. package/dist/llm/index.d.ts +2 -1
  46. package/dist/llm/index.d.ts.map +1 -1
  47. package/dist/llm/index.js +7 -0
  48. package/dist/llm/providers/local/schemas.d.ts +2 -2
  49. package/dist/llm/providers/openrouter-model-registry.cjs +66 -11
  50. package/dist/llm/providers/openrouter-model-registry.d.ts +26 -0
  51. package/dist/llm/providers/openrouter-model-registry.d.ts.map +1 -1
  52. package/dist/llm/providers/openrouter-model-registry.js +65 -11
  53. package/dist/llm/reasoning/anthropic-betas.cjs +31 -0
  54. package/dist/llm/reasoning/anthropic-betas.d.ts +3 -0
  55. package/dist/llm/reasoning/anthropic-betas.d.ts.map +1 -0
  56. package/dist/llm/reasoning/anthropic-betas.js +7 -0
  57. package/dist/llm/reasoning/anthropic-thinking.cjs +79 -0
  58. package/dist/llm/reasoning/anthropic-thinking.d.ts +15 -0
  59. package/dist/llm/reasoning/anthropic-thinking.d.ts.map +1 -0
  60. package/dist/llm/reasoning/anthropic-thinking.js +52 -0
  61. package/dist/llm/reasoning/openai-reasoning-effort.cjs +86 -0
  62. package/dist/llm/reasoning/openai-reasoning-effort.d.ts +5 -0
  63. package/dist/llm/reasoning/openai-reasoning-effort.d.ts.map +1 -0
  64. package/dist/llm/reasoning/openai-reasoning-effort.js +61 -0
  65. package/dist/llm/reasoning/profile.cjs +113 -0
  66. package/dist/llm/reasoning/profile.d.ts +13 -0
  67. package/dist/llm/reasoning/profile.d.ts.map +1 -0
  68. package/dist/llm/reasoning/profile.js +92 -0
  69. package/dist/llm/reasoning/profiles/anthropic.cjs +61 -0
  70. package/dist/llm/reasoning/profiles/anthropic.d.ts +8 -0
  71. package/dist/llm/reasoning/profiles/anthropic.d.ts.map +1 -0
  72. package/dist/llm/reasoning/profiles/anthropic.js +45 -0
  73. package/dist/llm/reasoning/profiles/bedrock.cjs +54 -0
  74. package/dist/llm/reasoning/profiles/bedrock.d.ts +3 -0
  75. package/dist/llm/reasoning/profiles/bedrock.d.ts.map +1 -0
  76. package/dist/llm/reasoning/profiles/bedrock.js +36 -0
  77. package/dist/llm/reasoning/profiles/google.cjs +45 -0
  78. package/dist/llm/reasoning/profiles/google.d.ts +9 -0
  79. package/dist/llm/reasoning/profiles/google.d.ts.map +1 -0
  80. package/dist/llm/reasoning/profiles/google.js +21 -0
  81. package/dist/llm/reasoning/profiles/openai-compatible.cjs +39 -0
  82. package/dist/llm/reasoning/profiles/openai-compatible.d.ts +3 -0
  83. package/dist/llm/reasoning/profiles/openai-compatible.d.ts.map +1 -0
  84. package/dist/llm/reasoning/profiles/openai-compatible.js +16 -0
  85. package/dist/llm/reasoning/profiles/openai.cjs +41 -0
  86. package/dist/llm/reasoning/profiles/openai.d.ts +3 -0
  87. package/dist/llm/reasoning/profiles/openai.d.ts.map +1 -0
  88. package/dist/llm/reasoning/profiles/openai.js +18 -0
  89. package/dist/llm/reasoning/profiles/openrouter.cjs +83 -0
  90. package/dist/llm/reasoning/profiles/openrouter.d.ts +10 -0
  91. package/dist/llm/reasoning/profiles/openrouter.d.ts.map +1 -0
  92. package/dist/llm/reasoning/profiles/openrouter.js +59 -0
  93. package/dist/llm/reasoning/profiles/shared.cjs +80 -0
  94. package/dist/llm/reasoning/profiles/shared.d.ts +25 -0
  95. package/dist/llm/reasoning/profiles/shared.d.ts.map +1 -0
  96. package/dist/llm/reasoning/profiles/shared.js +53 -0
  97. package/dist/llm/reasoning/profiles/vertex.cjs +46 -0
  98. package/dist/llm/reasoning/profiles/vertex.d.ts +3 -0
  99. package/dist/llm/reasoning/profiles/vertex.d.ts.map +1 -0
  100. package/dist/llm/reasoning/profiles/vertex.js +23 -0
  101. package/dist/llm/registry/auto-update.cjs +18 -0
  102. package/dist/llm/registry/auto-update.d.ts.map +1 -1
  103. package/dist/llm/registry/auto-update.js +18 -0
  104. package/dist/llm/registry/index.cjs +126 -26
  105. package/dist/llm/registry/index.d.ts +48 -4
  106. package/dist/llm/registry/index.d.ts.map +1 -1
  107. package/dist/llm/registry/index.js +136 -28
  108. package/dist/llm/registry/models.generated.cjs +5198 -59
  109. package/dist/llm/registry/models.generated.d.ts +1893 -76
  110. package/dist/llm/registry/models.generated.d.ts.map +1 -1
  111. package/dist/llm/registry/models.generated.js +5196 -58
  112. package/dist/llm/registry/sync.cjs +72 -1
  113. package/dist/llm/registry/sync.d.ts +21 -1
  114. package/dist/llm/registry/sync.d.ts.map +1 -1
  115. package/dist/llm/registry/sync.js +72 -1
  116. package/dist/llm/resolver.cjs +13 -1
  117. package/dist/llm/resolver.d.ts.map +1 -1
  118. package/dist/llm/resolver.js +13 -1
  119. package/dist/llm/schemas.cjs +75 -14
  120. package/dist/llm/schemas.d.ts +84 -27
  121. package/dist/llm/schemas.d.ts.map +1 -1
  122. package/dist/llm/schemas.js +75 -14
  123. package/dist/llm/services/factory.cjs +55 -8
  124. package/dist/llm/services/factory.d.ts +1 -1
  125. package/dist/llm/services/factory.d.ts.map +1 -1
  126. package/dist/llm/services/factory.js +58 -8
  127. package/dist/llm/services/vercel.cjs +2 -2
  128. package/dist/llm/services/vercel.js +2 -2
  129. package/dist/llm/types.d.ts +9 -0
  130. package/dist/llm/types.d.ts.map +1 -1
  131. package/dist/logger/default-logger-factory.d.ts +12 -12
  132. package/dist/logger/v2/dexto-logger.cjs +35 -0
  133. package/dist/logger/v2/dexto-logger.d.ts +19 -0
  134. package/dist/logger/v2/dexto-logger.d.ts.map +1 -1
  135. package/dist/logger/v2/dexto-logger.js +35 -0
  136. package/dist/logger/v2/schemas.d.ts +6 -6
  137. package/dist/logger/v2/test-utils.cjs +2 -0
  138. package/dist/logger/v2/test-utils.d.ts.map +1 -1
  139. package/dist/logger/v2/test-utils.js +2 -0
  140. package/dist/logger/v2/types.d.ts +14 -1
  141. package/dist/logger/v2/types.d.ts.map +1 -1
  142. package/dist/mcp/schemas.d.ts +15 -15
  143. package/dist/memory/schemas.d.ts +4 -4
  144. package/dist/prompts/index.cjs +9 -0
  145. package/dist/prompts/index.d.ts +1 -0
  146. package/dist/prompts/index.d.ts.map +1 -1
  147. package/dist/prompts/index.js +10 -0
  148. package/dist/prompts/prompt-manager.cjs +2 -0
  149. package/dist/prompts/prompt-manager.d.ts.map +1 -1
  150. package/dist/prompts/prompt-manager.js +2 -0
  151. package/dist/prompts/providers/config-prompt-provider.cjs +11 -1
  152. package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -1
  153. package/dist/prompts/providers/config-prompt-provider.js +11 -1
  154. package/dist/prompts/schemas.cjs +2 -2
  155. package/dist/prompts/schemas.d.ts +7 -7
  156. package/dist/prompts/schemas.js +2 -2
  157. package/dist/prompts/types.d.ts +6 -2
  158. package/dist/prompts/types.d.ts.map +1 -1
  159. package/dist/systemPrompt/in-built-prompts.cjs +5 -5
  160. package/dist/systemPrompt/in-built-prompts.d.ts +1 -1
  161. package/dist/systemPrompt/in-built-prompts.d.ts.map +1 -1
  162. package/dist/systemPrompt/in-built-prompts.js +5 -5
  163. package/dist/systemPrompt/schemas.d.ts +5 -5
  164. package/dist/systemPrompt/types.d.ts +11 -0
  165. package/dist/systemPrompt/types.d.ts.map +1 -1
  166. package/dist/tools/display-types.d.ts +10 -0
  167. package/dist/tools/display-types.d.ts.map +1 -1
  168. package/dist/tools/index.cjs +3 -1
  169. package/dist/tools/index.d.ts +1 -0
  170. package/dist/tools/index.d.ts.map +1 -1
  171. package/dist/tools/index.js +1 -0
  172. package/dist/tools/presentation.cjs +49 -0
  173. package/dist/tools/presentation.d.ts +11 -0
  174. package/dist/tools/presentation.d.ts.map +1 -0
  175. package/dist/tools/presentation.js +24 -0
  176. package/dist/tools/tool-manager.cjs +389 -136
  177. package/dist/tools/tool-manager.d.ts +36 -24
  178. package/dist/tools/tool-manager.d.ts.map +1 -1
  179. package/dist/tools/tool-manager.js +389 -136
  180. package/dist/tools/types.d.ts +134 -55
  181. package/dist/tools/types.d.ts.map +1 -1
  182. package/dist/utils/path.cjs +10 -1
  183. package/dist/utils/path.d.ts +5 -2
  184. package/dist/utils/path.d.ts.map +1 -1
  185. package/dist/utils/path.js +10 -1
  186. package/dist/utils/service-initializer.d.ts +1 -0
  187. package/dist/utils/service-initializer.d.ts.map +1 -1
  188. package/package.json +7 -5
@@ -26,6 +26,7 @@ let _ToolManager = class _ToolManager {
26
26
  agentEventBus;
27
27
  toolPolicies;
28
28
  toolExecutionContextFactory;
29
+ contributorContextFactory;
29
30
  // Hook support - set after construction to avoid circular dependencies
30
31
  hookManager;
31
32
  sessionManager;
@@ -102,6 +103,20 @@ let _ToolManager = class _ToolManager {
102
103
  }
103
104
  this.invalidateCache();
104
105
  }
106
+ addTools(tools) {
107
+ const added = [];
108
+ for (const tool of tools) {
109
+ if (this.agentTools.has(tool.id)) {
110
+ continue;
111
+ }
112
+ this.agentTools.set(tool.id, tool);
113
+ added.push(tool.id);
114
+ }
115
+ if (added.length > 0) {
116
+ this.invalidateCache();
117
+ }
118
+ return added;
119
+ }
105
120
  setToolExecutionContextFactory(factory) {
106
121
  this.toolExecutionContextFactory = factory;
107
122
  }
@@ -191,6 +206,37 @@ let _ToolManager = class _ToolManager {
191
206
  );
192
207
  this.logger.debug(`Auto-approve tools: ${normalized.join(", ")}`);
193
208
  }
209
+ /**
210
+ * Add session-level auto-approve tools.
211
+ * Merges into the existing list instead of replacing it.
212
+ *
213
+ * @param sessionId The session ID
214
+ * @param autoApproveTools Array of tool names to auto-approve (e.g., ['bash_exec', 'mcp--read_file'])
215
+ */
216
+ addSessionAutoApproveTools(sessionId, autoApproveTools) {
217
+ if (autoApproveTools.length === 0) {
218
+ return;
219
+ }
220
+ const normalized = autoApproveTools.map(
221
+ (pattern) => this.normalizeToolPolicyPattern(pattern)
222
+ );
223
+ const existing = this.sessionAutoApproveTools.get(sessionId) ?? [];
224
+ const merged = [...existing];
225
+ const seen = new Set(existing);
226
+ for (const toolName of normalized) {
227
+ if (seen.has(toolName)) {
228
+ continue;
229
+ }
230
+ merged.push(toolName);
231
+ seen.add(toolName);
232
+ }
233
+ const actuallyAdded = Math.max(0, merged.length - existing.length);
234
+ this.sessionAutoApproveTools.set(sessionId, merged);
235
+ this.logger.info(
236
+ `Session auto-approve tools updated for '${sessionId}': +${actuallyAdded} tools`
237
+ );
238
+ this.logger.debug(`Auto-approve tools: ${merged.join(", ")}`);
239
+ }
194
240
  /**
195
241
  * Set session-level auto-approve tools chosen by the user.
196
242
  */
@@ -384,16 +430,175 @@ let _ToolManager = class _ToolManager {
384
430
  });
385
431
  }
386
432
  // ==================== Pattern Approval Helpers ====================
433
+ getToolApprovalPatternKeyFn(toolName) {
434
+ const tool = this.agentTools.get(toolName);
435
+ return tool?.approval?.patternKey;
436
+ }
437
+ getToolSuggestApprovalPatternsFn(toolName) {
438
+ const tool = this.agentTools.get(toolName);
439
+ return tool?.approval?.suggestPatterns;
440
+ }
441
+ getToolApprovalOverrideFn(toolName) {
442
+ const tool = this.agentTools.get(toolName);
443
+ return tool?.approval?.override;
444
+ }
445
+ getToolApprovalOnGrantedFn(toolName) {
446
+ const tool = this.agentTools.get(toolName);
447
+ return tool?.approval?.onGranted;
448
+ }
449
+ getToolPreviewFn(toolName) {
450
+ const tool = this.agentTools.get(toolName);
451
+ return tool?.presentation?.preview;
452
+ }
453
+ getToolDescribeHeaderFn(toolName) {
454
+ const tool = this.agentTools.get(toolName);
455
+ return tool?.presentation?.describeHeader;
456
+ }
457
+ getToolDescribeArgsFn(toolName) {
458
+ const tool = this.agentTools.get(toolName);
459
+ return tool?.presentation?.describeArgs;
460
+ }
461
+ getToolDescribeResultFn(toolName) {
462
+ const tool = this.agentTools.get(toolName);
463
+ return tool?.presentation?.describeResult;
464
+ }
465
+ buildGenericToolPresentationSnapshot(toolName) {
466
+ const toTitleCase = (name) => name.replace(/[_-]+/g, " ").split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
467
+ const isMcp = toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX);
468
+ const fallbackTitle = (() => {
469
+ if (!isMcp) {
470
+ return toTitleCase(toolName);
471
+ }
472
+ const actualToolName = toolName.substring(_ToolManager.MCP_TOOL_PREFIX.length);
473
+ const parts = actualToolName.split("--");
474
+ const toolPart = parts.length >= 2 ? parts.slice(1).join("--") : actualToolName;
475
+ return toTitleCase(toolPart);
476
+ })();
477
+ const snapshot = {
478
+ version: 1,
479
+ source: {
480
+ type: toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX) ? "mcp" : "local"
481
+ },
482
+ header: {
483
+ title: fallbackTitle
484
+ }
485
+ };
486
+ if (snapshot.source?.type === "mcp") {
487
+ const actualToolName = toolName.substring(_ToolManager.MCP_TOOL_PREFIX.length);
488
+ const parts = actualToolName.split("--");
489
+ if (parts.length >= 2 && parts[0]) {
490
+ snapshot.source.mcpServerName = parts[0];
491
+ }
492
+ }
493
+ return snapshot;
494
+ }
495
+ getToolPresentationSnapshotForToolCallEvent(toolName, args, toolCallId, sessionId) {
496
+ const fallback = this.buildGenericToolPresentationSnapshot(toolName);
497
+ if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
498
+ return fallback;
499
+ }
500
+ const describeHeader = this.getToolDescribeHeaderFn(toolName);
501
+ const describeArgs = this.getToolDescribeArgsFn(toolName);
502
+ if (!describeHeader && !describeArgs) {
503
+ return fallback;
504
+ }
505
+ try {
506
+ const validatedArgs = this.validateLocalToolArgs(toolName, args);
507
+ const context = this.buildToolExecutionContext({ sessionId, toolCallId });
508
+ const isPromiseLike = (value) => {
509
+ if (typeof value !== "object" || value === null) {
510
+ return false;
511
+ }
512
+ return typeof value.then === "function";
513
+ };
514
+ let nextSnapshot = fallback;
515
+ if (describeHeader) {
516
+ const header = describeHeader(validatedArgs, context);
517
+ if (!isPromiseLike(header) && header) {
518
+ nextSnapshot = {
519
+ ...nextSnapshot,
520
+ header: { ...nextSnapshot.header, ...header }
521
+ };
522
+ }
523
+ }
524
+ if (describeArgs) {
525
+ const argsPresentation = describeArgs(validatedArgs, context);
526
+ if (!isPromiseLike(argsPresentation) && argsPresentation) {
527
+ nextSnapshot = {
528
+ ...nextSnapshot,
529
+ args: argsPresentation
530
+ };
531
+ }
532
+ }
533
+ return nextSnapshot;
534
+ } catch (error) {
535
+ this.logger.debug(
536
+ `Tool presentation snapshot generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
537
+ );
538
+ return fallback;
539
+ }
540
+ }
541
+ async getToolPresentationSnapshotForCall(toolName, args, toolCallId, sessionId) {
542
+ const fallback = this.buildGenericToolPresentationSnapshot(toolName);
543
+ if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
544
+ return fallback;
545
+ }
546
+ const describeHeader = this.getToolDescribeHeaderFn(toolName);
547
+ const describeArgs = this.getToolDescribeArgsFn(toolName);
548
+ if (!describeHeader && !describeArgs) {
549
+ return fallback;
550
+ }
551
+ try {
552
+ const context = this.buildToolExecutionContext({ sessionId, toolCallId });
553
+ const describedHeader = describeHeader ? await Promise.resolve(describeHeader(args, context)) : null;
554
+ const describedArgs = describeArgs ? await Promise.resolve(describeArgs(args, context)) : null;
555
+ return {
556
+ ...fallback,
557
+ ...describedHeader ? { header: { ...fallback.header, ...describedHeader } } : {},
558
+ ...describedArgs ? { args: describedArgs } : {}
559
+ };
560
+ } catch (error) {
561
+ this.logger.debug(
562
+ `Tool presentation snapshot generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
563
+ );
564
+ return fallback;
565
+ }
566
+ }
567
+ async augmentSnapshotWithResult(toolName, snapshot, result, args, toolCallId, sessionId) {
568
+ if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
569
+ return snapshot;
570
+ }
571
+ const describeResult = this.getToolDescribeResultFn(toolName);
572
+ if (!describeResult) {
573
+ return snapshot;
574
+ }
575
+ try {
576
+ const context = this.buildToolExecutionContext({ sessionId, toolCallId });
577
+ const resultPresentation = await Promise.resolve(describeResult(result, args, context));
578
+ if (!resultPresentation) {
579
+ return snapshot;
580
+ }
581
+ return {
582
+ ...snapshot,
583
+ result: resultPresentation
584
+ };
585
+ } catch (error) {
586
+ this.logger.debug(
587
+ `Tool result presentation snapshot generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
588
+ );
589
+ return snapshot;
590
+ }
591
+ }
387
592
  getToolPatternKey(toolName, args) {
388
593
  if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
389
594
  return null;
390
595
  }
391
- const tool = this.agentTools.get(toolName);
392
- if (!tool?.getApprovalPatternKey) {
596
+ const getPatternKey = this.getToolApprovalPatternKeyFn(toolName);
597
+ if (!getPatternKey) {
393
598
  return null;
394
599
  }
395
600
  try {
396
- return tool.getApprovalPatternKey(args);
601
+ return getPatternKey(args);
397
602
  } catch (error) {
398
603
  this.logger.debug(
399
604
  `Pattern key generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
@@ -405,12 +610,12 @@ let _ToolManager = class _ToolManager {
405
610
  if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
406
611
  return void 0;
407
612
  }
408
- const tool = this.agentTools.get(toolName);
409
- if (!tool?.suggestApprovalPatterns) {
613
+ const suggestPatterns = this.getToolSuggestApprovalPatternsFn(toolName);
614
+ if (!suggestPatterns) {
410
615
  return void 0;
411
616
  }
412
617
  try {
413
- const patterns = tool.suggestApprovalPatterns(args);
618
+ const patterns = suggestPatterns(args);
414
619
  return patterns.length > 0 ? patterns : void 0;
415
620
  } catch (error) {
416
621
  this.logger.debug(
@@ -436,8 +641,10 @@ let _ToolManager = class _ToolManager {
436
641
  if (request.sessionId !== sessionId) {
437
642
  return false;
438
643
  }
439
- const metadata = request.metadata;
440
- return metadata.toolName === toolName;
644
+ if (request.metadata.toolName !== toolName) {
645
+ return false;
646
+ }
647
+ return request.metadata.directoryAccess === void 0;
441
648
  },
442
649
  { rememberChoice: false }
443
650
  // Don't propagate remember choice to auto-approved requests
@@ -456,8 +663,7 @@ let _ToolManager = class _ToolManager {
456
663
  if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
457
664
  return;
458
665
  }
459
- const tool = this.agentTools.get(toolName);
460
- const getPatternKey = tool?.getApprovalPatternKey;
666
+ const getPatternKey = this.getToolApprovalPatternKeyFn(toolName);
461
667
  if (!getPatternKey) {
462
668
  return;
463
669
  }
@@ -469,17 +675,20 @@ let _ToolManager = class _ToolManager {
469
675
  if (request.sessionId !== sessionId) {
470
676
  return false;
471
677
  }
472
- const metadata = request.metadata;
473
- if (metadata.toolName !== toolName) {
678
+ if (request.metadata.toolName !== toolName) {
474
679
  return false;
475
680
  }
476
- const args = metadata.args;
681
+ if (request.metadata.directoryAccess !== void 0) {
682
+ return false;
683
+ }
684
+ const args = request.metadata.args;
477
685
  if (typeof args !== "object" || args === null) {
478
686
  return false;
479
687
  }
688
+ const argsRecord = args;
480
689
  let patternKey;
481
690
  try {
482
- patternKey = getPatternKey(args);
691
+ patternKey = getPatternKey(argsRecord);
483
692
  } catch (error) {
484
693
  this.logger.debug(
485
694
  `Pattern key generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
@@ -499,42 +708,68 @@ let _ToolManager = class _ToolManager {
499
708
  }
500
709
  }
501
710
  /**
502
- * Auto-approve pending directory access requests that match a newly approved directory access request.
503
- *
504
- * This handles the case where parallel file operations request directory approval concurrently.
711
+ * Auto-approve pending tool approval requests that are now covered by a remembered directory.
712
+ * Called after a user selects "remember directory" for a directory-access prompt.
505
713
  */
506
- autoApprovePendingDirectoryAccessRequests(options) {
714
+ autoApprovePendingDirectoryRequests(toolName, sessionId) {
507
715
  const count = this.approvalManager.autoApprovePendingRequests(
508
716
  (request) => {
509
- if (request.type !== ApprovalType.DIRECTORY_ACCESS) {
717
+ if (request.type !== ApprovalType.TOOL_APPROVAL) {
510
718
  return false;
511
719
  }
512
- if (request.sessionId !== options.sessionId) {
720
+ if (request.sessionId !== sessionId) {
513
721
  return false;
514
722
  }
515
- const metadata = request.metadata;
516
- if (typeof metadata?.parentDir !== "string" || metadata.parentDir !== options.parentDir) {
723
+ if (request.metadata.toolName !== toolName) {
517
724
  return false;
518
725
  }
519
- if (options.rememberDirectory) {
520
- return true;
521
- }
522
- if (typeof metadata?.operation !== "string" || typeof metadata?.toolName !== "string") {
726
+ const directoryAccess = request.metadata.directoryAccess;
727
+ if (!directoryAccess) {
523
728
  return false;
524
729
  }
525
- return metadata.operation === options.operation && metadata.toolName === options.toolName;
730
+ return this.approvalManager.isDirectorySessionApproved(directoryAccess.parentDir);
526
731
  },
527
732
  { rememberDirectory: false }
528
733
  );
529
734
  if (count > 0) {
530
735
  this.logger.info(
531
- `Auto-approved ${count} parallel request(s) for directory '${options.parentDir}' after directory access was approved`
736
+ 'Auto-approved parallel request(s) after user selected "remember directory"',
737
+ { count, toolName }
532
738
  );
533
739
  }
534
740
  }
535
741
  getMcpManager() {
536
742
  return this.mcpManager;
537
743
  }
744
+ setContributorContextFactory(factory) {
745
+ this.contributorContextFactory = factory ?? void 0;
746
+ }
747
+ async buildContributorContext() {
748
+ const baseWorkspace = this.currentWorkspace ?? null;
749
+ const baseContext = {
750
+ mcpManager: this.mcpManager,
751
+ workspace: baseWorkspace
752
+ };
753
+ if (!this.contributorContextFactory) {
754
+ return baseContext;
755
+ }
756
+ try {
757
+ const overrides = await this.contributorContextFactory() ?? {};
758
+ const workspace = overrides.workspace !== void 0 ? overrides.workspace : baseWorkspace;
759
+ const environment = overrides.environment !== void 0 ? overrides.environment : baseContext.environment;
760
+ const mcpManager = overrides.mcpManager ?? baseContext.mcpManager;
761
+ return {
762
+ mcpManager,
763
+ workspace,
764
+ ...environment !== void 0 ? { environment } : {}
765
+ };
766
+ } catch (error) {
767
+ this.logger.warn(
768
+ `Failed to build contributor context: ${error instanceof Error ? error.message : String(error)}`
769
+ );
770
+ return baseContext;
771
+ }
772
+ }
538
773
  /**
539
774
  * Get all MCP tools (delegates to mcpManager.getAllTools())
540
775
  * This provides access to MCP tools while maintaining separation of concerns
@@ -554,7 +789,7 @@ let _ToolManager = class _ToolManager {
554
789
  };
555
790
  return this.toolExecutionContextFactory(baseContext);
556
791
  }
557
- validateLocalToolArgsOrThrow(toolName, args) {
792
+ validateLocalToolArgs(toolName, args) {
558
793
  if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
559
794
  return args;
560
795
  }
@@ -675,15 +910,22 @@ let _ToolManager = class _ToolManager {
675
910
  async executeTool(toolName, args, toolCallId, sessionId, abortSignal) {
676
911
  const { toolArgs: rawToolArgs, meta } = extractToolCallMeta(args);
677
912
  let toolArgs = rawToolArgs;
913
+ const callDescription = typeof meta.callDescription === "string" ? meta.callDescription : typeof rawToolArgs.description === "string" ? rawToolArgs.description : void 0;
678
914
  const backgroundTasksEnabled = isBackgroundTasksEnabled();
679
- const toolDisplayName = this.agentTools.get(toolName)?.displayName;
680
915
  this.logger.debug(`\u{1F527} Tool execution requested: '${toolName}' (toolCallId: ${toolCallId})`);
681
916
  this.logger.debug(`Tool args: ${JSON.stringify(toolArgs, null, 2)}`);
682
917
  if (sessionId) {
918
+ const presentationSnapshot = this.getToolPresentationSnapshotForToolCallEvent(
919
+ toolName,
920
+ toolArgs,
921
+ toolCallId,
922
+ sessionId
923
+ );
683
924
  this.agentEventBus.emit("llm:tool-call", {
684
925
  toolName,
685
- ...toolDisplayName !== void 0 && { toolDisplayName },
926
+ presentationSnapshot,
686
927
  args: toolArgs,
928
+ ...callDescription !== void 0 && { callDescription },
687
929
  callId: toolCallId,
688
930
  sessionId
689
931
  });
@@ -691,13 +933,14 @@ let _ToolManager = class _ToolManager {
691
933
  const {
692
934
  requireApproval,
693
935
  approvalStatus,
694
- args: validatedToolArgs
936
+ args: validatedToolArgs,
937
+ presentationSnapshot: callSnapshot
695
938
  } = await this.handleToolApproval(
696
939
  toolName,
697
940
  toolArgs,
698
941
  toolCallId,
699
942
  sessionId,
700
- meta.callDescription
943
+ callDescription
701
944
  );
702
945
  toolArgs = validatedToolArgs;
703
946
  this.logger.debug(`\u2705 Tool execution approved: ${toolName}`);
@@ -731,7 +974,7 @@ let _ToolManager = class _ToolManager {
731
974
  );
732
975
  toolArgs = modifiedPayload.args;
733
976
  try {
734
- toolArgs = this.validateLocalToolArgsOrThrow(toolName, toolArgs);
977
+ toolArgs = this.validateLocalToolArgs(toolName, toolArgs);
735
978
  } catch (error) {
736
979
  this.logger.error(
737
980
  `Post-hook validation failed for tool '${toolName}': a beforeToolCall hook may have set invalid args`
@@ -854,9 +1097,17 @@ let _ToolManager = class _ToolManager {
854
1097
  );
855
1098
  result = modifiedPayload.result;
856
1099
  }
1100
+ const presentationSnapshot = await this.augmentSnapshotWithResult(
1101
+ toolName,
1102
+ callSnapshot,
1103
+ result,
1104
+ toolArgs,
1105
+ toolCallId,
1106
+ sessionId
1107
+ );
857
1108
  return {
858
1109
  result,
859
- ...toolDisplayName !== void 0 && { toolDisplayName },
1110
+ ...presentationSnapshot !== void 0 && { presentationSnapshot },
860
1111
  ...requireApproval && { requireApproval, approvalStatus }
861
1112
  };
862
1113
  } catch (error) {
@@ -981,124 +1232,113 @@ let _ToolManager = class _ToolManager {
981
1232
  );
982
1233
  }
983
1234
  /**
984
- * Check if a tool has a custom approval override and handle it.
985
- * Tools can implement getApprovalOverride() to request specialized approval flows
986
- * (e.g., directory access approval for file tools) instead of default tool confirmation.
987
- *
988
- * @param toolName Tool name
989
- * @param args The tool arguments
990
- * @param sessionId Optional session ID
991
- * @returns { handled: true } if custom approval was processed, { handled: false } to continue normal flow
1235
+ * Handle tool approval flow. Checks various precedence levels to determine
1236
+ * if a tool should be auto-approved, denied, or requires manual approval.
992
1237
  */
993
- async checkCustomApprovalOverride(toolName, args, toolCallId, sessionId) {
994
- if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
995
- return { handled: false };
996
- }
997
- const tool = this.agentTools.get(toolName);
998
- if (!tool?.getApprovalOverride) {
999
- return { handled: false };
1000
- }
1001
- const context = this.buildToolExecutionContext({ sessionId, toolCallId });
1002
- const approvalRequest = await tool.getApprovalOverride(args, context);
1003
- if (!approvalRequest) {
1004
- return { handled: false };
1005
- }
1006
- this.logger.debug(
1007
- `Tool '${toolName}' requested custom approval: type=${approvalRequest.type}`
1008
- );
1009
- if (sessionId && !approvalRequest.sessionId) {
1010
- approvalRequest.sessionId = sessionId;
1011
- }
1012
- const response = await this.approvalManager.requestApproval(approvalRequest);
1013
- if (response.status === ApprovalStatus.APPROVED) {
1014
- if (tool.onApprovalGranted) {
1015
- tool.onApprovalGranted(response, context, approvalRequest);
1016
- }
1017
- if (approvalRequest.type === ApprovalType.DIRECTORY_ACCESS) {
1018
- const metadata = approvalRequest.metadata;
1019
- const parentDir = typeof metadata?.parentDir === "string" ? metadata.parentDir : null;
1020
- const operation = typeof metadata?.operation === "string" ? metadata.operation : null;
1021
- if (parentDir && operation) {
1022
- const data = response.data;
1023
- const rememberDirectory = data?.rememberDirectory ?? false;
1024
- this.autoApprovePendingDirectoryAccessRequests({
1025
- parentDir,
1026
- operation,
1027
- sessionId,
1028
- toolName,
1029
- rememberDirectory
1030
- });
1031
- }
1032
- }
1238
+ async handleToolApproval(toolName, args, toolCallId, sessionId, callDescription) {
1239
+ if (this.isInAlwaysDenyList(toolName)) {
1033
1240
  this.logger.info(
1034
- `Custom approval granted for '${toolName}', type=${approvalRequest.type}, session=${sessionId ?? "global"}`
1241
+ `Tool '${toolName}' is in static deny list \u2013 blocking execution (session: ${sessionId ?? "global"})`
1035
1242
  );
1036
- return { handled: true };
1243
+ throw ToolError.executionDenied(toolName, sessionId);
1037
1244
  }
1038
- this.logger.info(
1039
- `Custom approval denied for '${toolName}', type=${approvalRequest.type}, reason=${response.reason ?? "unknown"}`
1245
+ const validatedArgs = this.validateLocalToolArgs(toolName, args);
1246
+ const presentationSnapshot = await this.getToolPresentationSnapshotForCall(
1247
+ toolName,
1248
+ validatedArgs,
1249
+ toolCallId,
1250
+ sessionId
1040
1251
  );
1041
- if (approvalRequest.type === "directory_access") {
1042
- const metadata = approvalRequest.metadata;
1043
- throw ToolError.directoryAccessDenied(
1044
- metadata?.parentDir ?? "unknown directory",
1045
- sessionId
1046
- );
1252
+ let directoryAccess;
1253
+ let directoryAccessApprovalRequest;
1254
+ if (!toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
1255
+ const getApprovalOverride = this.getToolApprovalOverrideFn(toolName);
1256
+ if (getApprovalOverride) {
1257
+ const context = this.buildToolExecutionContext({ sessionId, toolCallId });
1258
+ const approvalRequest = await getApprovalOverride(validatedArgs, context);
1259
+ if (approvalRequest) {
1260
+ if (approvalRequest.type === ApprovalType.DIRECTORY_ACCESS) {
1261
+ const metadata = approvalRequest.metadata;
1262
+ if (typeof metadata !== "object" || metadata === null || typeof metadata.path !== "string" || typeof metadata.parentDir !== "string" || typeof metadata.operation !== "string" || typeof metadata.toolName !== "string") {
1263
+ throw ToolError.configInvalid(
1264
+ `Tool '${toolName}' returned invalid directory access metadata`
1265
+ );
1266
+ }
1267
+ directoryAccess = metadata;
1268
+ directoryAccessApprovalRequest = approvalRequest;
1269
+ } else {
1270
+ this.logger.debug(
1271
+ `Tool '${toolName}' requested custom approval: type=${approvalRequest.type}`
1272
+ );
1273
+ if (sessionId && !approvalRequest.sessionId) {
1274
+ approvalRequest.sessionId = sessionId;
1275
+ }
1276
+ const response = await this.approvalManager.requestApproval(approvalRequest);
1277
+ if (response.status === ApprovalStatus.APPROVED) {
1278
+ const onGranted = this.getToolApprovalOnGrantedFn(toolName);
1279
+ if (onGranted) {
1280
+ await Promise.resolve(
1281
+ onGranted(response, context, approvalRequest)
1282
+ );
1283
+ }
1284
+ this.logger.info(
1285
+ `Custom approval granted for '${toolName}', type=${approvalRequest.type}, session=${sessionId ?? "global"}`
1286
+ );
1287
+ return {
1288
+ requireApproval: true,
1289
+ approvalStatus: "approved",
1290
+ args: validatedArgs,
1291
+ presentationSnapshot
1292
+ };
1293
+ }
1294
+ this.logger.info(
1295
+ `Custom approval denied for '${toolName}', type=${approvalRequest.type}, reason=${response.reason ?? "unknown"}`
1296
+ );
1297
+ throw ToolError.executionDenied(toolName, sessionId);
1298
+ }
1299
+ }
1300
+ }
1047
1301
  }
1048
- throw ToolError.executionDenied(toolName, sessionId);
1049
- }
1050
- /**
1051
- * Handle tool approval flow. Checks various precedence levels to determine
1052
- * if a tool should be auto-approved, denied, or requires manual approval.
1053
- */
1054
- async handleToolApproval(toolName, args, toolCallId, sessionId, callDescription) {
1055
- const validatedArgs = this.validateLocalToolArgsOrThrow(toolName, args);
1056
1302
  const quickResult = await this.tryQuickApprovalResolution(
1057
1303
  toolName,
1058
1304
  validatedArgs,
1059
- toolCallId,
1060
- sessionId
1305
+ sessionId,
1306
+ directoryAccess
1061
1307
  );
1062
1308
  if (quickResult !== null) {
1063
- return { ...quickResult, args: validatedArgs };
1309
+ return { ...quickResult, args: validatedArgs, presentationSnapshot };
1064
1310
  }
1065
1311
  const manualResult = await this.requestManualApproval(
1066
1312
  toolName,
1067
1313
  validatedArgs,
1068
1314
  toolCallId,
1069
1315
  sessionId,
1070
- callDescription
1316
+ directoryAccess,
1317
+ directoryAccessApprovalRequest,
1318
+ callDescription,
1319
+ presentationSnapshot
1071
1320
  );
1072
- return { ...manualResult, args: validatedArgs };
1321
+ return { ...manualResult, args: validatedArgs, presentationSnapshot };
1073
1322
  }
1074
1323
  /**
1075
1324
  * Try to resolve tool approval quickly based on policies and cached permissions.
1076
1325
  * Returns null if manual approval is needed.
1077
1326
  *
1078
1327
  * Precedence order (highest to lowest):
1079
- * 1. Static deny list (security - always blocks)
1080
- * 2. Custom approval override (tool-specific approval flows)
1081
- * 3. Session auto-approve (skill allowed-tools)
1082
- * 4. Static allow list
1083
- * 5. Dynamic "remembered" allowed list
1084
- * 6. Tool approval patterns
1085
- * 7. Approval mode (auto-approve/auto-deny)
1328
+ * 1. Directory access requirement (outside-root paths)
1329
+ * 2. Session auto-approve (skill allowed-tools)
1330
+ * 3. Static allow list
1331
+ * 4. Dynamic "remembered" allowed list
1332
+ * 5. Tool approval patterns
1333
+ * 6. Approval mode (auto-approve/auto-deny)
1086
1334
  */
1087
- async tryQuickApprovalResolution(toolName, args, toolCallId, sessionId) {
1088
- if (this.isInAlwaysDenyList(toolName)) {
1089
- this.logger.info(
1090
- `Tool '${toolName}' is in static deny list \u2013 blocking execution (session: ${sessionId ?? "global"})`
1091
- );
1092
- throw ToolError.executionDenied(toolName, sessionId);
1093
- }
1094
- const customApprovalResult = await this.checkCustomApprovalOverride(
1095
- toolName,
1096
- args,
1097
- toolCallId,
1098
- sessionId
1099
- );
1100
- if (customApprovalResult.handled) {
1101
- return { requireApproval: true, approvalStatus: "approved" };
1335
+ async tryQuickApprovalResolution(toolName, args, sessionId, directoryAccess) {
1336
+ if (directoryAccess) {
1337
+ if (this.approvalMode === "auto-approve") {
1338
+ this.approvalManager.addApprovedDirectory(directoryAccess.parentDir, "once");
1339
+ return { requireApproval: false };
1340
+ }
1341
+ return null;
1102
1342
  }
1103
1343
  if (sessionId && this.isToolAutoApprovedForSession(sessionId, toolName)) {
1104
1344
  this.logger.info(
@@ -1139,12 +1379,11 @@ let _ToolManager = class _ToolManager {
1139
1379
  * Request manual approval from the user for a tool execution.
1140
1380
  * Generates preview, sends approval request, and handles the response.
1141
1381
  */
1142
- async requestManualApproval(toolName, args, toolCallId, sessionId, callDescription) {
1382
+ async requestManualApproval(toolName, args, toolCallId, sessionId, directoryAccess, directoryAccessApprovalRequest, callDescription, presentationSnapshot) {
1143
1383
  this.logger.info(
1144
1384
  `Tool approval requested for ${toolName}, sessionId: ${sessionId ?? "global"}`
1145
1385
  );
1146
1386
  try {
1147
- const toolDisplayName = this.agentTools.get(toolName)?.displayName;
1148
1387
  const displayPreview = await this.generateToolPreview(
1149
1388
  toolName,
1150
1389
  args,
@@ -1154,14 +1393,24 @@ let _ToolManager = class _ToolManager {
1154
1393
  const suggestedPatterns = this.getToolSuggestedPatterns(toolName, args);
1155
1394
  const response = await this.approvalManager.requestToolApproval({
1156
1395
  toolName,
1157
- ...toolDisplayName !== void 0 && { toolDisplayName },
1396
+ ...presentationSnapshot !== void 0 && { presentationSnapshot },
1158
1397
  toolCallId,
1159
1398
  args,
1160
1399
  ...callDescription !== void 0 && { description: callDescription },
1161
1400
  ...sessionId !== void 0 && { sessionId },
1162
1401
  ...displayPreview !== void 0 && { displayPreview },
1402
+ ...directoryAccess !== void 0 && { directoryAccess },
1163
1403
  ...suggestedPatterns !== void 0 && { suggestedPatterns }
1164
1404
  });
1405
+ if (response.status === ApprovalStatus.APPROVED && directoryAccessApprovalRequest !== void 0) {
1406
+ const onGranted = this.getToolApprovalOnGrantedFn(toolName);
1407
+ if (onGranted) {
1408
+ const context = this.buildToolExecutionContext({ sessionId, toolCallId });
1409
+ await Promise.resolve(
1410
+ onGranted(response, context, directoryAccessApprovalRequest)
1411
+ );
1412
+ }
1413
+ }
1165
1414
  if (response.status === ApprovalStatus.APPROVED && response.data) {
1166
1415
  await this.handleRememberChoice(toolName, response, sessionId);
1167
1416
  }
@@ -1183,13 +1432,13 @@ let _ToolManager = class _ToolManager {
1183
1432
  * Generate a preview for the tool approval UI if the tool supports it.
1184
1433
  */
1185
1434
  async generateToolPreview(toolName, args, toolCallId, sessionId) {
1186
- const tool = this.agentTools.get(toolName);
1187
- if (!tool?.generatePreview) {
1435
+ const previewFn = this.getToolPreviewFn(toolName);
1436
+ if (!previewFn) {
1188
1437
  return void 0;
1189
1438
  }
1190
1439
  try {
1191
1440
  const context = this.buildToolExecutionContext({ sessionId, toolCallId });
1192
- const preview = await tool.generatePreview(args, context);
1441
+ const preview = await previewFn(args, context);
1193
1442
  this.logger.debug(`Generated preview for ${toolName}`);
1194
1443
  return preview ?? void 0;
1195
1444
  } catch (previewError) {
@@ -1204,13 +1453,14 @@ let _ToolManager = class _ToolManager {
1204
1453
  }
1205
1454
  }
1206
1455
  /**
1207
- * Handle "remember choice" or "remember pattern" when user approves a tool.
1456
+ * Handle "remember" actions when user approves a tool.
1208
1457
  */
1209
1458
  async handleRememberChoice(toolName, response, sessionId) {
1210
1459
  const data = response.data;
1211
1460
  if (!data) return;
1212
1461
  const rememberChoice = data.rememberChoice;
1213
1462
  const rememberPattern = data.rememberPattern;
1463
+ const rememberDirectory = data.rememberDirectory;
1214
1464
  if (rememberChoice) {
1215
1465
  const allowSessionId = sessionId ?? response.sessionId;
1216
1466
  await this.allowedToolsProvider.allowTool(toolName, allowSessionId);
@@ -1218,10 +1468,13 @@ let _ToolManager = class _ToolManager {
1218
1468
  `Tool '${toolName}' added to allowed tools for session '${allowSessionId ?? "global"}' (remember choice selected)`
1219
1469
  );
1220
1470
  this.autoApprovePendingToolRequests(toolName, allowSessionId);
1221
- } else if (rememberPattern && this.agentTools.get(toolName)?.getApprovalPatternKey) {
1471
+ } else if (rememberPattern && this.getToolApprovalPatternKeyFn(toolName)) {
1222
1472
  this.approvalManager.addPattern(toolName, rememberPattern);
1223
1473
  this.logger.info(`Pattern '${rememberPattern}' added for tool '${toolName}' approval`);
1224
1474
  this.autoApprovePendingPatternRequests(toolName, sessionId);
1475
+ } else if (rememberDirectory) {
1476
+ const allowSessionId = sessionId ?? response.sessionId;
1477
+ this.autoApprovePendingDirectoryRequests(toolName, allowSessionId);
1225
1478
  }
1226
1479
  }
1227
1480
  /**