machinaos 0.0.78 → 0.0.80

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 (743) hide show
  1. package/.env.template +74 -5
  2. package/{workflows/AI Assistant_workflow-1778504793388-ou1m1tz2x.json → .machina/workflows/AI Assistant_example_workflow-1779017037684-e2e5da7a.json } +164 -105
  3. package/{workflows/AI Employee_example_workflow-1777720598005-u4cm858dv.json → .machina/workflows/AI Employee_example_workflow-1779102911870-cbc76c82.json } +582 -328
  4. package/{workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json → .machina/workflows/Claude Assistant_example_workflow-1779095939967-2369cff4.json } +152 -83
  5. package/README.md +5 -2
  6. package/bin/cli.js +2 -2
  7. package/{machina → cli}/__main__.py +11 -7
  8. package/cli/_common.py +122 -0
  9. package/cli/buildenv.py +40 -0
  10. package/cli/cli.py +204 -0
  11. package/{machina → cli}/colors.py +10 -2
  12. package/cli/commands/__init__.py +1 -0
  13. package/cli/commands/_temporal_specs.py +59 -0
  14. package/{machina → cli}/commands/build.py +35 -45
  15. package/cli/commands/clean.py +141 -0
  16. package/cli/commands/daemon/__init__.py +47 -0
  17. package/cli/commands/daemon/_state.py +97 -0
  18. package/cli/commands/daemon/restart.py +14 -0
  19. package/cli/commands/daemon/start.py +49 -0
  20. package/cli/commands/daemon/status.py +20 -0
  21. package/cli/commands/daemon/stop.py +22 -0
  22. package/{machina → cli}/commands/dev.py +32 -42
  23. package/{machina → cli}/commands/docs.py +13 -11
  24. package/{machina → cli}/commands/start.py +69 -62
  25. package/{machina → cli}/commands/stop.py +7 -10
  26. package/{machina → cli}/commands/version.py +12 -6
  27. package/cli/config.py +170 -0
  28. package/cli/platform_.py +169 -0
  29. package/{machina → cli}/ports.py +42 -3
  30. package/{machina → cli}/run.py +29 -2
  31. package/{machina → cli}/supervisor.py +29 -12
  32. package/{machina → cli}/tcp.py +6 -2
  33. package/{machina → cli}/tree.py +38 -11
  34. package/client/dist/assets/{ActionBar-Du2MSFSz.js → ActionBar-Cjr3TF7g.js} +1 -1
  35. package/client/dist/assets/{ApiKeyInput-k2LBmBjb.js → ApiKeyInput-DIJE2PVA.js} +1 -1
  36. package/client/dist/assets/{ApiKeyPanel-C_bV9U0X.js → ApiKeyPanel-CPmye7uh.js} +1 -1
  37. package/client/dist/assets/{ApiUsageSection-CmVfwZzL.js → ApiUsageSection-TF_7gH2D.js} +1 -1
  38. package/client/dist/assets/{EmailPanel-CeKIMGu-.js → EmailPanel-Bs-xvbKR.js} +1 -1
  39. package/client/dist/assets/{OAuthPanel-KA3t3Q2K.js → OAuthPanel-BDtVJhAV.js} +1 -1
  40. package/client/dist/assets/{QrPairingPanel-NgNpJNuk.js → QrPairingPanel-BwJehTuZ.js} +1 -1
  41. package/client/dist/assets/{RateLimitSection-Du5YNVIA.js → RateLimitSection-CfNOoPIS.js} +1 -1
  42. package/client/dist/assets/{StatusCard-DNLyayXc.js → StatusCard-DkwIrgdP.js} +1 -1
  43. package/client/dist/assets/index-P2FzntoL.js +165 -0
  44. package/client/dist/index.html +1 -1
  45. package/client/package.json +1 -1
  46. package/client/src/Dashboard.tsx +128 -76
  47. package/client/src/adapters/nodeSpecToDescription.ts +7 -0
  48. package/client/src/assets/icons/index.test.ts +10 -0
  49. package/client/src/assets/icons/index.ts +16 -3
  50. package/client/src/components/AIAgentNode.tsx +8 -8
  51. package/client/src/components/ParameterRenderer.tsx +6 -3
  52. package/client/src/components/SkillEditorModal.tsx +1 -0
  53. package/client/src/components/credentials/panels/EmailPanel.tsx +2 -0
  54. package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +2 -0
  55. package/client/src/components/credentials/sections/RateLimitSection.tsx +1 -0
  56. package/client/src/components/icons/AIProviderIcons.tsx +1 -0
  57. package/client/src/components/maps/GoogleMapsPicker.tsx +1 -0
  58. package/client/src/components/parameterPanel/InputSection.tsx +1 -0
  59. package/client/src/components/parameterPanel/MasterSkillEditor.tsx +1 -0
  60. package/client/src/components/parameterPanel/OutputSection.tsx +1 -0
  61. package/client/src/components/ui/ComponentPalette.tsx +1 -0
  62. package/client/src/components/ui/MapSelector.tsx +1 -0
  63. package/client/src/components/ui/NodeContextMenu.tsx +3 -3
  64. package/client/src/components/ui/SettingsPanel.tsx +1 -0
  65. package/client/src/components/ui/action-button.tsx +1 -0
  66. package/client/src/components/ui/badge.tsx +1 -0
  67. package/client/src/components/ui/button.tsx +1 -0
  68. package/client/src/components/ui/form.tsx +1 -0
  69. package/client/src/components/ui/tabs.tsx +1 -0
  70. package/client/src/contexts/AuthContext.tsx +1 -0
  71. package/client/src/contexts/ThemeContext.tsx +1 -0
  72. package/client/src/contexts/WebSocketContext.tsx +104 -34
  73. package/client/src/hooks/__tests__/useApiKeys.test.ts +2 -2
  74. package/client/src/hooks/useReactFlowNodes.ts +1 -0
  75. package/client/src/hooks/useWorkflowValidation.ts +142 -0
  76. package/client/src/lib/nodeSpec.ts +1 -0
  77. package/client/src/test/providers.tsx +1 -0
  78. package/client/src/types/__tests__/cloudEvents.test.ts +5 -2
  79. package/client/src/types/cloudEvents.ts +19 -7
  80. package/client/src/utils/nodeUtils.ts +1 -1
  81. package/client/src/utils/workflow.ts +8 -2
  82. package/client/src/utils/workflowExport.ts +60 -3
  83. package/package.json +24 -23
  84. package/scripts/install.js +16 -27
  85. package/scripts/migrate_icons.py +3 -1
  86. package/scripts/migrate_skill_icons.py +6 -7
  87. package/scripts/postinstall.js +11 -9
  88. package/server/config/ai_cli_providers.json +2 -3
  89. package/server/config/credential_providers.json +15 -15
  90. package/server/config/llm_defaults.json +1 -1
  91. package/server/config/model_registry.json +416 -611
  92. package/server/constants.py +285 -223
  93. package/server/core/__init__.py +1 -1
  94. package/server/core/cache.py +9 -29
  95. package/server/core/cleanup.py +12 -24
  96. package/server/core/config.py +148 -24
  97. package/server/core/container.py +68 -59
  98. package/server/core/credential_backends.py +5 -13
  99. package/server/core/credentials_database.py +13 -43
  100. package/server/core/database.py +292 -353
  101. package/server/core/health.py +4 -5
  102. package/server/core/logging.py +241 -87
  103. package/server/core/paths.py +285 -0
  104. package/server/core/tracing.py +2 -8
  105. package/server/gunicorn.conf.py +1 -0
  106. package/server/main.py +150 -74
  107. package/server/middleware/auth.py +18 -24
  108. package/server/models/__init__.py +1 -1
  109. package/server/models/auth.py +5 -12
  110. package/server/models/database.py +36 -68
  111. package/server/models/node_metadata.py +25 -18
  112. package/server/nodejs/dist/index.js +107 -0
  113. package/server/nodes/README.md +11 -5
  114. package/server/nodes/__init__.py +1 -1
  115. package/server/nodes/_visuals.py +146 -14
  116. package/server/nodes/agent/_events.py +124 -0
  117. package/server/nodes/agent/_handles.py +15 -29
  118. package/server/nodes/agent/_inline.py +28 -25
  119. package/server/nodes/agent/_specialized.py +30 -15
  120. package/server/nodes/agent/{ai_agent.py → ai_agent/__init__.py} +33 -17
  121. package/server/nodes/agent/ai_agent/meta.json +3 -0
  122. package/server/nodes/agent/{ai_employee.py → ai_employee/__init__.py} +5 -2
  123. package/server/nodes/agent/ai_employee/meta.json +3 -0
  124. package/server/nodes/agent/{android_agent.py → android_agent/__init__.py} +1 -1
  125. package/server/nodes/agent/android_agent/meta.json +3 -0
  126. package/server/nodes/agent/{autonomous_agent.py → autonomous_agent/__init__.py} +2 -1
  127. package/server/nodes/agent/autonomous_agent/meta.json +3 -0
  128. package/server/nodes/agent/{chat_agent.py → chat_agent/__init__.py} +29 -12
  129. package/server/nodes/agent/chat_agent/meta.json +3 -0
  130. package/server/nodes/agent/{claude_code_agent.py → claude_code_agent/__init__.py} +192 -95
  131. package/server/nodes/agent/claude_code_agent/_handlers.py +169 -0
  132. package/server/{services/claude_oauth.py → nodes/agent/claude_code_agent/_oauth.py} +26 -13
  133. package/server/nodes/agent/claude_code_agent/_pool.py +1020 -0
  134. package/server/nodes/agent/claude_code_agent/_provider.py +513 -0
  135. package/server/nodes/agent/claude_code_agent/_skills.py +245 -0
  136. package/server/nodes/agent/claude_code_agent/meta.json +3 -0
  137. package/server/nodes/agent/{codex_agent.py → codex_agent/__init__.py} +26 -35
  138. package/server/nodes/agent/codex_agent/meta.json +3 -0
  139. package/server/nodes/agent/{coding_agent.py → coding_agent/__init__.py} +1 -1
  140. package/server/nodes/agent/coding_agent/meta.json +3 -0
  141. package/server/nodes/agent/{consumer_agent.py → consumer_agent/__init__.py} +1 -1
  142. package/server/nodes/agent/consumer_agent/meta.json +3 -0
  143. package/server/nodes/agent/{orchestrator_agent.py → orchestrator_agent/__init__.py} +5 -2
  144. package/server/nodes/agent/orchestrator_agent/meta.json +3 -0
  145. package/server/nodes/agent/{payments_agent.py → payments_agent/__init__.py} +1 -1
  146. package/server/nodes/agent/payments_agent/meta.json +3 -0
  147. package/server/nodes/agent/{productivity_agent.py → productivity_agent/__init__.py} +1 -1
  148. package/server/nodes/agent/productivity_agent/meta.json +3 -0
  149. package/server/nodes/agent/{rlm_agent.py → rlm_agent/__init__.py} +18 -17
  150. package/server/nodes/agent/rlm_agent/meta.json +3 -0
  151. package/server/nodes/agent/{social_agent.py → social_agent/__init__.py} +1 -1
  152. package/server/nodes/agent/social_agent/meta.json +3 -0
  153. package/server/nodes/agent/{task_agent.py → task_agent/__init__.py} +1 -1
  154. package/server/nodes/agent/task_agent/meta.json +3 -0
  155. package/server/nodes/agent/{tool_agent.py → tool_agent/__init__.py} +1 -1
  156. package/server/nodes/agent/tool_agent/meta.json +3 -0
  157. package/server/nodes/agent/{travel_agent.py → travel_agent/__init__.py} +1 -1
  158. package/server/nodes/agent/travel_agent/meta.json +3 -0
  159. package/server/nodes/agent/{web_agent.py → web_agent/__init__.py} +1 -1
  160. package/server/nodes/agent/web_agent/meta.json +3 -0
  161. package/server/nodes/android/__init__.py +24 -0
  162. package/server/nodes/android/_base.py +93 -76
  163. package/server/nodes/android/_dispatcher.py +140 -223
  164. package/server/nodes/android/_events.py +154 -0
  165. package/server/nodes/android/_handlers.py +13 -7
  166. package/server/nodes/android/_option_loaders.py +1 -4
  167. package/server/nodes/android/_refresh.py +27 -37
  168. package/server/nodes/android/_relay/broadcaster.py +25 -41
  169. package/server/nodes/android/_relay/client.py +23 -42
  170. package/server/nodes/android/_relay/manager.py +1 -0
  171. package/server/nodes/android/_relay/protocol.py +6 -0
  172. package/server/nodes/android/_router.py +48 -133
  173. package/server/nodes/android/{airplane_mode_control.py → airplane_mode_control/__init__.py} +2 -1
  174. package/server/nodes/android/airplane_mode_control/meta.json +3 -0
  175. package/server/nodes/android/{app_launcher.py → app_launcher/__init__.py} +2 -1
  176. package/server/nodes/android/app_launcher/meta.json +3 -0
  177. package/server/nodes/android/{app_list.py → app_list/__init__.py} +2 -1
  178. package/server/nodes/android/app_list/meta.json +3 -0
  179. package/server/nodes/android/{audio_automation.py → audio_automation/__init__.py} +2 -1
  180. package/server/nodes/android/audio_automation/meta.json +3 -0
  181. package/server/nodes/android/{battery_monitor.py → battery_monitor/__init__.py} +2 -1
  182. package/server/nodes/android/battery_monitor/meta.json +3 -0
  183. package/server/nodes/android/{bluetooth_automation.py → bluetooth_automation/__init__.py} +2 -1
  184. package/server/nodes/android/bluetooth_automation/meta.json +3 -0
  185. package/server/nodes/android/{camera_control.py → camera_control/__init__.py} +2 -1
  186. package/server/nodes/android/camera_control/meta.json +3 -0
  187. package/server/nodes/android/{device_state_automation.py → device_state_automation/__init__.py} +2 -1
  188. package/server/nodes/android/device_state_automation/meta.json +3 -0
  189. package/server/nodes/android/{environmental_sensors.py → environmental_sensors/__init__.py} +2 -1
  190. package/server/nodes/android/environmental_sensors/meta.json +3 -0
  191. package/server/nodes/android/{location.py → location/__init__.py} +2 -1
  192. package/server/nodes/android/location/meta.json +3 -0
  193. package/server/nodes/android/{media_control.py → media_control/__init__.py} +2 -1
  194. package/server/nodes/android/media_control/meta.json +3 -0
  195. package/server/nodes/android/{motion_detection.py → motion_detection/__init__.py} +2 -1
  196. package/server/nodes/android/motion_detection/meta.json +3 -0
  197. package/server/nodes/android/{network_monitor.py → network_monitor/__init__.py} +2 -1
  198. package/server/nodes/android/network_monitor/meta.json +3 -0
  199. package/server/nodes/android/{screen_control_automation.py → screen_control_automation/__init__.py} +2 -1
  200. package/server/nodes/android/screen_control_automation/meta.json +3 -0
  201. package/server/nodes/android/{system_info.py → system_info/__init__.py} +2 -1
  202. package/server/nodes/android/system_info/meta.json +3 -0
  203. package/server/nodes/android/{wifi_automation.py → wifi_automation/__init__.py} +2 -1
  204. package/server/nodes/android/wifi_automation/meta.json +3 -0
  205. package/server/nodes/browser/__init__.py +22 -1
  206. package/server/nodes/browser/_install.py +63 -0
  207. package/server/nodes/browser/_service.py +21 -25
  208. package/server/nodes/browser/{browser.py → browser/__init__.py} +58 -25
  209. package/server/nodes/browser/browser/meta.json +3 -0
  210. package/server/nodes/chat/{chat_history.py → chat_history/__init__.py} +2 -4
  211. package/server/nodes/chat/chat_history/meta.json +3 -0
  212. package/server/nodes/chat/{chat_send.py → chat_send/__init__.py} +2 -4
  213. package/server/nodes/chat/chat_send/icon.svg +1 -0
  214. package/server/nodes/chat/chat_send/meta.json +3 -0
  215. package/server/nodes/code/_base.py +1 -1
  216. package/server/nodes/code/{javascript_executor.py → javascript_executor/__init__.py} +5 -5
  217. package/server/nodes/code/javascript_executor/meta.json +3 -0
  218. package/server/nodes/code/{python_executor.py → python_executor/__init__.py} +32 -14
  219. package/server/nodes/code/python_executor/meta.json +3 -0
  220. package/server/nodes/code/{typescript_executor.py → typescript_executor/__init__.py} +5 -5
  221. package/server/nodes/code/typescript_executor/meta.json +3 -0
  222. package/server/nodes/document/{document_parser.py → document_parser/__init__.py} +26 -15
  223. package/server/nodes/document/document_parser/meta.json +3 -0
  224. package/server/nodes/document/{embedding_generator.py → embedding_generator/__init__.py} +16 -9
  225. package/server/nodes/document/embedding_generator/meta.json +3 -0
  226. package/server/nodes/document/{file_downloader.py → file_downloader/__init__.py} +30 -20
  227. package/server/nodes/document/file_downloader/meta.json +3 -0
  228. package/server/nodes/document/{http_scraper.py → http_scraper/__init__.py} +31 -21
  229. package/server/nodes/document/http_scraper/meta.json +3 -0
  230. package/server/nodes/document/{text_chunker.py → text_chunker/__init__.py} +17 -12
  231. package/server/nodes/document/text_chunker/meta.json +3 -0
  232. package/server/nodes/document/{vector_store.py → vector_store/__init__.py} +88 -72
  233. package/server/nodes/document/vector_store/meta.json +3 -0
  234. package/server/nodes/email/__init__.py +9 -2
  235. package/server/nodes/email/_events.py +54 -0
  236. package/server/nodes/email/_filters.py +3 -3
  237. package/server/nodes/email/_himalaya.py +95 -50
  238. package/server/nodes/email/_service.py +23 -13
  239. package/server/nodes/email/{email_read.py → email_read/__init__.py} +23 -11
  240. package/server/nodes/email/email_read/icon.svg +6 -0
  241. package/server/nodes/email/email_read/meta.json +3 -0
  242. package/server/nodes/email/{email_receive.py → email_receive/__init__.py} +45 -23
  243. package/server/nodes/email/email_receive/meta.json +3 -0
  244. package/server/nodes/email/{email_send.py → email_send/__init__.py} +13 -7
  245. package/server/nodes/email/email_send/meta.json +3 -0
  246. package/server/nodes/filesystem/_backend.py +1 -5
  247. package/server/nodes/filesystem/{file_modify.py → file_modify/__init__.py} +10 -5
  248. package/server/nodes/filesystem/file_modify/meta.json +3 -0
  249. package/server/nodes/filesystem/{file_read.py → file_read/__init__.py} +7 -3
  250. package/server/nodes/filesystem/file_read/meta.json +3 -0
  251. package/server/nodes/filesystem/{fs_search.py → fs_search/__init__.py} +11 -3
  252. package/server/nodes/filesystem/fs_search/meta.json +3 -0
  253. package/server/nodes/filesystem/{shell.py → shell/__init__.py} +12 -5
  254. package/server/nodes/filesystem/shell/meta.json +3 -0
  255. package/server/nodes/google/__init__.py +12 -0
  256. package/server/nodes/google/_auth_helper.py +7 -13
  257. package/server/nodes/google/_base.py +14 -11
  258. package/server/nodes/google/_credentials.py +2 -1
  259. package/server/nodes/google/_events.py +47 -0
  260. package/server/nodes/google/_filters.py +3 -3
  261. package/server/nodes/google/_gmail.py +70 -47
  262. package/server/nodes/google/_handlers.py +3 -1
  263. package/server/nodes/google/_oauth.py +25 -11
  264. package/server/nodes/google/_option_loaders.py +9 -30
  265. package/server/nodes/google/_refresh.py +8 -12
  266. package/server/nodes/google/_router.py +4 -5
  267. package/server/nodes/google/{calendar.py → calendar/__init__.py} +87 -64
  268. package/server/nodes/google/calendar/meta.json +3 -0
  269. package/server/nodes/google/{contacts.py → contacts/__init__.py} +84 -72
  270. package/server/nodes/google/contacts/meta.json +3 -0
  271. package/server/nodes/google/{drive.py → drive/__init__.py} +87 -72
  272. package/server/nodes/google/drive/meta.json +3 -0
  273. package/server/nodes/google/{gmail.py → gmail/__init__.py} +73 -39
  274. package/server/nodes/google/gmail/meta.json +3 -0
  275. package/server/nodes/google/{gmail_receive.py → gmail_receive/__init__.py} +31 -24
  276. package/server/nodes/google/gmail_receive/icon.svg +7 -0
  277. package/server/nodes/google/gmail_receive/meta.json +3 -0
  278. package/server/nodes/google/google.svg +7 -0
  279. package/server/nodes/google/{sheets.py → sheets/__init__.py} +54 -42
  280. package/server/nodes/google/sheets/meta.json +3 -0
  281. package/server/nodes/google/{tasks.py → tasks/__init__.py} +56 -43
  282. package/server/nodes/google/tasks/meta.json +3 -0
  283. package/server/nodes/groups.py +28 -28
  284. package/server/nodes/location/__init__.py +31 -1
  285. package/server/nodes/location/_credentials.py +1 -6
  286. package/server/nodes/location/_service.py +88 -107
  287. package/server/nodes/location/{gmaps_create.py → gmaps_create/__init__.py} +6 -6
  288. package/server/nodes/location/gmaps_create/meta.json +3 -0
  289. package/server/nodes/location/{gmaps_locations.py → gmaps_locations/__init__.py} +8 -6
  290. package/server/nodes/location/gmaps_locations/meta.json +3 -0
  291. package/server/nodes/location/{gmaps_nearby_places.py → gmaps_nearby_places/__init__.py} +8 -6
  292. package/server/nodes/location/gmaps_nearby_places/meta.json +3 -0
  293. package/server/nodes/model/_base.py +10 -7
  294. package/server/nodes/model/_credentials.py +10 -10
  295. package/server/nodes/model/_local_validator.py +28 -24
  296. package/server/nodes/model/{anthropic_chat_model.py → anthropic_chat_model/__init__.py} +5 -3
  297. package/server/nodes/model/anthropic_chat_model/meta.json +3 -0
  298. package/server/nodes/model/{cerebras_chat_model.py → cerebras_chat_model/__init__.py} +5 -3
  299. package/server/nodes/model/cerebras_chat_model/meta.json +3 -0
  300. package/server/nodes/model/{deepseek_chat_model.py → deepseek_chat_model/__init__.py} +8 -4
  301. package/server/nodes/model/deepseek_chat_model/meta.json +3 -0
  302. package/server/nodes/model/{gemini_chat_model.py → gemini_chat_model/__init__.py} +5 -3
  303. package/server/nodes/model/gemini_chat_model/meta.json +3 -0
  304. package/server/nodes/model/{groq_chat_model.py → groq_chat_model/__init__.py} +2 -2
  305. package/server/nodes/model/groq_chat_model/meta.json +3 -0
  306. package/server/nodes/model/{kimi_chat_model.py → kimi_chat_model/__init__.py} +2 -2
  307. package/server/nodes/model/kimi_chat_model/meta.json +3 -0
  308. package/server/nodes/model/{lmstudio_chat_model.py → lmstudio_chat_model/__init__.py} +2 -2
  309. package/server/nodes/model/lmstudio_chat_model/meta.json +3 -0
  310. package/server/nodes/model/{mistral_chat_model.py → mistral_chat_model/__init__.py} +2 -2
  311. package/server/nodes/model/mistral_chat_model/meta.json +3 -0
  312. package/server/nodes/model/{ollama_chat_model.py → ollama_chat_model/__init__.py} +2 -2
  313. package/server/nodes/model/ollama_chat_model/meta.json +3 -0
  314. package/server/nodes/model/{openai_chat_model.py → openai_chat_model/__init__.py} +8 -4
  315. package/server/nodes/model/openai_chat_model/meta.json +3 -0
  316. package/server/nodes/model/{openrouter_chat_model.py → openrouter_chat_model/__init__.py} +8 -4
  317. package/server/nodes/model/openrouter_chat_model/meta.json +3 -0
  318. package/server/nodes/proxy/_usage.py +14 -15
  319. package/server/nodes/proxy/{proxy_config.py → proxy_config/__init__.py} +39 -30
  320. package/server/nodes/proxy/proxy_config/meta.json +3 -0
  321. package/server/nodes/proxy/{proxy_request.py → proxy_request/__init__.py} +30 -16
  322. package/server/nodes/proxy/proxy_request/meta.json +3 -0
  323. package/server/nodes/proxy/{proxy_status.py → proxy_status/__init__.py} +2 -0
  324. package/server/nodes/proxy/proxy_status/meta.json +3 -0
  325. package/server/nodes/scheduler/{cron_scheduler.py → cron_scheduler/__init__.py} +96 -23
  326. package/server/nodes/scheduler/cron_scheduler/_workflow.py +155 -0
  327. package/server/nodes/scheduler/cron_scheduler/meta.json +3 -0
  328. package/server/nodes/scheduler/{timer.py → timer/__init__.py} +6 -5
  329. package/server/nodes/scheduler/timer/meta.json +3 -0
  330. package/server/nodes/scraper/_credentials.py +0 -1
  331. package/server/nodes/scraper/{apify_actor.py → apify_actor/__init__.py} +44 -35
  332. package/server/nodes/scraper/apify_actor/icon.svg +5 -0
  333. package/server/nodes/scraper/apify_actor/meta.json +3 -0
  334. package/server/nodes/scraper/{crawlee_scraper.py → crawlee_scraper/__init__.py} +96 -57
  335. package/server/nodes/scraper/crawlee_scraper/meta.json +3 -0
  336. package/server/nodes/search/{brave_search.py → brave_search/__init__.py} +6 -5
  337. package/server/nodes/search/brave_search/icon.svg +3 -0
  338. package/server/nodes/search/brave_search/meta.json +3 -0
  339. package/server/nodes/search/{duckduckgo_search.py → duckduckgo_search/__init__.py} +17 -6
  340. package/server/nodes/search/duckduckgo_search/meta.json +3 -0
  341. package/server/nodes/search/{perplexity_search.py → perplexity_search/__init__.py} +4 -5
  342. package/server/nodes/search/perplexity_search/icon.svg +3 -0
  343. package/server/nodes/search/perplexity_search/meta.json +3 -0
  344. package/server/nodes/search/{serper_search.py → serper_search/__init__.py} +32 -25
  345. package/server/nodes/search/serper_search/icon.svg +3 -0
  346. package/server/nodes/search/serper_search/meta.json +3 -0
  347. package/server/nodes/skill/__init__.py +21 -1
  348. package/server/nodes/skill/_expander.py +75 -0
  349. package/server/nodes/skill/{master_skill.py → master_skill/__init__.py} +2 -8
  350. package/server/nodes/skill/master_skill/_events.py +84 -0
  351. package/server/nodes/skill/master_skill/meta.json +3 -0
  352. package/server/nodes/skill/{simple_memory.py → simple_memory/__init__.py} +8 -16
  353. package/server/nodes/skill/simple_memory/meta.json +3 -0
  354. package/server/nodes/social/_base.py +223 -231
  355. package/server/nodes/social/{social_receive.py → social_receive/__init__.py} +38 -13
  356. package/server/nodes/social/social_receive/meta.json +3 -0
  357. package/server/nodes/social/{social_send.py → social_send/__init__.py} +71 -29
  358. package/server/nodes/social/social_send/icon.svg +1 -0
  359. package/server/nodes/social/social_send/meta.json +3 -0
  360. package/server/nodes/stripe/__init__.py +7 -3
  361. package/server/nodes/stripe/_credentials.py +0 -1
  362. package/server/nodes/stripe/_handlers.py +18 -7
  363. package/server/nodes/stripe/_install.py +14 -15
  364. package/server/nodes/stripe/_source.py +5 -5
  365. package/server/nodes/stripe/icon.svg +1 -0
  366. package/server/nodes/stripe/meta.json +3 -0
  367. package/server/nodes/stripe/stripe_action.py +4 -4
  368. package/server/nodes/stripe/stripe_receive.py +6 -9
  369. package/server/nodes/telegram/__init__.py +13 -0
  370. package/server/nodes/telegram/_credentials.py +2 -7
  371. package/server/nodes/telegram/_events.py +167 -0
  372. package/server/nodes/telegram/_filters.py +3 -11
  373. package/server/nodes/telegram/_handlers.py +17 -7
  374. package/server/nodes/telegram/_refresh.py +24 -34
  375. package/server/nodes/telegram/_service.py +29 -45
  376. package/server/nodes/telegram/meta.json +3 -0
  377. package/server/nodes/telegram/telegram.svg +3 -0
  378. package/server/nodes/telegram/telegram_receive.py +38 -18
  379. package/server/nodes/telegram/telegram_send.py +21 -19
  380. package/server/nodes/text/{file_handler.py → file_handler/__init__.py} +7 -1
  381. package/server/nodes/text/file_handler/meta.json +3 -0
  382. package/server/nodes/text/{text_generator.py → text_generator/__init__.py} +2 -1
  383. package/server/nodes/text/text_generator/meta.json +3 -0
  384. package/server/nodes/tool/{agent_builder.py → agent_builder/__init__.py} +105 -100
  385. package/server/nodes/tool/agent_builder/_events.py +91 -0
  386. package/server/nodes/tool/agent_builder/meta.json +3 -0
  387. package/server/nodes/tool/{calculator_tool.py → calculator_tool/__init__.py} +19 -7
  388. package/server/nodes/tool/calculator_tool/meta.json +3 -0
  389. package/server/nodes/tool/{current_time_tool.py → current_time_tool/__init__.py} +6 -4
  390. package/server/nodes/tool/current_time_tool/meta.json +3 -0
  391. package/server/nodes/tool/{task_manager.py → task_manager/__init__.py} +17 -18
  392. package/server/nodes/tool/task_manager/meta.json +3 -0
  393. package/server/nodes/tool/{write_todos.py → write_todos/__init__.py} +20 -6
  394. package/server/nodes/tool/write_todos/meta.json +3 -0
  395. package/server/nodes/trigger/{chat_trigger.py → chat_trigger/__init__.py} +11 -7
  396. package/server/nodes/trigger/chat_trigger/_events.py +53 -0
  397. package/server/nodes/trigger/chat_trigger/meta.json +3 -0
  398. package/server/nodes/trigger/{task_trigger.py → task_trigger/__init__.py} +10 -7
  399. package/server/nodes/trigger/task_trigger/meta.json +3 -0
  400. package/server/nodes/trigger/{webhook_trigger.py → webhook_trigger/__init__.py} +10 -7
  401. package/server/nodes/trigger/webhook_trigger/_events.py +54 -0
  402. package/server/nodes/trigger/webhook_trigger/meta.json +3 -0
  403. package/server/nodes/twitter/__init__.py +7 -1
  404. package/server/nodes/twitter/_base.py +86 -61
  405. package/server/nodes/twitter/_credentials.py +7 -5
  406. package/server/nodes/twitter/_events.py +101 -0
  407. package/server/nodes/twitter/_filters.py +9 -9
  408. package/server/nodes/twitter/_handlers.py +3 -1
  409. package/server/nodes/twitter/_oauth.py +1 -2
  410. package/server/nodes/twitter/_refresh.py +8 -12
  411. package/server/nodes/twitter/{twitter_receive.py → twitter_receive/__init__.py} +7 -7
  412. package/server/nodes/twitter/twitter_receive/icon.svg +1 -0
  413. package/server/nodes/twitter/twitter_receive/meta.json +3 -0
  414. package/server/nodes/twitter/{twitter_search.py → twitter_search/__init__.py} +16 -11
  415. package/server/nodes/twitter/twitter_search/icon.svg +1 -0
  416. package/server/nodes/twitter/twitter_search/meta.json +3 -0
  417. package/server/nodes/twitter/{twitter_send.py → twitter_send/__init__.py} +60 -27
  418. package/server/nodes/twitter/twitter_send/icon.svg +1 -0
  419. package/server/nodes/twitter/twitter_send/meta.json +3 -0
  420. package/server/nodes/twitter/{twitter_user.py → twitter_user/__init__.py} +34 -19
  421. package/server/nodes/twitter/twitter_user/icon.svg +1 -0
  422. package/server/nodes/twitter/twitter_user/meta.json +3 -0
  423. package/server/nodes/utility/{console.py → console/__init__.py} +17 -22
  424. package/server/nodes/utility/console/meta.json +3 -0
  425. package/server/nodes/utility/{http_request.py → http_request/__init__.py} +9 -6
  426. package/server/nodes/utility/http_request/meta.json +3 -0
  427. package/server/nodes/utility/{process_manager.py → process_manager/__init__.py} +10 -6
  428. package/server/nodes/utility/process_manager/meta.json +3 -0
  429. package/server/nodes/utility/team_monitor/meta.json +3 -0
  430. package/server/nodes/utility/{webhook_response.py → webhook_response/__init__.py} +12 -7
  431. package/server/nodes/utility/webhook_response/meta.json +3 -0
  432. package/server/nodes/visuals.json +69 -251
  433. package/server/nodes/whatsapp/__init__.py +24 -0
  434. package/server/nodes/whatsapp/_base.py +283 -338
  435. package/server/nodes/whatsapp/_credentials.py +44 -0
  436. package/server/nodes/whatsapp/_events.py +277 -0
  437. package/server/nodes/whatsapp/_filters.py +36 -37
  438. package/server/nodes/whatsapp/_handlers.py +2 -0
  439. package/server/nodes/whatsapp/_option_loaders.py +1 -3
  440. package/server/nodes/whatsapp/_refresh.py +13 -18
  441. package/server/nodes/whatsapp/_runtime.py +9 -6
  442. package/server/nodes/whatsapp/_service.py +89 -152
  443. package/server/nodes/whatsapp/meta.json +3 -0
  444. package/server/nodes/whatsapp/whatsapp_db.py +116 -54
  445. package/server/nodes/whatsapp/whatsapp_receive.py +30 -13
  446. package/server/nodes/whatsapp/whatsapp_send.py +60 -37
  447. package/server/nodes/workflow/{start.py → start/__init__.py} +1 -4
  448. package/server/nodes/workflow/start/meta.json +3 -0
  449. package/server/package-lock.json +3 -3
  450. package/server/package.json +3 -0
  451. package/server/pyproject.toml +39 -10
  452. package/server/requirements.txt +3 -5
  453. package/server/routers/__init__.py +1 -1
  454. package/server/routers/auth.py +16 -56
  455. package/server/routers/database.py +27 -50
  456. package/server/routers/nodejs_compat.py +25 -87
  457. package/server/routers/schemas.py +66 -2
  458. package/server/routers/webhook.py +12 -12
  459. package/server/routers/websocket.py +312 -1716
  460. package/server/routers/workflow.py +28 -53
  461. package/server/scripts/smoke_test_skills.py +178 -0
  462. package/server/services/__init__.py +1 -1
  463. package/server/services/_supervisor/process.py +9 -3
  464. package/server/services/_supervisor/registry.py +3 -3
  465. package/server/services/_supervisor/util.py +1 -1
  466. package/server/services/agent_team.py +15 -43
  467. package/server/services/agent_teams/__init__.py +17 -0
  468. package/server/services/agent_teams/handlers.py +195 -0
  469. package/server/services/ai.py +853 -1108
  470. package/server/services/auth.py +10 -34
  471. package/server/services/chat_client.py +5 -34
  472. package/server/services/circuit_breaker.py +2 -6
  473. package/server/services/cli_agent/__init__.py +28 -4
  474. package/server/services/cli_agent/_cli_auth.py +61 -0
  475. package/server/services/cli_agent/_handlers.py +24 -183
  476. package/server/services/cli_agent/config.py +5 -8
  477. package/server/services/cli_agent/factory.py +168 -22
  478. package/server/services/cli_agent/jsonl_watcher.py +380 -0
  479. package/server/services/cli_agent/lockfile.py +9 -2
  480. package/server/services/cli_agent/mcp_server.py +110 -34
  481. package/server/services/cli_agent/protocol.py +37 -19
  482. package/server/services/cli_agent/providers/__init__.py +8 -4
  483. package/server/services/cli_agent/providers/google_gemini.py +11 -5
  484. package/server/services/cli_agent/providers/openai_codex.py +34 -34
  485. package/server/services/cli_agent/service.py +245 -83
  486. package/server/services/cli_agent/session.py +409 -229
  487. package/server/services/cli_agent/transports/__init__.py +47 -0
  488. package/server/services/cli_agent/transports/base.py +111 -0
  489. package/server/services/cli_agent/transports/posix.py +196 -0
  490. package/server/services/cli_agent/transports/windows.py +189 -0
  491. package/server/services/cli_agent/types.py +45 -18
  492. package/server/services/cli_agent/workflow_tools.py +28 -15
  493. package/server/services/compaction.py +68 -52
  494. package/server/services/credential_registry.py +6 -20
  495. package/server/services/credentials/__init__.py +18 -0
  496. package/server/services/credentials/handlers.py +196 -0
  497. package/server/services/deployment/__init__.py +12 -1
  498. package/server/services/deployment/canary_registry.py +137 -0
  499. package/server/services/deployment/handlers.py +382 -0
  500. package/server/services/deployment/manager.py +653 -163
  501. package/server/services/deployment/poll_registry.py +2 -6
  502. package/server/services/deployment/state.py +2 -0
  503. package/server/services/deployment/triggers.py +87 -93
  504. package/server/services/event_waiter.py +47 -54
  505. package/server/services/events/__init__.py +11 -0
  506. package/server/services/events/admin_handlers.py +368 -0
  507. package/server/services/events/daemon.py +3 -1
  508. package/server/services/events/dispatch.py +188 -0
  509. package/server/services/events/envelope.py +264 -45
  510. package/server/services/events/oauth_lifecycle.py +98 -42
  511. package/server/services/events/triggers.py +3 -13
  512. package/server/services/events/verifiers/hmac_basic.py +1 -1
  513. package/server/services/events/verifiers/standard_webhooks.py +2 -4
  514. package/server/services/events/webhook.py +2 -3
  515. package/server/services/example_loader.py +73 -15
  516. package/server/services/execution/cache.py +36 -76
  517. package/server/services/execution/conditions.py +7 -20
  518. package/server/services/execution/dlq.py +20 -24
  519. package/server/services/execution/executor.py +234 -265
  520. package/server/services/execution/models.py +40 -46
  521. package/server/services/execution/recovery.py +23 -46
  522. package/server/services/handlers/__init__.py +12 -16
  523. package/server/services/handlers/todo.py +3 -6
  524. package/server/services/handlers/tools.py +143 -194
  525. package/server/services/handlers/triggers.py +24 -23
  526. package/server/services/llm/config.py +10 -1
  527. package/server/services/llm/factory.py +16 -4
  528. package/server/services/llm/messages.py +1 -5
  529. package/server/services/llm/protocol.py +9 -1
  530. package/server/services/llm/providers/anthropic.py +23 -12
  531. package/server/services/llm/providers/gemini.py +43 -22
  532. package/server/services/llm/providers/openai.py +14 -6
  533. package/server/services/llm/providers/openrouter.py +6 -1
  534. package/server/services/markdown_formatter.py +1 -2
  535. package/server/services/memory/__init__.py +2 -2
  536. package/server/services/memory/jsonl.py +6 -2
  537. package/server/services/memory/markdown.py +6 -6
  538. package/server/services/memory/state.py +6 -5
  539. package/server/services/memory_store.py +8 -12
  540. package/server/services/model_registry.py +22 -20
  541. package/server/services/node_executor.py +85 -80
  542. package/server/services/node_output_schemas.py +4 -7
  543. package/server/services/node_registry.py +40 -4
  544. package/server/services/node_spec.py +3 -7
  545. package/server/services/nodejs_client.py +4 -14
  546. package/server/services/oauth_utils.py +11 -7
  547. package/server/services/parameter_resolver.py +30 -36
  548. package/server/services/plugin/base.py +321 -38
  549. package/server/services/plugin/connection.py +12 -7
  550. package/server/services/plugin/credential.py +80 -22
  551. package/server/services/plugin/edge_walker.py +128 -105
  552. package/server/services/plugin/identifiers.py +48 -0
  553. package/server/services/plugin/interceptor.py +1 -1
  554. package/server/services/plugin/oauth.py +25 -21
  555. package/server/services/plugin/operation.py +1 -1
  556. package/server/services/plugin/polling.py +151 -26
  557. package/server/services/plugin/registry.py +52 -4
  558. package/server/services/plugin/routing.py +6 -9
  559. package/server/services/plugin/scaling.py +36 -18
  560. package/server/services/plugin/service_factories.py +95 -0
  561. package/server/services/plugin/shutdown_hooks.py +103 -0
  562. package/server/services/plugin/social_provider_registry.py +80 -0
  563. package/server/services/plugin/ws.py +2 -1
  564. package/server/services/pricing.py +26 -40
  565. package/server/services/pricing_handlers.py +90 -0
  566. package/server/services/process_service.py +33 -32
  567. package/server/services/proxy/models.py +15 -9
  568. package/server/services/proxy/service.py +26 -40
  569. package/server/services/rlm/adapters.py +43 -40
  570. package/server/services/rlm/constants.py +9 -9
  571. package/server/services/rlm/service.py +57 -45
  572. package/server/services/scheduler.py +8 -39
  573. package/server/services/settings/__init__.py +16 -0
  574. package/server/services/settings/handlers.py +275 -0
  575. package/server/services/skill_loader.py +53 -45
  576. package/server/services/skill_prompt.py +8 -6
  577. package/server/services/skills/__init__.py +23 -0
  578. package/server/services/skills/handlers.py +479 -0
  579. package/server/services/status_broadcaster.py +314 -291
  580. package/server/services/temporal/__init__.py +22 -1
  581. package/server/services/temporal/_handlers.py +65 -0
  582. package/server/services/temporal/_install.py +158 -0
  583. package/server/services/temporal/_refresh.py +57 -0
  584. package/server/services/temporal/_retry_policies.py +85 -0
  585. package/server/services/temporal/_runtime.py +181 -0
  586. package/server/services/temporal/_supervised_runtime.py +102 -0
  587. package/server/services/temporal/activities.py +168 -11
  588. package/server/services/temporal/agent_activities.py +683 -0
  589. package/server/services/temporal/agent_workflow.py +601 -0
  590. package/server/services/temporal/client.py +58 -13
  591. package/server/services/temporal/executor.py +2 -3
  592. package/server/services/temporal/plugin_activities.py +37 -2
  593. package/server/services/temporal/plugin_registry.py +82 -0
  594. package/server/services/temporal/polling_trigger_workflow.py +267 -0
  595. package/server/services/temporal/schedules.py +220 -0
  596. package/server/services/temporal/search_attributes.py +177 -0
  597. package/server/services/temporal/trigger_listener_workflow.py +378 -0
  598. package/server/services/temporal/worker.py +111 -18
  599. package/server/services/temporal/workflow.py +259 -40
  600. package/server/services/temporal/ws_client.py +22 -11
  601. package/server/services/text.py +14 -28
  602. package/server/services/tracked_http.py +29 -49
  603. package/server/services/user_auth.py +7 -21
  604. package/server/services/workflow.py +28 -20
  605. package/server/services/workflow_import.py +351 -0
  606. package/server/services/workflow_ops.py +4 -0
  607. package/server/services/workflow_storage/__init__.py +18 -0
  608. package/server/services/workflow_storage/handlers.py +132 -0
  609. package/server/services/workflow_validator.py +209 -0
  610. package/server/services/ws_handler_registry.py +80 -9
  611. package/server/skills/assistant/agent-builder-skill/SKILL.md +6 -6
  612. package/server/tests/conftest.py +54 -3
  613. package/server/tests/credentials/test_auth_service.py +9 -21
  614. package/server/tests/credentials/test_credential_broadcasts.py +116 -22
  615. package/server/tests/credentials/test_credentials_database.py +12 -38
  616. package/server/tests/credentials/test_encryption.py +3 -9
  617. package/server/tests/credentials/test_google_oauth.py +1 -3
  618. package/server/tests/credentials/test_oauth_utils.py +31 -38
  619. package/server/tests/credentials/test_twitter_oauth.py +1 -3
  620. package/server/tests/credentials/test_websocket_handlers.py +37 -72
  621. package/server/tests/fixtures/tool_names_snapshot.json +78 -0
  622. package/server/tests/llm/test_factory.py +12 -4
  623. package/server/tests/llm/test_providers.py +25 -32
  624. package/server/tests/llm/test_wiring.py +27 -22
  625. package/server/tests/nodes/_compat.py +4 -5
  626. package/server/tests/nodes/_harness.py +31 -24
  627. package/server/tests/nodes/_mocks.py +2 -6
  628. package/server/tests/nodes/test_agent_builder.py +43 -35
  629. package/server/tests/nodes/test_ai_agents.py +29 -24
  630. package/server/tests/nodes/test_ai_chat_models.py +3 -9
  631. package/server/tests/nodes/test_ai_tools.py +29 -24
  632. package/server/tests/nodes/test_android.py +34 -64
  633. package/server/tests/nodes/test_chat_utility.py +2 -2
  634. package/server/tests/nodes/test_code_fs_process.py +26 -84
  635. package/server/tests/nodes/test_document.py +23 -47
  636. package/server/tests/nodes/test_email.py +88 -51
  637. package/server/tests/nodes/test_google_workspace.py +26 -20
  638. package/server/tests/nodes/test_http_proxy.py +43 -89
  639. package/server/tests/nodes/test_search.py +3 -9
  640. package/server/tests/nodes/test_specialized_agents.py +58 -162
  641. package/server/tests/nodes/test_stripe_plugin.py +25 -5
  642. package/server/tests/nodes/test_telegram_social.py +33 -37
  643. package/server/tests/nodes/test_twitter.py +59 -150
  644. package/server/tests/nodes/test_web_automation.py +21 -51
  645. package/server/tests/nodes/test_whatsapp.py +13 -19
  646. package/server/tests/nodes/test_workflow_triggers.py +16 -45
  647. package/server/tests/services/cli_agent/test_claude_session_events.py +201 -0
  648. package/server/tests/services/cli_agent/test_jsonl_watcher.py +190 -0
  649. package/server/tests/services/cli_agent/test_mcp_server.py +67 -29
  650. package/server/tests/services/cli_agent/test_providers.py +236 -47
  651. package/server/tests/services/cli_agent/test_service.py +9 -7
  652. package/server/tests/services/memory/test_jsonl.py +30 -25
  653. package/server/tests/services/test_events.py +26 -7
  654. package/server/tests/services/test_identifiers.py +122 -0
  655. package/server/tests/services/test_process_lifecycle.py +129 -0
  656. package/server/tests/services/test_supervisor.py +0 -1
  657. package/server/tests/temporal/__init__.py +0 -0
  658. package/server/tests/temporal/test_agent_workflow.py +215 -0
  659. package/server/tests/temporal/test_dispatch.py +231 -0
  660. package/server/tests/test_admin_handlers.py +394 -0
  661. package/server/tests/test_auto_skill.py +4 -2
  662. package/server/tests/test_canary_registry.py +310 -0
  663. package/server/tests/test_chat_trigger_canary_producer.py +101 -0
  664. package/server/tests/test_cloudevents_node_parameters.py +129 -0
  665. package/server/tests/test_credential_icon.py +115 -0
  666. package/server/tests/test_cron_canary.py +511 -0
  667. package/server/tests/test_deployment_canary_listener.py +692 -0
  668. package/server/tests/test_event_framework_phase_a.py +537 -0
  669. package/server/tests/test_no_raw_prints.py +131 -0
  670. package/server/tests/test_node_spec.py +196 -103
  671. package/server/tests/test_parameter_resolver.py +20 -20
  672. package/server/tests/test_plugin_contract.py +76 -49
  673. package/server/tests/test_plugin_helpers.py +0 -1
  674. package/server/tests/test_plugin_self_containment.py +40 -47
  675. package/server/tests/test_polling_trigger_workflow.py +572 -0
  676. package/server/tests/test_retry_policies.py +146 -0
  677. package/server/tests/test_service_factories.py +168 -0
  678. package/server/tests/test_shutdown_hooks.py +199 -0
  679. package/server/tests/test_social_provider_registry.py +177 -0
  680. package/server/tests/test_status_broadcasts.py +214 -63
  681. package/server/tests/test_task_trigger_canary_producer.py +131 -0
  682. package/server/tests/test_telegram_trigger_canary_producer.py +113 -0
  683. package/server/tests/test_tool_registry.py +110 -0
  684. package/server/tests/test_trigger_listener_workflow.py +365 -0
  685. package/server/tests/test_whatsapp_trigger_canary_producer.py +164 -0
  686. package/server/tests/test_workflow_ops.py +1 -3
  687. package/server/tests/test_workflow_validator.py +791 -0
  688. package/server/uv.lock +3539 -0
  689. package/client/dist/assets/index-DQ0nwhec.js +0 -257
  690. package/client/src/assets/icons/apify/index.ts +0 -19
  691. package/client/src/assets/icons/browser/index.ts +0 -17
  692. package/client/src/assets/icons/email/index.ts +0 -22
  693. package/client/src/assets/icons/google/index.ts +0 -34
  694. package/client/src/assets/icons/llm/deepseek.svg +0 -1
  695. package/client/src/assets/icons/llm/index.ts +0 -18
  696. package/client/src/assets/icons/llm/kimi.svg +0 -1
  697. package/client/src/assets/icons/llm/mistral.svg +0 -1
  698. package/client/src/assets/icons/search/index.ts +0 -28
  699. package/client/src/assets/icons/telegram/index.ts +0 -19
  700. package/machina/buildenv.py +0 -44
  701. package/machina/cli.py +0 -55
  702. package/machina/commands/__init__.py +0 -1
  703. package/machina/commands/clean.py +0 -80
  704. package/machina/commands/daemon.py +0 -150
  705. package/machina/config.py +0 -93
  706. package/machina/platform_.py +0 -37
  707. package/machina/pyproject.toml +0 -33
  708. package/server/nodes/agent/deep_agent.py +0 -103
  709. package/server/services/agents/__init__.py +0 -9
  710. package/server/services/agents/adapters.py +0 -199
  711. package/server/services/agents/constants.py +0 -10
  712. package/server/services/agents/service.py +0 -297
  713. package/server/services/cli_agent/providers/anthropic_claude.py +0 -419
  714. /package/{machina → cli}/README.md +0 -0
  715. /package/{machina → cli}/__init__.py +0 -0
  716. /package/{client/src/assets/icons/apify → server/credentials/icons}/apify.svg +0 -0
  717. /package/{client/src/assets/icons/search/brave.svg → server/credentials/icons/brave_search.svg} +0 -0
  718. /package/{client/src/assets/icons/email/read.svg → server/credentials/icons/email_himalaya.svg} +0 -0
  719. /package/{client/src/assets/icons/search → server/credentials/icons}/perplexity.svg +0 -0
  720. /package/{client/src/assets/icons/search/google.svg → server/credentials/icons/serper.svg} +0 -0
  721. /package/{client/src/assets → server/credentials}/icons/stripe.svg +0 -0
  722. /package/{client/src/assets/icons/twitter/x.svg → server/credentials/icons/twitter.svg} +0 -0
  723. /package/{client/src/assets/icons/browser/chrome.svg → server/nodes/browser/browser/icon.svg} +0 -0
  724. /package/{client/src/assets/icons/chat/chat.svg → server/nodes/chat/chat_history/icon.svg} +0 -0
  725. /package/{client/src/assets/icons/code/javascript.svg → server/nodes/code/javascript_executor/icon.svg} +0 -0
  726. /package/{client/src/assets/icons/code/python.svg → server/nodes/code/python_executor/icon.svg} +0 -0
  727. /package/{client/src/assets/icons/code/typescript.svg → server/nodes/code/typescript_executor/icon.svg} +0 -0
  728. /package/{client/src/assets/icons/email/receive.svg → server/nodes/email/email_receive/icon.svg} +0 -0
  729. /package/{client/src/assets/icons/email/send.svg → server/nodes/email/email_send/icon.svg} +0 -0
  730. /package/{client/src/assets/icons/google/calendar.svg → server/nodes/google/calendar/icon.svg} +0 -0
  731. /package/{client/src/assets/icons/google/contacts.svg → server/nodes/google/contacts/icon.svg} +0 -0
  732. /package/{client/src/assets/icons/google/drive.svg → server/nodes/google/drive/icon.svg} +0 -0
  733. /package/{client/src/assets/icons/google/gmail.svg → server/nodes/google/gmail/icon.svg} +0 -0
  734. /package/{client/src/assets/icons/google/sheets.svg → server/nodes/google/sheets/icon.svg} +0 -0
  735. /package/{client/src/assets/icons/google/tasks.svg → server/nodes/google/tasks/icon.svg} +0 -0
  736. /package/{client/src/assets/icons/search/duckduckgo.svg → server/nodes/search/duckduckgo_search/icon.svg} +0 -0
  737. /package/{client/src/assets/icons/social/social.svg → server/nodes/social/social_receive/icon.svg} +0 -0
  738. /package/{client/src/assets/icons/telegram/telegram.svg → server/nodes/telegram/icon.svg} +0 -0
  739. /package/server/nodes/utility/{team_monitor.py → team_monitor/__init__.py} +0 -0
  740. /package/{client/src/assets/icons/whatsapp/whatsapp-db.svg → server/nodes/whatsapp/icon_whatsappDb.svg} +0 -0
  741. /package/{client/src/assets/icons/whatsapp/whatsapp-receive.svg → server/nodes/whatsapp/icon_whatsappReceive.svg} +0 -0
  742. /package/{client/src/assets/icons/whatsapp/whatsapp-send.svg → server/nodes/whatsapp/icon_whatsappSend.svg} +0 -0
  743. /package/{client/src/assets/icons → server/nodes}/whatsapp/whatsapp.svg +0 -0
@@ -57,10 +57,13 @@ class WorkflowExecutor:
57
57
  - Event history for debugging and recovery
58
58
  """
59
59
 
60
- def __init__(self, cache: ExecutionCache,
61
- node_executor: Callable[[str, str, Dict, Dict], Awaitable[Dict]],
62
- status_callback: Callable[[str, str, Dict], Awaitable[None]] = None,
63
- dlq_enabled: bool = False):
60
+ def __init__(
61
+ self,
62
+ cache: ExecutionCache,
63
+ node_executor: Callable[[str, str, Dict, Dict], Awaitable[Dict]],
64
+ status_callback: Callable[[str, str, Dict], Awaitable[None]] = None,
65
+ dlq_enabled: bool = False,
66
+ ):
64
67
  """Initialize executor.
65
68
 
66
69
  Args:
@@ -85,9 +88,9 @@ class WorkflowExecutor:
85
88
  # EXECUTION ENTRY POINTS
86
89
  # =========================================================================
87
90
 
88
- async def execute_workflow(self, workflow_id: str, nodes: List[Dict],
89
- edges: List[Dict], session_id: str = "default",
90
- enable_caching: bool = True) -> Dict[str, Any]:
91
+ async def execute_workflow(
92
+ self, workflow_id: str, nodes: List[Dict], edges: List[Dict], session_id: str = "default", enable_caching: bool = True
93
+ ) -> Dict[str, Any]:
91
94
  """Execute a workflow with parallel node execution.
92
95
 
93
96
  Args:
@@ -113,11 +116,13 @@ class WorkflowExecutor:
113
116
  # Compute execution layers (for parallel batches)
114
117
  ctx.execution_order = self._compute_execution_layers(nodes, edges)
115
118
 
116
- logger.info("Starting workflow execution",
117
- execution_id=ctx.execution_id,
118
- workflow_id=workflow_id,
119
- node_count=len(nodes),
120
- layers=len(ctx.execution_order))
119
+ logger.info(
120
+ "Starting workflow execution",
121
+ execution_id=ctx.execution_id,
122
+ workflow_id=workflow_id,
123
+ node_count=len(nodes),
124
+ layers=len(ctx.execution_order),
125
+ )
121
126
 
122
127
  # Track in memory
123
128
  self._active_contexts[ctx.execution_id] = ctx
@@ -128,10 +133,14 @@ class WorkflowExecutor:
128
133
  await self.cache.save_execution_state(ctx)
129
134
 
130
135
  # Add workflow_started event
131
- await self.cache.add_event(ctx.execution_id, "workflow_started", {
132
- "workflow_id": workflow_id,
133
- "node_count": len(nodes),
134
- })
136
+ await self.cache.add_event(
137
+ ctx.execution_id,
138
+ "workflow_started",
139
+ {
140
+ "workflow_id": workflow_id,
141
+ "node_count": len(nodes),
142
+ },
143
+ )
135
144
 
136
145
  try:
137
146
  # Run the decide loop
@@ -147,11 +156,15 @@ class WorkflowExecutor:
147
156
  await self.cache.save_execution_state(ctx)
148
157
 
149
158
  # Add workflow_completed event
150
- await self.cache.add_event(ctx.execution_id, "workflow_completed", {
151
- "status": ctx.status.value,
152
- "completed_nodes": len(ctx.get_completed_nodes()),
153
- "execution_time": ctx.completed_at - ctx.started_at,
154
- })
159
+ await self.cache.add_event(
160
+ ctx.execution_id,
161
+ "workflow_completed",
162
+ {
163
+ "status": ctx.status.value,
164
+ "completed_nodes": len(ctx.get_completed_nodes()),
165
+ "execution_time": ctx.completed_at - ctx.started_at,
166
+ },
167
+ )
155
168
 
156
169
  return {
157
170
  "success": ctx.status == WorkflowStatus.COMPLETED,
@@ -178,14 +191,17 @@ class WorkflowExecutor:
178
191
  }
179
192
 
180
193
  except Exception as e:
181
- logger.error("Workflow execution failed", execution_id=ctx.execution_id,
182
- error=str(e))
194
+ logger.error("Workflow execution failed", execution_id=ctx.execution_id, error=str(e))
183
195
  ctx.status = WorkflowStatus.FAILED
184
196
  ctx.errors.append({"error": str(e), "timestamp": time.time()})
185
197
  await self.cache.save_execution_state(ctx)
186
- await self.cache.add_event(ctx.execution_id, "workflow_failed", {
187
- "error": str(e),
188
- })
198
+ await self.cache.add_event(
199
+ ctx.execution_id,
200
+ "workflow_failed",
201
+ {
202
+ "error": str(e),
203
+ },
204
+ )
189
205
  return {
190
206
  "success": False,
191
207
  "execution_id": ctx.execution_id,
@@ -211,8 +227,7 @@ class WorkflowExecutor:
211
227
  if ctx:
212
228
  ctx.status = WorkflowStatus.CANCELLED
213
229
  for node_exec in ctx.node_executions.values():
214
- if node_exec.status in (TaskStatus.PENDING, TaskStatus.SCHEDULED,
215
- TaskStatus.RUNNING, TaskStatus.WAITING):
230
+ if node_exec.status in (TaskStatus.PENDING, TaskStatus.SCHEDULED, TaskStatus.RUNNING, TaskStatus.WAITING):
216
231
  node_exec.status = TaskStatus.CANCELLED
217
232
  await self.cache.save_execution_state(ctx)
218
233
  logger.info("Execution cancelled", execution_id=execution_id)
@@ -223,8 +238,7 @@ class WorkflowExecutor:
223
238
  # CONDUCTOR DECIDE PATTERN
224
239
  # =========================================================================
225
240
 
226
- async def _workflow_decide(self, ctx: ExecutionContext,
227
- enable_caching: bool = True) -> None:
241
+ async def _workflow_decide(self, ctx: ExecutionContext, enable_caching: bool = True) -> None:
228
242
  """Core orchestration loop - Conductor's decide pattern.
229
243
 
230
244
  Evaluates current state, finds ready nodes, executes them in parallel,
@@ -236,19 +250,15 @@ class WorkflowExecutor:
236
250
  """
237
251
  # Distributed lock prevents concurrent decides for same execution
238
252
  try:
239
- async with self.cache.distributed_lock(
240
- f"execution:{ctx.execution_id}:decide", timeout=60
241
- ):
253
+ async with self.cache.distributed_lock(f"execution:{ctx.execution_id}:decide", timeout=60):
242
254
  await self._decide_iteration(ctx, enable_caching)
243
255
  except TimeoutError:
244
- logger.warning("Could not acquire decide lock",
245
- execution_id=ctx.execution_id)
256
+ logger.warning("Could not acquire decide lock", execution_id=ctx.execution_id)
246
257
  # Retry after short delay
247
258
  await asyncio.sleep(0.5)
248
259
  await self._workflow_decide(ctx, enable_caching)
249
260
 
250
- async def _decide_iteration(self, ctx: ExecutionContext,
251
- enable_caching: bool) -> None:
261
+ async def _decide_iteration(self, ctx: ExecutionContext, enable_caching: bool) -> None:
252
262
  """Continuous scheduling loop - Temporal/Conductor pattern.
253
263
 
254
264
  When any node completes, immediately check for newly-ready dependents
@@ -270,15 +280,15 @@ class WorkflowExecutor:
270
280
  else:
271
281
  pending = ctx.get_pending_nodes()
272
282
  if pending:
273
- logger.warning("Stuck: pending nodes with unsatisfied deps",
274
- execution_id=ctx.execution_id,
275
- pending=pending)
283
+ logger.warning("Stuck: pending nodes with unsatisfied deps", execution_id=ctx.execution_id, pending=pending)
276
284
  return
277
285
 
278
- logger.info("Starting continuous execution",
279
- execution_id=ctx.execution_id,
280
- initial_batch=len(ready_nodes),
281
- nodes=[n.node_id for n in ready_nodes])
286
+ logger.info(
287
+ "Starting continuous execution",
288
+ execution_id=ctx.execution_id,
289
+ initial_batch=len(ready_nodes),
290
+ nodes=[n.node_id for n in ready_nodes],
291
+ )
282
292
 
283
293
  # Execute with continuous scheduling - new pattern
284
294
  await self._execute_with_continuous_scheduling(ctx, ready_nodes, enable_caching)
@@ -291,10 +301,7 @@ class WorkflowExecutor:
291
301
  # =========================================================================
292
302
 
293
303
  async def _execute_with_continuous_scheduling(
294
- self,
295
- ctx: ExecutionContext,
296
- initial_nodes: List[NodeExecution],
297
- enable_caching: bool
304
+ self, ctx: ExecutionContext, initial_nodes: List[NodeExecution], enable_caching: bool
298
305
  ) -> None:
299
306
  """Execute workflow with continuous scheduling.
300
307
 
@@ -317,10 +324,7 @@ class WorkflowExecutor:
317
324
  def create_node_task(node: NodeExecution) -> asyncio.Task:
318
325
  """Create and track a task for node execution."""
319
326
  node.status = TaskStatus.SCHEDULED
320
- task = asyncio.create_task(
321
- self._execute_node_with_retry(ctx, node, enable_caching),
322
- name=f"node_{node.node_id}"
323
- )
327
+ task = asyncio.create_task(self._execute_node_with_retry(ctx, node, enable_caching), name=f"node_{node.node_id}")
324
328
  task_to_node[task] = node
325
329
  pending_tasks.add(task)
326
330
  return task
@@ -340,10 +344,7 @@ class WorkflowExecutor:
340
344
  break
341
345
 
342
346
  # Wait for ANY task to complete
343
- done, pending_tasks = await asyncio.wait(
344
- pending_tasks,
345
- return_when=asyncio.FIRST_COMPLETED
346
- )
347
+ done, pending_tasks = await asyncio.wait(pending_tasks, return_when=asyncio.FIRST_COMPLETED)
347
348
 
348
349
  # Process each completed task
349
350
  for task in done:
@@ -357,11 +358,13 @@ class WorkflowExecutor:
357
358
  node.status = TaskStatus.FAILED
358
359
  node.error = str(result)
359
360
  node.completed_at = time.time()
360
- ctx.errors.append({
361
- "node_id": node.node_id,
362
- "error": str(result),
363
- "timestamp": time.time(),
364
- })
361
+ ctx.errors.append(
362
+ {
363
+ "node_id": node.node_id,
364
+ "error": str(result),
365
+ "timestamp": time.time(),
366
+ }
367
+ )
365
368
  await self._notify_status(node.node_id, "error", {"error": str(result)})
366
369
  logger.error("Node failed", node_id=node.node_id, error=str(result))
367
370
  workflow_failed = True
@@ -370,23 +373,27 @@ class WorkflowExecutor:
370
373
  node.status = TaskStatus.FAILED
371
374
  node.error = result.get("error", "Unknown error")
372
375
  node.completed_at = time.time()
373
- ctx.errors.append({
374
- "node_id": node.node_id,
375
- "error": node.error,
376
- "retries_exhausted": True,
377
- "timestamp": time.time(),
378
- })
376
+ ctx.errors.append(
377
+ {
378
+ "node_id": node.node_id,
379
+ "error": node.error,
380
+ "retries_exhausted": True,
381
+ "timestamp": time.time(),
382
+ }
383
+ )
379
384
  workflow_failed = True
380
385
 
381
386
  elif not result.get("success"):
382
387
  node.status = TaskStatus.FAILED
383
388
  node.error = result.get("error", "Unknown error")
384
389
  node.completed_at = time.time()
385
- ctx.errors.append({
386
- "node_id": node.node_id,
387
- "error": node.error,
388
- "timestamp": time.time(),
389
- })
390
+ ctx.errors.append(
391
+ {
392
+ "node_id": node.node_id,
393
+ "error": node.error,
394
+ "timestamp": time.time(),
395
+ }
396
+ )
390
397
  await self._notify_status(node.node_id, "error", {"error": node.error})
391
398
  logger.error("Node failed", node_id=node.node_id, error=node.error)
392
399
  workflow_failed = True
@@ -408,11 +415,13 @@ class WorkflowExecutor:
408
415
  node.status = TaskStatus.FAILED
409
416
  node.error = str(e)
410
417
  node.completed_at = time.time()
411
- ctx.errors.append({
412
- "node_id": node.node_id,
413
- "error": str(e),
414
- "timestamp": time.time(),
415
- })
418
+ ctx.errors.append(
419
+ {
420
+ "node_id": node.node_id,
421
+ "error": str(e),
422
+ "timestamp": time.time(),
423
+ }
424
+ )
416
425
  await self._notify_status(node.node_id, "error", {"error": str(e)})
417
426
  logger.error("Node exception", node_id=node.node_id, error=str(e))
418
427
  workflow_failed = True
@@ -422,27 +431,21 @@ class WorkflowExecutor:
422
431
  for ready_node in newly_ready:
423
432
  create_node_task(ready_node)
424
433
  await self._notify_status(ready_node.node_id, "scheduled", {})
425
- logger.info("Scheduled dependent node",
426
- node_id=ready_node.node_id,
427
- triggered_by=node.node_id)
434
+ logger.info("Scheduled dependent node", node_id=ready_node.node_id, triggered_by=node.node_id)
428
435
 
429
436
  # Periodic state save
430
437
  await self.cache.save_execution_state(ctx)
431
438
 
432
439
  # Handle workflow failure - cancel remaining tasks
433
440
  if workflow_failed and pending_tasks:
434
- logger.info("Workflow failed, cancelling remaining tasks",
435
- pending_count=len(pending_tasks))
441
+ logger.info("Workflow failed, cancelling remaining tasks", pending_count=len(pending_tasks))
436
442
 
437
443
  for task in pending_tasks:
438
444
  task.cancel()
439
445
 
440
446
  # Wait for cancelled tasks
441
447
  if pending_tasks:
442
- cancelled_done, _ = await asyncio.wait(
443
- pending_tasks,
444
- return_when=asyncio.ALL_COMPLETED
445
- )
448
+ cancelled_done, _ = await asyncio.wait(pending_tasks, return_when=asyncio.ALL_COMPLETED)
446
449
 
447
450
  for task in cancelled_done:
448
451
  node = task_to_node.get(task)
@@ -456,9 +459,7 @@ class WorkflowExecutor:
456
459
  # PARALLEL EXECUTION (Legacy - Fork/Join with FIRST_COMPLETED pattern)
457
460
  # =========================================================================
458
461
 
459
- async def _execute_parallel_nodes(self, ctx: ExecutionContext,
460
- nodes: List[NodeExecution],
461
- enable_caching: bool) -> None:
462
+ async def _execute_parallel_nodes(self, ctx: ExecutionContext, nodes: List[NodeExecution], enable_caching: bool) -> None:
462
463
  """Execute multiple nodes in parallel using asyncio.wait with FIRST_COMPLETED.
463
464
 
464
465
  Uses the standard asyncio pattern for mixed task types:
@@ -485,10 +486,7 @@ class WorkflowExecutor:
485
486
  task_to_node: Dict[asyncio.Task, NodeExecution] = {}
486
487
 
487
488
  for node in nodes:
488
- task = asyncio.create_task(
489
- self._execute_node_with_retry(ctx, node, enable_caching),
490
- name=f"node_{node.node_id}"
491
- )
489
+ task = asyncio.create_task(self._execute_node_with_retry(ctx, node, enable_caching), name=f"node_{node.node_id}")
492
490
  node_to_task[node.node_id] = task
493
491
  task_to_node[task] = node
494
492
 
@@ -498,10 +496,7 @@ class WorkflowExecutor:
498
496
  # Process tasks as they complete using FIRST_COMPLETED pattern
499
497
  while pending:
500
498
  # Wait for any task to complete
501
- done, pending = await asyncio.wait(
502
- pending,
503
- return_when=asyncio.FIRST_COMPLETED
504
- )
499
+ done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
505
500
 
506
501
  # Process completed tasks
507
502
  for task in done:
@@ -515,14 +510,15 @@ class WorkflowExecutor:
515
510
  node.status = TaskStatus.FAILED
516
511
  node.error = str(result)
517
512
  node.completed_at = time.time()
518
- ctx.errors.append({
519
- "node_id": node.node_id,
520
- "error": str(result),
521
- "timestamp": time.time(),
522
- })
513
+ ctx.errors.append(
514
+ {
515
+ "node_id": node.node_id,
516
+ "error": str(result),
517
+ "timestamp": time.time(),
518
+ }
519
+ )
523
520
  await self._notify_status(node.node_id, "error", {"error": str(result)})
524
- logger.error("Parallel node failed",
525
- node_id=node.node_id, error=str(result))
521
+ logger.error("Parallel node failed", node_id=node.node_id, error=str(result))
526
522
  workflow_failed = True
527
523
 
528
524
  elif result.get("retries_exhausted"):
@@ -530,12 +526,14 @@ class WorkflowExecutor:
530
526
  node.status = TaskStatus.FAILED
531
527
  node.error = result.get("error", "Unknown error")
532
528
  node.completed_at = time.time()
533
- ctx.errors.append({
534
- "node_id": node.node_id,
535
- "error": node.error,
536
- "retries_exhausted": True,
537
- "timestamp": time.time(),
538
- })
529
+ ctx.errors.append(
530
+ {
531
+ "node_id": node.node_id,
532
+ "error": node.error,
533
+ "retries_exhausted": True,
534
+ "timestamp": time.time(),
535
+ }
536
+ )
539
537
  workflow_failed = True
540
538
 
541
539
  elif not result.get("success"):
@@ -543,14 +541,15 @@ class WorkflowExecutor:
543
541
  node.status = TaskStatus.FAILED
544
542
  node.error = result.get("error", "Unknown error")
545
543
  node.completed_at = time.time()
546
- ctx.errors.append({
547
- "node_id": node.node_id,
548
- "error": node.error,
549
- "timestamp": time.time(),
550
- })
544
+ ctx.errors.append(
545
+ {
546
+ "node_id": node.node_id,
547
+ "error": node.error,
548
+ "timestamp": time.time(),
549
+ }
550
+ )
551
551
  await self._notify_status(node.node_id, "error", {"error": node.error})
552
- logger.error("Parallel node failed",
553
- node_id=node.node_id, error=node.error)
552
+ logger.error("Parallel node failed", node_id=node.node_id, error=node.error)
554
553
  workflow_failed = True
555
554
 
556
555
  except asyncio.CancelledError:
@@ -564,31 +563,28 @@ class WorkflowExecutor:
564
563
  node.status = TaskStatus.FAILED
565
564
  node.error = str(e)
566
565
  node.completed_at = time.time()
567
- ctx.errors.append({
568
- "node_id": node.node_id,
569
- "error": str(e),
570
- "timestamp": time.time(),
571
- })
566
+ ctx.errors.append(
567
+ {
568
+ "node_id": node.node_id,
569
+ "error": str(e),
570
+ "timestamp": time.time(),
571
+ }
572
+ )
572
573
  await self._notify_status(node.node_id, "error", {"error": str(e)})
573
- logger.error("Parallel node exception",
574
- node_id=node.node_id, error=str(e))
574
+ logger.error("Parallel node exception", node_id=node.node_id, error=str(e))
575
575
  workflow_failed = True
576
576
 
577
577
  # If workflow failed, cancel remaining pending tasks
578
578
  # This prevents trigger nodes from blocking forever when a regular node fails
579
579
  if workflow_failed and pending:
580
- logger.info("Workflow failed, cancelling remaining tasks",
581
- pending_count=len(pending))
580
+ logger.info("Workflow failed, cancelling remaining tasks", pending_count=len(pending))
582
581
 
583
582
  for task in pending:
584
583
  task.cancel()
585
584
 
586
585
  # Wait for cancelled tasks to finish
587
586
  if pending:
588
- cancelled_done, _ = await asyncio.wait(
589
- pending,
590
- return_when=asyncio.ALL_COMPLETED
591
- )
587
+ cancelled_done, _ = await asyncio.wait(pending, return_when=asyncio.ALL_COMPLETED)
592
588
 
593
589
  # Mark cancelled nodes
594
590
  for task in cancelled_done:
@@ -604,9 +600,7 @@ class WorkflowExecutor:
604
600
  if workflow_failed:
605
601
  ctx.status = WorkflowStatus.FAILED
606
602
 
607
- async def _execute_single_node(self, ctx: ExecutionContext,
608
- node: NodeExecution,
609
- enable_caching: bool) -> None:
603
+ async def _execute_single_node(self, ctx: ExecutionContext, node: NodeExecution, enable_caching: bool) -> None:
610
604
  """Execute a single node with retry logic.
611
605
 
612
606
  Args:
@@ -625,23 +619,27 @@ class WorkflowExecutor:
625
619
  node.status = TaskStatus.FAILED
626
620
  node.error = result.get("error", "Unknown error")
627
621
  node.completed_at = time.time()
628
- ctx.errors.append({
629
- "node_id": node.node_id,
630
- "error": node.error,
631
- "retries_exhausted": True,
632
- "timestamp": time.time(),
633
- })
622
+ ctx.errors.append(
623
+ {
624
+ "node_id": node.node_id,
625
+ "error": node.error,
626
+ "retries_exhausted": True,
627
+ "timestamp": time.time(),
628
+ }
629
+ )
634
630
  ctx.status = WorkflowStatus.FAILED
635
631
 
636
632
  except Exception as e:
637
633
  node.status = TaskStatus.FAILED
638
634
  node.error = str(e)
639
635
  node.completed_at = time.time()
640
- ctx.errors.append({
641
- "node_id": node.node_id,
642
- "error": str(e),
643
- "timestamp": time.time(),
644
- })
636
+ ctx.errors.append(
637
+ {
638
+ "node_id": node.node_id,
639
+ "error": str(e),
640
+ "timestamp": time.time(),
641
+ }
642
+ )
645
643
  await self._notify_status(node.node_id, "error", {"error": str(e)})
646
644
  ctx.status = WorkflowStatus.FAILED
647
645
 
@@ -649,9 +647,7 @@ class WorkflowExecutor:
649
647
  # RETRY LOGIC
650
648
  # =========================================================================
651
649
 
652
- async def _execute_node_with_retry(self, ctx: ExecutionContext,
653
- node: NodeExecution,
654
- enable_caching: bool) -> Dict[str, Any]:
650
+ async def _execute_node_with_retry(self, ctx: ExecutionContext, node: NodeExecution, enable_caching: bool) -> Dict[str, Any]:
655
651
  """Execute node with retry logic and DLQ on final failure.
656
652
 
657
653
  Uses exponential backoff retry policy based on node type.
@@ -689,19 +685,25 @@ class WorkflowExecutor:
689
685
  # Check if we should retry
690
686
  if retry_policy.should_retry(error, attempt + 1):
691
687
  delay = retry_policy.calculate_delay(attempt)
692
- logger.info("Retrying node after failure",
693
- node_id=node.node_id,
694
- attempt=attempt + 1,
695
- max_attempts=retry_policy.max_attempts,
696
- delay=delay,
697
- error=error[:100])
698
-
699
- await self._notify_status(node.node_id, "retrying", {
700
- "attempt": attempt + 1,
701
- "max_attempts": retry_policy.max_attempts,
702
- "delay": delay,
703
- "error": error,
704
- })
688
+ logger.info(
689
+ "Retrying node after failure",
690
+ node_id=node.node_id,
691
+ attempt=attempt + 1,
692
+ max_attempts=retry_policy.max_attempts,
693
+ delay=delay,
694
+ error=error[:100],
695
+ )
696
+
697
+ await self._notify_status(
698
+ node.node_id,
699
+ "retrying",
700
+ {
701
+ "attempt": attempt + 1,
702
+ "max_attempts": retry_policy.max_attempts,
703
+ "delay": delay,
704
+ "error": error,
705
+ },
706
+ )
705
707
 
706
708
  await asyncio.sleep(delay)
707
709
 
@@ -717,18 +719,12 @@ class WorkflowExecutor:
717
719
  raise # Propagate cancellation
718
720
  except Exception as e:
719
721
  last_error = str(e)
720
- logger.warning("Node execution exception",
721
- node_id=node.node_id,
722
- attempt=attempt + 1,
723
- error=last_error)
722
+ logger.warning("Node execution exception", node_id=node.node_id, attempt=attempt + 1, error=last_error)
724
723
 
725
724
  # Check if we should retry
726
725
  if retry_policy.should_retry(last_error, attempt + 1):
727
726
  delay = retry_policy.calculate_delay(attempt)
728
- logger.info("Retrying node after exception",
729
- node_id=node.node_id,
730
- attempt=attempt + 1,
731
- delay=delay)
727
+ logger.info("Retrying node after exception", node_id=node.node_id, attempt=attempt + 1, delay=delay)
732
728
 
733
729
  await asyncio.sleep(delay)
734
730
  node.status = TaskStatus.PENDING
@@ -752,9 +748,7 @@ class WorkflowExecutor:
752
748
  # CACHED NODE EXECUTION (Prefect pattern)
753
749
  # =========================================================================
754
750
 
755
- async def _execute_node_with_caching(self, ctx: ExecutionContext,
756
- node: NodeExecution,
757
- enable_caching: bool) -> Dict[str, Any]:
751
+ async def _execute_node_with_caching(self, ctx: ExecutionContext, node: NodeExecution, enable_caching: bool) -> Dict[str, Any]:
758
752
  """Execute node with result caching (Prefect pattern).
759
753
 
760
754
  Args:
@@ -771,9 +765,7 @@ class WorkflowExecutor:
771
765
 
772
766
  # Check cache first (Prefect pattern)
773
767
  if enable_caching:
774
- cached_result = await self.cache.get_cached_result(
775
- ctx.execution_id, node.node_id, inputs
776
- )
768
+ cached_result = await self.cache.get_cached_result(ctx.execution_id, node.node_id, inputs)
777
769
  if cached_result:
778
770
  logger.info("Cache hit", node_id=node.node_id)
779
771
  node.status = TaskStatus.CACHED
@@ -781,11 +773,14 @@ class WorkflowExecutor:
781
773
  node.input_hash = hash_inputs(inputs)
782
774
  node.completed_at = time.time()
783
775
  ctx.outputs[node.node_id] = cached_result
784
- await self._notify_status(node.node_id, "success",
785
- {"cached": True, **cached_result})
786
- await self.cache.add_event(ctx.execution_id, "node_cached", {
787
- "node_id": node.node_id,
788
- })
776
+ await self._notify_status(node.node_id, "success", {"cached": True, **cached_result})
777
+ await self.cache.add_event(
778
+ ctx.execution_id,
779
+ "node_cached",
780
+ {
781
+ "node_id": node.node_id,
782
+ },
783
+ )
789
784
  return cached_result
790
785
 
791
786
  # Execute node
@@ -793,10 +788,14 @@ class WorkflowExecutor:
793
788
  node.started_at = time.time()
794
789
  node.input_hash = hash_inputs(inputs)
795
790
  await self._notify_status(node.node_id, "executing", {})
796
- await self.cache.add_event(ctx.execution_id, "node_started", {
797
- "node_id": node.node_id,
798
- "node_type": node.node_type,
799
- })
791
+ await self.cache.add_event(
792
+ ctx.execution_id,
793
+ "node_started",
794
+ {
795
+ "node_id": node.node_id,
796
+ "node_type": node.node_type,
797
+ },
798
+ )
800
799
 
801
800
  # Update heartbeat (for crash detection)
802
801
  await self.cache.update_heartbeat(ctx.execution_id, node.node_id)
@@ -816,12 +815,7 @@ class WorkflowExecutor:
816
815
  logger.info(f"[Executor] exec_context['outputs'] keys: {list(exec_context['outputs'].keys())}")
817
816
 
818
817
  # Call the actual node executor
819
- result = await self.node_executor(
820
- node.node_id,
821
- node.node_type,
822
- node_data.get("parameters", {}),
823
- exec_context
824
- )
818
+ result = await self.node_executor(node.node_id, node.node_type, node_data.get("parameters", {}), exec_context)
825
819
 
826
820
  # Process result
827
821
  if result.get("success"):
@@ -832,30 +826,38 @@ class WorkflowExecutor:
832
826
 
833
827
  # Cache result (Prefect pattern)
834
828
  if enable_caching:
835
- await self.cache.set_cached_result(
836
- ctx.execution_id, node.node_id, inputs, node.output
837
- )
829
+ await self.cache.set_cached_result(ctx.execution_id, node.node_id, inputs, node.output)
838
830
 
839
831
  await self._notify_status(node.node_id, "success", node.output)
840
- await self.cache.add_event(ctx.execution_id, "node_completed", {
841
- "node_id": node.node_id,
842
- "execution_time": node.completed_at - node.started_at,
843
- })
832
+ await self.cache.add_event(
833
+ ctx.execution_id,
834
+ "node_completed",
835
+ {
836
+ "node_id": node.node_id,
837
+ "execution_time": node.completed_at - node.started_at,
838
+ },
839
+ )
844
840
  else:
845
841
  node.status = TaskStatus.FAILED
846
842
  node.error = result.get("error", "Unknown error")
847
843
  node.completed_at = time.time()
848
- ctx.errors.append({
849
- "node_id": node.node_id,
850
- "error": node.error,
851
- "timestamp": time.time(),
852
- })
844
+ ctx.errors.append(
845
+ {
846
+ "node_id": node.node_id,
847
+ "error": node.error,
848
+ "timestamp": time.time(),
849
+ }
850
+ )
853
851
 
854
852
  await self._notify_status(node.node_id, "error", {"error": node.error})
855
- await self.cache.add_event(ctx.execution_id, "node_failed", {
856
- "node_id": node.node_id,
857
- "error": node.error,
858
- })
853
+ await self.cache.add_event(
854
+ ctx.execution_id,
855
+ "node_failed",
856
+ {
857
+ "node_id": node.node_id,
858
+ "error": node.error,
859
+ },
860
+ )
859
861
 
860
862
  # Mark workflow as failed
861
863
  ctx.status = WorkflowStatus.FAILED
@@ -866,8 +868,7 @@ class WorkflowExecutor:
866
868
  # DAG ANALYSIS
867
869
  # =========================================================================
868
870
 
869
- def _compute_execution_layers(self, nodes: List[Dict],
870
- edges: List[Dict]) -> List[List[str]]:
871
+ def _compute_execution_layers(self, nodes: List[Dict], edges: List[Dict]) -> List[List[str]]:
871
872
  """Compute execution layers for parallel execution.
872
873
 
873
874
  Nodes in the same layer have no dependencies on each other
@@ -891,9 +892,7 @@ class WorkflowExecutor:
891
892
  from constants import CONFIG_NODE_TYPES, TOOLKIT_NODE_TYPES, AI_AGENT_TYPES
892
893
 
893
894
  # Build node type lookup for trigger detection
894
- node_types: Dict[str, str] = {
895
- node["id"]: node.get("type", "unknown") for node in nodes
896
- }
895
+ node_types: Dict[str, str] = {node["id"]: node.get("type", "unknown") for node in nodes}
897
896
 
898
897
  # Find toolkit sub-nodes (nodes that connect TO a toolkit)
899
898
  toolkit_node_ids = {n.get("id") for n in nodes if n.get("type") in TOOLKIT_NODE_TYPES}
@@ -914,7 +913,7 @@ class WorkflowExecutor:
914
913
  # Nodes connected to AI Agent config handles are sub-nodes
915
914
  # These handles: input-memory, input-tools, input-skill, input-teammates
916
915
  if target in ai_agent_node_ids and source and target_handle:
917
- if target_handle in ('input-memory', 'input-tools', 'input-skill', 'input-teammates'):
916
+ if target_handle in ("input-memory", "input-tools", "input-skill", "input-teammates"):
918
917
  subnode_ids.add(source)
919
918
 
920
919
  # Filter out config nodes and sub-nodes from execution
@@ -949,15 +948,11 @@ class WorkflowExecutor:
949
948
 
950
949
  while remaining:
951
950
  # Find all nodes with in-degree 0 (no dependencies)
952
- layer = [
953
- node_id for node_id in remaining
954
- if in_degree[node_id] == 0
955
- ]
951
+ layer = [node_id for node_id in remaining if in_degree[node_id] == 0]
956
952
 
957
953
  if not layer:
958
954
  # Cycle detected or stuck
959
- logger.warning("Cycle detected or no start nodes",
960
- remaining=list(remaining))
955
+ logger.warning("Cycle detected or no start nodes", remaining=list(remaining))
961
956
  # Add remaining as single layer to avoid infinite loop
962
957
  layers.append(list(remaining))
963
958
  break
@@ -977,7 +972,7 @@ class WorkflowExecutor:
977
972
  "Non-trigger node found at graph entry point",
978
973
  node_id=node_id,
979
974
  node_type=node_type,
980
- expected_types=list(WORKFLOW_TRIGGER_TYPES)
975
+ expected_types=list(WORKFLOW_TRIGGER_TYPES),
981
976
  )
982
977
 
983
978
  # Log trigger node identification
@@ -985,10 +980,7 @@ class WorkflowExecutor:
985
980
  logger.info(
986
981
  "Identified trigger nodes as workflow starting points",
987
982
  trigger_count=len(trigger_nodes),
988
- trigger_nodes=[
989
- f"{nid[:8]}({node_types.get(nid)})"
990
- for nid in trigger_nodes
991
- ]
983
+ trigger_nodes=[f"{nid[:8]}({node_types.get(nid)})" for nid in trigger_nodes],
992
984
  )
993
985
 
994
986
  is_first_layer = False
@@ -1001,9 +993,7 @@ class WorkflowExecutor:
1001
993
  for successor in adjacency[node_id]:
1002
994
  in_degree[successor] -= 1
1003
995
 
1004
- logger.debug("Computed execution layers",
1005
- layer_count=len(layers),
1006
- layers=[[n[:8] for n in layer] for layer in layers])
996
+ logger.debug("Computed execution layers", layer_count=len(layers), layers=[[n[:8] for n in layer] for layer in layers])
1007
997
 
1008
998
  return layers
1009
999
 
@@ -1077,22 +1067,18 @@ class WorkflowExecutor:
1077
1067
  # Check conditional edges for this node
1078
1068
  if node_id in conditional_edges:
1079
1069
  # Has conditional incoming edges - evaluate them
1080
- conditions_met = self._evaluate_incoming_conditions(
1081
- ctx, node_id, conditional_edges[node_id]
1082
- )
1070
+ conditions_met = self._evaluate_incoming_conditions(ctx, node_id, conditional_edges[node_id])
1083
1071
  if not conditions_met:
1084
1072
  # Mark as SKIPPED if conditions not met and all deps done
1085
1073
  node_exec.status = TaskStatus.SKIPPED
1086
- logger.info("Node skipped due to unmet conditions",
1087
- node_id=node_id)
1074
+ logger.info("Node skipped due to unmet conditions", node_id=node_id)
1088
1075
  continue
1089
1076
 
1090
1077
  ready.append(node_exec)
1091
1078
 
1092
1079
  return ready
1093
1080
 
1094
- def _evaluate_incoming_conditions(self, ctx: ExecutionContext, target_node_id: str,
1095
- edges: List[Dict]) -> bool:
1081
+ def _evaluate_incoming_conditions(self, ctx: ExecutionContext, target_node_id: str, edges: List[Dict]) -> bool:
1096
1082
  """Evaluate conditions on incoming edges to determine if node should run.
1097
1083
 
1098
1084
  Args:
@@ -1115,16 +1101,11 @@ class WorkflowExecutor:
1115
1101
 
1116
1102
  # Evaluate condition
1117
1103
  if evaluate_condition(condition, source_output):
1118
- logger.debug("Conditional edge matched",
1119
- source=source_id,
1120
- target=target_node_id,
1121
- condition=condition)
1104
+ logger.debug("Conditional edge matched", source=source_id, target=target_node_id, condition=condition)
1122
1105
  return True
1123
1106
 
1124
1107
  # No conditions matched
1125
- logger.debug("No conditional edges matched",
1126
- target=target_node_id,
1127
- edge_count=len(edges))
1108
+ logger.debug("No conditional edges matched", target=target_node_id, edge_count=len(edges))
1128
1109
  return False
1129
1110
 
1130
1111
  def _get_node_data(self, ctx: ExecutionContext, node_id: str) -> Dict[str, Any]:
@@ -1167,8 +1148,7 @@ class WorkflowExecutor:
1167
1148
  # STATUS NOTIFICATIONS
1168
1149
  # =========================================================================
1169
1150
 
1170
- async def _notify_status(self, node_id: str, status: str,
1171
- data: Dict[str, Any]) -> None:
1151
+ async def _notify_status(self, node_id: str, status: str, data: Dict[str, Any]) -> None:
1172
1152
  """Send status notification via callback.
1173
1153
 
1174
1154
  Args:
@@ -1186,9 +1166,7 @@ class WorkflowExecutor:
1186
1166
  # RECOVERY
1187
1167
  # =========================================================================
1188
1168
 
1189
- async def recover_execution(self, execution_id: str,
1190
- nodes: List[Dict],
1191
- edges: List[Dict]) -> Optional[Dict[str, Any]]:
1169
+ async def recover_execution(self, execution_id: str, nodes: List[Dict], edges: List[Dict]) -> Optional[Dict[str, Any]]:
1192
1170
  """Recover and resume an interrupted execution.
1193
1171
 
1194
1172
  Args:
@@ -1205,8 +1183,7 @@ class WorkflowExecutor:
1205
1183
  return None
1206
1184
 
1207
1185
  if ctx.status != WorkflowStatus.RUNNING:
1208
- logger.info("Execution already complete", execution_id=execution_id,
1209
- status=ctx.status.value)
1186
+ logger.info("Execution already complete", execution_id=execution_id, status=ctx.status.value)
1210
1187
  return {
1211
1188
  "success": ctx.status == WorkflowStatus.COMPLETED,
1212
1189
  "execution_id": execution_id,
@@ -1214,9 +1191,7 @@ class WorkflowExecutor:
1214
1191
  "recovered": False,
1215
1192
  }
1216
1193
 
1217
- logger.info("Recovering execution",
1218
- execution_id=execution_id,
1219
- checkpoints=ctx.checkpoints)
1194
+ logger.info("Recovering execution", execution_id=execution_id, checkpoints=ctx.checkpoints)
1220
1195
 
1221
1196
  # Reset any RUNNING nodes to PENDING (they were interrupted)
1222
1197
  for node_exec in ctx.node_executions.values():
@@ -1262,9 +1237,7 @@ class WorkflowExecutor:
1262
1237
  # DLQ REPLAY
1263
1238
  # =========================================================================
1264
1239
 
1265
- async def replay_dlq_entry(self, entry_id: str,
1266
- nodes: List[Dict],
1267
- edges: List[Dict]) -> Dict[str, Any]:
1240
+ async def replay_dlq_entry(self, entry_id: str, nodes: List[Dict], edges: List[Dict]) -> Dict[str, Any]:
1268
1241
  """Replay a failed node from the Dead Letter Queue.
1269
1242
 
1270
1243
  Creates a new execution context and attempts to re-execute the failed node.
@@ -1285,11 +1258,13 @@ class WorkflowExecutor:
1285
1258
  "error": f"DLQ entry not found: {entry_id}",
1286
1259
  }
1287
1260
 
1288
- logger.info("Replaying DLQ entry",
1289
- entry_id=entry_id,
1290
- node_id=entry.node_id,
1291
- node_type=entry.node_type,
1292
- original_execution=entry.execution_id)
1261
+ logger.info(
1262
+ "Replaying DLQ entry",
1263
+ entry_id=entry_id,
1264
+ node_id=entry.node_id,
1265
+ node_type=entry.node_type,
1266
+ original_execution=entry.execution_id,
1267
+ )
1293
1268
 
1294
1269
  # Create new execution context for replay
1295
1270
  ctx = ExecutionContext.create(
@@ -1321,9 +1296,7 @@ class WorkflowExecutor:
1321
1296
  if node_exec.status == TaskStatus.COMPLETED:
1322
1297
  # Success - remove from DLQ
1323
1298
  await self.cache.remove_from_dlq(entry_id)
1324
- logger.info("DLQ replay succeeded",
1325
- entry_id=entry_id,
1326
- node_id=entry.node_id)
1299
+ logger.info("DLQ replay succeeded", entry_id=entry_id, node_id=entry.node_id)
1327
1300
 
1328
1301
  return {
1329
1302
  "success": True,
@@ -1334,11 +1307,7 @@ class WorkflowExecutor:
1334
1307
  }
1335
1308
  else:
1336
1309
  # Still failing - update DLQ entry
1337
- await self.cache.update_dlq_entry(
1338
- entry_id,
1339
- entry.retry_count + 1,
1340
- node_exec.error or "Unknown error"
1341
- )
1310
+ await self.cache.update_dlq_entry(entry_id, entry.retry_count + 1, node_exec.error or "Unknown error")
1342
1311
 
1343
1312
  return {
1344
1313
  "success": False,