@librechat/agents 3.0.66 → 3.0.68
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/common/enum.cjs +3 -1
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/main.cjs +14 -7
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/tools.cjs +2 -2
- package/dist/cjs/messages/tools.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +1 -1
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/{ToolSearchRegex.cjs → ToolSearch.cjs} +318 -63
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -0
- package/dist/esm/common/enum.mjs +3 -1
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -1
- package/dist/esm/messages/tools.mjs +2 -2
- package/dist/esm/messages/tools.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +1 -1
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/{ToolSearchRegex.mjs → ToolSearch.mjs} +311 -63
- package/dist/esm/tools/ToolSearch.mjs.map +1 -0
- package/dist/types/common/enum.d.ts +4 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/tools/ToolSearch.d.ts +133 -0
- package/dist/types/types/tools.d.ts +8 -2
- package/package.json +2 -2
- package/src/common/enum.ts +3 -1
- package/src/index.ts +1 -1
- package/src/messages/__tests__/tools.test.ts +21 -21
- package/src/messages/tools.ts +2 -2
- package/src/scripts/programmatic_exec_agent.ts +4 -4
- package/src/scripts/{tool_search_regex.ts → tool_search.ts} +5 -5
- package/src/tools/ToolNode.ts +1 -1
- package/src/tools/{ToolSearchRegex.ts → ToolSearch.ts} +390 -69
- package/src/tools/__tests__/{ToolSearchRegex.integration.test.ts → ToolSearch.integration.test.ts} +6 -6
- package/src/tools/__tests__/ToolSearch.test.ts +734 -0
- package/src/types/tools.ts +9 -2
- package/dist/cjs/tools/ToolSearchRegex.cjs.map +0 -1
- package/dist/esm/tools/ToolSearchRegex.mjs.map +0 -1
- package/dist/types/tools/ToolSearchRegex.d.ts +0 -80
- package/src/tools/__tests__/ToolSearchRegex.test.ts +0 -232
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
3
|
+
import type * as t from '@/types';
|
|
4
|
+
/** Zod schema type for tool search parameters */
|
|
5
|
+
type ToolSearchSchema = z.ZodObject<{
|
|
6
|
+
query: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
7
|
+
fields: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>>;
|
|
8
|
+
max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
9
|
+
mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Creates the Zod schema with dynamic query description based on mode.
|
|
13
|
+
* @param mode - The search mode determining query interpretation
|
|
14
|
+
* @returns Zod schema for tool search parameters
|
|
15
|
+
*/
|
|
16
|
+
declare function createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema;
|
|
17
|
+
/**
|
|
18
|
+
* Extracts the MCP server name from a tool name.
|
|
19
|
+
* MCP tools follow the pattern: toolName_mcp_serverName
|
|
20
|
+
* @param toolName - The full tool name
|
|
21
|
+
* @returns The server name if it's an MCP tool, undefined otherwise
|
|
22
|
+
*/
|
|
23
|
+
declare function extractMcpServerName(toolName: string): string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Checks if a tool belongs to a specific MCP server.
|
|
26
|
+
* @param toolName - The full tool name
|
|
27
|
+
* @param serverName - The server name to match
|
|
28
|
+
* @returns True if the tool belongs to the specified server
|
|
29
|
+
*/
|
|
30
|
+
declare function isFromMcpServer(toolName: string, serverName: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if a tool belongs to any of the specified MCP servers.
|
|
33
|
+
* @param toolName - The full tool name
|
|
34
|
+
* @param serverNames - Array of server names to match
|
|
35
|
+
* @returns True if the tool belongs to any of the specified servers
|
|
36
|
+
*/
|
|
37
|
+
declare function isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Normalizes server filter input to always be an array.
|
|
40
|
+
* @param serverFilter - String, array of strings, or undefined
|
|
41
|
+
* @returns Array of server names (empty if none specified)
|
|
42
|
+
*/
|
|
43
|
+
declare function normalizeServerFilter(serverFilter: string | string[] | undefined): string[];
|
|
44
|
+
/**
|
|
45
|
+
* Escapes special regex characters in a string to use as a literal pattern.
|
|
46
|
+
* @param pattern - The string to escape
|
|
47
|
+
* @returns The escaped string safe for use in a RegExp
|
|
48
|
+
*/
|
|
49
|
+
declare function escapeRegexSpecialChars(pattern: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Counts the maximum nesting depth of groups in a regex pattern.
|
|
52
|
+
* @param pattern - The regex pattern to analyze
|
|
53
|
+
* @returns The maximum nesting depth
|
|
54
|
+
*/
|
|
55
|
+
declare function countNestedGroups(pattern: string): number;
|
|
56
|
+
/**
|
|
57
|
+
* Detects nested quantifiers that can cause catastrophic backtracking.
|
|
58
|
+
* Patterns like (a+)+, (a*)*, (a+)*, etc.
|
|
59
|
+
* @param pattern - The regex pattern to check
|
|
60
|
+
* @returns True if nested quantifiers are detected
|
|
61
|
+
*/
|
|
62
|
+
declare function hasNestedQuantifiers(pattern: string): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Checks if a regex pattern contains potentially dangerous constructs.
|
|
65
|
+
* @param pattern - The regex pattern to validate
|
|
66
|
+
* @returns True if the pattern is dangerous
|
|
67
|
+
*/
|
|
68
|
+
declare function isDangerousPattern(pattern: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Sanitizes a regex pattern for safe execution.
|
|
71
|
+
* If the pattern is dangerous, it will be escaped to a literal string search.
|
|
72
|
+
* @param pattern - The regex pattern to sanitize
|
|
73
|
+
* @returns Object containing the safe pattern and whether it was escaped
|
|
74
|
+
*/
|
|
75
|
+
declare function sanitizeRegex(pattern: string): {
|
|
76
|
+
safe: string;
|
|
77
|
+
wasEscaped: boolean;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Performs safe local substring search without regex.
|
|
81
|
+
* Uses case-insensitive String.includes() for complete safety against ReDoS.
|
|
82
|
+
* @param tools - Array of tool metadata to search
|
|
83
|
+
* @param query - The search term (treated as literal substring)
|
|
84
|
+
* @param fields - Which fields to search
|
|
85
|
+
* @param maxResults - Maximum results to return
|
|
86
|
+
* @returns Search response with matching tools
|
|
87
|
+
*/
|
|
88
|
+
declare function performLocalSearch(tools: t.ToolMetadata[], query: string, fields: string[], maxResults: number): t.ToolSearchResponse;
|
|
89
|
+
/**
|
|
90
|
+
* Extracts the base tool name (without MCP server suffix) from a full tool name.
|
|
91
|
+
* @param toolName - The full tool name
|
|
92
|
+
* @returns The base tool name without server suffix
|
|
93
|
+
*/
|
|
94
|
+
declare function getBaseToolName(toolName: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Formats a server listing response when listing all tools from MCP server(s).
|
|
97
|
+
* Provides a cohesive view of all tools grouped by server.
|
|
98
|
+
* NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.
|
|
99
|
+
* @param tools - Array of tool metadata from the server(s)
|
|
100
|
+
* @param serverNames - The MCP server name(s)
|
|
101
|
+
* @returns Formatted string showing all tools from the server(s)
|
|
102
|
+
*/
|
|
103
|
+
declare function formatServerListing(tools: t.ToolMetadata[], serverNames: string | string[]): string;
|
|
104
|
+
/**
|
|
105
|
+
* Creates a Tool Search tool for discovering tools from a large registry.
|
|
106
|
+
*
|
|
107
|
+
* This tool enables AI agents to dynamically discover tools from a large library
|
|
108
|
+
* without loading all tool definitions into the LLM context window. The agent
|
|
109
|
+
* can search for relevant tools on-demand.
|
|
110
|
+
*
|
|
111
|
+
* **Modes:**
|
|
112
|
+
* - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.
|
|
113
|
+
* - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.
|
|
114
|
+
*
|
|
115
|
+
* The tool registry can be provided either:
|
|
116
|
+
* 1. At initialization time via params.toolRegistry
|
|
117
|
+
* 2. At runtime via config.configurable.toolRegistry when invoking
|
|
118
|
+
*
|
|
119
|
+
* @param params - Configuration parameters for the tool (toolRegistry is optional)
|
|
120
|
+
* @returns A LangChain DynamicStructuredTool for tool searching
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* // Option 1: Code interpreter mode (regex via sandbox)
|
|
124
|
+
* const tool = createToolSearch({ apiKey, toolRegistry });
|
|
125
|
+
* await tool.invoke({ query: 'expense.*report' });
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* // Option 2: Local mode (safe substring search, no API key needed)
|
|
129
|
+
* const tool = createToolSearch({ mode: 'local', toolRegistry });
|
|
130
|
+
* await tool.invoke({ query: 'expense' });
|
|
131
|
+
*/
|
|
132
|
+
declare function createToolSearch(initParams?: t.ToolSearchParams): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>>;
|
|
133
|
+
export { createToolSearch, performLocalSearch, extractMcpServerName, isFromMcpServer, isFromAnyMcpServer, normalizeServerFilter, getBaseToolName, formatServerListing, sanitizeRegex, escapeRegexSpecialChars, isDangerousPattern, countNestedGroups, hasNestedQuantifiers, };
|
|
@@ -99,12 +99,18 @@ export type ProgrammaticCache = {
|
|
|
99
99
|
toolMap: ToolMap;
|
|
100
100
|
toolDefs: LCTool[];
|
|
101
101
|
};
|
|
102
|
-
/**
|
|
103
|
-
export type
|
|
102
|
+
/** Search mode: code_interpreter uses external sandbox, local uses safe substring matching */
|
|
103
|
+
export type ToolSearchMode = 'code_interpreter' | 'local';
|
|
104
|
+
/** Parameters for creating a Tool Search tool */
|
|
105
|
+
export type ToolSearchParams = {
|
|
104
106
|
apiKey?: string;
|
|
105
107
|
toolRegistry?: LCToolRegistry;
|
|
106
108
|
onlyDeferred?: boolean;
|
|
107
109
|
baseUrl?: string;
|
|
110
|
+
/** Search mode: 'code_interpreter' (default) uses sandbox for regex, 'local' uses safe substring matching */
|
|
111
|
+
mode?: ToolSearchMode;
|
|
112
|
+
/** Filter tools to only those from specific MCP server(s). Can be a single name or array of names. */
|
|
113
|
+
mcpServer?: string | string[];
|
|
108
114
|
[key: string]: unknown;
|
|
109
115
|
};
|
|
110
116
|
/** Simplified tool metadata for search purposes */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@librechat/agents",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.68",
|
|
4
4
|
"main": "./dist/cjs/main.cjs",
|
|
5
5
|
"module": "./dist/esm/main.mjs",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"memory": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/memory.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
|
58
58
|
"tool": "node --trace-warnings -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'openrouter' --name 'Jo' --location 'New York, NY'",
|
|
59
59
|
"search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/search.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
|
|
60
|
-
"
|
|
60
|
+
"tool_search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tool_search.ts",
|
|
61
61
|
"programmatic_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec.ts",
|
|
62
62
|
"code_exec_ptc": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_ptc.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
|
63
63
|
"programmatic_exec_agent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec_agent.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
|
package/src/common/enum.ts
CHANGED
|
@@ -159,11 +159,13 @@ export enum Callback {
|
|
|
159
159
|
export enum Constants {
|
|
160
160
|
OFFICIAL_CODE_BASEURL = 'https://api.librechat.ai/v1',
|
|
161
161
|
EXECUTE_CODE = 'execute_code',
|
|
162
|
-
|
|
162
|
+
TOOL_SEARCH = 'tool_search',
|
|
163
163
|
PROGRAMMATIC_TOOL_CALLING = 'run_tools_with_code',
|
|
164
164
|
WEB_SEARCH = 'web_search',
|
|
165
165
|
CONTENT_AND_ARTIFACT = 'content_and_artifact',
|
|
166
166
|
LC_TRANSFER_TO_ = 'lc_transfer_to_',
|
|
167
|
+
/** Delimiter for MCP tools: toolName_mcp_serverName */
|
|
168
|
+
MCP_DELIMITER = '_mcp_',
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
export enum TitleMethod {
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,7 @@ export * from './graphs';
|
|
|
12
12
|
export * from './tools/Calculator';
|
|
13
13
|
export * from './tools/CodeExecutor';
|
|
14
14
|
export * from './tools/ProgrammaticToolCalling';
|
|
15
|
-
export * from './tools/
|
|
15
|
+
export * from './tools/ToolSearch';
|
|
16
16
|
export * from './tools/handlers';
|
|
17
17
|
export * from './tools/search';
|
|
18
18
|
|
|
@@ -41,7 +41,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
41
41
|
return new ToolMessage({
|
|
42
42
|
content: `Found ${discoveredTools.length} tools`,
|
|
43
43
|
tool_call_id: toolCallId,
|
|
44
|
-
name: Constants.
|
|
44
|
+
name: Constants.TOOL_SEARCH,
|
|
45
45
|
artifact: {
|
|
46
46
|
tool_references: discoveredTools.map((name) => ({
|
|
47
47
|
tool_name: name,
|
|
@@ -79,7 +79,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
79
79
|
createAIMessage('Searching...', [
|
|
80
80
|
{
|
|
81
81
|
id: 'call_1',
|
|
82
|
-
name: Constants.
|
|
82
|
+
name: Constants.TOOL_SEARCH,
|
|
83
83
|
args: { pattern: 'database' },
|
|
84
84
|
},
|
|
85
85
|
]),
|
|
@@ -97,12 +97,12 @@ describe('Tool Discovery Functions', () => {
|
|
|
97
97
|
createAIMessage('Searching...', [
|
|
98
98
|
{
|
|
99
99
|
id: 'call_1',
|
|
100
|
-
name: Constants.
|
|
100
|
+
name: Constants.TOOL_SEARCH,
|
|
101
101
|
args: { pattern: 'database' },
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
id: 'call_2',
|
|
105
|
-
name: Constants.
|
|
105
|
+
name: Constants.TOOL_SEARCH,
|
|
106
106
|
args: { pattern: 'file' },
|
|
107
107
|
},
|
|
108
108
|
]),
|
|
@@ -137,7 +137,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
137
137
|
new ToolMessage({
|
|
138
138
|
content: 'Some result',
|
|
139
139
|
tool_call_id: 'orphan_call',
|
|
140
|
-
name: Constants.
|
|
140
|
+
name: Constants.TOOL_SEARCH,
|
|
141
141
|
}),
|
|
142
142
|
];
|
|
143
143
|
|
|
@@ -153,7 +153,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
153
153
|
createAIMessage('Searching...', [
|
|
154
154
|
{
|
|
155
155
|
id: 'old_call',
|
|
156
|
-
name: Constants.
|
|
156
|
+
name: Constants.TOOL_SEARCH,
|
|
157
157
|
args: { pattern: 'old' },
|
|
158
158
|
},
|
|
159
159
|
]),
|
|
@@ -163,7 +163,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
163
163
|
createAIMessage('Searching again...', [
|
|
164
164
|
{
|
|
165
165
|
id: 'new_call',
|
|
166
|
-
name: Constants.
|
|
166
|
+
name: Constants.TOOL_SEARCH,
|
|
167
167
|
args: { pattern: 'new' },
|
|
168
168
|
},
|
|
169
169
|
]),
|
|
@@ -182,7 +182,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
182
182
|
createAIMessage('Working...', [
|
|
183
183
|
{
|
|
184
184
|
id: 'search_call',
|
|
185
|
-
name: Constants.
|
|
185
|
+
name: Constants.TOOL_SEARCH,
|
|
186
186
|
args: { pattern: 'test' },
|
|
187
187
|
},
|
|
188
188
|
{ id: 'other_call', name: 'get_weather', args: { city: 'NYC' } },
|
|
@@ -202,14 +202,14 @@ describe('Tool Discovery Functions', () => {
|
|
|
202
202
|
createAIMessage('Searching...', [
|
|
203
203
|
{
|
|
204
204
|
id: 'call_1',
|
|
205
|
-
name: Constants.
|
|
205
|
+
name: Constants.TOOL_SEARCH,
|
|
206
206
|
args: { pattern: 'xyz' },
|
|
207
207
|
},
|
|
208
208
|
]),
|
|
209
209
|
new ToolMessage({
|
|
210
210
|
content: 'No tools found',
|
|
211
211
|
tool_call_id: 'call_1',
|
|
212
|
-
name: Constants.
|
|
212
|
+
name: Constants.TOOL_SEARCH,
|
|
213
213
|
artifact: {
|
|
214
214
|
tool_references: [],
|
|
215
215
|
metadata: { total_searched: 10, pattern: 'xyz' },
|
|
@@ -228,14 +228,14 @@ describe('Tool Discovery Functions', () => {
|
|
|
228
228
|
createAIMessage('Searching...', [
|
|
229
229
|
{
|
|
230
230
|
id: 'call_1',
|
|
231
|
-
name: Constants.
|
|
231
|
+
name: Constants.TOOL_SEARCH,
|
|
232
232
|
args: { pattern: 'test' },
|
|
233
233
|
},
|
|
234
234
|
]),
|
|
235
235
|
new ToolMessage({
|
|
236
236
|
content: 'Error occurred',
|
|
237
237
|
tool_call_id: 'call_1',
|
|
238
|
-
name: Constants.
|
|
238
|
+
name: Constants.TOOL_SEARCH,
|
|
239
239
|
// No artifact
|
|
240
240
|
}),
|
|
241
241
|
];
|
|
@@ -251,7 +251,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
251
251
|
createAIMessage('Searching...', [
|
|
252
252
|
{
|
|
253
253
|
id: 'call_1',
|
|
254
|
-
name: Constants.
|
|
254
|
+
name: Constants.TOOL_SEARCH,
|
|
255
255
|
args: { pattern: 'test' },
|
|
256
256
|
},
|
|
257
257
|
]),
|
|
@@ -271,7 +271,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
271
271
|
createAIMessage('First search', [
|
|
272
272
|
{
|
|
273
273
|
id: 'first_call',
|
|
274
|
-
name: Constants.
|
|
274
|
+
name: Constants.TOOL_SEARCH,
|
|
275
275
|
args: { pattern: 'first' },
|
|
276
276
|
},
|
|
277
277
|
]),
|
|
@@ -280,7 +280,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
280
280
|
createAIMessage('Second search', [
|
|
281
281
|
{
|
|
282
282
|
id: 'second_call',
|
|
283
|
-
name: Constants.
|
|
283
|
+
name: Constants.TOOL_SEARCH,
|
|
284
284
|
args: { pattern: 'second' },
|
|
285
285
|
},
|
|
286
286
|
]),
|
|
@@ -301,7 +301,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
301
301
|
createAIMessage('Searching...', [
|
|
302
302
|
{
|
|
303
303
|
id: 'call_1',
|
|
304
|
-
name: Constants.
|
|
304
|
+
name: Constants.TOOL_SEARCH,
|
|
305
305
|
args: { pattern: 'test' },
|
|
306
306
|
},
|
|
307
307
|
]),
|
|
@@ -335,7 +335,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
335
335
|
new ToolMessage({
|
|
336
336
|
content: 'Result',
|
|
337
337
|
tool_call_id: 'orphan',
|
|
338
|
-
name: Constants.
|
|
338
|
+
name: Constants.TOOL_SEARCH,
|
|
339
339
|
}),
|
|
340
340
|
];
|
|
341
341
|
|
|
@@ -364,7 +364,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
364
364
|
createAIMessage('Working...', [
|
|
365
365
|
{
|
|
366
366
|
id: 'search_call',
|
|
367
|
-
name: Constants.
|
|
367
|
+
name: Constants.TOOL_SEARCH,
|
|
368
368
|
args: { pattern: 'test' },
|
|
369
369
|
},
|
|
370
370
|
{ id: 'weather_call', name: 'get_weather', args: { city: 'NYC' } },
|
|
@@ -384,7 +384,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
384
384
|
createAIMessage('Searching...', [
|
|
385
385
|
{
|
|
386
386
|
id: 'old_call',
|
|
387
|
-
name: Constants.
|
|
387
|
+
name: Constants.TOOL_SEARCH,
|
|
388
388
|
args: { pattern: 'old' },
|
|
389
389
|
},
|
|
390
390
|
]),
|
|
@@ -410,7 +410,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
410
410
|
createAIMessage('Searching...', [
|
|
411
411
|
{
|
|
412
412
|
id: 'call_1',
|
|
413
|
-
name: Constants.
|
|
413
|
+
name: Constants.TOOL_SEARCH,
|
|
414
414
|
args: { pattern: 'test' },
|
|
415
415
|
},
|
|
416
416
|
]),
|
|
@@ -446,7 +446,7 @@ describe('Tool Discovery Functions', () => {
|
|
|
446
446
|
createAIMessage('Searching...', [
|
|
447
447
|
{
|
|
448
448
|
id: 'call_1',
|
|
449
|
-
name: Constants.
|
|
449
|
+
name: Constants.TOOL_SEARCH,
|
|
450
450
|
args: { pattern: 'test' },
|
|
451
451
|
},
|
|
452
452
|
]),
|
package/src/messages/tools.ts
CHANGED
|
@@ -43,7 +43,7 @@ export function extractToolDiscoveries(messages: BaseMessage[]): string[] {
|
|
|
43
43
|
for (let i = latestAIParentIndex + 1; i < messages.length; i++) {
|
|
44
44
|
const msg = messages[i];
|
|
45
45
|
if (!(msg instanceof ToolMessage)) continue;
|
|
46
|
-
if (msg.name !== Constants.
|
|
46
|
+
if (msg.name !== Constants.TOOL_SEARCH) continue;
|
|
47
47
|
if (!toolCallIds.has(msg.tool_call_id)) continue;
|
|
48
48
|
|
|
49
49
|
// This is a tool search result from the current turn
|
|
@@ -88,7 +88,7 @@ export function hasToolSearchInCurrentTurn(messages: BaseMessage[]): boolean {
|
|
|
88
88
|
const msg = messages[i];
|
|
89
89
|
if (
|
|
90
90
|
msg instanceof ToolMessage &&
|
|
91
|
-
msg.name === Constants.
|
|
91
|
+
msg.name === Constants.TOOL_SEARCH &&
|
|
92
92
|
toolCallIds.has(msg.tool_call_id)
|
|
93
93
|
) {
|
|
94
94
|
return true;
|
|
@@ -23,7 +23,7 @@ import type { RunnableConfig } from '@langchain/core/runnables';
|
|
|
23
23
|
import type * as t from '@/types';
|
|
24
24
|
import { createCodeExecutionTool } from '@/tools/CodeExecutor';
|
|
25
25
|
import { createProgrammaticToolCallingTool } from '@/tools/ProgrammaticToolCalling';
|
|
26
|
-
import {
|
|
26
|
+
import { createToolSearch } from '@/tools/ToolSearch';
|
|
27
27
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
28
28
|
import { getArgs } from '@/scripts/args';
|
|
29
29
|
import { Run } from '@/run';
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Tool registry only needs business logic tools that require filtering.
|
|
43
|
-
* Special tools (execute_code, run_tools_with_code,
|
|
43
|
+
* Special tools (execute_code, run_tools_with_code, tool_search)
|
|
44
44
|
* are always bound directly to the LLM and don't need registry entries.
|
|
45
45
|
*/
|
|
46
46
|
function createAgentToolRegistry(): t.LCToolRegistry {
|
|
@@ -73,7 +73,7 @@ async function main(): Promise<void> {
|
|
|
73
73
|
// Create special tools (PTC, code execution, tool search)
|
|
74
74
|
const codeExecTool = createCodeExecutionTool();
|
|
75
75
|
const ptcTool = createProgrammaticToolCallingTool();
|
|
76
|
-
const toolSearchTool =
|
|
76
|
+
const toolSearchTool = createToolSearch();
|
|
77
77
|
|
|
78
78
|
// Build complete tool list and map
|
|
79
79
|
const allTools = [...mockTools, codeExecTool, ptcTool, toolSearchTool];
|
|
@@ -199,7 +199,7 @@ Use the run_tools_with_code tool to do this efficiently - don't call each tool s
|
|
|
199
199
|
console.log('='.repeat(70));
|
|
200
200
|
console.log('\nKey observations:');
|
|
201
201
|
console.log(
|
|
202
|
-
'1. LLM only sees tools with allowed_callers including "direct" (get_weather, execute_code, run_tools_with_code,
|
|
202
|
+
'1. LLM only sees tools with allowed_callers including "direct" (get_weather, execute_code, run_tools_with_code, tool_search)'
|
|
203
203
|
);
|
|
204
204
|
console.log(
|
|
205
205
|
'2. When PTC is invoked, ToolNode automatically injects programmatic tools (get_team_members, get_expenses, get_weather)'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// src/scripts/
|
|
1
|
+
// src/scripts/tool_search.ts
|
|
2
2
|
/**
|
|
3
3
|
* Test script for the Tool Search Regex tool.
|
|
4
|
-
* Run with: npm run
|
|
4
|
+
* Run with: npm run tool_search
|
|
5
5
|
*
|
|
6
6
|
* Demonstrates runtime registry injection - the tool registry is passed
|
|
7
7
|
* at invocation time, not at initialization time.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { config } from 'dotenv';
|
|
10
10
|
config();
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { createToolSearch } from '@/tools/ToolSearch';
|
|
13
13
|
import type { LCToolRegistry } from '@/types';
|
|
14
14
|
import { createToolSearchToolRegistry } from '@/test/mockTools';
|
|
15
15
|
|
|
@@ -22,7 +22,7 @@ interface RunTestOptions {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async function runTest(
|
|
25
|
-
searchTool: ReturnType<typeof
|
|
25
|
+
searchTool: ReturnType<typeof createToolSearch>,
|
|
26
26
|
testName: string,
|
|
27
27
|
query: string,
|
|
28
28
|
options: RunTestOptions
|
|
@@ -82,7 +82,7 @@ async function main(): Promise<void> {
|
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
console.log('\nCreating Tool Search Regex tool WITH registry for testing...');
|
|
85
|
-
const searchTool =
|
|
85
|
+
const searchTool = createToolSearch({ apiKey, toolRegistry });
|
|
86
86
|
console.log('Tool created successfully!');
|
|
87
87
|
console.log(
|
|
88
88
|
'Note: In production, ToolNode injects toolRegistry via params when invoked through the graph.\n'
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -132,7 +132,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
132
132
|
toolMap,
|
|
133
133
|
toolDefs,
|
|
134
134
|
};
|
|
135
|
-
} else if (call.name === Constants.
|
|
135
|
+
} else if (call.name === Constants.TOOL_SEARCH) {
|
|
136
136
|
invokeParams = {
|
|
137
137
|
...invokeParams,
|
|
138
138
|
toolRegistry: this.toolRegistry,
|