@dexto/core 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/DextoAgent.cjs +25 -5
- package/dist/agent/DextoAgent.d.ts +12 -1
- package/dist/agent/DextoAgent.d.ts.map +1 -1
- package/dist/agent/DextoAgent.js +25 -5
- package/dist/agent/schemas.d.ts +18 -18
- package/dist/approval/manager.cjs +87 -27
- package/dist/approval/manager.d.ts +10 -1
- package/dist/approval/manager.d.ts.map +1 -1
- package/dist/approval/manager.js +87 -27
- package/dist/approval/schemas.cjs +22 -8
- package/dist/approval/schemas.d.ts +276 -102
- package/dist/approval/schemas.d.ts.map +1 -1
- package/dist/approval/schemas.js +22 -8
- package/dist/context/manager.cjs +2 -2
- package/dist/context/manager.d.ts +2 -1
- package/dist/context/manager.d.ts.map +1 -1
- package/dist/context/manager.js +2 -2
- package/dist/context/types.d.ts +3 -2
- package/dist/context/types.d.ts.map +1 -1
- package/dist/events/index.d.ts +17 -12
- package/dist/events/index.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/types.d.ts +1 -22
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/llm/executor/stream-processor.cjs +3 -3
- package/dist/llm/executor/stream-processor.d.ts +3 -2
- package/dist/llm/executor/stream-processor.d.ts.map +1 -1
- package/dist/llm/executor/stream-processor.js +3 -3
- package/dist/llm/executor/turn-executor.cjs +3 -3
- package/dist/llm/executor/turn-executor.d.ts +1 -1
- package/dist/llm/executor/turn-executor.d.ts.map +1 -1
- package/dist/llm/executor/turn-executor.js +3 -3
- package/dist/llm/providers/local/schemas.d.ts +2 -2
- package/dist/llm/schemas.d.ts +4 -4
- package/dist/llm/services/vercel.cjs +1 -1
- package/dist/llm/services/vercel.js +1 -1
- package/dist/logger/default-logger-factory.d.ts +12 -12
- package/dist/logger/v2/dexto-logger.cjs +35 -0
- package/dist/logger/v2/dexto-logger.d.ts +19 -0
- package/dist/logger/v2/dexto-logger.d.ts.map +1 -1
- package/dist/logger/v2/dexto-logger.js +35 -0
- package/dist/logger/v2/schemas.d.ts +6 -6
- package/dist/logger/v2/test-utils.cjs +2 -0
- package/dist/logger/v2/test-utils.d.ts.map +1 -1
- package/dist/logger/v2/test-utils.js +2 -0
- package/dist/logger/v2/types.d.ts +14 -1
- package/dist/logger/v2/types.d.ts.map +1 -1
- package/dist/mcp/schemas.d.ts +15 -15
- package/dist/memory/schemas.d.ts +4 -4
- package/dist/prompts/schemas.d.ts +7 -7
- package/dist/systemPrompt/in-built-prompts.cjs +5 -5
- package/dist/systemPrompt/in-built-prompts.d.ts +1 -1
- package/dist/systemPrompt/in-built-prompts.d.ts.map +1 -1
- package/dist/systemPrompt/in-built-prompts.js +5 -5
- package/dist/systemPrompt/schemas.d.ts +5 -5
- package/dist/systemPrompt/types.d.ts +11 -0
- package/dist/systemPrompt/types.d.ts.map +1 -1
- package/dist/tools/display-types.d.ts +10 -0
- package/dist/tools/display-types.d.ts.map +1 -1
- package/dist/tools/index.cjs +3 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/presentation.cjs +49 -0
- package/dist/tools/presentation.d.ts +11 -0
- package/dist/tools/presentation.d.ts.map +1 -0
- package/dist/tools/presentation.js +24 -0
- package/dist/tools/tool-manager.cjs +322 -155
- package/dist/tools/tool-manager.d.ts +23 -25
- package/dist/tools/tool-manager.d.ts.map +1 -1
- package/dist/tools/tool-manager.js +322 -155
- package/dist/tools/types.d.ts +134 -55
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/utils/path.cjs +10 -1
- package/dist/utils/path.d.ts +5 -2
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +10 -1
- package/package.json +2 -2
|
@@ -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;
|
|
@@ -384,16 +385,175 @@ let _ToolManager = class _ToolManager {
|
|
|
384
385
|
});
|
|
385
386
|
}
|
|
386
387
|
// ==================== Pattern Approval Helpers ====================
|
|
388
|
+
getToolApprovalPatternKeyFn(toolName) {
|
|
389
|
+
const tool = this.agentTools.get(toolName);
|
|
390
|
+
return tool?.approval?.patternKey;
|
|
391
|
+
}
|
|
392
|
+
getToolSuggestApprovalPatternsFn(toolName) {
|
|
393
|
+
const tool = this.agentTools.get(toolName);
|
|
394
|
+
return tool?.approval?.suggestPatterns;
|
|
395
|
+
}
|
|
396
|
+
getToolApprovalOverrideFn(toolName) {
|
|
397
|
+
const tool = this.agentTools.get(toolName);
|
|
398
|
+
return tool?.approval?.override;
|
|
399
|
+
}
|
|
400
|
+
getToolApprovalOnGrantedFn(toolName) {
|
|
401
|
+
const tool = this.agentTools.get(toolName);
|
|
402
|
+
return tool?.approval?.onGranted;
|
|
403
|
+
}
|
|
404
|
+
getToolPreviewFn(toolName) {
|
|
405
|
+
const tool = this.agentTools.get(toolName);
|
|
406
|
+
return tool?.presentation?.preview;
|
|
407
|
+
}
|
|
408
|
+
getToolDescribeHeaderFn(toolName) {
|
|
409
|
+
const tool = this.agentTools.get(toolName);
|
|
410
|
+
return tool?.presentation?.describeHeader;
|
|
411
|
+
}
|
|
412
|
+
getToolDescribeArgsFn(toolName) {
|
|
413
|
+
const tool = this.agentTools.get(toolName);
|
|
414
|
+
return tool?.presentation?.describeArgs;
|
|
415
|
+
}
|
|
416
|
+
getToolDescribeResultFn(toolName) {
|
|
417
|
+
const tool = this.agentTools.get(toolName);
|
|
418
|
+
return tool?.presentation?.describeResult;
|
|
419
|
+
}
|
|
420
|
+
buildGenericToolPresentationSnapshot(toolName) {
|
|
421
|
+
const toTitleCase = (name) => name.replace(/[_-]+/g, " ").split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
422
|
+
const isMcp = toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX);
|
|
423
|
+
const fallbackTitle = (() => {
|
|
424
|
+
if (!isMcp) {
|
|
425
|
+
return toTitleCase(toolName);
|
|
426
|
+
}
|
|
427
|
+
const actualToolName = toolName.substring(_ToolManager.MCP_TOOL_PREFIX.length);
|
|
428
|
+
const parts = actualToolName.split("--");
|
|
429
|
+
const toolPart = parts.length >= 2 ? parts.slice(1).join("--") : actualToolName;
|
|
430
|
+
return toTitleCase(toolPart);
|
|
431
|
+
})();
|
|
432
|
+
const snapshot = {
|
|
433
|
+
version: 1,
|
|
434
|
+
source: {
|
|
435
|
+
type: toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX) ? "mcp" : "local"
|
|
436
|
+
},
|
|
437
|
+
header: {
|
|
438
|
+
title: fallbackTitle
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
if (snapshot.source?.type === "mcp") {
|
|
442
|
+
const actualToolName = toolName.substring(_ToolManager.MCP_TOOL_PREFIX.length);
|
|
443
|
+
const parts = actualToolName.split("--");
|
|
444
|
+
if (parts.length >= 2 && parts[0]) {
|
|
445
|
+
snapshot.source.mcpServerName = parts[0];
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return snapshot;
|
|
449
|
+
}
|
|
450
|
+
getToolPresentationSnapshotForToolCallEvent(toolName, args, toolCallId, sessionId) {
|
|
451
|
+
const fallback = this.buildGenericToolPresentationSnapshot(toolName);
|
|
452
|
+
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
453
|
+
return fallback;
|
|
454
|
+
}
|
|
455
|
+
const describeHeader = this.getToolDescribeHeaderFn(toolName);
|
|
456
|
+
const describeArgs = this.getToolDescribeArgsFn(toolName);
|
|
457
|
+
if (!describeHeader && !describeArgs) {
|
|
458
|
+
return fallback;
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
const validatedArgs = this.validateLocalToolArgs(toolName, args);
|
|
462
|
+
const context = this.buildToolExecutionContext({ sessionId, toolCallId });
|
|
463
|
+
const isPromiseLike = (value) => {
|
|
464
|
+
if (typeof value !== "object" || value === null) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
return typeof value.then === "function";
|
|
468
|
+
};
|
|
469
|
+
let nextSnapshot = fallback;
|
|
470
|
+
if (describeHeader) {
|
|
471
|
+
const header = describeHeader(validatedArgs, context);
|
|
472
|
+
if (!isPromiseLike(header) && header) {
|
|
473
|
+
nextSnapshot = {
|
|
474
|
+
...nextSnapshot,
|
|
475
|
+
header: { ...nextSnapshot.header, ...header }
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (describeArgs) {
|
|
480
|
+
const argsPresentation = describeArgs(validatedArgs, context);
|
|
481
|
+
if (!isPromiseLike(argsPresentation) && argsPresentation) {
|
|
482
|
+
nextSnapshot = {
|
|
483
|
+
...nextSnapshot,
|
|
484
|
+
args: argsPresentation
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return nextSnapshot;
|
|
489
|
+
} catch (error) {
|
|
490
|
+
this.logger.debug(
|
|
491
|
+
`Tool presentation snapshot generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
|
|
492
|
+
);
|
|
493
|
+
return fallback;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
async getToolPresentationSnapshotForCall(toolName, args, toolCallId, sessionId) {
|
|
497
|
+
const fallback = this.buildGenericToolPresentationSnapshot(toolName);
|
|
498
|
+
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
499
|
+
return fallback;
|
|
500
|
+
}
|
|
501
|
+
const describeHeader = this.getToolDescribeHeaderFn(toolName);
|
|
502
|
+
const describeArgs = this.getToolDescribeArgsFn(toolName);
|
|
503
|
+
if (!describeHeader && !describeArgs) {
|
|
504
|
+
return fallback;
|
|
505
|
+
}
|
|
506
|
+
try {
|
|
507
|
+
const context = this.buildToolExecutionContext({ sessionId, toolCallId });
|
|
508
|
+
const describedHeader = describeHeader ? await Promise.resolve(describeHeader(args, context)) : null;
|
|
509
|
+
const describedArgs = describeArgs ? await Promise.resolve(describeArgs(args, context)) : null;
|
|
510
|
+
return {
|
|
511
|
+
...fallback,
|
|
512
|
+
...describedHeader ? { header: { ...fallback.header, ...describedHeader } } : {},
|
|
513
|
+
...describedArgs ? { args: describedArgs } : {}
|
|
514
|
+
};
|
|
515
|
+
} catch (error) {
|
|
516
|
+
this.logger.debug(
|
|
517
|
+
`Tool presentation snapshot generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
|
|
518
|
+
);
|
|
519
|
+
return fallback;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async augmentSnapshotWithResult(toolName, snapshot, result, args, toolCallId, sessionId) {
|
|
523
|
+
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
524
|
+
return snapshot;
|
|
525
|
+
}
|
|
526
|
+
const describeResult = this.getToolDescribeResultFn(toolName);
|
|
527
|
+
if (!describeResult) {
|
|
528
|
+
return snapshot;
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
const context = this.buildToolExecutionContext({ sessionId, toolCallId });
|
|
532
|
+
const resultPresentation = await Promise.resolve(describeResult(result, args, context));
|
|
533
|
+
if (!resultPresentation) {
|
|
534
|
+
return snapshot;
|
|
535
|
+
}
|
|
536
|
+
return {
|
|
537
|
+
...snapshot,
|
|
538
|
+
result: resultPresentation
|
|
539
|
+
};
|
|
540
|
+
} catch (error) {
|
|
541
|
+
this.logger.debug(
|
|
542
|
+
`Tool result presentation snapshot generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
|
|
543
|
+
);
|
|
544
|
+
return snapshot;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
387
547
|
getToolPatternKey(toolName, args) {
|
|
388
548
|
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
389
549
|
return null;
|
|
390
550
|
}
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
551
|
+
const getPatternKey = this.getToolApprovalPatternKeyFn(toolName);
|
|
552
|
+
if (!getPatternKey) {
|
|
393
553
|
return null;
|
|
394
554
|
}
|
|
395
555
|
try {
|
|
396
|
-
return
|
|
556
|
+
return getPatternKey(args);
|
|
397
557
|
} catch (error) {
|
|
398
558
|
this.logger.debug(
|
|
399
559
|
`Pattern key generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -405,12 +565,12 @@ let _ToolManager = class _ToolManager {
|
|
|
405
565
|
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
406
566
|
return void 0;
|
|
407
567
|
}
|
|
408
|
-
const
|
|
409
|
-
if (!
|
|
568
|
+
const suggestPatterns = this.getToolSuggestApprovalPatternsFn(toolName);
|
|
569
|
+
if (!suggestPatterns) {
|
|
410
570
|
return void 0;
|
|
411
571
|
}
|
|
412
572
|
try {
|
|
413
|
-
const patterns =
|
|
573
|
+
const patterns = suggestPatterns(args);
|
|
414
574
|
return patterns.length > 0 ? patterns : void 0;
|
|
415
575
|
} catch (error) {
|
|
416
576
|
this.logger.debug(
|
|
@@ -436,8 +596,7 @@ let _ToolManager = class _ToolManager {
|
|
|
436
596
|
if (request.sessionId !== sessionId) {
|
|
437
597
|
return false;
|
|
438
598
|
}
|
|
439
|
-
|
|
440
|
-
return metadata.toolName === toolName;
|
|
599
|
+
return request.metadata.toolName === toolName;
|
|
441
600
|
},
|
|
442
601
|
{ rememberChoice: false }
|
|
443
602
|
// Don't propagate remember choice to auto-approved requests
|
|
@@ -456,8 +615,7 @@ let _ToolManager = class _ToolManager {
|
|
|
456
615
|
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
457
616
|
return;
|
|
458
617
|
}
|
|
459
|
-
const
|
|
460
|
-
const getPatternKey = tool?.getApprovalPatternKey;
|
|
618
|
+
const getPatternKey = this.getToolApprovalPatternKeyFn(toolName);
|
|
461
619
|
if (!getPatternKey) {
|
|
462
620
|
return;
|
|
463
621
|
}
|
|
@@ -469,17 +627,17 @@ let _ToolManager = class _ToolManager {
|
|
|
469
627
|
if (request.sessionId !== sessionId) {
|
|
470
628
|
return false;
|
|
471
629
|
}
|
|
472
|
-
|
|
473
|
-
if (metadata.toolName !== toolName) {
|
|
630
|
+
if (request.metadata.toolName !== toolName) {
|
|
474
631
|
return false;
|
|
475
632
|
}
|
|
476
|
-
const args = metadata.args;
|
|
633
|
+
const args = request.metadata.args;
|
|
477
634
|
if (typeof args !== "object" || args === null) {
|
|
478
635
|
return false;
|
|
479
636
|
}
|
|
637
|
+
const argsRecord = args;
|
|
480
638
|
let patternKey;
|
|
481
639
|
try {
|
|
482
|
-
patternKey = getPatternKey(
|
|
640
|
+
patternKey = getPatternKey(argsRecord);
|
|
483
641
|
} catch (error) {
|
|
484
642
|
this.logger.debug(
|
|
485
643
|
`Pattern key generation failed for '${toolName}': ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -498,43 +656,38 @@ let _ToolManager = class _ToolManager {
|
|
|
498
656
|
);
|
|
499
657
|
}
|
|
500
658
|
}
|
|
501
|
-
/**
|
|
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.
|
|
505
|
-
*/
|
|
506
|
-
autoApprovePendingDirectoryAccessRequests(options) {
|
|
507
|
-
const count = this.approvalManager.autoApprovePendingRequests(
|
|
508
|
-
(request) => {
|
|
509
|
-
if (request.type !== ApprovalType.DIRECTORY_ACCESS) {
|
|
510
|
-
return false;
|
|
511
|
-
}
|
|
512
|
-
if (request.sessionId !== options.sessionId) {
|
|
513
|
-
return false;
|
|
514
|
-
}
|
|
515
|
-
const metadata = request.metadata;
|
|
516
|
-
if (typeof metadata?.parentDir !== "string" || metadata.parentDir !== options.parentDir) {
|
|
517
|
-
return false;
|
|
518
|
-
}
|
|
519
|
-
if (options.rememberDirectory) {
|
|
520
|
-
return true;
|
|
521
|
-
}
|
|
522
|
-
if (typeof metadata?.operation !== "string" || typeof metadata?.toolName !== "string") {
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
return metadata.operation === options.operation && metadata.toolName === options.toolName;
|
|
526
|
-
},
|
|
527
|
-
{ rememberDirectory: false }
|
|
528
|
-
);
|
|
529
|
-
if (count > 0) {
|
|
530
|
-
this.logger.info(
|
|
531
|
-
`Auto-approved ${count} parallel request(s) for directory '${options.parentDir}' after directory access was approved`
|
|
532
|
-
);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
659
|
getMcpManager() {
|
|
536
660
|
return this.mcpManager;
|
|
537
661
|
}
|
|
662
|
+
setContributorContextFactory(factory) {
|
|
663
|
+
this.contributorContextFactory = factory ?? void 0;
|
|
664
|
+
}
|
|
665
|
+
async buildContributorContext() {
|
|
666
|
+
const baseWorkspace = this.currentWorkspace ?? null;
|
|
667
|
+
const baseContext = {
|
|
668
|
+
mcpManager: this.mcpManager,
|
|
669
|
+
workspace: baseWorkspace
|
|
670
|
+
};
|
|
671
|
+
if (!this.contributorContextFactory) {
|
|
672
|
+
return baseContext;
|
|
673
|
+
}
|
|
674
|
+
try {
|
|
675
|
+
const overrides = await this.contributorContextFactory() ?? {};
|
|
676
|
+
const workspace = overrides.workspace !== void 0 ? overrides.workspace : baseWorkspace;
|
|
677
|
+
const environment = overrides.environment !== void 0 ? overrides.environment : baseContext.environment;
|
|
678
|
+
const mcpManager = overrides.mcpManager ?? baseContext.mcpManager;
|
|
679
|
+
return {
|
|
680
|
+
mcpManager,
|
|
681
|
+
workspace,
|
|
682
|
+
...environment !== void 0 ? { environment } : {}
|
|
683
|
+
};
|
|
684
|
+
} catch (error) {
|
|
685
|
+
this.logger.warn(
|
|
686
|
+
`Failed to build contributor context: ${error instanceof Error ? error.message : String(error)}`
|
|
687
|
+
);
|
|
688
|
+
return baseContext;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
538
691
|
/**
|
|
539
692
|
* Get all MCP tools (delegates to mcpManager.getAllTools())
|
|
540
693
|
* This provides access to MCP tools while maintaining separation of concerns
|
|
@@ -554,7 +707,7 @@ let _ToolManager = class _ToolManager {
|
|
|
554
707
|
};
|
|
555
708
|
return this.toolExecutionContextFactory(baseContext);
|
|
556
709
|
}
|
|
557
|
-
|
|
710
|
+
validateLocalToolArgs(toolName, args) {
|
|
558
711
|
if (toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
559
712
|
return args;
|
|
560
713
|
}
|
|
@@ -675,15 +828,22 @@ let _ToolManager = class _ToolManager {
|
|
|
675
828
|
async executeTool(toolName, args, toolCallId, sessionId, abortSignal) {
|
|
676
829
|
const { toolArgs: rawToolArgs, meta } = extractToolCallMeta(args);
|
|
677
830
|
let toolArgs = rawToolArgs;
|
|
831
|
+
const callDescription = typeof meta.callDescription === "string" ? meta.callDescription : typeof rawToolArgs.description === "string" ? rawToolArgs.description : void 0;
|
|
678
832
|
const backgroundTasksEnabled = isBackgroundTasksEnabled();
|
|
679
|
-
const toolDisplayName = this.agentTools.get(toolName)?.displayName;
|
|
680
833
|
this.logger.debug(`\u{1F527} Tool execution requested: '${toolName}' (toolCallId: ${toolCallId})`);
|
|
681
834
|
this.logger.debug(`Tool args: ${JSON.stringify(toolArgs, null, 2)}`);
|
|
682
835
|
if (sessionId) {
|
|
836
|
+
const presentationSnapshot = this.getToolPresentationSnapshotForToolCallEvent(
|
|
837
|
+
toolName,
|
|
838
|
+
toolArgs,
|
|
839
|
+
toolCallId,
|
|
840
|
+
sessionId
|
|
841
|
+
);
|
|
683
842
|
this.agentEventBus.emit("llm:tool-call", {
|
|
684
843
|
toolName,
|
|
685
|
-
|
|
844
|
+
presentationSnapshot,
|
|
686
845
|
args: toolArgs,
|
|
846
|
+
...callDescription !== void 0 && { callDescription },
|
|
687
847
|
callId: toolCallId,
|
|
688
848
|
sessionId
|
|
689
849
|
});
|
|
@@ -691,13 +851,14 @@ let _ToolManager = class _ToolManager {
|
|
|
691
851
|
const {
|
|
692
852
|
requireApproval,
|
|
693
853
|
approvalStatus,
|
|
694
|
-
args: validatedToolArgs
|
|
854
|
+
args: validatedToolArgs,
|
|
855
|
+
presentationSnapshot: callSnapshot
|
|
695
856
|
} = await this.handleToolApproval(
|
|
696
857
|
toolName,
|
|
697
858
|
toolArgs,
|
|
698
859
|
toolCallId,
|
|
699
860
|
sessionId,
|
|
700
|
-
|
|
861
|
+
callDescription
|
|
701
862
|
);
|
|
702
863
|
toolArgs = validatedToolArgs;
|
|
703
864
|
this.logger.debug(`\u2705 Tool execution approved: ${toolName}`);
|
|
@@ -731,7 +892,7 @@ let _ToolManager = class _ToolManager {
|
|
|
731
892
|
);
|
|
732
893
|
toolArgs = modifiedPayload.args;
|
|
733
894
|
try {
|
|
734
|
-
toolArgs = this.
|
|
895
|
+
toolArgs = this.validateLocalToolArgs(toolName, toolArgs);
|
|
735
896
|
} catch (error) {
|
|
736
897
|
this.logger.error(
|
|
737
898
|
`Post-hook validation failed for tool '${toolName}': a beforeToolCall hook may have set invalid args`
|
|
@@ -854,9 +1015,17 @@ let _ToolManager = class _ToolManager {
|
|
|
854
1015
|
);
|
|
855
1016
|
result = modifiedPayload.result;
|
|
856
1017
|
}
|
|
1018
|
+
const presentationSnapshot = await this.augmentSnapshotWithResult(
|
|
1019
|
+
toolName,
|
|
1020
|
+
callSnapshot,
|
|
1021
|
+
result,
|
|
1022
|
+
toolArgs,
|
|
1023
|
+
toolCallId,
|
|
1024
|
+
sessionId
|
|
1025
|
+
);
|
|
857
1026
|
return {
|
|
858
1027
|
result,
|
|
859
|
-
...
|
|
1028
|
+
...presentationSnapshot !== void 0 && { presentationSnapshot },
|
|
860
1029
|
...requireApproval && { requireApproval, approvalStatus }
|
|
861
1030
|
};
|
|
862
1031
|
} catch (error) {
|
|
@@ -981,124 +1150,113 @@ let _ToolManager = class _ToolManager {
|
|
|
981
1150
|
);
|
|
982
1151
|
}
|
|
983
1152
|
/**
|
|
984
|
-
*
|
|
985
|
-
*
|
|
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
|
|
1153
|
+
* Handle tool approval flow. Checks various precedence levels to determine
|
|
1154
|
+
* if a tool should be auto-approved, denied, or requires manual approval.
|
|
992
1155
|
*/
|
|
993
|
-
async
|
|
994
|
-
if (
|
|
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
|
-
}
|
|
1156
|
+
async handleToolApproval(toolName, args, toolCallId, sessionId, callDescription) {
|
|
1157
|
+
if (this.isInAlwaysDenyList(toolName)) {
|
|
1033
1158
|
this.logger.info(
|
|
1034
|
-
`
|
|
1159
|
+
`Tool '${toolName}' is in static deny list \u2013 blocking execution (session: ${sessionId ?? "global"})`
|
|
1035
1160
|
);
|
|
1036
|
-
|
|
1161
|
+
throw ToolError.executionDenied(toolName, sessionId);
|
|
1037
1162
|
}
|
|
1038
|
-
this.
|
|
1039
|
-
|
|
1163
|
+
const validatedArgs = this.validateLocalToolArgs(toolName, args);
|
|
1164
|
+
const presentationSnapshot = await this.getToolPresentationSnapshotForCall(
|
|
1165
|
+
toolName,
|
|
1166
|
+
validatedArgs,
|
|
1167
|
+
toolCallId,
|
|
1168
|
+
sessionId
|
|
1040
1169
|
);
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1170
|
+
let directoryAccess;
|
|
1171
|
+
let directoryAccessApprovalRequest;
|
|
1172
|
+
if (!toolName.startsWith(_ToolManager.MCP_TOOL_PREFIX)) {
|
|
1173
|
+
const getApprovalOverride = this.getToolApprovalOverrideFn(toolName);
|
|
1174
|
+
if (getApprovalOverride) {
|
|
1175
|
+
const context = this.buildToolExecutionContext({ sessionId, toolCallId });
|
|
1176
|
+
const approvalRequest = await getApprovalOverride(validatedArgs, context);
|
|
1177
|
+
if (approvalRequest) {
|
|
1178
|
+
if (approvalRequest.type === ApprovalType.DIRECTORY_ACCESS) {
|
|
1179
|
+
const metadata = approvalRequest.metadata;
|
|
1180
|
+
if (typeof metadata !== "object" || metadata === null || typeof metadata.path !== "string" || typeof metadata.parentDir !== "string" || typeof metadata.operation !== "string" || typeof metadata.toolName !== "string") {
|
|
1181
|
+
throw ToolError.configInvalid(
|
|
1182
|
+
`Tool '${toolName}' returned invalid directory access metadata`
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
directoryAccess = metadata;
|
|
1186
|
+
directoryAccessApprovalRequest = approvalRequest;
|
|
1187
|
+
} else {
|
|
1188
|
+
this.logger.debug(
|
|
1189
|
+
`Tool '${toolName}' requested custom approval: type=${approvalRequest.type}`
|
|
1190
|
+
);
|
|
1191
|
+
if (sessionId && !approvalRequest.sessionId) {
|
|
1192
|
+
approvalRequest.sessionId = sessionId;
|
|
1193
|
+
}
|
|
1194
|
+
const response = await this.approvalManager.requestApproval(approvalRequest);
|
|
1195
|
+
if (response.status === ApprovalStatus.APPROVED) {
|
|
1196
|
+
const onGranted = this.getToolApprovalOnGrantedFn(toolName);
|
|
1197
|
+
if (onGranted) {
|
|
1198
|
+
await Promise.resolve(
|
|
1199
|
+
onGranted(response, context, approvalRequest)
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
this.logger.info(
|
|
1203
|
+
`Custom approval granted for '${toolName}', type=${approvalRequest.type}, session=${sessionId ?? "global"}`
|
|
1204
|
+
);
|
|
1205
|
+
return {
|
|
1206
|
+
requireApproval: true,
|
|
1207
|
+
approvalStatus: "approved",
|
|
1208
|
+
args: validatedArgs,
|
|
1209
|
+
presentationSnapshot
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
this.logger.info(
|
|
1213
|
+
`Custom approval denied for '${toolName}', type=${approvalRequest.type}, reason=${response.reason ?? "unknown"}`
|
|
1214
|
+
);
|
|
1215
|
+
throw ToolError.executionDenied(toolName, sessionId);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1047
1219
|
}
|
|
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
1220
|
const quickResult = await this.tryQuickApprovalResolution(
|
|
1057
1221
|
toolName,
|
|
1058
1222
|
validatedArgs,
|
|
1059
|
-
|
|
1060
|
-
|
|
1223
|
+
sessionId,
|
|
1224
|
+
directoryAccess
|
|
1061
1225
|
);
|
|
1062
1226
|
if (quickResult !== null) {
|
|
1063
|
-
return { ...quickResult, args: validatedArgs };
|
|
1227
|
+
return { ...quickResult, args: validatedArgs, presentationSnapshot };
|
|
1064
1228
|
}
|
|
1065
1229
|
const manualResult = await this.requestManualApproval(
|
|
1066
1230
|
toolName,
|
|
1067
1231
|
validatedArgs,
|
|
1068
1232
|
toolCallId,
|
|
1069
1233
|
sessionId,
|
|
1070
|
-
|
|
1234
|
+
directoryAccess,
|
|
1235
|
+
directoryAccessApprovalRequest,
|
|
1236
|
+
callDescription,
|
|
1237
|
+
presentationSnapshot
|
|
1071
1238
|
);
|
|
1072
|
-
return { ...manualResult, args: validatedArgs };
|
|
1239
|
+
return { ...manualResult, args: validatedArgs, presentationSnapshot };
|
|
1073
1240
|
}
|
|
1074
1241
|
/**
|
|
1075
1242
|
* Try to resolve tool approval quickly based on policies and cached permissions.
|
|
1076
1243
|
* Returns null if manual approval is needed.
|
|
1077
1244
|
*
|
|
1078
1245
|
* Precedence order (highest to lowest):
|
|
1079
|
-
* 1.
|
|
1080
|
-
* 2.
|
|
1081
|
-
* 3.
|
|
1082
|
-
* 4.
|
|
1083
|
-
* 5.
|
|
1084
|
-
* 6.
|
|
1085
|
-
* 7. Approval mode (auto-approve/auto-deny)
|
|
1246
|
+
* 1. Directory access requirement (outside-root paths)
|
|
1247
|
+
* 2. Session auto-approve (skill allowed-tools)
|
|
1248
|
+
* 3. Static allow list
|
|
1249
|
+
* 4. Dynamic "remembered" allowed list
|
|
1250
|
+
* 5. Tool approval patterns
|
|
1251
|
+
* 6. Approval mode (auto-approve/auto-deny)
|
|
1086
1252
|
*/
|
|
1087
|
-
async tryQuickApprovalResolution(toolName, args,
|
|
1088
|
-
if (
|
|
1089
|
-
this.
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
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" };
|
|
1253
|
+
async tryQuickApprovalResolution(toolName, args, sessionId, directoryAccess) {
|
|
1254
|
+
if (directoryAccess) {
|
|
1255
|
+
if (this.approvalMode === "auto-approve") {
|
|
1256
|
+
this.approvalManager.addApprovedDirectory(directoryAccess.parentDir, "once");
|
|
1257
|
+
return { requireApproval: false };
|
|
1258
|
+
}
|
|
1259
|
+
return null;
|
|
1102
1260
|
}
|
|
1103
1261
|
if (sessionId && this.isToolAutoApprovedForSession(sessionId, toolName)) {
|
|
1104
1262
|
this.logger.info(
|
|
@@ -1139,12 +1297,11 @@ let _ToolManager = class _ToolManager {
|
|
|
1139
1297
|
* Request manual approval from the user for a tool execution.
|
|
1140
1298
|
* Generates preview, sends approval request, and handles the response.
|
|
1141
1299
|
*/
|
|
1142
|
-
async requestManualApproval(toolName, args, toolCallId, sessionId, callDescription) {
|
|
1300
|
+
async requestManualApproval(toolName, args, toolCallId, sessionId, directoryAccess, directoryAccessApprovalRequest, callDescription, presentationSnapshot) {
|
|
1143
1301
|
this.logger.info(
|
|
1144
1302
|
`Tool approval requested for ${toolName}, sessionId: ${sessionId ?? "global"}`
|
|
1145
1303
|
);
|
|
1146
1304
|
try {
|
|
1147
|
-
const toolDisplayName = this.agentTools.get(toolName)?.displayName;
|
|
1148
1305
|
const displayPreview = await this.generateToolPreview(
|
|
1149
1306
|
toolName,
|
|
1150
1307
|
args,
|
|
@@ -1154,14 +1311,24 @@ let _ToolManager = class _ToolManager {
|
|
|
1154
1311
|
const suggestedPatterns = this.getToolSuggestedPatterns(toolName, args);
|
|
1155
1312
|
const response = await this.approvalManager.requestToolApproval({
|
|
1156
1313
|
toolName,
|
|
1157
|
-
...
|
|
1314
|
+
...presentationSnapshot !== void 0 && { presentationSnapshot },
|
|
1158
1315
|
toolCallId,
|
|
1159
1316
|
args,
|
|
1160
1317
|
...callDescription !== void 0 && { description: callDescription },
|
|
1161
1318
|
...sessionId !== void 0 && { sessionId },
|
|
1162
1319
|
...displayPreview !== void 0 && { displayPreview },
|
|
1320
|
+
...directoryAccess !== void 0 && { directoryAccess },
|
|
1163
1321
|
...suggestedPatterns !== void 0 && { suggestedPatterns }
|
|
1164
1322
|
});
|
|
1323
|
+
if (response.status === ApprovalStatus.APPROVED && directoryAccessApprovalRequest !== void 0) {
|
|
1324
|
+
const onGranted = this.getToolApprovalOnGrantedFn(toolName);
|
|
1325
|
+
if (onGranted) {
|
|
1326
|
+
const context = this.buildToolExecutionContext({ sessionId, toolCallId });
|
|
1327
|
+
await Promise.resolve(
|
|
1328
|
+
onGranted(response, context, directoryAccessApprovalRequest)
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1165
1332
|
if (response.status === ApprovalStatus.APPROVED && response.data) {
|
|
1166
1333
|
await this.handleRememberChoice(toolName, response, sessionId);
|
|
1167
1334
|
}
|
|
@@ -1183,13 +1350,13 @@ let _ToolManager = class _ToolManager {
|
|
|
1183
1350
|
* Generate a preview for the tool approval UI if the tool supports it.
|
|
1184
1351
|
*/
|
|
1185
1352
|
async generateToolPreview(toolName, args, toolCallId, sessionId) {
|
|
1186
|
-
const
|
|
1187
|
-
if (!
|
|
1353
|
+
const previewFn = this.getToolPreviewFn(toolName);
|
|
1354
|
+
if (!previewFn) {
|
|
1188
1355
|
return void 0;
|
|
1189
1356
|
}
|
|
1190
1357
|
try {
|
|
1191
1358
|
const context = this.buildToolExecutionContext({ sessionId, toolCallId });
|
|
1192
|
-
const preview = await
|
|
1359
|
+
const preview = await previewFn(args, context);
|
|
1193
1360
|
this.logger.debug(`Generated preview for ${toolName}`);
|
|
1194
1361
|
return preview ?? void 0;
|
|
1195
1362
|
} catch (previewError) {
|
|
@@ -1218,7 +1385,7 @@ let _ToolManager = class _ToolManager {
|
|
|
1218
1385
|
`Tool '${toolName}' added to allowed tools for session '${allowSessionId ?? "global"}' (remember choice selected)`
|
|
1219
1386
|
);
|
|
1220
1387
|
this.autoApprovePendingToolRequests(toolName, allowSessionId);
|
|
1221
|
-
} else if (rememberPattern && this.
|
|
1388
|
+
} else if (rememberPattern && this.getToolApprovalPatternKeyFn(toolName)) {
|
|
1222
1389
|
this.approvalManager.addPattern(toolName, rememberPattern);
|
|
1223
1390
|
this.logger.info(`Pattern '${rememberPattern}' added for tool '${toolName}' approval`);
|
|
1224
1391
|
this.autoApprovePendingPatternRequests(toolName, sessionId);
|