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
@@ -0,0 +1,44 @@
1
+ """WhatsApp Personal credential stub.
2
+
3
+ WhatsApp's "personal" connection is QR-paired session-based — the bot
4
+ binary (``edgymeow``) handles the WebSocket session lifecycle and there's
5
+ no API key / OAuth token to store. The credential class exists only so
6
+ ``CREDENTIAL_REGISTRY`` can resolve the ``whatsapp`` provider
7
+ key (for catalogue icon lookup via
8
+ :meth:`services.plugin.credential.Credential.get_icon_path`). It does
9
+ NOT implement ``resolve()`` — connection-state queries go through the
10
+ ``whatsapp_status`` WebSocket flow + the QR-pairing UI, not through
11
+ ``auth_service.get_*``.
12
+
13
+ See ``server/config/credential_providers.json`` (entry
14
+ ``whatsapp``) for the catalogue-level declaration of the QR
15
+ pairing UI / status rows / actions. This module's only job is to make
16
+ the icon endpoint find ``credential_whatsapp.svg`` co-located
17
+ in this folder.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from services.plugin.credential import Credential
23
+
24
+
25
+ class WhatsAppCredential(Credential):
26
+ """Catalogue stub for the QR-paired WhatsApp Personal connection.
27
+
28
+ Not an :class:`ApiKeyCredential` / :class:`OAuth2Credential` —
29
+ WhatsApp's pairing is session-based and managed entirely by the
30
+ :class:`~nodes.whatsapp._runtime.WhatsAppRuntime` supervisor +
31
+ WebSocket handlers. The class is registered into
32
+ ``CREDENTIAL_REGISTRY`` purely to give the catalogue icon endpoint
33
+ (``GET /api/schemas/credentials/whatsapp/icon``) a class
34
+ to call :meth:`get_icon_path` on. ``resolve()`` is never called
35
+ because no node plugin declares this credential in its
36
+ ``credentials`` tuple — the connection is implicit, mediated by
37
+ ``services.whatsapp_service`` and the runtime supervisor.
38
+ """
39
+
40
+ id = "whatsapp"
41
+ display_name = "WhatsApp Personal"
42
+ auth = "custom"
43
+ category = "Social"
44
+ docs_url = "https://faq.whatsapp.com/general/about-linked-devices"
@@ -0,0 +1,277 @@
1
+ """Wave 12 B2: CloudEvents factories + broadcaster wrappers for whatsapp.
2
+
3
+ Plugin-specific event emission — replaces:
4
+ - 10 ``broadcaster.update_whatsapp_status(...)`` callsites (event
5
+ handlers + status / start / restart WS handlers)
6
+ - 7 ``broadcaster.send_custom_event("whatsapp_*", ...)`` callsites
7
+ (message_sent / message_received / 4 newsletter events /
8
+ history_sync_complete)
9
+
10
+ …all of which previously emitted raw dicts and lived as a tangle in
11
+ ``_service.py``. After B2 every whatsapp wire frame originates from
12
+ exactly one wrapper in this module — single source of truth for shape.
13
+
14
+ Per RFC plugin_authoring_rfc.md §6.4:
15
+ - Plugin-specific factories live in the plugin folder (NOT central
16
+ ``services/events/envelope.py``).
17
+ - Cross-cutting factories (``credential``, ``oauth_completed``, …)
18
+ stay in central envelope.
19
+
20
+ Wire format (Wave 12 D4 — legacy ``whatsapp_status`` raw frame retired):
21
+ - Status: typed CloudEvents envelope on ``plugin_connection_status``
22
+ (FE routes by ``envelope.source``).
23
+ - Message / newsletter / history: still dual-emit on their legacy
24
+ wire keys until the matching FE handlers migrate to envelope-aware
25
+ readers (follow-up D4 round).
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import time
31
+ from typing import Any, Dict, Literal, Mapping, Optional
32
+
33
+ from services.events.envelope import WorkflowEvent
34
+
35
+
36
+ # ---- Wire-routing keys (outer ``type`` field the FE switches on) -----------
37
+ #
38
+ # Unchanged from the pre-B2 shape per RFC §11 (FE still routes on the
39
+ # legacy keys). Only the INNER ``data.type`` gains the ``com.machinaos.``
40
+ # reverse-DNS prefix via the typed CloudEvents factories below.
41
+
42
+ _STATUS_TYPED_WIRE_KEY = "plugin_connection_status" # shared cross-plugin channel
43
+
44
+ _MESSAGE_SENT_WIRE_KEY = "whatsapp_message_sent"
45
+ _MESSAGE_RECEIVED_WIRE_KEY = "whatsapp_message_received"
46
+
47
+ _NEWSLETTER_WIRE_KEYS: Dict[str, str] = {
48
+ "joined": "whatsapp_newsletter_join",
49
+ "left": "whatsapp_newsletter_leave",
50
+ "muted": "whatsapp_newsletter_mute_change",
51
+ "live_updated": "whatsapp_newsletter_live_update",
52
+ }
53
+
54
+ _HISTORY_SYNCED_WIRE_KEY = "whatsapp_history_sync_complete"
55
+
56
+
57
+ # ---- Typed factories (plugin-specific per RFC §6.4) ------------------------
58
+
59
+
60
+ def whatsapp_connection_status(
61
+ *,
62
+ connected: bool,
63
+ has_session: bool = False,
64
+ running: bool = False,
65
+ pairing: bool = False,
66
+ device_id: Optional[str] = None,
67
+ qr: Optional[str] = None,
68
+ ) -> WorkflowEvent:
69
+ """Connection-state envelope. ``subject`` is the device_id so the
70
+ FE can route per-device updates."""
71
+ return WorkflowEvent(
72
+ source="machinaos://nodes/whatsapp",
73
+ type=("com.machinaos.whatsapp.connection.opened" if connected else "com.machinaos.whatsapp.connection.closed"),
74
+ subject=device_id,
75
+ data={
76
+ "connected": connected,
77
+ "has_session": has_session,
78
+ "running": running,
79
+ "pairing": pairing,
80
+ "device_id": device_id,
81
+ "qr": qr,
82
+ },
83
+ )
84
+
85
+
86
+ def whatsapp_message_event(
87
+ direction: Literal["sent", "received"],
88
+ params: Mapping[str, Any],
89
+ ) -> WorkflowEvent:
90
+ """Message envelope (sent or received). Subject auto-extracted
91
+ from the params payload (chat_id / sender / from)."""
92
+ payload = dict(params)
93
+ subject = payload.get("chat_id") or payload.get("sender") or payload.get("from")
94
+ return WorkflowEvent(
95
+ source="machinaos://nodes/whatsapp",
96
+ type=f"com.machinaos.whatsapp.message.{direction}",
97
+ subject=str(subject) if subject else None,
98
+ data=payload,
99
+ )
100
+
101
+
102
+ def whatsapp_newsletter_event(
103
+ verb: Literal["joined", "left", "muted", "live_updated"],
104
+ params: Mapping[str, Any],
105
+ ) -> WorkflowEvent:
106
+ """Newsletter-lifecycle envelope. Subject auto-extracted from
107
+ ``newsletter_jid`` if present in params."""
108
+ payload = dict(params)
109
+ subject = payload.get("newsletter_jid") or payload.get("jid")
110
+ return WorkflowEvent(
111
+ source="machinaos://nodes/whatsapp",
112
+ type=f"com.machinaos.whatsapp.newsletter.{verb}",
113
+ subject=str(subject) if subject else None,
114
+ data=payload,
115
+ )
116
+
117
+
118
+ def whatsapp_history_synced(params: Mapping[str, Any]) -> WorkflowEvent:
119
+ """History-sync-complete envelope. Subject is the device_id when
120
+ available in the params payload."""
121
+ payload = dict(params)
122
+ subject = payload.get("device_id")
123
+ return WorkflowEvent(
124
+ source="machinaos://nodes/whatsapp",
125
+ type="com.machinaos.whatsapp.history.synced",
126
+ subject=str(subject) if subject else None,
127
+ data=payload,
128
+ )
129
+
130
+
131
+ # ---- Broadcaster wrappers --------------------------------------------------
132
+
133
+
134
+ async def broadcast_whatsapp_status(
135
+ *,
136
+ connected: bool,
137
+ has_session: bool = False,
138
+ running: bool = False,
139
+ pairing: bool = False,
140
+ device_id: Optional[str] = None,
141
+ qr: Optional[str] = None,
142
+ ) -> None:
143
+ """Update the whatsapp status cache + emit the typed
144
+ ``plugin_connection_status`` CloudEvents envelope.
145
+
146
+ Replaces ``StatusBroadcaster.update_whatsapp_status``. Legacy raw
147
+ ``whatsapp_status`` frame retired in Wave 12 D4 — FE consumes via
148
+ the envelope-aware ``plugin_connection_status`` case.
149
+ """
150
+ from services.status_broadcaster import get_status_broadcaster
151
+
152
+ broadcaster = get_status_broadcaster()
153
+
154
+ payload: Dict[str, Any] = {
155
+ "connected": connected,
156
+ "has_session": has_session,
157
+ "running": running,
158
+ "pairing": pairing,
159
+ "device_id": device_id,
160
+ "qr": qr,
161
+ "timestamp": time.time(),
162
+ }
163
+ broadcaster._status["whatsapp"] = payload
164
+
165
+ event = whatsapp_connection_status(
166
+ connected=connected,
167
+ has_session=has_session,
168
+ running=running,
169
+ pairing=pairing,
170
+ device_id=device_id,
171
+ qr=qr,
172
+ )
173
+ await broadcaster.broadcast(
174
+ {
175
+ "type": _STATUS_TYPED_WIRE_KEY,
176
+ "data": event.model_dump(mode="json"),
177
+ }
178
+ )
179
+
180
+
181
+ async def broadcast_whatsapp_message(
182
+ direction: Literal["sent", "received"],
183
+ params: Mapping[str, Any],
184
+ ) -> None:
185
+ """Emit a message event (sent or received).
186
+
187
+ Inbound (``received``) routes via :func:`services.events.dispatch.emit`
188
+ — the canary CloudEvents path Signals running
189
+ :class:`TriggerListenerWorkflow` consumers AND broadcasts the
190
+ envelope on the ``whatsapp_message_received`` wire key.
191
+
192
+ Outbound (``sent``) is observation-only: no trigger consumer
193
+ exists, so it bypasses ``dispatch.emit`` and goes out as a raw
194
+ legacy frame on ``whatsapp_message_sent`` for the FE message-list
195
+ UI.
196
+ """
197
+ from services.status_broadcaster import get_status_broadcaster
198
+
199
+ broadcaster = get_status_broadcaster()
200
+ payload = dict(params)
201
+
202
+ if direction == "received":
203
+ # Canary path — single ``emit`` call delivers to Temporal
204
+ # listeners + FE WS. The FE message-list handler at
205
+ # WebSocketContext.tsx still reads ``data.*`` for back-compat,
206
+ # so we also broadcast the legacy raw frame until that handler
207
+ # migrates to envelope-shape (Wave 12 D4 follow-up).
208
+ from services.events.dispatch import emit
209
+
210
+ await broadcaster.broadcast(
211
+ {
212
+ "type": _MESSAGE_RECEIVED_WIRE_KEY,
213
+ "data": payload,
214
+ }
215
+ )
216
+ await emit(
217
+ whatsapp_message_event("received", payload),
218
+ wire_routing_key=_MESSAGE_RECEIVED_WIRE_KEY,
219
+ )
220
+ else:
221
+ # Outbound observation only — direct legacy raw broadcast.
222
+ await broadcaster.broadcast(
223
+ {
224
+ "type": _MESSAGE_SENT_WIRE_KEY,
225
+ "data": payload,
226
+ }
227
+ )
228
+
229
+
230
+ async def broadcast_whatsapp_newsletter(
231
+ verb: Literal["joined", "left", "muted", "live_updated"],
232
+ params: Mapping[str, Any],
233
+ ) -> None:
234
+ """Emit a newsletter-lifecycle event for FE observation.
235
+
236
+ Not a trigger event — no canary consumer. Direct raw broadcast on
237
+ the legacy wire key until the FE newsletter UI migrates to read
238
+ the envelope shape, at which point this becomes a ``dispatch.emit``
239
+ call like :func:`broadcast_whatsapp_message`.
240
+ """
241
+ from services.status_broadcaster import get_status_broadcaster
242
+
243
+ broadcaster = get_status_broadcaster()
244
+ await broadcaster.broadcast(
245
+ {
246
+ "type": _NEWSLETTER_WIRE_KEYS[verb],
247
+ "data": dict(params),
248
+ }
249
+ )
250
+
251
+
252
+ async def broadcast_whatsapp_history_synced(params: Mapping[str, Any]) -> None:
253
+ """Emit a history-sync-complete event for FE observation.
254
+
255
+ Not a trigger event — no canary consumer. Direct raw broadcast.
256
+ """
257
+ from services.status_broadcaster import get_status_broadcaster
258
+
259
+ broadcaster = get_status_broadcaster()
260
+ await broadcaster.broadcast(
261
+ {
262
+ "type": _HISTORY_SYNCED_WIRE_KEY,
263
+ "data": dict(params),
264
+ }
265
+ )
266
+
267
+
268
+ __all__ = [
269
+ "broadcast_whatsapp_history_synced",
270
+ "broadcast_whatsapp_message",
271
+ "broadcast_whatsapp_newsletter",
272
+ "broadcast_whatsapp_status",
273
+ "whatsapp_connection_status",
274
+ "whatsapp_history_synced",
275
+ "whatsapp_message_event",
276
+ "whatsapp_newsletter_event",
277
+ ]
@@ -40,66 +40,65 @@ def build_filter(params: Dict) -> Callable[[Dict], bool]:
40
40
  - ``group_info`` -- present for group messages, with ``group_jid``
41
41
  / ``sender_jid`` / ``sender_phone`` / ``sender_name``
42
42
  """
43
- msg_type = params.get('message_type_filter', 'all')
44
- sender_filter = params.get('filter', 'all')
45
- contact_phone = params.get('phone_number', '')
46
- group_id = params.get('group_id', '')
47
- sender_number = params.get('sender_number', '')
48
- keywords = [
49
- k.strip().lower()
50
- for k in params.get('keywords', '').split(',')
51
- if k.strip()
52
- ]
53
- ignore_own = params.get('ignore_own_messages', True)
54
- forwarded_filter = params.get('forwarded_filter', 'all')
43
+ msg_type = params.get("message_type_filter", "all")
44
+ sender_filter = params.get("filter", "all")
45
+ contact_phone = params.get("phone_number", "")
46
+ group_id = params.get("group_id", "")
47
+ sender_number = params.get("sender_number", "")
48
+ keywords = [k.strip().lower() for k in params.get("keywords", "").split(",") if k.strip()]
49
+ ignore_own = params.get("ignore_own_messages", True)
50
+ forwarded_filter = params.get("forwarded_filter", "all")
55
51
 
56
52
  logger.debug(
57
53
  "[WhatsAppFilter] Built: type=%s, filter=%s, group_id=%r, forwarded=%s",
58
- msg_type, sender_filter, group_id, forwarded_filter,
54
+ msg_type,
55
+ sender_filter,
56
+ group_id,
57
+ forwarded_filter,
59
58
  )
60
59
 
61
60
  def matches(m: Dict) -> bool:
62
- msg_chat_id = m.get('chat_id', '')
63
- is_group = m.get('is_group', False)
64
- group_info = m.get('group_info', {})
61
+ msg_chat_id = m.get("chat_id", "")
62
+ is_group = m.get("is_group", False)
63
+ group_info = m.get("group_info", {})
65
64
 
66
65
  # Use sender_phone directly -- Go RPC already resolves LIDs.
67
66
  # For group messages, prefer group_info.sender_phone, fall back
68
67
  # to root sender_phone.
69
68
  if is_group:
70
- sender_phone = group_info.get('sender_phone', '') or m.get('sender_phone', '')
69
+ sender_phone = group_info.get("sender_phone", "") or m.get("sender_phone", "")
71
70
  else:
72
- sender_phone = m.get('sender_phone', '')
71
+ sender_phone = m.get("sender_phone", "")
73
72
 
74
73
  # Fallback: extract phone from sender JID if sender_phone absent.
75
74
  if not sender_phone:
76
- sender = m.get('sender', '')
77
- sender_phone = sender.split('@')[0] if '@' in sender else sender
75
+ sender = m.get("sender", "")
76
+ sender_phone = sender.split("@")[0] if "@" in sender else sender
78
77
 
79
78
  # Message type filter (schema field: message_type).
80
- if msg_type != 'all' and m.get('message_type') != msg_type:
79
+ if msg_type != "all" and m.get("message_type") != msg_type:
81
80
  return False
82
81
 
83
82
  # Sender filter -- for ``contact`` filter, use actual phone.
84
- if sender_filter == 'self':
83
+ if sender_filter == "self":
85
84
  # Self-chat (notes-to-self) only -- must be from me AND in
86
85
  # a chat with myself.
87
- if not m.get('is_from_me'):
86
+ if not m.get("is_from_me"):
88
87
  return False
89
- chat_id = m.get('chat_id', '')
90
- sender = m.get('sender', '')
88
+ chat_id = m.get("chat_id", "")
89
+ sender = m.get("sender", "")
91
90
  if chat_id != sender:
92
91
  return False
93
92
 
94
- if sender_filter == 'any_contact':
93
+ if sender_filter == "any_contact":
95
94
  if is_group:
96
95
  return False
97
96
 
98
- if sender_filter == 'contact':
97
+ if sender_filter == "contact":
99
98
  if contact_phone not in sender_phone:
100
99
  return False
101
100
 
102
- if sender_filter == 'group':
101
+ if sender_filter == "group":
103
102
  if not is_group:
104
103
  return False
105
104
  if msg_chat_id != group_id:
@@ -109,26 +108,26 @@ def build_filter(params: Dict) -> Callable[[Dict], bool]:
109
108
  if sender_number not in sender_phone:
110
109
  return False
111
110
 
112
- if sender_filter == 'channel':
113
- if not msg_chat_id.endswith('@newsletter'):
111
+ if sender_filter == "channel":
112
+ if not msg_chat_id.endswith("@newsletter"):
114
113
  return False
115
- channel_jid = params.get('channel_jid', '')
114
+ channel_jid = params.get("channel_jid", "")
116
115
  if channel_jid and msg_chat_id != channel_jid:
117
116
  return False
118
117
 
119
- if sender_filter == 'keywords':
120
- text = (m.get('text') or '').lower()
118
+ if sender_filter == "keywords":
119
+ text = (m.get("text") or "").lower()
121
120
  if not any(kw in text for kw in keywords):
122
121
  return False
123
122
 
124
123
  # Ignore own messages -- but not when filtering for ``self``.
125
- if ignore_own and sender_filter != 'self' and m.get('is_from_me'):
124
+ if ignore_own and sender_filter != "self" and m.get("is_from_me"):
126
125
  return False
127
126
 
128
- is_forwarded = m.get('is_forwarded', False)
129
- if forwarded_filter == 'only_forwarded' and not is_forwarded:
127
+ is_forwarded = m.get("is_forwarded", False)
128
+ if forwarded_filter == "only_forwarded" and not is_forwarded:
130
129
  return False
131
- if forwarded_filter == 'ignore_forwarded' and is_forwarded:
130
+ if forwarded_filter == "ignore_forwarded" and is_forwarded:
132
131
  return False
133
132
 
134
133
  logger.debug("[WhatsAppFilter] Matched message from %s", sender_phone)
@@ -80,6 +80,7 @@ async def handle_whatsapp_chat_history(data: Dict[str, Any], websocket: WebSocke
80
80
 
81
81
  # ---- Rate-limit RPC passthroughs ----
82
82
 
83
+
83
84
  async def handle_whatsapp_rate_limit_get(data: Dict[str, Any], websocket: WebSocket) -> Dict[str, Any]:
84
85
  """Get rate-limit config and current stats."""
85
86
  return await _wa_rpc_call("rate_limit_get", {})
@@ -102,6 +103,7 @@ async def handle_whatsapp_rate_limit_unpause(data: Dict[str, Any], websocket: We
102
103
 
103
104
  # ---- Lightweight RPC passthroughs ----
104
105
 
106
+
105
107
  async def handle_whatsapp_mark_read(data: Dict[str, Any], websocket: WebSocket) -> Dict[str, Any]:
106
108
  """Mark messages as read. Schema: mark_read({message_ids, chat_jid, sender_jid?})."""
107
109
  message_ids = data.get("message_ids", [])
@@ -56,9 +56,7 @@ async def load_group_members(params: Dict[str, Any]) -> List[Dict[str, Any]]:
56
56
  if not group_id:
57
57
  return []
58
58
  response = await handle_whatsapp_group_info(group_id)
59
- participants = (
60
- response.get("participants", []) if isinstance(response, dict) else []
61
- )
59
+ participants = response.get("participants", []) if isinstance(response, dict) else []
62
60
  return [
63
61
  {
64
62
  "value": p.get("phone") or p.get("jid") or "",
@@ -14,7 +14,6 @@ pre-migration behaviour.
14
14
  from __future__ import annotations
15
15
 
16
16
  import logging
17
- import time
18
17
  from typing import TYPE_CHECKING
19
18
 
20
19
  from opentelemetry import trace
@@ -28,35 +27,31 @@ tracer = trace.get_tracer(__name__)
28
27
 
29
28
  async def refresh_whatsapp_status(broadcaster: "StatusBroadcaster") -> None:
30
29
  """Refresh WhatsApp cache + broadcast. One pass per
31
- ``_refresh_all_services`` cycle.
30
+ ``_refresh_all_services`` cycle. Wave 12 B2 — routes through the
31
+ plugin's canonical broadcaster wrapper so the wire shape is
32
+ single-sourced in ``_events.py``.
32
33
  """
33
34
  with tracer.start_as_current_span("broadcaster.refresh_whatsapp") as span:
34
35
  try:
36
+ from ._events import broadcast_whatsapp_status
35
37
  from ._service import get_client
36
38
 
37
39
  client = await get_client()
38
40
  status_data = await client.call("status")
39
41
 
40
- broadcaster._status["whatsapp"] = {
41
- "connected": status_data.get("connected", False),
42
- "has_session": status_data.get("has_session", False),
43
- "running": status_data.get("running", False),
44
- "pairing": status_data.get("pairing", False),
45
- "device_id": status_data.get("device_id"),
46
- "qr": None,
47
- "timestamp": time.time(),
48
- }
42
+ await broadcast_whatsapp_status(
43
+ connected=status_data.get("connected", False),
44
+ has_session=status_data.get("has_session", False),
45
+ running=status_data.get("running", False),
46
+ pairing=status_data.get("pairing", False),
47
+ device_id=status_data.get("device_id"),
48
+ qr=None,
49
+ )
49
50
  logger.debug(
50
51
  "[StatusBroadcaster] Refreshed WhatsApp status: connected=%s",
51
52
  status_data.get("connected"),
52
53
  )
53
- await broadcaster.broadcast({
54
- "type": "whatsapp_status",
55
- "data": broadcaster._status["whatsapp"],
56
- })
57
54
  span.set_attribute("connected", bool(status_data.get("connected", False)))
58
55
  except Exception as exc: # noqa: BLE001
59
56
  span.record_exception(exc)
60
- logger.debug(
61
- "[StatusBroadcaster] Could not refresh WhatsApp status: %s", exc
62
- )
57
+ logger.debug("[StatusBroadcaster] Could not refresh WhatsApp status: %s", exc)
@@ -36,6 +36,7 @@ class WhatsAppRuntime(BaseProcessSupervisor):
36
36
  super().__init__()
37
37
  if settings is None:
38
38
  from core.config import Settings
39
+
39
40
  settings = Settings()
40
41
  self.settings = settings
41
42
 
@@ -43,11 +44,12 @@ class WhatsAppRuntime(BaseProcessSupervisor):
43
44
 
44
45
  @property
45
46
  def data_root(self) -> Path:
46
- sub = getattr(self.settings, "whatsapp_data_subdir", "whatsapp")
47
- base = Path(self.settings.data_dir)
48
- if not base.is_absolute():
49
- base = _PROJECT_ROOT / "server" / base
50
- return (base / sub).resolve()
47
+ # Routes through ``Settings._resolve_under_data`` so dev mode's
48
+ # ``DATA_DIR=.machina`` lands the WhatsApp tree at
49
+ # ``<repo>/.machina/whatsapp/`` (not ``<repo>/server/.machina/...``,
50
+ # which the old ad-hoc ``_PROJECT_ROOT / "server" / data_dir``
51
+ # logic produced when ``DATA_DIR`` was relative).
52
+ return Path(self.settings._resolve_under_data(self.settings.whatsapp_data_subdir))
51
53
 
52
54
  @property
53
55
  def port(self) -> int:
@@ -107,7 +109,8 @@ class WhatsAppRuntime(BaseProcessSupervisor):
107
109
  config["server"]["port"] = self.port
108
110
  config["server"]["host"] = self.bind_host
109
111
  (self.data_root / "configs" / "config.yaml").write_text(
110
- yaml.safe_dump(config, sort_keys=False), encoding="utf-8",
112
+ yaml.safe_dump(config, sort_keys=False),
113
+ encoding="utf-8",
111
114
  )
112
115
 
113
116