@librechat/agents 3.1.21 → 3.1.22

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.
@@ -183,10 +183,15 @@ export declare class AgentContext {
183
183
  markToolsAsDiscovered(toolNames: string[]): boolean;
184
184
  /**
185
185
  * Gets tools that should be bound to the LLM.
186
- * Includes:
186
+ * In event-driven mode (toolDefinitions present, tools empty), creates schema-only tools.
187
+ * Otherwise filters tool instances based on:
187
188
  * 1. Non-deferred tools with allowed_callers: ['direct']
188
189
  * 2. Discovered tools (from tool search)
189
190
  * @returns Array of tools to bind to model
190
191
  */
191
192
  getToolsForBinding(): t.GraphTools | undefined;
193
+ /** Creates schema-only tools from toolDefinitions for event-driven mode */
194
+ private getEventDrivenToolsForBinding;
195
+ /** Filters tool instances for binding based on registry config */
196
+ private filterToolsForBinding;
192
197
  }
@@ -9,7 +9,7 @@ export * from './tools/CodeExecutor';
9
9
  export * from './tools/ProgrammaticToolCalling';
10
10
  export * from './tools/ToolSearch';
11
11
  export * from './tools/ToolNode';
12
- export * from './tools/createSchemaOnlyTool';
12
+ export * from './tools/schema';
13
13
  export * from './tools/handlers';
14
14
  export * from './tools/search';
15
15
  export * from './common';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.1.21",
3
+ "version": "3.1.22",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -10,6 +10,7 @@ import type {
10
10
  import type { RunnableConfig, Runnable } from '@langchain/core/runnables';
11
11
  import type * as t from '@/types';
12
12
  import type { createPruneMessages } from '@/messages';
13
+ import { createSchemaOnlyTools } from '@/tools/schema';
13
14
  import { ContentTypes, Providers } from '@/common';
14
15
  import { toJsonSchema } from '@/utils/schema';
15
16
 
@@ -571,40 +572,70 @@ export class AgentContext {
571
572
 
572
573
  /**
573
574
  * Gets tools that should be bound to the LLM.
574
- * Includes:
575
+ * In event-driven mode (toolDefinitions present, tools empty), creates schema-only tools.
576
+ * Otherwise filters tool instances based on:
575
577
  * 1. Non-deferred tools with allowed_callers: ['direct']
576
578
  * 2. Discovered tools (from tool search)
577
579
  * @returns Array of tools to bind to model
578
580
  */
579
581
  getToolsForBinding(): t.GraphTools | undefined {
582
+ /** Event-driven mode: create schema-only tools from definitions */
583
+ if (this.toolDefinitions && this.toolDefinitions.length > 0) {
584
+ return this.getEventDrivenToolsForBinding();
585
+ }
586
+
587
+ /** Traditional mode: filter actual tool instances */
580
588
  if (!this.tools || !this.toolRegistry) {
581
589
  return this.tools;
582
590
  }
583
591
 
584
- const toolsToInclude = this.tools.filter((tool) => {
592
+ return this.filterToolsForBinding(this.tools);
593
+ }
594
+
595
+ /** Creates schema-only tools from toolDefinitions for event-driven mode */
596
+ private getEventDrivenToolsForBinding(): t.GraphTools {
597
+ if (!this.toolDefinitions) {
598
+ return [];
599
+ }
600
+
601
+ const defsToInclude = this.toolDefinitions.filter((def) => {
602
+ const allowedCallers = def.allowed_callers ?? ['direct'];
603
+ if (!allowedCallers.includes('direct')) {
604
+ return false;
605
+ }
606
+ if (
607
+ def.defer_loading === true &&
608
+ !this.discoveredToolNames.has(def.name)
609
+ ) {
610
+ return false;
611
+ }
612
+ return true;
613
+ });
614
+
615
+ return createSchemaOnlyTools(defsToInclude) as t.GraphTools;
616
+ }
617
+
618
+ /** Filters tool instances for binding based on registry config */
619
+ private filterToolsForBinding(tools: t.GraphTools): t.GraphTools {
620
+ return tools.filter((tool) => {
585
621
  if (!('name' in tool)) {
586
- return true; // No name, include by default
622
+ return true;
587
623
  }
588
624
 
589
625
  const toolDef = this.toolRegistry?.get(tool.name);
590
626
  if (!toolDef) {
591
- return true; // Not in registry, include by default
627
+ return true;
592
628
  }
593
629
 
594
- // Check if discovered (overrides defer_loading)
595
630
  if (this.discoveredToolNames.has(tool.name)) {
596
- // Discovered tools must still have allowed_callers: ['direct']
597
631
  const allowedCallers = toolDef.allowed_callers ?? ['direct'];
598
632
  return allowedCallers.includes('direct');
599
633
  }
600
634
 
601
- // Not discovered: must be direct-callable AND not deferred
602
635
  const allowedCallers = toolDef.allowed_callers ?? ['direct'];
603
636
  return (
604
637
  allowedCallers.includes('direct') && toolDef.defer_loading !== true
605
638
  );
606
639
  });
607
-
608
- return toolsToInclude;
609
640
  }
610
641
  }
@@ -58,9 +58,9 @@ import {
58
58
  } from '@/utils';
59
59
  import { getChatModelClass, manualToolStreamProviders } from '@/llm/providers';
60
60
  import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
61
- import { createSchemaOnlyTools } from '@/tools/createSchemaOnlyTool';
62
61
  import { ChatOpenAI, AzureChatOpenAI } from '@/llm/openai';
63
62
  import { safeDispatchCustomEvent } from '@/utils/events';
63
+ import { createSchemaOnlyTools } from '@/tools/schema';
64
64
  import { AgentContext } from '@/agents/AgentContext';
65
65
  import { createFakeStreamingLLM } from '@/llm/fake';
66
66
  import { HandlerRegistry } from '@/events';
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@ export * from './tools/CodeExecutor';
14
14
  export * from './tools/ProgrammaticToolCalling';
15
15
  export * from './tools/ToolSearch';
16
16
  export * from './tools/ToolNode';
17
- export * from './tools/createSchemaOnlyTool';
17
+ export * from './tools/schema';
18
18
  export * from './tools/handlers';
19
19
  export * from './tools/search';
20
20
 
@@ -1 +0,0 @@
1
- {"version":3,"file":"createSchemaOnlyTool.cjs","sources":["../../../src/tools/createSchemaOnlyTool.ts"],"sourcesContent":["import { tool, type StructuredToolInterface } from '@langchain/core/tools';\nimport type { LCTool } from '@/types';\n\n/**\n * Creates a schema-only tool for LLM binding in event-driven mode.\n * These tools have valid schemas for the LLM to understand but should\n * never be invoked directly - ToolNode handles execution via events.\n */\nexport function createSchemaOnlyTool(\n definition: LCTool\n): StructuredToolInterface {\n const { name, description, parameters, responseFormat } = definition;\n\n return tool(\n async () => {\n throw new Error(\n `Tool \"${name}\" should not be invoked directly in event-driven mode. ` +\n 'ToolNode should dispatch ON_TOOL_EXECUTE events instead.'\n );\n },\n {\n name,\n description: description ?? '',\n schema: parameters ?? { type: 'object', properties: {} },\n responseFormat: responseFormat ?? 'content_and_artifact',\n }\n );\n}\n\n/**\n * Creates schema-only tools for all definitions in an array.\n */\nexport function createSchemaOnlyTools(\n definitions: LCTool[]\n): StructuredToolInterface[] {\n return definitions.map((def) => createSchemaOnlyTool(def));\n}\n"],"names":["tool"],"mappings":";;;;AAGA;;;;AAIG;AACG,SAAU,oBAAoB,CAClC,UAAkB,EAAA;IAElB,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,UAAU;AAEpE,IAAA,OAAOA,UAAI,CACT,YAAW;AACT,QAAA,MAAM,IAAI,KAAK,CACb,CAAA,MAAA,EAAS,IAAI,CAAyD,uDAAA,CAAA;AACpE,YAAA,0DAA0D,CAC7D;AACH,KAAC,EACD;QACE,IAAI;QACJ,WAAW,EAAE,WAAW,IAAI,EAAE;QAC9B,MAAM,EAAE,UAAU,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QACxD,cAAc,EAAE,cAAc,IAAI,sBAAsB;AACzD,KAAA,CACF;AACH;AAEA;;AAEG;AACG,SAAU,qBAAqB,CACnC,WAAqB,EAAA;AAErB,IAAA,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,oBAAoB,CAAC,GAAG,CAAC,CAAC;AAC5D;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"createSchemaOnlyTool.mjs","sources":["../../../src/tools/createSchemaOnlyTool.ts"],"sourcesContent":["import { tool, type StructuredToolInterface } from '@langchain/core/tools';\nimport type { LCTool } from '@/types';\n\n/**\n * Creates a schema-only tool for LLM binding in event-driven mode.\n * These tools have valid schemas for the LLM to understand but should\n * never be invoked directly - ToolNode handles execution via events.\n */\nexport function createSchemaOnlyTool(\n definition: LCTool\n): StructuredToolInterface {\n const { name, description, parameters, responseFormat } = definition;\n\n return tool(\n async () => {\n throw new Error(\n `Tool \"${name}\" should not be invoked directly in event-driven mode. ` +\n 'ToolNode should dispatch ON_TOOL_EXECUTE events instead.'\n );\n },\n {\n name,\n description: description ?? '',\n schema: parameters ?? { type: 'object', properties: {} },\n responseFormat: responseFormat ?? 'content_and_artifact',\n }\n );\n}\n\n/**\n * Creates schema-only tools for all definitions in an array.\n */\nexport function createSchemaOnlyTools(\n definitions: LCTool[]\n): StructuredToolInterface[] {\n return definitions.map((def) => createSchemaOnlyTool(def));\n}\n"],"names":[],"mappings":";;AAGA;;;;AAIG;AACG,SAAU,oBAAoB,CAClC,UAAkB,EAAA;IAElB,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,UAAU;AAEpE,IAAA,OAAO,IAAI,CACT,YAAW;AACT,QAAA,MAAM,IAAI,KAAK,CACb,CAAA,MAAA,EAAS,IAAI,CAAyD,uDAAA,CAAA;AACpE,YAAA,0DAA0D,CAC7D;AACH,KAAC,EACD;QACE,IAAI;QACJ,WAAW,EAAE,WAAW,IAAI,EAAE;QAC9B,MAAM,EAAE,UAAU,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QACxD,cAAc,EAAE,cAAc,IAAI,sBAAsB;AACzD,KAAA,CACF;AACH;AAEA;;AAEG;AACG,SAAU,qBAAqB,CACnC,WAAqB,EAAA;AAErB,IAAA,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,oBAAoB,CAAC,GAAG,CAAC,CAAC;AAC5D;;;;"}