@librechat/agents 3.0.74 → 3.0.76

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 (37) hide show
  1. package/dist/cjs/graphs/Graph.cjs +34 -0
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/tools/CodeExecutor.cjs +22 -21
  4. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  5. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +14 -11
  6. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  7. package/dist/cjs/tools/ToolNode.cjs +28 -1
  8. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  9. package/dist/cjs/tools/ToolSearch.cjs +12 -2
  10. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  11. package/dist/esm/graphs/Graph.mjs +35 -1
  12. package/dist/esm/graphs/Graph.mjs.map +1 -1
  13. package/dist/esm/tools/CodeExecutor.mjs +22 -21
  14. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  15. package/dist/esm/tools/ProgrammaticToolCalling.mjs +14 -11
  16. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  17. package/dist/esm/tools/ToolNode.mjs +28 -1
  18. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  19. package/dist/esm/tools/ToolSearch.mjs +12 -2
  20. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  21. package/dist/types/graphs/Graph.d.ts +6 -0
  22. package/dist/types/tools/CodeExecutor.d.ts +0 -3
  23. package/dist/types/tools/ProgrammaticToolCalling.d.ts +0 -3
  24. package/dist/types/tools/ToolNode.d.ts +3 -1
  25. package/dist/types/types/tools.d.ts +32 -0
  26. package/package.json +3 -2
  27. package/src/graphs/Graph.ts +44 -0
  28. package/src/scripts/code_exec_files.ts +58 -15
  29. package/src/scripts/code_exec_session.ts +282 -0
  30. package/src/scripts/test_code_api.ts +361 -0
  31. package/src/tools/CodeExecutor.ts +26 -23
  32. package/src/tools/ProgrammaticToolCalling.ts +18 -14
  33. package/src/tools/ToolNode.ts +33 -0
  34. package/src/tools/ToolSearch.ts +12 -2
  35. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +0 -2
  36. package/src/tools/__tests__/ToolSearch.test.ts +84 -0
  37. package/src/types/tools.ts +40 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ToolSearch.mjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport * as okapibm25Module from 'okapibm25';\nimport { config } from 'dotenv';\n\ntype BM25Fn = (\n documents: string[],\n keywords: string[],\n constants?: { k1?: number; b?: number }\n) => number[];\n\nfunction getBM25Function(): BM25Fn {\n const mod = okapibm25Module as unknown as {\n default: BM25Fn | { default: BM25Fn } | undefined;\n };\n if (typeof mod === 'function') return mod;\n if (typeof mod.default === 'function') return mod.default;\n if (mod.default != null && typeof mod.default.default === 'function')\n return mod.default.default;\n throw new Error('Could not resolve BM25 function from okapibm25 module');\n}\n\nconst BM25 = getBM25Function();\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.ZodDefault<z.ZodOptional<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 mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;\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. Optional if mcp_server is provided.'\n : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';\n\n return z.object({\n query: z\n .string()\n .max(MAX_PATTERN_LENGTH)\n .optional()\n .default('')\n .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 mcp_server: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'\n ),\n });\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n * MCP tools follow the pattern: toolName_mcp_serverName\n * @param toolName - The full tool name\n * @returns The server name if it's an MCP tool, undefined otherwise\n */\nfunction extractMcpServerName(toolName: string): string | undefined {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return undefined;\n }\n return toolName.substring(delimiterIndex + Constants.MCP_DELIMITER.length);\n}\n\n/**\n * Checks if a tool belongs to a specific MCP server.\n * @param toolName - The full tool name\n * @param serverName - The server name to match\n * @returns True if the tool belongs to the specified server\n */\nfunction isFromMcpServer(toolName: string, serverName: string): boolean {\n const toolServer = extractMcpServerName(toolName);\n return toolServer === serverName;\n}\n\n/**\n * Checks if a tool belongs to any of the specified MCP servers.\n * @param toolName - The full tool name\n * @param serverNames - Array of server names to match\n * @returns True if the tool belongs to any of the specified servers\n */\nfunction isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean {\n const toolServer = extractMcpServerName(toolName);\n if (toolServer === undefined) {\n return false;\n }\n return serverNames.includes(toolServer);\n}\n\n/**\n * Normalizes server filter input to always be an array.\n * @param serverFilter - String, array of strings, or undefined\n * @returns Array of server names (empty if none specified)\n */\nfunction normalizeServerFilter(\n serverFilter: string | string[] | undefined\n): string[] {\n if (serverFilter === undefined) {\n return [];\n }\n if (typeof serverFilter === 'string') {\n return serverFilter === '' ? [] : [serverFilter];\n }\n return serverFilter.filter((s) => s !== '');\n}\n\n/**\n * Extracts all unique MCP server names from a tool registry.\n * @param toolRegistry - The tool registry to scan\n * @param onlyDeferred - If true, only considers deferred tools\n * @returns Array of unique server names, sorted alphabetically\n */\nfunction getAvailableMcpServers(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean = true\n): string[] {\n if (!toolRegistry) {\n return [];\n }\n\n const servers = new Set<string>();\n for (const [, toolDef] of toolRegistry) {\n if (onlyDeferred && toolDef.defer_loading !== true) {\n continue;\n }\n const server = extractMcpServerName(toolDef.name);\n if (server !== undefined && server !== '') {\n servers.add(server);\n }\n }\n\n return Array.from(servers).sort();\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 * Tokenizes a string into lowercase words for BM25.\n * @param text - The text to tokenize\n * @returns Array of lowercase tokens\n */\nfunction tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9_]/g, ' ')\n .split(/\\s+/)\n .filter((token) => token.length > 0);\n}\n\n/**\n * Creates a searchable document string from tool metadata.\n * @param tool - The tool metadata\n * @param fields - Which fields to include\n * @returns Combined document string for BM25\n */\nfunction createToolDocument(tool: t.ToolMetadata, fields: string[]): string {\n const parts: string[] = [];\n\n if (fields.includes('name')) {\n const baseName = tool.name.replace(/_/g, ' ');\n parts.push(baseName, baseName);\n }\n\n if (fields.includes('description') && tool.description) {\n parts.push(tool.description);\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties).join(' ');\n parts.push(paramNames);\n }\n\n return parts.join(' ');\n}\n\n/**\n * Determines which field had the best match for a query.\n * @param tool - The tool to check\n * @param queryTokens - Tokenized query\n * @param fields - Fields to check\n * @returns The matched field and a snippet\n */\nfunction findMatchedField(\n tool: t.ToolMetadata,\n queryTokens: string[],\n fields: string[]\n): { field: string; snippet: string } {\n if (fields.includes('name')) {\n const nameLower = tool.name.toLowerCase();\n for (const token of queryTokens) {\n if (nameLower.includes(token)) {\n return { field: 'name', snippet: tool.name };\n }\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const descLower = tool.description.toLowerCase();\n for (const token of queryTokens) {\n if (descLower.includes(token)) {\n return {\n field: 'description',\n snippet: tool.description.substring(0, 100),\n };\n }\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties);\n const paramLower = paramNames.join(' ').toLowerCase();\n for (const token of queryTokens) {\n if (paramLower.includes(token)) {\n return { field: 'parameters', snippet: paramNames.join(', ') };\n }\n }\n }\n\n const fallbackSnippet = tool.description\n ? tool.description.substring(0, 100)\n : tool.name;\n return { field: 'unknown', snippet: fallbackSnippet };\n}\n\n/**\n * Performs BM25-based search for better relevance ranking.\n * Uses Okapi BM25 algorithm for term frequency and document length normalization.\n * @param tools - Array of tool metadata to search\n * @param query - The search query\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools ranked by BM25 score\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n if (tools.length === 0 || !query.trim()) {\n return {\n tool_references: [],\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n }\n\n const documents = tools.map((tool) => createToolDocument(tool, fields));\n const queryTokens = tokenize(query);\n\n if (queryTokens.length === 0) {\n return {\n tool_references: [],\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n }\n\n const scores = BM25(documents, queryTokens, { k1: 1.5, b: 0.75 }) as number[];\n\n const maxScore = Math.max(...scores.filter((s) => s > 0), 1);\n\n const results: t.ToolSearchResult[] = [];\n for (let i = 0; i < tools.length; i++) {\n if (scores[i] > 0) {\n const { field, snippet } = findMatchedField(\n tools[i],\n queryTokens,\n fields\n );\n const normalizedScore = Math.min(scores[i] / maxScore, 1.0);\n\n results.push({\n tool_name: tools[i].name,\n match_score: normalizedScore,\n matched_field: field,\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 as structured JSON for efficient parsing.\n * @param searchResponse - The parsed search response\n * @returns JSON string with search results\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n const output = {\n found: tool_references.length,\n tools: tool_references.map((ref) => ({\n name: ref.tool_name,\n score: Number(ref.match_score.toFixed(2)),\n matched_in: ref.matched_field,\n snippet: ref.snippet,\n })),\n total_searched: total_tools_searched,\n query: pattern_used,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Extracts the base tool name (without MCP server suffix) from a full tool name.\n * @param toolName - The full tool name\n * @returns The base tool name without server suffix\n */\nfunction getBaseToolName(toolName: string): string {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return toolName;\n }\n return toolName.substring(0, delimiterIndex);\n}\n\n/**\n * Generates a compact listing of deferred tools grouped by server.\n * Format: \"server: tool1, tool2, tool3\"\n * Non-MCP tools are grouped under \"other\".\n * @param toolRegistry - The tool registry\n * @param onlyDeferred - Whether to only include deferred tools\n * @returns Formatted string with tools grouped by server\n */\nfunction getDeferredToolsListing(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean\n): string {\n if (!toolRegistry) {\n return '';\n }\n\n const toolsByServer: Record<string, string[]> = {};\n\n for (const lcTool of toolRegistry.values()) {\n if (onlyDeferred && lcTool.defer_loading !== true) {\n continue;\n }\n\n const toolName = lcTool.name;\n const serverName = extractMcpServerName(toolName) ?? 'other';\n const baseName = getBaseToolName(toolName);\n\n if (!(serverName in toolsByServer)) {\n toolsByServer[serverName] = [];\n }\n toolsByServer[serverName].push(baseName);\n }\n\n const serverNames = Object.keys(toolsByServer).sort((a, b) => {\n if (a === 'other') return 1;\n if (b === 'other') return -1;\n return a.localeCompare(b);\n });\n\n if (serverNames.length === 0) {\n return '';\n }\n\n const lines = serverNames.map(\n (server) => `${server}: ${toolsByServer[server].join(', ')}`\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Formats a server listing response as structured JSON.\n * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.\n * @param tools - Array of tool metadata from the server(s)\n * @param serverNames - The MCP server name(s)\n * @returns JSON string showing all tools grouped by server\n */\nfunction formatServerListing(\n tools: t.ToolMetadata[],\n serverNames: string | string[]\n): string {\n const servers = Array.isArray(serverNames) ? serverNames : [serverNames];\n\n if (tools.length === 0) {\n return JSON.stringify(\n {\n listing_mode: true,\n servers,\n total_tools: 0,\n tools_by_server: {},\n hint: 'No tools found from the specified MCP server(s).',\n },\n null,\n 2\n );\n }\n\n const toolsByServer: Record<\n string,\n Array<{ name: string; description: string }>\n > = {};\n for (const tool of tools) {\n const server = extractMcpServerName(tool.name) ?? 'unknown';\n if (!(server in toolsByServer)) {\n toolsByServer[server] = [];\n }\n toolsByServer[server].push({\n name: getBaseToolName(tool.name),\n description:\n tool.description.length > 100\n ? tool.description.substring(0, 97) + '...'\n : tool.description,\n });\n }\n\n const output = {\n listing_mode: true,\n servers,\n total_tools: tools.length,\n tools_by_server: toolsByServer,\n hint: `To use a tool, search for it by name (e.g., query: \"${getBaseToolName(tools[0]?.name ?? 'tool_name')}\") to load it.`,\n };\n\n return JSON.stringify(output, null, 2);\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 deferredToolsListing = getDeferredToolsListing(\n initParams.toolRegistry,\n defaultOnlyDeferred\n );\n\n const toolsListSection =\n deferredToolsListing.length > 0\n ? `\n\nDeferred tools (search to load):\n${deferredToolsListing}`\n : '';\n\n const mcpNote =\n deferredToolsListing.includes(Constants.MCP_DELIMITER) ||\n deferredToolsListing.split('\\n').some((line) => !line.startsWith('other:'))\n ? `\n- MCP tools use format: toolName${Constants.MCP_DELIMITER}serverName\n- Use mcp_server param to filter by server`\n : '';\n\n const description =\n mode === 'local'\n ? `\nSearches deferred tools using BM25 ranking. Multi-word queries supported.\n${mcpNote}${toolsListSection}\n`.trim()\n : `\nSearches deferred tools by regex pattern.\n${mcpNote}${toolsListSection}\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 mcp_server,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n mcpServer: paramMcpServer,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n const rawServerFilter =\n mcp_server ?? paramMcpServer ?? initParams.mcpServer;\n const serverFilters = normalizeServerFilter(rawServerFilter);\n const hasServerFilter = serverFilters.length > 0;\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 if (onlyDeferred === true && lcTool.defer_loading !== true) {\n return false;\n }\n if (\n hasServerFilter &&\n !isFromAnyMcpServer(lcTool.name, serverFilters)\n ) {\n return false;\n }\n return 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 const serverMsg = hasServerFilter\n ? ` from MCP server(s): ${serverFilters.join(', ')}`\n : '';\n return [\n `No tools available to search${serverMsg}. The tool registry is empty or no matching deferred tools are registered.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n mcp_server: serverFilters,\n },\n },\n ];\n }\n\n const isServerListing = hasServerFilter && query === '';\n\n if (isServerListing) {\n const formattedOutput = formatServerListing(\n deferredTools,\n serverFilters\n );\n\n return [\n formattedOutput,\n {\n tool_references: [],\n metadata: {\n total_available: deferredTools.length,\n mcp_server: serverFilters,\n listing_mode: true,\n },\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 mcp_server: serverFilters.length > 0 ? serverFilters : undefined,\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 extractMcpServerName,\n isFromMcpServer,\n isFromAnyMcpServer,\n normalizeServerFilter,\n getAvailableMcpServers,\n getDeferredToolsListing,\n getBaseToolName,\n formatServerListing,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolSearch.mjs","sources":["../../../src/tools/ToolSearch.ts"],"sourcesContent":["// src/tools/ToolSearch.ts\nimport { z } from 'zod';\nimport * as okapibm25Module from 'okapibm25';\nimport { config } from 'dotenv';\n\ntype BM25Fn = (\n documents: string[],\n keywords: string[],\n constants?: { k1?: number; b?: number }\n) => number[];\n\nfunction getBM25Function(): BM25Fn {\n const mod = okapibm25Module as unknown as {\n default: BM25Fn | { default: BM25Fn } | undefined;\n };\n if (typeof mod === 'function') return mod;\n if (typeof mod.default === 'function') return mod.default;\n if (mod.default != null && typeof mod.default.default === 'function')\n return mod.default.default;\n throw new Error('Could not resolve BM25 function from okapibm25 module');\n}\n\nconst BM25 = getBM25Function();\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.ZodDefault<z.ZodOptional<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 mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;\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. Optional if mcp_server is provided.'\n : 'Regex pattern to search tool names and descriptions. Optional if mcp_server is provided.';\n\n return z.object({\n query: z\n .string()\n .max(MAX_PATTERN_LENGTH)\n .optional()\n .default('')\n .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 mcp_server: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Filter to tools from specific MCP server(s). Can be a single server name or array of names. If provided without a query, lists all tools from those servers.'\n ),\n });\n}\n\n/**\n * Extracts the MCP server name from a tool name.\n * MCP tools follow the pattern: toolName_mcp_serverName\n * @param toolName - The full tool name\n * @returns The server name if it's an MCP tool, undefined otherwise\n */\nfunction extractMcpServerName(toolName: string): string | undefined {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return undefined;\n }\n return toolName.substring(delimiterIndex + Constants.MCP_DELIMITER.length);\n}\n\n/**\n * Checks if a tool belongs to a specific MCP server.\n * @param toolName - The full tool name\n * @param serverName - The server name to match\n * @returns True if the tool belongs to the specified server\n */\nfunction isFromMcpServer(toolName: string, serverName: string): boolean {\n const toolServer = extractMcpServerName(toolName);\n return toolServer === serverName;\n}\n\n/**\n * Checks if a tool belongs to any of the specified MCP servers.\n * @param toolName - The full tool name\n * @param serverNames - Array of server names to match\n * @returns True if the tool belongs to any of the specified servers\n */\nfunction isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean {\n const toolServer = extractMcpServerName(toolName);\n if (toolServer === undefined) {\n return false;\n }\n return serverNames.includes(toolServer);\n}\n\n/**\n * Normalizes server filter input to always be an array.\n * @param serverFilter - String, array of strings, or undefined\n * @returns Array of server names (empty if none specified)\n */\nfunction normalizeServerFilter(\n serverFilter: string | string[] | undefined\n): string[] {\n if (serverFilter === undefined) {\n return [];\n }\n if (typeof serverFilter === 'string') {\n return serverFilter === '' ? [] : [serverFilter];\n }\n return serverFilter.filter((s) => s !== '');\n}\n\n/**\n * Extracts all unique MCP server names from a tool registry.\n * @param toolRegistry - The tool registry to scan\n * @param onlyDeferred - If true, only considers deferred tools\n * @returns Array of unique server names, sorted alphabetically\n */\nfunction getAvailableMcpServers(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean = true\n): string[] {\n if (!toolRegistry) {\n return [];\n }\n\n const servers = new Set<string>();\n for (const [, toolDef] of toolRegistry) {\n if (onlyDeferred && toolDef.defer_loading !== true) {\n continue;\n }\n const server = extractMcpServerName(toolDef.name);\n if (server !== undefined && server !== '') {\n servers.add(server);\n }\n }\n\n return Array.from(servers).sort();\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 * Tokenizes a string into lowercase words for BM25.\n * Splits on underscores and non-alphanumeric characters for consistent matching.\n * @param text - The text to tokenize\n * @returns Array of lowercase tokens\n */\nfunction tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]/g, ' ')\n .split(/\\s+/)\n .filter((token) => token.length > 0);\n}\n\n/**\n * Creates a searchable document string from tool metadata.\n * @param tool - The tool metadata\n * @param fields - Which fields to include\n * @returns Combined document string for BM25\n */\nfunction createToolDocument(tool: t.ToolMetadata, fields: string[]): string {\n const parts: string[] = [];\n\n if (fields.includes('name')) {\n const baseName = tool.name.replace(/_/g, ' ');\n parts.push(baseName, baseName);\n }\n\n if (fields.includes('description') && tool.description) {\n parts.push(tool.description);\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties).join(' ');\n parts.push(paramNames);\n }\n\n return parts.join(' ');\n}\n\n/**\n * Determines which field had the best match for a query.\n * @param tool - The tool to check\n * @param queryTokens - Tokenized query\n * @param fields - Fields to check\n * @returns The matched field and a snippet\n */\nfunction findMatchedField(\n tool: t.ToolMetadata,\n queryTokens: string[],\n fields: string[]\n): { field: string; snippet: string } {\n if (fields.includes('name')) {\n const nameLower = tool.name.toLowerCase();\n for (const token of queryTokens) {\n if (nameLower.includes(token)) {\n return { field: 'name', snippet: tool.name };\n }\n }\n }\n\n if (fields.includes('description') && tool.description) {\n const descLower = tool.description.toLowerCase();\n for (const token of queryTokens) {\n if (descLower.includes(token)) {\n return {\n field: 'description',\n snippet: tool.description.substring(0, 100),\n };\n }\n }\n }\n\n if (fields.includes('parameters') && tool.parameters?.properties) {\n const paramNames = Object.keys(tool.parameters.properties);\n const paramLower = paramNames.join(' ').toLowerCase();\n for (const token of queryTokens) {\n if (paramLower.includes(token)) {\n return { field: 'parameters', snippet: paramNames.join(', ') };\n }\n }\n }\n\n const fallbackSnippet = tool.description\n ? tool.description.substring(0, 100)\n : tool.name;\n return { field: 'unknown', snippet: fallbackSnippet };\n}\n\n/**\n * Performs BM25-based search for better relevance ranking.\n * Uses Okapi BM25 algorithm for term frequency and document length normalization.\n * @param tools - Array of tool metadata to search\n * @param query - The search query\n * @param fields - Which fields to search\n * @param maxResults - Maximum results to return\n * @returns Search response with matching tools ranked by BM25 score\n */\nfunction performLocalSearch(\n tools: t.ToolMetadata[],\n query: string,\n fields: string[],\n maxResults: number\n): t.ToolSearchResponse {\n if (tools.length === 0 || !query.trim()) {\n return {\n tool_references: [],\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n }\n\n const documents = tools.map((tool) => createToolDocument(tool, fields));\n const queryTokens = tokenize(query);\n\n if (queryTokens.length === 0) {\n return {\n tool_references: [],\n total_tools_searched: tools.length,\n pattern_used: query,\n };\n }\n\n const scores = BM25(documents, queryTokens, { k1: 1.5, b: 0.75 }) as number[];\n\n const maxScore = Math.max(...scores.filter((s) => s > 0), 1);\n const queryLower = query.toLowerCase().trim();\n\n const results: t.ToolSearchResult[] = [];\n for (let i = 0; i < tools.length; i++) {\n if (scores[i] > 0) {\n const { field, snippet } = findMatchedField(\n tools[i],\n queryTokens,\n fields\n );\n let normalizedScore = Math.min(scores[i] / maxScore, 1.0);\n\n // Boost score for exact base name match\n const baseName = getBaseToolName(tools[i].name).toLowerCase();\n if (baseName === queryLower) {\n normalizedScore = 1.0;\n } else if (baseName.startsWith(queryLower)) {\n normalizedScore = Math.max(normalizedScore, 0.95);\n }\n\n results.push({\n tool_name: tools[i].name,\n match_score: normalizedScore,\n matched_field: field,\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 as structured JSON for efficient parsing.\n * @param searchResponse - The parsed search response\n * @returns JSON string with search results\n */\nfunction formatSearchResults(searchResponse: t.ToolSearchResponse): string {\n const { tool_references, total_tools_searched, pattern_used } =\n searchResponse;\n\n const output = {\n found: tool_references.length,\n tools: tool_references.map((ref) => ({\n name: ref.tool_name,\n score: Number(ref.match_score.toFixed(2)),\n matched_in: ref.matched_field,\n snippet: ref.snippet,\n })),\n total_searched: total_tools_searched,\n query: pattern_used,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Extracts the base tool name (without MCP server suffix) from a full tool name.\n * @param toolName - The full tool name\n * @returns The base tool name without server suffix\n */\nfunction getBaseToolName(toolName: string): string {\n const delimiterIndex = toolName.indexOf(Constants.MCP_DELIMITER);\n if (delimiterIndex === -1) {\n return toolName;\n }\n return toolName.substring(0, delimiterIndex);\n}\n\n/**\n * Generates a compact listing of deferred tools grouped by server.\n * Format: \"server: tool1, tool2, tool3\"\n * Non-MCP tools are grouped under \"other\".\n * @param toolRegistry - The tool registry\n * @param onlyDeferred - Whether to only include deferred tools\n * @returns Formatted string with tools grouped by server\n */\nfunction getDeferredToolsListing(\n toolRegistry: t.LCToolRegistry | undefined,\n onlyDeferred: boolean\n): string {\n if (!toolRegistry) {\n return '';\n }\n\n const toolsByServer: Record<string, string[]> = {};\n\n for (const lcTool of toolRegistry.values()) {\n if (onlyDeferred && lcTool.defer_loading !== true) {\n continue;\n }\n\n const toolName = lcTool.name;\n const serverName = extractMcpServerName(toolName) ?? 'other';\n const baseName = getBaseToolName(toolName);\n\n if (!(serverName in toolsByServer)) {\n toolsByServer[serverName] = [];\n }\n toolsByServer[serverName].push(baseName);\n }\n\n const serverNames = Object.keys(toolsByServer).sort((a, b) => {\n if (a === 'other') return 1;\n if (b === 'other') return -1;\n return a.localeCompare(b);\n });\n\n if (serverNames.length === 0) {\n return '';\n }\n\n const lines = serverNames.map(\n (server) => `${server}: ${toolsByServer[server].join(', ')}`\n );\n\n return lines.join('\\n');\n}\n\n/**\n * Formats a server listing response as structured JSON.\n * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.\n * @param tools - Array of tool metadata from the server(s)\n * @param serverNames - The MCP server name(s)\n * @returns JSON string showing all tools grouped by server\n */\nfunction formatServerListing(\n tools: t.ToolMetadata[],\n serverNames: string | string[]\n): string {\n const servers = Array.isArray(serverNames) ? serverNames : [serverNames];\n\n if (tools.length === 0) {\n return JSON.stringify(\n {\n listing_mode: true,\n servers,\n total_tools: 0,\n tools_by_server: {},\n hint: 'No tools found from the specified MCP server(s).',\n },\n null,\n 2\n );\n }\n\n const toolsByServer: Record<\n string,\n Array<{ name: string; description: string }>\n > = {};\n for (const tool of tools) {\n const server = extractMcpServerName(tool.name) ?? 'unknown';\n if (!(server in toolsByServer)) {\n toolsByServer[server] = [];\n }\n toolsByServer[server].push({\n name: getBaseToolName(tool.name),\n description:\n tool.description.length > 100\n ? tool.description.substring(0, 97) + '...'\n : tool.description,\n });\n }\n\n const output = {\n listing_mode: true,\n servers,\n total_tools: tools.length,\n tools_by_server: toolsByServer,\n hint: `To use a tool, search for it by name (e.g., query: \"${getBaseToolName(tools[0]?.name ?? 'tool_name')}\") to load it.`,\n };\n\n return JSON.stringify(output, null, 2);\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 deferredToolsListing = getDeferredToolsListing(\n initParams.toolRegistry,\n defaultOnlyDeferred\n );\n\n const toolsListSection =\n deferredToolsListing.length > 0\n ? `\n\nDeferred tools (search to load):\n${deferredToolsListing}`\n : '';\n\n const mcpNote =\n deferredToolsListing.includes(Constants.MCP_DELIMITER) ||\n deferredToolsListing.split('\\n').some((line) => !line.startsWith('other:'))\n ? `\n- MCP tools use format: toolName${Constants.MCP_DELIMITER}serverName\n- Use mcp_server param to filter by server`\n : '';\n\n const description =\n mode === 'local'\n ? `\nSearches deferred tools using BM25 ranking. Multi-word queries supported.\n${mcpNote}${toolsListSection}\n`.trim()\n : `\nSearches deferred tools by regex pattern.\n${mcpNote}${toolsListSection}\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 mcp_server,\n } = params;\n\n const {\n toolRegistry: paramToolRegistry,\n onlyDeferred: paramOnlyDeferred,\n mcpServer: paramMcpServer,\n } = config.toolCall ?? {};\n\n const toolRegistry = paramToolRegistry ?? initParams.toolRegistry;\n const onlyDeferred =\n paramOnlyDeferred !== undefined\n ? paramOnlyDeferred\n : defaultOnlyDeferred;\n const rawServerFilter =\n mcp_server ?? paramMcpServer ?? initParams.mcpServer;\n const serverFilters = normalizeServerFilter(rawServerFilter);\n const hasServerFilter = serverFilters.length > 0;\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 if (onlyDeferred === true && lcTool.defer_loading !== true) {\n return false;\n }\n if (\n hasServerFilter &&\n !isFromAnyMcpServer(lcTool.name, serverFilters)\n ) {\n return false;\n }\n return 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 const serverMsg = hasServerFilter\n ? ` from MCP server(s): ${serverFilters.join(', ')}`\n : '';\n return [\n `No tools available to search${serverMsg}. The tool registry is empty or no matching deferred tools are registered.`,\n {\n tool_references: [],\n metadata: {\n total_searched: 0,\n pattern: query,\n mcp_server: serverFilters,\n },\n },\n ];\n }\n\n const isServerListing = hasServerFilter && query === '';\n\n if (isServerListing) {\n const formattedOutput = formatServerListing(\n deferredTools,\n serverFilters\n );\n\n return [\n formattedOutput,\n {\n tool_references: [],\n metadata: {\n total_available: deferredTools.length,\n mcp_server: serverFilters,\n listing_mode: true,\n },\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 mcp_server: serverFilters.length > 0 ? serverFilters : undefined,\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 extractMcpServerName,\n isFromMcpServer,\n isFromAnyMcpServer,\n normalizeServerFilter,\n getAvailableMcpServers,\n getDeferredToolsListing,\n getBaseToolName,\n formatServerListing,\n sanitizeRegex,\n escapeRegexSpecialChars,\n isDangerousPattern,\n countNestedGroups,\n hasNestedQuantifiers,\n};\n"],"names":[],"mappings":";;;;;;;;;;AAAA;AAWA,SAAS,eAAe,GAAA;IACtB,MAAM,GAAG,GAAG,eAEX;IACD,IAAI,OAAO,GAAG,KAAK,UAAU;AAAE,QAAA,OAAO,GAAG;AACzC,IAAA,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU;QAAE,OAAO,GAAG,CAAC,OAAO;AACzD,IAAA,IAAI,GAAG,CAAC,OAAO,IAAI,IAAI,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,UAAU;AAClE,QAAA,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO;AAC5B,IAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;AAC1E;AAEA,MAAM,IAAI,GAAG,eAAe,EAAE;AAS9B,MAAM,EAAE;AAER;AACA,MAAM,kBAAkB,GAAG,GAAG;AAE9B;AACA,MAAM,oBAAoB,GAAG,CAAC;AAE9B;AACA,MAAM,cAAc,GAAG,IAAI;AAY3B;;;;AAIG;AACH,SAAS,sBAAsB,CAAC,IAAsB,EAAA;AACpD,IAAA,MAAM,gBAAgB,GACpB,IAAI,KAAK;AACP,UAAE;UACA,0FAA0F;IAEhG,OAAO,CAAC,CAAC,MAAM,CAAC;AACd,QAAA,KAAK,EAAE;AACJ,aAAA,MAAM;aACN,GAAG,CAAC,kBAAkB;AACtB,aAAA,QAAQ;aACR,OAAO,CAAC,EAAE;aACV,QAAQ,CAAC,gBAAgB,CAAC;AAC7B,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;AACzD,QAAA,UAAU,EAAE;AACT,aAAA,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AACvC,aAAA,QAAQ;aACR,QAAQ,CACP,8JAA8J,CAC/J;AACJ,KAAA,CAAC;AACJ;AAEA;;;;;AAKG;AACH,SAAS,oBAAoB,CAAC,QAAgB,EAAA;IAC5C,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC;AAChE,IAAA,IAAI,cAAc,KAAK,EAAE,EAAE;AACzB,QAAA,OAAO,SAAS;;AAElB,IAAA,OAAO,QAAQ,CAAC,SAAS,CAAC,cAAc,GAAG,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC;AAC5E;AAEA;;;;;AAKG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,UAAkB,EAAA;AAC3D,IAAA,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAAQ,CAAC;IACjD,OAAO,UAAU,KAAK,UAAU;AAClC;AAEA;;;;;AAKG;AACH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,WAAqB,EAAA;AACjE,IAAA,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAAQ,CAAC;AACjD,IAAA,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5B,QAAA,OAAO,KAAK;;AAEd,IAAA,OAAO,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC;AACzC;AAEA;;;;AAIG;AACH,SAAS,qBAAqB,CAC5B,YAA2C,EAAA;AAE3C,IAAA,IAAI,YAAY,KAAK,SAAS,EAAE;AAC9B,QAAA,OAAO,EAAE;;AAEX,IAAA,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE;AACpC,QAAA,OAAO,YAAY,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC;;AAElD,IAAA,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;AAC7C;AAEA;;;;;AAKG;AACH,SAAS,sBAAsB,CAC7B,YAA0C,EAC1C,eAAwB,IAAI,EAAA;IAE5B,IAAI,CAAC,YAAY,EAAE;AACjB,QAAA,OAAO,EAAE;;AAGX,IAAA,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU;IACjC,KAAK,MAAM,GAAG,OAAO,CAAC,IAAI,YAAY,EAAE;QACtC,IAAI,YAAY,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI,EAAE;YAClD;;QAEF,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC;QACjD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,EAAE;AACzC,YAAA,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;;;IAIvB,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE;AACnC;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;;;;;AAKG;AACH,SAAS,QAAQ,CAAC,IAAY,EAAA;AAC5B,IAAA,OAAO;AACJ,SAAA,WAAW;AACX,SAAA,OAAO,CAAC,YAAY,EAAE,GAAG;SACzB,KAAK,CAAC,KAAK;AACX,SAAA,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACxC;AAEA;;;;;AAKG;AACH,SAAS,kBAAkB,CAAC,IAAoB,EAAE,MAAgB,EAAA;IAChE,MAAM,KAAK,GAAa,EAAE;AAE1B,IAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;AAC3B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;AAC7C,QAAA,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;;IAGhC,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;AACtD,QAAA,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;;AAG9B,IAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE;AAChE,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AACpE,QAAA,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;;AAGxB,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACxB;AAEA;;;;;;AAMG;AACH,SAAS,gBAAgB,CACvB,IAAoB,EACpB,WAAqB,EACrB,MAAgB,EAAA;AAEhB,IAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AACzC,QAAA,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE;AAC/B,YAAA,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;gBAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE;;;;IAKlD,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE;AAChD,QAAA,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE;AAC/B,YAAA,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;gBAC7B,OAAO;AACL,oBAAA,KAAK,EAAE,aAAa;oBACpB,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;iBAC5C;;;;AAKP,IAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE;AAChE,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAC1D,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;AACrD,QAAA,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE;AAC/B,YAAA,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AAC9B,gBAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;;;;AAKpE,IAAA,MAAM,eAAe,GAAG,IAAI,CAAC;UACzB,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG;AACnC,UAAE,IAAI,CAAC,IAAI;IACb,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE;AACvD;AAEA;;;;;;;;AAQG;AACH,SAAS,kBAAkB,CACzB,KAAuB,EACvB,KAAa,EACb,MAAgB,EAChB,UAAkB,EAAA;AAElB,IAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE;QACvC,OAAO;AACL,YAAA,eAAe,EAAE,EAAE;YACnB,oBAAoB,EAAE,KAAK,CAAC,MAAM;AAClC,YAAA,YAAY,EAAE,KAAK;SACpB;;AAGH,IAAA,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACvE,IAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC;AAEnC,IAAA,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;QAC5B,OAAO;AACL,YAAA,eAAe,EAAE,EAAE;YACnB,oBAAoB,EAAE,KAAK,CAAC,MAAM;AAClC,YAAA,YAAY,EAAE,KAAK;SACpB;;AAGH,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAa;IAE7E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE;IAE7C,MAAM,OAAO,GAAyB,EAAE;AACxC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACrC,QAAA,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;AACjB,YAAA,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,gBAAgB,CACzC,KAAK,CAAC,CAAC,CAAC,EACR,WAAW,EACX,MAAM,CACP;AACD,YAAA,IAAI,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,CAAC;;AAGzD,YAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;AAC7D,YAAA,IAAI,QAAQ,KAAK,UAAU,EAAE;gBAC3B,eAAe,GAAG,GAAG;;AAChB,iBAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;gBAC1C,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC;;YAGnD,OAAO,CAAC,IAAI,CAAC;AACX,gBAAA,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI;AACxB,gBAAA,WAAW,EAAE,eAAe;AAC5B,gBAAA,aAAa,EAAE,KAAK;gBACpB,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,MAAM,MAAM,GAAG;QACb,KAAK,EAAE,eAAe,CAAC,MAAM;QAC7B,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;YACnC,IAAI,EAAE,GAAG,CAAC,SAAS;YACnB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACzC,UAAU,EAAE,GAAG,CAAC,aAAa;YAC7B,OAAO,EAAE,GAAG,CAAC,OAAO;AACrB,SAAA,CAAC,CAAC;AACH,QAAA,cAAc,EAAE,oBAAoB;AACpC,QAAA,KAAK,EAAE,YAAY;KACpB;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC;AAEA;;;;AAIG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAA;IACvC,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC;AAChE,IAAA,IAAI,cAAc,KAAK,EAAE,EAAE;AACzB,QAAA,OAAO,QAAQ;;IAEjB,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC;AAC9C;AAEA;;;;;;;AAOG;AACH,SAAS,uBAAuB,CAC9B,YAA0C,EAC1C,YAAqB,EAAA;IAErB,IAAI,CAAC,YAAY,EAAE;AACjB,QAAA,OAAO,EAAE;;IAGX,MAAM,aAAa,GAA6B,EAAE;IAElD,KAAK,MAAM,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE;QAC1C,IAAI,YAAY,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,EAAE;YACjD;;AAGF,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI;QAC5B,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAAQ,CAAC,IAAI,OAAO;AAC5D,QAAA,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC;AAE1C,QAAA,IAAI,EAAE,UAAU,IAAI,aAAa,CAAC,EAAE;AAClC,YAAA,aAAa,CAAC,UAAU,CAAC,GAAG,EAAE;;QAEhC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;;AAG1C,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;QAC3D,IAAI,CAAC,KAAK,OAAO;AAAE,YAAA,OAAO,CAAC;QAC3B,IAAI,CAAC,KAAK,OAAO;YAAE,OAAO,EAAE;AAC5B,QAAA,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;AAC3B,KAAC,CAAC;AAEF,IAAA,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;AAC5B,QAAA,OAAO,EAAE;;IAGX,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAC3B,CAAC,MAAM,KAAK,CAAA,EAAG,MAAM,CAAK,EAAA,EAAA,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAE,CAAA,CAC7D;AAED,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACzB;AAEA;;;;;;AAMG;AACH,SAAS,mBAAmB,CAC1B,KAAuB,EACvB,WAA8B,EAAA;AAE9B,IAAA,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,GAAG,CAAC,WAAW,CAAC;AAExE,IAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QACtB,OAAO,IAAI,CAAC,SAAS,CACnB;AACE,YAAA,YAAY,EAAE,IAAI;YAClB,OAAO;AACP,YAAA,WAAW,EAAE,CAAC;AACd,YAAA,eAAe,EAAE,EAAE;AACnB,YAAA,IAAI,EAAE,kDAAkD;AACzD,SAAA,EACD,IAAI,EACJ,CAAC,CACF;;IAGH,MAAM,aAAa,GAGf,EAAE;AACN,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS;AAC3D,QAAA,IAAI,EAAE,MAAM,IAAI,aAAa,CAAC,EAAE;AAC9B,YAAA,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE;;AAE5B,QAAA,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;AACzB,YAAA,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;AAChC,YAAA,WAAW,EACT,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG;AACxB,kBAAE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG;kBACpC,IAAI,CAAC,WAAW;AACvB,SAAA,CAAC;;AAGJ,IAAA,MAAM,MAAM,GAAG;AACb,QAAA,YAAY,EAAE,IAAI;QAClB,OAAO;QACP,WAAW,EAAE,KAAK,CAAC,MAAM;AACzB,QAAA,eAAe,EAAE,aAAa;AAC9B,QAAA,IAAI,EAAE,CAAA,oDAAA,EAAuD,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,WAAW,CAAC,CAAgB,cAAA,CAAA;KAC5H;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC;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;IAE5C,MAAM,oBAAoB,GAAG,uBAAuB,CAClD,UAAU,CAAC,YAAY,EACvB,mBAAmB,CACpB;AAED,IAAA,MAAM,gBAAgB,GACpB,oBAAoB,CAAC,MAAM,GAAG;AAC5B,UAAE;;;AAGN,EAAA,oBAAoB,CAAE;UAChB,EAAE;IAER,MAAM,OAAO,GACX,oBAAoB,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,CAAC;QACtD,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AACxE,UAAE;AAC0B,gCAAA,EAAA,SAAS,CAAC,aAAa,CAAA;AACd,0CAAA;UACnC,EAAE;AAER,IAAA,MAAM,WAAW,GACf,IAAI,KAAK;AACP,UAAE;;AAEN,EAAA,OAAO,GAAG,gBAAgB;AAC3B,CAAA,CAAC,IAAI;AACA,UAAE;;AAEN,EAAA,OAAO,GAAG,gBAAgB;CAC3B,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,EAChB,UAAU,GACX,GAAG,MAAM;AAEV,QAAA,MAAM,EACJ,YAAY,EAAE,iBAAiB,EAC/B,YAAY,EAAE,iBAAiB,EAC/B,SAAS,EAAE,cAAc,GAC1B,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;QACzB,MAAM,eAAe,GACnB,UAAU,IAAI,cAAc,IAAI,UAAU,CAAC,SAAS;AACtD,QAAA,MAAM,aAAa,GAAG,qBAAqB,CAAC,eAAe,CAAC;AAC5D,QAAA,MAAM,eAAe,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC;AAEhD,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,aAAA,MAAM,CAAC,CAAC,MAAM,KAAI;YACjB,IAAI,YAAY,KAAK,IAAI,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI,EAAE;AAC1D,gBAAA,OAAO,KAAK;;AAEd,YAAA,IACE,eAAe;gBACf,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,EAC/C;AACA,gBAAA,OAAO,KAAK;;AAEd,YAAA,OAAO,IAAI;AACb,SAAC;AACA,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,MAAM,SAAS,GAAG;kBACd,wBAAwB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAE;kBAClD,EAAE;YACN,OAAO;AACL,gBAAA,CAAA,4BAAA,EAA+B,SAAS,CAA4E,0EAAA,CAAA;AACpH,gBAAA;AACE,oBAAA,eAAe,EAAE,EAAE;AACnB,oBAAA,QAAQ,EAAE;AACR,wBAAA,cAAc,EAAE,CAAC;AACjB,wBAAA,OAAO,EAAE,KAAK;AACd,wBAAA,UAAU,EAAE,aAAa;AAC1B,qBAAA;AACF,iBAAA;aACF;;AAGH,QAAA,MAAM,eAAe,GAAG,eAAe,IAAI,KAAK,KAAK,EAAE;QAEvD,IAAI,eAAe,EAAE;YACnB,MAAM,eAAe,GAAG,mBAAmB,CACzC,aAAa,EACb,aAAa,CACd;YAED,OAAO;gBACL,eAAe;AACf,gBAAA;AACE,oBAAA,eAAe,EAAE,EAAE;AACnB,oBAAA,QAAQ,EAAE;wBACR,eAAe,EAAE,aAAa,CAAC,MAAM;AACrC,wBAAA,UAAU,EAAE,aAAa;AACzB,wBAAA,YAAY,EAAE,IAAI;AACnB,qBAAA;AACF,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;AACpC,wBAAA,UAAU,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,aAAa,GAAG,SAAS;AACjE,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;;;;"}
@@ -44,6 +44,12 @@ export declare abstract class Graph<T extends t.BaseGraphState = t.BaseGraphStat
44
44
  /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
45
45
  invokedToolIds?: Set<string>;
46
46
  handlerRegistry: HandlerRegistry | undefined;
47
+ /**
48
+ * Tool session contexts for automatic state persistence across tool invocations.
49
+ * Keyed by tool name (e.g., Constants.EXECUTE_CODE).
50
+ * Currently supports code execution session tracking (session_id, files).
51
+ */
52
+ sessions: t.ToolSessionMap;
47
53
  }
48
54
  export declare class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
49
55
  overrideModel?: t.ChatModel;
@@ -6,18 +6,15 @@ export declare const getCodeBaseURL: () => string;
6
6
  declare const CodeExecutionToolSchema: z.ZodObject<{
7
7
  lang: z.ZodEnum<["py", "js", "ts", "c", "cpp", "java", "php", "rs", "go", "d", "f90", "r"]>;
8
8
  code: z.ZodString;
9
- session_id: z.ZodOptional<z.ZodString>;
10
9
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
11
10
  }, "strip", z.ZodTypeAny, {
12
11
  code: string;
13
12
  lang: "r" | "d" | "py" | "js" | "ts" | "c" | "cpp" | "java" | "php" | "rs" | "go" | "f90";
14
13
  args?: string[] | undefined;
15
- session_id?: string | undefined;
16
14
  }, {
17
15
  code: string;
18
16
  lang: "r" | "d" | "py" | "js" | "ts" | "c" | "cpp" | "java" | "php" | "rs" | "go" | "f90";
19
17
  args?: string[] | undefined;
20
- session_id?: string | undefined;
21
18
  }>;
22
19
  declare function createCodeExecutionTool(params?: t.CodeExecutionToolParams): DynamicStructuredTool<typeof CodeExecutionToolSchema>;
23
20
  export { createCodeExecutionTool };
@@ -3,16 +3,13 @@ import { DynamicStructuredTool } from '@langchain/core/tools';
3
3
  import type * as t from '@/types';
4
4
  declare const ProgrammaticToolCallingSchema: z.ZodObject<{
5
5
  code: z.ZodString;
6
- session_id: z.ZodOptional<z.ZodString>;
7
6
  timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
8
7
  }, "strip", z.ZodTypeAny, {
9
8
  code: string;
10
9
  timeout: number;
11
- session_id?: string | undefined;
12
10
  }, {
13
11
  code: string;
14
12
  timeout?: number | undefined;
15
- session_id?: string | undefined;
16
13
  }>;
17
14
  /**
18
15
  * Normalizes a tool name to Python identifier format.
@@ -16,7 +16,9 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
16
16
  private toolRegistry?;
17
17
  /** Cached programmatic tools (computed once on first PTC call) */
18
18
  private programmaticCache?;
19
- constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, }: t.ToolNodeConstructorParams);
19
+ /** Reference to Graph's sessions map for automatic session injection */
20
+ private sessions?;
21
+ constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, }: t.ToolNodeConstructorParams);
20
22
  /**
21
23
  * Returns cached programmatic tools, computing once on first access.
22
24
  * Single iteration builds both toolMap and toolDefs simultaneously.
@@ -29,6 +29,8 @@ export type ToolNodeOptions = {
29
29
  errorHandler?: (data: ToolErrorData, metadata?: Record<string, unknown>) => Promise<void>;
30
30
  /** Tool registry for lazy computation of programmatic tools and tool search */
31
31
  toolRegistry?: LCToolRegistry;
32
+ /** Reference to Graph's sessions map for automatic session injection */
33
+ sessions?: ToolSessionMap;
32
34
  };
33
35
  export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
34
36
  export type ToolEndEvent = {
@@ -205,3 +207,33 @@ export type ProgrammaticToolCallingParams = {
205
207
  /** Environment variable key for API key */
206
208
  [key: string]: unknown;
207
209
  };
210
+ /**
211
+ * Tracks code execution session state for automatic file persistence.
212
+ * Stored in Graph.sessions and injected into subsequent tool invocations.
213
+ */
214
+ export type CodeSessionContext = {
215
+ /** Session ID from the code execution environment */
216
+ session_id: string;
217
+ /** Files generated in this session (for context/tracking) */
218
+ files: FileRefs;
219
+ /** Timestamp of last update */
220
+ lastUpdated: number;
221
+ };
222
+ /**
223
+ * Artifact structure returned by code execution tools (CodeExecutor, PTC).
224
+ * Used to extract session context after tool completion.
225
+ */
226
+ export type CodeExecutionArtifact = {
227
+ session_id?: string;
228
+ files?: FileRefs;
229
+ };
230
+ /**
231
+ * Generic session context union type for different tool types.
232
+ * Extend this as new tool session types are added.
233
+ */
234
+ export type ToolSessionContext = CodeSessionContext;
235
+ /**
236
+ * Map of tool names to their session contexts.
237
+ * Keys are tool constants (e.g., Constants.EXECUTE_CODE, Constants.PROGRAMMATIC_TOOL_CALLING).
238
+ */
239
+ export type ToolSessionMap = Map<string, ToolSessionContext>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.0.74",
3
+ "version": "3.0.76",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -50,7 +50,8 @@
50
50
  "code_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
51
51
  "image": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/image.ts --provider 'google' --name 'Jo' --location 'New York, NY'",
52
52
  "code_exec_files": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_files.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
53
- "code_exec_simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_simple.ts --provider 'google' --name 'Jo' --location 'New York, NY'",
53
+ "code_exec_session": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_session.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
54
+ "code_exec_simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_simple.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
54
55
  "simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/simple.ts --provider 'openrouter' --name 'Jo' --location 'New York, NY'",
55
56
  "caching": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/caching.ts --name 'Jo' --location 'New York, NY'",
56
57
  "thinking": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/thinking.ts --name 'Jo' --location 'New York, NY'",
@@ -35,6 +35,7 @@ import {
35
35
  GraphEvents,
36
36
  Providers,
37
37
  StepTypes,
38
+ Constants,
38
39
  } from '@/common';
39
40
  import {
40
41
  formatAnthropicArtifactContent,
@@ -135,6 +136,12 @@ export abstract class Graph<
135
136
  /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
136
137
  invokedToolIds?: Set<string>;
137
138
  handlerRegistry: HandlerRegistry | undefined;
139
+ /**
140
+ * Tool session contexts for automatic state persistence across tool invocations.
141
+ * Keyed by tool name (e.g., Constants.EXECUTE_CODE).
142
+ * Currently supports code execution session tracking (session_id, files).
143
+ */
144
+ sessions: t.ToolSessionMap = new Map();
138
145
  }
139
146
 
140
147
  export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
@@ -457,6 +464,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
457
464
  errorHandler: (data, metadata) =>
458
465
  StandardGraph.handleToolCallErrorStatic(this, data, metadata),
459
466
  toolRegistry: agentContext?.toolRegistry,
467
+ sessions: this.sessions,
460
468
  });
461
469
  }
462
470
 
@@ -1043,6 +1051,42 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1043
1051
  throw new Error(`No run step found for stepId ${stepId}`);
1044
1052
  }
1045
1053
 
1054
+ /**
1055
+ * Extract and store code execution session context from artifacts.
1056
+ * Only update session_id when files are generated - this ensures we don't
1057
+ * lose the original session that contains the files.
1058
+ */
1059
+ const toolName = output.name;
1060
+ if (
1061
+ toolName === Constants.EXECUTE_CODE ||
1062
+ toolName === Constants.PROGRAMMATIC_TOOL_CALLING
1063
+ ) {
1064
+ const artifact = output.artifact as t.CodeExecutionArtifact | undefined;
1065
+ const newFiles = artifact?.files ?? [];
1066
+ const hasNewFiles = newFiles.length > 0;
1067
+
1068
+ if (
1069
+ hasNewFiles &&
1070
+ artifact?.session_id != null &&
1071
+ artifact.session_id !== ''
1072
+ ) {
1073
+ /**
1074
+ * Files were generated - update session with the new session_id.
1075
+ * The new session_id is the one that contains these files.
1076
+ */
1077
+ const existingSession = this.sessions.get(Constants.EXECUTE_CODE) as
1078
+ | t.CodeSessionContext
1079
+ | undefined;
1080
+ const existingFiles = existingSession?.files ?? [];
1081
+
1082
+ this.sessions.set(Constants.EXECUTE_CODE, {
1083
+ session_id: artifact.session_id,
1084
+ files: [...existingFiles, ...newFiles],
1085
+ lastUpdated: Date.now(),
1086
+ });
1087
+ }
1088
+ }
1089
+
1046
1090
  const dispatchedOutput =
1047
1091
  typeof output.content === 'string'
1048
1092
  ? output.content
@@ -1,4 +1,11 @@
1
- // src/scripts/cli.ts
1
+ // src/scripts/code_exec_files.ts
2
+ /**
3
+ * Tests automatic session tracking for code execution file persistence.
4
+ * Files created in one execution are automatically available in subsequent executions
5
+ * without the LLM needing to track or pass session_id.
6
+ *
7
+ * Run with: npm run code_exec_files
8
+ */
2
9
  import { config } from 'dotenv';
3
10
  config();
4
11
  import { HumanMessage, BaseMessage } from '@langchain/core/messages';
@@ -12,12 +19,39 @@ import {
12
19
  } from '@/events';
13
20
  import { getLLMConfig } from '@/utils/llmConfig';
14
21
  import { getArgs } from '@/scripts/args';
15
- import { GraphEvents } from '@/common';
22
+ import { Constants, GraphEvents } from '@/common';
16
23
  import { Run } from '@/run';
17
24
  import { createCodeExecutionTool } from '@/tools/CodeExecutor';
18
25
 
19
26
  const conversationHistory: BaseMessage[] = [];
20
27
 
28
+ /**
29
+ * Prints session context from the graph for debugging
30
+ */
31
+ function printSessionContext(run: Run<t.IState>): void {
32
+ const graph = run.Graph;
33
+ if (!graph) {
34
+ console.log('[Session] No graph available');
35
+ return;
36
+ }
37
+
38
+ const session = graph.sessions.get(Constants.EXECUTE_CODE) as
39
+ | t.CodeSessionContext
40
+ | undefined;
41
+
42
+ if (!session) {
43
+ console.log('[Session] No session context stored yet');
44
+ return;
45
+ }
46
+
47
+ console.log('[Session] Current session context:');
48
+ console.log(` - session_id: ${session.session_id}`);
49
+ console.log(` - files: ${JSON.stringify(session.files, null, 2)}`);
50
+ console.log(
51
+ ` - lastUpdated: ${new Date(session.lastUpdated).toISOString()}`
52
+ );
53
+ }
54
+
21
55
  async function testCodeExecution(): Promise<void> {
22
56
  const { userName, location, provider, currentDate } = await getArgs();
23
57
  const { contentParts, aggregateContent } = createContentAggregator();
@@ -72,7 +106,7 @@ async function testCodeExecution(): Promise<void> {
72
106
  handle: (
73
107
  _event: string,
74
108
  data: t.StreamEventData,
75
- metadata?: Record<string, unknown>
109
+ _metadata?: Record<string, unknown>
76
110
  ): void => {
77
111
  console.log('====== TOOL_START ======');
78
112
  console.dir(data, { depth: null });
@@ -96,7 +130,7 @@ async function testCodeExecution(): Promise<void> {
96
130
  customHandlers,
97
131
  });
98
132
 
99
- const config: Partial<RunnableConfig> & {
133
+ const streamConfig: Partial<RunnableConfig> & {
100
134
  version: 'v1' | 'v2';
101
135
  run_id?: string;
102
136
  streamMode: string;
@@ -107,10 +141,12 @@ async function testCodeExecution(): Promise<void> {
107
141
  },
108
142
  streamMode: 'values',
109
143
  version: 'v2' as const,
110
- // recursionLimit: 3,
111
144
  };
112
145
 
113
- console.log('Test 1: Create Project Plan');
146
+ console.log('\n========== Test 1: Create Project Plan ==========\n');
147
+ console.log(
148
+ 'Creating initial file - this establishes the session context.\n'
149
+ );
114
150
 
115
151
  const userMessage1 = `
116
152
  Hi ${userName} here. We are testing your file capabilities.
@@ -125,36 +161,43 @@ async function testCodeExecution(): Promise<void> {
125
161
  let inputs = {
126
162
  messages: conversationHistory,
127
163
  };
128
- const finalContentParts1 = await run.processStream(inputs, config);
164
+ await run.processStream(inputs, streamConfig);
129
165
  const finalMessages1 = run.getRunMessages();
130
166
  if (finalMessages1) {
131
167
  conversationHistory.push(...finalMessages1);
132
168
  }
133
- console.log('\n\n====================\n\n');
169
+
170
+ console.log('\n\n========== Session Context After Test 1 ==========\n');
171
+ printSessionContext(run);
134
172
  console.dir(contentParts, { depth: null });
135
173
 
136
- console.log('Test 2: Edit Project Plan');
174
+ console.log('\n========== Test 2: Edit Project Plan ==========\n');
175
+ console.log(
176
+ 'Editing the file from Test 1 - session_id is automatically injected.\n'
177
+ );
137
178
 
138
179
  const userMessage2 = `
139
180
  Thanks for creating the project plan. Now I'd like you to edit the same plan to:
140
181
 
141
- 1. Add a new section called "Technology Stack" that contains: "The technology stack for this project includes the following technologies" and nothing more.
142
-
182
+ 1. Read the existing project_plan.txt file
183
+ 2. Add a new section called "Technology Stack" that contains: "The technology stack for this project includes the following technologies" and nothing more.
184
+ 3. Save this as a new file called "project_plan_v2.txt" (remember files are read-only)
185
+ 4. Print the contents of both files to verify
143
186
  `;
144
187
 
145
- // Make sure to pass the file ID of the previous file you created and explicitly duplicate or rename the file in your code so we can then access it. Also print the contents of the new file to ensure we did what we wanted.`;
146
-
147
188
  conversationHistory.push(new HumanMessage(userMessage2));
148
189
 
149
190
  inputs = {
150
191
  messages: conversationHistory,
151
192
  };
152
- const finalContentParts2 = await run.processStream(inputs, config);
193
+ await run.processStream(inputs, streamConfig);
153
194
  const finalMessages2 = run.getRunMessages();
154
195
  if (finalMessages2) {
155
196
  conversationHistory.push(...finalMessages2);
156
197
  }
157
- console.log('\n\n====================\n\n');
198
+
199
+ console.log('\n\n========== Session Context After Test 2 ==========\n');
200
+ printSessionContext(run);
158
201
  console.dir(contentParts, { depth: null });
159
202
 
160
203
  const { handleLLMEnd, collected } = createMetadataAggregator();