illuma-agents 1.0.37 → 1.0.38

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 (125) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +69 -14
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +3 -1
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +50 -8
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/graphs/MultiAgentGraph.cjs +277 -11
  8. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  9. package/dist/cjs/llm/bedrock/index.cjs +128 -61
  10. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  11. package/dist/cjs/main.cjs +16 -7
  12. package/dist/cjs/main.cjs.map +1 -1
  13. package/dist/cjs/messages/cache.cjs +1 -0
  14. package/dist/cjs/messages/cache.cjs.map +1 -1
  15. package/dist/cjs/messages/core.cjs +1 -1
  16. package/dist/cjs/messages/core.cjs.map +1 -1
  17. package/dist/cjs/messages/tools.cjs +2 -2
  18. package/dist/cjs/messages/tools.cjs.map +1 -1
  19. package/dist/cjs/stream.cjs +4 -2
  20. package/dist/cjs/stream.cjs.map +1 -1
  21. package/dist/cjs/tools/BrowserTools.cjs.map +1 -1
  22. package/dist/cjs/tools/CodeExecutor.cjs +22 -21
  23. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  24. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +14 -11
  25. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  26. package/dist/cjs/tools/ToolNode.cjs +101 -2
  27. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  28. package/dist/cjs/tools/ToolSearch.cjs +862 -0
  29. package/dist/cjs/tools/ToolSearch.cjs.map +1 -0
  30. package/dist/esm/agents/AgentContext.mjs +69 -14
  31. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  32. package/dist/esm/common/enum.mjs +3 -1
  33. package/dist/esm/common/enum.mjs.map +1 -1
  34. package/dist/esm/graphs/Graph.mjs +51 -9
  35. package/dist/esm/graphs/Graph.mjs.map +1 -1
  36. package/dist/esm/graphs/MultiAgentGraph.mjs +278 -12
  37. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  38. package/dist/esm/llm/bedrock/index.mjs +127 -60
  39. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  40. package/dist/esm/main.mjs +1 -1
  41. package/dist/esm/messages/cache.mjs +1 -0
  42. package/dist/esm/messages/cache.mjs.map +1 -1
  43. package/dist/esm/messages/core.mjs +1 -1
  44. package/dist/esm/messages/core.mjs.map +1 -1
  45. package/dist/esm/messages/tools.mjs +2 -2
  46. package/dist/esm/messages/tools.mjs.map +1 -1
  47. package/dist/esm/stream.mjs +4 -2
  48. package/dist/esm/stream.mjs.map +1 -1
  49. package/dist/esm/tools/BrowserTools.mjs.map +1 -1
  50. package/dist/esm/tools/CodeExecutor.mjs +22 -21
  51. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  52. package/dist/esm/tools/ProgrammaticToolCalling.mjs +14 -11
  53. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  54. package/dist/esm/tools/ToolNode.mjs +102 -3
  55. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  56. package/dist/esm/tools/ToolSearch.mjs +827 -0
  57. package/dist/esm/tools/ToolSearch.mjs.map +1 -0
  58. package/dist/types/agents/AgentContext.d.ts +33 -1
  59. package/dist/types/common/enum.d.ts +4 -2
  60. package/dist/types/graphs/Graph.d.ts +6 -0
  61. package/dist/types/graphs/MultiAgentGraph.d.ts +16 -0
  62. package/dist/types/index.d.ts +1 -1
  63. package/dist/types/llm/bedrock/index.d.ts +89 -11
  64. package/dist/types/llm/bedrock/types.d.ts +27 -0
  65. package/dist/types/llm/bedrock/utils/index.d.ts +5 -0
  66. package/dist/types/llm/bedrock/utils/message_inputs.d.ts +31 -0
  67. package/dist/types/llm/bedrock/utils/message_outputs.d.ts +33 -0
  68. package/dist/types/tools/CodeExecutor.d.ts +0 -3
  69. package/dist/types/tools/ProgrammaticToolCalling.d.ts +0 -3
  70. package/dist/types/tools/ToolNode.d.ts +3 -1
  71. package/dist/types/tools/ToolSearch.d.ts +148 -0
  72. package/dist/types/types/graph.d.ts +2 -0
  73. package/dist/types/types/llm.d.ts +3 -1
  74. package/dist/types/types/tools.d.ts +42 -2
  75. package/package.json +12 -5
  76. package/src/agents/AgentContext.ts +88 -16
  77. package/src/common/enum.ts +3 -1
  78. package/src/graphs/Graph.ts +64 -13
  79. package/src/graphs/MultiAgentGraph.ts +350 -13
  80. package/src/index.ts +1 -1
  81. package/src/llm/bedrock/index.ts +221 -99
  82. package/src/llm/bedrock/llm.spec.ts +616 -0
  83. package/src/llm/bedrock/types.ts +51 -0
  84. package/src/llm/bedrock/utils/index.ts +18 -0
  85. package/src/llm/bedrock/utils/message_inputs.ts +563 -0
  86. package/src/llm/bedrock/utils/message_outputs.ts +310 -0
  87. package/src/messages/__tests__/tools.test.ts +21 -21
  88. package/src/messages/cache.test.ts +259 -0
  89. package/src/messages/cache.ts +104 -1
  90. package/src/messages/core.ts +1 -1
  91. package/src/messages/tools.ts +2 -2
  92. package/src/scripts/caching.ts +27 -19
  93. package/src/scripts/code_exec_files.ts +58 -15
  94. package/src/scripts/code_exec_multi_session.ts +241 -0
  95. package/src/scripts/code_exec_session.ts +282 -0
  96. package/src/scripts/multi-agent-conditional.ts +1 -0
  97. package/src/scripts/multi-agent-supervisor.ts +1 -0
  98. package/src/scripts/programmatic_exec_agent.ts +4 -4
  99. package/src/scripts/test-handoff-preamble.ts +277 -0
  100. package/src/scripts/test-parallel-handoffs.ts +291 -0
  101. package/src/scripts/test-tools-before-handoff.ts +8 -4
  102. package/src/scripts/test_code_api.ts +361 -0
  103. package/src/scripts/thinking-bedrock.ts +159 -0
  104. package/src/scripts/thinking.ts +39 -18
  105. package/src/scripts/{tool_search_regex.ts → tool_search.ts} +5 -5
  106. package/src/scripts/tools.ts +7 -3
  107. package/src/stream.ts +4 -2
  108. package/src/tools/BrowserTools.ts +39 -17
  109. package/src/tools/CodeExecutor.ts +26 -23
  110. package/src/tools/ProgrammaticToolCalling.ts +18 -14
  111. package/src/tools/ToolNode.ts +114 -1
  112. package/src/tools/ToolSearch.ts +1041 -0
  113. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +0 -2
  114. package/src/tools/__tests__/{ToolSearchRegex.integration.test.ts → ToolSearch.integration.test.ts} +6 -6
  115. package/src/tools/__tests__/ToolSearch.test.ts +1003 -0
  116. package/src/types/graph.ts +2 -0
  117. package/src/types/llm.ts +3 -1
  118. package/src/types/tools.ts +51 -2
  119. package/dist/cjs/tools/ToolSearchRegex.cjs +0 -455
  120. package/dist/cjs/tools/ToolSearchRegex.cjs.map +0 -1
  121. package/dist/esm/tools/ToolSearchRegex.mjs +0 -448
  122. package/dist/esm/tools/ToolSearchRegex.mjs.map +0 -1
  123. package/dist/types/tools/ToolSearchRegex.d.ts +0 -80
  124. package/src/tools/ToolSearchRegex.ts +0 -535
  125. package/src/tools/__tests__/ToolSearchRegex.test.ts +0 -232
@@ -0,0 +1,148 @@
1
+ import { z } from 'zod';
2
+ import { DynamicStructuredTool } from '@langchain/core/tools';
3
+ import type * as t from '@/types';
4
+ /** Zod schema type for tool search parameters */
5
+ type ToolSearchSchema = z.ZodObject<{
6
+ query: z.ZodDefault<z.ZodOptional<z.ZodString>>;
7
+ fields: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodEnum<['name', 'description', 'parameters']>>>>;
8
+ max_results: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
9
+ mcp_server: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString>]>>;
10
+ }>;
11
+ /**
12
+ * Creates the Zod schema with dynamic query description based on mode.
13
+ * @param mode - The search mode determining query interpretation
14
+ * @returns Zod schema for tool search parameters
15
+ */
16
+ declare function createToolSearchSchema(mode: t.ToolSearchMode): ToolSearchSchema;
17
+ /**
18
+ * Extracts the MCP server name from a tool name.
19
+ * MCP tools follow the pattern: toolName_mcp_serverName
20
+ * @param toolName - The full tool name
21
+ * @returns The server name if it's an MCP tool, undefined otherwise
22
+ */
23
+ declare function extractMcpServerName(toolName: string): string | undefined;
24
+ /**
25
+ * Checks if a tool belongs to a specific MCP server.
26
+ * @param toolName - The full tool name
27
+ * @param serverName - The server name to match
28
+ * @returns True if the tool belongs to the specified server
29
+ */
30
+ declare function isFromMcpServer(toolName: string, serverName: string): boolean;
31
+ /**
32
+ * Checks if a tool belongs to any of the specified MCP servers.
33
+ * @param toolName - The full tool name
34
+ * @param serverNames - Array of server names to match
35
+ * @returns True if the tool belongs to any of the specified servers
36
+ */
37
+ declare function isFromAnyMcpServer(toolName: string, serverNames: string[]): boolean;
38
+ /**
39
+ * Normalizes server filter input to always be an array.
40
+ * @param serverFilter - String, array of strings, or undefined
41
+ * @returns Array of server names (empty if none specified)
42
+ */
43
+ declare function normalizeServerFilter(serverFilter: string | string[] | undefined): string[];
44
+ /**
45
+ * Extracts all unique MCP server names from a tool registry.
46
+ * @param toolRegistry - The tool registry to scan
47
+ * @param onlyDeferred - If true, only considers deferred tools
48
+ * @returns Array of unique server names, sorted alphabetically
49
+ */
50
+ declare function getAvailableMcpServers(toolRegistry: t.LCToolRegistry | undefined, onlyDeferred?: boolean): string[];
51
+ /**
52
+ * Escapes special regex characters in a string to use as a literal pattern.
53
+ * @param pattern - The string to escape
54
+ * @returns The escaped string safe for use in a RegExp
55
+ */
56
+ declare function escapeRegexSpecialChars(pattern: string): string;
57
+ /**
58
+ * Counts the maximum nesting depth of groups in a regex pattern.
59
+ * @param pattern - The regex pattern to analyze
60
+ * @returns The maximum nesting depth
61
+ */
62
+ declare function countNestedGroups(pattern: string): number;
63
+ /**
64
+ * Detects nested quantifiers that can cause catastrophic backtracking.
65
+ * Patterns like (a+)+, (a*)*, (a+)*, etc.
66
+ * @param pattern - The regex pattern to check
67
+ * @returns True if nested quantifiers are detected
68
+ */
69
+ declare function hasNestedQuantifiers(pattern: string): boolean;
70
+ /**
71
+ * Checks if a regex pattern contains potentially dangerous constructs.
72
+ * @param pattern - The regex pattern to validate
73
+ * @returns True if the pattern is dangerous
74
+ */
75
+ declare function isDangerousPattern(pattern: string): boolean;
76
+ /**
77
+ * Sanitizes a regex pattern for safe execution.
78
+ * If the pattern is dangerous, it will be escaped to a literal string search.
79
+ * @param pattern - The regex pattern to sanitize
80
+ * @returns Object containing the safe pattern and whether it was escaped
81
+ */
82
+ declare function sanitizeRegex(pattern: string): {
83
+ safe: string;
84
+ wasEscaped: boolean;
85
+ };
86
+ /**
87
+ * Performs BM25-based search for better relevance ranking.
88
+ * Uses Okapi BM25 algorithm for term frequency and document length normalization.
89
+ * @param tools - Array of tool metadata to search
90
+ * @param query - The search query
91
+ * @param fields - Which fields to search
92
+ * @param maxResults - Maximum results to return
93
+ * @returns Search response with matching tools ranked by BM25 score
94
+ */
95
+ declare function performLocalSearch(tools: t.ToolMetadata[], query: string, fields: string[], maxResults: number): t.ToolSearchResponse;
96
+ /**
97
+ * Extracts the base tool name (without MCP server suffix) from a full tool name.
98
+ * @param toolName - The full tool name
99
+ * @returns The base tool name without server suffix
100
+ */
101
+ declare function getBaseToolName(toolName: string): string;
102
+ /**
103
+ * Generates a compact listing of deferred tools grouped by server.
104
+ * Format: "server: tool1, tool2, tool3"
105
+ * Non-MCP tools are grouped under "other".
106
+ * @param toolRegistry - The tool registry
107
+ * @param onlyDeferred - Whether to only include deferred tools
108
+ * @returns Formatted string with tools grouped by server
109
+ */
110
+ declare function getDeferredToolsListing(toolRegistry: t.LCToolRegistry | undefined, onlyDeferred: boolean): string;
111
+ /**
112
+ * Formats a server listing response as structured JSON.
113
+ * NOTE: This is a PREVIEW only - tools are NOT discovered/loaded.
114
+ * @param tools - Array of tool metadata from the server(s)
115
+ * @param serverNames - The MCP server name(s)
116
+ * @returns JSON string showing all tools grouped by server
117
+ */
118
+ declare function formatServerListing(tools: t.ToolMetadata[], serverNames: string | string[]): string;
119
+ /**
120
+ * Creates a Tool Search tool for discovering tools from a large registry.
121
+ *
122
+ * This tool enables AI agents to dynamically discover tools from a large library
123
+ * without loading all tool definitions into the LLM context window. The agent
124
+ * can search for relevant tools on-demand.
125
+ *
126
+ * **Modes:**
127
+ * - `code_interpreter` (default): Uses external sandbox for regex search. Safer for complex patterns.
128
+ * - `local`: Uses safe substring matching locally. No network call, faster, completely safe from ReDoS.
129
+ *
130
+ * The tool registry can be provided either:
131
+ * 1. At initialization time via params.toolRegistry
132
+ * 2. At runtime via config.configurable.toolRegistry when invoking
133
+ *
134
+ * @param params - Configuration parameters for the tool (toolRegistry is optional)
135
+ * @returns A LangChain DynamicStructuredTool for tool searching
136
+ *
137
+ * @example
138
+ * // Option 1: Code interpreter mode (regex via sandbox)
139
+ * const tool = createToolSearch({ apiKey, toolRegistry });
140
+ * await tool.invoke({ query: 'expense.*report' });
141
+ *
142
+ * @example
143
+ * // Option 2: Local mode (safe substring search, no API key needed)
144
+ * const tool = createToolSearch({ mode: 'local', toolRegistry });
145
+ * await tool.invoke({ query: 'expense' });
146
+ */
147
+ declare function createToolSearch(initParams?: t.ToolSearchParams): DynamicStructuredTool<ReturnType<typeof createToolSearchSchema>>;
148
+ export { createToolSearch, performLocalSearch, extractMcpServerName, isFromMcpServer, isFromAnyMcpServer, normalizeServerFilter, getAvailableMcpServers, getDeferredToolsListing, getBaseToolName, formatServerListing, sanitizeRegex, escapeRegexSpecialChars, isDangerousPattern, countNestedGroups, hasNestedQuantifiers, };
@@ -236,6 +236,8 @@ export type MultiAgentGraphInput = StandardGraphInput & {
236
236
  };
237
237
  export interface AgentInputs {
238
238
  agentId: string;
239
+ /** Human-readable name for the agent (used in handoff context). Defaults to agentId if not provided. */
240
+ name?: string;
239
241
  toolEnd?: boolean;
240
242
  toolMap?: ToolMap;
241
243
  tools?: GraphTools;
@@ -37,7 +37,9 @@ export type AnthropicReasoning = {
37
37
  thinkingBudget?: number;
38
38
  };
39
39
  export type OpenAIClientOptions = ChatOpenAIFields;
40
- export type AnthropicClientOptions = AnthropicInput;
40
+ export type AnthropicClientOptions = AnthropicInput & {
41
+ promptCache?: boolean;
42
+ };
41
43
  export type MistralAIClientOptions = ChatMistralAIInput;
42
44
  export type VertexAIClientOptions = ChatVertexAIInput & {
43
45
  includeThoughts?: boolean;
@@ -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 = {
@@ -55,6 +57,8 @@ export type FileRef = {
55
57
  id: string;
56
58
  name: string;
57
59
  path?: string;
60
+ /** Session ID this file belongs to (for multi-session file tracking) */
61
+ session_id?: string;
58
62
  };
59
63
  export type FileRefs = FileRef[];
60
64
  export type ExecuteResult = {
@@ -99,12 +103,18 @@ export type ProgrammaticCache = {
99
103
  toolMap: ToolMap;
100
104
  toolDefs: LCTool[];
101
105
  };
102
- /** Parameters for creating a Tool Search Regex tool */
103
- export type ToolSearchRegexParams = {
106
+ /** Search mode: code_interpreter uses external sandbox, local uses safe substring matching */
107
+ export type ToolSearchMode = 'code_interpreter' | 'local';
108
+ /** Parameters for creating a Tool Search tool */
109
+ export type ToolSearchParams = {
104
110
  apiKey?: string;
105
111
  toolRegistry?: LCToolRegistry;
106
112
  onlyDeferred?: boolean;
107
113
  baseUrl?: string;
114
+ /** Search mode: 'code_interpreter' (default) uses sandbox for regex, 'local' uses safe substring matching */
115
+ mode?: ToolSearchMode;
116
+ /** Filter tools to only those from specific MCP server(s). Can be a single name or array of names. */
117
+ mcpServer?: string | string[];
108
118
  [key: string]: unknown;
109
119
  };
110
120
  /** Simplified tool metadata for search purposes */
@@ -199,3 +209,33 @@ export type ProgrammaticToolCallingParams = {
199
209
  /** Environment variable key for API key */
200
210
  [key: string]: unknown;
201
211
  };
212
+ /**
213
+ * Tracks code execution session state for automatic file persistence.
214
+ * Stored in Graph.sessions and injected into subsequent tool invocations.
215
+ */
216
+ export type CodeSessionContext = {
217
+ /** Session ID from the code execution environment */
218
+ session_id: string;
219
+ /** Files generated in this session (for context/tracking) */
220
+ files: FileRefs;
221
+ /** Timestamp of last update */
222
+ lastUpdated: number;
223
+ };
224
+ /**
225
+ * Artifact structure returned by code execution tools (CodeExecutor, PTC).
226
+ * Used to extract session context after tool completion.
227
+ */
228
+ export type CodeExecutionArtifact = {
229
+ session_id?: string;
230
+ files?: FileRefs;
231
+ };
232
+ /**
233
+ * Generic session context union type for different tool types.
234
+ * Extend this as new tool session types are added.
235
+ */
236
+ export type ToolSessionContext = CodeSessionContext;
237
+ /**
238
+ * Map of tool names to their session contexts.
239
+ * Keys are tool constants (e.g., Constants.EXECUTE_CODE, Constants.PROGRAMMATIC_TOOL_CALLING).
240
+ */
241
+ export type ToolSessionMap = Map<string, ToolSessionContext>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "illuma-agents",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -44,14 +44,17 @@
44
44
  "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'",
45
45
  "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'",
46
46
  "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'",
47
- "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'",
48
- "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'",
47
+ "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'",
48
+ "code_exec_multi_session": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_multi_session.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
49
+ "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'",
50
+ "simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/simple.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
49
51
  "caching": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/caching.ts --name 'Jo' --location 'New York, NY'",
50
52
  "thinking": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/thinking.ts --name 'Jo' --location 'New York, NY'",
53
+ "thinking:bedrock": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/thinking-bedrock.ts --name 'Jo' --location 'New York, NY'",
51
54
  "memory": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/memory.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
52
- "tool": "node --trace-warnings -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'openrouter' --name 'Jo' --location 'New York, NY'",
55
+ "tool": "node --trace-warnings -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
53
56
  "search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/search.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
54
- "tool_search_regex": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tool_search_regex.ts",
57
+ "tool_search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tool_search.ts",
55
58
  "programmatic_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec.ts",
56
59
  "code_exec_ptc": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_ptc.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
57
60
  "programmatic_exec_agent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec_agent.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
@@ -69,6 +72,7 @@
69
72
  "multi-agent-sequence": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-sequence.ts",
70
73
  "multi-agent-conditional": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-conditional.ts",
71
74
  "multi-agent-supervisor": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-supervisor.ts",
75
+ "test-handoff-preamble": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-handoff-preamble.ts",
72
76
  "multi-agent-list-handoff": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-multi-agent-list-handoff.ts",
73
77
  "test-parallel-agent-labeling": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-parallel-agent-labeling.ts",
74
78
  "test-thinking-handoff": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-thinking-handoff.ts",
@@ -102,6 +106,7 @@
102
106
  }
103
107
  },
104
108
  "dependencies": {
109
+ "@aws-sdk/client-bedrock-runtime": "^3.970.0",
105
110
  "@langchain/anthropic": "^0.3.26",
106
111
  "@langchain/aws": "^0.1.15",
107
112
  "@langchain/core": "^0.3.80",
@@ -124,6 +129,7 @@
124
129
  "https-proxy-agent": "^7.0.6",
125
130
  "mathjs": "^15.1.0",
126
131
  "nanoid": "^3.3.7",
132
+ "okapibm25": "^1.4.1",
127
133
  "openai": "5.8.2"
128
134
  },
129
135
  "imports": {
@@ -151,6 +157,7 @@
151
157
  "eslint-plugin-import": "^2.31.0",
152
158
  "husky": "^9.1.7",
153
159
  "jest": "^30.2.0",
160
+ "jest-util": "^30.2.0",
154
161
  "lint-staged": "^15.2.7",
155
162
  "prettier": "^3.6.2",
156
163
  "rollup": "^4.34.6",
@@ -27,6 +27,7 @@ export class AgentContext {
27
27
  ): AgentContext {
28
28
  const {
29
29
  agentId,
30
+ name,
30
31
  provider,
31
32
  clientOptions,
32
33
  tools,
@@ -44,6 +45,7 @@ export class AgentContext {
44
45
 
45
46
  const agentContext = new AgentContext({
46
47
  agentId,
48
+ name: name ?? agentId,
47
49
  provider,
48
50
  clientOptions,
49
51
  maxContextTokens,
@@ -87,6 +89,8 @@ export class AgentContext {
87
89
 
88
90
  /** Agent identifier */
89
91
  agentId: string;
92
+ /** Human-readable name for this agent (used in handoff context). Falls back to agentId if not provided. */
93
+ name?: string;
90
94
  /** Provider for this specific agent */
91
95
  provider: Providers;
92
96
  /** Client options for this agent */
@@ -173,9 +177,20 @@ export class AgentContext {
173
177
  artifacts: 0,
174
178
  memory: 0,
175
179
  };
180
+ /**
181
+ * Handoff context when this agent receives control via handoff.
182
+ * Contains source and parallel execution info for system message context.
183
+ */
184
+ handoffContext?: {
185
+ /** Source agent that transferred control */
186
+ sourceAgentName: string;
187
+ /** Names of sibling agents executing in parallel (empty if sequential) */
188
+ parallelSiblings: string[];
189
+ };
176
190
 
177
191
  constructor({
178
192
  agentId,
193
+ name,
179
194
  provider,
180
195
  clientOptions,
181
196
  maxContextTokens,
@@ -193,6 +208,7 @@ export class AgentContext {
193
208
  useLegacyContent,
194
209
  }: {
195
210
  agentId: string;
211
+ name?: string;
196
212
  provider: Providers;
197
213
  clientOptions?: t.ClientOptions;
198
214
  maxContextTokens?: number;
@@ -210,6 +226,7 @@ export class AgentContext {
210
226
  useLegacyContent?: boolean;
211
227
  }) {
212
228
  this.agentId = agentId;
229
+ this.name = name;
213
230
  this.provider = provider;
214
231
  this.clientOptions = clientOptions;
215
232
  this.maxContextTokens = maxContextTokens;
@@ -324,27 +341,65 @@ export class AgentContext {
324
341
 
325
342
  /**
326
343
  * Builds the raw instructions string (without creating SystemMessage).
344
+ * Includes agent identity preamble and handoff context when available.
327
345
  */
328
346
  private buildInstructionsString(): string {
329
- let result = this.instructions ?? '';
347
+ const parts: string[] = [];
348
+
349
+ /** Build agent identity and handoff context preamble */
350
+ const identityPreamble = this.buildIdentityPreamble();
351
+ if (identityPreamble) {
352
+ parts.push(identityPreamble);
353
+ }
330
354
 
355
+ /** Add main instructions */
356
+ if (this.instructions != null && this.instructions !== '') {
357
+ parts.push(this.instructions);
358
+ }
359
+
360
+ /** Add additional instructions */
331
361
  if (
332
362
  this.additionalInstructions != null &&
333
363
  this.additionalInstructions !== ''
334
364
  ) {
335
- result = result
336
- ? `${result}\n\n${this.additionalInstructions}`
337
- : this.additionalInstructions;
365
+ parts.push(this.additionalInstructions);
338
366
  }
339
367
 
368
+ /** Add programmatic tools documentation */
340
369
  const programmaticToolsDoc = this.buildProgrammaticOnlyToolsInstructions();
341
370
  if (programmaticToolsDoc) {
342
- result = result
343
- ? `${result}${programmaticToolsDoc}`
344
- : programmaticToolsDoc;
371
+ parts.push(programmaticToolsDoc);
372
+ }
373
+
374
+ return parts.join('\n\n');
375
+ }
376
+
377
+ /**
378
+ * Builds the agent identity preamble including handoff context if present.
379
+ * This helps the agent understand its role in the multi-agent workflow.
380
+ */
381
+ private buildIdentityPreamble(): string {
382
+ if (!this.handoffContext) return '';
383
+
384
+ const displayName = this.name ?? this.agentId;
385
+ const { sourceAgentName, parallelSiblings } = this.handoffContext;
386
+ const isParallel = parallelSiblings.length > 0;
387
+
388
+ const lines: string[] = [];
389
+ lines.push('## Multi-Agent Workflow');
390
+ lines.push(
391
+ `You are "${displayName}", transferred from "${sourceAgentName}".`
392
+ );
393
+
394
+ if (isParallel) {
395
+ lines.push(`Running in parallel with: ${parallelSiblings.join(', ')}.`);
345
396
  }
346
397
 
347
- return result;
398
+ lines.push(
399
+ 'Execute only tasks relevant to your role. Routing is already handled if requested, unless you can route further.'
400
+ );
401
+
402
+ return lines.join('\n');
348
403
  }
349
404
 
350
405
  /**
@@ -374,14 +429,7 @@ export class AgentContext {
374
429
  const anthropicOptions = this.clientOptions as
375
430
  | t.AnthropicClientOptions
376
431
  | undefined;
377
- const defaultHeaders = anthropicOptions?.clientOptions?.defaultHeaders as
378
- | Record<string, string>
379
- | undefined;
380
- const anthropicBeta = defaultHeaders?.['anthropic-beta'];
381
- if (
382
- typeof anthropicBeta === 'string' &&
383
- anthropicBeta.includes('prompt-caching')
384
- ) {
432
+ if (anthropicOptions?.promptCache === true) {
385
433
  finalInstructions = {
386
434
  content: [
387
435
  {
@@ -455,6 +503,7 @@ export class AgentContext {
455
503
  this.tokenTypeSwitch = undefined;
456
504
  this.currentTokenType = ContentTypes.TEXT;
457
505
  this.discoveredToolNames.clear();
506
+ this.handoffContext = undefined;
458
507
  }
459
508
 
460
509
  /**
@@ -626,6 +675,29 @@ export class AgentContext {
626
675
  return registry;
627
676
  }
628
677
 
678
+ /**
679
+ * Sets the handoff context for this agent.
680
+ * Call this when the agent receives control via handoff from another agent.
681
+ * Marks system runnable as stale to include handoff context in system message.
682
+ * @param sourceAgentName - Name of the agent that transferred control
683
+ * @param parallelSiblings - Names of other agents executing in parallel with this one
684
+ */
685
+ setHandoffContext(sourceAgentName: string, parallelSiblings: string[]): void {
686
+ this.handoffContext = { sourceAgentName, parallelSiblings };
687
+ this.systemRunnableStale = true;
688
+ }
689
+
690
+ /**
691
+ * Clears any handoff context.
692
+ * Call this when resetting the agent or when handoff context is no longer relevant.
693
+ */
694
+ clearHandoffContext(): void {
695
+ if (this.handoffContext) {
696
+ this.handoffContext = undefined;
697
+ this.systemRunnableStale = true;
698
+ }
699
+ }
700
+
629
701
  /**
630
702
  * Marks tools as discovered via tool search.
631
703
  * Discovered tools will be included in the next model binding.
@@ -161,11 +161,13 @@ export enum Callback {
161
161
  export enum Constants {
162
162
  OFFICIAL_CODE_BASEURL = 'https://api.illuma.ai/v1',
163
163
  EXECUTE_CODE = 'execute_code',
164
- TOOL_SEARCH_REGEX = 'tool_search_regex',
164
+ TOOL_SEARCH = 'tool_search',
165
165
  PROGRAMMATIC_TOOL_CALLING = 'run_tools_with_code',
166
166
  WEB_SEARCH = 'web_search',
167
167
  CONTENT_AND_ARTIFACT = 'content_and_artifact',
168
168
  LC_TRANSFER_TO_ = 'lc_transfer_to_',
169
+ /** Delimiter for MCP tools: toolName_mcp_serverName */
170
+ MCP_DELIMITER = '_mcp_',
169
171
  }
170
172
 
171
173
  export enum TitleMethod {
@@ -37,6 +37,7 @@ import {
37
37
  Providers,
38
38
  StepTypes,
39
39
  MessageTypes,
40
+ Constants,
40
41
  } from '@/common';
41
42
  import {
42
43
  formatAnthropicArtifactContent,
@@ -141,6 +142,12 @@ export abstract class Graph<
141
142
  /** Set of invoked tool call IDs from non-message run steps completed mid-run, if any */
142
143
  invokedToolIds?: Set<string>;
143
144
  handlerRegistry: HandlerRegistry | undefined;
145
+ /**
146
+ * Tool session contexts for automatic state persistence across tool invocations.
147
+ * Keyed by tool name (e.g., Constants.EXECUTE_CODE).
148
+ * Currently supports code execution session tracking (session_id, files).
149
+ */
150
+ sessions: t.ToolSessionMap = new Map();
144
151
  }
145
152
 
146
153
  export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
@@ -487,11 +494,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
487
494
  finalInstructions != null &&
488
495
  finalInstructions &&
489
496
  provider === Providers.ANTHROPIC &&
490
- ((
491
- (clientOptions as t.AnthropicClientOptions).clientOptions
492
- ?.defaultHeaders as Record<string, string> | undefined
493
- )?.['anthropic-beta']?.includes('prompt-caching') ??
494
- false)
497
+ (clientOptions as t.AnthropicClientOptions).promptCache === true
495
498
  ) {
496
499
  finalInstructions = {
497
500
  content: [
@@ -528,6 +531,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
528
531
  errorHandler: (data, metadata) =>
529
532
  StandardGraph.handleToolCallErrorStatic(this, data, metadata),
530
533
  toolRegistry: agentContext?.toolRegistry,
534
+ sessions: this.sessions,
531
535
  });
532
536
  }
533
537
 
@@ -860,14 +864,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
860
864
  const anthropicOptions = agentContext.clientOptions as
861
865
  | t.AnthropicClientOptions
862
866
  | undefined;
863
- const defaultHeaders = anthropicOptions?.clientOptions
864
- ?.defaultHeaders as Record<string, string> | undefined;
865
- const anthropicBeta = defaultHeaders?.['anthropic-beta'];
866
-
867
- if (
868
- typeof anthropicBeta === 'string' &&
869
- anthropicBeta.includes('prompt-caching')
870
- ) {
867
+ if (anthropicOptions?.promptCache === true) {
871
868
  finalMessages = addCacheControl<BaseMessage>(finalMessages);
872
869
  }
873
870
  } else if (agentContext.provider === Providers.BEDROCK) {
@@ -1366,6 +1363,60 @@ If I seem to be missing something we discussed earlier, just give me a quick rem
1366
1363
  throw new Error(`No run step found for stepId ${stepId}`);
1367
1364
  }
1368
1365
 
1366
+ /**
1367
+ * Extract and store code execution session context from artifacts.
1368
+ * Each file is stamped with its source session_id to support multi-session file tracking.
1369
+ * When the same filename appears in a later execution, the newer version replaces the old.
1370
+ */
1371
+ const toolName = output.name;
1372
+ if (
1373
+ toolName === Constants.EXECUTE_CODE ||
1374
+ toolName === Constants.PROGRAMMATIC_TOOL_CALLING
1375
+ ) {
1376
+ const artifact = output.artifact as t.CodeExecutionArtifact | undefined;
1377
+ const newFiles = artifact?.files ?? [];
1378
+ const hasNewFiles = newFiles.length > 0;
1379
+
1380
+ if (
1381
+ hasNewFiles &&
1382
+ artifact?.session_id != null &&
1383
+ artifact.session_id !== ''
1384
+ ) {
1385
+ /**
1386
+ * Stamp each new file with its source session_id.
1387
+ * This enables files from different executions (parallel or sequential)
1388
+ * to be tracked and passed to subsequent calls.
1389
+ */
1390
+ const filesWithSession: t.FileRefs = newFiles.map((file) => ({
1391
+ ...file,
1392
+ session_id: artifact.session_id,
1393
+ }));
1394
+
1395
+ const existingSession = this.sessions.get(Constants.EXECUTE_CODE) as
1396
+ | t.CodeSessionContext
1397
+ | undefined;
1398
+ const existingFiles = existingSession?.files ?? [];
1399
+
1400
+ /**
1401
+ * Merge files, preferring latest versions by name.
1402
+ * If a file with the same name exists, replace it with the new version.
1403
+ * This handles cases where files are edited/recreated in subsequent executions.
1404
+ */
1405
+ const newFileNames = new Set(filesWithSession.map((f) => f.name));
1406
+ const filteredExisting = existingFiles.filter(
1407
+ (f) => !newFileNames.has(f.name)
1408
+ );
1409
+
1410
+ this.sessions.set(Constants.EXECUTE_CODE, {
1411
+ /** Keep latest session_id for reference/fallback */
1412
+ session_id: artifact.session_id,
1413
+ /** Accumulated files with latest versions preferred */
1414
+ files: [...filteredExisting, ...filesWithSession],
1415
+ lastUpdated: Date.now(),
1416
+ });
1417
+ }
1418
+ }
1419
+
1369
1420
  const dispatchedOutput =
1370
1421
  typeof output.content === 'string'
1371
1422
  ? output.content