flow-frame-core 0.1.0

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 (416) hide show
  1. package/README.md +64 -0
  2. package/dist/Dockerfile +86 -0
  3. package/dist/GPU_DEPLOYMENT_README.md +324 -0
  4. package/dist/OPS_AGENT_README.md +174 -0
  5. package/dist/README-H100-VM.md +192 -0
  6. package/dist/README-worker-pools.md +231 -0
  7. package/dist/README.md +8 -0
  8. package/dist/WEB-ELEMENT-REQUESTS-README.md +302 -0
  9. package/dist/append.d.ts +3 -0
  10. package/dist/append.d.ts.map +1 -0
  11. package/dist/append.js +42 -0
  12. package/dist/append.js.map +1 -0
  13. package/dist/audioRoutes.d.ts +2 -0
  14. package/dist/audioRoutes.d.ts.map +1 -0
  15. package/dist/audioRoutes.js +97 -0
  16. package/dist/audioRoutes.js.map +1 -0
  17. package/dist/augment-parallel.d.ts +6 -0
  18. package/dist/augment-parallel.d.ts.map +1 -0
  19. package/dist/augment-parallel.js +128 -0
  20. package/dist/augment-parallel.js.map +1 -0
  21. package/dist/augment-worker.d.ts +2 -0
  22. package/dist/augment-worker.d.ts.map +1 -0
  23. package/dist/augment-worker.js +100 -0
  24. package/dist/augment-worker.js.map +1 -0
  25. package/dist/browerRoutes.d.ts +2 -0
  26. package/dist/browerRoutes.d.ts.map +1 -0
  27. package/dist/browerRoutes.js +323 -0
  28. package/dist/browerRoutes.js.map +1 -0
  29. package/dist/browser-utils/utils.d.ts +6 -0
  30. package/dist/browser-utils/utils.d.ts.map +1 -0
  31. package/dist/browser-utils/utils.js +133 -0
  32. package/dist/browser-utils/utils.js.map +1 -0
  33. package/dist/capture_training_data_endpoints.d.ts +158 -0
  34. package/dist/capture_training_data_endpoints.d.ts.map +1 -0
  35. package/dist/capture_training_data_endpoints.js +1812 -0
  36. package/dist/capture_training_data_endpoints.js.map +1 -0
  37. package/dist/config.json +28 -0
  38. package/dist/configEndpoints.d.ts +2 -0
  39. package/dist/configEndpoints.d.ts.map +1 -0
  40. package/dist/configEndpoints.js +459 -0
  41. package/dist/configEndpoints.js.map +1 -0
  42. package/dist/constants.d.ts +109 -0
  43. package/dist/constants.d.ts.map +1 -0
  44. package/dist/constants.js +110 -0
  45. package/dist/constants.js.map +1 -0
  46. package/dist/docs/workflow_nodes.md +257 -0
  47. package/dist/download.d.ts +11 -0
  48. package/dist/download.d.ts.map +1 -0
  49. package/dist/download.js +31 -0
  50. package/dist/download.js.map +1 -0
  51. package/dist/download.py +61 -0
  52. package/dist/ecosystem.config.json +63 -0
  53. package/dist/email-body-extractor.d.ts +20 -0
  54. package/dist/email-body-extractor.d.ts.map +1 -0
  55. package/dist/email-body-extractor.js +103 -0
  56. package/dist/email-body-extractor.js.map +1 -0
  57. package/dist/express_util.d.ts +2 -0
  58. package/dist/express_util.d.ts.map +1 -0
  59. package/dist/express_util.js +30 -0
  60. package/dist/express_util.js.map +1 -0
  61. package/dist/extension/background.d.ts +2 -0
  62. package/dist/extension/background.d.ts.map +1 -0
  63. package/dist/extension/background.js +268 -0
  64. package/dist/extension/background.js.map +1 -0
  65. package/dist/extension/manifest.json +19 -0
  66. package/dist/extensionUtils.d.ts +2 -0
  67. package/dist/extensionUtils.d.ts.map +1 -0
  68. package/dist/extensionUtils.js +48 -0
  69. package/dist/extensionUtils.js.map +1 -0
  70. package/dist/filter-gmail-poller/README.md +320 -0
  71. package/dist/filter-gmail-poller/demo.d.ts +2 -0
  72. package/dist/filter-gmail-poller/demo.d.ts.map +1 -0
  73. package/dist/filter-gmail-poller/demo.js +79 -0
  74. package/dist/filter-gmail-poller/demo.js.map +1 -0
  75. package/dist/filter-gmail-poller/example-existing-app.d.ts +2 -0
  76. package/dist/filter-gmail-poller/example-existing-app.d.ts.map +1 -0
  77. package/dist/filter-gmail-poller/example-existing-app.js +72 -0
  78. package/dist/filter-gmail-poller/example-existing-app.js.map +1 -0
  79. package/dist/filter-gmail-poller/filter-gmail-poller.d.ts +160 -0
  80. package/dist/filter-gmail-poller/filter-gmail-poller.d.ts.map +1 -0
  81. package/dist/filter-gmail-poller/filter-gmail-poller.js +1048 -0
  82. package/dist/filter-gmail-poller/filter-gmail-poller.js.map +1 -0
  83. package/dist/filter-gmail-poller/index.d.ts +3 -0
  84. package/dist/filter-gmail-poller/index.d.ts.map +1 -0
  85. package/dist/filter-gmail-poller/index.js +18 -0
  86. package/dist/filter-gmail-poller/index.js.map +1 -0
  87. package/dist/filter-gmail-poller/manual-test.d.ts +2 -0
  88. package/dist/filter-gmail-poller/manual-test.d.ts.map +1 -0
  89. package/dist/filter-gmail-poller/manual-test.js +70 -0
  90. package/dist/filter-gmail-poller/manual-test.js.map +1 -0
  91. package/dist/filter-gmail-poller/poller-prompts.d.ts +12 -0
  92. package/dist/filter-gmail-poller/poller-prompts.d.ts.map +1 -0
  93. package/dist/filter-gmail-poller/poller-prompts.js +330 -0
  94. package/dist/filter-gmail-poller/poller-prompts.js.map +1 -0
  95. package/dist/filter-gmail-poller/test.js +69 -0
  96. package/dist/flowframe-auto-firebase-adminsdk.json +13 -0
  97. package/dist/gmail-poller/README-microsoft-email-poller.md +203 -0
  98. package/dist/gmail-poller/README.md +129 -0
  99. package/dist/gmail-poller/example.d.ts +5 -0
  100. package/dist/gmail-poller/example.d.ts.map +1 -0
  101. package/dist/gmail-poller/example.js +83 -0
  102. package/dist/gmail-poller/example.js.map +1 -0
  103. package/dist/gmail-poller/gmail-poller.d.ts +82 -0
  104. package/dist/gmail-poller/gmail-poller.d.ts.map +1 -0
  105. package/dist/gmail-poller/gmail-poller.js +455 -0
  106. package/dist/gmail-poller/gmail-poller.js.map +1 -0
  107. package/dist/gmail-poller/manual-test.d.ts +2 -0
  108. package/dist/gmail-poller/manual-test.d.ts.map +1 -0
  109. package/dist/gmail-poller/manual-test.js +37 -0
  110. package/dist/gmail-poller/manual-test.js.map +1 -0
  111. package/dist/gmail-poller/microsoft-email-example.d.ts +8 -0
  112. package/dist/gmail-poller/microsoft-email-example.d.ts.map +1 -0
  113. package/dist/gmail-poller/microsoft-email-example.js +58 -0
  114. package/dist/gmail-poller/microsoft-email-example.js.map +1 -0
  115. package/dist/gmail-poller/microsoft-email-poller.d.ts +73 -0
  116. package/dist/gmail-poller/microsoft-email-poller.d.ts.map +1 -0
  117. package/dist/gmail-poller/microsoft-email-poller.js +346 -0
  118. package/dist/gmail-poller/microsoft-email-poller.js.map +1 -0
  119. package/dist/gmail-poller/setup-auth.d.ts +3 -0
  120. package/dist/gmail-poller/setup-auth.d.ts.map +1 -0
  121. package/dist/gmail-poller/setup-auth.js +36 -0
  122. package/dist/gmail-poller/setup-auth.js.map +1 -0
  123. package/dist/gmail-poller/test.js +36 -0
  124. package/dist/index.d.ts +10 -0
  125. package/dist/index.d.ts.map +1 -0
  126. package/dist/index.js +28 -0
  127. package/dist/index.js.map +1 -0
  128. package/dist/inference/augment_levels.d.ts +2 -0
  129. package/dist/inference/augment_levels.d.ts.map +1 -0
  130. package/dist/inference/augment_levels.js +1 -0
  131. package/dist/inference/augment_levels.js.map +1 -0
  132. package/dist/inference/capture-overlay.d.ts +13 -0
  133. package/dist/inference/capture-overlay.d.ts.map +1 -0
  134. package/dist/inference/capture-overlay.js +355 -0
  135. package/dist/inference/capture-overlay.js.map +1 -0
  136. package/dist/inference/capturescreenshot.d.ts +12 -0
  137. package/dist/inference/capturescreenshot.d.ts.map +1 -0
  138. package/dist/inference/capturescreenshot.js +157 -0
  139. package/dist/inference/capturescreenshot.js.map +1 -0
  140. package/dist/jsonHandler.d.ts +37 -0
  141. package/dist/jsonHandler.d.ts.map +1 -0
  142. package/dist/jsonHandler.js +191 -0
  143. package/dist/jsonHandler.js.map +1 -0
  144. package/dist/localStorage.json +11 -0
  145. package/dist/media_data_endpoints.d.ts +2 -0
  146. package/dist/media_data_endpoints.d.ts.map +1 -0
  147. package/dist/media_data_endpoints.js +102 -0
  148. package/dist/media_data_endpoints.js.map +1 -0
  149. package/dist/operations/blender-ops.d.ts +4 -0
  150. package/dist/operations/blender-ops.d.ts.map +1 -0
  151. package/dist/operations/blender-ops.js +55 -0
  152. package/dist/operations/blender-ops.js.map +1 -0
  153. package/dist/operations.d.ts +34 -0
  154. package/dist/operations.d.ts.map +1 -0
  155. package/dist/operations.js +1514 -0
  156. package/dist/operations.js.map +1 -0
  157. package/dist/pdfRoutes.d.ts +2 -0
  158. package/dist/pdfRoutes.d.ts.map +1 -0
  159. package/dist/pdfRoutes.js +56 -0
  160. package/dist/pdfRoutes.js.map +1 -0
  161. package/dist/peers.d.ts +9 -0
  162. package/dist/peers.d.ts.map +1 -0
  163. package/dist/peers.js +70 -0
  164. package/dist/peers.js.map +1 -0
  165. package/dist/playparser.d.ts +2 -0
  166. package/dist/playparser.d.ts.map +1 -0
  167. package/dist/playparser.js +281 -0
  168. package/dist/playparser.js.map +1 -0
  169. package/dist/process.d.ts +4 -0
  170. package/dist/process.d.ts.map +1 -0
  171. package/dist/process.js +375 -0
  172. package/dist/process.js.map +1 -0
  173. package/dist/promptRoutes.d.ts +7 -0
  174. package/dist/promptRoutes.d.ts.map +1 -0
  175. package/dist/promptRoutes.js +68 -0
  176. package/dist/promptRoutes.js.map +1 -0
  177. package/dist/queueManager.d.ts +23 -0
  178. package/dist/queueManager.d.ts.map +1 -0
  179. package/dist/queueManager.js +96 -0
  180. package/dist/queueManager.js.map +1 -0
  181. package/dist/run-flow.d.ts +8 -0
  182. package/dist/run-flow.d.ts.map +1 -0
  183. package/dist/run-flow.js +220 -0
  184. package/dist/run-flow.js.map +1 -0
  185. package/dist/scraper.d.ts +2 -0
  186. package/dist/scraper.d.ts.map +1 -0
  187. package/dist/scraper.js +75 -0
  188. package/dist/scraper.js.map +1 -0
  189. package/dist/scraper_endpoints.d.ts +2 -0
  190. package/dist/scraper_endpoints.d.ts.map +1 -0
  191. package/dist/scraper_endpoints.js +40 -0
  192. package/dist/scraper_endpoints.js.map +1 -0
  193. package/dist/server.d.ts +2 -0
  194. package/dist/server.d.ts.map +1 -0
  195. package/dist/server.js +528 -0
  196. package/dist/server.js.map +1 -0
  197. package/dist/services/ModelContext.d.ts +7 -0
  198. package/dist/services/ModelContext.d.ts.map +1 -0
  199. package/dist/services/ModelContext.js +7 -0
  200. package/dist/services/ModelContext.js.map +1 -0
  201. package/dist/services/agenticUiPlanner.d.ts +27 -0
  202. package/dist/services/agenticUiPlanner.d.ts.map +1 -0
  203. package/dist/services/agenticUiPlanner.js +161 -0
  204. package/dist/services/agenticUiPlanner.js.map +1 -0
  205. package/dist/services/apiKeyService.d.ts +3 -0
  206. package/dist/services/apiKeyService.d.ts.map +1 -0
  207. package/dist/services/apiKeyService.js +7 -0
  208. package/dist/services/apiKeyService.js.map +1 -0
  209. package/dist/services/audioService.d.ts +10 -0
  210. package/dist/services/audioService.d.ts.map +1 -0
  211. package/dist/services/audioService.js +140 -0
  212. package/dist/services/audioService.js.map +1 -0
  213. package/dist/services/autoPromptOptimizer.d.ts +44 -0
  214. package/dist/services/autoPromptOptimizer.d.ts.map +1 -0
  215. package/dist/services/autoPromptOptimizer.js +344 -0
  216. package/dist/services/autoPromptOptimizer.js.map +1 -0
  217. package/dist/services/autoPromptOptimizer.manual-test.d.ts +2 -0
  218. package/dist/services/autoPromptOptimizer.manual-test.d.ts.map +1 -0
  219. package/dist/services/autoPromptOptimizer.manual-test.js +27 -0
  220. package/dist/services/autoPromptOptimizer.manual-test.js.map +1 -0
  221. package/dist/services/chainExecutor.d.ts +26 -0
  222. package/dist/services/chainExecutor.d.ts.map +1 -0
  223. package/dist/services/chainExecutor.js +399 -0
  224. package/dist/services/chainExecutor.js.map +1 -0
  225. package/dist/services/classifyImageQuestion.d.ts +55 -0
  226. package/dist/services/classifyImageQuestion.d.ts.map +1 -0
  227. package/dist/services/classifyImageQuestion.js +428 -0
  228. package/dist/services/classifyImageQuestion.js.map +1 -0
  229. package/dist/services/configuration/executor.d.ts +3 -0
  230. package/dist/services/configuration/executor.d.ts.map +1 -0
  231. package/dist/services/configuration/executor.js +795 -0
  232. package/dist/services/configuration/executor.js.map +1 -0
  233. package/dist/services/error.d.ts +13 -0
  234. package/dist/services/error.d.ts.map +1 -0
  235. package/dist/services/error.js +34 -0
  236. package/dist/services/error.js.map +1 -0
  237. package/dist/services/executor.d.ts +11 -0
  238. package/dist/services/executor.d.ts.map +1 -0
  239. package/dist/services/executor.js +1587 -0
  240. package/dist/services/executor.js.map +1 -0
  241. package/dist/services/extractPdf.d.ts +26 -0
  242. package/dist/services/extractPdf.d.ts.map +1 -0
  243. package/dist/services/extractPdf.js +256 -0
  244. package/dist/services/extractPdf.js.map +1 -0
  245. package/dist/services/generateJsTransformFromPrompt.d.ts +11 -0
  246. package/dist/services/generateJsTransformFromPrompt.d.ts.map +1 -0
  247. package/dist/services/generateJsTransformFromPrompt.js +328 -0
  248. package/dist/services/generateJsTransformFromPrompt.js.map +1 -0
  249. package/dist/services/localizeFirebaseMedia.d.ts +20 -0
  250. package/dist/services/localizeFirebaseMedia.d.ts.map +1 -0
  251. package/dist/services/localizeFirebaseMedia.js +135 -0
  252. package/dist/services/localizeFirebaseMedia.js.map +1 -0
  253. package/dist/services/polyfill_canvas.d.ts +2 -0
  254. package/dist/services/polyfill_canvas.d.ts.map +1 -0
  255. package/dist/services/polyfill_canvas.js +19 -0
  256. package/dist/services/polyfill_canvas.js.map +1 -0
  257. package/dist/services/promptRoutes.d.ts +7 -0
  258. package/dist/services/promptRoutes.d.ts.map +1 -0
  259. package/dist/services/promptRoutes.js +70 -0
  260. package/dist/services/promptRoutes.js.map +1 -0
  261. package/dist/services/runPrompt.d.ts +29 -0
  262. package/dist/services/runPrompt.d.ts.map +1 -0
  263. package/dist/services/runPrompt.js +232 -0
  264. package/dist/services/runPrompt.js.map +1 -0
  265. package/dist/services/schemaInference.d.ts +2 -0
  266. package/dist/services/schemaInference.d.ts.map +1 -0
  267. package/dist/services/schemaInference.js +17 -0
  268. package/dist/services/schemaInference.js.map +1 -0
  269. package/dist/services/self-learning/api.d.ts +2 -0
  270. package/dist/services/self-learning/api.d.ts.map +1 -0
  271. package/dist/services/self-learning/api.js +84 -0
  272. package/dist/services/self-learning/api.js.map +1 -0
  273. package/dist/services/self-learning/autolearn.d.ts +23 -0
  274. package/dist/services/self-learning/autolearn.d.ts.map +1 -0
  275. package/dist/services/self-learning/autolearn.js +308 -0
  276. package/dist/services/self-learning/autolearn.js.map +1 -0
  277. package/dist/services/self-learning/discover.d.ts +11 -0
  278. package/dist/services/self-learning/discover.d.ts.map +1 -0
  279. package/dist/services/self-learning/discover.js +446 -0
  280. package/dist/services/self-learning/discover.js.map +1 -0
  281. package/dist/services/self-learning/image.d.ts +10 -0
  282. package/dist/services/self-learning/image.d.ts.map +1 -0
  283. package/dist/services/self-learning/image.js +38 -0
  284. package/dist/services/self-learning/image.js.map +1 -0
  285. package/dist/services/self-learning/injest.d.ts +25 -0
  286. package/dist/services/self-learning/injest.d.ts.map +1 -0
  287. package/dist/services/self-learning/injest.js +110 -0
  288. package/dist/services/self-learning/injest.js.map +1 -0
  289. package/dist/services/self-learning/learn.d.ts +2 -0
  290. package/dist/services/self-learning/learn.d.ts.map +1 -0
  291. package/dist/services/self-learning/learn.js +145 -0
  292. package/dist/services/self-learning/learn.js.map +1 -0
  293. package/dist/services/self-learning/matcher.d.ts +2 -0
  294. package/dist/services/self-learning/matcher.d.ts.map +1 -0
  295. package/dist/services/self-learning/matcher.js +38 -0
  296. package/dist/services/self-learning/matcher.js.map +1 -0
  297. package/dist/services/self-learning/openai.d.ts +8 -0
  298. package/dist/services/self-learning/openai.d.ts.map +1 -0
  299. package/dist/services/self-learning/openai.js +97 -0
  300. package/dist/services/self-learning/openai.js.map +1 -0
  301. package/dist/services/self-learning/phash.d.ts +5 -0
  302. package/dist/services/self-learning/phash.d.ts.map +1 -0
  303. package/dist/services/self-learning/phash.js +68 -0
  304. package/dist/services/self-learning/phash.js.map +1 -0
  305. package/dist/services/self-learning/recognize.d.ts +17 -0
  306. package/dist/services/self-learning/recognize.d.ts.map +1 -0
  307. package/dist/services/self-learning/recognize.js +116 -0
  308. package/dist/services/self-learning/recognize.js.map +1 -0
  309. package/dist/services/self-learning/record_transition.d.ts +8 -0
  310. package/dist/services/self-learning/record_transition.d.ts.map +1 -0
  311. package/dist/services/self-learning/record_transition.js +20 -0
  312. package/dist/services/self-learning/record_transition.js.map +1 -0
  313. package/dist/services/self-learning/registry.d.ts +4 -0
  314. package/dist/services/self-learning/registry.d.ts.map +1 -0
  315. package/dist/services/self-learning/registry.js +19 -0
  316. package/dist/services/self-learning/registry.js.map +1 -0
  317. package/dist/services/self-learning/schema.d.ts +114 -0
  318. package/dist/services/self-learning/schema.d.ts.map +1 -0
  319. package/dist/services/self-learning/schema.js +70 -0
  320. package/dist/services/self-learning/schema.js.map +1 -0
  321. package/dist/services/self-learning/schemaStrictify.d.ts +2 -0
  322. package/dist/services/self-learning/schemaStrictify.d.ts.map +1 -0
  323. package/dist/services/self-learning/schemaStrictify.js +34 -0
  324. package/dist/services/self-learning/schemaStrictify.js.map +1 -0
  325. package/dist/services/self-learning/transition_graph.d.ts +6 -0
  326. package/dist/services/self-learning/transition_graph.d.ts.map +1 -0
  327. package/dist/services/self-learning/transition_graph.js +83 -0
  328. package/dist/services/self-learning/transition_graph.js.map +1 -0
  329. package/dist/services/self-learning/transition_log.d.ts +3 -0
  330. package/dist/services/self-learning/transition_log.d.ts.map +1 -0
  331. package/dist/services/self-learning/transition_log.js +42 -0
  332. package/dist/services/self-learning/transition_log.js.map +1 -0
  333. package/dist/services/self-learning/util.d.ts +3 -0
  334. package/dist/services/self-learning/util.d.ts.map +1 -0
  335. package/dist/services/self-learning/util.js +11 -0
  336. package/dist/services/self-learning/util.js.map +1 -0
  337. package/dist/services/stepByStepAiPlanner.d.ts +39 -0
  338. package/dist/services/stepByStepAiPlanner.d.ts.map +1 -0
  339. package/dist/services/stepByStepAiPlanner.js +379 -0
  340. package/dist/services/stepByStepAiPlanner.js.map +1 -0
  341. package/dist/services/test-genjs.js +39 -0
  342. package/dist/services/test-genjs.manual-test.d.ts +2 -0
  343. package/dist/services/test-genjs.manual-test.d.ts.map +1 -0
  344. package/dist/services/test-genjs.manual-test.js +40 -0
  345. package/dist/services/test-genjs.manual-test.js.map +1 -0
  346. package/dist/services/uiMapPathFinder.d.ts +13 -0
  347. package/dist/services/uiMapPathFinder.d.ts.map +1 -0
  348. package/dist/services/uiMapPathFinder.js +79 -0
  349. package/dist/services/uiMapPathFinder.js.map +1 -0
  350. package/dist/services/uiMapService.d.ts +26 -0
  351. package/dist/services/uiMapService.d.ts.map +1 -0
  352. package/dist/services/uiMapService.js +275 -0
  353. package/dist/services/uiMapService.js.map +1 -0
  354. package/dist/services/uiPlanner.d.ts +54 -0
  355. package/dist/services/uiPlanner.d.ts.map +1 -0
  356. package/dist/services/uiPlanner.js +558 -0
  357. package/dist/services/uiPlanner.js.map +1 -0
  358. package/dist/services/utilityFunctions.d.ts +80 -0
  359. package/dist/services/utilityFunctions.d.ts.map +1 -0
  360. package/dist/services/utilityFunctions.js +352 -0
  361. package/dist/services/utilityFunctions.js.map +1 -0
  362. package/dist/services/variableGenerator.d.ts +39 -0
  363. package/dist/services/variableGenerator.d.ts.map +1 -0
  364. package/dist/services/variableGenerator.js +157 -0
  365. package/dist/services/variableGenerator.js.map +1 -0
  366. package/dist/services/workflow/build-workflow.d.ts +49 -0
  367. package/dist/services/workflow/build-workflow.d.ts.map +1 -0
  368. package/dist/services/workflow/build-workflow.js +119 -0
  369. package/dist/services/workflow/build-workflow.js.map +1 -0
  370. package/dist/standardRoutes.d.ts +2 -0
  371. package/dist/standardRoutes.d.ts.map +1 -0
  372. package/dist/standardRoutes.js +1495 -0
  373. package/dist/standardRoutes.js.map +1 -0
  374. package/dist/stepWorkflowRoutes.d.ts +2 -0
  375. package/dist/stepWorkflowRoutes.d.ts.map +1 -0
  376. package/dist/stepWorkflowRoutes.js +1007 -0
  377. package/dist/stepWorkflowRoutes.js.map +1 -0
  378. package/dist/storage.d.ts +19 -0
  379. package/dist/storage.d.ts.map +1 -0
  380. package/dist/storage.docker.json +61 -0
  381. package/dist/storage.js +131 -0
  382. package/dist/storage.js.map +1 -0
  383. package/dist/storage.json +78 -0
  384. package/dist/storage_cache/boxes.json +48 -0
  385. package/dist/storage_cache/suno_state.json +3 -0
  386. package/dist/suno_download.d.ts +11 -0
  387. package/dist/suno_download.d.ts.map +1 -0
  388. package/dist/suno_download.js +33 -0
  389. package/dist/suno_download.js.map +1 -0
  390. package/dist/suno_download.py +119 -0
  391. package/dist/test-web-element-requests.d.ts +6 -0
  392. package/dist/test-web-element-requests.d.ts.map +1 -0
  393. package/dist/test-web-element-requests.js +114 -0
  394. package/dist/test-web-element-requests.js.map +1 -0
  395. package/dist/test_pdf_render.d.ts +2 -0
  396. package/dist/test_pdf_render.d.ts.map +1 -0
  397. package/dist/test_pdf_render.js +50 -0
  398. package/dist/test_pdf_render.js.map +1 -0
  399. package/dist/training_data_viewer_endpoints.d.ts +2 -0
  400. package/dist/training_data_viewer_endpoints.d.ts.map +1 -0
  401. package/dist/training_data_viewer_endpoints.js +141 -0
  402. package/dist/training_data_viewer_endpoints.js.map +1 -0
  403. package/dist/utils.d.ts +353 -0
  404. package/dist/utils.d.ts.map +1 -0
  405. package/dist/utils.js +1517 -0
  406. package/dist/utils.js.map +1 -0
  407. package/dist/vm-h100.env.template +55 -0
  408. package/dist/web-element-requests.d.ts +102 -0
  409. package/dist/web-element-requests.d.ts.map +1 -0
  410. package/dist/web-element-requests.js +278 -0
  411. package/dist/web-element-requests.js.map +1 -0
  412. package/dist/workflowRoutes.d.ts +2 -0
  413. package/dist/workflowRoutes.d.ts.map +1 -0
  414. package/dist/workflowRoutes.js +441 -0
  415. package/dist/workflowRoutes.js.map +1 -0
  416. package/package.json +109 -0
@@ -0,0 +1,1587 @@
1
+ import { runPrompt } from './runPrompt.js';
2
+ import { getUtilityFunctions } from './utilityFunctions.js';
3
+ import { NodeExecutionState } from './ModelContext.js';
4
+ import { executeConfiguration, executeStep } from './configuration/executor.js';
5
+ import FilterGmailPoller from '../filter-gmail-poller/filter-gmail-poller.js';
6
+ import { safeExtractJSON } from '../jsonHandler.js';
7
+ import { get, pause } from '../utils.js';
8
+ import { MULTI_TASK_PROMPT_VALIDATION, POLLER_PROMPT_FILTER, validateMultiTaskPromptOutput } from '../filter-gmail-poller/poller-prompts.js';
9
+ import { extractGmailBodyText } from '../email-body-extractor.js';
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import { createTaskConfig, DEFAULT_MODEL, runAutoPromptSearch } from './autoPromptOptimizer.js';
13
+ import { fileToDataUrl } from './self-learning/image.js';
14
+ import { KEYS } from '../constants.js';
15
+ import { generateUIMap } from './uiMapService.js';
16
+ import { StepByStepAiPlanner } from './stepByStepAiPlanner.js';
17
+ import { UiMapPathFinder } from './uiMapPathFinder.js';
18
+ import { executeChain } from './chainExecutor.js';
19
+ export function computeExecutionOrder(nodes, edges) {
20
+ // Build a quick lookup of which node IDs actually exist
21
+ const nodeIds = new Set(nodes.map(n => n.id));
22
+ // 1a) Drop any edges whose source or target node has been removed
23
+ const validEdges = edges.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target));
24
+ // ─── ORIGINAL STEPS, BUT USING validEdges ───────────────────────────────────
25
+ // 1b) Filter out the loop-back edges from the body back into the loop node
26
+ const acyclicEdges = validEdges.filter(e => e.targetHandle !== 'bodyIn');
27
+ // 2) Build indegree map & adjacency using only acyclicEdges
28
+ const indegree = new Map(nodes.map(n => [n.id, 0]));
29
+ const adj = new Map(nodes.map(n => [n.id, []]));
30
+ acyclicEdges.forEach(e => {
31
+ adj.get(e.source).push(e.target);
32
+ indegree.set(e.target, (indegree.get(e.target) || 0) + 1);
33
+ });
34
+ // 3) Initialize queue with zero-indegree nodes
35
+ const queue = Array.from(indegree.entries())
36
+ .filter(([, d]) => d === 0)
37
+ .map(([id]) => id);
38
+ // 4) Kahn’s algorithm
39
+ const sorted = [];
40
+ const nodeMap = new Map(nodes.map(n => [n.id, n]));
41
+ while (queue.length) {
42
+ const id = queue.shift();
43
+ // only push nodes that still exist
44
+ const node = nodeMap.get(id);
45
+ if (node)
46
+ sorted.push(node);
47
+ for (const nbr of adj.get(id) || []) {
48
+ indegree.set(nbr, indegree.get(nbr) - 1);
49
+ if (indegree.get(nbr) === 0) {
50
+ queue.push(nbr);
51
+ }
52
+ }
53
+ }
54
+ return sorted;
55
+ }
56
+ /**
57
+ * Returns the subgraph consisting of all nodes/edges reachable
58
+ * from startId, including startId itself.
59
+ */
60
+ export function getSubgraph(startId, nodes, edges) {
61
+ if (!startId) {
62
+ return { nodes: [], edges: [] };
63
+ }
64
+ // 1️⃣ Start with the startId node itself
65
+ const seen = new Set([startId]);
66
+ const queue = [startId];
67
+ // 2️⃣ BFS to find all reachable nodes
68
+ while (queue.length) {
69
+ const id = queue.shift();
70
+ for (const e of edges) {
71
+ if (e.source === id && !seen.has(e.target)) {
72
+ seen.add(e.target);
73
+ queue.push(e.target);
74
+ }
75
+ }
76
+ }
77
+ // 3️⃣ Filter to only include reachable nodes & edges
78
+ const subNodes = nodes.filter((n) => seen.has(n.id));
79
+ const subEdges = edges.filter((e) => seen.has(e.source) && seen.has(e.target));
80
+ return { nodes: subNodes, edges: subEdges };
81
+ }
82
+ /**
83
+ * Extracts and parses the first JSON code‐fence in a string.
84
+ *
85
+ * @param {string} text The text containing a ```json … ``` block.
86
+ * @returns {any} The parsed JavaScript value.
87
+ * @throws {Error} If no JSON fence is found or JSON is invalid.
88
+ */
89
+ function extractJSONFrom(text) {
90
+ // This regex looks for ```json, then lazily captures everything up to the next ```
91
+ const fenceRE = /```json\s*([\s\S]*?)\s*```/i;
92
+ const match = text.match(fenceRE);
93
+ if (!match) {
94
+ try {
95
+ return JSON.parse(text);
96
+ }
97
+ catch (e) {
98
+ console.log(text);
99
+ }
100
+ throw new Error("No ```json … ``` block found");
101
+ }
102
+ const jsonString = match[1];
103
+ try {
104
+ return JSON.parse(jsonString);
105
+ }
106
+ catch (err) {
107
+ throw new Error("Invalid JSON inside code fence: " + err.message);
108
+ }
109
+ }
110
+ function saveNodeContext(ctx, inputs = {}) {
111
+ try {
112
+ const contextFile = path.join(process.cwd(), 'node_context.ndjson');
113
+ const contextEntry = {
114
+ timestamp: new Date().toISOString(),
115
+ context: ctx,
116
+ inputs: inputs
117
+ };
118
+ const jsonLine = JSON.stringify(contextEntry) + '\n';
119
+ fs.appendFileSync(contextFile, jsonLine);
120
+ }
121
+ catch (err) {
122
+ console.error('Error saving node context:', err);
123
+ }
124
+ }
125
+ function saveNodeValues(ctx, inputs = {}) {
126
+ try {
127
+ const valuesFile = path.join(process.cwd(), 'node_values.ndjson');
128
+ // Read existing values if file exists
129
+ let existingValues = new Map();
130
+ if (fs.existsSync(valuesFile)) {
131
+ const lines = fs.readFileSync(valuesFile, 'utf8').trim().split('\n');
132
+ for (const line of lines) {
133
+ try {
134
+ const entry = JSON.parse(line);
135
+ existingValues.set(entry.nodeId, entry);
136
+ }
137
+ catch (e) {
138
+ // Skip malformed lines
139
+ }
140
+ }
141
+ }
142
+ // Update with new values from ctx
143
+ for (const [nodeId, value] of Object.entries(ctx)) {
144
+ existingValues.set(nodeId, {
145
+ nodeId,
146
+ value,
147
+ input: inputs[nodeId],
148
+ timestamp: new Date().toISOString()
149
+ });
150
+ }
151
+ // Write all values back to file
152
+ const allEntries = Array.from(existingValues.values());
153
+ const content = allEntries.map(entry => JSON.stringify(entry)).join('\n') + '\n';
154
+ fs.writeFileSync(valuesFile, content);
155
+ }
156
+ catch (err) {
157
+ console.error('Error saving node values:', err);
158
+ }
159
+ }
160
+ export async function executeFlow(nodes, edges, workflows, modelContext, initialCtx = {}, callback, globalContext = {}) {
161
+ const sorted = computeExecutionOrder(nodes, edges);
162
+ const ctx = { ...initialCtx }; // start from seed
163
+ const inputs = {}; // Track inputs for each node
164
+ for (const node of sorted) {
165
+ const incoming = edges.find((e) => e.target === node.id);
166
+ const input = incoming ? ctx[incoming.source] : undefined;
167
+ const getHandleVal = (id) => {
168
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
169
+ if (e) {
170
+ let sourceNode = nodes.find(node => node.id === e.source);
171
+ if (ctx?.[e.source]) {
172
+ return ctx?.[e.source];
173
+ }
174
+ else if (sourceNode && e.sourceHandle) {
175
+ return sourceNode.data?.[e.sourceHandle];
176
+ }
177
+ }
178
+ return undefined;
179
+ };
180
+ // Store input for this node
181
+ inputs[node.id] = input;
182
+ try {
183
+ if (callback) {
184
+ callback(node.id, {
185
+ state: NodeExecutionState.Running,
186
+ message: `Executing ${node.type}...`
187
+ });
188
+ }
189
+ switch (node.type) {
190
+ case 'setNode': {
191
+ const data = node.data;
192
+ const key = data.key;
193
+ let valueToSet = undefined;
194
+ // If no value provided, try to get from input
195
+ const inEdge = edges.find(e => e.target === node.id && e.targetHandle === 'in');
196
+ if (inEdge) {
197
+ valueToSet = ctx[inEdge.source];
198
+ }
199
+ else {
200
+ valueToSet = input;
201
+ }
202
+ if (valueToSet === undefined) {
203
+ valueToSet = data.value;
204
+ }
205
+ if (valueToSet === undefined) {
206
+ throw new Error(`No value provided for SetNode ${node.id}`);
207
+ }
208
+ modelContext[key] = valueToSet;
209
+ ctx[node.id] = valueToSet;
210
+ break;
211
+ }
212
+ case 'getNode': {
213
+ const data = node.data;
214
+ const selectedKey = data.selectedKey;
215
+ if (!selectedKey) {
216
+ throw new Error(`No key selected for GetNode ${node.id}`);
217
+ }
218
+ const value = modelContext[selectedKey];
219
+ ctx[node.id] = value;
220
+ data.value = value;
221
+ data.lastFetched = new Date().toISOString();
222
+ break;
223
+ }
224
+ case 'promptNode': {
225
+ const sysEdge = edges.find(e => e.target === node.id && e.targetHandle === 'system');
226
+ const usrEdge = edges.find(e => e.target === node.id && e.targetHandle === 'user');
227
+ const imgEdge = edges.find(e => e.target === node.id && e.targetHandle === 'images');
228
+ const systemPrompt = sysEdge
229
+ ? ctx[sysEdge.source]
230
+ : node.data.systemPrompt;
231
+ const userPrompt = usrEdge
232
+ ? ctx[usrEdge.source]
233
+ : node.data.userPrompt;
234
+ let images = [];
235
+ if (imgEdge) {
236
+ const val = ctx[imgEdge.source];
237
+ if (Array.isArray(val))
238
+ images = val;
239
+ else if (typeof val === 'string')
240
+ images = val.split(',').map(s => s.trim()).filter(Boolean);
241
+ }
242
+ else if (node.data.images) {
243
+ images = node.data.images.split(',').map(s => s.trim()).filter(Boolean);
244
+ }
245
+ // Convert file paths to data URLs
246
+ const processedImages = images.map((img) => {
247
+ if (img.startsWith('http://') || img.startsWith('https://') || img.startsWith('data:')) {
248
+ return img;
249
+ }
250
+ try {
251
+ return fileToDataUrl(img);
252
+ }
253
+ catch (e) {
254
+ console.warn(`Could not convert image path to data URL: ${img}`, e.message);
255
+ return img;
256
+ }
257
+ });
258
+ // console.log(`System Prompt: ${systemPrompt}`);
259
+ console.log(`User Prompt: ${userPrompt}`);
260
+ const model = node.data.model;
261
+ const fullPrompt = [
262
+ { role: 'system', content: systemPrompt },
263
+ { role: 'user', content: userPrompt }
264
+ ];
265
+ const out = await runPrompt(fullPrompt, model, processedImages);
266
+ // parse or raw
267
+ try {
268
+ ctx[node.id] = extractJSONFrom(out);
269
+ }
270
+ catch {
271
+ ctx[node.id] = out;
272
+ }
273
+ break;
274
+ }
275
+ case 'switchNode': {
276
+ const data = node.data;
277
+ const switchValue = input;
278
+ let matched = false;
279
+ for (const switchCase of data.cases) {
280
+ if (switchValue === switchCase.matchText) {
281
+ let switchCaseValue = getHandleVal(`case-${switchCase.id}`);
282
+ ctx[node.id] = switchCaseValue;
283
+ matched = true;
284
+ break;
285
+ }
286
+ }
287
+ if (!matched) {
288
+ ctx[node.id] = getHandleVal(`default`) || undefined;
289
+ }
290
+ break;
291
+ }
292
+ case 'propertyNode': {
293
+ const obj = input;
294
+ const path = node.data.property.split('.');
295
+ ctx[node.id] = path.reduce((o, k) => o?.[k], obj);
296
+ break;
297
+ }
298
+ case 'arrayItemNode': {
299
+ const arr = input;
300
+ const idx = node.data.index;
301
+ ctx[node.id] = Array.isArray(arr) ? arr[idx] : undefined;
302
+ break;
303
+ }
304
+ case 'inputArrayNode': {
305
+ const data = node.data;
306
+ let arr = data.parsed;
307
+ if (!Array.isArray(arr)) {
308
+ try {
309
+ arr = extractJSONFrom(data.raw);
310
+ }
311
+ catch {
312
+ arr = [];
313
+ }
314
+ }
315
+ ctx[node.id] = arr;
316
+ break;
317
+ }
318
+ case 'fetchNode': {
319
+ // 1️⃣ Destructure new options
320
+ const { url, method, responseType, timeoutMinutes = 10 } = node.data;
321
+ // 2️⃣ Determine request body: manual or from "body" handle
322
+ const bodyEdge = edges.find((e) => e.target === node.id && e.targetHandle === 'body');
323
+ let requestBody = node.data.body;
324
+ if (bodyEdge) {
325
+ requestBody = ctx[bodyEdge.source];
326
+ }
327
+ try {
328
+ // 3️⃣ Build RequestInit with method and optional body
329
+ const init = { method };
330
+ if (method !== 'GET' && method !== 'HEAD' && requestBody != null) {
331
+ const bodyString = typeof requestBody === 'string'
332
+ ? requestBody
333
+ : JSON.stringify(requestBody);
334
+ init.body = bodyString;
335
+ init.headers = { 'Content-Type': 'application/json' };
336
+ }
337
+ // 4️⃣ Add timeout controller (configurable, default 10 minutes)
338
+ const controller = new AbortController();
339
+ const timeoutMs = (timeoutMinutes || 10) * 60 * 1000; // Convert minutes to milliseconds
340
+ console.log(`Fetch timeout set to ${timeoutMs} ms for node ${node.id}`);
341
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
342
+ init.signal = controller.signal;
343
+ init.headersTimeout = 0; // Disable headers timeout to prevent premature failures
344
+ // 5️⃣ Execute fetch and parse based on responseType
345
+ const res = await fetch(modelContext.defaultServer + url, init);
346
+ clearTimeout(timeoutId); // Clear timeout on success
347
+ let val;
348
+ if (responseType === 'json') {
349
+ val = await res.json();
350
+ }
351
+ else {
352
+ const text = await res.text();
353
+ try {
354
+ val = JSON.parse(text);
355
+ }
356
+ catch {
357
+ val = text;
358
+ }
359
+ }
360
+ // 6️⃣ Store result in context
361
+ ctx[node.id] = val;
362
+ }
363
+ catch (err) {
364
+ ctx[node.id] = undefined;
365
+ // Handle timeout errors specifically
366
+ if (err.name === 'AbortError') {
367
+ throw new Error(`Fetch request timed out after ${timeoutMinutes || 10} minutes for URL: ${modelContext.defaultServer + url}`);
368
+ }
369
+ throw err;
370
+ }
371
+ break;
372
+ }
373
+ case 'pauseNode': {
374
+ // Check for seconds input from handle
375
+ const secondsEdge = edges.find((e) => e.target === node.id && e.targetHandle === 'seconds');
376
+ let seconds = node.data.seconds || 0;
377
+ if (secondsEdge) {
378
+ const sourceValue = ctx[secondsEdge.source];
379
+ if (typeof sourceValue === 'number') {
380
+ seconds = sourceValue;
381
+ }
382
+ else if (typeof sourceValue === 'string') {
383
+ seconds = parseInt(sourceValue, 10) || 0;
384
+ }
385
+ }
386
+ console.log(`Pausing for ${seconds} seconds in node ${node.id}`);
387
+ await new Promise(resolve => setTimeout(resolve, seconds * 1000));
388
+ ctx[node.id] = input; // Pass through the input
389
+ break;
390
+ }
391
+ case 'autoPromptOptimizerNode':
392
+ {
393
+ const getVal = (id) => {
394
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
395
+ if (e) {
396
+ let sourceNode = nodes.find(node => node.id === e.source);
397
+ if (ctx?.[e.source]) {
398
+ return ctx?.[e.source];
399
+ }
400
+ else if (sourceNode && e.sourceHandle) {
401
+ return sourceNode.data?.[e.sourceHandle];
402
+ }
403
+ }
404
+ return undefined;
405
+ };
406
+ const testConfig = createTaskConfig({
407
+ name: getVal('name') || node.data.name || 'demo_email_extraction',
408
+ taskDescription: getVal('taskDescription') || node.data.taskDescription || 'Extract a simple structured meeting request from an email body.',
409
+ outputFormatDescription: getVal('outputFormatDescription') || node.data.outputFormatDescription || 'Return a JSON object with keys action, person, and datetime. Output ONLY JSON.',
410
+ dataset: getVal('dataset') || node.data.dataset || []
411
+ });
412
+ const { bestPrompt, allResults } = await runAutoPromptSearch(testConfig, {
413
+ maxIterations: getVal('maxIterations') || node.data.maxIterations || 5,
414
+ promptsPerRound: getVal('promptsPerRound') || node.data.promptsPerRound || 10,
415
+ topPromptsToFeedBack: getVal('topPromptsToFeedBack') || node.data.topPromptsToFeedBack || 3,
416
+ model: getVal('model') || node.data.model || 'gpt-4'
417
+ });
418
+ ctx[node.id] = {
419
+ bestPrompt,
420
+ allResults
421
+ };
422
+ }
423
+ break;
424
+ case 'gmailNode':
425
+ {
426
+ let poller = FilterGmailPoller.instance;
427
+ if (poller) {
428
+ // Set filter configuration before stepping through emails
429
+ if (node.data.subjectPrefix) {
430
+ console.log(`PollerNode: Setting filter configuration:`, node.data.subjectPrefix);
431
+ await poller.updateFilterConfig({ subjectPrefix: node.data.subjectPrefix });
432
+ }
433
+ else {
434
+ console.log(`PollerNode: Using existing filter configuration`);
435
+ }
436
+ if (node.data.labelNames && node.data.labelNames.length > 0) {
437
+ console.log(`PollerNode: Setting label IDs:`, node.data.labelNames);
438
+ await poller.updateFilterConfig({ labelNames: node.data.labelNames });
439
+ }
440
+ console.log(`PollerNode: Stepping through emails manually (not continuous polling)`);
441
+ // Step through emails manually instead of continuous polling
442
+ const emailResult = await poller.stepThroughEmails({
443
+ maxResults: 10, // Process up to 10 emails at a time
444
+ includeDetails: true // Get full email details
445
+ });
446
+ console.log(`Found ${emailResult.totalMessages} emails to process`);
447
+ let emails = [];
448
+ for (let email of emailResult.messages) {
449
+ console.log(`Processing email: ${email.id}`);
450
+ const emailBody = extractGmailBodyText(email);
451
+ const subject = poller.getEmailSubject(email);
452
+ emails.push({ id: email.id, body: emailBody, subject });
453
+ }
454
+ ctx[node.id] = emails;
455
+ }
456
+ }
457
+ break;
458
+ case 'pollerNode': {
459
+ let pollerNodeResults = [];
460
+ console.log(`Executing PollerNode ${node.id}`);
461
+ // PollerNode does not produce output directly, it will execute the nodes connected to it.
462
+ const getVal = (id) => {
463
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
464
+ if (e) {
465
+ let sourceNode = nodes.find(node => node.id === e.source);
466
+ if (ctx?.[e.source]) {
467
+ return ctx?.[e.source];
468
+ }
469
+ else if (sourceNode && e.sourceHandle) {
470
+ return sourceNode.data?.[e.sourceHandle];
471
+ }
472
+ }
473
+ return undefined;
474
+ };
475
+ let poller = FilterGmailPoller.instance;
476
+ const enableContinuous = node.data.enableContinuous;
477
+ do {
478
+ if (poller) {
479
+ // Set filter configuration before stepping through emails
480
+ if (node.data.subjectPrefix) {
481
+ console.log(`PollerNode: Setting filter configuration:`, node.data.subjectPrefix);
482
+ await poller.updateFilterConfig({ subjectPrefix: node.data.subjectPrefix });
483
+ }
484
+ else {
485
+ console.log(`PollerNode: Using existing filter configuration`);
486
+ }
487
+ if (node.data.labelNames && node.data.labelNames.length > 0) {
488
+ console.log(`PollerNode: Setting label IDs:`, node.data.labelNames);
489
+ await poller.updateFilterConfig({ labelNames: node.data.labelNames });
490
+ }
491
+ console.log(`PollerNode: Stepping through emails manually (not continuous polling)`);
492
+ // Step through emails manually instead of continuous polling
493
+ const emailResult = await poller.stepThroughEmails({
494
+ maxResults: 10, // Process up to 10 emails at a time
495
+ includeDetails: true // Get full email details
496
+ });
497
+ console.log(`Found ${emailResult.totalMessages} emails to process`);
498
+ for (let email of emailResult.messages) {
499
+ console.log(`Processing email: ${email.id}`);
500
+ const emailBody = extractGmailBodyText(email);
501
+ const subject = poller.getEmailSubject(email);
502
+ console.log('------------------------------ Email ------------------------------');
503
+ console.log(emailBody);
504
+ console.log('------------------------------ End ------------------------------');
505
+ try {
506
+ const connectedLetters = [];
507
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').forEach((handle, index) => {
508
+ if (node?.data?.inputs) {
509
+ const entries = Object.entries(node.data.inputs);
510
+ if (entries) {
511
+ let temp = entries.find(([key, val]) => {
512
+ return val?.label === handle;
513
+ });
514
+ const value = getVal(temp?.[0]);
515
+ const graph = temp?.[1]?.graph;
516
+ if (value !== undefined && graph) {
517
+ ctx[node.id] = ctx[node.id] || {};
518
+ ctx[node.id][handle] = value;
519
+ connectedLetters.push({
520
+ handle,
521
+ input_id: temp?.[0],
522
+ graph: graph
523
+ });
524
+ }
525
+ }
526
+ }
527
+ });
528
+ // Now execute the subgraph for each connected letter
529
+ console.log(`PollerNode executing subgraph for letters:`);
530
+ let matchingOptions = [];
531
+ for (const cl of connectedLetters) {
532
+ const { handle, input_id, output_id } = cl;
533
+ const { text } = ctx[node.id][handle];
534
+ const fullPrompt = [
535
+ { role: 'system', content: POLLER_PROMPT_FILTER },
536
+ {
537
+ role: 'user',
538
+ content: JSON.stringify({
539
+ email: `Subject: ${subject} \n\n Body: ${emailBody}`,
540
+ taskDescription: text
541
+ })
542
+ }
543
+ ];
544
+ let res = await runPrompt(fullPrompt, node.data.llmModel || 'gpt-4');
545
+ let safeRes = safeExtractJSON(res);
546
+ if (safeRes) {
547
+ const { result, explanation } = safeRes;
548
+ console.log(`PollerNode ${handle} got result: ${result}`);
549
+ console.log(`PollerNode ${handle} got explanation: ${explanation}`);
550
+ if (result === 'MATCH') {
551
+ matchingOptions.push({
552
+ letter: handle,
553
+ result,
554
+ explanation,
555
+ text
556
+ });
557
+ }
558
+ }
559
+ }
560
+ if (matchingOptions.length > 1) {
561
+ let temp = {};
562
+ matchingOptions.forEach(mo => {
563
+ temp[mo.letter] = mo.text;
564
+ });
565
+ const checkMultiMatches = [
566
+ { role: 'system', content: MULTI_TASK_PROMPT_VALIDATION },
567
+ { role: 'user', content: JSON.stringify(temp) }
568
+ ];
569
+ let res = await runPrompt(checkMultiMatches, node.data.llmModel || 'gpt-4');
570
+ let safeRes = safeExtractJSON(res);
571
+ const { isValid, errors } = validateMultiTaskPromptOutput(safeRes, Object.keys(temp));
572
+ if (!isValid) {
573
+ console.error(`Multi-task prompt validation failed for email ${email.id}:`, errors);
574
+ }
575
+ else {
576
+ if (res?.decisions) {
577
+ matchingOptions = matchingOptions.filter(mo => res.decisions[mo.letter]);
578
+ console.log(`Filtered matching options: ${JSON.stringify(matchingOptions)} with multi-task validation ${JSON.stringify(res.decisions)}`);
579
+ }
580
+ }
581
+ }
582
+ if (matchingOptions.length > 0) {
583
+ // Execute selected graph
584
+ let { letter } = matchingOptions[0];
585
+ let connected = connectedLetters.find(x => x.handle === letter);
586
+ if (connected?.graph) {
587
+ console.log(`Executing graph: ${connected.graph} for letter ${letter}`);
588
+ // Load the graph configuration
589
+ const graphData = await fetch(modelContext.defaultServer + `/loadConfiguration?name=${encodeURIComponent(connected.graph)}`).then((r) => r.json());
590
+ if (graphData) {
591
+ const { nodes: graphNodes, edges: graphEdges } = graphData;
592
+ console.log(graphData);
593
+ // Inject the email data into the graph
594
+ const seedCtx = { email: { body: emailBody, subject }, item: { body: emailBody, subject } };
595
+ console.log('Executing subgraph with seedCtx:', seedCtx);
596
+ let res = await executeFlow(graphNodes, graphEdges, workflows, modelContext, seedCtx, callback, globalContext);
597
+ console.log(res);
598
+ pollerNodeResults.push(res);
599
+ }
600
+ else {
601
+ console.log(`Failed to load graph: ${connected.graph}`);
602
+ }
603
+ }
604
+ else {
605
+ throw new Error(`Connected letter ${letter} has no graph selected`);
606
+ }
607
+ }
608
+ else {
609
+ console.log(`PollerNode got no valid response for email ${email.id}`);
610
+ }
611
+ // After processing, move email to "processed" folder
612
+ if (node.data.removeEmails) {
613
+ // If removeEmails is true, delete the email instead of moving
614
+ await poller.moveEmailToFolder(email.id, 'processed');
615
+ }
616
+ }
617
+ catch (emailError) {
618
+ console.error(`Error processing email ${email.id}:`, emailError);
619
+ // Still try to move to processed folder even if processing failed
620
+ try {
621
+ if (node.data.removeEmails) {
622
+ // If removeEmails is true, delete the email instead of moving
623
+ await poller.moveEmailToFolder(email.id, 'processed');
624
+ }
625
+ }
626
+ catch (moveError) {
627
+ console.error(`Failed to move email ${email.id} to processed folder:`, moveError);
628
+ }
629
+ }
630
+ }
631
+ console.log(`PollerNode completed processing ${emailResult.totalMessages} emails`);
632
+ }
633
+ await pause(() => {
634
+ console.log(`Pausing for 10 seconds...`);
635
+ }, 10000);
636
+ } while (enableContinuous);
637
+ ctx[node.id] = pollerNodeResults || [];
638
+ break;
639
+ }
640
+ case 'smartAutomationNode':
641
+ {
642
+ // SmartAutomationNode executes a predefined smart automation workflow
643
+ const getVal = (id) => {
644
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
645
+ if (e) {
646
+ let sourceNode = nodes.find(node => node.id === e.source);
647
+ if (ctx?.[e.source]) {
648
+ return ctx?.[e.source];
649
+ }
650
+ else if (sourceNode && e.sourceHandle) {
651
+ return sourceNode.data?.[e.sourceHandle];
652
+ }
653
+ }
654
+ return undefined;
655
+ };
656
+ const input = getVal('input');
657
+ const automationName = node.data.workflow;
658
+ const automationWorkflow = workflows.find(wf => {
659
+ return wf.workflow.name === automationName || wf.workflow.id === automationName;
660
+ });
661
+ if (!automationWorkflow) {
662
+ throw new Error(`Smart Automation workflow not found: ${automationName}`);
663
+ }
664
+ console.log(`Executing SmartAutomationNode ${node.id} with workflow ${automationName}`);
665
+ let result = await executeConfiguration(automationWorkflow, node.data, ctx, { inputs: input }, workflows);
666
+ console.log(`SmartAutomationNode ${node.id} executed automation ${automationName}:`, result);
667
+ ctx[node.id] = result || {};
668
+ break;
669
+ }
670
+ break;
671
+ case 'workflowNode': {
672
+ // 1. Find input edges by handle id
673
+ const getVal = (id) => {
674
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
675
+ if (e) {
676
+ let sourceNode = nodes.find(node => node.id === e.source);
677
+ if (ctx?.[e.source]) {
678
+ return ctx?.[e.source];
679
+ }
680
+ else if (sourceNode && e.sourceHandle) {
681
+ return sourceNode.data?.[e.sourceHandle];
682
+ }
683
+ }
684
+ return undefined;
685
+ };
686
+ const a = getVal('a'), b = getVal('b'), c = getVal('c');
687
+ // 2. Get utility functions
688
+ const workflow = workflows.find(wf => {
689
+ console.log(wf);
690
+ return wf.workflow.id === node.data.workflow || wf.workflow.id === node.data.workflowName;
691
+ });
692
+ if (!workflow) {
693
+ console.log(`There are ${workflows.length} workflows loaded:`);
694
+ console.log(workflows.map(d => `${d.workflow.id}=> ${d.workflow.name}`).join('\n'));
695
+ throw new Error(`Workflow not found: ${node.data.workflow}`);
696
+ }
697
+ let result = await executeConfiguration(workflow, node.data, ctx, { a, b, c }, workflows);
698
+ console.log(`WorkflowNode ${node.id} executed workflow ${node.data.workflow}:`, result);
699
+ ctx[node.id] = result || {};
700
+ break;
701
+ }
702
+ case 'uiPlannerExecNode':
703
+ {
704
+ // Takes the plan from a UiPlannerNode and executes the steps
705
+ const getVal = (id) => {
706
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
707
+ if (e) {
708
+ let sourceNode = nodes.find(node => node.id === e.source);
709
+ if (ctx?.[e.source]) {
710
+ return ctx?.[e.source];
711
+ }
712
+ else if (sourceNode && e.sourceHandle) {
713
+ return sourceNode.data?.[e.sourceHandle];
714
+ }
715
+ }
716
+ return undefined;
717
+ };
718
+ const plan = getVal('plan');
719
+ if (!plan || !Array.isArray(plan.steps)) {
720
+ throw new Error(`Invalid plan input for UiPlannerExecNode ${node.id}`);
721
+ }
722
+ // Mock objects for executeStep compatibility
723
+ const mockWorkflow = { id: 'ui-planner-exec', content: { id: 'ui-planner-exec' } };
724
+ const mockJob = { id: 'exec' };
725
+ const mockConfig = { version: 'exec' };
726
+ const stepOutput = {};
727
+ const results = [];
728
+ for (const step of plan.steps) {
729
+ console.log(`Executing plan step: ${step.description}`);
730
+ try {
731
+ await executeStep(mockWorkflow, mockJob, step, modelContext, // Global context/config
732
+ { a: ctx }, // Inputs wrapper
733
+ stepOutput, workflows, mockConfig);
734
+ results.push({ step: step.description, status: 'completed' });
735
+ }
736
+ catch (error) {
737
+ console.error(`Error executing step ${step.id}:`, error);
738
+ results.push({ step: step.description, status: 'failed', error: error.message });
739
+ throw error;
740
+ }
741
+ }
742
+ ctx[node.id] = { planExecuted: true, results };
743
+ break;
744
+ }
745
+ break;
746
+ case 'globalNode': {
747
+ // 1. Find input edges by handle id
748
+ const getVal = (id) => {
749
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
750
+ if (e) {
751
+ let sourceNode = nodes.find(node => node.id === e.source);
752
+ if (ctx?.[e.source]) {
753
+ return ctx?.[e.source];
754
+ }
755
+ else if (sourceNode && e.sourceHandle) {
756
+ return sourceNode.data?.[e.sourceHandle];
757
+ }
758
+ }
759
+ return undefined;
760
+ };
761
+ // 2. Process key-value pairs from node data
762
+ const { pairs = [] } = node.data;
763
+ // 3. Build global context object
764
+ const globalData = {};
765
+ for (const pair of pairs) {
766
+ const { key, value, inputHandleId } = pair;
767
+ if (inputHandleId) {
768
+ // Get value from connected input
769
+ const connectedValue = getVal(inputHandleId);
770
+ globalData[key] = connectedValue !== undefined ? connectedValue : value;
771
+ }
772
+ else {
773
+ // Use static value
774
+ globalData[key] = value;
775
+ }
776
+ }
777
+ // 4. Merge into global context
778
+ Object.assign(globalContext, globalData);
779
+ console.log(`Global Context updated in GlobalNode ${node.id}:`, globalContext);
780
+ console.log(`Global Data set by GlobalNode ${node.id}:`, globalData);
781
+ console.log(`node.data:`, node.data);
782
+ // 5. Store result in local context for chaining
783
+ ctx[node.id] = globalData;
784
+ break;
785
+ }
786
+ case 'outputNode': {
787
+ const inEdge = edges.find((e) => e.target === node.id);
788
+ const payload = inEdge ? ctx[inEdge.source] : undefined;
789
+ const { url, method } = node.data;
790
+ try {
791
+ await fetch(modelContext.defaultServer + url, {
792
+ method: method || 'POST',
793
+ headers: { 'Content-Type': 'application/json' },
794
+ body: JSON.stringify({ ...node.data, data: payload, }),
795
+ });
796
+ }
797
+ catch (err) {
798
+ console.error(`Output node error:`, err);
799
+ throw err;
800
+ }
801
+ break;
802
+ }
803
+ case 'inputNode': {
804
+ // read the name from node.data, then read the context,
805
+ // and set the ctx with that value or the default value from the node.
806
+ const data = node.data;
807
+ console.log('InputNode context:');
808
+ console.log(`data.name: ${data.name}`);
809
+ console.log(ctx);
810
+ ctx[node.id] = ctx[data.name] || data.value;
811
+ data.value = ctx[node.id];
812
+ console.log(`data.value: ${data.value}`);
813
+ console.log(`InputNode ${node.id} set to:`, ctx[node.id]);
814
+ break;
815
+ }
816
+ case 'graphNode': {
817
+ {
818
+ const arr = [input];
819
+ console.log(`Executing GraphNode ${node.id}`);
820
+ // inside executeFlow, case 'forLoopNode':
821
+ console.log(input);
822
+ const graphData = await fetch(modelContext.defaultServer + `/loadConfiguration?name=${encodeURIComponent(node.data.graph)}`).then((r) => r.json());
823
+ const graph = graphData;
824
+ if (!graph) {
825
+ ctx[node.id] = [];
826
+ break;
827
+ }
828
+ const { nodes: bodyNodes, edges: bodyEdges } = graph;
829
+ const results = [];
830
+ const item = arr[0];
831
+ // 1️⃣ Before each iteration, inject into InputNodes:
832
+ const seedCtx = { [`${node.id}.item`]: item };
833
+ for (const subNode of bodyNodes) {
834
+ if (subNode.type === 'inputNode') {
835
+ const data = subNode.data;
836
+ if (data.name === 'index') {
837
+ data.value = 0;
838
+ seedCtx[subNode.id] = 0;
839
+ }
840
+ else if (data.name === 'item') {
841
+ data.value = item;
842
+ seedCtx[subNode.id] = item;
843
+ }
844
+ else if (data.name === 'array') {
845
+ data.value = arr;
846
+ seedCtx[subNode.id] = arr;
847
+ }
848
+ }
849
+ }
850
+ if (callback) {
851
+ callback(node.id, { progress: (1) / arr.length, state: NodeExecutionState.Running });
852
+ }
853
+ const bodyCtx = await executeFlow(bodyNodes, bodyEdges, workflows, modelContext, seedCtx, callback, globalContext);
854
+ // find the ResultNode in bodyNodes
855
+ const resultNode = bodyNodes.find((n) => n.type === 'resultNode');
856
+ if (!resultNode) {
857
+ console.warn(`No ResultNode found in loop body for node ${node.id}`);
858
+ results.push(undefined);
859
+ }
860
+ else {
861
+ // see if something fed into its 'in' handle
862
+ const inEdge = bodyEdges.find(e => e.target === resultNode.id && e.targetHandle === 'in');
863
+ const outVal = inEdge
864
+ ? bodyCtx[inEdge.source]
865
+ : resultNode.data.value;
866
+ results.push(outVal);
867
+ }
868
+ ctx[node.id] = results[0];
869
+ if (callback) {
870
+ callback(node.id, { progress: (1) / arr.length, state: NodeExecutionState.Complete });
871
+ }
872
+ }
873
+ break;
874
+ }
875
+ case 'ifNode': {
876
+ const arr = [input];
877
+ // inside executeFlow, case 'forLoopNode':
878
+ const graph = input ? node.data.trueGraph : node.data.falseGraph;
879
+ if (!graph) {
880
+ ctx[node.id] = [];
881
+ break;
882
+ }
883
+ const { nodes: bodyNodes, edges: bodyEdges } = graph;
884
+ const results = [];
885
+ const item = arr[0];
886
+ // 1️⃣ Before each iteration, inject into InputNodes:
887
+ const seedCtx = { [`${node.id}.item`]: item };
888
+ for (const subNode of bodyNodes) {
889
+ if (subNode.type === 'inputNode') {
890
+ const data = subNode.data;
891
+ if (data.name === 'index') {
892
+ data.value = 0;
893
+ seedCtx[subNode.id] = 0;
894
+ }
895
+ else if (data.name === 'item') {
896
+ data.value = item;
897
+ seedCtx[subNode.id] = item;
898
+ }
899
+ else if (data.name === 'array') {
900
+ data.value = arr;
901
+ seedCtx[subNode.id] = arr;
902
+ }
903
+ }
904
+ }
905
+ if (callback) {
906
+ callback(node.id, { progress: (1) / arr.length });
907
+ }
908
+ const bodyCtx = await executeFlow(bodyNodes, bodyEdges, workflows, modelContext, seedCtx, callback, globalContext);
909
+ // find the ResultNode in bodyNodes
910
+ const resultNode = bodyNodes.find((n) => n.type === 'resultNode');
911
+ if (!resultNode) {
912
+ console.warn(`No ResultNode found in loop body for node ${node.id}`);
913
+ results.push(undefined);
914
+ }
915
+ else {
916
+ // see if something fed into its 'in' handle
917
+ const inEdge = bodyEdges.find(e => e.target === resultNode.id && e.targetHandle === 'in');
918
+ const outVal = inEdge
919
+ ? bodyCtx[inEdge.source]
920
+ : resultNode.data.value;
921
+ results.push(outVal);
922
+ }
923
+ ctx[node.id] = results;
924
+ break;
925
+ }
926
+ case 'ifWorkflowNode': {
927
+ const conditionEdge = edges.find(e => e.target === node.id && e.targetHandle === 'condition');
928
+ const inEdge = edges.find(e => e.target === node.id && e.targetHandle === 'in');
929
+ const condition = conditionEdge
930
+ ? ctx[conditionEdge.source]
931
+ : node.data.condition;
932
+ const inValues = inEdge
933
+ ? ctx[inEdge.source]
934
+ : undefined;
935
+ console.log(`Executing ifWorkflowNode ${node.id} with node.data:`, node);
936
+ console.log(`Condition value: ${condition}`);
937
+ console.log(`Input values:`, inValues);
938
+ // Determine which workflow to execute based on the input condition
939
+ const workflowName = condition ? node.data.trueWorkflow : node.data.falseWorkflow;
940
+ if (!workflowName) {
941
+ console.warn(`No workflow selected for ${condition ? 'true' : 'false'} branch in ifWorkflowNode ${node.id}`);
942
+ ctx[node.id] = undefined;
943
+ break;
944
+ }
945
+ // Load the workflow configuration
946
+ const graphData = await fetch(modelContext.defaultServer + `/loadConfiguration?name=${encodeURIComponent(workflowName || '')}`).then((r) => r.json());
947
+ const graph = graphData;
948
+ if (!graph) {
949
+ console.error(`Workflow '${workflowName}' not found for ifWorkflowNode ${node.id}`);
950
+ ctx[node.id] = undefined;
951
+ break;
952
+ }
953
+ console.log(`Executing ${condition ? 'true' : 'false'} branch workflow: ${workflowName}`);
954
+ const { nodes: bodyNodes, edges: bodyEdges } = graph;
955
+ // Execute the workflow with the input as context
956
+ const seedCtx = { [`${node.id}.condition`]: condition, item: inValues };
957
+ // const bodyCtx = await executeFlow(bodyNodes, bodyEdges, workflows, modelContext, seedCtx, callback, globalContext);
958
+ const bodyCtx = await executeFlow(bodyNodes, bodyEdges, workflows, modelContext, seedCtx, callback, globalContext);
959
+ // Find the ResultNode in the workflow
960
+ const resultNode = bodyNodes.find((n) => n.type === 'resultNode');
961
+ if (!resultNode) {
962
+ console.warn(`No ResultNode found in workflow ${workflowName} for ifWorkflowNode ${node.id}`);
963
+ ctx[node.id] = undefined;
964
+ }
965
+ else {
966
+ // Get the output from the ResultNode
967
+ const inEdge = bodyEdges.find(e => e.target === resultNode.id && e.targetHandle === 'in');
968
+ const outVal = inEdge
969
+ ? bodyCtx[inEdge.source]
970
+ : resultNode.data.value;
971
+ ctx[node.id] = outVal;
972
+ }
973
+ break;
974
+ }
975
+ case 'ifGraphNode': { // similar to ifWorkflowNode but loads a automations
976
+ const conditionEdge = edges.find(e => e.target === node.id && e.targetHandle === 'condition');
977
+ const inputEdge = edges.find(e => e.target === node.id && e.targetHandle === 'input');
978
+ const condition = conditionEdge
979
+ ? ctx[conditionEdge.source]
980
+ : node.data.condition;
981
+ const inValues = inputEdge ? ctx[inputEdge.source] : undefined;
982
+ console.log(`Executing ifGraphNode ${node.id} with node.data:`, node);
983
+ console.log(`Condition value: ${condition}`);
984
+ console.log(`Input values:`, inValues);
985
+ // Determine which graph to execute based on the input condition
986
+ const workflowId = condition ? node.data.trueAutomation : node.data.falseAutomation;
987
+ const workflowName = condition ? node.data.trueAutomationName : node.data.falseAutomationName;
988
+ if (!workflowId) {
989
+ console.warn(`No automation selected for ${condition ? 'true' : 'false'} branch in ifGraphNode(automationNode) ${node.id}`);
990
+ ctx[node.id] = undefined;
991
+ throw new Error(`No automation selected for ${condition ? 'true' : 'false'} branch in ifGraphNode(automationNode) ${node.id}`);
992
+ }
993
+ console.log(`Executing ${condition ? 'true' : 'false'} branch graph: ${workflowId}`);
994
+ // 2. Get utility functions
995
+ const workflow = workflows.find(wf => {
996
+ console.log(wf);
997
+ return wf.workflow.id === workflowId || wf.workflow.id === workflowName;
998
+ });
999
+ if (!workflow) {
1000
+ console.log(`There are ${workflows.length} workflows loaded:`);
1001
+ console.log(workflows.map(d => `${d.workflow.id}=> ${d.workflow.name}`).join('\n'));
1002
+ throw new Error(`Workflow not found: ${workflowId}`);
1003
+ }
1004
+ let result = await executeConfiguration(workflow, node.data, ctx, { a: inValues, b: undefined, c: undefined }, workflows);
1005
+ ctx[node.id] = result;
1006
+ break;
1007
+ }
1008
+ case 'forEachNode':
1009
+ {
1010
+ const arr = Array.isArray(input) ? input : [];
1011
+ // Load the graph by ID instead of using embedded subnodes
1012
+ const graphName = node.data.graphNodeId;
1013
+ if (!graphName) {
1014
+ ctx[node.id] = [];
1015
+ break;
1016
+ }
1017
+ const graphData = await fetch(modelContext.defaultServer + `/loadConfiguration?name=${encodeURIComponent(graphName)}`).then((r) => r.json());
1018
+ const graph = graphData;
1019
+ if (!graph) {
1020
+ ctx[node.id] = [];
1021
+ break;
1022
+ }
1023
+ const { nodes: bodyNodes, edges: bodyEdges } = graph;
1024
+ const results = [];
1025
+ let max = arr.length;
1026
+ if (node.data.limitItems) {
1027
+ max = Math.min(node.data.limitCount || arr.length, arr.length);
1028
+ }
1029
+ for (let i = 0; i < max; i++) {
1030
+ const item = arr[i];
1031
+ // 1️⃣ Before each iteration, inject into InputNodes:
1032
+ const seedCtx = { [`${node.id}.item`]: item };
1033
+ for (const subNode of bodyNodes) {
1034
+ if (subNode.type === 'inputNode') {
1035
+ const data = subNode.data;
1036
+ if (data.name === 'index') {
1037
+ data.value = i;
1038
+ seedCtx[subNode.id] = i;
1039
+ }
1040
+ else if (data.name === 'item') {
1041
+ data.value = item;
1042
+ seedCtx[subNode.id] = item;
1043
+ }
1044
+ else if (data.name === 'array') {
1045
+ data.value = arr;
1046
+ seedCtx[subNode.id] = arr;
1047
+ }
1048
+ }
1049
+ }
1050
+ if (callback) {
1051
+ callback(node.id, { state: NodeExecutionState.Running, message: `Executing loop iteration ${i + 1} of ${arr.length}` });
1052
+ }
1053
+ const bodyCtx = await executeFlow(bodyNodes, bodyEdges, workflows, modelContext, seedCtx, callback, globalContext);
1054
+ // find the ResultNode in bodyNodes
1055
+ const resultNode = bodyNodes.find((n) => n.type === 'resultNode');
1056
+ if (!resultNode) {
1057
+ console.warn(`No ResultNode found in loop body for node ${node.id}`);
1058
+ results.push(undefined);
1059
+ }
1060
+ else {
1061
+ // see if something fed into its 'in' handle
1062
+ const inEdge = bodyEdges.find(e => e.target === resultNode.id && e.targetHandle === 'in');
1063
+ const outVal = inEdge
1064
+ ? bodyCtx[inEdge.source]
1065
+ : resultNode.data.value;
1066
+ results.push(outVal);
1067
+ }
1068
+ }
1069
+ ctx[node.id] = results;
1070
+ }
1071
+ break;
1072
+ case 'forLoopNode': {
1073
+ const arr = Array.isArray(input) ? input : [];
1074
+ // inside executeFlow, case 'forLoopNode':
1075
+ const bodyGraph = node.data.bodyGraph;
1076
+ if (!bodyGraph) {
1077
+ ctx[node.id] = [];
1078
+ break;
1079
+ }
1080
+ const { nodes: bodyNodes, edges: bodyEdges } = node.data.bodyGraph;
1081
+ const results = [];
1082
+ for (let i = 0; i < arr.length; i++) {
1083
+ const item = arr[i];
1084
+ // 1️⃣ Before each iteration, inject into InputNodes:
1085
+ const seedCtx = { [`${node.id}.item`]: item };
1086
+ for (const subNode of bodyNodes) {
1087
+ if (subNode.type === 'inputNode') {
1088
+ const data = subNode.data;
1089
+ if (data.name === 'index') {
1090
+ data.value = i;
1091
+ seedCtx[subNode.id] = i;
1092
+ }
1093
+ else if (data.name === 'item') {
1094
+ data.value = item;
1095
+ seedCtx[subNode.id] = item;
1096
+ }
1097
+ else if (data.name === 'array') {
1098
+ data.value = arr;
1099
+ seedCtx[subNode.id] = arr;
1100
+ }
1101
+ }
1102
+ }
1103
+ if (callback) {
1104
+ callback(node.id, { state: NodeExecutionState.Running, message: `Executing loop iteration ${i + 1} of ${arr.length}` });
1105
+ }
1106
+ const bodyCtx = await executeFlow(bodyNodes, bodyEdges, workflows, modelContext, seedCtx, callback, globalContext);
1107
+ // find the ResultNode in bodyNodes
1108
+ const resultNode = bodyNodes.find((n) => n.type === 'resultNode');
1109
+ if (!resultNode) {
1110
+ console.warn(`No ResultNode found in loop body for node ${node.id}`);
1111
+ results.push(undefined);
1112
+ }
1113
+ else {
1114
+ // see if something fed into its 'in' handle
1115
+ const inEdge = bodyEdges.find(e => e.target === resultNode.id && e.targetHandle === 'in');
1116
+ const outVal = inEdge
1117
+ ? bodyCtx[inEdge.source]
1118
+ : resultNode.data.value;
1119
+ results.push(outVal);
1120
+ }
1121
+ }
1122
+ ctx[node.id] = results;
1123
+ break;
1124
+ }
1125
+ case 'execJSNode': {
1126
+ // 1. Find input edges by handle id
1127
+ const getVal = (id) => {
1128
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
1129
+ if (e) {
1130
+ let sourceNode = nodes.find(node => node.id === e.source);
1131
+ if (ctx?.[e.source]) {
1132
+ return ctx?.[e.source];
1133
+ }
1134
+ else if (sourceNode && e.sourceHandle) {
1135
+ return sourceNode.data?.[e.sourceHandle];
1136
+ }
1137
+ }
1138
+ return undefined;
1139
+ };
1140
+ let inputParams = 'abcdefg'.split('');
1141
+ let inputValues = inputParams.map(p => getVal(p));
1142
+ const { code } = node.data;
1143
+ // 2. Get utility functions
1144
+ const utils = { ...getUtilityFunctions(), fs, path };
1145
+ // 3. Build function with utilities available in scope
1146
+ const functionBody = `
1147
+ // Destructure utility functions for direct use
1148
+
1149
+ const {
1150
+ cleanJSONString,
1151
+ safeExtractJSON,
1152
+ containsJSON,
1153
+ extractMultipleJSON,
1154
+ extractJSON, capitalize, titleCase, slugify, truncate,
1155
+ chunk, unique, flatten, groupBy,
1156
+ pick, omit, deepMerge,
1157
+ formatDate, timeAgo,
1158
+ clamp, round, randomBetween, formatNumber,
1159
+ isEmail, isUrl, isEmpty,
1160
+ fetchJSON, delay, retry,
1161
+ template, log, inspect,
1162
+ fs, path
1163
+ } = utils;
1164
+
1165
+ // Global context available
1166
+ const $global = ${JSON.stringify(globalContext)};
1167
+
1168
+ // User code
1169
+ ${code || 'return undefined;'}
1170
+ `;
1171
+ console.log(`Global Context in ExecJSNode ${node.id}:`, globalContext);
1172
+ const fn = new Function(...inputParams, 'utils', 'global', functionBody);
1173
+ // 4. Execute and store result
1174
+ try {
1175
+ ctx[node.id] = await fn(...inputValues, utils, globalContext);
1176
+ }
1177
+ catch (err) {
1178
+ console.error(`ExecJSNode error:`, err);
1179
+ if (err && err.includes('[try again]')) {
1180
+ throw new Error(`ExecJSNode ${node.id} failed: ${err}`);
1181
+ }
1182
+ console.log(`Function body was:`, functionBody);
1183
+ ctx[node.id] = undefined;
1184
+ }
1185
+ node.data.output = ctx[node.id];
1186
+ console.log(`ExecJSNode ${node.id} output:`, ctx[node.id]);
1187
+ break;
1188
+ }
1189
+ case 'globalGetNode': {
1190
+ // 1. Find input edges by handle id
1191
+ const getVal = (id) => {
1192
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
1193
+ if (e) {
1194
+ let sourceNode = nodes.find(node => node.id === e.source);
1195
+ if (ctx?.[e.source]) {
1196
+ return ctx[e.source];
1197
+ }
1198
+ else if (sourceNode?.data?.value !== undefined) {
1199
+ return sourceNode.data.value;
1200
+ }
1201
+ }
1202
+ return undefined;
1203
+ };
1204
+ // 2. Get key from input or node data
1205
+ let key = getVal('in'); // from 'in' handle
1206
+ if (key === undefined) {
1207
+ key = node.data.key; // from node data
1208
+ }
1209
+ // 3. Get default value from 'value' handle or node data
1210
+ let defaultValue = getVal('value'); // from 'value' handle
1211
+ if (defaultValue === undefined) {
1212
+ defaultValue = node.data.defaultValue; // from node data
1213
+ }
1214
+ // 4. Read from global context
1215
+ let result = undefined;
1216
+ if (key && typeof key === 'string' && globalContext) {
1217
+ // Support dot notation like 'user.name'
1218
+ const path = key.split('.');
1219
+ result = path.reduce((obj, k) => obj?.[k], globalContext);
1220
+ }
1221
+ // 5. Use default value if result is undefined
1222
+ if (result === undefined) {
1223
+ result = defaultValue;
1224
+ }
1225
+ // 6. Store result and update display
1226
+ ctx[node.id] = result;
1227
+ node.data.lastValue = result;
1228
+ break;
1229
+ }
1230
+ case 'resultNode': {
1231
+ const getVal = (id) => {
1232
+ const e = edges.find(e => e.target === node.id && e.targetHandle === id);
1233
+ if (e) {
1234
+ let node = nodes.find(node => node.id === e.source);
1235
+ if (ctx?.[e.source]) {
1236
+ return ctx?.[e.source];
1237
+ }
1238
+ else if (node && e.sourceHandle) {
1239
+ return node.data?.[e.sourceHandle];
1240
+ }
1241
+ }
1242
+ return undefined;
1243
+ };
1244
+ const a = getVal("in");
1245
+ ctx[node.id] = a;
1246
+ node.data.value = a;
1247
+ break;
1248
+ }
1249
+ case 'extensionNode': {
1250
+ const { extensionPath, capabilityId } = node.data;
1251
+ // 1. Fetch extensions list from API
1252
+ let extensions = [];
1253
+ try {
1254
+ const response = await fetch(`${modelContext.defaultServer}/get-extensions`);
1255
+ if (!response.ok)
1256
+ throw new Error(`Failed to fetch extensions: ${response.statusText}`);
1257
+ const data = await response.json();
1258
+ extensions = data.extensions || [];
1259
+ }
1260
+ catch (err) {
1261
+ console.error('Error fetching extensions:', err);
1262
+ throw new Error(`Could not retrieve extensions list: ${err.message}`);
1263
+ }
1264
+ // 2. Find the extension metadata
1265
+ const extensionMeta = extensions.find(ext => ext.location === extensionPath);
1266
+ if (!extensionMeta) {
1267
+ throw new Error(`Extension not found in registry: ${extensionPath}`);
1268
+ }
1269
+ // 3. Find the specific capability
1270
+ const capability = extensionMeta.capabilities?.find(cap => cap.id === capabilityId);
1271
+ if (!capability) {
1272
+ throw new Error(`Capability ${capabilityId} not found in extension ${extensionPath}`);
1273
+ }
1274
+ // 4. Resolve path and install dependencies
1275
+ let extensionFolders = [];
1276
+ try {
1277
+ const res = await fetch(`${modelContext.defaultServer}/getObject`, {
1278
+ method: 'POST',
1279
+ headers: { 'Content-Type': 'application/json' },
1280
+ body: JSON.stringify({ key: 'extension_folders' })
1281
+ });
1282
+ if (res.ok) {
1283
+ const data = await res.json();
1284
+ extensionFolders = data.extension_folders || [];
1285
+ }
1286
+ }
1287
+ catch (e) {
1288
+ console.warn('Failed to fetch extension folders:', e);
1289
+ }
1290
+ let resolvedPath;
1291
+ const pathsToTry = [
1292
+ extensionPath,
1293
+ ...extensionFolders.map(folder => path.join(folder, extensionPath))
1294
+ ];
1295
+ for (const p of pathsToTry) {
1296
+ if (fs.existsSync(p)) {
1297
+ resolvedPath = p;
1298
+ break;
1299
+ }
1300
+ }
1301
+ if (!resolvedPath) {
1302
+ throw new Error(`Extension path not found. Checked: ${pathsToTry.join(', ')}`);
1303
+ }
1304
+ // Determine directory for installation
1305
+ const stat = fs.statSync(resolvedPath);
1306
+ const extensionDir = stat.isDirectory() ? resolvedPath : path.dirname(resolvedPath);
1307
+ // Install dependencies via API
1308
+ try {
1309
+ console.log(`Installing dependencies in ${extensionDir}...`);
1310
+ const installRes = await fetch(`${modelContext.defaultServer}/installDependencies`, {
1311
+ method: 'POST',
1312
+ headers: { 'Content-Type': 'application/json' },
1313
+ body: JSON.stringify({ targetDir: extensionDir })
1314
+ });
1315
+ if (!installRes.ok) {
1316
+ console.warn(`Failed to install dependencies: ${installRes.statusText}`);
1317
+ }
1318
+ else {
1319
+ console.log(`Dependencies installed successfully.`);
1320
+ }
1321
+ }
1322
+ catch (e) {
1323
+ console.warn(`Error calling /installDependencies:`, e);
1324
+ }
1325
+ // 5. Execution handled via CLI, no need to import module in this process
1326
+ // let extensionModule; ...
1327
+ // Helper to get value from incoming edge
1328
+ const getVal = (targetHandleId) => {
1329
+ const edge = edges.find(e => e.target === node.id && e.targetHandle === targetHandleId);
1330
+ if (!edge)
1331
+ return undefined;
1332
+ // 1. Try execution context
1333
+ const sourceVal = ctx[edge.source];
1334
+ if (sourceVal !== undefined) {
1335
+ if (edge.sourceHandle && typeof sourceVal === 'object') {
1336
+ // Try exact match
1337
+ if (sourceVal[edge.sourceHandle] !== undefined)
1338
+ return sourceVal[edge.sourceHandle];
1339
+ // Try stripping "output-" prefix
1340
+ const cleanHandle = edge.sourceHandle.replace(/^output-/, '');
1341
+ if (sourceVal[cleanHandle] !== undefined)
1342
+ return sourceVal[cleanHandle];
1343
+ }
1344
+ return sourceVal;
1345
+ }
1346
+ // 2. Fallback to node data (for static values)
1347
+ const sourceNode = nodes.find(n => n.id === edge.source);
1348
+ if (sourceNode && edge.sourceHandle) {
1349
+ return sourceNode.data?.[edge.sourceHandle];
1350
+ }
1351
+ return undefined;
1352
+ };
1353
+ // Gather inputs defined in the capability
1354
+ const inputs = {};
1355
+ // 1. Map named inputs
1356
+ if (capability.inputs) {
1357
+ for (const inputDef of capability.inputs) {
1358
+ const handleId = `input-${inputDef.name}`;
1359
+ const val = getVal(handleId);
1360
+ if (val !== undefined) {
1361
+ inputs[inputDef.name] = val;
1362
+ }
1363
+ }
1364
+ }
1365
+ // 2. Check for generic "in" handle
1366
+ const genericIn = getVal('in');
1367
+ // if (genericIn !== undefined) {
1368
+ // inputs['in'] = genericIn;
1369
+ // }
1370
+ console.log(`Executing extension node ${node.id} (${extensionPath}::${capabilityId}) via CLI`, inputs);
1371
+ // Execute via CLI endpoint
1372
+ const cliResponse = await fetch(`${modelContext.defaultServer}/runWorkflowCLI`, {
1373
+ method: 'POST',
1374
+ headers: { 'Content-Type': 'application/json' },
1375
+ body: JSON.stringify({
1376
+ targetDir: extensionDir,
1377
+ parameters: {
1378
+ ...inputs
1379
+ }
1380
+ })
1381
+ });
1382
+ if (!cliResponse.ok) {
1383
+ throw new Error(`CLI execution failed: ${cliResponse.statusText}`);
1384
+ }
1385
+ const cliResult = await cliResponse.json();
1386
+ if (cliResult.error) {
1387
+ throw new Error(`CLI execution error: ${cliResult.error}\nStderr: ${cliResult.stderr}`);
1388
+ }
1389
+ // Try to parse the output
1390
+ // let output = cliResult.stdout;
1391
+ // const extracted = safeExtractJSON(output);
1392
+ // if (extracted) {
1393
+ // output = extracted;
1394
+ // }
1395
+ console.log(`Extension node ${node.id} CLI result:`, cliResult);
1396
+ // console.log(`Extension node ${node.id} output:`, output);
1397
+ ctx[node.id] = cliResult;
1398
+ node.data.output = cliResult;
1399
+ break;
1400
+ }
1401
+ case 'uiMapSelectorNode': {
1402
+ // For now, just pass through the input
1403
+ const { selectedFiles } = node.data;
1404
+ let workflow_folder = (get(KEYS.workflow_folder));
1405
+ // if the files are relative paths, make them absolute based on workflow_folder
1406
+ const absoluteFiles = selectedFiles.map(file => {
1407
+ if (!path.isAbsolute(file)) {
1408
+ return path.join(workflow_folder, file);
1409
+ }
1410
+ return file;
1411
+ });
1412
+ console.log(absoluteFiles);
1413
+ const uiMap = await generateUIMap(absoluteFiles);
1414
+ ctx[node.id] = { uiMap, files: absoluteFiles };
1415
+ node.data.output = { uiMap, files: absoluteFiles };
1416
+ break;
1417
+ }
1418
+ case 'uiMapProcessorNode': {
1419
+ // For now, just pass through the input
1420
+ ctx[node.id] = input;
1421
+ break;
1422
+ }
1423
+ case 'uiMapChatNode': {
1424
+ // For now, just pass through the input
1425
+ ctx[node.id] = node?.data?.generatedContext || '';
1426
+ break;
1427
+ }
1428
+ case 'uiDependencyGraphNode': {
1429
+ // For now, just pass through the input
1430
+ const { bodyGraph } = node.data;
1431
+ if (!bodyGraph) {
1432
+ throw new Error(`UiDependencyGraphNode ${node.id}: Missing required input (UI Map)`);
1433
+ }
1434
+ // 2. Parse UI Map
1435
+ let graph;
1436
+ try {
1437
+ graph = typeof bodyGraph === 'string' ? JSON.parse(bodyGraph) : bodyGraph;
1438
+ }
1439
+ catch (e) {
1440
+ throw new Error(`UiDependencyGraphNode ${node.id}: Invalid UI Map JSON - ${e.message}`);
1441
+ }
1442
+ ctx[node.id] = graph;
1443
+ node.data.output = graph;
1444
+ break;
1445
+ }
1446
+ case 'uiPlannerNode':
1447
+ {
1448
+ // 1. Resolve inputs
1449
+ const uiMapEdge = edges.find(e => e.target === node.id && e.targetHandle === 'uiMap');
1450
+ const contextEdge = edges.find(e => e.target === node.id && e.targetHandle === 'promptContext');
1451
+ const requestEdge = edges.find(e => e.target === node.id && e.targetHandle === 'userRequest');
1452
+ const dependencyGraphEdge = edges.find(e => e.target === node.id && e.targetHandle === 'dependencyGraph');
1453
+ const uiMapStr = uiMapEdge ? ctx[uiMapEdge.source] : node.data.uiMap;
1454
+ const promptContext = contextEdge ? ctx[contextEdge.source] : node.data.promptContext;
1455
+ const userRequest = requestEdge ? ctx[requestEdge.source] : node.data.userRequest;
1456
+ const dependencyGraph = dependencyGraphEdge ? ctx[dependencyGraphEdge.source] : node.data.dependencyGraph;
1457
+ if (!uiMapStr || !userRequest) {
1458
+ throw new Error(`UiPlannerNode ${node.id}: Missing required inputs (UI Map or User Request)`);
1459
+ }
1460
+ // 2. Parse UI Map
1461
+ let uiMapInput;
1462
+ try {
1463
+ uiMapInput = typeof uiMapStr === 'string' ? JSON.parse(uiMapStr) : uiMapStr;
1464
+ }
1465
+ catch (e) {
1466
+ throw new Error(`UiPlannerNode ${node.id}: Invalid UI Map JSON - ${e.message}`);
1467
+ }
1468
+ const uiMap = uiMapInput.uiMap || uiMapInput;
1469
+ const filePaths = uiMapInput.files || [];
1470
+ const automationFiles = [];
1471
+ if (filePaths.length > 0) {
1472
+ for (const filePath of filePaths) {
1473
+ try {
1474
+ const content = await fs.promises.readFile(filePath, 'utf-8');
1475
+ automationFiles.push({ path: filePath, content: JSON.parse(content) });
1476
+ }
1477
+ catch (err) {
1478
+ console.warn(`UiPlannerNode: Failed to read automation file ${filePath}`, err);
1479
+ }
1480
+ }
1481
+ }
1482
+ // 3. Initialize Planner
1483
+ const pathFinder = new UiMapPathFinder(uiMap);
1484
+ // const planner = new UiPlanner(uiMap, pathFinder, {}, automationFiles);
1485
+ const planner = new StepByStepAiPlanner(uiMap, pathFinder, {}, automationFiles);
1486
+ // 4. Execute Plan
1487
+ const model = node.data.model || DEFAULT_MODEL;
1488
+ const context = { promptContext, dependencyGraph };
1489
+ // We assume startStateId is 'home' or passed in context if needed,
1490
+ // but for now defaulting to 'home' as per UiPlanner default.
1491
+ // If the node had a 'startState' input, we could use that.
1492
+ const startStateId = 'home';
1493
+ console.log(`UiPlannerNode ${node.id} planning for request: "${userRequest}"`);
1494
+ const plan = await planner.plan(userRequest, startStateId, context, model);
1495
+ ctx[node.id] = plan;
1496
+ }
1497
+ break;
1498
+ case 'promptFarmNode':
1499
+ {
1500
+ const promptLibIdEdge = edges.find(e => e.target === node.id && e.targetHandle === 'promptLibId');
1501
+ const chainIdEdge = edges.find(e => e.target === node.id && e.targetHandle === 'chainId');
1502
+ const promptLibId = promptLibIdEdge ? ctx[promptLibIdEdge.source] : node.data.promptLibId;
1503
+ const chainId = chainIdEdge ? ctx[chainIdEdge.source] : node.data.chainId;
1504
+ if (!promptLibId) {
1505
+ throw new Error(`PromptFarm node ${node.id}: Missing required input (Prompt Library ID)`);
1506
+ }
1507
+ // Fetch Lib
1508
+ const serverUrl = modelContext.defaultServer || 'http://localhost:3000';
1509
+ const safeLibId = promptLibId.replace(/\.prompt_lib$/, '');
1510
+ const libRes = await fetch(`${serverUrl}/api/prompt-libs/${safeLibId}`);
1511
+ if (!libRes.ok)
1512
+ throw new Error(`Failed to load Prompt Lib ${promptLibId}: ${libRes.statusText}`);
1513
+ const libJson = await libRes.json();
1514
+ const libData = libJson.promptLib || {};
1515
+ // Resolve Chain
1516
+ let targetChain = null;
1517
+ if (libData.executionTree && chainId) {
1518
+ // Support groupKey, or groupKey::resultKey
1519
+ const parts = chainId.split('::');
1520
+ const groupKey = parts[0];
1521
+ const resultKey = parts[1] || 'default';
1522
+ if (libData.executionTree[groupKey]) {
1523
+ targetChain = libData.executionTree[groupKey][resultKey];
1524
+ }
1525
+ }
1526
+ if (!targetChain) {
1527
+ // Fallback: Check if we have legacy format or just grab the first available
1528
+ if (!chainId && libData.executionTree) {
1529
+ const firstGroup = Object.keys(libData.executionTree)[0];
1530
+ if (firstGroup)
1531
+ targetChain = libData.executionTree[firstGroup]['default'];
1532
+ }
1533
+ }
1534
+ if (!targetChain)
1535
+ throw new Error(`Chain not found: ${chainId || 'default'} in lib ${promptLibId}`);
1536
+ // Execute
1537
+ console.log(`Executing Prompt Chain: ${chainId} from ${promptLibId}`);
1538
+ const result = await executeChain({
1539
+ chainDef: targetChain,
1540
+ prompts: libData.prompts || {},
1541
+ input: input || node.data.input || '', // The incoming input to the node or manual input
1542
+ preamble: libData.preamble,
1543
+ precontext: libData.precontext,
1544
+ serverUrl,
1545
+ model: node.data.model || DEFAULT_MODEL,
1546
+ logFn: (msg) => {
1547
+ console.log(`[PromptFarm:${node.id}] ${msg}`);
1548
+ if (callback) {
1549
+ callback(node.id, {
1550
+ state: NodeExecutionState.Running,
1551
+ message: msg
1552
+ });
1553
+ }
1554
+ }
1555
+ });
1556
+ ctx[node.id] = result.result;
1557
+ // Store metadata for inspection
1558
+ node.data.executionHistory = result.history;
1559
+ node.data.output = result.result;
1560
+ break;
1561
+ }
1562
+ default:
1563
+ break;
1564
+ }
1565
+ if (callback) {
1566
+ callback(node.id, { state: NodeExecutionState.Complete });
1567
+ }
1568
+ }
1569
+ catch (err) {
1570
+ console.error(`Error executing node ${node.id}:`, err);
1571
+ if (callback) {
1572
+ callback(node.id, { state: NodeExecutionState.Error });
1573
+ }
1574
+ throw err;
1575
+ }
1576
+ // Save the cumulative context to file
1577
+ saveNodeContext(ctx);
1578
+ // Save individual node values (latest values across all executions)
1579
+ saveNodeValues(ctx, inputs);
1580
+ }
1581
+ // Save the cumulative context to file
1582
+ saveNodeContext(ctx);
1583
+ // Save individual node values (latest values across all executions)
1584
+ saveNodeValues(ctx, inputs);
1585
+ return ctx;
1586
+ }
1587
+ //# sourceMappingURL=executor.js.map