@eko-ai/eko 1.0.8 → 1.0.10

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 (300) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +139 -131
  3. package/dist/core/eko.d.ts +3 -2
  4. package/dist/extension/script/bing.js +0 -0
  5. package/dist/extension/script/build_dom_tree.js +661 -661
  6. package/dist/extension/script/common.js +0 -0
  7. package/dist/extension/script/duckduckgo.js +0 -0
  8. package/dist/extension/script/google.js +0 -0
  9. package/dist/extension/tools/cancel_workflow.d.ts +9 -0
  10. package/dist/extension/tools/get_all_tabs.d.ts +9 -0
  11. package/dist/extension/tools/index.d.ts +3 -1
  12. package/dist/extension/tools/tab_management.d.ts +1 -1
  13. package/dist/extension/utils.d.ts +1 -1
  14. package/dist/extension.cjs.js +749 -278
  15. package/dist/extension.esm.js +749 -278
  16. package/dist/extension_content_script.js +55 -55
  17. package/dist/fellou.cjs.js +18 -18
  18. package/dist/fellou.esm.js +18 -18
  19. package/dist/index.cjs.js +2034 -1609
  20. package/dist/index.d.ts +3 -1
  21. package/dist/index.esm.js +2033 -1610
  22. package/dist/jest.config.js +10 -0
  23. package/dist/jest.config.js.map +1 -0
  24. package/dist/models/action.d.ts +8 -4
  25. package/dist/models/workflow.d.ts +8 -3
  26. package/dist/nodejs/tools/index.d.ts +1 -0
  27. package/dist/nodejs.cjs.js +1832 -1623
  28. package/dist/nodejs.esm.js +1832 -1623
  29. package/dist/rollup.config.js +171 -0
  30. package/dist/rollup.config.js.map +1 -0
  31. package/dist/schemas/workflow.schema.d.ts +2 -13
  32. package/dist/script.js +10 -0
  33. package/dist/script.js.map +1 -0
  34. package/dist/services/llm/claude-provider.d.ts +2 -1
  35. package/dist/services/llm/deepseek-provider.d.ts +13 -0
  36. package/dist/services/llm/openai-provider.d.ts +2 -1
  37. package/dist/services/llm/provider-factory.d.ts +4 -0
  38. package/dist/services/llm/siliconflow-provider.d.ts +13 -0
  39. package/dist/services/parser/workflow-parser.d.ts +0 -7
  40. package/dist/services/workflow/generator.d.ts +1 -0
  41. package/dist/src/core/eko.js +99 -0
  42. package/dist/src/core/eko.js.map +1 -0
  43. package/dist/src/core/tool-registry.js +51 -0
  44. package/dist/src/core/tool-registry.js.map +1 -0
  45. package/dist/src/extension/content/index.js +409 -0
  46. package/dist/src/extension/content/index.js.map +1 -0
  47. package/dist/src/extension/core.js +29 -0
  48. package/dist/src/extension/core.js.map +1 -0
  49. package/dist/src/extension/index.js +12 -0
  50. package/dist/src/extension/index.js.map +1 -0
  51. package/dist/src/extension/script/bing.js +25 -0
  52. package/dist/src/extension/script/bing.js.map +1 -0
  53. package/dist/src/extension/script/build_dom_tree.js +585 -0
  54. package/dist/src/extension/script/build_dom_tree.js.map +1 -0
  55. package/dist/src/extension/script/common.js +203 -0
  56. package/dist/src/extension/script/common.js.map +1 -0
  57. package/dist/src/extension/script/duckduckgo.js +25 -0
  58. package/dist/src/extension/script/duckduckgo.js.map +1 -0
  59. package/dist/src/extension/script/google.js +26 -0
  60. package/dist/src/extension/script/google.js.map +1 -0
  61. package/dist/src/extension/tools/browser.js +174 -0
  62. package/dist/src/extension/tools/browser.js.map +1 -0
  63. package/dist/src/extension/tools/browser_use.js +186 -0
  64. package/dist/src/extension/tools/browser_use.js.map +1 -0
  65. package/dist/src/extension/tools/element_click.js +123 -0
  66. package/dist/src/extension/tools/element_click.js.map +1 -0
  67. package/dist/src/extension/tools/export_file.js +93 -0
  68. package/dist/src/extension/tools/export_file.js.map +1 -0
  69. package/dist/src/extension/tools/extract_content.js +38 -0
  70. package/dist/src/extension/tools/extract_content.js.map +1 -0
  71. package/dist/src/extension/tools/find_element_position.js +125 -0
  72. package/dist/src/extension/tools/find_element_position.js.map +1 -0
  73. package/dist/src/extension/tools/html_script.js +219 -0
  74. package/dist/src/extension/tools/html_script.js.map +1 -0
  75. package/dist/src/extension/tools/index.js +12 -0
  76. package/dist/src/extension/tools/index.js.map +1 -0
  77. package/dist/src/extension/tools/open_url.js +68 -0
  78. package/dist/src/extension/tools/open_url.js.map +1 -0
  79. package/dist/src/extension/tools/request_login.js +87 -0
  80. package/dist/src/extension/tools/request_login.js.map +1 -0
  81. package/dist/src/extension/tools/screenshot.js +26 -0
  82. package/dist/src/extension/tools/screenshot.js.map +1 -0
  83. package/dist/src/extension/tools/tab_management.js +160 -0
  84. package/dist/src/extension/tools/tab_management.js.map +1 -0
  85. package/dist/src/extension/tools/web_search.js +281 -0
  86. package/dist/src/extension/tools/web_search.js.map +1 -0
  87. package/dist/src/extension/utils.js +244 -0
  88. package/dist/src/extension/utils.js.map +1 -0
  89. package/dist/src/fellou/computer.js +104 -0
  90. package/dist/src/fellou/computer.js.map +1 -0
  91. package/dist/src/fellou/index.js +7 -0
  92. package/dist/src/fellou/index.js.map +1 -0
  93. package/dist/src/fellou/tools/computer_use.js +111 -0
  94. package/dist/src/fellou/tools/computer_use.js.map +1 -0
  95. package/dist/src/index.js +9 -0
  96. package/dist/src/index.js.map +1 -0
  97. package/dist/src/models/action.js +364 -0
  98. package/dist/src/models/action.js.map +1 -0
  99. package/dist/src/models/workflow.js +120 -0
  100. package/dist/src/models/workflow.js.map +1 -0
  101. package/dist/src/nodejs/core.js +18 -0
  102. package/dist/src/nodejs/core.js.map +1 -0
  103. package/dist/src/nodejs/index.js +6 -0
  104. package/dist/src/nodejs/index.js.map +1 -0
  105. package/dist/src/nodejs/script/build_dom_tree.js +586 -0
  106. package/dist/src/nodejs/script/build_dom_tree.js.map +1 -0
  107. package/dist/src/nodejs/tools/browser_use.js +458 -0
  108. package/dist/src/nodejs/tools/browser_use.js.map +1 -0
  109. package/dist/src/nodejs/tools/command_execute.js +65 -0
  110. package/dist/src/nodejs/tools/command_execute.js.map +1 -0
  111. package/dist/src/nodejs/tools/file_read.js +45 -0
  112. package/dist/src/nodejs/tools/file_read.js.map +1 -0
  113. package/dist/src/nodejs/tools/file_write.js +95 -0
  114. package/dist/src/nodejs/tools/file_write.js.map +1 -0
  115. package/dist/src/nodejs/tools/index.js +5 -0
  116. package/dist/src/nodejs/tools/index.js.map +1 -0
  117. package/dist/src/schemas/workflow.schema.js +64 -0
  118. package/dist/src/schemas/workflow.schema.js.map +1 -0
  119. package/dist/src/services/llm/claude-provider.js +140 -0
  120. package/dist/src/services/llm/claude-provider.js.map +1 -0
  121. package/dist/src/services/llm/deepseek-provider.js +432 -0
  122. package/dist/src/services/llm/deepseek-provider.js.map +1 -0
  123. package/dist/src/services/llm/glm-provider.js +317 -0
  124. package/dist/src/services/llm/glm-provider.js.map +1 -0
  125. package/dist/src/services/llm/openai-provider copy.js +317 -0
  126. package/dist/src/services/llm/openai-provider copy.js.map +1 -0
  127. package/dist/src/services/llm/openai-provider.js +317 -0
  128. package/dist/src/services/llm/openai-provider.js.map +1 -0
  129. package/dist/src/services/parser/workflow-parser.js +208 -0
  130. package/dist/src/services/parser/workflow-parser.js.map +1 -0
  131. package/dist/src/services/workflow/generator.js +105 -0
  132. package/dist/src/services/workflow/generator.js.map +1 -0
  133. package/dist/src/services/workflow/templates.js +42 -0
  134. package/dist/src/services/workflow/templates.js.map +1 -0
  135. package/dist/src/types/action.types.js +2 -0
  136. package/dist/src/types/action.types.js.map +1 -0
  137. package/dist/src/types/eko.types.js +2 -0
  138. package/dist/src/types/eko.types.js.map +1 -0
  139. package/dist/src/types/index.js +6 -0
  140. package/dist/src/types/index.js.map +1 -0
  141. package/dist/src/types/llm.types.js +2 -0
  142. package/dist/src/types/llm.types.js.map +1 -0
  143. package/dist/src/types/parser.types.js +2 -0
  144. package/dist/src/types/parser.types.js.map +1 -0
  145. package/dist/src/types/tools.types.js +2 -0
  146. package/dist/src/types/tools.types.js.map +1 -0
  147. package/dist/src/types/workflow.types.js +3 -0
  148. package/dist/src/types/workflow.types.js.map +1 -0
  149. package/dist/src/web/core.js +18 -0
  150. package/dist/src/web/core.js.map +1 -0
  151. package/dist/src/web/index.js +9 -0
  152. package/dist/src/web/index.js.map +1 -0
  153. package/dist/src/web/script/build_dom_tree.js +584 -0
  154. package/dist/src/web/script/build_dom_tree.js.map +1 -0
  155. package/dist/src/web/tools/browser.js +249 -0
  156. package/dist/src/web/tools/browser.js.map +1 -0
  157. package/dist/src/web/tools/browser_use.js +176 -0
  158. package/dist/src/web/tools/browser_use.js.map +1 -0
  159. package/dist/src/web/tools/element_click.js +121 -0
  160. package/dist/src/web/tools/element_click.js.map +1 -0
  161. package/dist/src/web/tools/export_file.js +74 -0
  162. package/dist/src/web/tools/export_file.js.map +1 -0
  163. package/dist/src/web/tools/extract_content.js +24 -0
  164. package/dist/src/web/tools/extract_content.js.map +1 -0
  165. package/dist/src/web/tools/find_element_position.js +121 -0
  166. package/dist/src/web/tools/find_element_position.js.map +1 -0
  167. package/dist/src/web/tools/html_script.js +219 -0
  168. package/dist/src/web/tools/html_script.js.map +1 -0
  169. package/dist/src/web/tools/index.js +8 -0
  170. package/dist/src/web/tools/index.js.map +1 -0
  171. package/dist/src/web/tools/screenshot.js +24 -0
  172. package/dist/src/web/tools/screenshot.js.map +1 -0
  173. package/dist/test/integration/claude-provider.test.js +170 -0
  174. package/dist/test/integration/claude-provider.test.js.map +1 -0
  175. package/dist/test/integration/deepseek-provider.test.js +171 -0
  176. package/dist/test/integration/deepseek-provider.test.js.map +1 -0
  177. package/dist/test/integration/glm-provider.test.js +173 -0
  178. package/dist/test/integration/glm-provider.test.js.map +1 -0
  179. package/dist/test/integration/openai-provider.test copy.js +170 -0
  180. package/dist/test/integration/openai-provider.test copy.js.map +1 -0
  181. package/dist/test/integration/openai-provider.test.js +170 -0
  182. package/dist/test/integration/openai-provider.test.js.map +1 -0
  183. package/dist/test/integration/qwen-provider.js +170 -0
  184. package/dist/test/integration/qwen-provider.js.map +1 -0
  185. package/dist/test/integration/qwen-provider.test copy.js +170 -0
  186. package/dist/test/integration/qwen-provider.test copy.js.map +1 -0
  187. package/dist/test/integration/qwen-provider.test.js +170 -0
  188. package/dist/test/integration/qwen-provider.test.js.map +1 -0
  189. package/dist/test/integration/workflow.execution.test.js +152 -0
  190. package/dist/test/integration/workflow.execution.test.js.map +1 -0
  191. package/dist/test/integration/workflow.generation-and-execution.test.js +131 -0
  192. package/dist/test/integration/workflow.generation-and-execution.test.js.map +1 -0
  193. package/dist/test/integration/workflow.generator.test.js +207 -0
  194. package/dist/test/integration/workflow.generator.test.js.map +1 -0
  195. package/dist/test/unit/action.test.js +186 -0
  196. package/dist/test/unit/action.test.js.map +1 -0
  197. package/dist/test/unit/tool-registry.test.js +99 -0
  198. package/dist/test/unit/tool-registry.test.js.map +1 -0
  199. package/dist/test/unit/workflow-parser.test.js +189 -0
  200. package/dist/test/unit/workflow-parser.test.js.map +1 -0
  201. package/dist/test/unit/workflow.test.js +102 -0
  202. package/dist/test/unit/workflow.test.js.map +1 -0
  203. package/dist/types/action.types.d.ts +8 -3
  204. package/dist/types/jest.config.d.ts +10 -0
  205. package/dist/types/rollup.config.d.ts +16 -0
  206. package/dist/types/script.d.ts +1 -0
  207. package/dist/types/src/core/eko.d.ts +20 -0
  208. package/dist/types/src/core/tool-registry.d.ts +13 -0
  209. package/dist/types/src/extension/content/index.d.ts +16 -0
  210. package/dist/types/src/extension/core.d.ts +11 -0
  211. package/dist/types/src/extension/index.d.ts +7 -0
  212. package/dist/types/src/extension/script/bing.d.ts +0 -0
  213. package/dist/types/src/extension/script/build_dom_tree.d.ts +38 -0
  214. package/dist/types/src/extension/script/common.d.ts +0 -0
  215. package/dist/types/src/extension/script/duckduckgo.d.ts +0 -0
  216. package/dist/types/src/extension/script/google.d.ts +0 -0
  217. package/dist/types/src/extension/tools/browser.d.ts +22 -0
  218. package/dist/types/src/extension/tools/browser_use.d.ts +19 -0
  219. package/dist/types/src/extension/tools/element_click.d.ts +12 -0
  220. package/dist/types/src/extension/tools/export_file.d.ts +18 -0
  221. package/dist/types/src/extension/tools/extract_content.d.ts +18 -0
  222. package/dist/types/src/extension/tools/find_element_position.d.ts +12 -0
  223. package/dist/types/src/extension/tools/html_script.d.ts +10 -0
  224. package/dist/types/src/extension/tools/index.d.ts +11 -0
  225. package/dist/types/src/extension/tools/open_url.d.ts +18 -0
  226. package/dist/{extension/tools/form_autofill.d.ts → types/src/extension/tools/request_login.d.ts} +3 -4
  227. package/dist/types/src/extension/tools/screenshot.d.ts +18 -0
  228. package/dist/types/src/extension/tools/tab_management.d.ts +19 -0
  229. package/dist/types/src/extension/tools/web_search.d.ts +18 -0
  230. package/dist/types/src/extension/utils.d.ts +31 -0
  231. package/dist/types/src/fellou/computer.d.ts +20 -0
  232. package/dist/types/src/fellou/index.d.ts +6 -0
  233. package/dist/types/src/fellou/tools/computer_use.d.ts +18 -0
  234. package/dist/types/src/index.d.ts +8 -0
  235. package/dist/types/src/models/action.d.ts +22 -0
  236. package/dist/types/src/models/workflow.d.ts +16 -0
  237. package/dist/types/src/nodejs/core.d.ts +2 -0
  238. package/dist/types/src/nodejs/index.d.ts +3 -0
  239. package/dist/types/src/nodejs/script/build_dom_tree.d.ts +1 -0
  240. package/dist/types/src/nodejs/tools/browser_use.d.ts +28 -0
  241. package/dist/types/src/nodejs/tools/command_execute.d.ts +12 -0
  242. package/dist/types/src/nodejs/tools/file_read.d.ts +11 -0
  243. package/dist/types/src/nodejs/tools/file_write.d.ts +15 -0
  244. package/dist/types/src/nodejs/tools/index.d.ts +4 -0
  245. package/dist/types/src/schemas/workflow.schema.d.ts +88 -0
  246. package/dist/types/src/services/llm/claude-provider.d.ts +11 -0
  247. package/dist/types/src/services/llm/deepseek-provider.d.ts +15 -0
  248. package/dist/types/src/services/llm/glm-provider.d.ts +11 -0
  249. package/dist/types/src/services/llm/openai-provider copy.d.ts +11 -0
  250. package/dist/types/src/services/llm/openai-provider.d.ts +11 -0
  251. package/dist/types/src/services/parser/workflow-parser.d.ts +29 -0
  252. package/dist/types/src/services/workflow/generator.d.ts +13 -0
  253. package/dist/types/src/services/workflow/templates.d.ts +8 -0
  254. package/dist/types/src/types/action.types.d.ts +38 -0
  255. package/dist/types/src/types/eko.types.d.ts +21 -0
  256. package/dist/types/src/types/index.d.ts +5 -0
  257. package/dist/types/src/types/llm.types.d.ts +54 -0
  258. package/dist/types/src/types/parser.types.d.ts +9 -0
  259. package/dist/types/src/types/tools.types.d.ts +88 -0
  260. package/dist/types/src/types/workflow.types.d.ts +39 -0
  261. package/dist/types/src/web/core.d.ts +2 -0
  262. package/dist/types/src/web/index.d.ts +5 -0
  263. package/dist/types/src/web/script/build_dom_tree.d.ts +10 -0
  264. package/dist/types/src/web/tools/browser.d.ts +21 -0
  265. package/dist/types/src/web/tools/browser_use.d.ts +19 -0
  266. package/dist/types/src/web/tools/element_click.d.ts +12 -0
  267. package/dist/types/src/web/tools/export_file.d.ts +18 -0
  268. package/dist/types/src/web/tools/extract_content.d.ts +17 -0
  269. package/dist/types/src/web/tools/find_element_position.d.ts +12 -0
  270. package/dist/types/src/web/tools/html_script.d.ts +10 -0
  271. package/dist/types/src/web/tools/index.d.ts +7 -0
  272. package/dist/types/src/web/tools/screenshot.d.ts +18 -0
  273. package/dist/types/test/integration/claude-provider.test.d.ts +1 -0
  274. package/dist/types/test/integration/deepseek-provider.test.d.ts +1 -0
  275. package/dist/types/test/integration/glm-provider.test.d.ts +1 -0
  276. package/dist/types/test/integration/openai-provider.test copy.d.ts +1 -0
  277. package/dist/types/test/integration/openai-provider.test.d.ts +1 -0
  278. package/dist/types/test/integration/qwen-provider.d.ts +1 -0
  279. package/dist/types/test/integration/qwen-provider.test copy.d.ts +1 -0
  280. package/dist/types/test/integration/qwen-provider.test.d.ts +1 -0
  281. package/dist/types/test/integration/workflow.execution.test.d.ts +1 -0
  282. package/dist/types/test/integration/workflow.generation-and-execution.test.d.ts +1 -0
  283. package/dist/types/test/integration/workflow.generator.test.d.ts +1 -0
  284. package/dist/types/test/unit/action.test.d.ts +1 -0
  285. package/dist/types/test/unit/tool-registry.test.d.ts +1 -0
  286. package/dist/types/test/unit/workflow-parser.test.d.ts +1 -0
  287. package/dist/types/test/unit/workflow.test.d.ts +1 -0
  288. package/dist/types/tools.types.d.ts +44 -1
  289. package/dist/types/workflow.types.d.ts +22 -9
  290. package/dist/universal_tools/cancel_workflow.d.ts +9 -0
  291. package/dist/universal_tools/human/text.d.ts +9 -0
  292. package/dist/universal_tools/human.d.ts +30 -0
  293. package/dist/universal_tools/index.d.ts +4 -0
  294. package/dist/universal_tools/summary_workflow.d.ts +9 -0
  295. package/dist/utils/execution-logger.d.ts +69 -0
  296. package/dist/web.cjs.js +117 -117
  297. package/dist/web.esm.js +117 -117
  298. package/package.json +106 -107
  299. package/dist/fellou/tools/index.d.ts +0 -2
  300. package/dist/types/framework.types.d.ts +0 -11
package/dist/index.cjs.js CHANGED
@@ -2,936 +2,258 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- class WorkflowImpl {
6
- constructor(id, name, description, nodes = [], variables = new Map(), llmProvider) {
7
- this.id = id;
8
- this.name = name;
9
- this.description = description;
10
- this.nodes = nodes;
11
- this.variables = variables;
12
- this.llmProvider = llmProvider;
5
+ const VERSION$1 = '0.33.1'; // x-release-please-version
6
+
7
+ let auto$1 = false;
8
+ let kind$1 = undefined;
9
+ let fetch$2 = undefined;
10
+ let File$2 = undefined;
11
+ let ReadableStream$2 = undefined;
12
+ let getDefaultAgent$1 = undefined;
13
+ let fileFromPath$1 = undefined;
14
+ function setShims$1(shims, options = { auto: false }) {
15
+ if (auto$1) {
16
+ throw new Error(`you must \`import '@anthropic-ai/sdk/shims/${shims.kind}'\` before importing anything else from @anthropic-ai/sdk`);
13
17
  }
14
- async execute(callback) {
15
- var _a, _b, _c, _d;
16
- if (!this.validateDAG()) {
17
- throw new Error("Invalid workflow: Contains circular dependencies");
18
- }
19
- this.abort = false;
20
- callback && await ((_b = (_a = callback.hooks).beforeWorkflow) === null || _b === void 0 ? void 0 : _b.call(_a, this));
21
- const executed = new Set();
22
- const executing = new Set();
23
- const executeNode = async (nodeId) => {
24
- var _a, _b, _c, _d, _e;
25
- if (this.abort) {
26
- throw new Error("Abort");
27
- }
28
- if (executed.has(nodeId)) {
29
- return;
30
- }
31
- if (executing.has(nodeId)) {
32
- throw new Error(`Circular dependency detected at node: ${nodeId}`);
33
- }
34
- const node = this.getNode(nodeId);
35
- // Execute the node's action
36
- const context = {
37
- __skip: false,
38
- __abort: false,
39
- variables: this.variables,
40
- llmProvider: this.llmProvider,
41
- tools: new Map(node.action.tools.map(tool => [tool.name, tool])),
42
- callback,
43
- next: () => context.__skip = true,
44
- abortAll: () => this.abort = context.__abort = true,
45
- };
46
- callback && await ((_b = (_a = callback.hooks).beforeSubtask) === null || _b === void 0 ? void 0 : _b.call(_a, node, context));
47
- if (context.__abort) {
48
- throw new Error("Abort");
49
- }
50
- else if (context.__skip) {
51
- return;
52
- }
53
- executing.add(nodeId);
54
- // Execute dependencies first
55
- for (const depId of node.dependencies) {
56
- await executeNode(depId);
57
- }
58
- // Prepare input by gathering outputs from dependencies
59
- const input = {};
60
- for (const depId of node.dependencies) {
61
- const depNode = this.getNode(depId);
62
- input[depId] = depNode.output.value;
63
- }
64
- node.input.value = input;
65
- node.output.value = await node.action.execute(node.input.value, context);
66
- executing.delete(nodeId);
67
- executed.add(nodeId);
68
- callback && await ((_d = (_c = callback.hooks).afterSubtask) === null || _d === void 0 ? void 0 : _d.call(_c, node, context, (_e = node.output) === null || _e === void 0 ? void 0 : _e.value));
69
- };
70
- // Execute all terminal nodes (nodes with no dependents)
71
- const terminalNodes = this.nodes.filter(node => !this.nodes.some(n => n.dependencies.includes(node.id)));
72
- await Promise.all(terminalNodes.map(node => executeNode(node.id)));
73
- callback && await ((_d = (_c = callback.hooks).afterWorkflow) === null || _d === void 0 ? void 0 : _d.call(_c, this, this.variables));
18
+ if (kind$1) {
19
+ throw new Error(`can't \`import '@anthropic-ai/sdk/shims/${shims.kind}'\` after \`import '@anthropic-ai/sdk/shims/${kind$1}'\``);
74
20
  }
75
- addNode(node) {
76
- if (this.nodes.some(n => n.id === node.id)) {
77
- throw new Error(`Node with id ${node.id} already exists`);
78
- }
79
- this.nodes.push(node);
21
+ auto$1 = options.auto;
22
+ kind$1 = shims.kind;
23
+ fetch$2 = shims.fetch;
24
+ File$2 = shims.File;
25
+ ReadableStream$2 = shims.ReadableStream;
26
+ getDefaultAgent$1 = shims.getDefaultAgent;
27
+ fileFromPath$1 = shims.fileFromPath;
28
+ }
29
+
30
+ /**
31
+ * Disclaimer: modules in _shims aren't intended to be imported by SDK users.
32
+ */
33
+ let MultipartBody$1 = class MultipartBody {
34
+ constructor(body) {
35
+ this.body = body;
80
36
  }
81
- removeNode(nodeId) {
82
- const index = this.nodes.findIndex(n => n.id === nodeId);
83
- if (index === -1) {
84
- throw new Error(`Node with id ${nodeId} not found`);
85
- }
86
- // Check if any nodes depend on this one
87
- const dependentNodes = this.nodes.filter(n => n.dependencies.includes(nodeId));
88
- if (dependentNodes.length > 0) {
89
- throw new Error(`Cannot remove node ${nodeId}: Nodes ${dependentNodes.map(n => n.id).join(", ")} depend on it`);
90
- }
91
- this.nodes.splice(index, 1);
37
+ get [Symbol.toStringTag]() {
38
+ return 'MultipartBody';
92
39
  }
93
- getNode(nodeId) {
94
- const node = this.nodes.find(n => n.id === nodeId);
95
- if (!node) {
96
- throw new Error(`Node with id ${nodeId} not found`);
97
- }
98
- return node;
40
+ };
41
+
42
+ function getRuntime$1({ manuallyImported } = {}) {
43
+ const recommendation = manuallyImported ?
44
+ `You may need to use polyfills`
45
+ : `Add one of these imports before your first \`import … from '@anthropic-ai/sdk'\`:
46
+ - \`import '@anthropic-ai/sdk/shims/node'\` (if you're running on Node)
47
+ - \`import '@anthropic-ai/sdk/shims/web'\` (otherwise)
48
+ `;
49
+ let _fetch, _Request, _Response, _Headers;
50
+ try {
51
+ // @ts-ignore
52
+ _fetch = fetch;
53
+ // @ts-ignore
54
+ _Request = Request;
55
+ // @ts-ignore
56
+ _Response = Response;
57
+ // @ts-ignore
58
+ _Headers = Headers;
99
59
  }
100
- validateDAG() {
101
- const visited = new Set();
102
- const recursionStack = new Set();
103
- const hasCycle = (nodeId) => {
104
- if (recursionStack.has(nodeId)) {
105
- return true;
60
+ catch (error) {
61
+ throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);
62
+ }
63
+ return {
64
+ kind: 'web',
65
+ fetch: _fetch,
66
+ Request: _Request,
67
+ Response: _Response,
68
+ Headers: _Headers,
69
+ FormData:
70
+ // @ts-ignore
71
+ typeof FormData !== 'undefined' ? FormData : (class FormData {
72
+ // @ts-ignore
73
+ constructor() {
74
+ throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);
106
75
  }
107
- if (visited.has(nodeId)) {
108
- return false;
76
+ }),
77
+ Blob: typeof Blob !== 'undefined' ? Blob : (class Blob {
78
+ constructor() {
79
+ throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);
109
80
  }
110
- visited.add(nodeId);
111
- recursionStack.add(nodeId);
112
- const node = this.getNode(nodeId);
113
- for (const depId of node.dependencies) {
114
- if (hasCycle(depId)) {
115
- return true;
116
- }
81
+ }),
82
+ File:
83
+ // @ts-ignore
84
+ typeof File !== 'undefined' ? File : (class File {
85
+ // @ts-ignore
86
+ constructor() {
87
+ throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);
117
88
  }
118
- recursionStack.delete(nodeId);
119
- return false;
120
- };
121
- return !this.nodes.some(node => hasCycle(node.id));
122
- }
89
+ }),
90
+ ReadableStream:
91
+ // @ts-ignore
92
+ typeof ReadableStream !== 'undefined' ? ReadableStream : (class ReadableStream {
93
+ // @ts-ignore
94
+ constructor() {
95
+ throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);
96
+ }
97
+ }),
98
+ getMultipartRequestOptions: async (
99
+ // @ts-ignore
100
+ form, opts) => ({
101
+ ...opts,
102
+ body: new MultipartBody$1(form),
103
+ }),
104
+ getDefaultAgent: (url) => undefined,
105
+ fileFromPath: () => {
106
+ throw new Error('The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads');
107
+ },
108
+ isFsReadStream: (value) => false,
109
+ };
123
110
  }
124
111
 
125
- // src/models/action.ts
126
112
  /**
127
- * Special tool that allows LLM to write values to context
113
+ * Disclaimer: modules in _shims aren't intended to be imported by SDK users.
128
114
  */
129
- class WriteContextTool {
130
- constructor() {
131
- this.name = 'write_context';
132
- this.description = 'Write a value to the workflow context. Use this to store intermediate results or outputs.';
133
- this.input_schema = {
134
- type: 'object',
135
- properties: {
136
- key: {
137
- type: 'string',
138
- description: 'The key to store the value under',
139
- },
140
- value: {
141
- type: 'string',
142
- description: 'The value to store (must be JSON stringified if object/array)',
143
- },
144
- },
145
- required: ['key', 'value'],
146
- };
115
+ if (!kind$1) setShims$1(getRuntime$1(), { auto: true });
116
+
117
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
118
+ class AnthropicError extends Error {
119
+ }
120
+ let APIError$1 = class APIError extends AnthropicError {
121
+ constructor(status, error, message, headers) {
122
+ super(`${APIError.makeMessage(status, error, message)}`);
123
+ this.status = status;
124
+ this.headers = headers;
125
+ this.request_id = headers?.['request-id'];
126
+ this.error = error;
147
127
  }
148
- async execute(context, params) {
149
- const { key, value } = params;
150
- try {
151
- // Try to parse the value as JSON
152
- const parsedValue = JSON.parse(value);
153
- context.variables.set(key, parsedValue);
128
+ static makeMessage(status, error, message) {
129
+ const msg = error?.message ?
130
+ typeof error.message === 'string' ?
131
+ error.message
132
+ : JSON.stringify(error.message)
133
+ : error ? JSON.stringify(error)
134
+ : message;
135
+ if (status && msg) {
136
+ return `${status} ${msg}`;
154
137
  }
155
- catch (_a) {
156
- // If parsing fails, store as string
157
- context.variables.set(key, value);
138
+ if (status) {
139
+ return `${status} status code (no body)`;
158
140
  }
159
- return { success: true, key, value };
141
+ if (msg) {
142
+ return msg;
143
+ }
144
+ return '(no status code or body)';
160
145
  }
161
- }
162
- function createReturnTool(outputSchema) {
163
- return {
164
- name: 'return_output',
165
- description: 'Return the final output of this action. Use this to return a value matching the required output schema.',
166
- input_schema: {
167
- type: 'object',
168
- properties: {
169
- value: outputSchema || {
170
- // Default to accepting any JSON value
171
- type: ['string', 'number', 'boolean', 'object', 'null'],
172
- description: 'The output value',
173
- },
174
- },
175
- required: ['value'],
176
- },
177
- async execute(context, params) {
178
- const { value } = params;
179
- context.variables.set('__action_output', value);
180
- return { returned: value };
181
- },
182
- };
183
- }
184
- class ActionImpl {
185
- constructor(type, // Only support prompt type
186
- name, description, tools, llmProvider, llmConfig, config) {
187
- this.type = type;
188
- this.name = name;
189
- this.description = description;
190
- this.tools = tools;
191
- this.llmProvider = llmProvider;
192
- this.llmConfig = llmConfig;
193
- this.maxRounds = 10; // Default max rounds
194
- this.writeContextTool = new WriteContextTool();
195
- this.tools = [...tools, this.writeContextTool];
196
- if (config === null || config === void 0 ? void 0 : config.maxRounds) {
197
- this.maxRounds = config.maxRounds;
146
+ static generate(status, errorResponse, message, headers) {
147
+ if (!status || !headers) {
148
+ return new APIConnectionError$1({ message, cause: castToError$1(errorResponse) });
198
149
  }
199
- }
200
- async executeSingleRound(messages, params, toolMap, context) {
201
- const roundMessages = [];
202
- let hasToolUse = false;
203
- let response = null;
204
- // Buffer to collect into roundMessages
205
- let assistantTextMessage = '';
206
- let toolUseMessage = null;
207
- let toolResultMessage = null;
208
- // Track tool execution promise
209
- let toolExecutionPromise = null;
210
- const handler = {
211
- onContent: (content) => {
212
- if (content.trim()) {
213
- assistantTextMessage += content;
214
- }
215
- },
216
- onToolUse: async (toolCall) => {
217
- console.log('Tool Call:', toolCall.name, toolCall.input);
218
- hasToolUse = true;
219
- const tool = toolMap.get(toolCall.name);
220
- if (!tool) {
221
- throw new Error(`Tool not found: ${toolCall.name}`);
222
- }
223
- toolUseMessage = {
224
- role: 'assistant',
225
- content: [
226
- {
227
- type: 'tool_use',
228
- id: toolCall.id,
229
- name: tool.name,
230
- input: toolCall.input,
231
- },
232
- ],
233
- };
234
- // Store the promise of tool execution
235
- toolExecutionPromise = (async () => {
236
- try {
237
- // beforeToolUse
238
- context.__skip = false;
239
- if (context.callback && context.callback.hooks.beforeToolUse) {
240
- let modified_input = await context.callback.hooks.beforeToolUse(tool, context, toolCall.input);
241
- if (modified_input) {
242
- toolCall.input = modified_input;
243
- }
244
- }
245
- if (context.__skip || context.__abort) {
246
- toolResultMessage = {
247
- role: 'user',
248
- content: [
249
- {
250
- type: 'tool_result',
251
- tool_use_id: toolCall.id,
252
- content: 'skip',
253
- },
254
- ],
255
- };
256
- return;
257
- }
258
- // Execute the tool
259
- let result = await tool.execute(context, toolCall.input);
260
- // afterToolUse
261
- if (context.callback && context.callback.hooks.afterToolUse) {
262
- let modified_result = await context.callback.hooks.afterToolUse(tool, context, result);
263
- if (modified_result) {
264
- result = modified_result;
265
- }
266
- }
267
- const resultMessage = {
268
- role: 'user',
269
- content: [
270
- result.image && result.image.type
271
- ? {
272
- type: 'tool_result',
273
- tool_use_id: toolCall.id,
274
- content: result.text
275
- ? [
276
- { type: 'image', source: result.image },
277
- { type: 'text', text: result.text },
278
- ]
279
- : [{ type: 'image', source: result.image }],
280
- }
281
- : {
282
- type: 'tool_result',
283
- tool_use_id: toolCall.id,
284
- content: [{ type: 'text', text: JSON.stringify(result) }],
285
- },
286
- ],
287
- };
288
- toolResultMessage = resultMessage;
289
- console.log('Tool Result:', result);
290
- }
291
- catch (err) {
292
- const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
293
- const errorResult = {
294
- role: 'user',
295
- content: [
296
- {
297
- type: 'tool_result',
298
- tool_use_id: toolCall.id,
299
- content: [{ type: 'text', text: `Error: ${errorMessage}` }],
300
- is_error: true,
301
- },
302
- ],
303
- };
304
- toolResultMessage = errorResult;
305
- console.error('Tool Error:', err);
306
- }
307
- })();
308
- },
309
- onComplete: (llmResponse) => {
310
- response = llmResponse;
311
- },
312
- onError: (error) => {
313
- console.error('Stream Error:', error);
314
- },
315
- };
316
- this.handleHistoryImageMessages(messages);
317
- // Wait for stream to complete
318
- await this.llmProvider.generateStream(messages, params, handler);
319
- // Wait for tool execution to complete if it was started
320
- if (toolExecutionPromise) {
321
- await toolExecutionPromise;
150
+ const error = errorResponse;
151
+ if (status === 400) {
152
+ return new BadRequestError$1(status, error, message, headers);
322
153
  }
323
- if (context.__abort) {
324
- throw new Error('Abort');
154
+ if (status === 401) {
155
+ return new AuthenticationError$1(status, error, message, headers);
325
156
  }
326
- // Add messages in the correct order after everything is complete
327
- if (assistantTextMessage) {
328
- roundMessages.push({ role: 'assistant', content: assistantTextMessage });
157
+ if (status === 403) {
158
+ return new PermissionDeniedError$1(status, error, message, headers);
329
159
  }
330
- if (toolUseMessage) {
331
- roundMessages.push(toolUseMessage);
160
+ if (status === 404) {
161
+ return new NotFoundError$1(status, error, message, headers);
332
162
  }
333
- if (toolResultMessage) {
334
- roundMessages.push(toolResultMessage);
163
+ if (status === 409) {
164
+ return new ConflictError$1(status, error, message, headers);
335
165
  }
336
- return { response, hasToolUse, roundMessages };
337
- }
338
- handleHistoryImageMessages(messages) {
339
- // Remove all images of the historical tool call results, except for the last one.
340
- let last_user = true;
341
- for (let i = messages.length - 1; i >= 0; i--) {
342
- const message = messages[i];
343
- if (message.role === 'user') {
344
- if (last_user) {
345
- last_user = false;
346
- continue;
347
- }
348
- if (message.content instanceof Array) {
349
- let content = message.content;
350
- for (let j = 0; j < content.length; j++) {
351
- if (content[j].type === 'tool_result' && content[j].content instanceof Array) {
352
- let tool_content = content[j].content;
353
- if (tool_content.length > 0) {
354
- for (let k = tool_content.length - 1; k >= 0; k--) {
355
- if (tool_content[k].type === 'image') {
356
- tool_content.splice(k, 1);
357
- }
358
- }
359
- }
360
- else if (tool_content[0].type === 'image') {
361
- tool_content = [{ type: 'text', text: 'ok' }];
362
- }
363
- }
364
- }
365
- }
366
- }
166
+ if (status === 422) {
167
+ return new UnprocessableEntityError$1(status, error, message, headers);
367
168
  }
368
- }
369
- async execute(input, context, outputSchema) {
370
- var _a;
371
- // Create return tool with output schema
372
- const returnTool = createReturnTool(outputSchema);
373
- // Create tool map combining context tools, action tools, and return tool
374
- const toolMap = new Map();
375
- this.tools.forEach((tool) => toolMap.set(tool.name, tool));
376
- (_a = context.tools) === null || _a === void 0 ? void 0 : _a.forEach((tool) => toolMap.set(tool.name, tool));
377
- toolMap.set(returnTool.name, returnTool);
378
- // Prepare initial messages
379
- const messages = [
380
- { role: 'system', content: this.formatSystemPrompt() },
381
- { role: 'user', content: this.formatUserPrompt(context, input) },
382
- ];
383
- console.log('Starting LLM conversation...');
384
- console.log('Initial messages:', messages);
385
- console.log('Output schema:', outputSchema);
386
- // Configure tool parameters
387
- const params = {
388
- ...this.llmConfig,
389
- tools: Array.from(toolMap.values()).map((tool) => ({
390
- name: tool.name,
391
- description: tool.description,
392
- input_schema: tool.input_schema,
393
- })),
394
- };
395
- let roundCount = 0;
396
- while (roundCount < this.maxRounds) {
397
- roundCount++;
398
- console.log(`Starting round ${roundCount} of ${this.maxRounds}`);
399
- console.log('Current conversation status:', JSON.stringify(messages, null, 2));
400
- const { response, hasToolUse, roundMessages } = await this.executeSingleRound(messages, params, toolMap, context);
401
- // Add round messages to conversation history
402
- messages.push(...roundMessages);
403
- // Check termination conditions
404
- if (!hasToolUse && response) {
405
- // LLM sent a message without using tools - request explicit return
406
- console.log('No tool use detected, requesting explicit return');
407
- console.log('Response:', response);
408
- const returnOnlyParams = {
409
- ...params,
410
- tools: [
411
- {
412
- name: returnTool.name,
413
- description: returnTool.description,
414
- input_schema: returnTool.input_schema,
415
- },
416
- ],
417
- };
418
- messages.push({
419
- role: 'user',
420
- content: 'Please process the above information and return a final result using the return_output tool.',
421
- });
422
- const { roundMessages: finalRoundMessages } = await this.executeSingleRound(messages, returnOnlyParams, new Map([[returnTool.name, returnTool]]), context);
423
- messages.push(...finalRoundMessages);
424
- break;
425
- }
426
- if (response === null || response === void 0 ? void 0 : response.toolCalls.some((call) => call.name === 'return_output')) {
427
- console.log('Task completed with return_output tool');
428
- break;
429
- }
430
- // If this is the last round, force an explicit return
431
- if (roundCount === this.maxRounds) {
432
- console.log('Max rounds reached, requesting explicit return');
433
- const returnOnlyParams = {
434
- ...params,
435
- tools: [
436
- {
437
- name: returnTool.name,
438
- description: returnTool.description,
439
- input_schema: returnTool.input_schema,
440
- },
441
- ],
442
- };
443
- messages.push({
444
- role: 'user',
445
- content: 'Maximum number of steps reached. Please return the best result possible with the return_output tool.',
446
- });
447
- const { roundMessages: finalRoundMessages } = await this.executeSingleRound(messages, returnOnlyParams, new Map([[returnTool.name, returnTool]]), context);
448
- messages.push(...finalRoundMessages);
449
- }
169
+ if (status === 429) {
170
+ return new RateLimitError$1(status, error, message, headers);
450
171
  }
451
- // Get and clean up output value
452
- const output = context.variables.get('__action_output');
453
- context.variables.delete('__action_output');
454
- if (output === undefined) {
455
- console.warn('Action completed without returning a value');
456
- return {};
172
+ if (status >= 500) {
173
+ return new InternalServerError$1(status, error, message, headers);
457
174
  }
458
- return output;
459
- }
460
- formatSystemPrompt() {
461
- return `You are a task executor. You need to complete the task specified by the user, using the tools provided. When you need to store results or outputs, use the write_context tool. When you are ready to return the final output, use the return_output tool.
462
-
463
- Remember to:
464
- 1. Use tools when needed to accomplish the task
465
- 2. Store important results using write_context, including intermediate and final results
466
- 3. Think step by step about what needs to be done`;
175
+ return new APIError(status, error, message, headers);
467
176
  }
468
- formatUserPrompt(context, input) {
469
- // Create a description of the current context
470
- const contextDescription = Array.from(context.variables.entries())
471
- .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
472
- .join('\n');
473
- return `You are executing the action "${this.name}". The specific instructions are: "${this.description}". You have access to the following context:
474
-
475
- ${contextDescription || 'No context variables set'}
476
-
477
- You have been provided with the following input:
478
- ${(typeof input === 'string' ? input : JSON.stringify(input, null, 2)) || 'No additional input provided'}
479
- `;
480
- }
481
- // Static factory method
482
- static createPromptAction(name, description, tools, llmProvider, llmConfig) {
483
- return new ActionImpl('prompt', name, description, tools, llmProvider, llmConfig);
177
+ };
178
+ let APIUserAbortError$1 = class APIUserAbortError extends APIError$1 {
179
+ constructor({ message } = {}) {
180
+ super(undefined, undefined, message || 'Request was aborted.', undefined);
484
181
  }
485
- }
486
-
487
- // src/services/workflow/templates.ts
488
- function createWorkflowPrompts(tools) {
489
- return {
490
- formatSystemPrompt: () => {
491
- const toolDescriptions = tools
492
- .map((tool) => `
493
- Tool: ${tool.name}
494
- Description: ${tool.description}
495
- Input Schema: ${JSON.stringify(tool.input_schema, null, 2)}
496
- `)
497
- .join('\n');
498
- return `You are a workflow generation assistant that creates Eko framework workflows.
499
- The following tools are available:
500
-
501
- ${toolDescriptions}
502
-
503
- Generate a complete workflow that:
504
- 1. Only uses the tools listed above
505
- 2. Properly sequences tool usage based on dependencies
506
- 3. Ensures each action has appropriate input/output schemas, and that the "tools" field in each action is populated with the sufficient subset of all available tools needed to complete the action
507
- 4. Creates a clear, logical flow to accomplish the user's goal
508
- 5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem`;
509
- },
510
- formatUserPrompt: (requirement) => `Create a workflow for the following requirement: ${requirement}`,
511
- modifyUserPrompt: (prompt) => `Modify workflow: ${prompt}`,
512
- };
513
- }
514
- function createWorkflowGenerationTool(registry) {
515
- return {
516
- name: 'generate_workflow',
517
- description: `Generate a workflow following the Eko framework DSL schema.
518
- The workflow must only use the available tools and ensure proper dependencies between nodes.`,
519
- input_schema: {
520
- type: 'object',
521
- properties: {
522
- workflow: registry.getWorkflowSchema(),
523
- },
524
- required: ['workflow'],
525
- },
526
- };
527
- }
528
-
529
- const byteToHex = [];
530
- for (let i = 0; i < 256; ++i) {
531
- byteToHex.push((i + 0x100).toString(16).slice(1));
532
- }
533
- function unsafeStringify(arr, offset = 0) {
534
- return (byteToHex[arr[offset + 0]] +
535
- byteToHex[arr[offset + 1]] +
536
- byteToHex[arr[offset + 2]] +
537
- byteToHex[arr[offset + 3]] +
538
- '-' +
539
- byteToHex[arr[offset + 4]] +
540
- byteToHex[arr[offset + 5]] +
541
- '-' +
542
- byteToHex[arr[offset + 6]] +
543
- byteToHex[arr[offset + 7]] +
544
- '-' +
545
- byteToHex[arr[offset + 8]] +
546
- byteToHex[arr[offset + 9]] +
547
- '-' +
548
- byteToHex[arr[offset + 10]] +
549
- byteToHex[arr[offset + 11]] +
550
- byteToHex[arr[offset + 12]] +
551
- byteToHex[arr[offset + 13]] +
552
- byteToHex[arr[offset + 14]] +
553
- byteToHex[arr[offset + 15]]).toLowerCase();
554
- }
555
-
556
- let getRandomValues;
557
- const rnds8 = new Uint8Array(16);
558
- function rng() {
559
- if (!getRandomValues) {
560
- if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
561
- throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
562
- }
563
- getRandomValues = crypto.getRandomValues.bind(crypto);
182
+ };
183
+ let APIConnectionError$1 = class APIConnectionError extends APIError$1 {
184
+ constructor({ message, cause }) {
185
+ super(undefined, undefined, message || 'Connection error.', undefined);
186
+ // in some environments the 'cause' property is already declared
187
+ // @ts-ignore
188
+ if (cause)
189
+ this.cause = cause;
564
190
  }
565
- return getRandomValues(rnds8);
566
- }
567
-
568
- const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
569
- var native = { randomUUID };
570
-
571
- function v4(options, buf, offset) {
572
- if (native.randomUUID && !buf && !options) {
573
- return native.randomUUID();
191
+ };
192
+ let APIConnectionTimeoutError$1 = class APIConnectionTimeoutError extends APIConnectionError$1 {
193
+ constructor({ message } = {}) {
194
+ super({ message: message ?? 'Request timed out.' });
574
195
  }
575
- options = options || {};
576
- const rnds = options.random || (options.rng || rng)();
577
- rnds[6] = (rnds[6] & 0x0f) | 0x40;
578
- rnds[8] = (rnds[8] & 0x3f) | 0x80;
579
- return unsafeStringify(rnds);
580
- }
196
+ };
197
+ let BadRequestError$1 = class BadRequestError extends APIError$1 {
198
+ };
199
+ let AuthenticationError$1 = class AuthenticationError extends APIError$1 {
200
+ };
201
+ let PermissionDeniedError$1 = class PermissionDeniedError extends APIError$1 {
202
+ };
203
+ let NotFoundError$1 = class NotFoundError extends APIError$1 {
204
+ };
205
+ let ConflictError$1 = class ConflictError extends APIError$1 {
206
+ };
207
+ let UnprocessableEntityError$1 = class UnprocessableEntityError extends APIError$1 {
208
+ };
209
+ let RateLimitError$1 = class RateLimitError extends APIError$1 {
210
+ };
211
+ let InternalServerError$1 = class InternalServerError extends APIError$1 {
212
+ };
581
213
 
582
- class WorkflowGenerator {
583
- constructor(llmProvider, toolRegistry) {
584
- this.llmProvider = llmProvider;
585
- this.toolRegistry = toolRegistry;
586
- this.message_history = [];
587
- }
588
- async generateWorkflow(prompt) {
589
- return this.doGenerateWorkflow(prompt, false);
590
- }
591
- async modifyWorkflow(prompt) {
592
- return this.doGenerateWorkflow(prompt, true);
214
+ /**
215
+ * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally
216
+ * reading lines from text.
217
+ *
218
+ * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258
219
+ */
220
+ let LineDecoder$1 = class LineDecoder {
221
+ constructor() {
222
+ this.buffer = [];
223
+ this.trailingCR = false;
593
224
  }
594
- async doGenerateWorkflow(prompt, modify) {
595
- // Create prompts with current set of tools
596
- const prompts = createWorkflowPrompts(this.toolRegistry.getToolDefinitions());
597
- let messages = [];
598
- if (modify) {
599
- messages = this.message_history;
600
- messages.push({
601
- role: 'user',
602
- content: prompts.modifyUserPrompt(prompt),
603
- });
225
+ decode(chunk) {
226
+ let text = this.decodeText(chunk);
227
+ if (this.trailingCR) {
228
+ text = '\r' + text;
229
+ this.trailingCR = false;
604
230
  }
605
- else {
606
- messages = this.message_history = [
607
- {
608
- role: 'system',
609
- content: prompts.formatSystemPrompt(),
610
- },
611
- {
612
- role: 'user',
613
- content: prompts.formatUserPrompt(prompt),
614
- },
615
- ];
231
+ if (text.endsWith('\r')) {
232
+ this.trailingCR = true;
233
+ text = text.slice(0, -1);
616
234
  }
617
- const params = {
618
- temperature: 0.7,
619
- maxTokens: 8192,
620
- tools: [createWorkflowGenerationTool(this.toolRegistry)],
621
- toolChoice: { type: 'tool', name: 'generate_workflow' },
622
- };
623
- const response = await this.llmProvider.generateText(messages, params);
624
- if (!response.toolCalls.length || !response.toolCalls[0].input.workflow) {
625
- messages.pop();
626
- throw new Error('Failed to generate workflow: Invalid response from LLM');
235
+ if (!text) {
236
+ return [];
627
237
  }
628
- messages.push({
629
- role: 'assistant',
630
- content: [
631
- {
632
- type: 'tool_use',
633
- id: response.toolCalls[0].id,
634
- name: response.toolCalls[0].name,
635
- input: response.toolCalls[0].input,
636
- },
637
- ],
638
- }, {
639
- role: 'user',
640
- content: [
641
- {
642
- type: 'tool_result',
643
- tool_use_id: response.toolCalls[0].id,
644
- content: 'ok',
645
- },
646
- ],
647
- });
648
- const workflowData = response.toolCalls[0].input.workflow;
649
- // Validate all tools exist
650
- for (const node of workflowData.nodes) {
651
- if (!this.toolRegistry.hasTools(node.action.tools)) {
652
- throw new Error(`Workflow contains undefined tools: ${node.action.tools}`);
653
- }
238
+ const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || '');
239
+ let lines = text.split(LineDecoder.NEWLINE_REGEXP);
240
+ // if there is a trailing new line then the last entry will be an empty
241
+ // string which we don't care about
242
+ if (trailingNewline) {
243
+ lines.pop();
654
244
  }
655
- // Generate a new UUID if not provided
656
- if (!workflowData.id) {
657
- workflowData.id = v4();
245
+ if (lines.length === 1 && !trailingNewline) {
246
+ this.buffer.push(lines[0]);
247
+ return [];
658
248
  }
659
- return this.createWorkflowFromData(workflowData);
660
- }
661
- createWorkflowFromData(data) {
662
- const workflow = new WorkflowImpl(data.id, data.name, data.description || '', [], new Map(Object.entries(data.variables || {})), this.llmProvider);
663
- // Add nodes to workflow
664
- if (Array.isArray(data.nodes)) {
665
- data.nodes.forEach((nodeData) => {
666
- const tools = nodeData.action.tools.map((toolName) => this.toolRegistry.getTool(toolName));
667
- const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, tools, this.llmProvider, { maxTokens: 1000 });
668
- const node = {
669
- id: nodeData.id,
670
- name: nodeData.name || nodeData.id,
671
- input: nodeData.input || { type: 'any', schema: {}, value: undefined },
672
- output: nodeData.output || { type: 'any', schema: {}, value: undefined },
673
- action: action,
674
- dependencies: nodeData.dependencies || [],
675
- };
676
- workflow.addNode(node);
677
- });
249
+ if (this.buffer.length > 0) {
250
+ lines = [this.buffer.join('') + lines[0], ...lines.slice(1)];
251
+ this.buffer = [];
678
252
  }
679
- return workflow;
680
- }
681
- }
682
-
683
- const VERSION$1 = '0.33.1'; // x-release-please-version
684
-
685
- let auto$1 = false;
686
- let kind$1 = undefined;
687
- let fetch$2 = undefined;
688
- let File$2 = undefined;
689
- let ReadableStream$2 = undefined;
690
- let getDefaultAgent$1 = undefined;
691
- let fileFromPath$1 = undefined;
692
- function setShims$1(shims, options = { auto: false }) {
693
- if (auto$1) {
694
- throw new Error(`you must \`import '@anthropic-ai/sdk/shims/${shims.kind}'\` before importing anything else from @anthropic-ai/sdk`);
695
- }
696
- if (kind$1) {
697
- throw new Error(`can't \`import '@anthropic-ai/sdk/shims/${shims.kind}'\` after \`import '@anthropic-ai/sdk/shims/${kind$1}'\``);
698
- }
699
- auto$1 = options.auto;
700
- kind$1 = shims.kind;
701
- fetch$2 = shims.fetch;
702
- File$2 = shims.File;
703
- ReadableStream$2 = shims.ReadableStream;
704
- getDefaultAgent$1 = shims.getDefaultAgent;
705
- fileFromPath$1 = shims.fileFromPath;
706
- }
707
-
708
- /**
709
- * Disclaimer: modules in _shims aren't intended to be imported by SDK users.
710
- */
711
- let MultipartBody$1 = class MultipartBody {
712
- constructor(body) {
713
- this.body = body;
714
- }
715
- get [Symbol.toStringTag]() {
716
- return 'MultipartBody';
717
- }
718
- };
719
-
720
- function getRuntime$1({ manuallyImported } = {}) {
721
- const recommendation = manuallyImported ?
722
- `You may need to use polyfills`
723
- : `Add one of these imports before your first \`import … from '@anthropic-ai/sdk'\`:
724
- - \`import '@anthropic-ai/sdk/shims/node'\` (if you're running on Node)
725
- - \`import '@anthropic-ai/sdk/shims/web'\` (otherwise)
726
- `;
727
- let _fetch, _Request, _Response, _Headers;
728
- try {
729
- // @ts-ignore
730
- _fetch = fetch;
731
- // @ts-ignore
732
- _Request = Request;
733
- // @ts-ignore
734
- _Response = Response;
735
- // @ts-ignore
736
- _Headers = Headers;
737
- }
738
- catch (error) {
739
- throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);
740
- }
741
- return {
742
- kind: 'web',
743
- fetch: _fetch,
744
- Request: _Request,
745
- Response: _Response,
746
- Headers: _Headers,
747
- FormData:
748
- // @ts-ignore
749
- typeof FormData !== 'undefined' ? FormData : (class FormData {
750
- // @ts-ignore
751
- constructor() {
752
- throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);
753
- }
754
- }),
755
- Blob: typeof Blob !== 'undefined' ? Blob : (class Blob {
756
- constructor() {
757
- throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);
758
- }
759
- }),
760
- File:
761
- // @ts-ignore
762
- typeof File !== 'undefined' ? File : (class File {
763
- // @ts-ignore
764
- constructor() {
765
- throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);
766
- }
767
- }),
768
- ReadableStream:
769
- // @ts-ignore
770
- typeof ReadableStream !== 'undefined' ? ReadableStream : (class ReadableStream {
771
- // @ts-ignore
772
- constructor() {
773
- throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);
774
- }
775
- }),
776
- getMultipartRequestOptions: async (
777
- // @ts-ignore
778
- form, opts) => ({
779
- ...opts,
780
- body: new MultipartBody$1(form),
781
- }),
782
- getDefaultAgent: (url) => undefined,
783
- fileFromPath: () => {
784
- throw new Error('The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads');
785
- },
786
- isFsReadStream: (value) => false,
787
- };
788
- }
789
-
790
- /**
791
- * Disclaimer: modules in _shims aren't intended to be imported by SDK users.
792
- */
793
- if (!kind$1) setShims$1(getRuntime$1(), { auto: true });
794
-
795
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
796
- class AnthropicError extends Error {
797
- }
798
- let APIError$1 = class APIError extends AnthropicError {
799
- constructor(status, error, message, headers) {
800
- super(`${APIError.makeMessage(status, error, message)}`);
801
- this.status = status;
802
- this.headers = headers;
803
- this.request_id = headers?.['request-id'];
804
- this.error = error;
805
- }
806
- static makeMessage(status, error, message) {
807
- const msg = error?.message ?
808
- typeof error.message === 'string' ?
809
- error.message
810
- : JSON.stringify(error.message)
811
- : error ? JSON.stringify(error)
812
- : message;
813
- if (status && msg) {
814
- return `${status} ${msg}`;
815
- }
816
- if (status) {
817
- return `${status} status code (no body)`;
818
- }
819
- if (msg) {
820
- return msg;
821
- }
822
- return '(no status code or body)';
823
- }
824
- static generate(status, errorResponse, message, headers) {
825
- if (!status || !headers) {
826
- return new APIConnectionError$1({ message, cause: castToError$1(errorResponse) });
827
- }
828
- const error = errorResponse;
829
- if (status === 400) {
830
- return new BadRequestError$1(status, error, message, headers);
831
- }
832
- if (status === 401) {
833
- return new AuthenticationError$1(status, error, message, headers);
834
- }
835
- if (status === 403) {
836
- return new PermissionDeniedError$1(status, error, message, headers);
837
- }
838
- if (status === 404) {
839
- return new NotFoundError$1(status, error, message, headers);
840
- }
841
- if (status === 409) {
842
- return new ConflictError$1(status, error, message, headers);
843
- }
844
- if (status === 422) {
845
- return new UnprocessableEntityError$1(status, error, message, headers);
846
- }
847
- if (status === 429) {
848
- return new RateLimitError$1(status, error, message, headers);
849
- }
850
- if (status >= 500) {
851
- return new InternalServerError$1(status, error, message, headers);
852
- }
853
- return new APIError(status, error, message, headers);
854
- }
855
- };
856
- let APIUserAbortError$1 = class APIUserAbortError extends APIError$1 {
857
- constructor({ message } = {}) {
858
- super(undefined, undefined, message || 'Request was aborted.', undefined);
859
- }
860
- };
861
- let APIConnectionError$1 = class APIConnectionError extends APIError$1 {
862
- constructor({ message, cause }) {
863
- super(undefined, undefined, message || 'Connection error.', undefined);
864
- // in some environments the 'cause' property is already declared
865
- // @ts-ignore
866
- if (cause)
867
- this.cause = cause;
868
- }
869
- };
870
- let APIConnectionTimeoutError$1 = class APIConnectionTimeoutError extends APIConnectionError$1 {
871
- constructor({ message } = {}) {
872
- super({ message: message ?? 'Request timed out.' });
873
- }
874
- };
875
- let BadRequestError$1 = class BadRequestError extends APIError$1 {
876
- };
877
- let AuthenticationError$1 = class AuthenticationError extends APIError$1 {
878
- };
879
- let PermissionDeniedError$1 = class PermissionDeniedError extends APIError$1 {
880
- };
881
- let NotFoundError$1 = class NotFoundError extends APIError$1 {
882
- };
883
- let ConflictError$1 = class ConflictError extends APIError$1 {
884
- };
885
- let UnprocessableEntityError$1 = class UnprocessableEntityError extends APIError$1 {
886
- };
887
- let RateLimitError$1 = class RateLimitError extends APIError$1 {
888
- };
889
- let InternalServerError$1 = class InternalServerError extends APIError$1 {
890
- };
891
-
892
- /**
893
- * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally
894
- * reading lines from text.
895
- *
896
- * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258
897
- */
898
- let LineDecoder$1 = class LineDecoder {
899
- constructor() {
900
- this.buffer = [];
901
- this.trailingCR = false;
902
- }
903
- decode(chunk) {
904
- let text = this.decodeText(chunk);
905
- if (this.trailingCR) {
906
- text = '\r' + text;
907
- this.trailingCR = false;
908
- }
909
- if (text.endsWith('\r')) {
910
- this.trailingCR = true;
911
- text = text.slice(0, -1);
912
- }
913
- if (!text) {
914
- return [];
915
- }
916
- const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || '');
917
- let lines = text.split(LineDecoder.NEWLINE_REGEXP);
918
- // if there is a trailing new line then the last entry will be an empty
919
- // string which we don't care about
920
- if (trailingNewline) {
921
- lines.pop();
922
- }
923
- if (lines.length === 1 && !trailingNewline) {
924
- this.buffer.push(lines[0]);
925
- return [];
926
- }
927
- if (this.buffer.length > 0) {
928
- lines = [this.buffer.join('') + lines[0], ...lines.slice(1)];
929
- this.buffer = [];
930
- }
931
- if (!trailingNewline) {
932
- this.buffer = [lines.pop() || ''];
933
- }
934
- return lines;
253
+ if (!trailingNewline) {
254
+ this.buffer = [lines.pop() || ''];
255
+ }
256
+ return lines;
935
257
  }
936
258
  decodeText(bytes) {
937
259
  if (bytes == null)
@@ -1043,7 +365,7 @@ let Stream$1 = class Stream {
1043
365
  let consumed = false;
1044
366
  async function* iterLines() {
1045
367
  const lineDecoder = new LineDecoder$1();
1046
- const iter = readableStreamAsyncIterable$1(readableStream);
368
+ const iter = readableStreamAsyncIterable(readableStream);
1047
369
  for await (const chunk of iter) {
1048
370
  for (const line of lineDecoder.decode(chunk)) {
1049
371
  yield line;
@@ -1148,7 +470,7 @@ async function* _iterSSEMessages$1(response, controller) {
1148
470
  }
1149
471
  const sseDecoder = new SSEDecoder$1();
1150
472
  const lineDecoder = new LineDecoder$1();
1151
- const iter = readableStreamAsyncIterable$1(response.body);
473
+ const iter = readableStreamAsyncIterable(response.body);
1152
474
  for await (const sseChunk of iterSSEChunks$1(iter)) {
1153
475
  for (const line of lineDecoder.decode(sseChunk)) {
1154
476
  const sse = sseDecoder.decode(line);
@@ -1269,7 +591,7 @@ function partition$1(str, delimiter) {
1269
591
  *
1270
592
  * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
1271
593
  */
1272
- function readableStreamAsyncIterable$1(stream) {
594
+ function readableStreamAsyncIterable(stream) {
1273
595
  if (stream[Symbol.asyncIterator])
1274
596
  return stream;
1275
597
  const reader = stream.getReader();
@@ -1832,7 +1154,7 @@ let APIClient$1 = class APIClient {
1832
1154
  };
1833
1155
  let AbstractPage$1 = class AbstractPage {
1834
1156
  constructor(client, response, body, options) {
1835
- _AbstractPage_client$1.set(this, void 0);
1157
+ _AbstractPage_client$1.set(this, undefined);
1836
1158
  __classPrivateFieldSet$5(this, _AbstractPage_client$1, client, "f");
1837
1159
  this.options = options;
1838
1160
  this.response = response;
@@ -2311,7 +1633,7 @@ class JSONLDecoder {
2311
1633
  controller.abort();
2312
1634
  throw new AnthropicError(`Attempted to iterate over a response with no body`);
2313
1635
  }
2314
- return new JSONLDecoder(readableStreamAsyncIterable$1(response.body), controller);
1636
+ return new JSONLDecoder(readableStreamAsyncIterable(response.body), controller);
2315
1637
  }
2316
1638
  }
2317
1639
 
@@ -2763,12 +2085,12 @@ class MessageStream {
2763
2085
  _MessageStream_instances.add(this);
2764
2086
  this.messages = [];
2765
2087
  this.receivedMessages = [];
2766
- _MessageStream_currentMessageSnapshot.set(this, void 0);
2088
+ _MessageStream_currentMessageSnapshot.set(this, undefined);
2767
2089
  this.controller = new AbortController();
2768
- _MessageStream_connectedPromise.set(this, void 0);
2090
+ _MessageStream_connectedPromise.set(this, undefined);
2769
2091
  _MessageStream_resolveConnectedPromise.set(this, () => { });
2770
2092
  _MessageStream_rejectConnectedPromise.set(this, () => { });
2771
- _MessageStream_endPromise.set(this, void 0);
2093
+ _MessageStream_endPromise.set(this, undefined);
2772
2094
  _MessageStream_resolveEndPromise.set(this, () => { });
2773
2095
  _MessageStream_rejectEndPromise.set(this, () => { });
2774
2096
  _MessageStream_listeners.set(this, {});
@@ -3391,14 +2713,14 @@ class ClaudeProvider {
3391
2713
  if (typeof window !== 'undefined' &&
3392
2714
  typeof document !== 'undefined' &&
3393
2715
  (typeof param == 'string' || param.apiKey)) {
3394
- console.warn(`
3395
- ⚠️ Security Warning:
3396
- DO NOT use API Keys in browser/frontend code!
3397
- This will expose your credentials and may lead to unauthorized usage.
3398
-
3399
- Best Practices: Configure backend API proxy request through baseURL and request headers.
3400
-
3401
- Please refer to the link: https://eko.fellou.ai/docs/getting-started/configuration#web-environment
2716
+ console.warn(`
2717
+ ⚠️ Security Warning:
2718
+ DO NOT use API Keys in browser/frontend code!
2719
+ This will expose your credentials and may lead to unauthorized usage.
2720
+
2721
+ Best Practices: Configure backend API proxy request through baseURL and request headers.
2722
+
2723
+ Please refer to the link: https://eko.fellou.ai/docs/getting-started/configuration#web-environment
3402
2724
  `);
3403
2725
  }
3404
2726
  if (typeof param == 'string') {
@@ -3408,8 +2730,13 @@ class ClaudeProvider {
3408
2730
  ...options,
3409
2731
  });
3410
2732
  }
2733
+ else if (param.messages && param.completions) {
2734
+ this.client = param;
2735
+ }
3411
2736
  else {
3412
- this.client = new Anthropic(param);
2737
+ let options = param;
2738
+ options.dangerouslyAllowBrowser = true;
2739
+ this.client = new Anthropic(options);
3413
2740
  }
3414
2741
  }
3415
2742
  processResponse(response) {
@@ -3445,7 +2772,7 @@ class ClaudeProvider {
3445
2772
  const response = await this.client.messages.create({
3446
2773
  system,
3447
2774
  model: params.model || this.defaultModel,
3448
- max_tokens: params.maxTokens || 1024,
2775
+ max_tokens: params.maxTokens || 8192,
3449
2776
  temperature: params.temperature,
3450
2777
  messages: messages.filter((s) => s.role != 'system'),
3451
2778
  tools: params.tools,
@@ -3468,13 +2795,13 @@ class ClaudeProvider {
3468
2795
  const stream = await this.client.messages.stream({
3469
2796
  system,
3470
2797
  model: params.model || this.defaultModel,
3471
- max_tokens: params.maxTokens || 4096,
2798
+ max_tokens: params.maxTokens || 8192,
3472
2799
  temperature: params.temperature,
3473
2800
  messages: messages.filter((s) => s.role != 'system'),
3474
2801
  tools: params.tools,
3475
2802
  tool_choice: params.toolChoice,
3476
2803
  });
3477
- (_a = handler.onStart) === null || _a === void 0 ? void 0 : _a.call(handler);
2804
+ (_a = handler.onStart) === null || _a === undefined ? undefined : _a.call(handler);
3478
2805
  let currentToolUse = null;
3479
2806
  try {
3480
2807
  for await (const event of stream) {
@@ -3516,7 +2843,7 @@ class ClaudeProvider {
3516
2843
  (_e = handler.onComplete) === null || _e === void 0 ? void 0 : _e.call(handler, this.processResponse(message));
3517
2844
  }
3518
2845
  catch (error) {
3519
- (_f = handler.onError) === null || _f === void 0 ? void 0 : _f.call(handler, error);
2846
+ (_f = handler.onError) === null || _f === undefined ? undefined : _f.call(handler, error);
3520
2847
  }
3521
2848
  }
3522
2849
  }
@@ -3669,7 +2996,7 @@ function inner_stringify(object, prefix, generateArrayPrefix, commaRoundTrip, al
3669
2996
  let tmp_sc = sideChannel;
3670
2997
  let step = 0;
3671
2998
  let find_flag = false;
3672
- while ((tmp_sc = tmp_sc.get(sentinel)) !== void undefined && !find_flag) {
2999
+ while ((tmp_sc = tmp_sc.get(sentinel)) !== undefined && !find_flag) {
3673
3000
  // Where object last appeared in the ref tree
3674
3001
  const pos = tmp_sc.get(object);
3675
3002
  step += 1;
@@ -3733,7 +3060,7 @@ function inner_stringify(object, prefix, generateArrayPrefix, commaRoundTrip, al
3733
3060
  // @ts-expect-error values only
3734
3061
  obj = maybe_map(obj, encoder);
3735
3062
  }
3736
- obj_keys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
3063
+ obj_keys = [{ value: obj.length > 0 ? obj.join(',') || null : undefined }];
3737
3064
  }
3738
3065
  else if (is_array(filter)) {
3739
3066
  obj_keys = filter;
@@ -3889,7 +3216,7 @@ function stringify(object, opts = {}) {
3889
3216
  return joined.length > 0 ? prefix + joined : '';
3890
3217
  }
3891
3218
 
3892
- const VERSION = '4.77.0'; // x-release-please-version
3219
+ const VERSION = '4.79.4'; // x-release-please-version
3893
3220
 
3894
3221
  let auto = false;
3895
3222
  let kind = undefined;
@@ -4201,13 +3528,48 @@ class LineDecoder {
4201
3528
  LineDecoder.NEWLINE_CHARS = new Set(['\n', '\r']);
4202
3529
  LineDecoder.NEWLINE_REGEXP = /\r\n|[\n\r]/g;
4203
3530
 
4204
- class Stream {
4205
- constructor(iterator, controller) {
4206
- this.iterator = iterator;
4207
- this.controller = controller;
4208
- }
4209
- static fromSSEResponse(response, controller) {
4210
- let consumed = false;
3531
+ /**
3532
+ * Most browsers don't yet have async iterable support for ReadableStream,
3533
+ * and Node has a very different way of reading bytes from its "ReadableStream".
3534
+ *
3535
+ * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
3536
+ */
3537
+ function ReadableStreamToAsyncIterable(stream) {
3538
+ if (stream[Symbol.asyncIterator])
3539
+ return stream;
3540
+ const reader = stream.getReader();
3541
+ return {
3542
+ async next() {
3543
+ try {
3544
+ const result = await reader.read();
3545
+ if (result?.done)
3546
+ reader.releaseLock(); // release lock when stream becomes closed
3547
+ return result;
3548
+ }
3549
+ catch (e) {
3550
+ reader.releaseLock(); // release lock when stream becomes errored
3551
+ throw e;
3552
+ }
3553
+ },
3554
+ async return() {
3555
+ const cancelPromise = reader.cancel();
3556
+ reader.releaseLock();
3557
+ await cancelPromise;
3558
+ return { done: true, value: undefined };
3559
+ },
3560
+ [Symbol.asyncIterator]() {
3561
+ return this;
3562
+ },
3563
+ };
3564
+ }
3565
+
3566
+ class Stream {
3567
+ constructor(iterator, controller) {
3568
+ this.iterator = iterator;
3569
+ this.controller = controller;
3570
+ }
3571
+ static fromSSEResponse(response, controller) {
3572
+ let consumed = false;
4211
3573
  async function* iterator() {
4212
3574
  if (consumed) {
4213
3575
  throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.');
@@ -4278,7 +3640,7 @@ class Stream {
4278
3640
  let consumed = false;
4279
3641
  async function* iterLines() {
4280
3642
  const lineDecoder = new LineDecoder();
4281
- const iter = readableStreamAsyncIterable(readableStream);
3643
+ const iter = ReadableStreamToAsyncIterable(readableStream);
4282
3644
  for await (const chunk of iter) {
4283
3645
  for (const line of lineDecoder.decode(chunk)) {
4284
3646
  yield line;
@@ -4383,7 +3745,7 @@ async function* _iterSSEMessages(response, controller) {
4383
3745
  }
4384
3746
  const sseDecoder = new SSEDecoder();
4385
3747
  const lineDecoder = new LineDecoder();
4386
- const iter = readableStreamAsyncIterable(response.body);
3748
+ const iter = ReadableStreamToAsyncIterable(response.body);
4387
3749
  for await (const sseChunk of iterSSEChunks(iter)) {
4388
3750
  for (const line of lineDecoder.decode(sseChunk)) {
4389
3751
  const sse = sseDecoder.decode(line);
@@ -4498,40 +3860,6 @@ function partition(str, delimiter) {
4498
3860
  }
4499
3861
  return [str, '', ''];
4500
3862
  }
4501
- /**
4502
- * Most browsers don't yet have async iterable support for ReadableStream,
4503
- * and Node has a very different way of reading bytes from its "ReadableStream".
4504
- *
4505
- * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
4506
- */
4507
- function readableStreamAsyncIterable(stream) {
4508
- if (stream[Symbol.asyncIterator])
4509
- return stream;
4510
- const reader = stream.getReader();
4511
- return {
4512
- async next() {
4513
- try {
4514
- const result = await reader.read();
4515
- if (result?.done)
4516
- reader.releaseLock(); // release lock when stream becomes closed
4517
- return result;
4518
- }
4519
- catch (e) {
4520
- reader.releaseLock(); // release lock when stream becomes errored
4521
- throw e;
4522
- }
4523
- },
4524
- async return() {
4525
- const cancelPromise = reader.cancel();
4526
- reader.releaseLock();
4527
- await cancelPromise;
4528
- return { done: true, value: undefined };
4529
- },
4530
- [Symbol.asyncIterator]() {
4531
- return this;
4532
- },
4533
- };
4534
- }
4535
3863
 
4536
3864
  const isResponseLike = (value) => value != null &&
4537
3865
  typeof value === 'object' &&
@@ -5030,9 +4358,18 @@ class APIClient {
5030
4358
  if (signal)
5031
4359
  signal.addEventListener('abort', () => controller.abort());
5032
4360
  const timeout = setTimeout(() => controller.abort(), ms);
4361
+ const fetchOptions = {
4362
+ signal: controller.signal,
4363
+ ...options,
4364
+ };
4365
+ if (fetchOptions.method) {
4366
+ // Custom methods like 'patch' need to be uppercased
4367
+ // See https://github.com/nodejs/undici/issues/2294
4368
+ fetchOptions.method = fetchOptions.method.toUpperCase();
4369
+ }
5033
4370
  return (
5034
4371
  // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
5035
- this.fetch.call(undefined, url, { signal: controller.signal, ...options }).finally(() => {
4372
+ this.fetch.call(undefined, url, fetchOptions).finally(() => {
5036
4373
  clearTimeout(timeout);
5037
4374
  }));
5038
4375
  }
@@ -5104,7 +4441,7 @@ class APIClient {
5104
4441
  }
5105
4442
  class AbstractPage {
5106
4443
  constructor(client, response, body, options) {
5107
- _AbstractPage_client.set(this, void 0);
4444
+ _AbstractPage_client.set(this, undefined);
5108
4445
  __classPrivateFieldSet$3(this, _AbstractPage_client, client, "f");
5109
4446
  this.options = options;
5110
4447
  this.response = response;
@@ -5427,9 +4764,36 @@ function applyHeadersMut(targetHeaders, newHeaders) {
5427
4764
  }
5428
4765
  }
5429
4766
  }
4767
+ const SENSITIVE_HEADERS = new Set(['authorization', 'api-key']);
5430
4768
  function debug(action, ...args) {
5431
4769
  if (typeof process !== 'undefined' && process?.env?.['DEBUG'] === 'true') {
5432
- console.log(`OpenAI:DEBUG:${action}`, ...args);
4770
+ const modifiedArgs = args.map((arg) => {
4771
+ if (!arg) {
4772
+ return arg;
4773
+ }
4774
+ // Check for sensitive headers in request body 'headers' object
4775
+ if (arg['headers']) {
4776
+ // clone so we don't mutate
4777
+ const modifiedArg = { ...arg, headers: { ...arg['headers'] } };
4778
+ for (const header in arg['headers']) {
4779
+ if (SENSITIVE_HEADERS.has(header.toLowerCase())) {
4780
+ modifiedArg['headers'][header] = 'REDACTED';
4781
+ }
4782
+ }
4783
+ return modifiedArg;
4784
+ }
4785
+ let modifiedArg = null;
4786
+ // Check for sensitive headers in headers object
4787
+ for (const header in arg) {
4788
+ if (SENSITIVE_HEADERS.has(header.toLowerCase())) {
4789
+ // avoid making a copy until we need to
4790
+ modifiedArg ?? (modifiedArg = { ...arg });
4791
+ modifiedArg[header] = 'REDACTED';
4792
+ }
4793
+ }
4794
+ return modifiedArg ?? arg;
4795
+ });
4796
+ console.log(`OpenAI:DEBUG:${action}`, ...modifiedArgs);
5433
4797
  }
5434
4798
  }
5435
4799
  /**
@@ -5571,7 +4935,12 @@ class Speech extends APIResource {
5571
4935
  * Generates audio from the input text.
5572
4936
  */
5573
4937
  create(body, options) {
5574
- return this._client.post('/audio/speech', { body, ...options, __binaryResponse: true });
4938
+ return this._client.post('/audio/speech', {
4939
+ body,
4940
+ ...options,
4941
+ headers: { Accept: 'application/octet-stream', ...options?.headers },
4942
+ __binaryResponse: true,
4943
+ });
5575
4944
  }
5576
4945
  }
5577
4946
 
@@ -5720,10 +5089,10 @@ class EventStream {
5720
5089
  constructor() {
5721
5090
  _EventStream_instances.add(this);
5722
5091
  this.controller = new AbortController();
5723
- _EventStream_connectedPromise.set(this, void 0);
5092
+ _EventStream_connectedPromise.set(this, undefined);
5724
5093
  _EventStream_resolveConnectedPromise.set(this, () => { });
5725
5094
  _EventStream_rejectConnectedPromise.set(this, () => { });
5726
- _EventStream_endPromise.set(this, void 0);
5095
+ _EventStream_endPromise.set(this, undefined);
5727
5096
  _EventStream_resolveEndPromise.set(this, () => { });
5728
5097
  _EventStream_rejectEndPromise.set(this, () => { });
5729
5098
  _EventStream_listeners.set(this, {});
@@ -6634,9 +6003,9 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
6634
6003
  constructor(params) {
6635
6004
  super();
6636
6005
  _ChatCompletionStream_instances.add(this);
6637
- _ChatCompletionStream_params.set(this, void 0);
6638
- _ChatCompletionStream_choiceEventStates.set(this, void 0);
6639
- _ChatCompletionStream_currentChatCompletionSnapshot.set(this, void 0);
6006
+ _ChatCompletionStream_params.set(this, undefined);
6007
+ _ChatCompletionStream_choiceEventStates.set(this, undefined);
6008
+ _ChatCompletionStream_currentChatCompletionSnapshot.set(this, undefined);
6640
6009
  __classPrivateFieldSet$1(this, _ChatCompletionStream_params, params, "f");
6641
6010
  __classPrivateFieldSet$1(this, _ChatCompletionStream_choiceEventStates, [], "f");
6642
6011
  }
@@ -7174,7 +6543,36 @@ class Chat extends APIResource {
7174
6543
  }
7175
6544
  (function (Chat) {
7176
6545
  Chat.Completions = Completions$1;
7177
- })(Chat || (Chat = {}));
6546
+ })(Chat);
6547
+
6548
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
6549
+ class Sessions extends APIResource {
6550
+ /**
6551
+ * Create an ephemeral API token for use in client-side applications with the
6552
+ * Realtime API. Can be configured with the same session parameters as the
6553
+ * `session.update` client event.
6554
+ *
6555
+ * It responds with a session object, plus a `client_secret` key which contains a
6556
+ * usable ephemeral API token that can be used to authenticate browser clients for
6557
+ * the Realtime API.
6558
+ */
6559
+ create(body, options) {
6560
+ return this._client.post('/realtime/sessions', {
6561
+ body,
6562
+ ...options,
6563
+ headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers },
6564
+ });
6565
+ }
6566
+ }
6567
+
6568
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
6569
+ class Realtime extends APIResource {
6570
+ constructor() {
6571
+ super(...arguments);
6572
+ this.sessions = new Sessions(this._client);
6573
+ }
6574
+ }
6575
+ Realtime.Sessions = Sessions;
7178
6576
 
7179
6577
  var __classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
7180
6578
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
@@ -7198,16 +6596,16 @@ class AssistantStream extends EventStream {
7198
6596
  //We are accumulating many types so the value here is not strict
7199
6597
  _AssistantStream_runStepSnapshots.set(this, {});
7200
6598
  _AssistantStream_messageSnapshots.set(this, {});
7201
- _AssistantStream_messageSnapshot.set(this, void 0);
7202
- _AssistantStream_finalRun.set(this, void 0);
7203
- _AssistantStream_currentContentIndex.set(this, void 0);
7204
- _AssistantStream_currentContent.set(this, void 0);
7205
- _AssistantStream_currentToolCallIndex.set(this, void 0);
7206
- _AssistantStream_currentToolCall.set(this, void 0);
6599
+ _AssistantStream_messageSnapshot.set(this, undefined);
6600
+ _AssistantStream_finalRun.set(this, undefined);
6601
+ _AssistantStream_currentContentIndex.set(this, undefined);
6602
+ _AssistantStream_currentContent.set(this, undefined);
6603
+ _AssistantStream_currentToolCallIndex.set(this, undefined);
6604
+ _AssistantStream_currentToolCall.set(this, undefined);
7207
6605
  //For current snapshot methods
7208
- _AssistantStream_currentEvent.set(this, void 0);
7209
- _AssistantStream_currentRunSnapshot.set(this, void 0);
7210
- _AssistantStream_currentRunStepSnapshot.set(this, void 0);
6606
+ _AssistantStream_currentEvent.set(this, undefined);
6607
+ _AssistantStream_currentRunSnapshot.set(this, undefined);
6608
+ _AssistantStream_currentRunStepSnapshot.set(this, undefined);
7211
6609
  }
7212
6610
  [(_AssistantStream_events = new WeakMap(), _AssistantStream_runStepSnapshots = new WeakMap(), _AssistantStream_messageSnapshots = new WeakMap(), _AssistantStream_messageSnapshot = new WeakMap(), _AssistantStream_finalRun = new WeakMap(), _AssistantStream_currentContentIndex = new WeakMap(), _AssistantStream_currentContent = new WeakMap(), _AssistantStream_currentToolCallIndex = new WeakMap(), _AssistantStream_currentToolCall = new WeakMap(), _AssistantStream_currentEvent = new WeakMap(), _AssistantStream_currentRunSnapshot = new WeakMap(), _AssistantStream_currentRunStepSnapshot = new WeakMap(), _AssistantStream_instances = new WeakSet(), Symbol.asyncIterator)]() {
7213
6611
  const pushQueue = [];
@@ -8353,12 +7751,14 @@ VectorStores.FileBatches = FileBatches;
8353
7751
  class Beta extends APIResource {
8354
7752
  constructor() {
8355
7753
  super(...arguments);
7754
+ this.realtime = new Realtime(this._client);
8356
7755
  this.vectorStores = new VectorStores(this._client);
8357
7756
  this.chat = new Chat(this._client);
8358
7757
  this.assistants = new Assistants(this._client);
8359
7758
  this.threads = new Threads(this._client);
8360
7759
  }
8361
7760
  }
7761
+ Beta.Realtime = Realtime;
8362
7762
  Beta.VectorStores = VectorStores;
8363
7763
  Beta.VectorStoresPage = VectorStoresPage;
8364
7764
  Beta.Assistants = Assistants;
@@ -8432,7 +7832,11 @@ class Files extends APIResource {
8432
7832
  * Returns the contents of the specified file.
8433
7833
  */
8434
7834
  content(fileId, options) {
8435
- return this._client.get(`/files/${fileId}/content`, { ...options, __binaryResponse: true });
7835
+ return this._client.get(`/files/${fileId}/content`, {
7836
+ ...options,
7837
+ headers: { Accept: 'application/binary', ...options?.headers },
7838
+ __binaryResponse: true,
7839
+ });
8436
7840
  }
8437
7841
  /**
8438
7842
  * Returns the contents of the specified file.
@@ -8440,10 +7844,7 @@ class Files extends APIResource {
8440
7844
  * @deprecated The `.content()` method should be used instead
8441
7845
  */
8442
7846
  retrieveContent(fileId, options) {
8443
- return this._client.get(`/files/${fileId}/content`, {
8444
- ...options,
8445
- headers: { Accept: 'application/json', ...options?.headers },
8446
- });
7847
+ return this._client.get(`/files/${fileId}/content`, options);
8447
7848
  }
8448
7849
  /**
8449
7850
  * Waits for the given file to be processed, default timeout is 30 mins.
@@ -8461,660 +7862,1698 @@ class Files extends APIResource {
8461
7862
  });
8462
7863
  }
8463
7864
  }
8464
- return file;
7865
+ return file;
7866
+ }
7867
+ }
7868
+ class FileObjectsPage extends CursorPage {
7869
+ }
7870
+ Files.FileObjectsPage = FileObjectsPage;
7871
+
7872
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7873
+ class Checkpoints extends APIResource {
7874
+ list(fineTuningJobId, query = {}, options) {
7875
+ if (isRequestOptions(query)) {
7876
+ return this.list(fineTuningJobId, {}, query);
7877
+ }
7878
+ return this._client.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/checkpoints`, FineTuningJobCheckpointsPage, { query, ...options });
7879
+ }
7880
+ }
7881
+ class FineTuningJobCheckpointsPage extends CursorPage {
7882
+ }
7883
+ Checkpoints.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage;
7884
+
7885
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7886
+ class Jobs extends APIResource {
7887
+ constructor() {
7888
+ super(...arguments);
7889
+ this.checkpoints = new Checkpoints(this._client);
7890
+ }
7891
+ /**
7892
+ * Creates a fine-tuning job which begins the process of creating a new model from
7893
+ * a given dataset.
7894
+ *
7895
+ * Response includes details of the enqueued job including job status and the name
7896
+ * of the fine-tuned models once complete.
7897
+ *
7898
+ * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning)
7899
+ */
7900
+ create(body, options) {
7901
+ return this._client.post('/fine_tuning/jobs', { body, ...options });
7902
+ }
7903
+ /**
7904
+ * Get info about a fine-tuning job.
7905
+ *
7906
+ * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning)
7907
+ */
7908
+ retrieve(fineTuningJobId, options) {
7909
+ return this._client.get(`/fine_tuning/jobs/${fineTuningJobId}`, options);
7910
+ }
7911
+ list(query = {}, options) {
7912
+ if (isRequestOptions(query)) {
7913
+ return this.list({}, query);
7914
+ }
7915
+ return this._client.getAPIList('/fine_tuning/jobs', FineTuningJobsPage, { query, ...options });
7916
+ }
7917
+ /**
7918
+ * Immediately cancel a fine-tune job.
7919
+ */
7920
+ cancel(fineTuningJobId, options) {
7921
+ return this._client.post(`/fine_tuning/jobs/${fineTuningJobId}/cancel`, options);
7922
+ }
7923
+ listEvents(fineTuningJobId, query = {}, options) {
7924
+ if (isRequestOptions(query)) {
7925
+ return this.listEvents(fineTuningJobId, {}, query);
7926
+ }
7927
+ return this._client.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/events`, FineTuningJobEventsPage, {
7928
+ query,
7929
+ ...options,
7930
+ });
7931
+ }
7932
+ }
7933
+ class FineTuningJobsPage extends CursorPage {
7934
+ }
7935
+ class FineTuningJobEventsPage extends CursorPage {
7936
+ }
7937
+ Jobs.FineTuningJobsPage = FineTuningJobsPage;
7938
+ Jobs.FineTuningJobEventsPage = FineTuningJobEventsPage;
7939
+ Jobs.Checkpoints = Checkpoints;
7940
+ Jobs.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage;
7941
+
7942
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7943
+ class FineTuning extends APIResource {
7944
+ constructor() {
7945
+ super(...arguments);
7946
+ this.jobs = new Jobs(this._client);
7947
+ }
7948
+ }
7949
+ FineTuning.Jobs = Jobs;
7950
+ FineTuning.FineTuningJobsPage = FineTuningJobsPage;
7951
+ FineTuning.FineTuningJobEventsPage = FineTuningJobEventsPage;
7952
+
7953
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7954
+ class Images extends APIResource {
7955
+ /**
7956
+ * Creates a variation of a given image.
7957
+ */
7958
+ createVariation(body, options) {
7959
+ return this._client.post('/images/variations', multipartFormRequestOptions({ body, ...options }));
7960
+ }
7961
+ /**
7962
+ * Creates an edited or extended image given an original image and a prompt.
7963
+ */
7964
+ edit(body, options) {
7965
+ return this._client.post('/images/edits', multipartFormRequestOptions({ body, ...options }));
7966
+ }
7967
+ /**
7968
+ * Creates an image given a prompt.
7969
+ */
7970
+ generate(body, options) {
7971
+ return this._client.post('/images/generations', { body, ...options });
7972
+ }
7973
+ }
7974
+
7975
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7976
+ class Models extends APIResource {
7977
+ /**
7978
+ * Retrieves a model instance, providing basic information about the model such as
7979
+ * the owner and permissioning.
7980
+ */
7981
+ retrieve(model, options) {
7982
+ return this._client.get(`/models/${model}`, options);
7983
+ }
7984
+ /**
7985
+ * Lists the currently available models, and provides basic information about each
7986
+ * one such as the owner and availability.
7987
+ */
7988
+ list(options) {
7989
+ return this._client.getAPIList('/models', ModelsPage, options);
7990
+ }
7991
+ /**
7992
+ * Delete a fine-tuned model. You must have the Owner role in your organization to
7993
+ * delete a model.
7994
+ */
7995
+ del(model, options) {
7996
+ return this._client.delete(`/models/${model}`, options);
7997
+ }
7998
+ }
7999
+ /**
8000
+ * Note: no pagination actually occurs yet, this is for forwards-compatibility.
8001
+ */
8002
+ class ModelsPage extends Page {
8003
+ }
8004
+ Models.ModelsPage = ModelsPage;
8005
+
8006
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8007
+ class Moderations extends APIResource {
8008
+ /**
8009
+ * Classifies if text and/or image inputs are potentially harmful. Learn more in
8010
+ * the [moderation guide](https://platform.openai.com/docs/guides/moderation).
8011
+ */
8012
+ create(body, options) {
8013
+ return this._client.post('/moderations', { body, ...options });
8014
+ }
8015
+ }
8016
+
8017
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8018
+ class Parts extends APIResource {
8019
+ /**
8020
+ * Adds a
8021
+ * [Part](https://platform.openai.com/docs/api-reference/uploads/part-object) to an
8022
+ * [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object.
8023
+ * A Part represents a chunk of bytes from the file you are trying to upload.
8024
+ *
8025
+ * Each Part can be at most 64 MB, and you can add Parts until you hit the Upload
8026
+ * maximum of 8 GB.
8027
+ *
8028
+ * It is possible to add multiple Parts in parallel. You can decide the intended
8029
+ * order of the Parts when you
8030
+ * [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete).
8031
+ */
8032
+ create(uploadId, body, options) {
8033
+ return this._client.post(`/uploads/${uploadId}/parts`, multipartFormRequestOptions({ body, ...options }));
8034
+ }
8035
+ }
8036
+
8037
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8038
+ class Uploads extends APIResource {
8039
+ constructor() {
8040
+ super(...arguments);
8041
+ this.parts = new Parts(this._client);
8042
+ }
8043
+ /**
8044
+ * Creates an intermediate
8045
+ * [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object
8046
+ * that you can add
8047
+ * [Parts](https://platform.openai.com/docs/api-reference/uploads/part-object) to.
8048
+ * Currently, an Upload can accept at most 8 GB in total and expires after an hour
8049
+ * after you create it.
8050
+ *
8051
+ * Once you complete the Upload, we will create a
8052
+ * [File](https://platform.openai.com/docs/api-reference/files/object) object that
8053
+ * contains all the parts you uploaded. This File is usable in the rest of our
8054
+ * platform as a regular File object.
8055
+ *
8056
+ * For certain `purpose`s, the correct `mime_type` must be specified. Please refer
8057
+ * to documentation for the supported MIME types for your use case:
8058
+ *
8059
+ * - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search#supported-files)
8060
+ *
8061
+ * For guidance on the proper filename extensions for each purpose, please follow
8062
+ * the documentation on
8063
+ * [creating a File](https://platform.openai.com/docs/api-reference/files/create).
8064
+ */
8065
+ create(body, options) {
8066
+ return this._client.post('/uploads', { body, ...options });
8067
+ }
8068
+ /**
8069
+ * Cancels the Upload. No Parts may be added after an Upload is cancelled.
8070
+ */
8071
+ cancel(uploadId, options) {
8072
+ return this._client.post(`/uploads/${uploadId}/cancel`, options);
8073
+ }
8074
+ /**
8075
+ * Completes the
8076
+ * [Upload](https://platform.openai.com/docs/api-reference/uploads/object).
8077
+ *
8078
+ * Within the returned Upload object, there is a nested
8079
+ * [File](https://platform.openai.com/docs/api-reference/files/object) object that
8080
+ * is ready to use in the rest of the platform.
8081
+ *
8082
+ * You can specify the order of the Parts by passing in an ordered list of the Part
8083
+ * IDs.
8084
+ *
8085
+ * The number of bytes uploaded upon completion must match the number of bytes
8086
+ * initially specified when creating the Upload object. No Parts may be added after
8087
+ * an Upload is completed.
8088
+ */
8089
+ complete(uploadId, body, options) {
8090
+ return this._client.post(`/uploads/${uploadId}/complete`, { body, ...options });
8091
+ }
8092
+ }
8093
+ Uploads.Parts = Parts;
8094
+
8095
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8096
+ var _a;
8097
+ /**
8098
+ * API Client for interfacing with the OpenAI API.
8099
+ */
8100
+ class OpenAI extends APIClient {
8101
+ /**
8102
+ * API Client for interfacing with the OpenAI API.
8103
+ *
8104
+ * @param {string | undefined} [opts.apiKey=process.env['OPENAI_API_KEY'] ?? undefined]
8105
+ * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null]
8106
+ * @param {string | null | undefined} [opts.project=process.env['OPENAI_PROJECT_ID'] ?? null]
8107
+ * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL'] ?? https://api.openai.com/v1] - Override the default base URL for the API.
8108
+ * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
8109
+ * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.
8110
+ * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
8111
+ * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
8112
+ * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.
8113
+ * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.
8114
+ * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.
8115
+ */
8116
+ constructor({ baseURL = readEnv('OPENAI_BASE_URL'), apiKey = readEnv('OPENAI_API_KEY'), organization = readEnv('OPENAI_ORG_ID') ?? null, project = readEnv('OPENAI_PROJECT_ID') ?? null, ...opts } = {}) {
8117
+ if (apiKey === undefined) {
8118
+ throw new OpenAIError("The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'My API Key' }).");
8119
+ }
8120
+ const options = {
8121
+ apiKey,
8122
+ organization,
8123
+ project,
8124
+ ...opts,
8125
+ baseURL: baseURL || `https://api.openai.com/v1`,
8126
+ };
8127
+ if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {
8128
+ throw new OpenAIError("It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n");
8129
+ }
8130
+ super({
8131
+ baseURL: options.baseURL,
8132
+ timeout: options.timeout ?? 600000 /* 10 minutes */,
8133
+ httpAgent: options.httpAgent,
8134
+ maxRetries: options.maxRetries,
8135
+ fetch: options.fetch,
8136
+ });
8137
+ this.completions = new Completions(this);
8138
+ this.chat = new Chat$1(this);
8139
+ this.embeddings = new Embeddings(this);
8140
+ this.files = new Files(this);
8141
+ this.images = new Images(this);
8142
+ this.audio = new Audio(this);
8143
+ this.moderations = new Moderations(this);
8144
+ this.models = new Models(this);
8145
+ this.fineTuning = new FineTuning(this);
8146
+ this.beta = new Beta(this);
8147
+ this.batches = new Batches(this);
8148
+ this.uploads = new Uploads(this);
8149
+ this._options = options;
8150
+ this.apiKey = apiKey;
8151
+ this.organization = organization;
8152
+ this.project = project;
8153
+ }
8154
+ defaultQuery() {
8155
+ return this._options.defaultQuery;
8156
+ }
8157
+ defaultHeaders(opts) {
8158
+ return {
8159
+ ...super.defaultHeaders(opts),
8160
+ 'OpenAI-Organization': this.organization,
8161
+ 'OpenAI-Project': this.project,
8162
+ ...this._options.defaultHeaders,
8163
+ };
8164
+ }
8165
+ authHeaders(opts) {
8166
+ return { Authorization: `Bearer ${this.apiKey}` };
8167
+ }
8168
+ stringifyQuery(query) {
8169
+ return stringify(query, { arrayFormat: 'brackets' });
8170
+ }
8171
+ }
8172
+ _a = OpenAI;
8173
+ OpenAI.OpenAI = _a;
8174
+ OpenAI.DEFAULT_TIMEOUT = 600000; // 10 minutes
8175
+ OpenAI.OpenAIError = OpenAIError;
8176
+ OpenAI.APIError = APIError;
8177
+ OpenAI.APIConnectionError = APIConnectionError;
8178
+ OpenAI.APIConnectionTimeoutError = APIConnectionTimeoutError;
8179
+ OpenAI.APIUserAbortError = APIUserAbortError;
8180
+ OpenAI.NotFoundError = NotFoundError;
8181
+ OpenAI.ConflictError = ConflictError;
8182
+ OpenAI.RateLimitError = RateLimitError;
8183
+ OpenAI.BadRequestError = BadRequestError;
8184
+ OpenAI.AuthenticationError = AuthenticationError;
8185
+ OpenAI.InternalServerError = InternalServerError;
8186
+ OpenAI.PermissionDeniedError = PermissionDeniedError;
8187
+ OpenAI.UnprocessableEntityError = UnprocessableEntityError;
8188
+ OpenAI.toFile = toFile;
8189
+ OpenAI.fileFromPath = fileFromPath;
8190
+ OpenAI.Completions = Completions;
8191
+ OpenAI.Chat = Chat$1;
8192
+ OpenAI.Embeddings = Embeddings;
8193
+ OpenAI.Files = Files;
8194
+ OpenAI.FileObjectsPage = FileObjectsPage;
8195
+ OpenAI.Images = Images;
8196
+ OpenAI.Audio = Audio;
8197
+ OpenAI.Moderations = Moderations;
8198
+ OpenAI.Models = Models;
8199
+ OpenAI.ModelsPage = ModelsPage;
8200
+ OpenAI.FineTuning = FineTuning;
8201
+ OpenAI.Beta = Beta;
8202
+ OpenAI.Batches = Batches;
8203
+ OpenAI.BatchesPage = BatchesPage;
8204
+ OpenAI.Uploads = Uploads;
8205
+
8206
+ class OpenaiProvider {
8207
+ constructor(param, defaultModel, options) {
8208
+ this.defaultModel = 'gpt-4o';
8209
+ if (defaultModel) {
8210
+ this.defaultModel = defaultModel;
8211
+ }
8212
+ if (typeof window !== 'undefined' &&
8213
+ typeof document !== 'undefined' &&
8214
+ (typeof param == 'string' || param.apiKey)) {
8215
+ console.warn(`
8216
+ ⚠️ Security Warning:
8217
+ DO NOT use API Keys in browser/frontend code!
8218
+ This will expose your credentials and may lead to unauthorized usage.
8219
+
8220
+ Best Practices: Configure backend API proxy request through baseURL and request headers.
8221
+
8222
+ Please refer to the link: https://eko.fellou.ai/docs/getting-started/configuration#web-environment
8223
+ `);
8224
+ }
8225
+ if (typeof param == 'string') {
8226
+ this.client = new OpenAI({
8227
+ apiKey: param,
8228
+ dangerouslyAllowBrowser: true,
8229
+ ...options,
8230
+ });
8231
+ }
8232
+ else if (param.chat && param.chat.completions) {
8233
+ this.client = param;
8234
+ }
8235
+ else {
8236
+ let options = param;
8237
+ options.dangerouslyAllowBrowser = true;
8238
+ this.client = new OpenAI(options);
8239
+ }
8240
+ }
8241
+ buildParams(messages, params, stream) {
8242
+ let tools = undefined;
8243
+ if (params.tools && params.tools.length > 0) {
8244
+ tools = [];
8245
+ for (let i = 0; i < params.tools.length; i++) {
8246
+ let tool = params.tools[i];
8247
+ tools.push({
8248
+ type: 'function',
8249
+ function: {
8250
+ name: tool.name,
8251
+ description: tool.description,
8252
+ parameters: tool.input_schema,
8253
+ },
8254
+ });
8255
+ }
8256
+ }
8257
+ let tool_choice = undefined;
8258
+ if (params.toolChoice) {
8259
+ if (params.toolChoice.type == 'auto') {
8260
+ tool_choice = 'auto';
8261
+ }
8262
+ else if (params.toolChoice.type == 'tool') {
8263
+ if (params.toolChoice.name) {
8264
+ tool_choice = {
8265
+ type: 'function',
8266
+ function: { name: params.toolChoice.name },
8267
+ };
8268
+ }
8269
+ else {
8270
+ tool_choice = 'required';
8271
+ }
8272
+ }
8273
+ }
8274
+ let _messages = [];
8275
+ for (let i = 0; i < messages.length; i++) {
8276
+ let message = messages[i];
8277
+ if (message.role == 'assistant' && typeof message.content !== 'string') {
8278
+ let _content = undefined;
8279
+ let _tool_calls = undefined;
8280
+ for (let j = 0; j < message.content.length; j++) {
8281
+ let content = message.content[j];
8282
+ if (content.type == 'text') {
8283
+ if (!_content) {
8284
+ _content = [];
8285
+ }
8286
+ _content.push(content);
8287
+ }
8288
+ else if (content.type == 'tool_use') {
8289
+ if (!_tool_calls) {
8290
+ _tool_calls = [];
8291
+ }
8292
+ _tool_calls.push({
8293
+ id: content.id,
8294
+ type: 'function',
8295
+ function: {
8296
+ name: content.name,
8297
+ arguments: typeof content.input == 'string' ? content.input : JSON.stringify(content.input),
8298
+ },
8299
+ });
8300
+ }
8301
+ }
8302
+ _messages.push({
8303
+ role: 'assistant',
8304
+ content: _content,
8305
+ tool_calls: _tool_calls,
8306
+ });
8307
+ }
8308
+ else if (message.role == 'user' && typeof message.content !== 'string') {
8309
+ for (let j = 0; j < message.content.length; j++) {
8310
+ let content = message.content[j];
8311
+ if (content.type == 'text') {
8312
+ _messages.push({
8313
+ role: 'user',
8314
+ content: content.text,
8315
+ });
8316
+ }
8317
+ else if (content.type == 'image') {
8318
+ _messages.push({
8319
+ role: 'user',
8320
+ content: [
8321
+ {
8322
+ type: 'image_url',
8323
+ image_url: {
8324
+ url: `data:${content.source.media_type};base64,${content.source.data}`,
8325
+ },
8326
+ },
8327
+ ],
8328
+ });
8329
+ }
8330
+ else if (content.type == 'tool_result') {
8331
+ let _content = [];
8332
+ if (content.content == 'string') {
8333
+ _content.push({ type: 'text', text: content.content });
8334
+ }
8335
+ else {
8336
+ for (let k = 0; k < content.content.length; k++) {
8337
+ let item = content.content[k];
8338
+ if (item.type == 'text') {
8339
+ _content.push({ ...item });
8340
+ }
8341
+ else if (item.type == 'image') {
8342
+ _content.push({
8343
+ type: 'image_url',
8344
+ image_url: {
8345
+ url: `data:${item.source.media_type};base64,${item.source.data}`,
8346
+ },
8347
+ });
8348
+ }
8349
+ }
8350
+ }
8351
+ let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
8352
+ if (hasImage) {
8353
+ // OpenAI does not support images returned by the tool.
8354
+ _messages.push({
8355
+ role: 'tool',
8356
+ content: 'ok',
8357
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8358
+ });
8359
+ _messages.push({
8360
+ role: 'user',
8361
+ content: _content,
8362
+ });
8363
+ }
8364
+ else {
8365
+ _messages.push({
8366
+ role: 'tool',
8367
+ content: _content,
8368
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8369
+ });
8370
+ }
8371
+ }
8372
+ }
8373
+ }
8374
+ else {
8375
+ _messages.push(message);
8376
+ }
8377
+ }
8378
+ return {
8379
+ stream: stream,
8380
+ model: params.model || this.defaultModel,
8381
+ max_tokens: params.maxTokens || 8192,
8382
+ temperature: params.temperature,
8383
+ messages: _messages,
8384
+ tools: tools,
8385
+ tool_choice: tool_choice,
8386
+ };
8387
+ }
8388
+ async generateText(messages, params) {
8389
+ const response = await this.client.chat.completions.create(this.buildParams(messages, params, false));
8390
+ let textContent = null;
8391
+ let toolCalls = [];
8392
+ let stop_reason = null;
8393
+ for (let i = 0; i < response.choices.length; i++) {
8394
+ let choice = response.choices[i];
8395
+ let message = choice.message;
8396
+ if (message.content) {
8397
+ if (textContent == null) {
8398
+ textContent = '';
8399
+ }
8400
+ textContent += message.content;
8401
+ }
8402
+ if (message.tool_calls) {
8403
+ for (let j = 0; j < message.tool_calls.length; j++) {
8404
+ let tool_call = message.tool_calls[j];
8405
+ toolCalls.push({
8406
+ id: tool_call.id,
8407
+ name: tool_call.function.name,
8408
+ input: JSON.parse(tool_call.function.arguments),
8409
+ });
8410
+ }
8411
+ }
8412
+ if (choice.finish_reason) {
8413
+ stop_reason = choice.finish_reason;
8414
+ }
8415
+ }
8416
+ let content = [];
8417
+ if (textContent) {
8418
+ content.push({
8419
+ type: 'text',
8420
+ text: textContent,
8421
+ });
8422
+ }
8423
+ if (toolCalls.length > 0) {
8424
+ for (let i = 0; i < toolCalls.length; i++) {
8425
+ let toolCall = toolCalls[i];
8426
+ content.push({
8427
+ type: 'tool_use',
8428
+ id: toolCall.id,
8429
+ name: toolCall.name,
8430
+ input: toolCall.input,
8431
+ });
8432
+ }
8433
+ }
8434
+ return {
8435
+ textContent,
8436
+ content,
8437
+ toolCalls,
8438
+ stop_reason,
8439
+ };
8465
8440
  }
8466
- }
8467
- class FileObjectsPage extends CursorPage {
8468
- }
8469
- Files.FileObjectsPage = FileObjectsPage;
8470
-
8471
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8472
- class Checkpoints extends APIResource {
8473
- list(fineTuningJobId, query = {}, options) {
8474
- if (isRequestOptions(query)) {
8475
- return this.list(fineTuningJobId, {}, query);
8441
+ async generateStream(messages, params, handler) {
8442
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
8443
+ const stream = await this.client.chat.completions.create(this.buildParams(messages, params, true));
8444
+ (_a = handler.onStart) === null || _a === undefined ? undefined : _a.call(handler);
8445
+ let textContent = null;
8446
+ let toolCalls = [];
8447
+ let stop_reason = null;
8448
+ let currentToolUse = null;
8449
+ try {
8450
+ for await (const chunk of stream) {
8451
+ for (let i = 0; i < chunk.choices.length; i++) {
8452
+ let choice = chunk.choices[i];
8453
+ if (choice.delta) {
8454
+ if (choice.delta.content) {
8455
+ if (textContent == null) {
8456
+ textContent = '';
8457
+ }
8458
+ textContent += choice.delta.content;
8459
+ (_b = handler.onContent) === null || _b === void 0 ? void 0 : _b.call(handler, choice.delta.content);
8460
+ }
8461
+ else if (choice.delta.tool_calls && choice.delta.tool_calls.length > 0) {
8462
+ let tool_calls = choice.delta.tool_calls[0];
8463
+ if (!currentToolUse) {
8464
+ currentToolUse = {
8465
+ id: tool_calls.id || '',
8466
+ name: ((_c = tool_calls.function) === null || _c === void 0 ? void 0 : _c.name) || '',
8467
+ accumulatedJson: ((_d = tool_calls.function) === null || _d === void 0 ? void 0 : _d.arguments) || '',
8468
+ };
8469
+ }
8470
+ else {
8471
+ if (tool_calls.id) {
8472
+ currentToolUse.id = tool_calls.id;
8473
+ }
8474
+ if ((_e = tool_calls.function) === null || _e === void 0 ? void 0 : _e.name) {
8475
+ currentToolUse.name = (_f = tool_calls.function) === null || _f === void 0 ? void 0 : _f.name;
8476
+ }
8477
+ currentToolUse.accumulatedJson += ((_g = tool_calls.function) === null || _g === void 0 ? void 0 : _g.arguments) || '';
8478
+ }
8479
+ }
8480
+ }
8481
+ if (choice.finish_reason) {
8482
+ stop_reason = choice.finish_reason;
8483
+ if (currentToolUse) {
8484
+ const toolCall = {
8485
+ id: currentToolUse.id,
8486
+ name: currentToolUse.name,
8487
+ input: JSON.parse(currentToolUse.accumulatedJson),
8488
+ };
8489
+ toolCalls.push(toolCall);
8490
+ (_h = handler.onToolUse) === null || _h === void 0 ? void 0 : _h.call(handler, toolCall);
8491
+ currentToolUse = null;
8492
+ }
8493
+ }
8494
+ }
8495
+ }
8496
+ let content = [];
8497
+ if (textContent) {
8498
+ content.push({
8499
+ type: 'text',
8500
+ text: textContent,
8501
+ });
8502
+ }
8503
+ if (toolCalls && toolCalls.length > 0) {
8504
+ for (let i = 0; i < toolCalls.length; i++) {
8505
+ let toolCall = toolCalls[i];
8506
+ content.push({
8507
+ type: 'tool_use',
8508
+ id: toolCall.id,
8509
+ name: toolCall.name,
8510
+ input: toolCall.input,
8511
+ });
8512
+ }
8513
+ }
8514
+ (_j = handler.onComplete) === null || _j === void 0 ? void 0 : _j.call(handler, {
8515
+ textContent: textContent,
8516
+ content: content,
8517
+ toolCalls: toolCalls,
8518
+ stop_reason: stop_reason,
8519
+ });
8520
+ }
8521
+ catch (error) {
8522
+ (_k = handler.onError) === null || _k === undefined ? undefined : _k.call(handler, error);
8476
8523
  }
8477
- return this._client.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/checkpoints`, FineTuningJobCheckpointsPage, { query, ...options });
8478
8524
  }
8479
8525
  }
8480
- class FineTuningJobCheckpointsPage extends CursorPage {
8481
- }
8482
- Checkpoints.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage;
8483
8526
 
8484
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8485
- class Jobs extends APIResource {
8486
- constructor() {
8487
- super(...arguments);
8488
- this.checkpoints = new Checkpoints(this._client);
8489
- }
8490
- /**
8491
- * Creates a fine-tuning job which begins the process of creating a new model from
8492
- * a given dataset.
8493
- *
8494
- * Response includes details of the enqueued job including job status and the name
8495
- * of the fine-tuned models once complete.
8496
- *
8497
- * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning)
8498
- */
8499
- create(body, options) {
8500
- return this._client.post('/fine_tuning/jobs', { body, ...options });
8501
- }
8502
- /**
8503
- * Get info about a fine-tuning job.
8504
- *
8505
- * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning)
8506
- */
8507
- retrieve(fineTuningJobId, options) {
8508
- return this._client.get(`/fine_tuning/jobs/${fineTuningJobId}`, options);
8509
- }
8510
- list(query = {}, options) {
8511
- if (isRequestOptions(query)) {
8512
- return this.list({}, query);
8527
+ class LLMProviderFactory {
8528
+ static buildLLMProvider(config) {
8529
+ let llmProvider;
8530
+ if (typeof config == 'string') {
8531
+ llmProvider = new ClaudeProvider(config);
8513
8532
  }
8514
- return this._client.getAPIList('/fine_tuning/jobs', FineTuningJobsPage, { query, ...options });
8515
- }
8516
- /**
8517
- * Immediately cancel a fine-tune job.
8518
- */
8519
- cancel(fineTuningJobId, options) {
8520
- return this._client.post(`/fine_tuning/jobs/${fineTuningJobId}/cancel`, options);
8521
- }
8522
- listEvents(fineTuningJobId, query = {}, options) {
8523
- if (isRequestOptions(query)) {
8524
- return this.listEvents(fineTuningJobId, {}, query);
8533
+ else if ('llm' in config) {
8534
+ if (config.llm == 'claude') {
8535
+ let claudeConfig = config;
8536
+ llmProvider = new ClaudeProvider(claudeConfig.apiKey, claudeConfig.modelName, claudeConfig.options);
8537
+ }
8538
+ else if (config.llm == 'openai') {
8539
+ let openaiConfig = config;
8540
+ llmProvider = new OpenaiProvider(openaiConfig.apiKey, openaiConfig.modelName, openaiConfig.options);
8541
+ }
8542
+ else {
8543
+ throw new Error('Unknown parameter: llm > ' + config['llm']);
8544
+ }
8525
8545
  }
8526
- return this._client.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/events`, FineTuningJobEventsPage, {
8527
- query,
8528
- ...options,
8529
- });
8530
- }
8531
- }
8532
- class FineTuningJobsPage extends CursorPage {
8533
- }
8534
- class FineTuningJobEventsPage extends CursorPage {
8535
- }
8536
- Jobs.FineTuningJobsPage = FineTuningJobsPage;
8537
- Jobs.FineTuningJobEventsPage = FineTuningJobEventsPage;
8538
- Jobs.Checkpoints = Checkpoints;
8539
- Jobs.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage;
8540
-
8541
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8542
- class FineTuning extends APIResource {
8543
- constructor() {
8544
- super(...arguments);
8545
- this.jobs = new Jobs(this._client);
8546
- }
8547
- }
8548
- FineTuning.Jobs = Jobs;
8549
- FineTuning.FineTuningJobsPage = FineTuningJobsPage;
8550
- FineTuning.FineTuningJobEventsPage = FineTuningJobEventsPage;
8551
-
8552
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8553
- class Images extends APIResource {
8554
- /**
8555
- * Creates a variation of a given image.
8556
- */
8557
- createVariation(body, options) {
8558
- return this._client.post('/images/variations', multipartFormRequestOptions({ body, ...options }));
8559
- }
8560
- /**
8561
- * Creates an edited or extended image given an original image and a prompt.
8562
- */
8563
- edit(body, options) {
8564
- return this._client.post('/images/edits', multipartFormRequestOptions({ body, ...options }));
8565
- }
8566
- /**
8567
- * Creates an image given a prompt.
8568
- */
8569
- generate(body, options) {
8570
- return this._client.post('/images/generations', { body, ...options });
8546
+ else {
8547
+ llmProvider = config;
8548
+ }
8549
+ return llmProvider;
8571
8550
  }
8572
8551
  }
8573
8552
 
8574
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8575
- class Models extends APIResource {
8576
- /**
8577
- * Retrieves a model instance, providing basic information about the model such as
8578
- * the owner and permissioning.
8579
- */
8580
- retrieve(model, options) {
8581
- return this._client.get(`/models/${model}`, options);
8553
+ /**
8554
+ * Manages logging for action execution, providing a cleaner view of the execution
8555
+ * flow while maintaining important context and history.
8556
+ */
8557
+ class ExecutionLogger {
8558
+ constructor(options = {}) {
8559
+ var _a;
8560
+ this.history = [];
8561
+ this.maxHistoryLength = options.maxHistoryLength || 10;
8562
+ this.logLevel = options.logLevel || 'info';
8563
+ this.includeTimestamp = (_a = options.includeTimestamp) !== null && _a !== undefined ? _a : true;
8564
+ this.debugImagePath = options.debugImagePath;
8565
+ this.imageSaver = options.imageSaver;
8566
+ // Check if running in Node.js environment
8567
+ this.isNode =
8568
+ typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
8582
8569
  }
8583
8570
  /**
8584
- * Lists the currently available models, and provides basic information about each
8585
- * one such as the owner and availability.
8571
+ * Logs a message with execution context
8586
8572
  */
8587
- list(options) {
8588
- return this._client.getAPIList('/models', ModelsPage, options);
8573
+ log(level, message, context) {
8574
+ if (this.shouldLog(level)) {
8575
+ const timestamp = this.includeTimestamp ? new Date().toISOString() : '';
8576
+ const contextSummary = this.summarizeContext(context);
8577
+ console.log(`${timestamp} [${level.toUpperCase()}] ${message}${contextSummary}`);
8578
+ }
8589
8579
  }
8590
8580
  /**
8591
- * Delete a fine-tuned model. You must have the Owner role in your organization to
8592
- * delete a model.
8581
+ * Updates conversation history while maintaining size limit
8593
8582
  */
8594
- del(model, options) {
8595
- return this._client.delete(`/models/${model}`, options);
8583
+ updateHistory(messages) {
8584
+ // Keep system messages and last N messages
8585
+ const systemMessages = messages.filter((m) => m.role === 'system');
8586
+ const nonSystemMessages = messages.filter((m) => m.role !== 'system');
8587
+ const recentMessages = nonSystemMessages.slice(-this.maxHistoryLength);
8588
+ this.history = [...systemMessages, ...recentMessages];
8596
8589
  }
8597
- }
8598
- /**
8599
- * Note: no pagination actually occurs yet, this is for forwards-compatibility.
8600
- */
8601
- class ModelsPage extends Page {
8602
- }
8603
- Models.ModelsPage = ModelsPage;
8604
-
8605
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8606
- class Moderations extends APIResource {
8607
8590
  /**
8608
- * Classifies if text and/or image inputs are potentially harmful. Learn more in
8609
- * the [moderation guide](https://platform.openai.com/docs/guides/moderation).
8591
+ * Gets current conversation history
8610
8592
  */
8611
- create(body, options) {
8612
- return this._client.post('/moderations', { body, ...options });
8593
+ getHistory() {
8594
+ return this.history;
8613
8595
  }
8614
- }
8615
-
8616
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8617
- class Parts extends APIResource {
8618
- /**
8619
- * Adds a
8620
- * [Part](https://platform.openai.com/docs/api-reference/uploads/part-object) to an
8621
- * [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object.
8622
- * A Part represents a chunk of bytes from the file you are trying to upload.
8623
- *
8624
- * Each Part can be at most 64 MB, and you can add Parts until you hit the Upload
8625
- * maximum of 8 GB.
8626
- *
8627
- * It is possible to add multiple Parts in parallel. You can decide the intended
8628
- * order of the Parts when you
8629
- * [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete).
8596
+ /**
8597
+ * Summarizes the execution context for logging
8630
8598
  */
8631
- create(uploadId, body, options) {
8632
- return this._client.post(`/uploads/${uploadId}/parts`, multipartFormRequestOptions({ body, ...options }));
8599
+ summarizeContext(context) {
8600
+ if (!context)
8601
+ return '';
8602
+ const summary = {
8603
+ variables: Object.fromEntries(context.variables),
8604
+ tools: context.tools ? Array.from(context.tools.keys()) : [],
8605
+ };
8606
+ return `\nContext: ${JSON.stringify(summary, null, 2)}`;
8633
8607
  }
8634
- }
8635
-
8636
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8637
- class Uploads extends APIResource {
8638
- constructor() {
8639
- super(...arguments);
8640
- this.parts = new Parts(this._client);
8608
+ /**
8609
+ * Checks if message should be logged based on log level
8610
+ */
8611
+ shouldLog(level) {
8612
+ const levels = {
8613
+ error: 0,
8614
+ warn: 1,
8615
+ info: 2,
8616
+ debug: 3,
8617
+ };
8618
+ return levels[level] <= levels[this.logLevel];
8641
8619
  }
8642
8620
  /**
8643
- * Creates an intermediate
8644
- * [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object
8645
- * that you can add
8646
- * [Parts](https://platform.openai.com/docs/api-reference/uploads/part-object) to.
8647
- * Currently, an Upload can accept at most 8 GB in total and expires after an hour
8648
- * after you create it.
8649
- *
8650
- * Once you complete the Upload, we will create a
8651
- * [File](https://platform.openai.com/docs/api-reference/files/object) object that
8652
- * contains all the parts you uploaded. This File is usable in the rest of our
8653
- * platform as a regular File object.
8654
- *
8655
- * For certain `purpose`s, the correct `mime_type` must be specified. Please refer
8656
- * to documentation for the supported MIME types for your use case:
8657
- *
8658
- * - [Assistants](https://platform.openai.com/docs/assistants/tools/file-search#supported-files)
8659
- *
8660
- * For guidance on the proper filename extensions for each purpose, please follow
8661
- * the documentation on
8662
- * [creating a File](https://platform.openai.com/docs/api-reference/files/create).
8621
+ * Logs the start of an action execution
8663
8622
  */
8664
- create(body, options) {
8665
- return this._client.post('/uploads', { body, ...options });
8623
+ logActionStart(actionName, input, context) {
8624
+ this.log('info', `Starting action: ${actionName}`, context);
8625
+ this.log('info', `Input: ${JSON.stringify(input, null, 2)}`);
8666
8626
  }
8667
8627
  /**
8668
- * Cancels the Upload. No Parts may be added after an Upload is cancelled.
8628
+ * Logs the completion of an action execution
8669
8629
  */
8670
- cancel(uploadId, options) {
8671
- return this._client.post(`/uploads/${uploadId}/cancel`, options);
8630
+ logActionComplete(actionName, result, context) {
8631
+ this.log('info', `Completed action: ${actionName}`, context);
8632
+ this.log('info', `Result: ${JSON.stringify(result, null, 2)}`);
8672
8633
  }
8673
8634
  /**
8674
- * Completes the
8675
- * [Upload](https://platform.openai.com/docs/api-reference/uploads/object).
8676
- *
8677
- * Within the returned Upload object, there is a nested
8678
- * [File](https://platform.openai.com/docs/api-reference/files/object) object that
8679
- * is ready to use in the rest of the platform.
8680
- *
8681
- * You can specify the order of the Parts by passing in an ordered list of the Part
8682
- * IDs.
8683
- *
8684
- * The number of bytes uploaded upon completion must match the number of bytes
8685
- * initially specified when creating the Upload object. No Parts may be added after
8686
- * an Upload is completed.
8635
+ * Logs a tool execution
8687
8636
  */
8688
- complete(uploadId, body, options) {
8689
- return this._client.post(`/uploads/${uploadId}/complete`, { body, ...options });
8637
+ logToolExecution(toolName, input, context) {
8638
+ this.log('info', `Executing tool: ${toolName}`);
8639
+ this.log('info', `Tool input: ${JSON.stringify(input, null, 2)}`);
8690
8640
  }
8691
- }
8692
- Uploads.Parts = Parts;
8693
-
8694
- // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8695
- var _a;
8696
- /**
8697
- * API Client for interfacing with the OpenAI API.
8698
- */
8699
- class OpenAI extends APIClient {
8700
8641
  /**
8701
- * API Client for interfacing with the OpenAI API.
8702
- *
8703
- * @param {string | undefined} [opts.apiKey=process.env['OPENAI_API_KEY'] ?? undefined]
8704
- * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null]
8705
- * @param {string | null | undefined} [opts.project=process.env['OPENAI_PROJECT_ID'] ?? null]
8706
- * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL'] ?? https://api.openai.com/v1] - Override the default base URL for the API.
8707
- * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
8708
- * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.
8709
- * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
8710
- * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
8711
- * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.
8712
- * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.
8713
- * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.
8642
+ * Logs an error that occurred during execution
8714
8643
  */
8715
- constructor({ baseURL = readEnv('OPENAI_BASE_URL'), apiKey = readEnv('OPENAI_API_KEY'), organization = readEnv('OPENAI_ORG_ID') ?? null, project = readEnv('OPENAI_PROJECT_ID') ?? null, ...opts } = {}) {
8716
- if (apiKey === undefined) {
8717
- throw new OpenAIError("The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'My API Key' }).");
8644
+ logError(error, context) {
8645
+ console.error(error);
8646
+ try {
8647
+ this.log('error', `Error occurred: ${error.message}`, context);
8648
+ if (error.stack) {
8649
+ this.log('debug', `Stack trace: ${error.stack}`);
8650
+ }
8718
8651
  }
8719
- const options = {
8720
- apiKey,
8721
- organization,
8722
- project,
8723
- ...opts,
8724
- baseURL: baseURL || `https://api.openai.com/v1`,
8725
- };
8726
- if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {
8727
- throw new OpenAIError("It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n");
8652
+ catch (error) {
8653
+ console.error("An error occurs when trying to log another error:");
8654
+ console.error(error);
8728
8655
  }
8729
- super({
8730
- baseURL: options.baseURL,
8731
- timeout: options.timeout ?? 600000 /* 10 minutes */,
8732
- httpAgent: options.httpAgent,
8733
- maxRetries: options.maxRetries,
8734
- fetch: options.fetch,
8735
- });
8736
- this.completions = new Completions(this);
8737
- this.chat = new Chat$1(this);
8738
- this.embeddings = new Embeddings(this);
8739
- this.files = new Files(this);
8740
- this.images = new Images(this);
8741
- this.audio = new Audio(this);
8742
- this.moderations = new Moderations(this);
8743
- this.models = new Models(this);
8744
- this.fineTuning = new FineTuning(this);
8745
- this.beta = new Beta(this);
8746
- this.batches = new Batches(this);
8747
- this.uploads = new Uploads(this);
8748
- this._options = options;
8749
- this.apiKey = apiKey;
8750
- this.organization = organization;
8751
- this.project = project;
8752
- }
8753
- defaultQuery() {
8754
- return this._options.defaultQuery;
8755
8656
  }
8756
- defaultHeaders(opts) {
8657
+ extractFromDataUrl(dataUrl) {
8658
+ const matches = dataUrl.match(/^data:image\/([a-zA-Z0-9]+);base64,(.+)$/);
8659
+ if (!matches) {
8660
+ throw new Error('Invalid data URL format');
8661
+ }
8757
8662
  return {
8758
- ...super.defaultHeaders(opts),
8759
- 'OpenAI-Organization': this.organization,
8760
- 'OpenAI-Project': this.project,
8761
- ...this._options.defaultHeaders,
8663
+ extension: matches[1],
8664
+ base64Data: matches[2],
8762
8665
  };
8763
8666
  }
8764
- authHeaders(opts) {
8765
- return { Authorization: `Bearer ${this.apiKey}` };
8667
+ async saveDebugImage(imageData, toolName) {
8668
+ try {
8669
+ let extension;
8670
+ let base64Data;
8671
+ // Handle both data URL strings and ImageData objects
8672
+ if (typeof imageData === 'string' && imageData.startsWith('data:')) {
8673
+ const extracted = this.extractFromDataUrl(imageData);
8674
+ extension = extracted.extension;
8675
+ base64Data = extracted.base64Data;
8676
+ }
8677
+ else if (typeof imageData === 'object' && 'type' in imageData) {
8678
+ extension = imageData.media_type.split('/')[1] || 'png';
8679
+ base64Data = imageData.data;
8680
+ }
8681
+ else {
8682
+ return '[image]';
8683
+ }
8684
+ // If custom image saver is provided, use it
8685
+ if (this.imageSaver) {
8686
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
8687
+ const filename = `${toolName}_${timestamp}.${extension}`;
8688
+ return await this.imageSaver({ type: 'base64', media_type: `image/${extension}`, data: base64Data }, filename);
8689
+ }
8690
+ // If in Node.js environment and debugImagePath is set
8691
+ if (this.isNode && this.debugImagePath) {
8692
+ // Dynamically import Node.js modules only when needed
8693
+ const { promises: fs } = await import('fs');
8694
+ const { join } = await import('path');
8695
+ await fs.mkdir(this.debugImagePath, { recursive: true });
8696
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
8697
+ const filename = `${toolName}_${timestamp}.${extension}`;
8698
+ const filepath = join(this.debugImagePath, filename);
8699
+ const buffer = Buffer.from(base64Data, 'base64');
8700
+ await fs.writeFile(filepath, buffer);
8701
+ return `[image saved to: ${filepath}]`;
8702
+ }
8703
+ // Default case - just return placeholder
8704
+ return '[image]';
8705
+ }
8706
+ catch (error) {
8707
+ console.warn('Failed to save debug image:', error);
8708
+ return '[image]';
8709
+ }
8710
+ }
8711
+ async formatToolResult(result) {
8712
+ // Handle null/undefined
8713
+ if (result == null) {
8714
+ return 'null';
8715
+ }
8716
+ // Handle direct image result
8717
+ if (result.image) {
8718
+ const imagePlaceholder = await this.saveDebugImage(result.image, 'tool');
8719
+ const modifiedResult = { ...result, image: imagePlaceholder };
8720
+ return JSON.stringify(modifiedResult);
8721
+ }
8722
+ // Handle nested images in result object
8723
+ if (typeof result === 'object') {
8724
+ const formatted = { ...result };
8725
+ for (const [key, value] of Object.entries(formatted)) {
8726
+ if (value && typeof value === 'string' && value.startsWith('data:image/')) {
8727
+ formatted[key] = await this.saveDebugImage(value, key);
8728
+ }
8729
+ else if (value &&
8730
+ typeof value === 'object' &&
8731
+ 'type' in value &&
8732
+ value.type === 'base64') {
8733
+ formatted[key] = await this.saveDebugImage(value, key);
8734
+ }
8735
+ }
8736
+ return JSON.stringify(formatted);
8737
+ }
8738
+ // Handle primitive values
8739
+ return String(result);
8766
8740
  }
8767
- stringifyQuery(query) {
8768
- return stringify(query, { arrayFormat: 'brackets' });
8741
+ async logToolResult(toolName, result, context) {
8742
+ if (this.shouldLog('info')) {
8743
+ const timestamp = this.includeTimestamp ? new Date().toISOString() : '';
8744
+ const contextSummary = this.summarizeContext(context);
8745
+ const formattedResult = await this.formatToolResult(result);
8746
+ console.log(`${timestamp} [INFO] Tool executed: ${toolName}\n` +
8747
+ `${timestamp} [INFO] Tool result: ${formattedResult}${contextSummary}`);
8748
+ }
8769
8749
  }
8770
8750
  }
8771
- _a = OpenAI;
8772
- OpenAI.OpenAI = _a;
8773
- OpenAI.DEFAULT_TIMEOUT = 600000; // 10 minutes
8774
- OpenAI.OpenAIError = OpenAIError;
8775
- OpenAI.APIError = APIError;
8776
- OpenAI.APIConnectionError = APIConnectionError;
8777
- OpenAI.APIConnectionTimeoutError = APIConnectionTimeoutError;
8778
- OpenAI.APIUserAbortError = APIUserAbortError;
8779
- OpenAI.NotFoundError = NotFoundError;
8780
- OpenAI.ConflictError = ConflictError;
8781
- OpenAI.RateLimitError = RateLimitError;
8782
- OpenAI.BadRequestError = BadRequestError;
8783
- OpenAI.AuthenticationError = AuthenticationError;
8784
- OpenAI.InternalServerError = InternalServerError;
8785
- OpenAI.PermissionDeniedError = PermissionDeniedError;
8786
- OpenAI.UnprocessableEntityError = UnprocessableEntityError;
8787
- OpenAI.toFile = toFile;
8788
- OpenAI.fileFromPath = fileFromPath;
8789
- OpenAI.Completions = Completions;
8790
- OpenAI.Chat = Chat$1;
8791
- OpenAI.Embeddings = Embeddings;
8792
- OpenAI.Files = Files;
8793
- OpenAI.FileObjectsPage = FileObjectsPage;
8794
- OpenAI.Images = Images;
8795
- OpenAI.Audio = Audio;
8796
- OpenAI.Moderations = Moderations;
8797
- OpenAI.Models = Models;
8798
- OpenAI.ModelsPage = ModelsPage;
8799
- OpenAI.FineTuning = FineTuning;
8800
- OpenAI.Beta = Beta;
8801
- OpenAI.Batches = Batches;
8802
- OpenAI.BatchesPage = BatchesPage;
8803
- OpenAI.Uploads = Uploads;
8804
8751
 
8805
- class OpenaiProvider {
8806
- constructor(param, defaultModel, options) {
8807
- this.defaultModel = 'gpt-4o';
8808
- if (defaultModel) {
8809
- this.defaultModel = defaultModel;
8752
+ class WorkflowImpl {
8753
+ constructor(id, name, description, nodes = [], variables = new Map(), llmProvider, loggerOptions) {
8754
+ this.id = id;
8755
+ this.name = name;
8756
+ this.description = description;
8757
+ this.nodes = nodes;
8758
+ this.variables = variables;
8759
+ this.llmProvider = llmProvider;
8760
+ this.abortControllers = new Map();
8761
+ if (loggerOptions) {
8762
+ this.logger = new ExecutionLogger(loggerOptions);
8810
8763
  }
8811
- if (typeof window !== 'undefined' &&
8812
- typeof document !== 'undefined' &&
8813
- (typeof param == 'string' || param.apiKey)) {
8814
- console.warn(`
8815
- ⚠️ Security Warning:
8816
- DO NOT use API Keys in browser/frontend code!
8817
- This will expose your credentials and may lead to unauthorized usage.
8818
-
8819
- Best Practices: Configure backend API proxy request through baseURL and request headers.
8820
-
8821
- Please refer to the link: https://eko.fellou.ai/docs/getting-started/configuration#web-environment
8822
- `);
8764
+ }
8765
+ setLogger(logger) {
8766
+ this.logger = logger;
8767
+ }
8768
+ async cancel() {
8769
+ this.abort = true;
8770
+ for (const controller of this.abortControllers.values()) {
8771
+ controller.abort("Workflow cancelled");
8772
+ }
8773
+ }
8774
+ async execute(callback) {
8775
+ var _a, _b, _c, _d;
8776
+ if (!this.validateDAG()) {
8777
+ throw new Error("Invalid workflow: Contains circular dependencies");
8778
+ }
8779
+ this.abort = false;
8780
+ callback && await ((_b = (_a = callback.hooks).beforeWorkflow) === null || _b === undefined ? undefined : _b.call(_a, this));
8781
+ const executed = new Set();
8782
+ const executing = new Set();
8783
+ const executeNode = async (nodeId) => {
8784
+ var _a, _b, _c, _d, _e;
8785
+ if (this.abort) {
8786
+ throw new Error("Abort");
8787
+ }
8788
+ if (executed.has(nodeId)) {
8789
+ return;
8790
+ }
8791
+ if (executing.has(nodeId)) {
8792
+ throw new Error(`Circular dependency detected at node: ${nodeId}`);
8793
+ }
8794
+ const node = this.getNode(nodeId);
8795
+ const abortController = new AbortController();
8796
+ this.abortControllers.set(nodeId, abortController);
8797
+ // Execute the node's action
8798
+ const context = {
8799
+ __skip: false,
8800
+ __abort: false,
8801
+ workflow: this,
8802
+ variables: this.variables,
8803
+ llmProvider: this.llmProvider,
8804
+ tools: new Map(node.action.tools.map(tool => [tool.name, tool])),
8805
+ callback,
8806
+ logger: this.logger,
8807
+ next: () => context.__skip = true,
8808
+ abortAll: () => {
8809
+ this.abort = context.__abort = true;
8810
+ // Abort all running tasks
8811
+ for (const controller of this.abortControllers.values()) {
8812
+ controller.abort("Workflow cancelled");
8813
+ }
8814
+ },
8815
+ signal: abortController.signal
8816
+ };
8817
+ executing.add(nodeId);
8818
+ // Execute dependencies first
8819
+ for (const depId of node.dependencies) {
8820
+ await executeNode(depId);
8821
+ }
8822
+ // Prepare input by gathering outputs from dependencies
8823
+ const input = { items: [] };
8824
+ for (const depId of node.dependencies) {
8825
+ const depNode = this.getNode(depId);
8826
+ input.items.push(depNode.output);
8827
+ }
8828
+ node.input = input;
8829
+ // Run pre-execution hooks and execute action
8830
+ callback && await ((_b = (_a = callback.hooks).beforeSubtask) === null || _b === undefined ? undefined : _b.call(_a, node, context));
8831
+ if (context.__abort) {
8832
+ throw new Error("Abort");
8833
+ }
8834
+ else if (context.__skip) {
8835
+ return;
8836
+ }
8837
+ node.output.value = await node.action.execute(node.input, node.output, context);
8838
+ executing.delete(nodeId);
8839
+ executed.add(nodeId);
8840
+ callback && await ((_d = (_c = callback.hooks).afterSubtask) === null || _d === undefined ? undefined : _d.call(_c, node, context, (_e = node.output) === null || _e === undefined ? undefined : _e.value));
8841
+ };
8842
+ // Execute all terminal nodes (nodes with no dependents)
8843
+ const terminalNodes = this.nodes.filter(node => !this.nodes.some(n => n.dependencies.includes(node.id)));
8844
+ await Promise.all(terminalNodes.map(node => executeNode(node.id)));
8845
+ callback && await ((_d = (_c = callback.hooks).afterWorkflow) === null || _d === undefined ? undefined : _d.call(_c, this, this.variables));
8846
+ return terminalNodes.map(node => node.output);
8847
+ }
8848
+ addNode(node) {
8849
+ if (this.nodes.some(n => n.id === node.id)) {
8850
+ throw new Error(`Node with id ${node.id} already exists`);
8851
+ }
8852
+ this.nodes.push(node);
8853
+ }
8854
+ removeNode(nodeId) {
8855
+ const index = this.nodes.findIndex(n => n.id === nodeId);
8856
+ if (index === -1) {
8857
+ throw new Error(`Node with id ${nodeId} not found`);
8823
8858
  }
8824
- if (typeof param == 'string') {
8825
- this.client = new OpenAI({
8826
- apiKey: param,
8827
- dangerouslyAllowBrowser: true,
8828
- ...options,
8829
- });
8859
+ // Check if any nodes depend on this one
8860
+ const dependentNodes = this.nodes.filter(n => n.dependencies.includes(nodeId));
8861
+ if (dependentNodes.length > 0) {
8862
+ throw new Error(`Cannot remove node ${nodeId}: Nodes ${dependentNodes.map(n => n.id).join(", ")} depend on it`);
8830
8863
  }
8831
- else {
8832
- this.client = new OpenAI(param);
8864
+ this.nodes.splice(index, 1);
8865
+ }
8866
+ getNode(nodeId) {
8867
+ const node = this.nodes.find(n => n.id === nodeId);
8868
+ if (!node) {
8869
+ throw new Error(`Node with id ${nodeId} not found`);
8833
8870
  }
8871
+ return node;
8834
8872
  }
8835
- buildParams(messages, params, stream) {
8836
- let tools = undefined;
8837
- if (params.tools && params.tools.length > 0) {
8838
- tools = [];
8839
- for (let i = 0; i < params.tools.length; i++) {
8840
- let tool = params.tools[i];
8841
- tools.push({
8842
- type: 'function',
8843
- function: {
8844
- name: tool.name,
8845
- description: tool.description,
8846
- parameters: tool.input_schema,
8847
- },
8848
- });
8873
+ validateDAG() {
8874
+ const visited = new Set();
8875
+ const recursionStack = new Set();
8876
+ const hasCycle = (nodeId) => {
8877
+ if (recursionStack.has(nodeId)) {
8878
+ return true;
8849
8879
  }
8850
- }
8851
- let tool_choice = undefined;
8852
- if (params.toolChoice) {
8853
- if (params.toolChoice.type == 'auto') {
8854
- tool_choice = 'auto';
8880
+ if (visited.has(nodeId)) {
8881
+ return false;
8855
8882
  }
8856
- else if (params.toolChoice.type == 'tool') {
8857
- if (params.toolChoice.name) {
8858
- tool_choice = {
8859
- type: 'function',
8860
- function: { name: params.toolChoice.name },
8861
- };
8862
- }
8863
- else {
8864
- tool_choice = 'required';
8883
+ visited.add(nodeId);
8884
+ recursionStack.add(nodeId);
8885
+ const node = this.getNode(nodeId);
8886
+ for (const depId of node.dependencies) {
8887
+ if (hasCycle(depId)) {
8888
+ return true;
8865
8889
  }
8866
8890
  }
8891
+ recursionStack.delete(nodeId);
8892
+ return false;
8893
+ };
8894
+ return !this.nodes.some(node => hasCycle(node.id));
8895
+ }
8896
+ }
8897
+
8898
+ // src/models/action.ts
8899
+ /**
8900
+ * Special tool that allows LLM to write values to context
8901
+ */
8902
+ class WriteContextTool {
8903
+ constructor() {
8904
+ this.name = 'write_context';
8905
+ this.description = 'Write a value to the global workflow context. Use this to store important intermediate results, but only when a piece of information is essential for future reference but missing from the final output specification of the current action.';
8906
+ this.input_schema = {
8907
+ type: 'object',
8908
+ properties: {
8909
+ key: {
8910
+ type: 'string',
8911
+ description: 'The key to store the value under',
8912
+ },
8913
+ value: {
8914
+ type: 'string',
8915
+ description: 'The value to store (must be JSON stringified if object/array)',
8916
+ },
8917
+ },
8918
+ required: ['key', 'value'],
8919
+ };
8920
+ }
8921
+ async execute(context, params) {
8922
+ const { key, value } = params;
8923
+ try {
8924
+ // Try to parse the value as JSON
8925
+ const parsedValue = JSON.parse(value);
8926
+ context.variables.set(key, parsedValue);
8867
8927
  }
8868
- let _messages = [];
8869
- for (let i = 0; i < messages.length; i++) {
8870
- let message = messages[i];
8871
- if (message.role == 'assistant' && typeof message.content !== 'string') {
8872
- let _content = undefined;
8873
- let _tool_calls = undefined;
8874
- for (let j = 0; j < message.content.length; j++) {
8875
- let content = message.content[j];
8876
- if (content.type == 'text') {
8877
- if (!_content) {
8878
- _content = [];
8879
- }
8880
- _content.push(content);
8881
- }
8882
- else if (content.type == 'tool_use') {
8883
- if (!_tool_calls) {
8884
- _tool_calls = [];
8885
- }
8886
- _tool_calls.push({
8887
- id: content.id,
8888
- type: 'function',
8889
- function: {
8890
- name: content.name,
8891
- arguments: typeof content.input == 'string' ? content.input : JSON.stringify(content.input),
8892
- },
8893
- });
8894
- }
8928
+ catch (_a) {
8929
+ // If parsing fails, store as string
8930
+ context.variables.set(key, value);
8931
+ }
8932
+ return { success: true, key, value };
8933
+ }
8934
+ }
8935
+ function createReturnTool(actionName, outputDescription, outputSchema) {
8936
+ return {
8937
+ name: 'return_output',
8938
+ description: `Return the final output of this action. Use this to return a value matching the required output schema (if specified) and the following description:
8939
+ ${outputDescription}
8940
+
8941
+ You can either set 'use_tool_result=true' to return the result of a previous tool call, or explicitly specify 'value' with 'use_tool_result=false' to return a value according to your own understanding. Whenever possible, reuse tool results to avoid redundancy.
8942
+ `,
8943
+ input_schema: {
8944
+ type: 'object',
8945
+ properties: {
8946
+ use_tool_result: {
8947
+ type: ['boolean'],
8948
+ description: `Whether to use the latest tool result as output. When set to true, the 'value' parameter is ignored.`,
8949
+ },
8950
+ value: outputSchema || {
8951
+ // Default to accepting any JSON value
8952
+ type: ['string', 'number', 'boolean', 'object', 'null'],
8953
+ description: 'The output value. Only provide a value if the previous tool result is not suitable for the output description. Otherwise, leave this as null.',
8954
+ },
8955
+ },
8956
+ required: ['use_tool_result', 'value'],
8957
+ },
8958
+ async execute(context, params) {
8959
+ context.variables.set(`__action_${actionName}_output`, params);
8960
+ return { success: true };
8961
+ },
8962
+ };
8963
+ }
8964
+ class ActionImpl {
8965
+ constructor(type, // Only support prompt type
8966
+ name, description, tools, llmProvider, llmConfig, config) {
8967
+ this.type = type;
8968
+ this.name = name;
8969
+ this.description = description;
8970
+ this.tools = tools;
8971
+ this.llmProvider = llmProvider;
8972
+ this.llmConfig = llmConfig;
8973
+ this.maxRounds = 10; // Default max rounds
8974
+ this.toolResults = new Map();
8975
+ this.logger = new ExecutionLogger();
8976
+ this.writeContextTool = new WriteContextTool();
8977
+ this.tools = [...tools, this.writeContextTool];
8978
+ if (config === null || config === undefined ? undefined : config.maxRounds) {
8979
+ this.maxRounds = config.maxRounds;
8980
+ }
8981
+ }
8982
+ async executeSingleRound(messages, params, toolMap, context) {
8983
+ this.logger = context.logger;
8984
+ const roundMessages = [];
8985
+ let hasToolUse = false;
8986
+ let response = null;
8987
+ // Buffer to collect into roundMessages
8988
+ let assistantTextMessage = '';
8989
+ let toolUseMessage = null;
8990
+ let toolResultMessage = null;
8991
+ // Track tool execution promise
8992
+ let toolExecutionPromise = null;
8993
+ // Listen for abort signal
8994
+ if (context.signal) {
8995
+ context.signal.addEventListener('abort', () => {
8996
+ context.__abort = true;
8997
+ });
8998
+ }
8999
+ const handler = {
9000
+ onContent: (content) => {
9001
+ if (content.trim()) {
9002
+ assistantTextMessage += content;
8895
9003
  }
8896
- _messages.push({
9004
+ },
9005
+ onToolUse: async (toolCall) => {
9006
+ this.logger.log('info', `Assistant: ${assistantTextMessage}`);
9007
+ this.logger.logToolExecution(toolCall.name, toolCall.input, context);
9008
+ hasToolUse = true;
9009
+ const tool = toolMap.get(toolCall.name);
9010
+ if (!tool) {
9011
+ throw new Error(`Tool not found: ${toolCall.name}`);
9012
+ }
9013
+ toolUseMessage = {
8897
9014
  role: 'assistant',
8898
- content: _content,
8899
- tool_calls: _tool_calls,
8900
- });
8901
- }
8902
- else if (message.role == 'user' && typeof message.content !== 'string') {
8903
- for (let j = 0; j < message.content.length; j++) {
8904
- let content = message.content[j];
8905
- if (content.type == 'text') {
8906
- _messages.push({
9015
+ content: [
9016
+ {
9017
+ type: 'tool_use',
9018
+ id: toolCall.id,
9019
+ name: tool.name,
9020
+ input: toolCall.input,
9021
+ },
9022
+ ],
9023
+ };
9024
+ // Store the promise of tool execution
9025
+ toolExecutionPromise = (async () => {
9026
+ var _a;
9027
+ try {
9028
+ // beforeToolUse
9029
+ context.__skip = false;
9030
+ if (context.callback && context.callback.hooks.beforeToolUse) {
9031
+ let modified_input = await context.callback.hooks.beforeToolUse(tool, context, toolCall.input);
9032
+ if (modified_input) {
9033
+ toolCall.input = modified_input;
9034
+ }
9035
+ }
9036
+ if (context.__skip || context.__abort || ((_a = context.signal) === null || _a === void 0 ? void 0 : _a.aborted)) {
9037
+ toolResultMessage = {
9038
+ role: 'user',
9039
+ content: [
9040
+ {
9041
+ type: 'tool_result',
9042
+ tool_use_id: toolCall.id,
9043
+ content: 'skip',
9044
+ },
9045
+ ],
9046
+ };
9047
+ return;
9048
+ }
9049
+ // Execute the tool
9050
+ let result = await tool.execute(context, toolCall.input);
9051
+ // afterToolUse
9052
+ if (context.callback && context.callback.hooks.afterToolUse) {
9053
+ let modified_result = await context.callback.hooks.afterToolUse(tool, context, result);
9054
+ if (modified_result) {
9055
+ result = modified_result;
9056
+ }
9057
+ }
9058
+ const result_has_image = result && "image" in result;
9059
+ const resultContent = result_has_image
9060
+ ? {
9061
+ type: 'tool_result',
9062
+ tool_use_id: toolCall.id,
9063
+ content: result.text
9064
+ ? [
9065
+ { type: 'image', source: result.image },
9066
+ { type: 'text', text: result.text },
9067
+ ]
9068
+ : [{ type: 'image', source: result.image }],
9069
+ }
9070
+ : {
9071
+ type: 'tool_result',
9072
+ tool_use_id: toolCall.id,
9073
+ content: [{ type: 'text', text: JSON.stringify(result) }],
9074
+ };
9075
+ const resultContentText = result_has_image
9076
+ ? result.text
9077
+ ? result.text + ' [Image]'
9078
+ : '[Image]'
9079
+ : JSON.stringify(result);
9080
+ const resultMessage = {
8907
9081
  role: 'user',
8908
- content: content.text,
8909
- });
9082
+ content: [resultContent],
9083
+ };
9084
+ toolResultMessage = resultMessage;
9085
+ this.logger.logToolResult(tool.name, result, context);
9086
+ // Store tool results except for the return_output tool
9087
+ if (tool.name !== 'return_output') {
9088
+ this.toolResults.set(toolCall.id, resultContentText);
9089
+ }
8910
9090
  }
8911
- else if (content.type == 'image') {
8912
- _messages.push({
9091
+ catch (err) {
9092
+ console.log("An error occurred when calling tool:");
9093
+ console.log(err);
9094
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
9095
+ const errorResult = {
8913
9096
  role: 'user',
8914
9097
  content: [
8915
9098
  {
8916
- type: 'image_url',
8917
- image_url: {
8918
- url: `data:${content.source.media_type};base64,${content.source.data}`,
8919
- },
9099
+ type: 'tool_result',
9100
+ tool_use_id: toolCall.id,
9101
+ content: [{ type: 'text', text: `Error: ${errorMessage}` }],
9102
+ is_error: true,
8920
9103
  },
8921
9104
  ],
8922
- });
9105
+ };
9106
+ toolResultMessage = errorResult;
9107
+ this.logger.logError(err, context);
8923
9108
  }
8924
- else if (content.type == 'tool_result') {
8925
- let _content = [];
8926
- if (content.content == 'string') {
8927
- _content.push({ type: 'text', text: content.content });
8928
- }
8929
- else {
8930
- for (let k = 0; k < content.content.length; k++) {
8931
- let item = content.content[k];
8932
- if (item.type == 'text') {
8933
- _content.push({ ...item });
8934
- }
8935
- else if (item.type == 'image') {
8936
- _content.push({
8937
- type: 'image_url',
8938
- image_url: {
8939
- url: `data:${item.source.media_type};base64,${item.source.data}`,
8940
- },
8941
- });
9109
+ })();
9110
+ },
9111
+ onComplete: (llmResponse) => {
9112
+ response = llmResponse;
9113
+ },
9114
+ onError: (error) => {
9115
+ console.error('Stream Error:', error);
9116
+ console.log('Last message array sent to LLM:', JSON.stringify(messages, null, 2));
9117
+ },
9118
+ };
9119
+ this.handleHistoryImageMessages(messages);
9120
+ // Wait for stream to complete
9121
+ if (!this.llmProvider) {
9122
+ throw new Error('LLM provider not set');
9123
+ }
9124
+ await this.llmProvider.generateStream(messages, params, handler);
9125
+ // Wait for tool execution to complete if it was started
9126
+ if (toolExecutionPromise) {
9127
+ await toolExecutionPromise;
9128
+ }
9129
+ if (context.__abort) {
9130
+ throw new Error('Abort');
9131
+ }
9132
+ // Add messages in the correct order after everything is complete
9133
+ if (assistantTextMessage) {
9134
+ roundMessages.push({ role: 'assistant', content: assistantTextMessage });
9135
+ }
9136
+ if (toolUseMessage) {
9137
+ roundMessages.push(toolUseMessage);
9138
+ }
9139
+ if (toolResultMessage) {
9140
+ roundMessages.push(toolResultMessage);
9141
+ }
9142
+ return { response, hasToolUse, roundMessages };
9143
+ }
9144
+ handleHistoryImageMessages(messages) {
9145
+ // Remove all images from historical tool results except the most recent user message
9146
+ const initialImageCount = this.countImages(messages);
9147
+ let foundFirstUser = false;
9148
+ for (let i = messages.length - 1; i >= 0; i--) {
9149
+ const message = messages[i];
9150
+ if (message.role === 'user') {
9151
+ if (!foundFirstUser) {
9152
+ foundFirstUser = true;
9153
+ continue;
9154
+ }
9155
+ if (Array.isArray(message.content)) {
9156
+ // Directly modify the message content array
9157
+ message.content = message.content.map((item) => {
9158
+ if (item.type === 'tool_result' && Array.isArray(item.content)) {
9159
+ // Create a new content array without images
9160
+ if (item.content.length > 0) {
9161
+ item.content = item.content.filter((c) => c.type !== 'image');
9162
+ // If all content was images and got filtered out, replace with ok message
9163
+ if (item.content.length === 0) {
9164
+ item.content = [{ type: 'text', text: 'ok' }];
8942
9165
  }
8943
9166
  }
8944
9167
  }
8945
- let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
8946
- if (hasImage) {
8947
- // OpenAI does not support images returned by the tool.
8948
- _messages.push({
8949
- role: 'tool',
8950
- content: 'ok',
8951
- tool_call_id: content.tool_call_id || content.tool_use_id,
8952
- });
8953
- _messages.push({
8954
- role: 'user',
8955
- content: _content,
8956
- });
8957
- }
8958
- else {
8959
- _messages.push({
8960
- role: 'tool',
8961
- content: _content,
8962
- tool_call_id: content.tool_call_id || content.tool_use_id,
8963
- });
8964
- }
8965
- }
9168
+ return item;
9169
+ });
8966
9170
  }
8967
9171
  }
8968
- else {
8969
- _messages.push(message);
8970
- }
8971
9172
  }
8972
- return {
8973
- stream: stream,
8974
- model: params.model || this.defaultModel,
8975
- max_tokens: params.maxTokens || 4096,
8976
- temperature: params.temperature,
8977
- messages: _messages,
8978
- tools: tools,
8979
- tool_choice: tool_choice,
8980
- };
9173
+ const finalImageCount = this.countImages(messages);
9174
+ if (initialImageCount !== finalImageCount) {
9175
+ this.logger.log("info", `Removed ${initialImageCount - finalImageCount} images from history`);
9176
+ }
8981
9177
  }
8982
- async generateText(messages, params) {
8983
- const response = await this.client.chat.completions.create(this.buildParams(messages, params, false));
8984
- let textContent = null;
8985
- let toolCalls = [];
8986
- let stop_reason = null;
8987
- for (let i = 0; i < response.choices.length; i++) {
8988
- let choice = response.choices[i];
8989
- let message = choice.message;
8990
- if (message.content) {
8991
- if (textContent == null) {
8992
- textContent = '';
8993
- }
8994
- textContent += message.content;
9178
+ countImages(messages) {
9179
+ let count = 0;
9180
+ messages.forEach(msg => {
9181
+ if (Array.isArray(msg.content)) {
9182
+ msg.content.forEach((item) => {
9183
+ if (item.type === 'tool_result' && Array.isArray(item.content)) {
9184
+ count += item.content.filter((c) => c.type === 'image').length;
9185
+ }
9186
+ });
8995
9187
  }
8996
- if (message.tool_calls) {
8997
- for (let j = 0; j < message.tool_calls.length; j++) {
8998
- let tool_call = message.tool_calls[j];
8999
- toolCalls.push({
9000
- id: tool_call.id,
9001
- name: tool_call.function.name,
9002
- input: JSON.parse(tool_call.function.arguments),
9003
- });
9004
- }
9188
+ });
9189
+ return count;
9190
+ }
9191
+ async execute(input, output, context, outputSchema) {
9192
+ var _a, _b, _c, _d, _e;
9193
+ this.logger = context.logger;
9194
+ console.log(`Executing action started: ${this.name}`);
9195
+ // Create return tool with output schema
9196
+ const returnTool = createReturnTool(this.name, output.description, outputSchema);
9197
+ // Create tool map combining context tools, action tools, and return tool
9198
+ const toolMap = new Map();
9199
+ this.tools.forEach((tool) => toolMap.set(tool.name, tool));
9200
+ (_a = context.tools) === null || _a === undefined ? undefined : _a.forEach((tool) => toolMap.set(tool.name, tool));
9201
+ toolMap.set(returnTool.name, returnTool);
9202
+ // Prepare initial messages
9203
+ const messages = [
9204
+ { role: 'system', content: this.formatSystemPrompt() },
9205
+ { role: 'user', content: this.formatUserPrompt(context, input) },
9206
+ ];
9207
+ this.logger.logActionStart(this.name, input, context);
9208
+ // Configure tool parameters
9209
+ const params = {
9210
+ ...this.llmConfig,
9211
+ tools: Array.from(toolMap.values()).map((tool) => ({
9212
+ name: tool.name,
9213
+ description: tool.description,
9214
+ input_schema: tool.input_schema,
9215
+ })),
9216
+ };
9217
+ let roundCount = 0;
9218
+ while (roundCount < this.maxRounds) {
9219
+ // Check for abort signal
9220
+ if ((_b = context.signal) === null || _b === undefined ? undefined : _b.aborted) {
9221
+ throw new Error('Workflow cancelled');
9005
9222
  }
9006
- if (choice.finish_reason) {
9007
- stop_reason = choice.finish_reason;
9223
+ roundCount++;
9224
+ this.logger.log('info', `Starting round ${roundCount} of ${this.maxRounds}`, context);
9225
+ console.log(messages);
9226
+ const { response, hasToolUse, roundMessages } = await this.executeSingleRound(messages, params, toolMap, context);
9227
+ console.log(response);
9228
+ console.log(hasToolUse);
9229
+ console.log(roundMessages);
9230
+ if (response === null || response === undefined ? undefined : response.textContent) {
9231
+ (_e = (_d = (_c = context.callback) === null || _c === undefined ? undefined : _c.hooks) === null || _d === undefined ? undefined : _d.onLlmMessage) === null || _e === undefined ? undefined : _e.call(_d, response.textContent);
9232
+ }
9233
+ // Add round messages to conversation history
9234
+ messages.push(...roundMessages);
9235
+ this.logger.log('debug', `Round ${roundCount} messages: ${JSON.stringify(roundMessages)}`, context);
9236
+ // Check termination conditions
9237
+ if (!hasToolUse && response) {
9238
+ // LLM sent a message without using tools - request explicit return
9239
+ this.logger.log('info', `Assistant: ${response.textContent}`);
9240
+ this.logger.log('warn', 'LLM sent a message without using tools; requesting explicit return');
9241
+ const returnOnlyParams = {
9242
+ ...params,
9243
+ tools: [
9244
+ {
9245
+ name: returnTool.name,
9246
+ description: returnTool.description,
9247
+ input_schema: returnTool.input_schema,
9248
+ },
9249
+ ],
9250
+ };
9251
+ messages.push({
9252
+ role: 'user',
9253
+ content: 'Please process the above information and return a final result using the return_output tool.',
9254
+ });
9255
+ const { roundMessages: finalRoundMessages } = await this.executeSingleRound(messages, returnOnlyParams, new Map([[returnTool.name, returnTool]]), context);
9256
+ messages.push(...finalRoundMessages);
9257
+ break;
9258
+ }
9259
+ if (response === null || response === undefined ? undefined : response.toolCalls.some((call) => call.name === 'return_output')) {
9260
+ break;
9261
+ }
9262
+ // If this is the last round, force an explicit return
9263
+ if (roundCount === this.maxRounds) {
9264
+ this.logger.log('warn', 'Max rounds reached, requesting explicit return');
9265
+ const returnOnlyParams = {
9266
+ ...params,
9267
+ tools: [
9268
+ {
9269
+ name: returnTool.name,
9270
+ description: returnTool.description,
9271
+ input_schema: returnTool.input_schema,
9272
+ },
9273
+ ],
9274
+ };
9275
+ messages.push({
9276
+ role: 'user',
9277
+ content: 'Maximum number of steps reached. Please return the best result possible with the return_output tool.',
9278
+ });
9279
+ const { roundMessages: finalRoundMessages } = await this.executeSingleRound(messages, returnOnlyParams, new Map([[returnTool.name, returnTool]]), context);
9280
+ messages.push(...finalRoundMessages);
9008
9281
  }
9009
9282
  }
9010
- let content = [];
9011
- if (textContent) {
9012
- content.push({
9013
- type: 'text',
9014
- text: textContent,
9283
+ // Get and clean up output value
9284
+ const outputKey = `__action_${this.name}_output`;
9285
+ const outputParams = context.variables.get(outputKey);
9286
+ context.variables.delete(outputKey);
9287
+ // Get output value, first checking for use_tool_result
9288
+ const outputParams_has_use_tool_result = outputParams && "use_tool_result" in outputParams;
9289
+ const outputValue = outputParams_has_use_tool_result
9290
+ ? Array.from(this.toolResults.values()).pop()
9291
+ : outputParams === null || outputParams === undefined ? undefined : outputParams.value;
9292
+ if (outputValue === undefined) {
9293
+ console.warn('Action completed without returning a value');
9294
+ return {};
9295
+ }
9296
+ return outputValue;
9297
+ }
9298
+ formatSystemPrompt() {
9299
+ return `You are a subtask executor. You need to complete the subtask specified by the user, which is a consisting part of the overall task. Help the user by calling the tools provided.
9300
+
9301
+ Remember to:
9302
+ 1. Use tools when needed to accomplish the task
9303
+ 2. Think step by step about what needs to be done
9304
+ 3. Return the output of the subtask using the 'return_output' tool when you are done; prefer using the 'tool_use_id' parameter to refer to the output of a tool call over providing a long text as the value
9305
+ 4. Use the context to store important information for later reference, but use it sparingly: most of the time, the output of the subtask should be sufficient for the next steps
9306
+ 5. If there are any unclear points during the task execution, please use the human-related tool to inquire with the user
9307
+ 6. If user intervention is required during the task execution, please use the human-related tool to transfer the operation rights to the user
9308
+ `;
9309
+ }
9310
+ formatUserPrompt(context, input) {
9311
+ var _a;
9312
+ const workflowDescription = ((_a = context.workflow) === null || _a === undefined ? undefined : _a.description) || null;
9313
+ const actionDescription = `${this.name} -- ${this.description}`;
9314
+ const inputDescription = JSON.stringify(input, null, 2) || null;
9315
+ const contextVariables = Array.from(context.variables.entries())
9316
+ .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
9317
+ .join('\n');
9318
+ return `You are executing a subtask in the workflow. The workflow description is as follows:
9319
+ ${workflowDescription}
9320
+
9321
+ The subtask description is as follows:
9322
+ ${actionDescription}
9323
+
9324
+ The input to the subtask is as follows:
9325
+ ${inputDescription}
9326
+
9327
+ There are some variables stored in the context that you can use for reference:
9328
+ ${contextVariables}
9329
+ `;
9330
+ }
9331
+ // Static factory method
9332
+ static createPromptAction(name, description, tools, llmProvider, llmConfig) {
9333
+ return new ActionImpl('prompt', name, description, tools, llmProvider, llmConfig);
9334
+ }
9335
+ }
9336
+
9337
+ // src/services/workflow/templates.ts
9338
+ function createWorkflowPrompts(tools) {
9339
+ return {
9340
+ formatSystemPrompt: () => {
9341
+ const toolDescriptions = tools
9342
+ .map((tool) => `
9343
+ Tool: ${tool.name}
9344
+ Description: ${tool.description}
9345
+ Input Schema: ${JSON.stringify(tool.input_schema, null, 2)}
9346
+ `)
9347
+ .join('\n');
9348
+ return `You are a workflow generation assistant that creates Eko framework workflows.
9349
+ The following tools are available:
9350
+
9351
+ ${toolDescriptions}
9352
+
9353
+ Generate a complete workflow that:
9354
+ 1. Only uses the tools listed above
9355
+ 2. Properly sequences tool usage based on dependencies
9356
+ 3. Ensures each action has appropriate input/output schemas, and that the "tools" field in each action is populated with the sufficient subset of all available tools needed to complete the action
9357
+ 4. Creates a clear, logical flow to accomplish the user's goal
9358
+ 5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem
9359
+ 6. You should always add a SubTask at the end of the workflow to summarize it, and this SubTask should always call the "summary_workflow" tool. It's dependencies should be all of the SubTasks`;
9360
+ },
9361
+ formatUserPrompt: (requirement) => `Create a workflow for the following requirement: ${requirement}`,
9362
+ modifyUserPrompt: (prompt) => `Modify workflow: ${prompt}`,
9363
+ };
9364
+ }
9365
+ function createWorkflowGenerationTool(registry) {
9366
+ return {
9367
+ name: 'generate_workflow',
9368
+ description: `Generate a workflow following the Eko framework DSL schema.
9369
+ The workflow must only use the available tools and ensure proper dependencies between nodes.`,
9370
+ input_schema: {
9371
+ type: 'object',
9372
+ properties: {
9373
+ workflow: registry.getWorkflowSchema(),
9374
+ },
9375
+ required: ['workflow'],
9376
+ },
9377
+ };
9378
+ }
9379
+
9380
+ const byteToHex = [];
9381
+ for (let i = 0; i < 256; ++i) {
9382
+ byteToHex.push((i + 0x100).toString(16).slice(1));
9383
+ }
9384
+ function unsafeStringify(arr, offset = 0) {
9385
+ return (byteToHex[arr[offset + 0]] +
9386
+ byteToHex[arr[offset + 1]] +
9387
+ byteToHex[arr[offset + 2]] +
9388
+ byteToHex[arr[offset + 3]] +
9389
+ '-' +
9390
+ byteToHex[arr[offset + 4]] +
9391
+ byteToHex[arr[offset + 5]] +
9392
+ '-' +
9393
+ byteToHex[arr[offset + 6]] +
9394
+ byteToHex[arr[offset + 7]] +
9395
+ '-' +
9396
+ byteToHex[arr[offset + 8]] +
9397
+ byteToHex[arr[offset + 9]] +
9398
+ '-' +
9399
+ byteToHex[arr[offset + 10]] +
9400
+ byteToHex[arr[offset + 11]] +
9401
+ byteToHex[arr[offset + 12]] +
9402
+ byteToHex[arr[offset + 13]] +
9403
+ byteToHex[arr[offset + 14]] +
9404
+ byteToHex[arr[offset + 15]]).toLowerCase();
9405
+ }
9406
+
9407
+ let getRandomValues;
9408
+ const rnds8 = new Uint8Array(16);
9409
+ function rng() {
9410
+ if (!getRandomValues) {
9411
+ if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
9412
+ throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
9413
+ }
9414
+ getRandomValues = crypto.getRandomValues.bind(crypto);
9415
+ }
9416
+ return getRandomValues(rnds8);
9417
+ }
9418
+
9419
+ const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
9420
+ var native = { randomUUID };
9421
+
9422
+ function v4(options, buf, offset) {
9423
+ if (native.randomUUID && true && !options) {
9424
+ return native.randomUUID();
9425
+ }
9426
+ options = options || {};
9427
+ const rnds = options.random ?? options.rng?.() ?? rng();
9428
+ if (rnds.length < 16) {
9429
+ throw new Error('Random bytes length must be >= 16');
9430
+ }
9431
+ rnds[6] = (rnds[6] & 0x0f) | 0x40;
9432
+ rnds[8] = (rnds[8] & 0x3f) | 0x80;
9433
+ return unsafeStringify(rnds);
9434
+ }
9435
+
9436
+ class WorkflowGenerator {
9437
+ constructor(llmProvider, toolRegistry) {
9438
+ this.llmProvider = llmProvider;
9439
+ this.toolRegistry = toolRegistry;
9440
+ this.message_history = [];
9441
+ }
9442
+ async generateWorkflow(prompt) {
9443
+ return this.doGenerateWorkflow(prompt, false);
9444
+ }
9445
+ async generateWorkflowFromJson(json) {
9446
+ return this.createWorkflowFromData(json);
9447
+ }
9448
+ async modifyWorkflow(prompt) {
9449
+ return this.doGenerateWorkflow(prompt, true);
9450
+ }
9451
+ async doGenerateWorkflow(prompt, modify) {
9452
+ // Create prompts with current set of tools
9453
+ const prompts = createWorkflowPrompts(this.toolRegistry.getToolDefinitions());
9454
+ let messages = [];
9455
+ if (modify) {
9456
+ messages = this.message_history;
9457
+ messages.push({
9458
+ role: 'user',
9459
+ content: prompts.modifyUserPrompt(prompt),
9015
9460
  });
9016
9461
  }
9017
- if (toolCalls && toolCalls.length > 0) {
9018
- for (let i = 0; i < toolCalls.length; i++) {
9019
- let toolCall = toolCalls[i];
9020
- content.push({
9021
- type: 'tool_use',
9022
- id: toolCall.id,
9023
- name: toolCall.name,
9024
- input: toolCall.input,
9025
- });
9026
- }
9462
+ else {
9463
+ messages = this.message_history = [
9464
+ {
9465
+ role: 'system',
9466
+ content: prompts.formatSystemPrompt(),
9467
+ },
9468
+ {
9469
+ role: 'user',
9470
+ content: prompts.formatUserPrompt(prompt),
9471
+ },
9472
+ ];
9027
9473
  }
9028
- return {
9029
- textContent,
9030
- content,
9031
- toolCalls,
9032
- stop_reason,
9474
+ const params = {
9475
+ temperature: 0.7,
9476
+ maxTokens: 8192,
9477
+ tools: [createWorkflowGenerationTool(this.toolRegistry)],
9478
+ toolChoice: { type: 'tool', name: 'generate_workflow' },
9033
9479
  };
9034
- }
9035
- async generateStream(messages, params, handler) {
9036
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
9037
- const stream = await this.client.chat.completions.create(this.buildParams(messages, params, true));
9038
- (_a = handler.onStart) === null || _a === void 0 ? void 0 : _a.call(handler);
9039
- let textContent = null;
9040
- let toolCalls = [];
9041
- let stop_reason = null;
9042
- let currentToolUse = null;
9043
- try {
9044
- for await (const chunk of stream) {
9045
- for (let i = 0; i < chunk.choices.length; i++) {
9046
- let choice = chunk.choices[i];
9047
- if (choice.delta) {
9048
- if (choice.delta.content) {
9049
- if (textContent == null) {
9050
- textContent = '';
9051
- }
9052
- textContent += choice.delta.content;
9053
- (_b = handler.onContent) === null || _b === void 0 ? void 0 : _b.call(handler, choice.delta.content);
9054
- }
9055
- else if (choice.delta.tool_calls && choice.delta.tool_calls.length > 0) {
9056
- let tool_calls = choice.delta.tool_calls[0];
9057
- if (!currentToolUse) {
9058
- currentToolUse = {
9059
- id: tool_calls.id || '',
9060
- name: ((_c = tool_calls.function) === null || _c === void 0 ? void 0 : _c.name) || '',
9061
- accumulatedJson: ((_d = tool_calls.function) === null || _d === void 0 ? void 0 : _d.arguments) || '',
9062
- };
9063
- }
9064
- else {
9065
- if (tool_calls.id) {
9066
- currentToolUse.id = tool_calls.id;
9067
- }
9068
- if ((_e = tool_calls.function) === null || _e === void 0 ? void 0 : _e.name) {
9069
- currentToolUse.name = (_f = tool_calls.function) === null || _f === void 0 ? void 0 : _f.name;
9070
- }
9071
- currentToolUse.accumulatedJson += ((_g = tool_calls.function) === null || _g === void 0 ? void 0 : _g.arguments) || '';
9072
- }
9073
- }
9074
- }
9075
- if (choice.finish_reason) {
9076
- stop_reason = choice.finish_reason;
9077
- if (currentToolUse) {
9078
- const toolCall = {
9079
- id: currentToolUse.id,
9080
- name: currentToolUse.name,
9081
- input: JSON.parse(currentToolUse.accumulatedJson),
9082
- };
9083
- toolCalls.push(toolCall);
9084
- (_h = handler.onToolUse) === null || _h === void 0 ? void 0 : _h.call(handler, toolCall);
9085
- currentToolUse = null;
9086
- }
9087
- }
9480
+ const response = await this.llmProvider.generateText(messages, params);
9481
+ if (!response.toolCalls.length || !response.toolCalls[0].input.workflow) {
9482
+ messages.pop();
9483
+ throw new Error('Failed to generate workflow: Invalid response from LLM');
9484
+ }
9485
+ messages.push({
9486
+ role: 'assistant',
9487
+ content: [
9488
+ {
9489
+ type: 'tool_use',
9490
+ id: response.toolCalls[0].id,
9491
+ name: response.toolCalls[0].name,
9492
+ input: response.toolCalls[0].input,
9493
+ },
9494
+ ],
9495
+ }, {
9496
+ role: 'user',
9497
+ content: [
9498
+ {
9499
+ type: 'tool_result',
9500
+ tool_use_id: response.toolCalls[0].id,
9501
+ content: 'ok',
9502
+ },
9503
+ ],
9504
+ });
9505
+ const workflowData = response.toolCalls[0].input.workflow;
9506
+ // Forcibly add special tools
9507
+ const specialTools = [
9508
+ "cancel_workflow",
9509
+ "human_input_text",
9510
+ "human_operate",
9511
+ ];
9512
+ for (const node of workflowData.nodes) {
9513
+ for (const tool of specialTools) {
9514
+ if (!node.action.tools.includes(tool)) {
9515
+ node.action.tools.push(tool);
9088
9516
  }
9089
9517
  }
9090
- let content = [];
9091
- if (textContent) {
9092
- content.push({
9093
- type: 'text',
9094
- text: textContent,
9095
- });
9096
- }
9097
- if (toolCalls && toolCalls.length > 0) {
9098
- for (let i = 0; i < toolCalls.length; i++) {
9099
- let toolCall = toolCalls[i];
9100
- content.push({
9101
- type: 'tool_use',
9102
- id: toolCall.id,
9103
- name: toolCall.name,
9104
- input: toolCall.input,
9105
- });
9106
- }
9518
+ }
9519
+ // Validate all tools exist
9520
+ for (const node of workflowData.nodes) {
9521
+ if (!this.toolRegistry.hasTools(node.action.tools)) {
9522
+ throw new Error(`Workflow contains undefined tools: ${node.action.tools}`);
9107
9523
  }
9108
- (_j = handler.onComplete) === null || _j === void 0 ? void 0 : _j.call(handler, {
9109
- textContent: textContent,
9110
- content: content,
9111
- toolCalls: toolCalls,
9112
- stop_reason: stop_reason,
9113
- });
9114
9524
  }
9115
- catch (error) {
9116
- (_k = handler.onError) === null || _k === void 0 ? void 0 : _k.call(handler, error);
9525
+ // Generate a new UUID if not provided
9526
+ if (!workflowData.id) {
9527
+ workflowData.id = v4();
9528
+ }
9529
+ // debug
9530
+ console.log("Debug the workflow...");
9531
+ console.log(workflowData);
9532
+ console.log("Debug the workflow...Done");
9533
+ return this.createWorkflowFromData(workflowData);
9534
+ }
9535
+ createWorkflowFromData(data) {
9536
+ const workflow = new WorkflowImpl(data.id, data.name, data.description || '', [], new Map(Object.entries(data.variables || {})), this.llmProvider, {
9537
+ logLevel: 'info',
9538
+ includeTimestamp: true,
9539
+ });
9540
+ // Add nodes to workflow
9541
+ if (Array.isArray(data.nodes)) {
9542
+ data.nodes.forEach((nodeData) => {
9543
+ const tools = nodeData.action.tools.map((toolName) => this.toolRegistry.getTool(toolName));
9544
+ const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, tools, this.llmProvider, { maxTokens: 8192 });
9545
+ const node = {
9546
+ id: nodeData.id,
9547
+ name: nodeData.name || nodeData.id,
9548
+ input: nodeData.input || { type: 'any', schema: {}, value: undefined },
9549
+ output: nodeData.output || { type: 'any', schema: {}, value: undefined },
9550
+ action: action,
9551
+ dependencies: nodeData.dependencies || [],
9552
+ };
9553
+ workflow.addNode(node);
9554
+ });
9117
9555
  }
9556
+ return workflow;
9118
9557
  }
9119
9558
  }
9120
9559
 
@@ -9140,18 +9579,11 @@ const workflowSchema = {
9140
9579
  type: "array",
9141
9580
  items: { type: "string" },
9142
9581
  },
9143
- input: {
9144
- type: "object",
9145
- properties: {
9146
- type: { type: "string" },
9147
- schema: { type: "object" },
9148
- },
9149
- },
9150
9582
  output: {
9151
9583
  type: "object",
9152
9584
  properties: {
9153
- type: { type: "string" },
9154
- schema: { type: "object" },
9585
+ name: { type: "string" },
9586
+ description: { type: "string" },
9155
9587
  },
9156
9588
  },
9157
9589
  action: {
@@ -9239,25 +9671,7 @@ class Eko {
9239
9671
  constructor(config) {
9240
9672
  this.toolRegistry = new ToolRegistry();
9241
9673
  this.workflowGeneratorMap = new Map();
9242
- if (typeof config == 'string') {
9243
- this.llmProvider = new ClaudeProvider(config);
9244
- }
9245
- else if ('llm' in config) {
9246
- if (config.llm == 'claude') {
9247
- let claudeConfig = config;
9248
- this.llmProvider = new ClaudeProvider(claudeConfig.apiKey, claudeConfig.modelName, claudeConfig.options);
9249
- }
9250
- else if (config.llm == 'openai') {
9251
- let openaiConfig = config;
9252
- this.llmProvider = new OpenaiProvider(openaiConfig.apiKey, openaiConfig.modelName, openaiConfig.options);
9253
- }
9254
- else {
9255
- throw new Error('Unknown parameter: llm > ' + config['llm']);
9256
- }
9257
- }
9258
- else {
9259
- this.llmProvider = config;
9260
- }
9674
+ this.llmProvider = LLMProviderFactory.buildLLMProvider(config);
9261
9675
  Eko.tools.forEach((tool) => this.toolRegistry.registerTool(tool));
9262
9676
  }
9263
9677
  async generate(prompt, param) {
@@ -9280,8 +9694,27 @@ class Eko {
9280
9694
  return workflow;
9281
9695
  }
9282
9696
  async execute(workflow, callback) {
9697
+ // Inject LLM provider at workflow level
9698
+ workflow.llmProvider = this.llmProvider;
9699
+ // Process each node's action
9700
+ for (const node of workflow.nodes) {
9701
+ if (node.action.type === 'prompt') {
9702
+ // Inject LLM provider
9703
+ node.action.llmProvider = this.llmProvider;
9704
+ // Resolve tools
9705
+ node.action.tools = node.action.tools.map(tool => {
9706
+ if (typeof tool === 'string') {
9707
+ return this.toolRegistry.getTool(tool);
9708
+ }
9709
+ return tool;
9710
+ });
9711
+ }
9712
+ }
9283
9713
  return await workflow.execute(callback);
9284
9714
  }
9715
+ async cancel(workflow) {
9716
+ return await workflow.cancel();
9717
+ }
9285
9718
  async modify(workflow, prompt) {
9286
9719
  const generator = this.workflowGeneratorMap.get(workflow);
9287
9720
  workflow = await generator.modifyWorkflow(prompt);
@@ -9465,31 +9898,30 @@ class WorkflowParser {
9465
9898
  errors,
9466
9899
  };
9467
9900
  }
9468
- /**
9469
- * Convert parsed JSON to runtime Workflow object
9470
- */
9471
9901
  static toRuntime(json) {
9472
9902
  const variables = new Map(Object.entries(json.variables || {}));
9473
- const workflow = new WorkflowImpl(json.id, json.name, json.description, [], variables);
9903
+ const workflow = new WorkflowImpl(json.id, json.name, json.description, [], variables, undefined, {
9904
+ logLevel: 'info',
9905
+ includeTimestamp: true,
9906
+ });
9474
9907
  // Convert nodes
9475
9908
  json.nodes.forEach((nodeJson) => {
9909
+ const action = ActionImpl.createPromptAction(nodeJson.action.name, nodeJson.action.description,
9910
+ // Pass tool names as strings, they'll be resolved at execution time
9911
+ nodeJson.action.tools || [], undefined, // LLM provider will be injected at execution time
9912
+ { maxTokens: 8192 });
9476
9913
  const node = {
9477
9914
  id: nodeJson.id,
9478
9915
  name: nodeJson.name || nodeJson.id,
9479
9916
  description: nodeJson.description,
9480
9917
  dependencies: nodeJson.dependencies || [],
9481
- input: this.convertIO(nodeJson.input),
9482
- output: this.convertIO(nodeJson.output),
9483
- action: {
9484
- type: nodeJson.action.type,
9485
- name: nodeJson.action.name,
9486
- description: nodeJson.action.description,
9487
- tools: nodeJson.action.tools || [],
9488
- execute: async (input, context) => {
9489
- // Default implementation - should be overridden by specific action types
9490
- return input;
9491
- },
9918
+ input: { items: [] },
9919
+ output: nodeJson.output || {
9920
+ name: `${nodeJson.name || nodeJson.id}_output`,
9921
+ description: `Output of node ${nodeJson.name || nodeJson.id}`,
9922
+ value: null,
9492
9923
  },
9924
+ action: action,
9493
9925
  };
9494
9926
  workflow.addNode(node);
9495
9927
  });
@@ -9509,32 +9941,25 @@ class WorkflowParser {
9509
9941
  name: node.name,
9510
9942
  description: node.description,
9511
9943
  dependencies: node.dependencies,
9512
- input: node.input,
9513
9944
  output: node.output,
9514
9945
  action: {
9515
9946
  type: node.action.type,
9516
9947
  name: node.action.name,
9517
9948
  description: node.action.description,
9518
- tools: node.action.tools,
9949
+ tools: node.action.tools
9950
+ .map((tool) => (typeof tool === 'string' ? tool : tool.name))
9951
+ .filter((tool) => tool !== 'write_context'),
9519
9952
  },
9520
9953
  })),
9521
9954
  variables: Object.fromEntries(workflow.variables),
9522
9955
  };
9523
9956
  }
9524
- /**
9525
- * Helper to convert IO definitions
9526
- */
9527
- static convertIO(io) {
9528
- return {
9529
- type: (io === null || io === void 0 ? void 0 : io.type) || 'object',
9530
- schema: (io === null || io === void 0 ? void 0 : io.schema) || {},
9531
- value: null,
9532
- };
9533
- }
9534
9957
  }
9535
9958
 
9536
9959
  exports.ClaudeProvider = ClaudeProvider;
9537
9960
  exports.Eko = Eko;
9961
+ exports.ExecutionLogger = ExecutionLogger;
9962
+ exports.LLMProviderFactory = LLMProviderFactory;
9538
9963
  exports.OpenaiProvider = OpenaiProvider;
9539
9964
  exports.ToolRegistry = ToolRegistry;
9540
9965
  exports.WorkflowGenerator = WorkflowGenerator;