@librechat/agents 3.6.10 → 3.6.11
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/cjs/agents/AgentContext.cjs +63 -10
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +4 -3
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/main.cjs +2 -0
- package/dist/cjs/stream.cjs +1 -0
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/CallerCapabilities.cjs +31 -0
- package/dist/cjs/tools/CallerCapabilities.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +23 -6
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +26 -2
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +65 -12
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +4 -3
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/stream.mjs +1 -0
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/CallerCapabilities.mjs +29 -1
- package/dist/esm/tools/CallerCapabilities.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +24 -7
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +26 -4
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +11 -0
- package/dist/types/tools/CallerCapabilities.d.ts +13 -0
- package/dist/types/tools/ToolNode.d.ts +9 -1
- package/dist/types/tools/local/resolveLocalExecutionTools.d.ts +6 -0
- package/dist/types/types/tools.d.ts +17 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +157 -15
- package/src/graphs/Graph.ts +6 -3
- package/src/stream.ts +6 -0
- package/src/tools/CallerCapabilities.ts +68 -0
- package/src/tools/ToolNode.ts +47 -4
- package/src/tools/local/resolveLocalExecutionTools.ts +77 -3
- package/src/types/tools.ts +18 -0
|
@@ -34,12 +34,18 @@ import {
|
|
|
34
34
|
} from '@/common';
|
|
35
35
|
import {
|
|
36
36
|
isProgrammaticRunnerAutoBound,
|
|
37
|
+
isProgrammaticRunnerResolvedDirectly,
|
|
38
|
+
resolveLocalImplementationNames,
|
|
37
39
|
resolveLocalToolRegistry,
|
|
38
40
|
} from '@/tools/local/resolveLocalExecutionTools';
|
|
39
41
|
import {
|
|
42
|
+
type CallerCapabilityProjection,
|
|
40
43
|
allowsToolCaller,
|
|
44
|
+
applyCallerCapabilityDefinitionOverrides,
|
|
45
|
+
createCallerCapabilityProjectionSnapshot,
|
|
41
46
|
isToolDefinitionActive,
|
|
42
47
|
isProgrammaticControlTool,
|
|
48
|
+
mergeCallerCapabilityDefinitions,
|
|
43
49
|
resolveCallerCapabilityProjection,
|
|
44
50
|
} from '@/tools/CallerCapabilities';
|
|
45
51
|
import { createSchemaOnlyTools } from '@/tools/schema';
|
|
@@ -59,6 +65,12 @@ type AgentSystemContentBlock =
|
|
|
59
65
|
|
|
60
66
|
type PromptCacheProvider = Providers.ANTHROPIC | Providers.OPENROUTER;
|
|
61
67
|
|
|
68
|
+
type ProgrammaticToolInstructionTarget = {
|
|
69
|
+
name: string;
|
|
70
|
+
codeGuidance: string;
|
|
71
|
+
executesDirectly: boolean;
|
|
72
|
+
};
|
|
73
|
+
|
|
62
74
|
/**
|
|
63
75
|
* Encapsulates agent-specific state that can vary between agents in a multi-agent system
|
|
64
76
|
*/
|
|
@@ -483,12 +495,53 @@ export class AgentContext {
|
|
|
483
495
|
|
|
484
496
|
/** Builds the caller boundary and schemas for programmatic-only tools. */
|
|
485
497
|
private buildProgrammaticOnlyToolsInstructions(): string {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
(toolDef) => isToolDefinitionActive(toolDef, this.discoveredToolNames)
|
|
498
|
+
const programmaticTools = this.getProgrammaticToolInstructionTargets();
|
|
499
|
+
if (programmaticTools.length === 0) return '';
|
|
500
|
+
const directProgrammaticTools = programmaticTools.filter(
|
|
501
|
+
(tool) => tool.executesDirectly
|
|
491
502
|
);
|
|
503
|
+
const eventProgrammaticTools = programmaticTools.filter(
|
|
504
|
+
(tool) => !tool.executesDirectly
|
|
505
|
+
);
|
|
506
|
+
const groups: Array<{
|
|
507
|
+
tools: ProgrammaticToolInstructionTarget[];
|
|
508
|
+
capabilities: CallerCapabilityProjection;
|
|
509
|
+
label: string;
|
|
510
|
+
}> = [];
|
|
511
|
+
if (directProgrammaticTools.length > 0) {
|
|
512
|
+
groups.push({
|
|
513
|
+
tools: directProgrammaticTools,
|
|
514
|
+
capabilities: this.getDirectProgrammaticCapabilityProjection(),
|
|
515
|
+
label: 'Direct programmatic runners',
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
if (eventProgrammaticTools.length > 0) {
|
|
519
|
+
groups.push({
|
|
520
|
+
tools: eventProgrammaticTools,
|
|
521
|
+
capabilities: this.getCallerCapabilityProjection(),
|
|
522
|
+
label: 'Event-dispatched programmatic runners',
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
if (groups.length === 0) {
|
|
526
|
+
return '';
|
|
527
|
+
}
|
|
528
|
+
const showGroupLabels = groups.length > 1;
|
|
529
|
+
return (
|
|
530
|
+
'\n\n## Programmatic Tool Calling' +
|
|
531
|
+
groups
|
|
532
|
+
.map(
|
|
533
|
+
({ tools, capabilities, label }) =>
|
|
534
|
+
(showGroupLabels ? `\n\n### ${label}` : '') +
|
|
535
|
+
this.buildProgrammaticToolGroupInstructions(tools, capabilities)
|
|
536
|
+
)
|
|
537
|
+
.join('')
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
private buildProgrammaticToolGroupInstructions(
|
|
542
|
+
programmaticTools: ProgrammaticToolInstructionTarget[],
|
|
543
|
+
capabilities: CallerCapabilityProjection
|
|
544
|
+
): string {
|
|
492
545
|
const programmaticOnlyTools = capabilities.codeExecutionOnlyTools;
|
|
493
546
|
const programmaticToolNames = capabilities.codeExecutionTools.map(
|
|
494
547
|
(toolDef) => toolDef.name
|
|
@@ -497,8 +550,6 @@ export class AgentContext {
|
|
|
497
550
|
.map((toolDef) => toolDef.name)
|
|
498
551
|
.filter((name) => !isProgrammaticControlTool(name));
|
|
499
552
|
|
|
500
|
-
const programmaticTools = this.getProgrammaticToolInstructionTargets();
|
|
501
|
-
if (programmaticTools.length === 0) return '';
|
|
502
553
|
const programmaticRunnerNames = programmaticTools
|
|
503
554
|
.map((tool) => `\`${tool.name}\``)
|
|
504
555
|
.join(' or ');
|
|
@@ -513,7 +564,7 @@ export class AgentContext {
|
|
|
513
564
|
.join(', ')}. Every ${programmaticRunnerNames} call must include a \`tool_manifest\` containing the exact registered names used by its code; the manifest is validated before execution starts.`
|
|
514
565
|
: '';
|
|
515
566
|
const boundary =
|
|
516
|
-
'\n\n
|
|
567
|
+
'\n\n' +
|
|
517
568
|
`Only these tools may be invoked inside ${programmaticRunnerNames}: ${quotedProgrammaticNames}.` +
|
|
518
569
|
directOnlyBoundary;
|
|
519
570
|
|
|
@@ -548,11 +599,8 @@ export class AgentContext {
|
|
|
548
599
|
);
|
|
549
600
|
}
|
|
550
601
|
|
|
551
|
-
private getProgrammaticToolInstructionTargets():
|
|
552
|
-
|
|
553
|
-
codeGuidance: string;
|
|
554
|
-
}> {
|
|
555
|
-
const targets: Array<{ name: string; codeGuidance: string }> = [];
|
|
602
|
+
private getProgrammaticToolInstructionTargets(): ProgrammaticToolInstructionTarget[] {
|
|
603
|
+
const targets: ProgrammaticToolInstructionTarget[] = [];
|
|
556
604
|
if (
|
|
557
605
|
this.hasBoundTool(Constants.BASH_PROGRAMMATIC_TOOL_CALLING) ||
|
|
558
606
|
isProgrammaticRunnerAutoBound(
|
|
@@ -563,6 +611,9 @@ export class AgentContext {
|
|
|
563
611
|
targets.push({
|
|
564
612
|
name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
|
|
565
613
|
codeGuidance: 'Bash code',
|
|
614
|
+
executesDirectly: this.isProgrammaticRunnerDirectlyBound(
|
|
615
|
+
Constants.BASH_PROGRAMMATIC_TOOL_CALLING
|
|
616
|
+
),
|
|
566
617
|
});
|
|
567
618
|
}
|
|
568
619
|
|
|
@@ -581,12 +632,73 @@ export class AgentContext {
|
|
|
581
632
|
codeGuidance: localDefault
|
|
582
633
|
? 'Bash code by default, or set `lang: "py"` to use Python code'
|
|
583
634
|
: 'Python code',
|
|
635
|
+
executesDirectly: this.isProgrammaticRunnerDirectlyBound(
|
|
636
|
+
Constants.PROGRAMMATIC_TOOL_CALLING
|
|
637
|
+
),
|
|
584
638
|
});
|
|
585
639
|
}
|
|
586
640
|
|
|
587
641
|
return targets;
|
|
588
642
|
}
|
|
589
643
|
|
|
644
|
+
/** Whether ToolNode executes this runner in-process instead of via an event. */
|
|
645
|
+
private isProgrammaticRunnerDirectlyBound(name: string): boolean {
|
|
646
|
+
return (
|
|
647
|
+
isProgrammaticRunnerResolvedDirectly(
|
|
648
|
+
name,
|
|
649
|
+
this.toolExecution,
|
|
650
|
+
this.toolDefinitions?.some((toolDef) => toolDef.name === name) === true
|
|
651
|
+
) ||
|
|
652
|
+
this.graphTools?.some(
|
|
653
|
+
(tool) => 'name' in tool && tool.name === name
|
|
654
|
+
) === true
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** Mirrors ToolNode's executable implementation gate for direct runners. */
|
|
659
|
+
private getDirectProgrammaticCapabilityProjection(): CallerCapabilityProjection {
|
|
660
|
+
const implementationNames = new Set<string>();
|
|
661
|
+
const isEventDriven = (this.toolDefinitions?.length ?? 0) > 0;
|
|
662
|
+
const resolverInputNames = new Set<string>();
|
|
663
|
+
if (isEventDriven) {
|
|
664
|
+
for (const toolDef of this.toolDefinitions ?? []) {
|
|
665
|
+
resolverInputNames.add(toolDef.name);
|
|
666
|
+
}
|
|
667
|
+
} else {
|
|
668
|
+
for (const tool of (this.tools as t.GenericTool[] | undefined) ?? []) {
|
|
669
|
+
if ('name' in tool && typeof tool.name === 'string') {
|
|
670
|
+
implementationNames.add(tool.name);
|
|
671
|
+
resolverInputNames.add(tool.name);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
for (const tool of (this.graphTools as t.GenericTool[] | undefined) ?? []) {
|
|
676
|
+
if ('name' in tool && typeof tool.name === 'string') {
|
|
677
|
+
implementationNames.add(tool.name);
|
|
678
|
+
resolverInputNames.add(tool.name);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
for (const name of resolveLocalImplementationNames(
|
|
682
|
+
resolverInputNames,
|
|
683
|
+
this.toolExecution
|
|
684
|
+
)) {
|
|
685
|
+
implementationNames.add(name);
|
|
686
|
+
}
|
|
687
|
+
const activeCapabilities = this.getCallerCapabilityProjection();
|
|
688
|
+
const executableCapabilities = resolveCallerCapabilityProjection(
|
|
689
|
+
this.toolRegistry?.values() ?? [],
|
|
690
|
+
(toolDef) =>
|
|
691
|
+
implementationNames.has(toolDef.name) &&
|
|
692
|
+
isToolDefinitionActive(toolDef, this.discoveredToolNames)
|
|
693
|
+
);
|
|
694
|
+
return {
|
|
695
|
+
directTools: activeCapabilities.directTools,
|
|
696
|
+
directOnlyTools: activeCapabilities.directOnlyTools,
|
|
697
|
+
codeExecutionTools: executableCapabilities.codeExecutionTools,
|
|
698
|
+
codeExecutionOnlyTools: executableCapabilities.codeExecutionOnlyTools,
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
590
702
|
private hasBoundTool(name: string): boolean {
|
|
591
703
|
return (
|
|
592
704
|
this.getToolsForBinding()?.some(
|
|
@@ -1123,9 +1235,21 @@ export class AgentContext {
|
|
|
1123
1235
|
this.indexTokenCountMap = { ...baseTokenMap };
|
|
1124
1236
|
}
|
|
1125
1237
|
|
|
1238
|
+
/** Event definitions with matching runtime caller/defer metadata applied. */
|
|
1239
|
+
getEffectiveToolDefinitions(): t.LCTool[] | undefined {
|
|
1240
|
+
if (!this.toolDefinitions) {
|
|
1241
|
+
return undefined;
|
|
1242
|
+
}
|
|
1243
|
+
return applyCallerCapabilityDefinitionOverrides(
|
|
1244
|
+
this.toolDefinitions,
|
|
1245
|
+
this.toolRegistry?.values()
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1126
1249
|
/** Active tool definitions for token accounting (excludes deferred-and-undiscovered entries). */
|
|
1127
1250
|
private getActiveToolDefinitions(): t.LCTool[] {
|
|
1128
|
-
|
|
1251
|
+
const effectiveToolDefinitions = this.getEffectiveToolDefinitions();
|
|
1252
|
+
if (!effectiveToolDefinitions) {
|
|
1129
1253
|
return [];
|
|
1130
1254
|
}
|
|
1131
1255
|
/**
|
|
@@ -1136,7 +1260,7 @@ export class AgentContext {
|
|
|
1136
1260
|
* `toolSchemaTokens` even though they were never bound.
|
|
1137
1261
|
*/
|
|
1138
1262
|
return resolveCallerCapabilityProjection(
|
|
1139
|
-
|
|
1263
|
+
effectiveToolDefinitions,
|
|
1140
1264
|
(toolDef) => isToolDefinitionActive(toolDef, this.discoveredToolNames)
|
|
1141
1265
|
).directTools;
|
|
1142
1266
|
}
|
|
@@ -1767,6 +1891,24 @@ export class AgentContext {
|
|
|
1767
1891
|
return Array.from(this.discoveredToolNames);
|
|
1768
1892
|
}
|
|
1769
1893
|
|
|
1894
|
+
/** Returns the live projection shared by prompt and event execution. */
|
|
1895
|
+
private getCallerCapabilityProjection(): CallerCapabilityProjection {
|
|
1896
|
+
return resolveCallerCapabilityProjection(
|
|
1897
|
+
mergeCallerCapabilityDefinitions(
|
|
1898
|
+
this.toolDefinitions,
|
|
1899
|
+
this.toolRegistry?.values()
|
|
1900
|
+
),
|
|
1901
|
+
(toolDef) => isToolDefinitionActive(toolDef, this.discoveredToolNames)
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
/** Returns the SDK-owned active caller projection for event-driven hosts. */
|
|
1906
|
+
getCallerCapabilityProjectionSnapshot(): t.CallerCapabilityProjectionSnapshot {
|
|
1907
|
+
return createCallerCapabilityProjectionSnapshot(
|
|
1908
|
+
this.getCallerCapabilityProjection()
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1770
1912
|
/**
|
|
1771
1913
|
* Marks tools as discovered via tool search.
|
|
1772
1914
|
* Discovered tools will be included in the next model binding.
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -2868,6 +2868,9 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2868
2868
|
* the breakpoint and don't invalidate the prefix.
|
|
2869
2869
|
*/
|
|
2870
2870
|
let toolsForBinding = rawToolsForBinding;
|
|
2871
|
+
const isDeferredTool = makeIsDeferred(
|
|
2872
|
+
agentContext.getEffectiveToolDefinitions()
|
|
2873
|
+
);
|
|
2871
2874
|
if (
|
|
2872
2875
|
agentContext.provider === Providers.ANTHROPIC &&
|
|
2873
2876
|
(agentContext.clientOptions as t.AnthropicClientOptions | undefined)
|
|
@@ -2876,7 +2879,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2876
2879
|
toolsForBinding =
|
|
2877
2880
|
partitionAndMarkAnthropicToolCache(
|
|
2878
2881
|
rawToolsForBinding,
|
|
2879
|
-
|
|
2882
|
+
isDeferredTool,
|
|
2880
2883
|
resolvePromptCacheTtl(
|
|
2881
2884
|
(
|
|
2882
2885
|
agentContext.clientOptions as
|
|
@@ -2896,7 +2899,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2896
2899
|
toolsForBinding =
|
|
2897
2900
|
partitionAndMarkOpenRouterToolCache(
|
|
2898
2901
|
rawToolsForBinding,
|
|
2899
|
-
|
|
2902
|
+
isDeferredTool,
|
|
2900
2903
|
resolvePromptCacheTtl(
|
|
2901
2904
|
(
|
|
2902
2905
|
agentContext.clientOptions as
|
|
@@ -2923,7 +2926,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2923
2926
|
toolsForBinding =
|
|
2924
2927
|
partitionAndMarkBedrockToolCache(
|
|
2925
2928
|
rawToolsForBinding,
|
|
2926
|
-
|
|
2929
|
+
isDeferredTool
|
|
2927
2930
|
) ?? rawToolsForBinding;
|
|
2928
2931
|
}
|
|
2929
2932
|
}
|
package/src/stream.ts
CHANGED
|
@@ -820,6 +820,12 @@ function startEagerToolExecutions(args: {
|
|
|
820
820
|
toolCalls: entries.map((entry) => entry.request),
|
|
821
821
|
userId: graph.config?.configurable?.user_id as string | undefined,
|
|
822
822
|
agentId: agentContext?.agentId,
|
|
823
|
+
callerCapabilityProjection:
|
|
824
|
+
(
|
|
825
|
+
agentContext as
|
|
826
|
+
| Partial<Pick<AgentContext, 'getCallerCapabilityProjectionSnapshot'>>
|
|
827
|
+
| undefined
|
|
828
|
+
)?.getCallerCapabilityProjectionSnapshot?.(),
|
|
823
829
|
configurable: graph.config?.configurable as
|
|
824
830
|
| Record<string, unknown>
|
|
825
831
|
| undefined,
|
|
@@ -14,6 +14,74 @@ export type CallerCapabilityProjection = {
|
|
|
14
14
|
codeExecutionOnlyTools: t.LCTool[];
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Combines event schemas with runtime capability metadata. Matching runtime
|
|
19
|
+
* entries override caller/defer policy without replacing the event schema;
|
|
20
|
+
* runtime-only definitions are appended intact.
|
|
21
|
+
*/
|
|
22
|
+
export function mergeCallerCapabilityDefinitions(
|
|
23
|
+
toolDefs: Iterable<t.LCTool> | null | undefined,
|
|
24
|
+
overrides: Iterable<t.LCTool> | null | undefined
|
|
25
|
+
): t.LCTool[] {
|
|
26
|
+
const runtimeDefinitions = Array.from(overrides ?? []);
|
|
27
|
+
const merged = new Map(
|
|
28
|
+
applyCallerCapabilityDefinitionOverrides(
|
|
29
|
+
toolDefs ?? [],
|
|
30
|
+
runtimeDefinitions
|
|
31
|
+
).map((toolDef) => [toolDef.name, toolDef])
|
|
32
|
+
);
|
|
33
|
+
for (const override of runtimeDefinitions) {
|
|
34
|
+
if (!merged.has(override.name)) {
|
|
35
|
+
merged.set(override.name, override);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return Array.from(merged.values());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Applies runtime caller metadata to schema-only event definitions without
|
|
43
|
+
* adding registry-only tools or replacing their model-facing schemas.
|
|
44
|
+
*/
|
|
45
|
+
export function applyCallerCapabilityDefinitionOverrides(
|
|
46
|
+
toolDefs: Iterable<t.LCTool>,
|
|
47
|
+
overrides: Iterable<t.LCTool> | null | undefined
|
|
48
|
+
): t.LCTool[] {
|
|
49
|
+
const overridesByName = new Map<string, t.LCTool>();
|
|
50
|
+
for (const override of overrides ?? []) {
|
|
51
|
+
overridesByName.set(override.name, override);
|
|
52
|
+
}
|
|
53
|
+
return Array.from(toolDefs, (toolDef) => {
|
|
54
|
+
const override = overridesByName.get(toolDef.name);
|
|
55
|
+
if (override == null) {
|
|
56
|
+
return toolDef;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
...toolDef,
|
|
60
|
+
allowed_callers: override.allowed_callers,
|
|
61
|
+
defer_loading: override.defer_loading,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Converts the live projection into the versioned event transport shape. */
|
|
67
|
+
export function createCallerCapabilityProjectionSnapshot(
|
|
68
|
+
projection: CallerCapabilityProjection
|
|
69
|
+
): t.CallerCapabilityProjectionSnapshot {
|
|
70
|
+
return {
|
|
71
|
+
version: 1,
|
|
72
|
+
directToolNames: projection.directTools.map((toolDef) => toolDef.name),
|
|
73
|
+
codeExecutionToolNames: projection.codeExecutionTools.map(
|
|
74
|
+
(toolDef) => toolDef.name
|
|
75
|
+
),
|
|
76
|
+
directOnlyToolNames: projection.directOnlyTools.map(
|
|
77
|
+
(toolDef) => toolDef.name
|
|
78
|
+
),
|
|
79
|
+
codeExecutionOnlyToolNames: projection.codeExecutionOnlyTools.map(
|
|
80
|
+
(toolDef) => toolDef.name
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
17
85
|
export function getAllowedCallers(
|
|
18
86
|
toolDef: t.LCTool
|
|
19
87
|
): readonly t.AllowedCaller[] {
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -95,8 +95,11 @@ import {
|
|
|
95
95
|
resolveLocalExecutionTools,
|
|
96
96
|
} from '@/tools/local';
|
|
97
97
|
import {
|
|
98
|
+
type CallerCapabilityProjection,
|
|
99
|
+
createCallerCapabilityProjectionSnapshot,
|
|
98
100
|
isToolDefinitionActive,
|
|
99
101
|
isProgrammaticControlTool,
|
|
102
|
+
mergeCallerCapabilityDefinitions,
|
|
100
103
|
resolveCallerCapabilityProjection,
|
|
101
104
|
} from '@/tools/CallerCapabilities';
|
|
102
105
|
import { stripCodeSessionFileSummary } from '@/tools/CodeSessionFileSummary';
|
|
@@ -698,6 +701,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
698
701
|
>();
|
|
699
702
|
/** Tool registry for filtering (lazy computation of programmatic maps) */
|
|
700
703
|
private toolRegistry?: t.LCToolRegistry;
|
|
704
|
+
/** Schema-only definitions used when event mode has no runtime registry. */
|
|
705
|
+
private toolDefinitions?: t.LCToolRegistry;
|
|
706
|
+
/** Tool-map entries created or replaced by the local execution resolver. */
|
|
707
|
+
private localImplementationNames = new Set<string>();
|
|
701
708
|
/** Reads deferred-tool discovery state from the owning agent context. */
|
|
702
709
|
private getDiscoveredToolNames?: () => readonly string[];
|
|
703
710
|
/** Reference to Graph's sessions map for automatic session injection */
|
|
@@ -803,6 +810,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
803
810
|
handleToolErrors,
|
|
804
811
|
loadRuntimeTools,
|
|
805
812
|
toolRegistry,
|
|
813
|
+
toolDefinitions,
|
|
806
814
|
getDiscoveredToolNames,
|
|
807
815
|
sessions,
|
|
808
816
|
codeSessionKey,
|
|
@@ -879,6 +887,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
879
887
|
toolRegistry,
|
|
880
888
|
toolExecution,
|
|
881
889
|
});
|
|
890
|
+
this.toolDefinitions = toolDefinitions;
|
|
882
891
|
this.getDiscoveredToolNames = getDiscoveredToolNames;
|
|
883
892
|
this.sessions = sessions;
|
|
884
893
|
this.codeSessionKey = codeSessionKey ?? Constants.EXECUTE_CODE;
|
|
@@ -999,6 +1008,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
999
1008
|
});
|
|
1000
1009
|
|
|
1001
1010
|
this.toolMap = resolved.toolMap;
|
|
1011
|
+
this.localImplementationNames = resolved.localImplementationNames;
|
|
1002
1012
|
if (resolved.fileCheckpointer != null) {
|
|
1003
1013
|
this.fileCheckpointer = resolved.fileCheckpointer;
|
|
1004
1014
|
}
|
|
@@ -1105,27 +1115,58 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1105
1115
|
this.settledInterruptingResults.clear();
|
|
1106
1116
|
}
|
|
1107
1117
|
|
|
1118
|
+
/** Returns the live caller projection used by direct and event execution. */
|
|
1119
|
+
private getCallerCapabilityProjection(): CallerCapabilityProjection {
|
|
1120
|
+
const discoveredToolNames = new Set(
|
|
1121
|
+
this.getDiscoveredToolNames?.() ?? []
|
|
1122
|
+
);
|
|
1123
|
+
return resolveCallerCapabilityProjection(
|
|
1124
|
+
mergeCallerCapabilityDefinitions(
|
|
1125
|
+
this.toolDefinitions?.values(),
|
|
1126
|
+
this.toolRegistry?.values()
|
|
1127
|
+
),
|
|
1128
|
+
(toolDef) => isToolDefinitionActive(toolDef, discoveredToolNames)
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/** Serializes the live caller projection for event-driven hosts. */
|
|
1133
|
+
private getCallerCapabilityProjectionSnapshot(): t.CallerCapabilityProjectionSnapshot {
|
|
1134
|
+
return createCallerCapabilityProjectionSnapshot(
|
|
1135
|
+
this.getCallerCapabilityProjection()
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1108
1139
|
/** Returns active tools projected by their effective caller capabilities. */
|
|
1109
1140
|
private getProgrammaticTools(): t.ProgrammaticCache {
|
|
1110
1141
|
const toolMap: t.ToolMap = new Map();
|
|
1142
|
+
const toolDefs: t.LCTool[] = [];
|
|
1111
1143
|
const discoveredToolNames = new Set(
|
|
1112
1144
|
this.getDiscoveredToolNames?.() ?? []
|
|
1113
1145
|
);
|
|
1114
|
-
const
|
|
1146
|
+
const executableCapabilities = resolveCallerCapabilityProjection(
|
|
1115
1147
|
this.toolRegistry?.values() ?? [],
|
|
1116
1148
|
(toolDef) => isToolDefinitionActive(toolDef, discoveredToolNames)
|
|
1117
1149
|
);
|
|
1118
|
-
for (const toolDef of
|
|
1150
|
+
for (const toolDef of executableCapabilities.codeExecutionTools) {
|
|
1151
|
+
if (
|
|
1152
|
+
this.eventDrivenMode &&
|
|
1153
|
+
this.directToolNames?.has(toolDef.name) !== true &&
|
|
1154
|
+
!this.localImplementationNames.has(toolDef.name)
|
|
1155
|
+
) {
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1119
1158
|
const tool = this.toolMap.get(toolDef.name);
|
|
1120
1159
|
if (tool != null) {
|
|
1121
1160
|
toolMap.set(toolDef.name, tool);
|
|
1161
|
+
toolDefs.push(toolDef);
|
|
1122
1162
|
}
|
|
1123
1163
|
}
|
|
1164
|
+
const activeCapabilities = this.getCallerCapabilityProjection();
|
|
1124
1165
|
|
|
1125
1166
|
return {
|
|
1126
1167
|
toolMap,
|
|
1127
|
-
toolDefs
|
|
1128
|
-
disallowedToolDefs:
|
|
1168
|
+
toolDefs,
|
|
1169
|
+
disallowedToolDefs: activeCapabilities.directOnlyTools
|
|
1129
1170
|
.filter((toolDef) => !isProgrammaticControlTool(toolDef.name))
|
|
1130
1171
|
.map((toolDef) => ({ name: toolDef.name })),
|
|
1131
1172
|
};
|
|
@@ -3455,6 +3496,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3455
3496
|
// the eager path sends `agentContext.agentId` — this must
|
|
3456
3497
|
// match it at the top level too.
|
|
3457
3498
|
agentId: this.executingAgentId,
|
|
3499
|
+
callerCapabilityProjection:
|
|
3500
|
+
this.getCallerCapabilityProjectionSnapshot(),
|
|
3458
3501
|
configurable: stripRunBreakerScope(
|
|
3459
3502
|
config.configurable as Record<string, unknown> | undefined
|
|
3460
3503
|
),
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
createLocalProgrammaticToolCallingTool,
|
|
5
5
|
} from './LocalProgrammaticToolCalling';
|
|
6
6
|
import {
|
|
7
|
+
CLOUDFLARE_CODING_TOOL_NAMES,
|
|
7
8
|
createCloudflareCodingToolBundle,
|
|
8
9
|
createCloudflareCodingTools,
|
|
9
10
|
createCloudflareExecutionTool,
|
|
@@ -30,6 +31,8 @@ import {
|
|
|
30
31
|
type ResolveLocalToolsResult = {
|
|
31
32
|
toolMap: t.ToolMap;
|
|
32
33
|
directToolNames: Set<string>;
|
|
34
|
+
/** Names whose toolMap entries were created or replaced by this resolver. */
|
|
35
|
+
localImplementationNames: Set<string>;
|
|
33
36
|
/**
|
|
34
37
|
* Set when `local.fileCheckpointing === true` AND the auto-bind
|
|
35
38
|
* coding suite is in use. ToolNode stashes this on the node and
|
|
@@ -81,6 +84,29 @@ export function isProgrammaticRunnerAutoBound(
|
|
|
81
84
|
return shouldUseLocalExecution(config);
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
/** Mirrors whether resolver policy creates or replaces this runner locally. */
|
|
88
|
+
export function isProgrammaticRunnerResolvedDirectly(
|
|
89
|
+
name: string,
|
|
90
|
+
config?: t.ToolExecutionConfig,
|
|
91
|
+
hasExplicitBinding: boolean = false
|
|
92
|
+
): boolean {
|
|
93
|
+
if (isProgrammaticRunnerAutoBound(name, config)) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (
|
|
97
|
+
!hasExplicitBinding ||
|
|
98
|
+
(name !== Constants.PROGRAMMATIC_TOOL_CALLING &&
|
|
99
|
+
name !== Constants.BASH_PROGRAMMATIC_TOOL_CALLING)
|
|
100
|
+
) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return (
|
|
104
|
+
(shouldUseLocalExecution(config) ||
|
|
105
|
+
shouldUseCloudflareSandboxExecution(config)) &&
|
|
106
|
+
!shouldIncludeCodingTools(config)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
84
110
|
function getCloudflareConfig(
|
|
85
111
|
config?: t.ToolExecutionConfig
|
|
86
112
|
): t.CloudflareSandboxExecutionConfig {
|
|
@@ -95,7 +121,12 @@ function getCloudflareConfig(
|
|
|
95
121
|
function getSelectedCloudflareCodingToolNames(
|
|
96
122
|
config: t.CloudflareSandboxExecutionConfig
|
|
97
123
|
): Set<string> {
|
|
98
|
-
|
|
124
|
+
const requestedNames = new Set(
|
|
125
|
+
config.codingToolNames ?? CLOUDFLARE_CODING_TOOL_NAMES
|
|
126
|
+
);
|
|
127
|
+
return new Set(
|
|
128
|
+
CLOUDFLARE_CODING_TOOL_NAMES.filter((name) => requestedNames.has(name))
|
|
129
|
+
);
|
|
99
130
|
}
|
|
100
131
|
|
|
101
132
|
function filterCloudflareCodingToolAllowlist(
|
|
@@ -340,6 +371,28 @@ export function resolveLocalToolRegistry(args: {
|
|
|
340
371
|
return registry;
|
|
341
372
|
}
|
|
342
373
|
|
|
374
|
+
/** Names that this execution config creates or replaces in the local tool map. */
|
|
375
|
+
export function resolveLocalImplementationNames(
|
|
376
|
+
toolNames: Iterable<string>,
|
|
377
|
+
toolExecution?: t.ToolExecutionConfig
|
|
378
|
+
): Set<string> {
|
|
379
|
+
if (
|
|
380
|
+
!shouldUseLocalExecution(toolExecution) &&
|
|
381
|
+
!shouldUseCloudflareSandboxExecution(toolExecution)
|
|
382
|
+
) {
|
|
383
|
+
return new Set();
|
|
384
|
+
}
|
|
385
|
+
if (shouldIncludeCodingTools(toolExecution)) {
|
|
386
|
+
return shouldUseCloudflareSandboxExecution(toolExecution)
|
|
387
|
+
? getSelectedCloudflareCodingToolNames(getCloudflareConfig(toolExecution))
|
|
388
|
+
: new Set(LOCAL_CODING_BUNDLE_NAMES);
|
|
389
|
+
}
|
|
390
|
+
const existingNames = new Set(toolNames);
|
|
391
|
+
return new Set(
|
|
392
|
+
[...CODE_EXECUTION_TOOLS].filter((name) => existingNames.has(name))
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
343
396
|
export function resolveLocalExecutionTools(args: {
|
|
344
397
|
toolMap: t.ToolMap;
|
|
345
398
|
toolExecution?: t.ToolExecutionConfig;
|
|
@@ -355,6 +408,10 @@ export function resolveLocalExecutionTools(args: {
|
|
|
355
408
|
fileCheckpointer?: t.LocalFileCheckpointer;
|
|
356
409
|
}): ResolveLocalToolsResult {
|
|
357
410
|
const directToolNames = new Set<string>();
|
|
411
|
+
const localImplementationNames = resolveLocalImplementationNames(
|
|
412
|
+
args.toolMap.keys(),
|
|
413
|
+
args.toolExecution
|
|
414
|
+
);
|
|
358
415
|
if (
|
|
359
416
|
!shouldUseLocalExecution(args.toolExecution) &&
|
|
360
417
|
!shouldUseCloudflareSandboxExecution(args.toolExecution)
|
|
@@ -362,6 +419,7 @@ export function resolveLocalExecutionTools(args: {
|
|
|
362
419
|
return {
|
|
363
420
|
toolMap: args.toolMap,
|
|
364
421
|
directToolNames,
|
|
422
|
+
localImplementationNames,
|
|
365
423
|
};
|
|
366
424
|
}
|
|
367
425
|
|
|
@@ -384,6 +442,7 @@ export function resolveLocalExecutionTools(args: {
|
|
|
384
442
|
fileCheckpointer = bundle.checkpointer;
|
|
385
443
|
for (const cloudflareTool of bundle.tools) {
|
|
386
444
|
toolMap.set(cloudflareTool.name, cloudflareTool);
|
|
445
|
+
localImplementationNames.add(cloudflareTool.name);
|
|
387
446
|
addDirectToolName(
|
|
388
447
|
directToolNames,
|
|
389
448
|
cloudflareTool.name,
|
|
@@ -395,6 +454,7 @@ export function resolveLocalExecutionTools(args: {
|
|
|
395
454
|
cloudflareConfig
|
|
396
455
|
)) {
|
|
397
456
|
toolMap.set(cloudflareTool.name, cloudflareTool);
|
|
457
|
+
localImplementationNames.add(cloudflareTool.name);
|
|
398
458
|
addDirectToolName(
|
|
399
459
|
directToolNames,
|
|
400
460
|
cloudflareTool.name,
|
|
@@ -418,10 +478,16 @@ export function resolveLocalExecutionTools(args: {
|
|
|
418
478
|
}
|
|
419
479
|
|
|
420
480
|
toolMap.set(name, cloudflareTool);
|
|
481
|
+
localImplementationNames.add(name);
|
|
421
482
|
addDirectToolName(directToolNames, name, args.toolRegistry);
|
|
422
483
|
}
|
|
423
484
|
|
|
424
|
-
return {
|
|
485
|
+
return {
|
|
486
|
+
toolMap,
|
|
487
|
+
directToolNames,
|
|
488
|
+
localImplementationNames,
|
|
489
|
+
fileCheckpointer,
|
|
490
|
+
};
|
|
425
491
|
}
|
|
426
492
|
|
|
427
493
|
const localConfig = args.toolExecution?.local ?? {};
|
|
@@ -443,6 +509,7 @@ export function resolveLocalExecutionTools(args: {
|
|
|
443
509
|
fileCheckpointer = bundle.checkpointer;
|
|
444
510
|
for (const localTool of bundle.tools) {
|
|
445
511
|
toolMap.set(localTool.name, localTool);
|
|
512
|
+
localImplementationNames.add(localTool.name);
|
|
446
513
|
addDirectToolName(
|
|
447
514
|
directToolNames,
|
|
448
515
|
localTool.name,
|
|
@@ -452,6 +519,7 @@ export function resolveLocalExecutionTools(args: {
|
|
|
452
519
|
} else {
|
|
453
520
|
for (const localTool of createLocalCodingTools(localConfig)) {
|
|
454
521
|
toolMap.set(localTool.name, localTool);
|
|
522
|
+
localImplementationNames.add(localTool.name);
|
|
455
523
|
addDirectToolName(
|
|
456
524
|
directToolNames,
|
|
457
525
|
localTool.name,
|
|
@@ -482,8 +550,14 @@ export function resolveLocalExecutionTools(args: {
|
|
|
482
550
|
}
|
|
483
551
|
|
|
484
552
|
toolMap.set(name, localTool);
|
|
553
|
+
localImplementationNames.add(name);
|
|
485
554
|
addDirectToolName(directToolNames, name, args.toolRegistry);
|
|
486
555
|
}
|
|
487
556
|
|
|
488
|
-
return {
|
|
557
|
+
return {
|
|
558
|
+
toolMap,
|
|
559
|
+
directToolNames,
|
|
560
|
+
localImplementationNames,
|
|
561
|
+
fileCheckpointer,
|
|
562
|
+
};
|
|
489
563
|
}
|