@librechat/agents 3.0.65 → 3.0.67

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 (49) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +12 -10
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +1 -1
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +22 -7
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/main.cjs +8 -7
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/cjs/messages/tools.cjs +2 -2
  10. package/dist/cjs/messages/tools.cjs.map +1 -1
  11. package/dist/cjs/tools/ToolNode.cjs +19 -4
  12. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  13. package/dist/cjs/tools/{ToolSearchRegex.cjs → ToolSearch.cjs} +154 -66
  14. package/dist/cjs/tools/ToolSearch.cjs.map +1 -0
  15. package/dist/esm/agents/AgentContext.mjs +12 -10
  16. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  17. package/dist/esm/common/enum.mjs +1 -1
  18. package/dist/esm/common/enum.mjs.map +1 -1
  19. package/dist/esm/graphs/MultiAgentGraph.mjs +22 -7
  20. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  21. package/dist/esm/main.mjs +1 -1
  22. package/dist/esm/messages/tools.mjs +2 -2
  23. package/dist/esm/messages/tools.mjs.map +1 -1
  24. package/dist/esm/tools/ToolNode.mjs +19 -4
  25. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  26. package/dist/esm/tools/{ToolSearchRegex.mjs → ToolSearch.mjs} +153 -66
  27. package/dist/esm/tools/ToolSearch.mjs.map +1 -0
  28. package/dist/types/agents/AgentContext.d.ts +7 -3
  29. package/dist/types/common/enum.d.ts +1 -1
  30. package/dist/types/graphs/MultiAgentGraph.d.ts +3 -3
  31. package/dist/types/index.d.ts +1 -1
  32. package/dist/types/tools/{ToolSearchRegex.d.ts → ToolSearch.d.ts} +33 -23
  33. package/dist/types/types/tools.d.ts +5 -1
  34. package/package.json +2 -2
  35. package/src/agents/AgentContext.ts +20 -12
  36. package/src/common/enum.ts +1 -1
  37. package/src/graphs/MultiAgentGraph.ts +29 -8
  38. package/src/index.ts +1 -1
  39. package/src/messages/__tests__/tools.test.ts +21 -21
  40. package/src/messages/tools.ts +2 -2
  41. package/src/scripts/programmatic_exec_agent.ts +4 -4
  42. package/src/scripts/{tool_search_regex.ts → tool_search.ts} +5 -5
  43. package/src/tools/ToolNode.ts +23 -5
  44. package/src/tools/{ToolSearchRegex.ts → ToolSearch.ts} +195 -74
  45. package/src/tools/__tests__/{ToolSearchRegex.integration.test.ts → ToolSearch.integration.test.ts} +6 -6
  46. package/src/tools/__tests__/{ToolSearchRegex.test.ts → ToolSearch.test.ts} +212 -3
  47. package/src/types/tools.ts +6 -1
  48. package/dist/cjs/tools/ToolSearchRegex.cjs.map +0 -1
  49. package/dist/esm/tools/ToolSearchRegex.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ToolNode.mjs","sources":["../../../src/tools/ToolNode.ts"],"sourcesContent":["import { ToolCall } from '@langchain/core/messages/tool';\nimport {\n ToolMessage,\n isAIMessage,\n isBaseMessage,\n} from '@langchain/core/messages';\nimport {\n END,\n Send,\n Command,\n isCommand,\n isGraphInterrupt,\n MessagesAnnotation,\n} from '@langchain/langgraph';\nimport type {\n RunnableConfig,\n RunnableToolLike,\n} from '@langchain/core/runnables';\nimport type { BaseMessage, AIMessage } from '@langchain/core/messages';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { RunnableCallable } from '@/utils';\nimport { Constants } from '@/common';\n\n/**\n * Helper to check if a value is a Send object\n */\nfunction isSend(value: unknown): value is Send {\n return value instanceof Send;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<T = any> extends RunnableCallable<T, T> {\n private toolMap: Map<string, StructuredToolInterface | RunnableToolLike>;\n private loadRuntimeTools?: t.ToolRefGenerator;\n handleToolErrors = true;\n trace = false;\n toolCallStepIds?: Map<string, string>;\n errorHandler?: t.ToolNodeConstructorParams['errorHandler'];\n private toolUsageCount: Map<string, number>;\n /** Tool registry for filtering (lazy computation of programmatic maps) */\n private toolRegistry?: t.LCToolRegistry;\n /** Cached programmatic tools (computed once on first PTC call) */\n private programmaticCache?: t.ProgrammaticCache;\n\n constructor({\n tools,\n toolMap,\n name,\n tags,\n errorHandler,\n toolCallStepIds,\n handleToolErrors,\n loadRuntimeTools,\n toolRegistry,\n }: t.ToolNodeConstructorParams) {\n super({ name, tags, func: (input, config) => this.run(input, config) });\n this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));\n this.toolCallStepIds = toolCallStepIds;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.loadRuntimeTools = loadRuntimeTools;\n this.errorHandler = errorHandler;\n this.toolUsageCount = new Map<string, number>();\n this.toolRegistry = toolRegistry;\n }\n\n /**\n * Returns cached programmatic tools, computing once on first access.\n * Single iteration builds both toolMap and toolDefs simultaneously.\n */\n private getProgrammaticTools(): { toolMap: t.ToolMap; toolDefs: t.LCTool[] } {\n if (this.programmaticCache) return this.programmaticCache;\n\n const toolMap: t.ToolMap = new Map();\n const toolDefs: t.LCTool[] = [];\n\n if (this.toolRegistry) {\n for (const [name, toolDef] of this.toolRegistry) {\n if (\n (toolDef.allowed_callers ?? ['direct']).includes('code_execution')\n ) {\n toolDefs.push(toolDef);\n const tool = this.toolMap.get(name);\n if (tool) toolMap.set(name, tool);\n }\n }\n }\n\n this.programmaticCache = { toolMap, toolDefs };\n return this.programmaticCache;\n }\n\n /**\n * Returns a snapshot of the current tool usage counts.\n * @returns A ReadonlyMap where keys are tool names and values are their usage counts.\n */\n public getToolUsageCounts(): ReadonlyMap<string, number> {\n return new Map(this.toolUsageCount); // Return a copy\n }\n\n /**\n * Runs a single tool call with error handling\n */\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig\n ): Promise<BaseMessage | Command> {\n const tool = this.toolMap.get(call.name);\n try {\n if (tool === undefined) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n const turn = this.toolUsageCount.get(call.name) ?? 0;\n this.toolUsageCount.set(call.name, turn + 1);\n const args = call.args;\n const stepId = this.toolCallStepIds?.get(call.id!);\n\n // Build invoke params - LangChain extracts non-schema fields to config.toolCall\n let invokeParams: Record<string, unknown> = {\n ...call,\n args,\n type: 'tool_call',\n stepId,\n turn,\n };\n\n // Inject runtime data for special tools (becomes available at config.toolCall)\n if (call.name === Constants.PROGRAMMATIC_TOOL_CALLING) {\n const { toolMap, toolDefs } = this.getProgrammaticTools();\n invokeParams = {\n ...invokeParams,\n toolMap,\n toolDefs,\n };\n } else if (call.name === Constants.TOOL_SEARCH_REGEX) {\n invokeParams = {\n ...invokeParams,\n toolRegistry: this.toolRegistry,\n };\n }\n\n const output = await tool.invoke(invokeParams, config);\n if (\n (isBaseMessage(output) && output._getType() === 'tool') ||\n isCommand(output)\n ) {\n return output;\n } else {\n return new ToolMessage({\n status: 'success',\n name: tool.name,\n content: typeof output === 'string' ? output : JSON.stringify(output),\n tool_call_id: call.id!,\n });\n }\n } catch (_e: unknown) {\n const e = _e as Error;\n if (!this.handleToolErrors) {\n throw e;\n }\n if (isGraphInterrupt(e)) {\n throw e;\n }\n if (this.errorHandler) {\n try {\n await this.errorHandler(\n {\n error: e,\n id: call.id!,\n name: call.name,\n input: call.args,\n },\n config.metadata\n );\n } catch (handlerError) {\n // eslint-disable-next-line no-console\n console.error('Error in errorHandler:', {\n toolName: call.name,\n toolCallId: call.id,\n toolArgs: call.args,\n stepId: this.toolCallStepIds?.get(call.id!),\n turn: this.toolUsageCount.get(call.name),\n originalError: {\n message: e.message,\n stack: e.stack ?? undefined,\n },\n handlerError:\n handlerError instanceof Error\n ? {\n message: handlerError.message,\n stack: handlerError.stack ?? undefined,\n }\n : {\n message: String(handlerError),\n stack: undefined,\n },\n });\n }\n }\n return new ToolMessage({\n status: 'error',\n content: `Error: ${e.message}\\n Please fix your mistakes.`,\n name: call.name,\n tool_call_id: call.id ?? '',\n });\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected async run(input: any, config: RunnableConfig): Promise<T> {\n let outputs: (BaseMessage | Command)[];\n\n if (this.isSendInput(input)) {\n outputs = [await this.runTool(input.lg_tool_call, config)];\n } else {\n let messages: BaseMessage[];\n if (Array.isArray(input)) {\n messages = input;\n } else if (this.isMessagesState(input)) {\n messages = input.messages;\n } else {\n throw new Error(\n 'ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.'\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg._getType() === 'tool')\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n if (isAIMessage(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (aiMessage == null || !isAIMessage(aiMessage)) {\n throw new Error('ToolNode only accepts AIMessages as input.');\n }\n\n if (this.loadRuntimeTools) {\n const { tools, toolMap } = this.loadRuntimeTools(\n aiMessage.tool_calls ?? []\n );\n this.toolMap =\n toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));\n this.programmaticCache = undefined; // Invalidate cache on toolMap change\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => {\n /**\n * Filter out:\n * 1. Already processed tool calls (present in toolMessageIds)\n * 2. Server tool calls (e.g., web_search with IDs starting with 'srvtoolu_')\n * which are executed by the provider's API and don't require invocation\n */\n return (\n (call.id == null || !toolMessageIds.has(call.id)) &&\n !(call.id?.startsWith('srvtoolu_') ?? false)\n );\n })\n .map((call) => this.runTool(call, config)) ?? []\n );\n }\n\n if (!outputs.some(isCommand)) {\n return (Array.isArray(input) ? outputs : { messages: outputs }) as T;\n }\n\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n /**\n * Collect handoff commands (Commands with string goto and Command.PARENT)\n * for potential parallel handoff aggregation\n */\n const handoffCommands: Command[] = [];\n const nonCommandOutputs: BaseMessage[] = [];\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send): send is Send => isSend(send))\n ) {\n /** Aggregate Send-based commands */\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else if (output.graph === Command.PARENT) {\n /**\n * Handoff Command with destination.\n * Handle both string ('agent') and array (['agent']) formats.\n * Collect for potential parallel aggregation.\n */\n const goto = output.goto;\n const isSingleStringDest = typeof goto === 'string';\n const isSingleArrayDest =\n Array.isArray(goto) &&\n goto.length === 1 &&\n typeof goto[0] === 'string';\n\n if (isSingleStringDest || isSingleArrayDest) {\n handoffCommands.push(output);\n } else {\n /** Multi-destination or other command - pass through */\n combinedOutputs.push(output);\n }\n } else {\n /** Other commands - pass through */\n combinedOutputs.push(output);\n }\n } else {\n nonCommandOutputs.push(output);\n combinedOutputs.push(\n Array.isArray(input) ? [output] : { messages: [output] }\n );\n }\n }\n\n /**\n * Handle handoff commands - convert to Send objects for parallel execution\n * when multiple handoffs are requested\n */\n if (handoffCommands.length > 1) {\n /**\n * Multiple parallel handoffs - convert to Send objects.\n * Each Send carries its own state with the appropriate messages.\n * This enables LLM-initiated parallel execution when calling multiple\n * transfer tools simultaneously.\n */\n const sends = handoffCommands.map((cmd) => {\n /** Extract destination - handle both string and array formats */\n const goto = cmd.goto;\n const destination =\n typeof goto === 'string' ? goto : (goto as string[])[0];\n return new Send(destination, cmd.update);\n });\n\n const parallelCommand = new Command({\n graph: Command.PARENT,\n goto: sends,\n });\n combinedOutputs.push(parallelCommand);\n } else if (handoffCommands.length === 1) {\n /** Single handoff - pass through as-is */\n combinedOutputs.push(handoffCommands[0]);\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as T;\n }\n\n private isSendInput(input: unknown): input is { lg_tool_call: ToolCall } {\n return (\n typeof input === 'object' && input != null && 'lg_tool_call' in input\n );\n }\n\n private isMessagesState(\n input: unknown\n ): input is { messages: BaseMessage[] } {\n return (\n typeof input === 'object' &&\n input != null &&\n 'messages' in input &&\n Array.isArray((input as { messages: unknown }).messages) &&\n (input as { messages: unknown[] }).messages.every(isBaseMessage)\n );\n }\n}\n\nfunction areToolCallsInvoked(\n message: AIMessage,\n invokedToolIds?: Set<string>\n): boolean {\n if (!invokedToolIds || invokedToolIds.size === 0) return false;\n return (\n message.tool_calls?.every(\n (toolCall) => toolCall.id != null && invokedToolIds.has(toolCall.id)\n ) ?? false\n );\n}\n\nexport function toolsCondition<T extends string>(\n state: BaseMessage[] | typeof MessagesAnnotation.State,\n toolNode: T,\n invokedToolIds?: Set<string>\n): T | typeof END {\n const message: AIMessage = Array.isArray(state)\n ? state[state.length - 1]\n : state.messages[state.messages.length - 1];\n\n if (\n 'tool_calls' in message &&\n (message.tool_calls?.length ?? 0) > 0 &&\n !areToolCallsInvoked(message, invokedToolIds)\n ) {\n return toolNode;\n } else {\n return END;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolNode.mjs","sources":["../../../src/tools/ToolNode.ts"],"sourcesContent":["import { ToolCall } from '@langchain/core/messages/tool';\nimport {\n ToolMessage,\n isAIMessage,\n isBaseMessage,\n} from '@langchain/core/messages';\nimport {\n END,\n Send,\n Command,\n isCommand,\n isGraphInterrupt,\n MessagesAnnotation,\n} from '@langchain/langgraph';\nimport type {\n RunnableConfig,\n RunnableToolLike,\n} from '@langchain/core/runnables';\nimport type { BaseMessage, AIMessage } from '@langchain/core/messages';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { RunnableCallable } from '@/utils';\nimport { Constants } from '@/common';\n\n/**\n * Helper to check if a value is a Send object\n */\nfunction isSend(value: unknown): value is Send {\n return value instanceof Send;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<T = any> extends RunnableCallable<T, T> {\n private toolMap: Map<string, StructuredToolInterface | RunnableToolLike>;\n private loadRuntimeTools?: t.ToolRefGenerator;\n handleToolErrors = true;\n trace = false;\n toolCallStepIds?: Map<string, string>;\n errorHandler?: t.ToolNodeConstructorParams['errorHandler'];\n private toolUsageCount: Map<string, number>;\n /** Tool registry for filtering (lazy computation of programmatic maps) */\n private toolRegistry?: t.LCToolRegistry;\n /** Cached programmatic tools (computed once on first PTC call) */\n private programmaticCache?: t.ProgrammaticCache;\n\n constructor({\n tools,\n toolMap,\n name,\n tags,\n errorHandler,\n toolCallStepIds,\n handleToolErrors,\n loadRuntimeTools,\n toolRegistry,\n }: t.ToolNodeConstructorParams) {\n super({ name, tags, func: (input, config) => this.run(input, config) });\n this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));\n this.toolCallStepIds = toolCallStepIds;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.loadRuntimeTools = loadRuntimeTools;\n this.errorHandler = errorHandler;\n this.toolUsageCount = new Map<string, number>();\n this.toolRegistry = toolRegistry;\n }\n\n /**\n * Returns cached programmatic tools, computing once on first access.\n * Single iteration builds both toolMap and toolDefs simultaneously.\n */\n private getProgrammaticTools(): { toolMap: t.ToolMap; toolDefs: t.LCTool[] } {\n if (this.programmaticCache) return this.programmaticCache;\n\n const toolMap: t.ToolMap = new Map();\n const toolDefs: t.LCTool[] = [];\n\n if (this.toolRegistry) {\n for (const [name, toolDef] of this.toolRegistry) {\n if (\n (toolDef.allowed_callers ?? ['direct']).includes('code_execution')\n ) {\n toolDefs.push(toolDef);\n const tool = this.toolMap.get(name);\n if (tool) toolMap.set(name, tool);\n }\n }\n }\n\n this.programmaticCache = { toolMap, toolDefs };\n return this.programmaticCache;\n }\n\n /**\n * Returns a snapshot of the current tool usage counts.\n * @returns A ReadonlyMap where keys are tool names and values are their usage counts.\n */\n public getToolUsageCounts(): ReadonlyMap<string, number> {\n return new Map(this.toolUsageCount); // Return a copy\n }\n\n /**\n * Runs a single tool call with error handling\n */\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig\n ): Promise<BaseMessage | Command> {\n const tool = this.toolMap.get(call.name);\n try {\n if (tool === undefined) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n const turn = this.toolUsageCount.get(call.name) ?? 0;\n this.toolUsageCount.set(call.name, turn + 1);\n const args = call.args;\n const stepId = this.toolCallStepIds?.get(call.id!);\n\n // Build invoke params - LangChain extracts non-schema fields to config.toolCall\n let invokeParams: Record<string, unknown> = {\n ...call,\n args,\n type: 'tool_call',\n stepId,\n turn,\n };\n\n // Inject runtime data for special tools (becomes available at config.toolCall)\n if (call.name === Constants.PROGRAMMATIC_TOOL_CALLING) {\n const { toolMap, toolDefs } = this.getProgrammaticTools();\n invokeParams = {\n ...invokeParams,\n toolMap,\n toolDefs,\n };\n } else if (call.name === Constants.TOOL_SEARCH) {\n invokeParams = {\n ...invokeParams,\n toolRegistry: this.toolRegistry,\n };\n }\n\n const output = await tool.invoke(invokeParams, config);\n if (\n (isBaseMessage(output) && output._getType() === 'tool') ||\n isCommand(output)\n ) {\n return output;\n } else {\n return new ToolMessage({\n status: 'success',\n name: tool.name,\n content: typeof output === 'string' ? output : JSON.stringify(output),\n tool_call_id: call.id!,\n });\n }\n } catch (_e: unknown) {\n const e = _e as Error;\n if (!this.handleToolErrors) {\n throw e;\n }\n if (isGraphInterrupt(e)) {\n throw e;\n }\n if (this.errorHandler) {\n try {\n await this.errorHandler(\n {\n error: e,\n id: call.id!,\n name: call.name,\n input: call.args,\n },\n config.metadata\n );\n } catch (handlerError) {\n // eslint-disable-next-line no-console\n console.error('Error in errorHandler:', {\n toolName: call.name,\n toolCallId: call.id,\n toolArgs: call.args,\n stepId: this.toolCallStepIds?.get(call.id!),\n turn: this.toolUsageCount.get(call.name),\n originalError: {\n message: e.message,\n stack: e.stack ?? undefined,\n },\n handlerError:\n handlerError instanceof Error\n ? {\n message: handlerError.message,\n stack: handlerError.stack ?? undefined,\n }\n : {\n message: String(handlerError),\n stack: undefined,\n },\n });\n }\n }\n return new ToolMessage({\n status: 'error',\n content: `Error: ${e.message}\\n Please fix your mistakes.`,\n name: call.name,\n tool_call_id: call.id ?? '',\n });\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected async run(input: any, config: RunnableConfig): Promise<T> {\n let outputs: (BaseMessage | Command)[];\n\n if (this.isSendInput(input)) {\n outputs = [await this.runTool(input.lg_tool_call, config)];\n } else {\n let messages: BaseMessage[];\n if (Array.isArray(input)) {\n messages = input;\n } else if (this.isMessagesState(input)) {\n messages = input.messages;\n } else {\n throw new Error(\n 'ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.'\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg._getType() === 'tool')\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n if (isAIMessage(message)) {\n aiMessage = message;\n break;\n }\n }\n\n if (aiMessage == null || !isAIMessage(aiMessage)) {\n throw new Error('ToolNode only accepts AIMessages as input.');\n }\n\n if (this.loadRuntimeTools) {\n const { tools, toolMap } = this.loadRuntimeTools(\n aiMessage.tool_calls ?? []\n );\n this.toolMap =\n toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));\n this.programmaticCache = undefined; // Invalidate cache on toolMap change\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => {\n /**\n * Filter out:\n * 1. Already processed tool calls (present in toolMessageIds)\n * 2. Server tool calls (e.g., web_search with IDs starting with 'srvtoolu_')\n * which are executed by the provider's API and don't require invocation\n */\n return (\n (call.id == null || !toolMessageIds.has(call.id)) &&\n !(call.id?.startsWith('srvtoolu_') ?? false)\n );\n })\n .map((call) => this.runTool(call, config)) ?? []\n );\n }\n\n if (!outputs.some(isCommand)) {\n return (Array.isArray(input) ? outputs : { messages: outputs }) as T;\n }\n\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n /**\n * Collect handoff commands (Commands with string goto and Command.PARENT)\n * for potential parallel handoff aggregation\n */\n const handoffCommands: Command[] = [];\n const nonCommandOutputs: BaseMessage[] = [];\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send): send is Send => isSend(send))\n ) {\n /** Aggregate Send-based commands */\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else if (output.graph === Command.PARENT) {\n /**\n * Handoff Command with destination.\n * Handle both string ('agent') and array (['agent']) formats.\n * Collect for potential parallel aggregation.\n */\n const goto = output.goto;\n const isSingleStringDest = typeof goto === 'string';\n const isSingleArrayDest =\n Array.isArray(goto) &&\n goto.length === 1 &&\n typeof goto[0] === 'string';\n\n if (isSingleStringDest || isSingleArrayDest) {\n handoffCommands.push(output);\n } else {\n /** Multi-destination or other command - pass through */\n combinedOutputs.push(output);\n }\n } else {\n /** Other commands - pass through */\n combinedOutputs.push(output);\n }\n } else {\n nonCommandOutputs.push(output);\n combinedOutputs.push(\n Array.isArray(input) ? [output] : { messages: [output] }\n );\n }\n }\n\n /**\n * Handle handoff commands - convert to Send objects for parallel execution\n * when multiple handoffs are requested\n */\n if (handoffCommands.length > 1) {\n /**\n * Multiple parallel handoffs - convert to Send objects.\n * Each Send carries its own state with the appropriate messages.\n * This enables LLM-initiated parallel execution when calling multiple\n * transfer tools simultaneously.\n */\n\n /** Collect all destinations for sibling tracking */\n const allDestinations = handoffCommands.map((cmd) => {\n const goto = cmd.goto;\n return typeof goto === 'string' ? goto : (goto as string[])[0];\n });\n\n const sends = handoffCommands.map((cmd, idx) => {\n const destination = allDestinations[idx];\n /** Get siblings (other destinations, not this one) */\n const siblings = allDestinations.filter((d) => d !== destination);\n\n /** Add siblings to ToolMessage additional_kwargs */\n const update = cmd.update as { messages?: BaseMessage[] } | undefined;\n if (update && update.messages) {\n for (const msg of update.messages) {\n if (msg.getType() === 'tool') {\n (msg as ToolMessage).additional_kwargs.handoff_parallel_siblings =\n siblings;\n }\n }\n }\n\n return new Send(destination, cmd.update);\n });\n\n const parallelCommand = new Command({\n graph: Command.PARENT,\n goto: sends,\n });\n combinedOutputs.push(parallelCommand);\n } else if (handoffCommands.length === 1) {\n /** Single handoff - pass through as-is */\n combinedOutputs.push(handoffCommands[0]);\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as T;\n }\n\n private isSendInput(input: unknown): input is { lg_tool_call: ToolCall } {\n return (\n typeof input === 'object' && input != null && 'lg_tool_call' in input\n );\n }\n\n private isMessagesState(\n input: unknown\n ): input is { messages: BaseMessage[] } {\n return (\n typeof input === 'object' &&\n input != null &&\n 'messages' in input &&\n Array.isArray((input as { messages: unknown }).messages) &&\n (input as { messages: unknown[] }).messages.every(isBaseMessage)\n );\n }\n}\n\nfunction areToolCallsInvoked(\n message: AIMessage,\n invokedToolIds?: Set<string>\n): boolean {\n if (!invokedToolIds || invokedToolIds.size === 0) return false;\n return (\n message.tool_calls?.every(\n (toolCall) => toolCall.id != null && invokedToolIds.has(toolCall.id)\n ) ?? false\n );\n}\n\nexport function toolsCondition<T extends string>(\n state: BaseMessage[] | typeof MessagesAnnotation.State,\n toolNode: T,\n invokedToolIds?: Set<string>\n): T | typeof END {\n const message: AIMessage = Array.isArray(state)\n ? state[state.length - 1]\n : state.messages[state.messages.length - 1];\n\n if (\n 'tool_calls' in message &&\n (message.tool_calls?.length ?? 0) > 0 &&\n !areToolCallsInvoked(message, invokedToolIds)\n ) {\n return toolNode;\n } else {\n return END;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ import { tool } from '@langchain/core/tools';
7
7
  import { getCodeBaseURL } from './CodeExecutor.mjs';
8
8
  import { EnvVar, Constants } from '../common/enum.mjs';
9
9
 
10
- // src/tools/ToolSearchRegex.ts
10
+ // src/tools/ToolSearch.ts
11
11
  config();
12
12
  /** Maximum allowed regex pattern length */
13
13
  const MAX_PATTERN_LENGTH = 200;
@@ -15,26 +15,32 @@ const MAX_PATTERN_LENGTH = 200;
15
15
  const MAX_REGEX_COMPLEXITY = 5;
16
16
  /** Default search timeout in milliseconds */
17
17
  const SEARCH_TIMEOUT = 5000;
18
- const ToolSearchRegexSchema = z.object({
19
- query: z
20
- .string()
21
- .min(1)
22
- .max(MAX_PATTERN_LENGTH)
23
- .describe('Regex pattern to search tool names and descriptions. Special regex characters will be sanitized for safety.'),
24
- fields: z
25
- .array(z.enum(['name', 'description', 'parameters']))
26
- .optional()
27
- .default(['name', 'description'])
28
- .describe('Which fields to search. Default: name and description'),
29
- max_results: z
30
- .number()
31
- .int()
32
- .min(1)
33
- .max(50)
34
- .optional()
35
- .default(10)
36
- .describe('Maximum number of matching tools to return'),
37
- });
18
+ /**
19
+ * Creates the Zod schema with dynamic query description based on mode.
20
+ * @param mode - The search mode determining query interpretation
21
+ * @returns Zod schema for tool search parameters
22
+ */
23
+ function createToolSearchSchema(mode) {
24
+ const queryDescription = mode === 'local'
25
+ ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching.'
26
+ : 'Regex pattern to search tool names and descriptions. Special regex characters will be sanitized for safety.';
27
+ return z.object({
28
+ query: z.string().min(1).max(MAX_PATTERN_LENGTH).describe(queryDescription),
29
+ fields: z
30
+ .array(z.enum(['name', 'description', 'parameters']))
31
+ .optional()
32
+ .default(['name', 'description'])
33
+ .describe('Which fields to search. Default: name and description'),
34
+ max_results: z
35
+ .number()
36
+ .int()
37
+ .min(1)
38
+ .max(50)
39
+ .optional()
40
+ .default(10)
41
+ .describe('Maximum number of matching tools to return'),
42
+ });
43
+ }
38
44
  /**
39
45
  * Escapes special regex characters in a string to use as a literal pattern.
40
46
  * @param pattern - The string to escape
@@ -145,6 +151,67 @@ function simplifyParametersForSearch(parameters) {
145
151
  }
146
152
  return { type: parameters.type };
147
153
  }
154
+ /**
155
+ * Performs safe local substring search without regex.
156
+ * Uses case-insensitive String.includes() for complete safety against ReDoS.
157
+ * @param tools - Array of tool metadata to search
158
+ * @param query - The search term (treated as literal substring)
159
+ * @param fields - Which fields to search
160
+ * @param maxResults - Maximum results to return
161
+ * @returns Search response with matching tools
162
+ */
163
+ function performLocalSearch(tools, query, fields, maxResults) {
164
+ const lowerQuery = query.toLowerCase();
165
+ const results = [];
166
+ for (const tool of tools) {
167
+ let bestScore = 0;
168
+ let matchedField = '';
169
+ let snippet = '';
170
+ if (fields.includes('name')) {
171
+ const lowerName = tool.name.toLowerCase();
172
+ if (lowerName.includes(lowerQuery)) {
173
+ const isExactMatch = lowerName === lowerQuery;
174
+ const startsWithQuery = lowerName.startsWith(lowerQuery);
175
+ bestScore = isExactMatch ? 1.0 : startsWithQuery ? 0.95 : 0.85;
176
+ matchedField = 'name';
177
+ snippet = tool.name;
178
+ }
179
+ }
180
+ if (fields.includes('description') && tool.description) {
181
+ const lowerDesc = tool.description.toLowerCase();
182
+ if (lowerDesc.includes(lowerQuery) && bestScore === 0) {
183
+ bestScore = 0.7;
184
+ matchedField = 'description';
185
+ snippet = tool.description.substring(0, 100);
186
+ }
187
+ }
188
+ if (fields.includes('parameters') && tool.parameters?.properties) {
189
+ const paramNames = Object.keys(tool.parameters.properties)
190
+ .join(' ')
191
+ .toLowerCase();
192
+ if (paramNames.includes(lowerQuery) && bestScore === 0) {
193
+ bestScore = 0.55;
194
+ matchedField = 'parameters';
195
+ snippet = Object.keys(tool.parameters.properties).join(' ');
196
+ }
197
+ }
198
+ if (bestScore > 0) {
199
+ results.push({
200
+ tool_name: tool.name,
201
+ match_score: bestScore,
202
+ matched_field: matchedField,
203
+ snippet,
204
+ });
205
+ }
206
+ }
207
+ results.sort((a, b) => b.match_score - a.match_score);
208
+ const topResults = results.slice(0, maxResults);
209
+ return {
210
+ tool_references: topResults,
211
+ total_tools_searched: tools.length,
212
+ pattern_used: query,
213
+ };
214
+ }
148
215
  /**
149
216
  * Generates the JavaScript search script to be executed in the sandbox.
150
217
  * Uses plain JavaScript for maximum compatibility with the Code API.
@@ -268,11 +335,15 @@ function formatSearchResults(searchResponse) {
268
335
  return response;
269
336
  }
270
337
  /**
271
- * Creates a Tool Search Regex tool for discovering tools from a large registry.
338
+ * Creates a Tool Search tool for discovering tools from a large registry.
272
339
  *
273
340
  * This tool enables AI agents to dynamically discover tools from a large library
274
341
  * without loading all tool definitions into the LLM context window. The agent
275
- * can search for relevant tools on-demand using regex patterns.
342
+ * can search for relevant tools on-demand.
343
+ *
344
+ * **Modes:**
345
+ * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.
346
+ * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.
276
347
  *
277
348
  * The tool registry can be provided either:
278
349
  * 1. At initialization time via params.toolRegistry
@@ -282,30 +353,42 @@ function formatSearchResults(searchResponse) {
282
353
  * @returns A LangChain DynamicStructuredTool for tool searching
283
354
  *
284
355
  * @example
285
- * // Option 1: Registry at initialization
286
- * const tool = createToolSearchRegexTool({ apiKey, toolRegistry });
287
- * await tool.invoke({ query: 'expense' });
356
+ * // Option 1: Code interpreter mode (regex via sandbox)
357
+ * const tool = createToolSearch({ apiKey, toolRegistry });
358
+ * await tool.invoke({ query: 'expense.*report' });
288
359
  *
289
360
  * @example
290
- * // Option 2: Registry at runtime
291
- * const tool = createToolSearchRegexTool({ apiKey });
292
- * await tool.invoke(
293
- * { query: 'expense' },
294
- * { configurable: { toolRegistry, onlyDeferred: true } }
295
- * );
361
+ * // Option 2: Local mode (safe substring search, no API key needed)
362
+ * const tool = createToolSearch({ mode: 'local', toolRegistry });
363
+ * await tool.invoke({ query: 'expense' });
296
364
  */
297
- function createToolSearchRegexTool(initParams = {}) {
298
- const apiKey = initParams[EnvVar.CODE_API_KEY] ??
299
- initParams.apiKey ??
300
- getEnvironmentVariable(EnvVar.CODE_API_KEY) ??
301
- '';
302
- if (!apiKey) {
303
- throw new Error('No API key provided for tool search regex tool.');
365
+ function createToolSearch(initParams = {}) {
366
+ const mode = initParams.mode ?? 'code_interpreter';
367
+ const defaultOnlyDeferred = initParams.onlyDeferred ?? true;
368
+ const schema = createToolSearchSchema(mode);
369
+ const apiKey = mode === 'code_interpreter'
370
+ ? (initParams[EnvVar.CODE_API_KEY] ??
371
+ initParams.apiKey ??
372
+ getEnvironmentVariable(EnvVar.CODE_API_KEY) ??
373
+ '')
374
+ : '';
375
+ if (mode === 'code_interpreter' && !apiKey) {
376
+ throw new Error('No API key provided for tool search in code_interpreter mode. Use mode: "local" to search without an API key.');
304
377
  }
305
378
  const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();
306
379
  const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
307
- const defaultOnlyDeferred = initParams.onlyDeferred ?? true;
308
- const description = `
380
+ const description = mode === 'local'
381
+ ? `
382
+ Searches through available tools to find ones matching your search term.
383
+
384
+ Usage:
385
+ - Provide a search term to find in tool names and descriptions.
386
+ - Uses case-insensitive substring matching (fast and safe).
387
+ - Use this when you need to discover tools for a specific task.
388
+ - Results include tool names, match quality scores, and snippets showing where the match occurred.
389
+ - Higher scores (0.95+) indicate name matches, medium scores (0.70+) indicate description matches.
390
+ `.trim()
391
+ : `
309
392
  Searches through available tools to find ones matching your query pattern.
310
393
 
311
394
  Usage:
@@ -316,27 +399,19 @@ Usage:
316
399
  `.trim();
317
400
  return tool(async (params, config) => {
318
401
  const { query, fields = ['name', 'description'], max_results = 10, } = params;
319
- // Extra params injected by ToolNode (follows web_search pattern)
320
402
  const { toolRegistry: paramToolRegistry, onlyDeferred: paramOnlyDeferred, } = config.toolCall ?? {};
321
- const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);
322
- let warningMessage = '';
323
- if (wasEscaped) {
324
- warningMessage =
325
- 'Note: The provided pattern was converted to a literal search for safety.\n\n';
326
- }
327
- // Priority: ToolNode injection (via config.toolCall) > initialization params
328
403
  const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;
329
404
  const onlyDeferred = paramOnlyDeferred !== undefined
330
405
  ? paramOnlyDeferred
331
406
  : defaultOnlyDeferred;
332
407
  if (toolRegistry == null) {
333
408
  return [
334
- `${warningMessage}Error: No tool registry provided. Configure toolRegistry at agent level or initialization.`,
409
+ 'Error: No tool registry provided. Configure toolRegistry at agent level or initialization.',
335
410
  {
336
411
  tool_references: [],
337
412
  metadata: {
338
413
  total_searched: 0,
339
- pattern: sanitizedPattern,
414
+ pattern: query,
340
415
  error: 'No tool registry provided',
341
416
  },
342
417
  },
@@ -344,12 +419,7 @@ Usage:
344
419
  }
345
420
  const toolsArray = Array.from(toolRegistry.values());
346
421
  const deferredTools = toolsArray
347
- .filter((lcTool) => {
348
- if (onlyDeferred === true) {
349
- return lcTool.defer_loading === true;
350
- }
351
- return true;
352
- })
422
+ .filter((lcTool) => onlyDeferred === true ? lcTool.defer_loading === true : true)
353
423
  .map((lcTool) => ({
354
424
  name: lcTool.name,
355
425
  description: lcTool.description ?? '',
@@ -357,16 +427,33 @@ Usage:
357
427
  }));
358
428
  if (deferredTools.length === 0) {
359
429
  return [
360
- `${warningMessage}No tools available to search. The tool registry is empty or no deferred tools are registered.`,
430
+ 'No tools available to search. The tool registry is empty or no deferred tools are registered.',
361
431
  {
362
432
  tool_references: [],
433
+ metadata: { total_searched: 0, pattern: query },
434
+ },
435
+ ];
436
+ }
437
+ if (mode === 'local') {
438
+ const searchResponse = performLocalSearch(deferredTools, query, fields, max_results);
439
+ const formattedOutput = formatSearchResults(searchResponse);
440
+ return [
441
+ formattedOutput,
442
+ {
443
+ tool_references: searchResponse.tool_references,
363
444
  metadata: {
364
- total_searched: 0,
365
- pattern: sanitizedPattern,
445
+ total_searched: searchResponse.total_tools_searched,
446
+ pattern: searchResponse.pattern_used,
366
447
  },
367
448
  },
368
449
  ];
369
450
  }
451
+ const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);
452
+ let warningMessage = '';
453
+ if (wasEscaped) {
454
+ warningMessage =
455
+ 'Note: The provided pattern was converted to a literal search for safety.\n\n';
456
+ }
370
457
  const searchScript = generateSearchScript(deferredTools, fields, max_results, sanitizedPattern);
371
458
  const postData = {
372
459
  lang: 'js',
@@ -393,7 +480,7 @@ Usage:
393
480
  const result = await response.json();
394
481
  if (result.stderr && result.stderr.trim()) {
395
482
  // eslint-disable-next-line no-console
396
- console.warn('[ToolSearchRegex] stderr:', result.stderr);
483
+ console.warn('[ToolSearch] stderr:', result.stderr);
397
484
  }
398
485
  if (!result.stdout || !result.stdout.trim()) {
399
486
  return [
@@ -422,7 +509,7 @@ Usage:
422
509
  }
423
510
  catch (error) {
424
511
  // eslint-disable-next-line no-console
425
- console.error('[ToolSearchRegex] Error:', error);
512
+ console.error('[ToolSearch] Error:', error);
426
513
  const errorMessage = error instanceof Error ? error.message : String(error);
427
514
  return [
428
515
  `Tool search failed: ${errorMessage}\n\nSuggestion: Try a simpler search pattern or search for specific tool names.`,
@@ -437,12 +524,12 @@ Usage:
437
524
  ];
438
525
  }
439
526
  }, {
440
- name: Constants.TOOL_SEARCH_REGEX,
527
+ name: Constants.TOOL_SEARCH,
441
528
  description,
442
- schema: ToolSearchRegexSchema,
529
+ schema,
443
530
  responseFormat: Constants.CONTENT_AND_ARTIFACT,
444
531
  });
445
532
  }
446
533
 
447
- export { countNestedGroups, createToolSearchRegexTool, escapeRegexSpecialChars, hasNestedQuantifiers, isDangerousPattern, sanitizeRegex };
448
- //# sourceMappingURL=ToolSearchRegex.mjs.map
534
+ export { countNestedGroups, createToolSearch, escapeRegexSpecialChars, hasNestedQuantifiers, isDangerousPattern, performLocalSearch, sanitizeRegex };
535
+ //# sourceMappingURL=ToolSearch.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolSearch.mjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport { config } from 'dotenv';\nimport fetch, { RequestInit } from 'node-fetch';\nimport { HttpsProxyAgent } from 'https-proxy-agent';\nimport { getEnvironmentVariable } from '@langchain/core/utils/env';\nimport { tool, DynamicStructuredTool } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport { getCodeBaseURL } from './CodeExecutor';\nimport { EnvVar, Constants } from '@/common';\n\nconfig();\n\n/** Maximum allowed regex pattern length */\nconst MAX_PATTERN_LENGTH = 200;\n\n/** Maximum allowed regex nesting depth */\nconst MAX_REGEX_COMPLEXITY = 5;\n\n/** Default search timeout in milliseconds */\nconst SEARCH_TIMEOUT = 5000;\n\n/** Zod schema type for tool search parameters */\ntype ToolSearchSchema = z.ZodObject<{\n query: z.ZodString;\n fields: z.ZodDefault<\n z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>\n >;\n max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;\n}>;\n\n/**\n * Creates the Zod schema with dynamic query description based on mode.\n * @param mode - The search mode determining query interpretation\n * @returns Zod schema for tool search parameters\n */\nfunction createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema {\n const queryDescription =\n mode === 'local'\n ? 'Search term to find in tool names and descriptions. Case-insensitive substring matching.'\n : 'Regex pattern to search tool names and descriptions. Special regex characters will be sanitized for safety.';\n\n return z.object({\n query: z.string().min(1).max(MAX_PATTERN_LENGTH).describe(queryDescription),\n fields: z\n .array(z.enum(['name', 'description', 'parameters']))\n .optional()\n .default(['name', 'description'])\n .describe('Which fields to search. Default: name and description'),\n max_results: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .default(10)\n .describe('Maximum number of matching tools to return'),\n });\n}\n\n/**\n * Escapes special regex characters in a string to use as a literal pattern.\n * @param pattern - The string to escape\n * @returns The escaped string safe for use in a RegExp\n */\nfunction escapeRegexSpecialChars(pattern: string): string {\n return pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Counts the maximum nesting depth of groups in a regex pattern.\n * @param pattern - The regex pattern to analyze\n * @returns The maximum nesting depth\n */\nfunction countNestedGroups(pattern: string): number {\n let maxDepth = 0;\n let currentDepth = 0;\n\n for (let i = 0; i < pattern.length; i++) {\n if (pattern[i] === '(' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth++;\n maxDepth = Math.max(maxDepth, currentDepth);\n } else if (pattern[i] === ')' && (i === 0 || pattern[i - 1] !== '\\\\')) {\n currentDepth = Math.max(0, currentDepth - 1);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Detects nested quantifiers that can cause catastrophic backtracking.\n * Patterns like (a+)+, (a*)*, (a+)*, etc.\n * @param pattern - The regex pattern to check\n * @returns True if nested quantifiers are detected\n */\nfunction hasNestedQuantifiers(pattern: string): boolean {\n const nestedQuantifierPattern = /\\([^)]*[+*][^)]*\\)[+*?]/;\n return nestedQuantifierPattern.test(pattern);\n}\n\n/**\n * Checks if a regex pattern contains potentially dangerous constructs.\n * @param pattern - The regex pattern to validate\n * @returns True if the pattern is dangerous\n */\nfunction isDangerousPattern(pattern: string): boolean {\n if (hasNestedQuantifiers(pattern)) {\n return true;\n }\n\n if (countNestedGroups(pattern) > MAX_REGEX_COMPLEXITY) {\n return true;\n }\n\n const dangerousPatterns = [\n /\\.\\{1000,\\}/, // Excessive wildcards\n /\\(\\?=\\.\\{100,\\}\\)/, // Runaway lookaheads\n /\\([^)]*\\|\\s*\\){20,}/, // Excessive alternation (rough check)\n /\\(\\.\\*\\)\\+/, // (.*)+\n /\\(\\.\\+\\)\\+/, // (.+)+\n /\\(\\.\\*\\)\\*/, // (.*)*\n /\\(\\.\\+\\)\\*/, // (.+)*\n ];\n\n for (const dangerous of dangerousPatterns) {\n if (dangerous.test(pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Sanitizes a regex pattern for safe execution.\n * If the pattern is dangerous, it will be escaped to a literal string search.\n * @param pattern - The regex pattern to sanitize\n * @returns Object containing the safe pattern and whether it was escaped\n */\nfunction sanitizeRegex(pattern: string): { safe: string; wasEscaped: boolean } {\n if (isDangerousPattern(pattern)) {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n\n try {\n new RegExp(pattern);\n return { safe: pattern, wasEscaped: false };\n } catch {\n return {\n safe: escapeRegexSpecialChars(pattern),\n wasEscaped: true,\n };\n }\n}\n\n/**\n * Simplifies tool parameters for search purposes.\n * Extracts only the essential structure needed for parameter name searching.\n * @param parameters - The tool's JSON schema parameters\n * @returns Simplified parameters object\n */\nfunction simplifyParametersForSearch(\n parameters?: t.JsonSchemaType\n): t.JsonSchemaType | undefined {\n if (!parameters) {\n return undefined;\n }\n\n if (parameters.properties) {\n return {\n type: parameters.type,\n properties: Object.fromEntries(\n Object.entries(parameters.properties).map(([key, value]) => [\n key,\n { type: (value as t.JsonSchemaType).type },\n ])\n ),\n } as t.JsonSchemaType;\n }\n\n return { type: parameters.type };\n}\n\n/**\n * Performs safe local substring search without regex.\n * Uses case-insensitive String.includes() for complete safety against ReDoS.\n * @param tools - Array of tool metadata to search\n * @param query - The search term (treated as literal substring)\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n const lowerQuery = query.toLowerCase();\n const results: t.ToolSearchResult[] = [];\n\n for (const tool of tools) {\n let bestScore = 0;\n let matchedField = '';\n let snippet = '';\n\n if (fields.includes('name')) {\n const lowerName = tool.name.toLowerCase();\n if (lowerName.includes(lowerQuery)) {\n const isExactMatch = lowerName === lowerQuery;\n const startsWithQuery = lowerName.startsWith(lowerQuery);\n bestScore = isExactMatch ? 1.0 : startsWithQuery ? 0.95 : 0.85;\n matchedField = 'name';\n snippet = tool.name;\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const lowerDesc = tool.description.toLowerCase();\n if (lowerDesc.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.7;\n matchedField = 'description';\n snippet = tool.description.substring(0, 100);\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties)\n .join(' ')\n .toLowerCase();\n if (paramNames.includes(lowerQuery) && bestScore === 0) {\n bestScore = 0.55;\n matchedField = 'parameters';\n snippet = Object.keys(tool.parameters.properties).join(' ');\n }\n }\n\n if (bestScore > 0) {\n results.push({\n tool_name: tool.name,\n match_score: bestScore,\n matched_field: matchedField,\n snippet,\n });\n }\n }\n\n results.sort((a, b) => b.match_score - a.match_score);\n const topResults = results.slice(0, maxResults);\n\n return {\n tool_references: topResults,\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n}\n\n/**\n * Generates the JavaScript search script to be executed in the sandbox.\n * Uses plain JavaScript for maximum compatibility with the Code API.\n * @param deferredTools - Array of tool metadata to search through\n * @param fields - Which fields to search\n * @param maxResults - Maximum number of results to return\n * @param sanitizedPattern - The sanitized regex pattern\n * @returns The JavaScript code string\n */\nfunction generateSearchScript(\n deferredTools: t.ToolMetadata[],\n fields: string[],\n maxResults: number,\n sanitizedPattern: string\n): string {\n const lines = [\n '// Tool definitions (injected)',\n 'var tools = ' + JSON.stringify(deferredTools) + ';',\n 'var searchFields = ' + JSON.stringify(fields) + ';',\n 'var maxResults = ' + maxResults + ';',\n 'var pattern = ' + JSON.stringify(sanitizedPattern) + ';',\n '',\n '// Compile regex (pattern is sanitized client-side)',\n 'var regex;',\n 'try {',\n ' regex = new RegExp(pattern, \\'i\\');',\n '} catch (e) {',\n ' regex = new RegExp(pattern.replace(/[.*+?^${}()[\\\\]\\\\\\\\|]/g, \"\\\\\\\\$&\"), \"i\");',\n '}',\n '',\n '// Search logic',\n 'var results = [];',\n '',\n 'for (var j = 0; j < tools.length; j++) {',\n ' var tool = tools[j];',\n ' var bestScore = 0;',\n ' var matchedField = \\'\\';',\n ' var snippet = \\'\\';',\n '',\n ' // Search name (highest priority)',\n ' if (searchFields.indexOf(\\'name\\') >= 0 && regex.test(tool.name)) {',\n ' bestScore = 0.95;',\n ' matchedField = \\'name\\';',\n ' snippet = tool.name;',\n ' }',\n '',\n ' // Search description (medium priority)',\n ' if (searchFields.indexOf(\\'description\\') >= 0 && tool.description && regex.test(tool.description)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.75;',\n ' matchedField = \\'description\\';',\n ' snippet = tool.description.substring(0, 100);',\n ' }',\n ' }',\n '',\n ' // Search parameter names (lower priority)',\n ' if (searchFields.indexOf(\\'parameters\\') >= 0 && tool.parameters && tool.parameters.properties) {',\n ' var paramNames = Object.keys(tool.parameters.properties).join(\\' \\');',\n ' if (regex.test(paramNames)) {',\n ' if (bestScore === 0) {',\n ' bestScore = 0.60;',\n ' matchedField = \\'parameters\\';',\n ' snippet = paramNames;',\n ' }',\n ' }',\n ' }',\n '',\n ' if (bestScore > 0) {',\n ' results.push({',\n ' tool_name: tool.name,',\n ' match_score: bestScore,',\n ' matched_field: matchedField,',\n ' snippet: snippet',\n ' });',\n ' }',\n '}',\n '',\n '// Sort by score (descending) and limit results',\n 'results.sort(function(a, b) { return b.match_score - a.match_score; });',\n 'var topResults = results.slice(0, maxResults);',\n '',\n '// Output as JSON',\n 'console.log(JSON.stringify({',\n ' tool_references: topResults.map(function(r) {',\n ' return {',\n ' tool_name: r.tool_name,',\n ' match_score: r.match_score,',\n ' matched_field: r.matched_field,',\n ' snippet: r.snippet',\n ' };',\n ' }),',\n ' total_tools_searched: tools.length,',\n ' pattern_used: pattern',\n '}));',\n ];\n return lines.join('\\n');\n}\n\n/**\n * Parses the search results from stdout JSON.\n * @param stdout - The stdout string containing JSON results\n * @returns Parsed search response\n */\nfunction parseSearchResults(stdout: string): t.ToolSearchResponse {\n const jsonMatch = stdout.trim();\n const parsed = JSON.parse(jsonMatch) as t.ToolSearchResponse;\n return parsed;\n}\n\n/**\n * Formats search results into a human-readable string.\n * @param searchResponse - The parsed search response\n * @returns Formatted string for LLM consumption\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n if (tool_references.length === 0) {\n return `No tools matched the pattern \"${pattern_used}\".\\nTotal tools searched: ${total_tools_searched}`;\n }\n\n let response = `Found ${tool_references.length} matching tools:\\n\\n`;\n\n for (const ref of tool_references) {\n response += `- ${ref.tool_name} (score: ${ref.match_score.toFixed(2)})\\n`;\n response += ` Matched in: ${ref.matched_field}\\n`;\n response += ` Snippet: ${ref.snippet}\\n\\n`;\n }\n\n response += `Total tools searched: ${total_tools_searched}\\n`;\n response += `Pattern used: ${pattern_used}`;\n\n return response;\n}\n\n/**\n * Creates a Tool Search tool for discovering tools from a large registry.\n *\n * This tool enables AI agents to dynamically discover tools from a large library\n * without loading all tool definitions into the LLM context window. The agent\n * can search for relevant tools on-demand.\n *\n * **Modes:**\n * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.\n * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.\n *\n * The tool registry can be provided either:\n * 1. At initialization time via params.toolRegistry\n * 2. At runtime via config.configurable.toolRegistry when invoking\n *\n * @param params - Configuration parameters for the tool (toolRegistry is optional)\n * @returns A LangChain DynamicStructuredTool for tool searching\n *\n * @example\n * // Option 1: Code interpreter mode (regex via sandbox)\n * const tool = createToolSearch({ apiKey, toolRegistry });\n * await tool.invoke({ query: 'expense.*report' });\n *\n * @example\n * // Option 2: Local mode (safe substring search, no API key needed)\n * const tool = createToolSearch({ mode: 'local', toolRegistry });\n * await tool.invoke({ query: 'expense' });\n */\nfunction createToolSearch(\n initParams: t.ToolSearchParams = {}\n): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>> {\n const mode: t.ToolSearchMode = initParams.mode ?? 'code_interpreter';\n const defaultOnlyDeferred = initParams.onlyDeferred ?? true;\n const schema = createToolSearchSchema(mode);\n\n const apiKey: string =\n mode === 'code_interpreter'\n ? ((initParams[EnvVar.CODE_API_KEY] as string | undefined) ??\n initParams.apiKey ??\n getEnvironmentVariable(EnvVar.CODE_API_KEY) ??\n '')\n : '';\n\n if (mode === 'code_interpreter' && !apiKey) {\n throw new Error(\n 'No API key provided for tool search in code_interpreter mode. Use mode: \"local\" to search without an API key.'\n );\n }\n\n const baseEndpoint = initParams.baseUrl ?? getCodeBaseURL();\n const EXEC_ENDPOINT = `${baseEndpoint}/exec`;\n\n const description =\n mode === 'local'\n ? `\nSearches through available tools to find ones matching your search term.\n\nUsage:\n- Provide a search term to find in tool names and descriptions.\n- Uses case-insensitive substring matching (fast and safe).\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.95+) indicate name matches, medium scores (0.70+) indicate description matches.\n`.trim()\n : `\nSearches through available tools to find ones matching your query pattern.\n\nUsage:\n- Provide a regex pattern to search tool names and descriptions.\n- Use this when you need to discover tools for a specific task.\n- Results include tool names, match quality scores, and snippets showing where the match occurred.\n- Higher scores (0.9+) indicate name matches, medium scores (0.7+) indicate description matches.\n`.trim();\n\n return tool<typeof schema>(\n async (params, config) => {\n const {\n query,\n fields = ['name', 'description'],\n max_results = 10,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n\n if (toolRegistry == null) {\n return [\n 'Error: No tool registry provided. Configure toolRegistry at agent level or initialization.',\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n error: 'No tool registry provided',\n },\n },\n ];\n }\n\n const toolsArray: t.LCTool[] = Array.from(toolRegistry.values());\n const deferredTools: t.ToolMetadata[] = toolsArray\n .filter((lcTool) =>\n onlyDeferred === true ? lcTool.defer_loading === true : true\n )\n .map((lcTool) => ({\n name: lcTool.name,\n description: lcTool.description ?? '',\n parameters: simplifyParametersForSearch(lcTool.parameters),\n }));\n\n if (deferredTools.length === 0) {\n return [\n 'No tools available to search. The tool registry is empty or no deferred tools are registered.',\n {\n tool_references: [],\n metadata: { total_searched: 0, pattern: query },\n },\n ];\n }\n\n if (mode === 'local') {\n const searchResponse = performLocalSearch(\n deferredTools,\n query,\n fields,\n max_results\n );\n const formattedOutput = formatSearchResults(searchResponse);\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n },\n },\n ];\n }\n\n const { safe: sanitizedPattern, wasEscaped } = sanitizeRegex(query);\n let warningMessage = '';\n if (wasEscaped) {\n warningMessage =\n 'Note: The provided pattern was converted to a literal search for safety.\\n\\n';\n }\n\n const searchScript = generateSearchScript(\n deferredTools,\n fields,\n max_results,\n sanitizedPattern\n );\n\n const postData = {\n lang: 'js',\n code: searchScript,\n timeout: SEARCH_TIMEOUT,\n };\n\n try {\n const fetchOptions: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'LibreChat/1.0',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(postData),\n };\n\n if (process.env.PROXY != null && process.env.PROXY !== '') {\n fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);\n }\n\n const response = await fetch(EXEC_ENDPOINT, fetchOptions);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const result: t.ExecuteResult = await response.json();\n\n if (result.stderr && result.stderr.trim()) {\n // eslint-disable-next-line no-console\n console.warn('[ToolSearch] stderr:', result.stderr);\n }\n\n if (!result.stdout || !result.stdout.trim()) {\n return [\n `${warningMessage}No tools matched the pattern \"${sanitizedPattern}\".\\nTotal tools searched: ${deferredTools.length}`,\n {\n tool_references: [],\n metadata: {\n total_searched: deferredTools.length,\n pattern: sanitizedPattern,\n },\n },\n ];\n }\n\n const searchResponse = parseSearchResults(result.stdout);\n const formattedOutput = `${warningMessage}${formatSearchResults(searchResponse)}`;\n\n return [\n formattedOutput,\n {\n tool_references: searchResponse.tool_references,\n metadata: {\n total_searched: searchResponse.total_tools_searched,\n pattern: searchResponse.pattern_used,\n },\n },\n ];\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[ToolSearch] Error:', error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return [\n `Tool search failed: ${errorMessage}\\n\\nSuggestion: Try a simpler search pattern or search for specific tool names.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: sanitizedPattern,\n error: errorMessage,\n },\n },\n ];\n }\n },\n {\n name: Constants.TOOL_SEARCH,\n description,\n schema,\n responseFormat: Constants.CONTENT_AND_ARTIFACT,\n }\n );\n}\n\nexport {\n createToolSearch,\n performLocalSearch,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":[],"mappings":";;;;;;;;;AAAA;AAWA,MAAM,EAAE;AAER;AACA,MAAM,kBAAkB,GAAG,GAAG;AAE9B;AACA,MAAM,oBAAoB,GAAG,CAAC;AAE9B;AACA,MAAM,cAAc,GAAG,IAAI;AAW3B;;;;AAIG;AACH,SAAS,sBAAsB,CAAC,IAAsB,EAAA;AACpD,IAAA,MAAM,gBAAgB,GACpB,IAAI,KAAK;AACP,UAAE;UACA,6GAA6G;IAEnH,OAAO,CAAC,CAAC,MAAM,CAAC;AACd,QAAA,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AAC3E,QAAA,MAAM,EAAE;AACL,aAAA,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,aAAa,EAAE,YAAY,CAAC,CAAC;AACnD,aAAA,QAAQ;AACR,aAAA,OAAO,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC;aAC/B,QAAQ,CAAC,uDAAuD,CAAC;AACpE,QAAA,WAAW,EAAE;AACV,aAAA,MAAM;AACN,aAAA,GAAG;aACH,GAAG,CAAC,CAAC;aACL,GAAG,CAAC,EAAE;AACN,aAAA,QAAQ;aACR,OAAO,CAAC,EAAE;aACV,QAAQ,CAAC,4CAA4C,CAAC;AAC1D,KAAA,CAAC;AACJ;AAEA;;;;AAIG;AACH,SAAS,uBAAuB,CAAC,OAAe,EAAA;IAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC;AACvD;AAEA;;;;AAIG;AACH,SAAS,iBAAiB,CAAC,OAAe,EAAA;IACxC,IAAI,QAAQ,GAAG,CAAC;IAChB,IAAI,YAAY,GAAG,CAAC;AAEpB,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACvC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE;AAC9D,YAAA,YAAY,EAAE;YACd,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC;;aACtC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE;YACrE,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,CAAC,CAAC;;;AAIhD,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;AAKG;AACH,SAAS,oBAAoB,CAAC,OAAe,EAAA;IAC3C,MAAM,uBAAuB,GAAG,yBAAyB;AACzD,IAAA,OAAO,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC;AAC9C;AAEA;;;;AAIG;AACH,SAAS,kBAAkB,CAAC,OAAe,EAAA;AACzC,IAAA,IAAI,oBAAoB,CAAC,OAAO,CAAC,EAAE;AACjC,QAAA,OAAO,IAAI;;AAGb,IAAA,IAAI,iBAAiB,CAAC,OAAO,CAAC,GAAG,oBAAoB,EAAE;AACrD,QAAA,OAAO,IAAI;;AAGb,IAAA,MAAM,iBAAiB,GAAG;AACxB,QAAA,aAAa;AACb,QAAA,mBAAmB;AACnB,QAAA,qBAAqB;AACrB,QAAA,YAAY;AACZ,QAAA,YAAY;AACZ,QAAA,YAAY;AACZ,QAAA,YAAY;KACb;AAED,IAAA,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE;AACzC,QAAA,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;AAC3B,YAAA,OAAO,IAAI;;;AAIf,IAAA,OAAO,KAAK;AACd;AAEA;;;;;AAKG;AACH,SAAS,aAAa,CAAC,OAAe,EAAA;AACpC,IAAA,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE;QAC/B,OAAO;AACL,YAAA,IAAI,EAAE,uBAAuB,CAAC,OAAO,CAAC;AACtC,YAAA,UAAU,EAAE,IAAI;SACjB;;AAGH,IAAA,IAAI;AACF,QAAA,IAAI,MAAM,CAAC,OAAO,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE;;AAC3C,IAAA,MAAM;QACN,OAAO;AACL,YAAA,IAAI,EAAE,uBAAuB,CAAC,OAAO,CAAC;AACtC,YAAA,UAAU,EAAE,IAAI;SACjB;;AAEL;AAEA;;;;;AAKG;AACH,SAAS,2BAA2B,CAClC,UAA6B,EAAA;IAE7B,IAAI,CAAC,UAAU,EAAE;AACf,QAAA,OAAO,SAAS;;AAGlB,IAAA,IAAI,UAAU,CAAC,UAAU,EAAE;QACzB,OAAO;YACL,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,UAAU,EAAE,MAAM,CAAC,WAAW,CAC5B,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK;gBAC1D,GAAG;AACH,gBAAA,EAAE,IAAI,EAAG,KAA0B,CAAC,IAAI,EAAE;AAC3C,aAAA,CAAC,CACH;SACkB;;AAGvB,IAAA,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE;AAClC;AAEA;;;;;;;;AAQG;AACH,SAAS,kBAAkB,CACzB,KAAuB,EACvB,KAAa,EACb,MAAgB,EAChB,UAAkB,EAAA;AAElB,IAAA,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE;IACtC,MAAM,OAAO,GAAyB,EAAE;AAExC,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,IAAI,SAAS,GAAG,CAAC;QACjB,IAAI,YAAY,GAAG,EAAE;QACrB,IAAI,OAAO,GAAG,EAAE;AAEhB,QAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;YAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AACzC,YAAA,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;AAClC,gBAAA,MAAM,YAAY,GAAG,SAAS,KAAK,UAAU;gBAC7C,MAAM,eAAe,GAAG,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC;AACxD,gBAAA,SAAS,GAAG,YAAY,GAAG,GAAG,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI;gBAC9D,YAAY,GAAG,MAAM;AACrB,gBAAA,OAAO,GAAG,IAAI,CAAC,IAAI;;;QAIvB,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;YACtD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE;YAChD,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,SAAS,KAAK,CAAC,EAAE;gBACrD,SAAS,GAAG,GAAG;gBACf,YAAY,GAAG,aAAa;gBAC5B,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;;;AAIhD,QAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE;YAChE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU;iBACtD,IAAI,CAAC,GAAG;AACR,iBAAA,WAAW,EAAE;YAChB,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,SAAS,KAAK,CAAC,EAAE;gBACtD,SAAS,GAAG,IAAI;gBAChB,YAAY,GAAG,YAAY;AAC3B,gBAAA,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;;;AAI/D,QAAA,IAAI,SAAS,GAAG,CAAC,EAAE;YACjB,OAAO,CAAC,IAAI,CAAC;gBACX,SAAS,EAAE,IAAI,CAAC,IAAI;AACpB,gBAAA,WAAW,EAAE,SAAS;AACtB,gBAAA,aAAa,EAAE,YAAY;gBAC3B,OAAO;AACR,aAAA,CAAC;;;AAIN,IAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;IACrD,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;IAE/C,OAAO;AACL,QAAA,eAAe,EAAE,UAAU;QAC3B,oBAAoB,EAAE,KAAK,CAAC,MAAM;AAClC,QAAA,YAAY,EAAE,KAAK;KACpB;AACH;AAEA;;;;;;;;AAQG;AACH,SAAS,oBAAoB,CAC3B,aAA+B,EAC/B,MAAgB,EAChB,UAAkB,EAClB,gBAAwB,EAAA;AAExB,IAAA,MAAM,KAAK,GAAG;QACZ,gCAAgC;QAChC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,GAAG;QACpD,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,GAAG;QACpD,mBAAmB,GAAG,UAAU,GAAG,GAAG;QACtC,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,GAAG,GAAG;QACzD,EAAE;QACF,qDAAqD;QACrD,YAAY;QACZ,OAAO;QACP,uCAAuC;QACvC,eAAe;QACf,iFAAiF;QACjF,GAAG;QACH,EAAE;QACF,iBAAiB;QACjB,mBAAmB;QACnB,EAAE;QACF,0CAA0C;QAC1C,wBAAwB;QACxB,sBAAsB;QACtB,4BAA4B;QAC5B,uBAAuB;QACvB,EAAE;QACF,qCAAqC;QACrC,uEAAuE;QACvE,uBAAuB;QACvB,8BAA8B;QAC9B,0BAA0B;QAC1B,KAAK;QACL,EAAE;QACF,2CAA2C;QAC3C,yGAAyG;QACzG,4BAA4B;QAC5B,yBAAyB;QACzB,uCAAuC;QACvC,qDAAqD;QACrD,OAAO;QACP,KAAK;QACL,EAAE;QACF,8CAA8C;QAC9C,qGAAqG;QACrG,2EAA2E;QAC3E,mCAAmC;QACnC,8BAA8B;QAC9B,2BAA2B;QAC3B,wCAAwC;QACxC,+BAA+B;QAC/B,SAAS;QACT,OAAO;QACP,KAAK;QACL,EAAE;QACF,wBAAwB;QACxB,oBAAoB;QACpB,6BAA6B;QAC7B,+BAA+B;QAC/B,oCAAoC;QACpC,wBAAwB;QACxB,SAAS;QACT,KAAK;QACL,GAAG;QACH,EAAE;QACF,iDAAiD;QACjD,yEAAyE;QACzE,gDAAgD;QAChD,EAAE;QACF,mBAAmB;QACnB,8BAA8B;QAC9B,iDAAiD;QACjD,cAAc;QACd,+BAA+B;QAC/B,mCAAmC;QACnC,uCAAuC;QACvC,0BAA0B;QAC1B,QAAQ;QACR,OAAO;QACP,uCAAuC;QACvC,yBAAyB;QACzB,MAAM;KACP;AACD,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACzB;AAEA;;;;AAIG;AACH,SAAS,kBAAkB,CAAC,MAAc,EAAA;AACxC,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAyB;AAC5D,IAAA,OAAO,MAAM;AACf;AAEA;;;;AAIG;AACH,SAAS,mBAAmB,CAAC,cAAoC,EAAA;IAC/D,MAAM,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,GAC3D,cAAc;AAEhB,IAAA,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE;AAChC,QAAA,OAAO,CAAiC,8BAAA,EAAA,YAAY,CAA6B,0BAAA,EAAA,oBAAoB,EAAE;;AAGzG,IAAA,IAAI,QAAQ,GAAG,CAAA,MAAA,EAAS,eAAe,CAAC,MAAM,sBAAsB;AAEpE,IAAA,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE;AACjC,QAAA,QAAQ,IAAI,CAAA,EAAA,EAAK,GAAG,CAAC,SAAS,CAAY,SAAA,EAAA,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AACzE,QAAA,QAAQ,IAAI,CAAiB,cAAA,EAAA,GAAG,CAAC,aAAa,IAAI;AAClD,QAAA,QAAQ,IAAI,CAAc,WAAA,EAAA,GAAG,CAAC,OAAO,MAAM;;AAG7C,IAAA,QAAQ,IAAI,CAAA,sBAAA,EAAyB,oBAAoB,CAAA,EAAA,CAAI;AAC7D,IAAA,QAAQ,IAAI,CAAA,cAAA,EAAiB,YAAY,CAAA,CAAE;AAE3C,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BG;AACH,SAAS,gBAAgB,CACvB,UAAA,GAAiC,EAAE,EAAA;AAEnC,IAAA,MAAM,IAAI,GAAqB,UAAU,CAAC,IAAI,IAAI,kBAAkB;AACpE,IAAA,MAAM,mBAAmB,GAAG,UAAU,CAAC,YAAY,IAAI,IAAI;AAC3D,IAAA,MAAM,MAAM,GAAG,sBAAsB,CAAC,IAAI,CAAC;AAE3C,IAAA,MAAM,MAAM,GACV,IAAI,KAAK;AACP,WAAI,UAAU,CAAC,MAAM,CAAC,YAAY,CAAwB;AACxD,YAAA,UAAU,CAAC,MAAM;AACjB,YAAA,sBAAsB,CAAC,MAAM,CAAC,YAAY,CAAC;AAC3C,YAAA,EAAE;UACF,EAAE;AAER,IAAA,IAAI,IAAI,KAAK,kBAAkB,IAAI,CAAC,MAAM,EAAE;AAC1C,QAAA,MAAM,IAAI,KAAK,CACb,+GAA+G,CAChH;;IAGH,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,IAAI,cAAc,EAAE;AAC3D,IAAA,MAAM,aAAa,GAAG,CAAG,EAAA,YAAY,OAAO;AAE5C,IAAA,MAAM,WAAW,GACf,IAAI,KAAK;AACP,UAAE;;;;;;;;;AASP,CAAA,CAAC,IAAI;AACA,UAAE;;;;;;;;CAQP,CAAC,IAAI,EAAE;IAEN,OAAO,IAAI,CACT,OAAO,MAAM,EAAE,MAAM,KAAI;AACvB,QAAA,MAAM,EACJ,KAAK,EACL,MAAM,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAChC,WAAW,GAAG,EAAE,GACjB,GAAG,MAAM;AAEV,QAAA,MAAM,EACJ,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,iBAAiB,GAChC,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE;AAEzB,QAAA,MAAM,YAAY,GAAG,iBAAiB,IAAI,UAAU,CAAC,YAAY;AACjE,QAAA,MAAM,YAAY,GAChB,iBAAiB,KAAK;AACpB,cAAE;cACA,mBAAmB;AAEzB,QAAA,IAAI,YAAY,IAAI,IAAI,EAAE;YACxB,OAAO;gBACL,4FAA4F;AAC5F,gBAAA;AACE,oBAAA,eAAe,EAAE,EAAE;AACnB,oBAAA,QAAQ,EAAE;AACR,wBAAA,cAAc,EAAE,CAAC;AACjB,wBAAA,OAAO,EAAE,KAAK;AACd,wBAAA,KAAK,EAAE,2BAA2B;AACnC,qBAAA;AACF,iBAAA;aACF;;QAGH,MAAM,UAAU,GAAe,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;QAChE,MAAM,aAAa,GAAqB;aACrC,MAAM,CAAC,CAAC,MAAM,KACb,YAAY,KAAK,IAAI,GAAG,MAAM,CAAC,aAAa,KAAK,IAAI,GAAG,IAAI;AAE7D,aAAA,GAAG,CAAC,CAAC,MAAM,MAAM;YAChB,IAAI,EAAE,MAAM,CAAC,IAAI;AACjB,YAAA,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;AACrC,YAAA,UAAU,EAAE,2BAA2B,CAAC,MAAM,CAAC,UAAU,CAAC;AAC3D,SAAA,CAAC,CAAC;AAEL,QAAA,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;YAC9B,OAAO;gBACL,+FAA+F;AAC/F,gBAAA;AACE,oBAAA,eAAe,EAAE,EAAE;oBACnB,QAAQ,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE;AAChD,iBAAA;aACF;;AAGH,QAAA,IAAI,IAAI,KAAK,OAAO,EAAE;AACpB,YAAA,MAAM,cAAc,GAAG,kBAAkB,CACvC,aAAa,EACb,KAAK,EACL,MAAM,EACN,WAAW,CACZ;AACD,YAAA,MAAM,eAAe,GAAG,mBAAmB,CAAC,cAAc,CAAC;YAE3D,OAAO;gBACL,eAAe;AACf,gBAAA;oBACE,eAAe,EAAE,cAAc,CAAC,eAAe;AAC/C,oBAAA,QAAQ,EAAE;wBACR,cAAc,EAAE,cAAc,CAAC,oBAAoB;wBACnD,OAAO,EAAE,cAAc,CAAC,YAAY;AACrC,qBAAA;AACF,iBAAA;aACF;;AAGH,QAAA,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC;QACnE,IAAI,cAAc,GAAG,EAAE;QACvB,IAAI,UAAU,EAAE;YACd,cAAc;AACZ,gBAAA,8EAA8E;;AAGlF,QAAA,MAAM,YAAY,GAAG,oBAAoB,CACvC,aAAa,EACb,MAAM,EACN,WAAW,EACX,gBAAgB,CACjB;AAED,QAAA,MAAM,QAAQ,GAAG;AACf,YAAA,IAAI,EAAE,IAAI;AACV,YAAA,IAAI,EAAE,YAAY;AAClB,YAAA,OAAO,EAAE,cAAc;SACxB;AAED,QAAA,IAAI;AACF,YAAA,MAAM,YAAY,GAAgB;AAChC,gBAAA,MAAM,EAAE,MAAM;AACd,gBAAA,OAAO,EAAE;AACP,oBAAA,cAAc,EAAE,kBAAkB;AAClC,oBAAA,YAAY,EAAE,eAAe;AAC7B,oBAAA,WAAW,EAAE,MAAM;AACpB,iBAAA;AACD,gBAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;aAC/B;AAED,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,EAAE;AACzD,gBAAA,YAAY,CAAC,KAAK,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;;YAG7D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC;AACzD,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAChB,MAAM,IAAI,KAAK,CAAC,CAAA,oBAAA,EAAuB,QAAQ,CAAC,MAAM,CAAE,CAAA,CAAC;;AAG3D,YAAA,MAAM,MAAM,GAAoB,MAAM,QAAQ,CAAC,IAAI,EAAE;YAErD,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;;gBAEzC,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,CAAC;;AAGrD,YAAA,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;gBAC3C,OAAO;AACL,oBAAA,CAAA,EAAG,cAAc,CAAiC,8BAAA,EAAA,gBAAgB,6BAA6B,aAAa,CAAC,MAAM,CAAE,CAAA;AACrH,oBAAA;AACE,wBAAA,eAAe,EAAE,EAAE;AACnB,wBAAA,QAAQ,EAAE;4BACR,cAAc,EAAE,aAAa,CAAC,MAAM;AACpC,4BAAA,OAAO,EAAE,gBAAgB;AAC1B,yBAAA;AACF,qBAAA;iBACF;;YAGH,MAAM,cAAc,GAAG,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC;YACxD,MAAM,eAAe,GAAG,CAAA,EAAG,cAAc,CAAA,EAAG,mBAAmB,CAAC,cAAc,CAAC,CAAA,CAAE;YAEjF,OAAO;gBACL,eAAe;AACf,gBAAA;oBACE,eAAe,EAAE,cAAc,CAAC,eAAe;AAC/C,oBAAA,QAAQ,EAAE;wBACR,cAAc,EAAE,cAAc,CAAC,oBAAoB;wBACnD,OAAO,EAAE,cAAc,CAAC,YAAY;AACrC,qBAAA;AACF,iBAAA;aACF;;QACD,OAAO,KAAK,EAAE;;AAEd,YAAA,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC;AAE3C,YAAA,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;YACxD,OAAO;AACL,gBAAA,CAAA,oBAAA,EAAuB,YAAY,CAAiF,+EAAA,CAAA;AACpH,gBAAA;AACE,oBAAA,eAAe,EAAE,EAAE;AACnB,oBAAA,QAAQ,EAAE;AACR,wBAAA,cAAc,EAAE,CAAC;AACjB,wBAAA,OAAO,EAAE,gBAAgB;AACzB,wBAAA,KAAK,EAAE,YAAY;AACpB,qBAAA;AACF,iBAAA;aACF;;AAEL,KAAC,EACD;QACE,IAAI,EAAE,SAAS,CAAC,WAAW;QAC3B,WAAW;QACX,MAAM;QACN,cAAc,EAAE,SAAS,CAAC,oBAAoB;AAC/C,KAAA,CACF;AACH;;;;"}
@@ -73,10 +73,13 @@ export declare class AgentContext {
73
73
  useLegacyContent: boolean;
74
74
  /**
75
75
  * Handoff context when this agent receives control via handoff.
76
- * Contains source agent name for system message identity context.
76
+ * Contains source and parallel execution info for system message context.
77
77
  */
78
78
  handoffContext?: {
79
+ /** Source agent that transferred control */
79
80
  sourceAgentName: string;
81
+ /** Names of sibling agents executing in parallel (empty if sequential) */
82
+ parallelSiblings: string[];
80
83
  };
81
84
  constructor({ agentId, name, provider, clientOptions, maxContextTokens, streamBuffer, tokenCounter, tools, toolMap, toolRegistry, instructions, additionalInstructions, reasoningKey, toolEnd, instructionTokens, useLegacyContent, }: {
82
85
  agentId: string;
@@ -155,9 +158,10 @@ export declare class AgentContext {
155
158
  * Sets the handoff context for this agent.
156
159
  * Call this when the agent receives control via handoff from another agent.
157
160
  * Marks system runnable as stale to include handoff context in system message.
158
- * @param sourceAgentName - The name of the agent that handed off to this agent
161
+ * @param sourceAgentName - Name of the agent that transferred control
162
+ * @param parallelSiblings - Names of other agents executing in parallel with this one
159
163
  */
160
- setHandoffContext(sourceAgentName: string): void;
164
+ setHandoffContext(sourceAgentName: string, parallelSiblings: string[]): void;
161
165
  /**
162
166
  * Clears any handoff context.
163
167
  * Call this when resetting the agent or when handoff context is no longer relevant.
@@ -114,7 +114,7 @@ export declare enum Callback {
114
114
  export declare enum Constants {
115
115
  OFFICIAL_CODE_BASEURL = "https://api.librechat.ai/v1",
116
116
  EXECUTE_CODE = "execute_code",
117
- TOOL_SEARCH_REGEX = "tool_search_regex",
117
+ TOOL_SEARCH = "tool_search",
118
118
  PROGRAMMATIC_TOOL_CALLING = "run_tools_with_code",
119
119
  WEB_SEARCH = "web_search",
120
120
  CONTENT_AND_ARTIFACT = "content_and_artifact",
@@ -86,15 +86,15 @@ export declare class MultiAgentGraph extends StandardGraph {
86
86
  private createAgentSubgraph;
87
87
  /**
88
88
  * Detects if the current agent is receiving a handoff and processes the messages accordingly.
89
- * Returns filtered messages with the transfer tool call/message removed, plus any instructions
90
- * and source agent information extracted from the transfer.
89
+ * Returns filtered messages with the transfer tool call/message removed, plus any instructions,
90
+ * source agent, and parallel sibling information extracted from the transfer.
91
91
  *
92
92
  * Supports both single handoffs (last message is the transfer) and parallel handoffs
93
93
  * (multiple transfer ToolMessages, need to find the one targeting this agent).
94
94
  *
95
95
  * @param messages - Current state messages
96
96
  * @param agentId - The agent ID to check for handoff reception
97
- * @returns Object with filtered messages, extracted instructions, and source agent, or null if not a handoff
97
+ * @returns Object with filtered messages, extracted instructions, source agent, and parallel siblings
98
98
  */
99
99
  private processHandoffReception;
100
100
  /**
@@ -7,7 +7,7 @@ export * from './graphs';
7
7
  export * from './tools/Calculator';
8
8
  export * from './tools/CodeExecutor';
9
9
  export * from './tools/ProgrammaticToolCalling';
10
- export * from './tools/ToolSearchRegex';
10
+ export * from './tools/ToolSearch';
11
11
  export * from './tools/handlers';
12
12
  export * from './tools/search';
13
13
  export * from './common';