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