@librechat/agents 3.6.9 → 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.
Files changed (146) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +99 -39
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/agents/projection.cjs +2 -2
  4. package/dist/cjs/agents/projection.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +32 -21
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/graphs/MultiAgentGraph.cjs +87 -16
  8. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  9. package/dist/cjs/llm/openai/index.cjs +10 -0
  10. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  11. package/dist/cjs/main.cjs +16 -0
  12. package/dist/cjs/messages/alternation.cjs +125 -20
  13. package/dist/cjs/messages/alternation.cjs.map +1 -1
  14. package/dist/cjs/messages/core.cjs +195 -18
  15. package/dist/cjs/messages/core.cjs.map +1 -1
  16. package/dist/cjs/messages/format.cjs +488 -118
  17. package/dist/cjs/messages/format.cjs.map +1 -1
  18. package/dist/cjs/messages/handoffCue.cjs +3 -2
  19. package/dist/cjs/messages/handoffCue.cjs.map +1 -1
  20. package/dist/cjs/messages/index.cjs +1 -0
  21. package/dist/cjs/messages/injected.cjs +5 -2
  22. package/dist/cjs/messages/injected.cjs.map +1 -1
  23. package/dist/cjs/messages/provenance.cjs +411 -0
  24. package/dist/cjs/messages/provenance.cjs.map +1 -0
  25. package/dist/cjs/messages/prune.cjs +18 -13
  26. package/dist/cjs/messages/prune.cjs.map +1 -1
  27. package/dist/cjs/messages/toolResultTypes.cjs +663 -0
  28. package/dist/cjs/messages/toolResultTypes.cjs.map +1 -0
  29. package/dist/cjs/run.cjs +7 -4
  30. package/dist/cjs/run.cjs.map +1 -1
  31. package/dist/cjs/stream.cjs +1 -0
  32. package/dist/cjs/stream.cjs.map +1 -1
  33. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +21 -4
  34. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  35. package/dist/cjs/tools/CallerCapabilities.cjs +79 -0
  36. package/dist/cjs/tools/CallerCapabilities.cjs.map +1 -0
  37. package/dist/cjs/tools/ProgrammaticCallerPolicy.cjs +34 -0
  38. package/dist/cjs/tools/ProgrammaticCallerPolicy.cjs.map +1 -0
  39. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +21 -4
  40. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  41. package/dist/cjs/tools/ToolNode.cjs +39 -21
  42. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  43. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +12 -4
  44. package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -1
  45. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +13 -4
  46. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs.map +1 -1
  47. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +73 -13
  48. package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
  49. package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
  50. package/dist/cjs/utils/toolContent.cjs +2 -2
  51. package/dist/cjs/utils/toolContent.cjs.map +1 -1
  52. package/dist/esm/agents/AgentContext.mjs +99 -39
  53. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  54. package/dist/esm/agents/projection.mjs +2 -2
  55. package/dist/esm/agents/projection.mjs.map +1 -1
  56. package/dist/esm/graphs/Graph.mjs +34 -23
  57. package/dist/esm/graphs/Graph.mjs.map +1 -1
  58. package/dist/esm/graphs/MultiAgentGraph.mjs +87 -16
  59. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  60. package/dist/esm/llm/openai/index.mjs +10 -0
  61. package/dist/esm/llm/openai/index.mjs.map +1 -1
  62. package/dist/esm/main.mjs +4 -3
  63. package/dist/esm/messages/alternation.mjs +125 -20
  64. package/dist/esm/messages/alternation.mjs.map +1 -1
  65. package/dist/esm/messages/core.mjs +196 -19
  66. package/dist/esm/messages/core.mjs.map +1 -1
  67. package/dist/esm/messages/format.mjs +488 -119
  68. package/dist/esm/messages/format.mjs.map +1 -1
  69. package/dist/esm/messages/handoffCue.mjs +3 -2
  70. package/dist/esm/messages/handoffCue.mjs.map +1 -1
  71. package/dist/esm/messages/index.mjs +1 -0
  72. package/dist/esm/messages/injected.mjs +5 -2
  73. package/dist/esm/messages/injected.mjs.map +1 -1
  74. package/dist/esm/messages/provenance.mjs +401 -0
  75. package/dist/esm/messages/provenance.mjs.map +1 -0
  76. package/dist/esm/messages/prune.mjs +18 -13
  77. package/dist/esm/messages/prune.mjs.map +1 -1
  78. package/dist/esm/messages/toolResultTypes.mjs +657 -0
  79. package/dist/esm/messages/toolResultTypes.mjs.map +1 -0
  80. package/dist/esm/run.mjs +7 -4
  81. package/dist/esm/run.mjs.map +1 -1
  82. package/dist/esm/stream.mjs +1 -0
  83. package/dist/esm/stream.mjs.map +1 -1
  84. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +21 -4
  85. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  86. package/dist/esm/tools/CallerCapabilities.mjs +73 -0
  87. package/dist/esm/tools/CallerCapabilities.mjs.map +1 -0
  88. package/dist/esm/tools/ProgrammaticCallerPolicy.mjs +32 -0
  89. package/dist/esm/tools/ProgrammaticCallerPolicy.mjs.map +1 -0
  90. package/dist/esm/tools/ProgrammaticToolCalling.mjs +21 -4
  91. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  92. package/dist/esm/tools/ToolNode.mjs +39 -21
  93. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  94. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +14 -6
  95. package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -1
  96. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +15 -6
  97. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs.map +1 -1
  98. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +72 -15
  99. package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
  100. package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
  101. package/dist/esm/utils/toolContent.mjs +2 -2
  102. package/dist/esm/utils/toolContent.mjs.map +1 -1
  103. package/dist/types/agents/AgentContext.d.ts +19 -13
  104. package/dist/types/agents/projection.d.ts +3 -1
  105. package/dist/types/graphs/Graph.d.ts +1 -1
  106. package/dist/types/llm/openai/index.d.ts +20 -0
  107. package/dist/types/messages/format.d.ts +5 -0
  108. package/dist/types/messages/index.d.ts +1 -0
  109. package/dist/types/messages/provenance.d.ts +85 -0
  110. package/dist/types/messages/toolResultTypes.d.ts +33 -0
  111. package/dist/types/tools/CallerCapabilities.d.ts +25 -0
  112. package/dist/types/tools/ProgrammaticCallerPolicy.d.ts +20 -0
  113. package/dist/types/tools/ToolNode.d.ts +12 -7
  114. package/dist/types/tools/local/resolveLocalExecutionTools.d.ts +10 -0
  115. package/dist/types/tools/ptcTimeout.d.ts +8 -0
  116. package/dist/types/types/graph.d.ts +3 -1
  117. package/dist/types/types/tools.d.ts +30 -2
  118. package/package.json +1 -1
  119. package/src/agents/AgentContext.ts +253 -69
  120. package/src/agents/projection.ts +9 -1
  121. package/src/graphs/Graph.ts +62 -26
  122. package/src/graphs/MultiAgentGraph.ts +175 -33
  123. package/src/llm/openai/index.ts +43 -0
  124. package/src/messages/alternation.ts +217 -34
  125. package/src/messages/core.ts +358 -38
  126. package/src/messages/format.ts +958 -137
  127. package/src/messages/handoffCue.ts +7 -4
  128. package/src/messages/index.ts +1 -0
  129. package/src/messages/injected.ts +9 -6
  130. package/src/messages/provenance.ts +897 -0
  131. package/src/messages/prune.ts +28 -10
  132. package/src/messages/toolResultTypes.ts +1174 -0
  133. package/src/run.ts +9 -4
  134. package/src/stream.ts +6 -0
  135. package/src/tools/BashProgrammaticToolCalling.ts +46 -12
  136. package/src/tools/CallerCapabilities.ts +146 -0
  137. package/src/tools/ProgrammaticCallerPolicy.ts +97 -0
  138. package/src/tools/ProgrammaticToolCalling.ts +41 -7
  139. package/src/tools/ToolNode.ts +111 -50
  140. package/src/tools/cloudflare/CloudflareProgrammaticToolCalling.ts +24 -26
  141. package/src/tools/local/LocalProgrammaticToolCalling.ts +28 -23
  142. package/src/tools/local/resolveLocalExecutionTools.ts +209 -16
  143. package/src/tools/ptcTimeout.ts +6 -0
  144. package/src/types/graph.ts +3 -0
  145. package/src/types/tools.ts +32 -3
  146. package/src/utils/toolContent.ts +2 -2
@@ -32,6 +32,22 @@ import {
32
32
  Constants,
33
33
  Providers,
34
34
  } from '@/common';
35
+ import {
36
+ isProgrammaticRunnerAutoBound,
37
+ isProgrammaticRunnerResolvedDirectly,
38
+ resolveLocalImplementationNames,
39
+ resolveLocalToolRegistry,
40
+ } from '@/tools/local/resolveLocalExecutionTools';
41
+ import {
42
+ type CallerCapabilityProjection,
43
+ allowsToolCaller,
44
+ applyCallerCapabilityDefinitionOverrides,
45
+ createCallerCapabilityProjectionSnapshot,
46
+ isToolDefinitionActive,
47
+ isProgrammaticControlTool,
48
+ mergeCallerCapabilityDefinitions,
49
+ resolveCallerCapabilityProjection,
50
+ } from '@/tools/CallerCapabilities';
35
51
  import { createSchemaOnlyTools } from '@/tools/schema';
36
52
  import { apportionTokenCounts } from '@/utils/tokens';
37
53
  import { isThinkingEnabled } from '@/llm/request';
@@ -49,6 +65,12 @@ type AgentSystemContentBlock =
49
65
 
50
66
  type PromptCacheProvider = Providers.ANTHROPIC | Providers.OPENROUTER;
51
67
 
68
+ type ProgrammaticToolInstructionTarget = {
69
+ name: string;
70
+ codeGuidance: string;
71
+ executesDirectly: boolean;
72
+ };
73
+
52
74
  /**
53
75
  * Encapsulates agent-specific state that can vary between agents in a multi-agent system
54
76
  */
@@ -59,7 +81,8 @@ export class AgentContext {
59
81
  static fromConfig(
60
82
  agentConfig: t.AgentInputs,
61
83
  tokenCounter?: t.TokenCounter,
62
- indexTokenCountMap?: Record<string, number>
84
+ indexTokenCountMap?: Record<string, number>,
85
+ toolExecution?: t.ToolExecutionConfig
63
86
  ): AgentContext {
64
87
  const {
65
88
  agentId,
@@ -103,6 +126,7 @@ export class AgentContext {
103
126
  tools,
104
127
  toolMap,
105
128
  toolRegistry,
129
+ toolExecution,
106
130
  toolDefinitions,
107
131
  instructions,
108
132
  additionalInstructions: additional_instructions,
@@ -269,6 +293,8 @@ export class AgentContext {
269
293
  * Used for tool search and programmatic tool calling.
270
294
  */
271
295
  toolRegistry?: t.LCToolRegistry;
296
+ /** Run-scoped backend used to identify auto-bound programmatic runners. */
297
+ private toolExecution?: t.ToolExecutionConfig;
272
298
  /**
273
299
  * Serializable tool definitions for event-driven execution.
274
300
  * When provided, ToolNode operates in event-driven mode.
@@ -385,6 +411,7 @@ export class AgentContext {
385
411
  tools,
386
412
  toolMap,
387
413
  toolRegistry,
414
+ toolExecution,
388
415
  toolDefinitions,
389
416
  instructions,
390
417
  additionalInstructions,
@@ -410,6 +437,7 @@ export class AgentContext {
410
437
  tools?: t.GraphTools;
411
438
  toolMap?: t.ToolMap;
412
439
  toolRegistry?: t.LCToolRegistry;
440
+ toolExecution?: t.ToolExecutionConfig;
413
441
  toolDefinitions?: t.LCTool[];
414
442
  instructions?: string;
415
443
  additionalInstructions?: string;
@@ -434,7 +462,11 @@ export class AgentContext {
434
462
  this.tokenCounter = tokenCounter;
435
463
  this.tools = tools;
436
464
  this.toolMap = toolMap;
437
- this.toolRegistry = toolRegistry;
465
+ this.toolRegistry = resolveLocalToolRegistry({
466
+ toolRegistry,
467
+ toolExecution,
468
+ });
469
+ this.toolExecution = toolExecution;
438
470
  this.toolDefinitions = toolDefinitions;
439
471
  this.instructions = instructions;
440
472
  this.additionalInstructions = additionalInstructions;
@@ -461,37 +493,85 @@ export class AgentContext {
461
493
  }
462
494
  }
463
495
 
464
- /**
465
- * Builds instructions text for tools that are ONLY callable via programmatic code execution.
466
- * These tools cannot be called directly by the LLM but are available through the
467
- * configured programmatic tool.
468
- *
469
- * Includes:
470
- * - Code_execution-only tools that are NOT deferred
471
- * - Code_execution-only tools that ARE deferred but have been discovered via tool search
472
- */
496
+ /** Builds the caller boundary and schemas for programmatic-only tools. */
473
497
  private buildProgrammaticOnlyToolsInstructions(): string {
474
- if (!this.toolRegistry) return '';
475
-
476
- const programmaticOnlyTools: t.LCTool[] = [];
477
- for (const [name, toolDef] of this.toolRegistry) {
478
- const allowedCallers = toolDef.allowed_callers ?? ['direct'];
479
- const isCodeExecutionOnly =
480
- allowedCallers.includes('code_execution') &&
481
- !allowedCallers.includes('direct');
482
-
483
- if (!isCodeExecutionOnly) continue;
484
-
485
- const isDeferred = toolDef.defer_loading === true;
486
- const isDiscovered = this.discoveredToolNames.has(name);
487
- if (!isDeferred || isDiscovered) {
488
- programmaticOnlyTools.push(toolDef);
489
- }
498
+ const programmaticTools = this.getProgrammaticToolInstructionTargets();
499
+ if (programmaticTools.length === 0) return '';
500
+ const directProgrammaticTools = programmaticTools.filter(
501
+ (tool) => tool.executesDirectly
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
+ });
490
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
+ }
491
540
 
492
- if (programmaticOnlyTools.length === 0) return '';
541
+ private buildProgrammaticToolGroupInstructions(
542
+ programmaticTools: ProgrammaticToolInstructionTarget[],
543
+ capabilities: CallerCapabilityProjection
544
+ ): string {
545
+ const programmaticOnlyTools = capabilities.codeExecutionOnlyTools;
546
+ const programmaticToolNames = capabilities.codeExecutionTools.map(
547
+ (toolDef) => toolDef.name
548
+ );
549
+ const directOnlyToolNames = capabilities.directOnlyTools
550
+ .map((toolDef) => toolDef.name)
551
+ .filter((name) => !isProgrammaticControlTool(name));
552
+
553
+ const programmaticRunnerNames = programmaticTools
554
+ .map((tool) => `\`${tool.name}\``)
555
+ .join(' or ');
556
+ const quotedProgrammaticNames =
557
+ programmaticToolNames.length > 0
558
+ ? programmaticToolNames.map((name) => `\`${name}\``).join(', ')
559
+ : 'none';
560
+ const directOnlyBoundary =
561
+ directOnlyToolNames.length > 0
562
+ ? `\nCall these tools directly; never list them in the \`tool_manifest\` or reference them inside ${programmaticRunnerNames}: ${directOnlyToolNames
563
+ .map((name) => `\`${name}\``)
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.`
565
+ : '';
566
+ const boundary =
567
+ '\n\n' +
568
+ `Only these tools may be invoked inside ${programmaticRunnerNames}: ${quotedProgrammaticNames}.` +
569
+ directOnlyBoundary;
570
+
571
+ if (programmaticOnlyTools.length === 0) {
572
+ return boundary;
573
+ }
493
574
 
494
- const programmaticTool = this.getProgrammaticToolInstructionTarget();
495
575
  const toolDescriptions = programmaticOnlyTools
496
576
  .map((tool) => {
497
577
  let desc = `- **${tool.name}**`;
@@ -506,41 +586,125 @@ export class AgentContext {
506
586
  .join('\n\n');
507
587
 
508
588
  return (
509
- '\n\n## Programmatic-Only Tools\n\n' +
510
- `The following tools are available exclusively through the \`${programmaticTool.name}\` tool. ` +
511
- `You cannot call these tools directly; instead, use \`${programmaticTool.name}\` with ${programmaticTool.language} code that invokes them.\n\n` +
589
+ boundary +
590
+ '\n\n### Programmatic-Only Tools\n\n' +
591
+ `The following tools are available exclusively through ${programmaticRunnerNames}. ` +
592
+ `You cannot call these tools directly; instead, ${programmaticTools
593
+ .map(
594
+ (tool) =>
595
+ `use \`${tool.name}\` with ${tool.codeGuidance} that invokes them`
596
+ )
597
+ .join(', or ')}.\n\n` +
512
598
  toolDescriptions
513
599
  );
514
600
  }
515
601
 
516
- private getProgrammaticToolInstructionTarget(): {
517
- name: string;
518
- language: 'bash' | 'Python';
519
- } {
520
- if (this.hasAvailableTool(Constants.BASH_PROGRAMMATIC_TOOL_CALLING)) {
521
- return {
602
+ private getProgrammaticToolInstructionTargets(): ProgrammaticToolInstructionTarget[] {
603
+ const targets: ProgrammaticToolInstructionTarget[] = [];
604
+ if (
605
+ this.hasBoundTool(Constants.BASH_PROGRAMMATIC_TOOL_CALLING) ||
606
+ isProgrammaticRunnerAutoBound(
607
+ Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
608
+ this.toolExecution
609
+ )
610
+ ) {
611
+ targets.push({
522
612
  name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING,
523
- language: 'bash',
524
- };
613
+ codeGuidance: 'Bash code',
614
+ executesDirectly: this.isProgrammaticRunnerDirectlyBound(
615
+ Constants.BASH_PROGRAMMATIC_TOOL_CALLING
616
+ ),
617
+ });
525
618
  }
526
619
 
527
- if (this.hasAvailableTool(Constants.PROGRAMMATIC_TOOL_CALLING)) {
528
- return { name: Constants.PROGRAMMATIC_TOOL_CALLING, language: 'Python' };
620
+ if (
621
+ this.hasBoundTool(Constants.PROGRAMMATIC_TOOL_CALLING) ||
622
+ isProgrammaticRunnerAutoBound(
623
+ Constants.PROGRAMMATIC_TOOL_CALLING,
624
+ this.toolExecution
625
+ )
626
+ ) {
627
+ const localDefault =
628
+ this.toolExecution?.engine === 'local' ||
629
+ this.toolExecution?.engine === 'cloudflare-sandbox';
630
+ targets.push({
631
+ name: Constants.PROGRAMMATIC_TOOL_CALLING,
632
+ codeGuidance: localDefault
633
+ ? 'Bash code by default, or set `lang: "py"` to use Python code'
634
+ : 'Python code',
635
+ executesDirectly: this.isProgrammaticRunnerDirectlyBound(
636
+ Constants.PROGRAMMATIC_TOOL_CALLING
637
+ ),
638
+ });
529
639
  }
530
640
 
531
- return { name: Constants.BASH_PROGRAMMATIC_TOOL_CALLING, language: 'bash' };
641
+ return targets;
532
642
  }
533
643
 
534
- private hasAvailableTool(name: string): boolean {
535
- if (this.toolDefinitions?.some((tool) => tool.name === name) === true)
536
- return true;
537
- if (
538
- this.tools?.some((tool) => 'name' in tool && tool.name === name) === true
539
- ) {
540
- return true;
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
+ }
541
680
  }
542
- if (this.toolMap?.has(name) === true) return true;
543
- return this.toolRegistry?.has(name) === true;
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
+
702
+ private hasBoundTool(name: string): boolean {
703
+ return (
704
+ this.getToolsForBinding()?.some(
705
+ (tool) => 'name' in tool && tool.name === name
706
+ ) === true
707
+ );
544
708
  }
545
709
 
546
710
  /**
@@ -1071,9 +1235,21 @@ export class AgentContext {
1071
1235
  this.indexTokenCountMap = { ...baseTokenMap };
1072
1236
  }
1073
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
+
1074
1249
  /** Active tool definitions for token accounting (excludes deferred-and-undiscovered entries). */
1075
1250
  private getActiveToolDefinitions(): t.LCTool[] {
1076
- if (!this.toolDefinitions) {
1251
+ const effectiveToolDefinitions = this.getEffectiveToolDefinitions();
1252
+ if (!effectiveToolDefinitions) {
1077
1253
  return [];
1078
1254
  }
1079
1255
  /**
@@ -1083,15 +1259,10 @@ export class AgentContext {
1083
1259
  * alone left programmatic-only definitions counted in
1084
1260
  * `toolSchemaTokens` even though they were never bound.
1085
1261
  */
1086
- return this.toolDefinitions.filter((def) => {
1087
- const allowedCallers = def.allowed_callers ?? ['direct'];
1088
- if (!allowedCallers.includes('direct')) {
1089
- return false;
1090
- }
1091
- return (
1092
- def.defer_loading !== true || this.discoveredToolNames.has(def.name)
1093
- );
1094
- });
1262
+ return resolveCallerCapabilityProjection(
1263
+ effectiveToolDefinitions,
1264
+ (toolDef) => isToolDefinitionActive(toolDef, this.discoveredToolNames)
1265
+ ).directTools;
1095
1266
  }
1096
1267
 
1097
1268
  /**
@@ -1720,6 +1891,24 @@ export class AgentContext {
1720
1891
  return Array.from(this.discoveredToolNames);
1721
1892
  }
1722
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
+
1723
1912
  /**
1724
1913
  * Marks tools as discovered via tool search.
1725
1914
  * Discovered tools will be included in the next model binding.
@@ -1807,14 +1996,9 @@ export class AgentContext {
1807
1996
  return true;
1808
1997
  }
1809
1998
 
1810
- if (this.discoveredToolNames.has(tool.name)) {
1811
- const allowedCallers = toolDef.allowed_callers ?? ['direct'];
1812
- return allowedCallers.includes('direct');
1813
- }
1814
-
1815
- const allowedCallers = toolDef.allowed_callers ?? ['direct'];
1816
1999
  return (
1817
- allowedCallers.includes('direct') && toolDef.defer_loading !== true
2000
+ allowsToolCaller(toolDef, 'direct') &&
2001
+ isToolDefinitionActive(toolDef, this.discoveredToolNames)
1818
2002
  );
1819
2003
  });
1820
2004
  }
@@ -13,6 +13,8 @@ export interface ProjectAgentContextUsageParams {
13
13
  indexTokenCountMap?: Record<string, number>;
14
14
  /** Provider-calibrated ratio from a prior snapshot, applied as a static seed. */
15
15
  calibrationRatio?: number;
16
+ /** Execution backend used to synthesize the live effective tool registry. */
17
+ toolExecution?: t.ToolExecutionConfig;
16
18
  runId?: string;
17
19
  agentId?: string;
18
20
  }
@@ -32,10 +34,16 @@ export async function projectAgentContextUsage({
32
34
  tokenCounter,
33
35
  indexTokenCountMap,
34
36
  calibrationRatio,
37
+ toolExecution,
35
38
  runId,
36
39
  agentId,
37
40
  }: ProjectAgentContextUsageParams): Promise<t.ContextUsageEvent | null> {
38
- const context = AgentContext.fromConfig(agent, tokenCounter, indexTokenCountMap);
41
+ const context = AgentContext.fromConfig(
42
+ agent,
43
+ tokenCounter,
44
+ indexTokenCountMap,
45
+ toolExecution
46
+ );
39
47
  await context.tokenCalculationPromise;
40
48
  return context.projectContextUsage(messages, {
41
49
  runId,
@@ -34,6 +34,7 @@ import type {
34
34
  import type {
35
35
  GraphFactory,
36
36
  GraphFactoryDependencies,
37
+ GraphFactoryRequest,
37
38
  } from '@/graphs/graphFactory';
38
39
  import type { OverflowRecoveryPlan } from '@/llm/contextOverflowRecovery';
39
40
  import type { FallbackErrorContext } from '@/llm/invoke';
@@ -61,6 +62,7 @@ import {
61
62
  resolveBedrockPromptCacheTtl,
62
63
  supportsBedrockToolCache,
63
64
  isSyntheticProviderContextMessage,
65
+ compactSyntheticProviderContextMessage,
64
66
  getMessageId,
65
67
  getMessageCreationContentMetadata,
66
68
  splitAssistantTextContentByPhase,
@@ -73,6 +75,7 @@ import {
73
75
  strictAlternationProviders,
74
76
  appendPredecessorHandoffCue,
75
77
  removePredecessorHandoffCue,
78
+ stampSyntheticProviderMessage,
76
79
  } from '@/messages';
77
80
  import {
78
81
  Constants,
@@ -133,11 +136,6 @@ import {
133
136
  resolveLangfuseConfig,
134
137
  resolveToolOutputTracingConfig,
135
138
  } from '@/langfuseConfig';
136
- import {
137
- compactToolContent,
138
- getToolContentCharLength,
139
- serializeToolContentBounded,
140
- } from '@/utils/toolContent';
141
139
  import {
142
140
  annotateMessagesForLLM,
143
141
  ToolOutputReferenceRegistry,
@@ -146,6 +144,10 @@ import {
146
144
  resolveLangfuseRuntimeScope,
147
145
  withLangfuseRuntimeScope,
148
146
  } from '@/langfuseRuntimeScope';
147
+ import {
148
+ getToolContentCharLength,
149
+ serializeToolContentBounded,
150
+ } from '@/utils/toolContent';
149
151
  import {
150
152
  appendCallbacks,
151
153
  findCallback,
@@ -412,7 +414,9 @@ function getCurrentStepIds({
412
414
  if (stepKey !== baseStepKey && !stepKey.startsWith(`${baseStepKey}_`)) {
413
415
  continue;
414
416
  }
415
- currentStepIds.push(...stepIds);
417
+ for (const stepId of stepIds) {
418
+ currentStepIds.push(stepId);
419
+ }
416
420
  }
417
421
  return currentStepIds;
418
422
  }
@@ -1457,6 +1461,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1457
1461
  subagentExecutionContext,
1458
1462
  preemption,
1459
1463
  streamLimits,
1464
+ toolExecution,
1460
1465
  }: t.StandardGraphInput,
1461
1466
  dependencies?: GraphFactoryDependencies
1462
1467
  ) {
@@ -1482,6 +1487,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1482
1487
  this.subagentExecutionContext = subagentExecutionContext;
1483
1488
  this.preemption = preemption;
1484
1489
  this.streamLimits = resolveStreamLimits(streamLimits);
1490
+ this.toolExecution = toolExecution;
1485
1491
 
1486
1492
  if (agents.length === 0) {
1487
1493
  throw new Error('At least one agent configuration is required');
@@ -1491,7 +1497,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1491
1497
  const agentContext = AgentContext.fromConfig(
1492
1498
  agentConfig,
1493
1499
  tokenCounter,
1494
- indexTokenCountMap
1500
+ indexTokenCountMap,
1501
+ toolExecution
1495
1502
  );
1496
1503
  if (calibrationRatio != null && calibrationRatio > 0) {
1497
1504
  agentContext.calibrationRatio = calibrationRatio;
@@ -2557,6 +2564,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2557
2564
  executingAgentId: agentContext?.agentId,
2558
2565
  toolCallStepIds: this.toolCallStepIds,
2559
2566
  toolRegistry: agentContext?.toolRegistry,
2567
+ getDiscoveredToolNames: (): readonly string[] =>
2568
+ agentContext?.getDiscoveredTools() ?? [],
2560
2569
  hookRegistry: this.hookRegistry,
2561
2570
  humanInTheLoop: this.humanInTheLoop,
2562
2571
  eagerEventToolExecution: this.eagerEventToolExecution,
@@ -2634,6 +2643,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2634
2643
  errorHandler: (data, metadata): Promise<boolean> =>
2635
2644
  StandardGraph.handleToolCallErrorStatic(this, data, metadata),
2636
2645
  toolRegistry: agentContext?.toolRegistry,
2646
+ getDiscoveredToolNames: (): readonly string[] =>
2647
+ agentContext?.getDiscoveredTools() ?? [],
2637
2648
  sessions: this.sessions,
2638
2649
  codeSessionKey: agentContext?.codeSessionKey,
2639
2650
  toolExecution: this.toolExecution,
@@ -2839,6 +2850,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2839
2850
  const rawToolsForBinding = resolveLocalToolsForBinding({
2840
2851
  tools: agentContext.getToolsForBinding(),
2841
2852
  toolExecution: this.toolExecution,
2853
+ toolRegistry: agentContext.toolRegistry,
2854
+ discoveredToolNames: new Set(agentContext.getDiscoveredTools()),
2842
2855
  });
2843
2856
 
2844
2857
  /**
@@ -2855,6 +2868,9 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2855
2868
  * the breakpoint and don't invalidate the prefix.
2856
2869
  */
2857
2870
  let toolsForBinding = rawToolsForBinding;
2871
+ const isDeferredTool = makeIsDeferred(
2872
+ agentContext.getEffectiveToolDefinitions()
2873
+ );
2858
2874
  if (
2859
2875
  agentContext.provider === Providers.ANTHROPIC &&
2860
2876
  (agentContext.clientOptions as t.AnthropicClientOptions | undefined)
@@ -2863,7 +2879,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2863
2879
  toolsForBinding =
2864
2880
  partitionAndMarkAnthropicToolCache(
2865
2881
  rawToolsForBinding,
2866
- makeIsDeferred(agentContext.toolDefinitions),
2882
+ isDeferredTool,
2867
2883
  resolvePromptCacheTtl(
2868
2884
  (
2869
2885
  agentContext.clientOptions as
@@ -2883,7 +2899,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2883
2899
  toolsForBinding =
2884
2900
  partitionAndMarkOpenRouterToolCache(
2885
2901
  rawToolsForBinding,
2886
- makeIsDeferred(agentContext.toolDefinitions),
2902
+ isDeferredTool,
2887
2903
  resolvePromptCacheTtl(
2888
2904
  (
2889
2905
  agentContext.clientOptions as
@@ -2910,7 +2926,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
2910
2926
  toolsForBinding =
2911
2927
  partitionAndMarkBedrockToolCache(
2912
2928
  rawToolsForBinding,
2913
- makeIsDeferred(agentContext.toolDefinitions)
2929
+ isDeferredTool
2914
2930
  ) ?? rawToolsForBinding;
2915
2931
  }
2916
2932
  }
@@ -3553,17 +3569,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
3553
3569
  const buildCandidate = (scale: number): BaseMessage[] => {
3554
3570
  const compacted = [...candidate];
3555
3571
  for (const { index, message, chars } of synthetic) {
3556
- const content = compactToolContent(
3557
- message.content,
3572
+ compacted[index] = compactSyntheticProviderContextMessage(
3573
+ message,
3558
3574
  Math.floor(chars * scale)
3559
- ).content;
3560
- compacted[index] = new HumanMessage({
3561
- content,
3562
- id: message.id,
3563
- name: message.name,
3564
- additional_kwargs: message.additional_kwargs,
3565
- response_metadata: message.response_metadata,
3566
- });
3575
+ );
3567
3576
  }
3568
3577
  return compacted;
3569
3578
  };
@@ -4725,15 +4734,26 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
4725
4734
  );
4726
4735
  if (contexts.length > 0) {
4727
4736
  injected.push(
4728
- new HumanMessage({
4729
- content: contexts.join('\n\n'),
4730
- additional_kwargs: { role: 'system', isMeta: true, source: 'hook' },
4731
- })
4737
+ stampSyntheticProviderMessage(
4738
+ new HumanMessage({
4739
+ content: contexts.join('\n\n'),
4740
+ additional_kwargs: {
4741
+ role: 'system',
4742
+ isMeta: true,
4743
+ source: 'hook',
4744
+ },
4745
+ })
4746
+ )
4732
4747
  );
4733
4748
  }
4734
4749
  if (result.injectedMessages.length > 0) {
4735
4750
  try {
4736
- injected.push(...convertInjectedMessages(result.injectedMessages));
4751
+ const convertedMessages = convertInjectedMessages(
4752
+ result.injectedMessages
4753
+ );
4754
+ for (const convertedMessage of convertedMessages) {
4755
+ injected.push(convertedMessage);
4756
+ }
4737
4757
  } catch (e) {
4738
4758
  console.warn(
4739
4759
  '[StandardGraph] Failed to convert PreemptBoundary injectedMessages:',
@@ -4805,7 +4825,23 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
4805
4825
  };
4806
4826
  const checkpointer = this.compileOptions?.checkpointer;
4807
4827
  return (request): StandardGraph => {
4808
- const childGraph = graphFactory(request);
4828
+ const configuredRequest: GraphFactoryRequest =
4829
+ request.kind === 'multi-agent'
4830
+ ? {
4831
+ kind: 'multi-agent',
4832
+ input: {
4833
+ ...request.input,
4834
+ toolExecution: runtimeConfig.toolExecution,
4835
+ },
4836
+ }
4837
+ : {
4838
+ kind: 'standard',
4839
+ input: {
4840
+ ...request.input,
4841
+ toolExecution: runtimeConfig.toolExecution,
4842
+ },
4843
+ };
4844
+ const childGraph = graphFactory(configuredRequest);
4809
4845
  if (subagentModelOverride != null) {
4810
4846
  childGraph.overrideModel = subagentModelOverride;
4811
4847
  childGraph.setSubagentModelOverride(subagentModelOverride);