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
@@ -98,11 +98,7 @@ class OAuthStateStore:
98
98
  def cleanup_expired(self) -> int:
99
99
  """Remove states older than ``ttl_seconds``. Returns count removed."""
100
100
  now = time.time()
101
- expired = [
102
- state
103
- for state, record in self._states.items()
104
- if now - record.get("created_at", 0) > self.ttl_seconds
105
- ]
101
+ expired = [state for state, record in self._states.items() if now - record.get("created_at", 0) > self.ttl_seconds]
106
102
  for state in expired:
107
103
  self._states.pop(state, None)
108
104
  if expired:
@@ -180,9 +176,7 @@ class OAuth2PKCEClient(ABC):
180
176
  scopes: Optional[List[str]] = None,
181
177
  ) -> None:
182
178
  if not self.provider:
183
- raise ValueError(
184
- f"{type(self).__name__} must set the ``provider`` ClassVar"
185
- )
179
+ raise ValueError(f"{type(self).__name__} must set the ``provider`` ClassVar")
186
180
  self.client_id = client_id
187
181
  self.client_secret = client_secret
188
182
  self.redirect_uri = redirect_uri
@@ -207,11 +201,14 @@ class OAuth2PKCEClient(ABC):
207
201
  code_verifier = _generate_code_verifier()
208
202
  code_challenge = _generate_code_challenge(code_verifier)
209
203
 
210
- self.state_store.put(state, {
211
- "code_verifier": code_verifier,
212
- "redirect_uri": self.redirect_uri,
213
- "data": state_data or {},
214
- })
204
+ self.state_store.put(
205
+ state,
206
+ {
207
+ "code_verifier": code_verifier,
208
+ "redirect_uri": self.redirect_uri,
209
+ "data": state_data or {},
210
+ },
211
+ )
215
212
 
216
213
  params = {
217
214
  "response_type": "code",
@@ -240,9 +237,7 @@ class OAuth2PKCEClient(ABC):
240
237
  in the header. Public clients put ``client_id`` in the body.
241
238
  """
242
239
  if self.client_secret:
243
- credentials = base64.b64encode(
244
- f"{self.client_id}:{self.client_secret}".encode()
245
- ).decode()
240
+ credentials = base64.b64encode(f"{self.client_id}:{self.client_secret}".encode()).decode()
246
241
  return {}, {"Authorization": f"Basic {credentials}"}
247
242
  return {"client_id": self.client_id}, {}
248
243
 
@@ -266,7 +261,9 @@ class OAuth2PKCEClient(ABC):
266
261
  try:
267
262
  async with httpx.AsyncClient(timeout=30.0) as client:
268
263
  response = await client.post(
269
- self.token_endpoint, data=body, headers=headers,
264
+ self.token_endpoint,
265
+ data=body,
266
+ headers=headers,
270
267
  )
271
268
  except httpx.HTTPError as exc:
272
269
  logger.error(f"[{self.provider}] HTTP error during token exchange: {exc}")
@@ -276,7 +273,8 @@ class OAuth2PKCEClient(ABC):
276
273
  error_data = response.json() if response.text else {}
277
274
  logger.error(
278
275
  f"[{self.provider}] Token exchange failed",
279
- status=response.status_code, error=error_data,
276
+ status=response.status_code,
277
+ error=error_data,
280
278
  )
281
279
  return {
282
280
  "success": False,
@@ -306,7 +304,9 @@ class OAuth2PKCEClient(ABC):
306
304
  try:
307
305
  async with httpx.AsyncClient(timeout=30.0) as client:
308
306
  response = await client.post(
309
- self.token_endpoint, data=body, headers=headers,
307
+ self.token_endpoint,
308
+ data=body,
309
+ headers=headers,
310
310
  )
311
311
  except httpx.HTTPError as exc:
312
312
  logger.error(f"[{self.provider}] HTTP error during token refresh: {exc}")
@@ -329,7 +329,9 @@ class OAuth2PKCEClient(ABC):
329
329
  }
330
330
 
331
331
  async def revoke_token(
332
- self, token: str, token_type: str = "access_token",
332
+ self,
333
+ token: str,
334
+ token_type: str = "access_token",
333
335
  ) -> Dict[str, Any]:
334
336
  """Revoke an access or refresh token (best-effort).
335
337
 
@@ -348,7 +350,9 @@ class OAuth2PKCEClient(ABC):
348
350
  try:
349
351
  async with httpx.AsyncClient(timeout=30.0) as client:
350
352
  response = await client.post(
351
- self.revocation_endpoint, data=body, headers=headers,
353
+ self.revocation_endpoint,
354
+ data=body,
355
+ headers=headers,
352
356
  )
353
357
  except httpx.HTTPError as exc:
354
358
  logger.error(f"[{self.provider}] HTTP error during token revoke: {exc}")
@@ -32,7 +32,7 @@ class OperationSpec:
32
32
  name: str
33
33
  method: Callable[..., Awaitable[Any]]
34
34
  routing: Optional[Routing] = None
35
- cost: Optional[Dict[str, Any]] = None # {"usage": "gmail_send", "count": 1}
35
+ cost: Optional[Dict[str, Any]] = None # {"usage": "gmail_send", "count": 1}
36
36
  annotations: Dict[str, Any] = field(default_factory=dict)
37
37
 
38
38
 
@@ -46,7 +46,7 @@ Out of scope (commit-stage)
46
46
  from __future__ import annotations
47
47
 
48
48
  import asyncio
49
- from typing import Any, Callable, ClassVar, Dict, Optional, Set, Tuple
49
+ from typing import Any, Callable, ClassVar, Dict, Set, Tuple
50
50
 
51
51
  from core.logging import get_logger
52
52
  from services.plugin.trigger import TriggerNode
@@ -97,9 +97,7 @@ class PollingTriggerNode(TriggerNode, abstract=True):
97
97
  """
98
98
  raise NotImplementedError
99
99
 
100
- async def fetch_ids(
101
- self, service: Any, params: Dict[str, Any]
102
- ) -> Set[str]:
100
+ async def fetch_ids(self, service: Any, params: Dict[str, Any]) -> Set[str]:
103
101
  """Return the current set of visible IDs for one poll cycle.
104
102
 
105
103
  Called once for the baseline pass at loop start, then once per
@@ -108,9 +106,7 @@ class PollingTriggerNode(TriggerNode, abstract=True):
108
106
  """
109
107
  raise NotImplementedError
110
108
 
111
- async def fetch_detail(
112
- self, service: Any, msg_id: str, params: Dict[str, Any]
113
- ) -> Dict[str, Any]:
109
+ async def fetch_detail(self, service: Any, msg_id: str, params: Dict[str, Any]) -> Dict[str, Any]:
114
110
  """Fetch the full event payload for one ID.
115
111
 
116
112
  Called once per new ID per cycle. The returned dict goes
@@ -119,9 +115,7 @@ class PollingTriggerNode(TriggerNode, abstract=True):
119
115
  """
120
116
  raise NotImplementedError
121
117
 
122
- async def post_emit(
123
- self, service: Any, msg_id: str, params: Dict[str, Any]
124
- ) -> None:
118
+ async def post_emit(self, service: Any, msg_id: str, params: Dict[str, Any]) -> None:
125
119
  """Optional side effect AFTER the payload was enqueued.
126
120
 
127
121
  Default no-op. Override for "mark-as-read" or similar
@@ -166,22 +160,131 @@ class PollingTriggerNode(TriggerNode, abstract=True):
166
160
  value = self.default_poll_interval
167
161
  return max(lo, min(hi, value))
168
162
 
169
- def _build_poll_coroutine(
170
- self, node_id: str, params: Dict[str, Any]
171
- ) -> Callable[[asyncio.Queue, Callable[[], bool]], Any]:
163
+ # ---- Wave 12 C2: per-cycle Temporal activity --------------------------
164
+ #
165
+ # The asyncio coroutine version above feeds the legacy
166
+ # ``setup_polling_trigger`` collector/processor task pair (dies on
167
+ # FastAPI restart). The Temporal-durable version below — yielded by
168
+ # :meth:`as_poll_activity` — does ONE cycle and returns events,
169
+ # called per ``workflow.sleep`` tick in
170
+ # :class:`services.temporal.polling_trigger_workflow.PollingTriggerWorkflow`.
171
+ # The seen-id baseline survives via workflow state (carried across
172
+ # ``continueAsNew``) rather than living inside the asyncio task.
173
+
174
+ @classmethod
175
+ def as_poll_activity(cls):
176
+ """Return a ``@activity.defn`` wrapping one poll cycle.
177
+
178
+ Stable activity name: ``poll.{type}.v{version}``.
179
+
180
+ Activity payload (in)::
181
+
182
+ {
183
+ "node_id": str,
184
+ "params": Dict[str, Any],
185
+ "seen_ids": List[str], # provider-side IDs from prior cycle
186
+ "baseline_only": bool, # True on the first call after start
187
+ }
188
+
189
+ Activity result (out)::
190
+
191
+ {
192
+ "events": List[Dict], # NEW event payloads this cycle
193
+ "seen_ids": List[str], # union of prior seen + current
194
+ }
195
+
196
+ Determinism: every operation runs inside the activity (network
197
+ I/O, mutable state) — the workflow body only sees the serialised
198
+ result so replay stays deterministic. Per-cycle errors raise
199
+ out of the activity; the workflow's ``RetryPolicy`` / try-except
200
+ owns retry semantics.
201
+ """
202
+ from temporalio import activity
203
+
204
+ activity_name = f"poll.{cls.type}.v{cls.version}"
205
+
206
+ @activity.defn(name=activity_name)
207
+ async def _poll_cycle_activity(payload: Dict[str, Any]) -> Dict[str, Any]:
208
+ node_id = payload.get("node_id", "")
209
+ params = payload.get("params", {}) or {}
210
+ prior_seen: Set[str] = set(payload.get("seen_ids") or [])
211
+ baseline_only = bool(payload.get("baseline_only"))
212
+
213
+ instance = cls()
214
+ try:
215
+ service = await instance.setup_service(params)
216
+ except Exception as exc: # noqa: BLE001
217
+ logger.error(
218
+ "Polling activity setup failed",
219
+ node_id=node_id,
220
+ node_type=cls.type,
221
+ error=str(exc),
222
+ )
223
+ raise
224
+
225
+ current = await instance.fetch_ids(service, params)
226
+
227
+ if baseline_only:
228
+ # First call after workflow start: establish the seen
229
+ # baseline without emitting anything. Matches the
230
+ # pre-Temporal collector's baseline pass.
231
+ return {"events": [], "seen_ids": list(current)}
232
+
233
+ new_ids = current - prior_seen
234
+ events: list[Dict[str, Any]] = []
235
+ for msg_id in new_ids:
236
+ try:
237
+ detail = await instance.fetch_detail(service, msg_id, params)
238
+ except Exception as exc: # noqa: BLE001
239
+ logger.warning(
240
+ "Polling activity fetch_detail failed; skipping id",
241
+ node_id=node_id,
242
+ node_type=cls.type,
243
+ msg_id=msg_id,
244
+ error=str(exc),
245
+ )
246
+ continue
247
+ # The workflow needs a stable event.id for cross-cycle
248
+ # dedup. Fall back to the provider id when fetch_detail
249
+ # doesn't supply one.
250
+ if "id" not in detail:
251
+ detail["id"] = msg_id
252
+ events.append(detail)
253
+ # post_emit side effect (e.g. mark-as-read). Failures
254
+ # MUST NOT block the next emit or kill the cycle —
255
+ # mirror the legacy coroutine semantics.
256
+ try:
257
+ await instance.post_emit(service, msg_id, params)
258
+ except Exception:
259
+ pass
260
+
261
+ # OOM fix: bound ``seen_ids`` to what the provider currently
262
+ # reports as visible — old IDs that have dropped off the
263
+ # provider's window (archived / deleted / aged out) fall
264
+ # out of seen too. Pre-fix this was ``prior_seen | current``
265
+ # which grew forever (every poll appended new IDs; nothing
266
+ # ever got evicted). At Gmail's ~100 msgs/day cadence the
267
+ # set hit ~36K entries in a year — ~1.4MB just for IDs,
268
+ # serialised through Temporal payload on every cycle. Now
269
+ # bounded by the provider's natural window size.
270
+ return {"events": events, "seen_ids": list(current)}
271
+
272
+ return _poll_cycle_activity
273
+
274
+ def _build_poll_coroutine(self, node_id: str, params: Dict[str, Any]) -> Callable[[asyncio.Queue, Callable[[], bool]], Any]:
172
275
  """Return the bound poll coroutine the deployment manager
173
276
  consumes. Closes over ``self``, ``node_id``, and ``params``.
174
277
  """
175
278
 
176
- async def poll(
177
- queue: asyncio.Queue, is_running_fn: Callable[[], bool]
178
- ) -> None:
279
+ async def poll(queue: asyncio.Queue, is_running_fn: Callable[[], bool]) -> None:
179
280
  try:
180
281
  service = await self.setup_service(params)
181
282
  except Exception as exc: # noqa: BLE001 -- single setup failure
182
283
  logger.error(
183
284
  "Polling trigger setup failed",
184
- node_id=node_id, node_type=self.type, error=str(exc),
285
+ node_id=node_id,
286
+ node_type=self.type,
287
+ error=str(exc),
185
288
  )
186
289
  return
187
290
 
@@ -197,12 +300,16 @@ class PollingTriggerNode(TriggerNode, abstract=True):
197
300
  seen = await self.fetch_ids(service, params)
198
301
  logger.info(
199
302
  "Polling trigger baseline established",
200
- node_id=node_id, node_type=self.type, seen=len(seen),
303
+ node_id=node_id,
304
+ node_type=self.type,
305
+ seen=len(seen),
201
306
  )
202
307
  except Exception as exc: # noqa: BLE001
203
308
  logger.warning(
204
309
  "Polling trigger baseline failed; treating all as new",
205
- node_id=node_id, node_type=self.type, error=str(exc),
310
+ node_id=node_id,
311
+ node_type=self.type,
312
+ error=str(exc),
206
313
  )
207
314
 
208
315
  cycle = 0
@@ -215,18 +322,23 @@ class PollingTriggerNode(TriggerNode, abstract=True):
215
322
  current = await self.fetch_ids(service, params)
216
323
  new_ids = current - seen
217
324
  if not new_ids:
325
+ # OOM fix: even when nothing new arrives we
326
+ # still rebase ``seen`` to ``current`` so old
327
+ # IDs that dropped off the provider's window
328
+ # don't linger forever.
329
+ seen = set(current)
218
330
  continue
219
331
  logger.debug(
220
332
  "Polling trigger cycle",
221
- node_id=node_id, node_type=self.type, cycle=cycle,
222
- current=len(current), seen=len(seen),
333
+ node_id=node_id,
334
+ node_type=self.type,
335
+ cycle=cycle,
336
+ current=len(current),
337
+ seen=len(seen),
223
338
  new=len(new_ids),
224
339
  )
225
340
  for msg_id in new_ids:
226
- seen.add(msg_id)
227
- payload = await self.fetch_detail(
228
- service, msg_id, params
229
- )
341
+ payload = await self.fetch_detail(service, msg_id, params)
230
342
  await queue.put(payload)
231
343
  # post_emit failure must NOT block the next emit
232
344
  # nor kill the loop; mirrors pre-migration
@@ -235,12 +347,25 @@ class PollingTriggerNode(TriggerNode, abstract=True):
235
347
  await self.post_emit(service, msg_id, params)
236
348
  except Exception:
237
349
  pass
350
+ # OOM fix: rebase ``seen`` to the provider's current
351
+ # window. Pre-fix this added every new ID to ``seen``
352
+ # forever (``seen.add(msg_id)`` inside the loop, no
353
+ # eviction). Long-running pollers (Gmail with the
354
+ # default 60s interval) accumulated tens of thousands
355
+ # of entries over weeks/months. Now bounded by the
356
+ # provider's natural window size — items that have
357
+ # been emitted are still in ``current`` until they
358
+ # age/archive out, at which point dropping them is
359
+ # correct (the provider will never re-surface them
360
+ # under the same filter).
361
+ seen = set(current)
238
362
  except asyncio.CancelledError:
239
363
  raise
240
364
  except Exception as exc: # noqa: BLE001 -- per-cycle isolation
241
365
  logger.error(
242
366
  "Polling trigger cycle error; retrying next interval",
243
- node_id=node_id, node_type=self.type,
367
+ node_id=node_id,
368
+ node_type=self.type,
244
369
  error=str(exc),
245
370
  )
246
371
 
@@ -78,17 +78,65 @@ class IdempotentRegistry(Generic[K, V]):
78
78
  self._on_register = on_register
79
79
 
80
80
  def register(self, key: K, value: V) -> None:
81
- """Add ``key -> value``. Idempotent on identity; raises on conflict."""
81
+ """Add ``key -> value``. Idempotent on equality; raises on conflict.
82
+
83
+ Three equivalence checks (any match = idempotent re-register):
84
+
85
+ 1. ``existing == value`` — covers strings / ints / dataclasses /
86
+ dicts (content-equal even on reload) and singleton instances
87
+ cached across imports.
88
+ 2. **Reload tolerance for callables**: same fully-qualified
89
+ name (``__module__`` + ``__qualname__``) means the same
90
+ source-level function reloaded under fresh identity.
91
+ ``importlib.reload(module)`` constructs new function objects
92
+ that compare unequal under Python's identity-based
93
+ ``function.__eq__``; without this branch the
94
+ self-containment reload tests would break for every plugin
95
+ that registers a wrapper closure.
96
+ 3. **Reload tolerance for classes**: same ``__module__`` +
97
+ ``__qualname__`` for class objects (same reason).
98
+
99
+ Genuinely conflicting registrations (different values, different
100
+ names) still raise ``ValueError`` at import time.
101
+ """
82
102
  existing = self._items.get(key)
83
- if existing is not None and existing is not value:
103
+ if existing is not None and not self._values_equivalent(existing, value):
84
104
  raise ValueError(
85
- f"{self._name}: {key!r} is already registered by "
86
- f"{_qual(existing)}; refusing to overwrite with {_qual(value)}"
105
+ f"{self._name}: {key!r} is already registered by " f"{_qual(existing)}; refusing to overwrite with {_qual(value)}"
87
106
  )
88
107
  self._items[key] = value
89
108
  if self._on_register is not None:
90
109
  self._on_register(key, value)
91
110
 
111
+ @staticmethod
112
+ def _values_equivalent(existing: object, new: object) -> bool:
113
+ """True iff ``existing`` and ``new`` are the same registration
114
+ for idempotency purposes. See :meth:`register` docstring."""
115
+ # Content equality first (strings, dicts, dataclasses, singletons
116
+ # cached across imports). Catches the bulk of cases.
117
+ try:
118
+ if existing == new:
119
+ return True
120
+ except Exception: # noqa: BLE001 — exotic types with broken __eq__
121
+ pass
122
+
123
+ # Reload tolerance: callable / class objects re-defined under a
124
+ # fresh module-level identity still count as the "same"
125
+ # registration when their fully-qualified name matches.
126
+ existing_module = getattr(existing, "__module__", None)
127
+ new_module = getattr(new, "__module__", None)
128
+ existing_qualname = getattr(existing, "__qualname__", None)
129
+ new_qualname = getattr(new, "__qualname__", None)
130
+ if (
131
+ existing_qualname is not None
132
+ and new_qualname is not None
133
+ and existing_module == new_module
134
+ and existing_qualname == new_qualname
135
+ ):
136
+ return True
137
+
138
+ return False
139
+
92
140
  def get(self, key: K) -> Optional[V]:
93
141
  return self._items.get(key)
94
142
 
@@ -61,6 +61,7 @@ class Routing(BaseModel):
61
61
  # ---------------------------------------------------------------------------
62
62
  # Template interpolation
63
63
 
64
+
64
65
  def _resolve_template(value: Any, env: Dict[str, Any]) -> Any:
65
66
  """Resolve ``={{expr}}`` templates against ``env``. Non-string values
66
67
  pass through. Supports dotted paths — ``params.maxResults``."""
@@ -94,6 +95,7 @@ def _resolve_dict(d: Dict[str, Any], env: Dict[str, Any]) -> Dict[str, Any]:
94
95
  # ---------------------------------------------------------------------------
95
96
  # post_receive strategies
96
97
 
98
+
97
99
  def _strategy_root_property(data: Any, action: PostReceiveAction) -> Any:
98
100
  if not action.property or not isinstance(data, dict):
99
101
  return data
@@ -114,9 +116,7 @@ def _strategy_limit(data: Any, action: PostReceiveAction) -> Any:
114
116
  def _strategy_filter(data: Any, action: PostReceiveAction) -> Any:
115
117
  if not isinstance(data, list) or not action.where:
116
118
  return data
117
- return [item for item in data if all(
118
- isinstance(item, dict) and item.get(k) == v for k, v in action.where.items()
119
- )]
119
+ return [item for item in data if all(isinstance(item, dict) and item.get(k) == v for k, v in action.where.items())]
120
120
 
121
121
 
122
122
  def _strategy_set(data: Any, action: PostReceiveAction) -> Any:
@@ -125,8 +125,7 @@ def _strategy_set(data: Any, action: PostReceiveAction) -> Any:
125
125
  if isinstance(data, dict):
126
126
  return {**data, **action.set_fields}
127
127
  if isinstance(data, list):
128
- return [{**item, **action.set_fields} if isinstance(item, dict) else item
129
- for item in data]
128
+ return [{**item, **action.set_fields} if isinstance(item, dict) else item for item in data]
130
129
  return data
131
130
 
132
131
 
@@ -141,6 +140,7 @@ POST_RECEIVE_STRATEGIES = {
141
140
  # ---------------------------------------------------------------------------
142
141
  # Execution
143
142
 
143
+
144
144
  async def execute_routing(
145
145
  routing: Routing,
146
146
  *,
@@ -164,10 +164,7 @@ async def execute_routing(
164
164
 
165
165
  kwargs: Dict[str, Any] = {"headers": headers, "params": qs}
166
166
  if req.body is not None:
167
- body_resolved = (
168
- _resolve_dict(req.body, env) if isinstance(req.body, dict) else
169
- _resolve_template(req.body, env)
170
- )
167
+ body_resolved = _resolve_dict(req.body, env) if isinstance(req.body, dict) else _resolve_template(req.body, env)
171
168
  if req.body_encoding == "form":
172
169
  kwargs["data"] = body_resolved
173
170
  else:
@@ -20,20 +20,29 @@ class TaskQueue:
20
20
  and provision a worker pool in ``services/temporal/worker.py``.
21
21
  """
22
22
 
23
- DEFAULT = "machina-default" # catch-all
24
- REST_API = "rest-api" # lightweight HTTP calls (gmail, brave, twitter)
25
- AI_HEAVY = "ai-heavy" # long-running LLM + agent loops
26
- CODE_EXEC = "code-exec" # python/js/ts sandboxed execution
27
- TRIGGERS_POLL = "triggers-poll" # polling triggers (long-lived)
23
+ DEFAULT = "machina-default" # catch-all
24
+ REST_API = "rest-api" # lightweight HTTP calls (gmail, brave, twitter)
25
+ AI_HEAVY = "ai-heavy" # long-running LLM + agent loops
26
+ CODE_EXEC = "code-exec" # python/js/ts sandboxed execution
27
+ TRIGGERS_POLL = "triggers-poll" # polling triggers (long-lived)
28
28
  TRIGGERS_EVENT = "triggers-event" # event-waiter triggers (long-lived)
29
- ANDROID = "android" # ADB / relay ops
30
- BROWSER = "browser" # agent-browser, Playwright
31
- MESSAGING = "messaging" # whatsapp / telegram / twitter send
29
+ ANDROID = "android" # ADB / relay ops
30
+ BROWSER = "browser" # agent-browser, Playwright
31
+ MESSAGING = "messaging" # whatsapp / telegram / twitter send
32
32
 
33
- ALL = frozenset({
34
- DEFAULT, REST_API, AI_HEAVY, CODE_EXEC,
35
- TRIGGERS_POLL, TRIGGERS_EVENT, ANDROID, BROWSER, MESSAGING,
36
- })
33
+ ALL = frozenset(
34
+ {
35
+ DEFAULT,
36
+ REST_API,
37
+ AI_HEAVY,
38
+ CODE_EXEC,
39
+ TRIGGERS_POLL,
40
+ TRIGGERS_EVENT,
41
+ ANDROID,
42
+ BROWSER,
43
+ MESSAGING,
44
+ }
45
+ )
37
46
 
38
47
 
39
48
  @dataclass(frozen=True)
@@ -47,11 +56,20 @@ class RetryPolicy:
47
56
  backoff_coefficient: float = 2.0
48
57
  maximum_interval: timedelta = timedelta(seconds=60)
49
58
  maximum_attempts: int = 3
50
- non_retryable_error_types: Sequence[str] = field(default_factory=lambda: (
51
- "ValidationError",
52
- "PermissionDeniedError",
53
- "InvalidParametersError",
54
- ))
59
+ non_retryable_error_types: Sequence[str] = field(
60
+ default_factory=lambda: (
61
+ "ValidationError",
62
+ "PermissionDeniedError",
63
+ "InvalidParametersError",
64
+ # Wave 12 A2: NodeUserError is the canonical "user-correctable
65
+ # failure" exception (missing input, missing credential, API
66
+ # rejected the payload). Retrying it just burns attempts since
67
+ # the underlying input won't fix itself. Plugins that raise
68
+ # NodeUserError fail fast; the framework surfaces the message
69
+ # to the user / agent loop without traceback noise.
70
+ "NodeUserError",
71
+ )
72
+ )
55
73
 
56
74
  def to_temporal(self):
57
75
  """Lazy import — only called inside the Temporal worker."""
@@ -74,5 +92,5 @@ DEFAULT_RETRY = RetryPolicy()
74
92
  # Kind-specific defaults — picked up when a subclass doesn't override.
75
93
  ACTION_START_TO_CLOSE = timedelta(minutes=10)
76
94
  AI_START_TO_CLOSE = timedelta(minutes=30)
77
- TRIGGER_START_TO_CLOSE = timedelta(hours=24) # long-lived
95
+ TRIGGER_START_TO_CLOSE = timedelta(hours=24) # long-lived
78
96
  CODE_START_TO_CLOSE = timedelta(minutes=5)
@@ -0,0 +1,95 @@
1
+ """Plugin-owned registry of service-factory callables for the DI container.
2
+
3
+ Closes the two remaining cross-plugin top-level imports in
4
+ ``core/container.py``:
5
+
6
+ - ``from nodes.location._service import MapsService`` (line 25)
7
+ - ``from nodes.android._dispatcher import AndroidService`` (line 30)
8
+
9
+ Both made the framework's DI container code know about specific
10
+ plugins' implementation classes — direct violation of the
11
+ "framework knows no plugin names" rule.
12
+
13
+ Pattern (matches the established Wave-11.I plugin-self-registration
14
+ shape; same as ``register_filter_builder`` /
15
+ ``register_poll_coroutine_factory`` / ``register_ws_handlers`` /
16
+ ``register_canary_trigger_type`` / ``register_social_send_handler`` /
17
+ ``register_shutdown_hook``):
18
+
19
+ 1. Plugin's ``__init__.py`` imports its service class from ``_service.py``
20
+ (intra-plugin, fine) and calls
21
+ ``register_service_factory("<name>", ServiceClass)``.
22
+ 2. The container's provider declaration references a lazy lookup
23
+ function — :func:`get_service_factory` — instead of the concrete
24
+ class. ``providers.Factory`` / ``providers.Singleton`` calls the
25
+ wrapper function with its declared kwargs; the wrapper looks up
26
+ the registered factory and instantiates.
27
+ 3. Lookup happens at **instantiation time** (first ``container.foo()``
28
+ call), not at class-definition time, so plugin import ordering
29
+ isn't a constraint — plugin auto-discovery on startup populates
30
+ the registry before any service is first resolved.
31
+
32
+ Factory signature
33
+ -----------------
34
+
35
+ The "factory" is typically the class itself (calling it constructs
36
+ the instance). Any zero-or-more-keyword-arg callable that returns
37
+ the service instance is acceptable.
38
+
39
+ ::
40
+
41
+ factory(**kwargs) -> ServiceInstance
42
+ """
43
+
44
+ from __future__ import annotations
45
+
46
+ from typing import Any, Callable, Optional
47
+
48
+ from services.plugin.registry import IdempotentRegistry
49
+
50
+
51
+ ServiceFactory = Callable[..., Any]
52
+
53
+
54
+ _REGISTRY: IdempotentRegistry[str, ServiceFactory] = IdempotentRegistry("service_factory")
55
+
56
+
57
+ def register_service_factory(name: str, factory: ServiceFactory) -> None:
58
+ """Publish a service factory for the DI container.
59
+
60
+ Idempotent on re-import (same callable / class for the same name
61
+ is a no-op). A different factory for an existing name raises
62
+ ``ValueError`` to surface plugin namespace collisions at import time.
63
+
64
+ Args:
65
+ name: Lower-case service identifier (``"maps"``, ``"android"``,
66
+ ...). The container's provider declaration references this
67
+ name via :func:`get_service_factory`.
68
+ factory: The service class (or any callable taking the
69
+ provider's declared kwargs) that constructs the service
70
+ instance.
71
+ """
72
+ _REGISTRY.register(name, factory)
73
+
74
+
75
+ def get_service_factory(name: str) -> Optional[ServiceFactory]:
76
+ """Return the factory for ``name``, or ``None`` if unregistered.
77
+
78
+ Container providers wrap this in a lazy thunk that surfaces a
79
+ clear "service not registered" error if a required plugin failed
80
+ to load, instead of silently producing ``None``.
81
+ """
82
+ return _REGISTRY.get(name)
83
+
84
+
85
+ def registered_service_names() -> frozenset[str]:
86
+ """Return an immutable snapshot of registered service identifiers."""
87
+ return frozenset(_REGISTRY.keys())
88
+
89
+
90
+ __all__ = [
91
+ "register_service_factory",
92
+ "get_service_factory",
93
+ "registered_service_names",
94
+ "ServiceFactory",
95
+ ]