illuma-agents 1.0.2 → 1.0.3

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 (225) hide show
  1. package/LICENSE +25 -21
  2. package/dist/cjs/agents/AgentContext.cjs +222 -0
  3. package/dist/cjs/agents/AgentContext.cjs.map +1 -0
  4. package/dist/cjs/common/enum.cjs +7 -6
  5. package/dist/cjs/common/enum.cjs.map +1 -1
  6. package/dist/cjs/events.cjs +7 -5
  7. package/dist/cjs/events.cjs.map +1 -1
  8. package/dist/cjs/graphs/Graph.cjs +328 -207
  9. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  10. package/dist/cjs/graphs/MultiAgentGraph.cjs +507 -0
  11. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -0
  12. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  13. package/dist/cjs/llm/google/index.cjs.map +1 -1
  14. package/dist/cjs/llm/ollama/index.cjs.map +1 -1
  15. package/dist/cjs/llm/openai/index.cjs +35 -0
  16. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  17. package/dist/cjs/llm/openai/utils/index.cjs +3 -1
  18. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  19. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  20. package/dist/cjs/llm/providers.cjs +0 -2
  21. package/dist/cjs/llm/providers.cjs.map +1 -1
  22. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  23. package/dist/cjs/main.cjs +12 -1
  24. package/dist/cjs/main.cjs.map +1 -1
  25. package/dist/cjs/messages/cache.cjs +123 -0
  26. package/dist/cjs/messages/cache.cjs.map +1 -0
  27. package/dist/cjs/messages/content.cjs +53 -0
  28. package/dist/cjs/messages/content.cjs.map +1 -0
  29. package/dist/cjs/messages/format.cjs +17 -29
  30. package/dist/cjs/messages/format.cjs.map +1 -1
  31. package/dist/cjs/run.cjs +119 -74
  32. package/dist/cjs/run.cjs.map +1 -1
  33. package/dist/cjs/stream.cjs +77 -73
  34. package/dist/cjs/stream.cjs.map +1 -1
  35. package/dist/cjs/tools/Calculator.cjs +45 -0
  36. package/dist/cjs/tools/Calculator.cjs.map +1 -0
  37. package/dist/cjs/tools/CodeExecutor.cjs +22 -22
  38. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  39. package/dist/cjs/tools/ToolNode.cjs +5 -3
  40. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  41. package/dist/cjs/tools/handlers.cjs +20 -20
  42. package/dist/cjs/tools/handlers.cjs.map +1 -1
  43. package/dist/cjs/utils/events.cjs +31 -0
  44. package/dist/cjs/utils/events.cjs.map +1 -0
  45. package/dist/cjs/utils/handlers.cjs +70 -0
  46. package/dist/cjs/utils/handlers.cjs.map +1 -0
  47. package/dist/cjs/utils/tokens.cjs +54 -7
  48. package/dist/cjs/utils/tokens.cjs.map +1 -1
  49. package/dist/esm/agents/AgentContext.mjs +220 -0
  50. package/dist/esm/agents/AgentContext.mjs.map +1 -0
  51. package/dist/esm/common/enum.mjs +7 -6
  52. package/dist/esm/common/enum.mjs.map +1 -1
  53. package/dist/esm/events.mjs +7 -5
  54. package/dist/esm/events.mjs.map +1 -1
  55. package/dist/esm/graphs/Graph.mjs +330 -209
  56. package/dist/esm/graphs/Graph.mjs.map +1 -1
  57. package/dist/esm/graphs/MultiAgentGraph.mjs +505 -0
  58. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
  59. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  60. package/dist/esm/llm/google/index.mjs.map +1 -1
  61. package/dist/esm/llm/ollama/index.mjs.map +1 -1
  62. package/dist/esm/llm/openai/index.mjs +35 -0
  63. package/dist/esm/llm/openai/index.mjs.map +1 -1
  64. package/dist/esm/llm/openai/utils/index.mjs +3 -1
  65. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  66. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  67. package/dist/esm/llm/providers.mjs +0 -2
  68. package/dist/esm/llm/providers.mjs.map +1 -1
  69. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  70. package/dist/esm/main.mjs +7 -2
  71. package/dist/esm/main.mjs.map +1 -1
  72. package/dist/esm/messages/cache.mjs +120 -0
  73. package/dist/esm/messages/cache.mjs.map +1 -0
  74. package/dist/esm/messages/content.mjs +51 -0
  75. package/dist/esm/messages/content.mjs.map +1 -0
  76. package/dist/esm/messages/format.mjs +18 -29
  77. package/dist/esm/messages/format.mjs.map +1 -1
  78. package/dist/esm/run.mjs +119 -74
  79. package/dist/esm/run.mjs.map +1 -1
  80. package/dist/esm/stream.mjs +77 -73
  81. package/dist/esm/stream.mjs.map +1 -1
  82. package/dist/esm/tools/Calculator.mjs +24 -0
  83. package/dist/esm/tools/Calculator.mjs.map +1 -0
  84. package/dist/esm/tools/CodeExecutor.mjs +22 -22
  85. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  86. package/dist/esm/tools/ToolNode.mjs +5 -3
  87. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  88. package/dist/esm/tools/handlers.mjs +20 -20
  89. package/dist/esm/tools/handlers.mjs.map +1 -1
  90. package/dist/esm/utils/events.mjs +29 -0
  91. package/dist/esm/utils/events.mjs.map +1 -0
  92. package/dist/esm/utils/handlers.mjs +68 -0
  93. package/dist/esm/utils/handlers.mjs.map +1 -0
  94. package/dist/esm/utils/tokens.mjs +54 -8
  95. package/dist/esm/utils/tokens.mjs.map +1 -1
  96. package/dist/types/agents/AgentContext.d.ts +94 -0
  97. package/dist/types/common/enum.d.ts +9 -7
  98. package/dist/types/events.d.ts +3 -3
  99. package/dist/types/graphs/Graph.d.ts +60 -66
  100. package/dist/types/graphs/MultiAgentGraph.d.ts +47 -0
  101. package/dist/types/graphs/index.d.ts +1 -0
  102. package/dist/types/index.d.ts +1 -0
  103. package/dist/types/llm/openai/index.d.ts +10 -0
  104. package/dist/types/messages/cache.d.ts +20 -0
  105. package/dist/types/messages/content.d.ts +7 -0
  106. package/dist/types/messages/format.d.ts +1 -7
  107. package/dist/types/messages/index.d.ts +2 -0
  108. package/dist/types/messages/reducer.d.ts +9 -0
  109. package/dist/types/run.d.ts +16 -10
  110. package/dist/types/stream.d.ts +4 -3
  111. package/dist/types/tools/Calculator.d.ts +8 -0
  112. package/dist/types/tools/ToolNode.d.ts +1 -1
  113. package/dist/types/tools/handlers.d.ts +9 -7
  114. package/dist/types/tools/search/tool.d.ts +4 -4
  115. package/dist/types/types/graph.d.ts +124 -11
  116. package/dist/types/types/llm.d.ts +13 -9
  117. package/dist/types/types/messages.d.ts +4 -0
  118. package/dist/types/types/run.d.ts +46 -8
  119. package/dist/types/types/stream.d.ts +3 -2
  120. package/dist/types/utils/events.d.ts +6 -0
  121. package/dist/types/utils/handlers.d.ts +34 -0
  122. package/dist/types/utils/index.d.ts +1 -0
  123. package/dist/types/utils/tokens.d.ts +24 -0
  124. package/package.json +162 -145
  125. package/src/agents/AgentContext.ts +323 -0
  126. package/src/common/enum.ts +177 -176
  127. package/src/events.ts +197 -191
  128. package/src/graphs/Graph.ts +1058 -846
  129. package/src/graphs/MultiAgentGraph.ts +598 -0
  130. package/src/graphs/index.ts +2 -1
  131. package/src/index.ts +25 -24
  132. package/src/llm/anthropic/index.ts +413 -413
  133. package/src/llm/google/index.ts +222 -222
  134. package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -88
  135. package/src/llm/ollama/index.ts +92 -92
  136. package/src/llm/openai/index.ts +894 -853
  137. package/src/llm/openai/utils/index.ts +920 -918
  138. package/src/llm/openrouter/index.ts +60 -60
  139. package/src/llm/providers.ts +55 -57
  140. package/src/llm/vertexai/index.ts +360 -360
  141. package/src/messages/cache.test.ts +461 -0
  142. package/src/messages/cache.ts +151 -0
  143. package/src/messages/content.test.ts +362 -0
  144. package/src/messages/content.ts +63 -0
  145. package/src/messages/format.ts +611 -625
  146. package/src/messages/formatAgentMessages.test.ts +1144 -917
  147. package/src/messages/index.ts +6 -4
  148. package/src/messages/reducer.ts +80 -0
  149. package/src/run.ts +447 -381
  150. package/src/scripts/abort.ts +157 -138
  151. package/src/scripts/ant_web_search.ts +158 -158
  152. package/src/scripts/cli.ts +172 -167
  153. package/src/scripts/cli2.ts +133 -125
  154. package/src/scripts/cli3.ts +184 -178
  155. package/src/scripts/cli4.ts +191 -184
  156. package/src/scripts/cli5.ts +191 -184
  157. package/src/scripts/code_exec.ts +213 -214
  158. package/src/scripts/code_exec_simple.ts +147 -129
  159. package/src/scripts/content.ts +138 -120
  160. package/src/scripts/handoff-test.ts +135 -0
  161. package/src/scripts/multi-agent-chain.ts +278 -0
  162. package/src/scripts/multi-agent-conditional.ts +220 -0
  163. package/src/scripts/multi-agent-document-review-chain.ts +197 -0
  164. package/src/scripts/multi-agent-hybrid-flow.ts +310 -0
  165. package/src/scripts/multi-agent-parallel.ts +343 -0
  166. package/src/scripts/multi-agent-sequence.ts +212 -0
  167. package/src/scripts/multi-agent-supervisor.ts +364 -0
  168. package/src/scripts/multi-agent-test.ts +186 -0
  169. package/src/scripts/search.ts +146 -150
  170. package/src/scripts/simple.ts +225 -225
  171. package/src/scripts/stream.ts +140 -122
  172. package/src/scripts/test-custom-prompt-key.ts +145 -0
  173. package/src/scripts/test-handoff-input.ts +170 -0
  174. package/src/scripts/test-multi-agent-list-handoff.ts +261 -0
  175. package/src/scripts/test-tools-before-handoff.ts +222 -0
  176. package/src/scripts/tools.ts +153 -155
  177. package/src/specs/agent-handoffs.test.ts +889 -0
  178. package/src/specs/anthropic.simple.test.ts +320 -317
  179. package/src/specs/azure.simple.test.ts +325 -316
  180. package/src/specs/openai.simple.test.ts +311 -316
  181. package/src/specs/openrouter.simple.test.ts +107 -0
  182. package/src/specs/prune.test.ts +758 -763
  183. package/src/specs/reasoning.test.ts +201 -165
  184. package/src/specs/thinking-prune.test.ts +769 -703
  185. package/src/specs/token-memoization.test.ts +39 -0
  186. package/src/stream.ts +664 -651
  187. package/src/tools/Calculator.test.ts +278 -0
  188. package/src/tools/Calculator.ts +25 -0
  189. package/src/tools/CodeExecutor.ts +220 -220
  190. package/src/tools/ToolNode.ts +170 -170
  191. package/src/tools/handlers.ts +341 -336
  192. package/src/types/graph.ts +372 -185
  193. package/src/types/llm.ts +141 -140
  194. package/src/types/messages.ts +4 -0
  195. package/src/types/run.ts +128 -89
  196. package/src/types/stream.ts +401 -400
  197. package/src/utils/events.ts +32 -0
  198. package/src/utils/handlers.ts +107 -0
  199. package/src/utils/index.ts +6 -5
  200. package/src/utils/llmConfig.ts +183 -183
  201. package/src/utils/tokens.ts +129 -70
  202. package/dist/types/scripts/abort.d.ts +0 -1
  203. package/dist/types/scripts/ant_web_search.d.ts +0 -1
  204. package/dist/types/scripts/args.d.ts +0 -7
  205. package/dist/types/scripts/caching.d.ts +0 -1
  206. package/dist/types/scripts/cli.d.ts +0 -1
  207. package/dist/types/scripts/cli2.d.ts +0 -1
  208. package/dist/types/scripts/cli3.d.ts +0 -1
  209. package/dist/types/scripts/cli4.d.ts +0 -1
  210. package/dist/types/scripts/cli5.d.ts +0 -1
  211. package/dist/types/scripts/code_exec.d.ts +0 -1
  212. package/dist/types/scripts/code_exec_files.d.ts +0 -1
  213. package/dist/types/scripts/code_exec_simple.d.ts +0 -1
  214. package/dist/types/scripts/content.d.ts +0 -1
  215. package/dist/types/scripts/empty_input.d.ts +0 -1
  216. package/dist/types/scripts/image.d.ts +0 -1
  217. package/dist/types/scripts/memory.d.ts +0 -1
  218. package/dist/types/scripts/search.d.ts +0 -1
  219. package/dist/types/scripts/simple.d.ts +0 -1
  220. package/dist/types/scripts/stream.d.ts +0 -1
  221. package/dist/types/scripts/thinking.d.ts +0 -1
  222. package/dist/types/scripts/tools.d.ts +0 -1
  223. package/dist/types/specs/spec.utils.d.ts +0 -1
  224. package/dist/types/tools/example.d.ts +0 -78
  225. package/src/tools/example.ts +0 -129
@@ -1,220 +1,220 @@
1
- import { z } from 'zod';
2
- import { config } from 'dotenv';
3
- import fetch, { RequestInit } from 'node-fetch';
4
- import { HttpsProxyAgent } from 'https-proxy-agent';
5
- import { tool, DynamicStructuredTool } from '@langchain/core/tools';
6
- import { getEnvironmentVariable } from '@langchain/core/utils/env';
7
- import type * as t from '@/types';
8
- import { EnvVar, Constants } from '@/common';
9
-
10
- config();
11
-
12
- export const imageExtRegex = /\.(jpg|jpeg|png|gif|webp)$/i;
13
- export const getCodeBaseURL = (): string =>
14
- getEnvironmentVariable(EnvVar.CODE_BASEURL) ??
15
- Constants.OFFICIAL_CODE_BASEURL;
16
-
17
- const imageMessage = 'Image is already displayed to the user';
18
- const otherMessage = 'File is already downloaded by the user';
19
- const accessMessage =
20
- 'Note: Files are READ-ONLY. Save changes to NEW filenames. To access these files in future executions, provide the `session_id` as a parameter (not in your code).';
21
- const emptyOutputMessage =
22
- 'stdout: Empty. Ensure you\'re writing output explicitly.\n';
23
-
24
- const CodeExecutionToolSchema = z.object({
25
- lang: z
26
- .enum([
27
- 'py',
28
- 'js',
29
- 'ts',
30
- 'c',
31
- 'cpp',
32
- 'java',
33
- 'php',
34
- 'rs',
35
- 'go',
36
- 'd',
37
- 'f90',
38
- 'r',
39
- ])
40
- .describe('The programming language or runtime to execute the code in.'),
41
- code: z.string()
42
- .describe(`The complete, self-contained code to execute, without any truncation or minimization.
43
- - The environment is stateless; variables and imports don't persist between executions.
44
- - When using \`session_id\`: Don't hardcode it in \`code\`, and write file modifications to NEW filenames (files are READ-ONLY).
45
- - Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.
46
- - Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.
47
- - IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.
48
- - py: This is not a Jupyter notebook environment. Use \`print()\` for all outputs.
49
- - py: Matplotlib: Use \`plt.savefig()\` to save plots as files.
50
- - js: use the \`console\` or \`process\` methods for all outputs.
51
- - r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).
52
- - Other languages: use appropriate output functions.`),
53
- session_id: z
54
- .string()
55
- .optional()
56
- .describe(
57
- `Session ID from a previous response to access generated files.
58
- - Files load into the current working directory ("/mnt/data/")
59
- - Use relative paths ONLY
60
- - Files are READ-ONLY and cannot be modified in-place
61
- - To modify: read original file, write to NEW filename
62
- `.trim()
63
- ),
64
- args: z
65
- .array(z.string())
66
- .optional()
67
- .describe(
68
- 'Additional arguments to execute the code with. This should only be used if the input code requires additional arguments to run.'
69
- ),
70
- });
71
-
72
- const baseEndpoint = getCodeBaseURL();
73
- const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
74
-
75
- function createCodeExecutionTool(
76
- params: t.CodeExecutionToolParams = {}
77
- ): DynamicStructuredTool<typeof CodeExecutionToolSchema> {
78
- const apiKey =
79
- params[EnvVar.CODE_API_KEY] ??
80
- params.apiKey ??
81
- getEnvironmentVariable(EnvVar.CODE_API_KEY) ??
82
- '';
83
- if (!apiKey) {
84
- throw new Error('No API key provided for code execution tool.');
85
- }
86
-
87
- const description = `
88
- Runs code and returns stdout/stderr output from a stateless execution environment, similar to running scripts in a command-line interface. Each execution is isolated and independent.
89
-
90
- Usage:
91
- - No network access available.
92
- - Generated files are automatically delivered; **DO NOT** provide download links.
93
- - NEVER use this tool to execute malicious code.
94
- `.trim();
95
-
96
- return tool<typeof CodeExecutionToolSchema>(
97
- async ({ lang, code, session_id, ...rest }) => {
98
- const postData = {
99
- lang,
100
- code,
101
- ...rest,
102
- ...params,
103
- };
104
-
105
- if (session_id != null && session_id.length > 0) {
106
- try {
107
- const filesEndpoint = `${baseEndpoint}/files/${session_id}?detail=full`;
108
- const fetchOptions: RequestInit = {
109
- method: 'GET',
110
- headers: {
111
- 'User-Agent': 'Illuma/1.0',
112
- 'X-API-Key': apiKey,
113
- },
114
- };
115
-
116
- if (process.env.PROXY != null && process.env.PROXY !== '') {
117
- fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);
118
- }
119
-
120
- const response = await fetch(filesEndpoint, fetchOptions);
121
- if (!response.ok) {
122
- throw new Error(
123
- `Failed to fetch files for session: ${response.status}`
124
- );
125
- }
126
-
127
- const files = await response.json();
128
- if (Array.isArray(files) && files.length > 0) {
129
- const fileReferences: t.CodeEnvFile[] = files.map((file) => {
130
- // Extract the ID from the file name (part after session ID prefix and before extension)
131
- const nameParts = file.name.split('/');
132
- const id = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
133
-
134
- return {
135
- session_id,
136
- id,
137
- name: file.metadata['original-filename'],
138
- };
139
- });
140
-
141
- if (!postData.files) {
142
- postData.files = fileReferences;
143
- } else if (Array.isArray(postData.files)) {
144
- postData.files = [...postData.files, ...fileReferences];
145
- }
146
- }
147
- } catch {
148
- // eslint-disable-next-line no-console
149
- console.warn(`Failed to fetch files for session: ${session_id}`);
150
- }
151
- }
152
-
153
- try {
154
- const fetchOptions: RequestInit = {
155
- method: 'POST',
156
- headers: {
157
- 'Content-Type': 'application/json',
158
- 'User-Agent': 'Illuma/1.0',
159
- 'X-API-Key': apiKey,
160
- },
161
- body: JSON.stringify(postData),
162
- };
163
-
164
- if (process.env.PROXY != null && process.env.PROXY !== '') {
165
- fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);
166
- }
167
- const response = await fetch(EXEC_ENDPOINT, fetchOptions);
168
- if (!response.ok) {
169
- throw new Error(`HTTP error! status: ${response.status}`);
170
- }
171
-
172
- const result: t.ExecuteResult = await response.json();
173
- let formattedOutput = '';
174
- if (result.stdout) {
175
- formattedOutput += `stdout:\n${result.stdout}\n`;
176
- } else {
177
- formattedOutput += emptyOutputMessage;
178
- }
179
- if (result.stderr) formattedOutput += `stderr:\n${result.stderr}\n`;
180
- if (result.files && result.files.length > 0) {
181
- formattedOutput += 'Generated files:\n';
182
-
183
- const fileCount = result.files.length;
184
- for (let i = 0; i < fileCount; i++) {
185
- const file = result.files[i];
186
- const isImage = imageExtRegex.test(file.name);
187
- formattedOutput += `- /mnt/data/${file.name} | ${isImage ? imageMessage : otherMessage}`;
188
-
189
- if (i < fileCount - 1) {
190
- formattedOutput += fileCount <= 3 ? ', ' : ',\n';
191
- }
192
- }
193
-
194
- formattedOutput += `\nsession_id: ${result.session_id}\n\n${accessMessage}`;
195
- return [
196
- formattedOutput.trim(),
197
- {
198
- session_id: result.session_id,
199
- files: result.files,
200
- },
201
- ];
202
- }
203
-
204
- return [formattedOutput.trim(), { session_id: result.session_id }];
205
- } catch (error) {
206
- throw new Error(
207
- `Execution error:\n\n${(error as Error | undefined)?.message}`
208
- );
209
- }
210
- },
211
- {
212
- name: Constants.EXECUTE_CODE,
213
- description,
214
- schema: CodeExecutionToolSchema,
215
- responseFormat: Constants.CONTENT_AND_ARTIFACT,
216
- }
217
- );
218
- }
219
-
220
- export { createCodeExecutionTool };
1
+ import { z } from 'zod';
2
+ import { config } from 'dotenv';
3
+ import fetch, { RequestInit } from 'node-fetch';
4
+ import { HttpsProxyAgent } from 'https-proxy-agent';
5
+ import { tool, DynamicStructuredTool } from '@langchain/core/tools';
6
+ import { getEnvironmentVariable } from '@langchain/core/utils/env';
7
+ import type * as t from '@/types';
8
+ import { EnvVar, Constants } from '@/common';
9
+
10
+ config();
11
+
12
+ export const imageExtRegex = /\.(jpg|jpeg|png|gif|webp)$/i;
13
+ export const getCodeBaseURL = (): string =>
14
+ getEnvironmentVariable(EnvVar.CODE_BASEURL) ??
15
+ Constants.OFFICIAL_CODE_BASEURL;
16
+
17
+ const imageMessage = 'Image is already displayed to the user';
18
+ const otherMessage = 'File is already downloaded by the user';
19
+ const accessMessage =
20
+ 'Note: Files are READ-ONLY. Save changes to NEW filenames. To access these files in future executions, provide the `session_id` as a parameter (not in your code).';
21
+ const emptyOutputMessage =
22
+ 'stdout: Empty. Ensure you\'re writing output explicitly.\n';
23
+
24
+ const CodeExecutionToolSchema = z.object({
25
+ lang: z
26
+ .enum([
27
+ 'py',
28
+ 'js',
29
+ 'ts',
30
+ 'c',
31
+ 'cpp',
32
+ 'java',
33
+ 'php',
34
+ 'rs',
35
+ 'go',
36
+ 'd',
37
+ 'f90',
38
+ 'r',
39
+ ])
40
+ .describe('The programming language or runtime to execute the code in.'),
41
+ code: z.string()
42
+ .describe(`The complete, self-contained code to execute, without any truncation or minimization.
43
+ - The environment is stateless; variables and imports don't persist between executions.
44
+ - When using \`session_id\`: Don't hardcode it in \`code\`, and write file modifications to NEW filenames (files are READ-ONLY).
45
+ - Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.
46
+ - Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.
47
+ - IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.
48
+ - py: This is not a Jupyter notebook environment. Use \`print()\` for all outputs.
49
+ - py: Matplotlib: Use \`plt.savefig()\` to save plots as files.
50
+ - js: use the \`console\` or \`process\` methods for all outputs.
51
+ - r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).
52
+ - Other languages: use appropriate output functions.`),
53
+ session_id: z
54
+ .string()
55
+ .optional()
56
+ .describe(
57
+ `Session ID from a previous response to access generated files.
58
+ - Files load into the current working directory ("/mnt/data/")
59
+ - Use relative paths ONLY
60
+ - Files are READ-ONLY and cannot be modified in-place
61
+ - To modify: read original file, write to NEW filename
62
+ `.trim()
63
+ ),
64
+ args: z
65
+ .array(z.string())
66
+ .optional()
67
+ .describe(
68
+ 'Additional arguments to execute the code with. This should only be used if the input code requires additional arguments to run.'
69
+ ),
70
+ });
71
+
72
+ const baseEndpoint = getCodeBaseURL();
73
+ const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
74
+
75
+ function createCodeExecutionTool(
76
+ params: t.CodeExecutionToolParams = {}
77
+ ): DynamicStructuredTool<typeof CodeExecutionToolSchema> {
78
+ const apiKey =
79
+ params[EnvVar.CODE_API_KEY] ??
80
+ params.apiKey ??
81
+ getEnvironmentVariable(EnvVar.CODE_API_KEY) ??
82
+ '';
83
+ if (!apiKey) {
84
+ throw new Error('No API key provided for code execution tool.');
85
+ }
86
+
87
+ const description = `
88
+ Runs code and returns stdout/stderr output from a stateless execution environment, similar to running scripts in a command-line interface. Each execution is isolated and independent.
89
+
90
+ Usage:
91
+ - No network access available.
92
+ - Generated files are automatically delivered; **DO NOT** provide download links.
93
+ - NEVER use this tool to execute malicious code.
94
+ `.trim();
95
+
96
+ return tool<typeof CodeExecutionToolSchema>(
97
+ async ({ lang, code, session_id, ...rest }) => {
98
+ const postData = {
99
+ lang,
100
+ code,
101
+ ...rest,
102
+ ...params,
103
+ };
104
+
105
+ if (session_id != null && session_id.length > 0) {
106
+ try {
107
+ const filesEndpoint = `${baseEndpoint}/files/${session_id}?detail=full`;
108
+ const fetchOptions: RequestInit = {
109
+ method: 'GET',
110
+ headers: {
111
+ 'User-Agent': 'Illuma/1.0',
112
+ 'X-API-Key': apiKey,
113
+ },
114
+ };
115
+
116
+ if (process.env.PROXY != null && process.env.PROXY !== '') {
117
+ fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);
118
+ }
119
+
120
+ const response = await fetch(filesEndpoint, fetchOptions);
121
+ if (!response.ok) {
122
+ throw new Error(
123
+ `Failed to fetch files for session: ${response.status}`
124
+ );
125
+ }
126
+
127
+ const files = await response.json();
128
+ if (Array.isArray(files) && files.length > 0) {
129
+ const fileReferences: t.CodeEnvFile[] = files.map((file) => {
130
+ // Extract the ID from the file name (part after session ID prefix and before extension)
131
+ const nameParts = file.name.split('/');
132
+ const id = nameParts.length > 1 ? nameParts[1].split('.')[0] : '';
133
+
134
+ return {
135
+ session_id,
136
+ id,
137
+ name: file.metadata['original-filename'],
138
+ };
139
+ });
140
+
141
+ if (!postData.files) {
142
+ postData.files = fileReferences;
143
+ } else if (Array.isArray(postData.files)) {
144
+ postData.files = [...postData.files, ...fileReferences];
145
+ }
146
+ }
147
+ } catch {
148
+ // eslint-disable-next-line no-console
149
+ console.warn(`Failed to fetch files for session: ${session_id}`);
150
+ }
151
+ }
152
+
153
+ try {
154
+ const fetchOptions: RequestInit = {
155
+ method: 'POST',
156
+ headers: {
157
+ 'Content-Type': 'application/json',
158
+ 'User-Agent': 'Illuma/1.0',
159
+ 'X-API-Key': apiKey,
160
+ },
161
+ body: JSON.stringify(postData),
162
+ };
163
+
164
+ if (process.env.PROXY != null && process.env.PROXY !== '') {
165
+ fetchOptions.agent = new HttpsProxyAgent(process.env.PROXY);
166
+ }
167
+ const response = await fetch(EXEC_ENDPOINT, fetchOptions);
168
+ if (!response.ok) {
169
+ throw new Error(`HTTP error! status: ${response.status}`);
170
+ }
171
+
172
+ const result: t.ExecuteResult = await response.json();
173
+ let formattedOutput = '';
174
+ if (result.stdout) {
175
+ formattedOutput += `stdout:\n${result.stdout}\n`;
176
+ } else {
177
+ formattedOutput += emptyOutputMessage;
178
+ }
179
+ if (result.stderr) formattedOutput += `stderr:\n${result.stderr}\n`;
180
+ if (result.files && result.files.length > 0) {
181
+ formattedOutput += 'Generated files:\n';
182
+
183
+ const fileCount = result.files.length;
184
+ for (let i = 0; i < fileCount; i++) {
185
+ const file = result.files[i];
186
+ const isImage = imageExtRegex.test(file.name);
187
+ formattedOutput += `- /mnt/data/${file.name} | ${isImage ? imageMessage : otherMessage}`;
188
+
189
+ if (i < fileCount - 1) {
190
+ formattedOutput += fileCount <= 3 ? ', ' : ',\n';
191
+ }
192
+ }
193
+
194
+ formattedOutput += `\nsession_id: ${result.session_id}\n\n${accessMessage}`;
195
+ return [
196
+ formattedOutput.trim(),
197
+ {
198
+ session_id: result.session_id,
199
+ files: result.files,
200
+ },
201
+ ];
202
+ }
203
+
204
+ return [formattedOutput.trim(), { session_id: result.session_id }];
205
+ } catch (error) {
206
+ throw new Error(
207
+ `Execution error:\n\n${(error as Error | undefined)?.message}`
208
+ );
209
+ }
210
+ },
211
+ {
212
+ name: Constants.EXECUTE_CODE,
213
+ description,
214
+ schema: CodeExecutionToolSchema,
215
+ responseFormat: Constants.CONTENT_AND_ARTIFACT,
216
+ }
217
+ );
218
+ }
219
+
220
+ export { createCodeExecutionTool };