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,3 @@
1
+ {
2
+ "color": "#8be9fd"
3
+ }
@@ -174,11 +174,7 @@ def get_backend(
174
174
 
175
175
  param_dir = parameters.get("working_directory")
176
176
  ctx_dir = context.get("workspace_dir") if context else None
177
- root = (
178
- param_dir
179
- or ctx_dir
180
- or os.path.join(Settings().workspace_base_resolved, "default")
181
- )
177
+ root = param_dir or ctx_dir or os.path.join(Settings().workspace_base_resolved, "default")
182
178
  os.makedirs(root, exist_ok=True)
183
179
  get_logger(__name__).info("[Filesystem] root=%s", root)
184
180
  # ``inherit_env=True`` makes the host PATH available so the agent can
@@ -37,6 +37,10 @@ class FileModifyNode(ActionNode):
37
37
  subtitle = "Write/Edit"
38
38
  group = ("filesystem", "tool")
39
39
  description = "Write new files or edit existing files"
40
+ tool_name = "file_modify"
41
+ tool_description = (
42
+ "Write a new file or edit an existing file with string replacement. Operations: write (create/overwrite), edit (find and replace)."
43
+ )
40
44
  component_kind = "square"
41
45
  handles = (
42
46
  {"name": "input-main", "kind": "input", "position": "left", "label": "Input", "role": "main"},
@@ -53,7 +57,7 @@ class FileModifyNode(ActionNode):
53
57
  async def modify(self, ctx: NodeContext, params: FileModifyParams) -> Any:
54
58
  """Inlined from handlers/filesystem.py (Wave 11.D.1)."""
55
59
  import asyncio
56
- from ._backend import get_backend, normalize_virtual_path
60
+ from .._backend import get_backend, normalize_virtual_path
57
61
 
58
62
  if not params.file_path:
59
63
  raise NodeUserError("file_path is required")
@@ -69,9 +73,7 @@ class FileModifyNode(ActionNode):
69
73
  resolved = backend._resolve_path(file_path)
70
74
  if resolved.exists():
71
75
  if resolved.is_dir():
72
- raise IsADirectoryError(
73
- f"Cannot write to {file_path}: path is a directory"
74
- )
76
+ raise IsADirectoryError(f"Cannot write to {file_path}: path is a directory")
75
77
  resolved.unlink()
76
78
  return backend.write(file_path, params.content)
77
79
 
@@ -87,7 +89,10 @@ class FileModifyNode(ActionNode):
87
89
  if not params.old_string:
88
90
  raise NodeUserError("old_string is required for edit")
89
91
  result = await asyncio.to_thread(
90
- backend.edit, file_path, params.old_string, params.new_string,
92
+ backend.edit,
93
+ file_path,
94
+ params.old_string,
95
+ params.new_string,
91
96
  replace_all=params.replace_all,
92
97
  )
93
98
  if result.error:
@@ -0,0 +1,3 @@
1
+ {
2
+ "color": "#8be9fd"
3
+ }
@@ -30,6 +30,8 @@ class FileReadNode(ActionNode):
30
30
  subtitle = "Read Contents"
31
31
  group = ("filesystem", "tool")
32
32
  description = "Read file contents with line numbers and pagination"
33
+ tool_name = "file_read"
34
+ tool_description = "Read file contents with pagination. Returns line-numbered text."
33
35
  component_kind = "square"
34
36
  handles = (
35
37
  {"name": "input-main", "kind": "input", "position": "left", "label": "Input", "role": "main"},
@@ -46,7 +48,7 @@ class FileReadNode(ActionNode):
46
48
  async def read(self, ctx: NodeContext, params: FileReadParams) -> Any:
47
49
  """Inlined from handlers/filesystem.py (Wave 11.D.1)."""
48
50
  import asyncio
49
- from ._backend import get_backend, normalize_virtual_path
51
+ from .._backend import get_backend, normalize_virtual_path
50
52
 
51
53
  if not params.file_path:
52
54
  raise NodeUserError("file_path is required")
@@ -54,8 +56,10 @@ class FileReadNode(ActionNode):
54
56
  file_path = normalize_virtual_path(params.file_path)
55
57
  try:
56
58
  content = await asyncio.to_thread(
57
- backend.read, file_path,
58
- offset=params.offset, limit=params.limit,
59
+ backend.read,
60
+ file_path,
61
+ offset=params.offset,
62
+ limit=params.limit,
59
63
  )
60
64
  except (FileNotFoundError, IsADirectoryError, ValueError) as e:
61
65
  # File doesn't exist / is a directory / bad offset — the
@@ -0,0 +1,3 @@
1
+ {
2
+ "color": "#8be9fd"
3
+ }
@@ -30,6 +30,10 @@ class FsSearchNode(ActionNode):
30
30
  subtitle = "ls/glob/grep"
31
31
  group = ("filesystem", "tool")
32
32
  description = "Search the filesystem (ls, glob, grep)"
33
+ tool_name = "fs_search"
34
+ tool_description = (
35
+ "Search the filesystem. Modes: ls (list directory), glob (pattern match files), grep (search file contents for text)."
36
+ )
33
37
  component_kind = "square"
34
38
  handles = (
35
39
  {"name": "input-main", "kind": "input", "position": "left", "label": "Input", "role": "main"},
@@ -46,7 +50,7 @@ class FsSearchNode(ActionNode):
46
50
  async def search(self, ctx: NodeContext, params: FsSearchParams) -> Any:
47
51
  """Inlined from handlers/filesystem.py (Wave 11.D.1)."""
48
52
  import asyncio
49
- from ._backend import get_backend, normalize_virtual_path
53
+ from .._backend import get_backend, normalize_virtual_path
50
54
 
51
55
  backend = get_backend(params.model_dump(), ctx.raw)
52
56
  path = normalize_virtual_path(params.path)
@@ -63,7 +67,9 @@ class FsSearchNode(ActionNode):
63
67
  if not params.pattern:
64
68
  raise NodeUserError("pattern is required for glob mode")
65
69
  matches = await asyncio.to_thread(
66
- backend.glob_info, params.pattern, path=path,
70
+ backend.glob_info,
71
+ params.pattern,
72
+ path=path,
67
73
  )
68
74
  return {
69
75
  "path": path,
@@ -76,7 +82,9 @@ class FsSearchNode(ActionNode):
76
82
  if not params.pattern:
77
83
  raise NodeUserError("pattern is required for grep mode")
78
84
  result = await asyncio.to_thread(
79
- backend.grep_raw, params.pattern, path=path,
85
+ backend.grep_raw,
86
+ params.pattern,
87
+ path=path,
80
88
  )
81
89
  if isinstance(result, str):
82
90
  raise NodeUserError(result)
@@ -0,0 +1,3 @@
1
+ {
2
+ "color": "#8be9fd"
3
+ }
@@ -41,6 +41,8 @@ class ShellNode(ActionNode):
41
41
  subtitle = "Run Command"
42
42
  group = ("filesystem", "tool")
43
43
  description = "Execute shell commands (sandboxed; no system PATH)"
44
+ tool_name = "shell_execute"
45
+ tool_description = "Execute a shell command. Returns stdout, stderr, and exit code."
44
46
  component_kind = "square"
45
47
  handles = (
46
48
  {"name": "input-main", "kind": "input", "position": "left", "label": "Input", "role": "main"},
@@ -58,7 +60,7 @@ class ShellNode(ActionNode):
58
60
  """Inlined from handlers/filesystem.py (Wave 11.D.1)."""
59
61
  import asyncio
60
62
  from core.logging import get_logger
61
- from ._backend import get_backend
63
+ from .._backend import get_backend
62
64
 
63
65
  log = get_logger(__name__)
64
66
 
@@ -66,7 +68,7 @@ class ShellNode(ActionNode):
66
68
  # Nushell's parser does, so the LLM sees an actionable hint instead
67
69
  # of ``nu::parser::shell_andand``. Documented in
68
70
  # ``server/skills/terminal/shell-skill/SKILL.md``.
69
- if (m := _BASH_CHAIN_RE.search(params.command)):
71
+ if m := _BASH_CHAIN_RE.search(params.command):
70
72
  op = m.group(1)
71
73
  replacement = "; (sequential)" if op == "&&" else "try { … } catch { … }"
72
74
  raise NodeUserError(
@@ -83,17 +85,22 @@ class ShellNode(ActionNode):
83
85
  # misleading users into thinking shell runs daemons.
84
86
  log.info(
85
87
  "[Shell] Executing: %s (timeout=%ds)",
86
- params.command[:200], params.timeout,
88
+ params.command[:200],
89
+ params.timeout,
87
90
  )
88
91
  result = await asyncio.to_thread(
89
- backend.execute, params.command, timeout=params.timeout,
92
+ backend.execute,
93
+ params.command,
94
+ timeout=params.timeout,
90
95
  )
91
96
  if result.exit_code == 124:
92
97
  log.warning("[Shell] Timed out after %ds: %s", params.timeout, params.command[:100])
93
98
  elif result.exit_code != 0:
94
99
  log.warning(
95
100
  "[Shell] Non-zero exit (%d): %s -> %s",
96
- result.exit_code, params.command[:100], result.output[:300],
101
+ result.exit_code,
102
+ params.command[:100],
103
+ result.output[:300],
97
104
  )
98
105
  else:
99
106
  log.info("[Shell] Completed: exit=%d len=%d", result.exit_code, len(result.output))
@@ -0,0 +1,3 @@
1
+ {
2
+ "color": "#8be9fd"
3
+ }
@@ -24,9 +24,11 @@ the FastAPI app pick up the plugin's surface without ever importing
24
24
  this module by name.
25
25
  """
26
26
 
27
+ from services.deployment.canary_registry import register_canary_trigger_type
27
28
  from services.event_waiter import register_filter_builder
28
29
  from services.status_broadcaster import register_service_refresh
29
30
  from services.ws_handler_registry import (
31
+ register_oauth_callback_path,
30
32
  register_option_loader,
31
33
  register_router,
32
34
  register_ws_handlers,
@@ -45,6 +47,7 @@ from ._refresh import refresh_google_status
45
47
 
46
48
  register_ws_handlers(WS_HANDLERS)
47
49
  register_router(_router.router, name="google")
50
+ register_oauth_callback_path("google", "/api/google/callback")
48
51
  register_service_refresh(refresh_google_status)
49
52
  register_filter_builder("googleGmailReceive", build_gmail_filter)
50
53
 
@@ -53,3 +56,12 @@ register_option_loader("gmailLabels", load_gmail_labels)
53
56
  register_option_loader("googleCalendarList", load_calendar_list)
54
57
  register_option_loader("googleDriveFolders", load_drive_folders)
55
58
  register_option_loader("googleTasklists", load_tasklists)
59
+
60
+ # Wave 12 C2: opt googleGmailReceive into the PollingTriggerWorkflow
61
+ # consumer path. DeploymentManager detects the PollingTriggerNode
62
+ # subclass and routes to PollingTriggerWorkflow (vs the push-side
63
+ # TriggerListenerWorkflow) automatically. Producer side: the per-cycle
64
+ # Temporal activity is emitted by GmailReceiveNode.as_poll_activity()
65
+ # and registered via collect_polling_activities() in the worker. See
66
+ # services/deployment/canary_registry.py.
67
+ register_canary_trigger_type("googleGmailReceive", "com.machinaos.gmail.message.received")
@@ -39,11 +39,11 @@ async def get_google_credentials(
39
39
  """
40
40
  from services.plugin.deps import get_auth_service, get_database
41
41
 
42
- account_mode = parameters.get('account_mode', 'owner')
42
+ account_mode = parameters.get("account_mode", "owner")
43
43
  customer_id = "owner"
44
44
 
45
- if account_mode == 'customer':
46
- customer_id = parameters.get('customer_id')
45
+ if account_mode == "customer":
46
+ customer_id = parameters.get("customer_id")
47
47
  if not customer_id:
48
48
  raise ValueError("customer_id required for customer mode")
49
49
 
@@ -65,15 +65,11 @@ async def get_google_credentials(
65
65
  tokens = await auth_service.get_oauth_tokens("google", customer_id="owner")
66
66
 
67
67
  if not tokens or not tokens.get("access_token"):
68
- raise ValueError(
69
- "Google Workspace not connected. Please authenticate via Credentials."
70
- )
68
+ raise ValueError("Google Workspace not connected. Please authenticate via Credentials.")
71
69
 
72
70
  access_token = tokens["access_token"]
73
71
  # refresh_token is read from DB directly (RFC 9700; not cached).
74
- refresh_token = await auth_service.get_oauth_refresh_token(
75
- "google", customer_id="owner"
76
- )
72
+ refresh_token = await auth_service.get_oauth_refresh_token("google", customer_id="owner")
77
73
 
78
74
  auth_service = get_auth_service()
79
75
  client_id = await auth_service.get_api_key("google_client_id") or ""
@@ -94,9 +90,7 @@ async def get_google_credentials(
94
90
  # best-effort optimization that persists the new token to the DB.
95
91
  if refresh_token and client_id and client_secret:
96
92
  try:
97
- await _try_refresh_and_persist(
98
- creds, auth_service, customer_id, account_mode
99
- )
93
+ await _try_refresh_and_persist(creds, auth_service, customer_id, account_mode)
100
94
  except Exception as e:
101
95
  # Non-fatal: the Credentials object will auto-refresh on 401 anyway
102
96
  logger.debug(f"Proactive token refresh skipped: {e}")
@@ -132,7 +126,7 @@ async def _try_refresh_and_persist(
132
126
  return
133
127
 
134
128
  # Persist refreshed token back to the correct store
135
- if account_mode == 'owner':
129
+ if account_mode == "owner":
136
130
  tokens = await auth_service.get_oauth_tokens("google", customer_id="owner")
137
131
  await auth_service.store_oauth_tokens(
138
132
  provider="google",
@@ -41,7 +41,8 @@ async def build_google_service(
41
41
  creds = await GoogleCredential.build_credentials(parameters, context)
42
42
  loop = asyncio.get_event_loop()
43
43
  return await loop.run_in_executor(
44
- None, lambda: build(api_name, api_version, credentials=creds),
44
+ None,
45
+ lambda: build(api_name, api_version, credentials=creds),
45
46
  )
46
47
 
47
48
 
@@ -65,16 +66,18 @@ async def track_google_usage(
65
66
  cost_data = pricing.calculate_api_cost(service, action, resource_count)
66
67
 
67
68
  db = get_database()
68
- await db.save_api_usage_metric({
69
- 'session_id': context.get('session_id', 'default'),
70
- 'node_id': node_id,
71
- 'workflow_id': context.get('workflow_id'),
72
- 'service': service,
73
- 'operation': cost_data.get('operation', action),
74
- 'endpoint': action,
75
- 'resource_count': resource_count,
76
- 'cost': cost_data.get('total_cost', 0.0),
77
- })
69
+ await db.save_api_usage_metric(
70
+ {
71
+ "session_id": context.get("session_id", "default"),
72
+ "node_id": node_id,
73
+ "workflow_id": context.get("workflow_id"),
74
+ "service": service,
75
+ "operation": cost_data.get("operation", action),
76
+ "endpoint": action,
77
+ "resource_count": resource_count,
78
+ "cost": cost_data.get("total_cost", 0.0),
79
+ }
80
+ )
78
81
  return cost_data
79
82
 
80
83
 
@@ -22,7 +22,6 @@ class GoogleCredential(OAuth2Credential):
22
22
  id = "google"
23
23
  display_name = "Google Workspace"
24
24
  category = "Productivity"
25
- icon = "asset:google"
26
25
  authorization_url = "https://accounts.google.com/o/oauth2/auth"
27
26
  token_url = "https://oauth2.googleapis.com/token"
28
27
  client_id_api_key = "google_client_id"
@@ -39,6 +38,7 @@ class GoogleCredential(OAuth2Credential):
39
38
  """Return the live scope list (lazy import)."""
40
39
  if not cls.scopes:
41
40
  from nodes.google._oauth import GOOGLE_WORKSPACE_SCOPES
41
+
42
42
  cls.scopes = tuple(GOOGLE_WORKSPACE_SCOPES)
43
43
  return cls.scopes
44
44
 
@@ -58,4 +58,5 @@ class GoogleCredential(OAuth2Credential):
58
58
  policy.
59
59
  """
60
60
  from nodes.google._auth_helper import get_google_credentials
61
+
61
62
  return await get_google_credentials(parameters, context)
@@ -0,0 +1,47 @@
1
+ """CloudEvents factory for gmail.
2
+
3
+ Per RFC plugin_authoring_rfc.md §6.4: plugin-specific factories live in
4
+ the plugin folder.
5
+
6
+ No dispatcher wrapper: the canary delivery path for ``googleGmailReceive``
7
+ is :class:`services.temporal.polling_trigger_workflow.PollingTriggerWorkflow`
8
+ (not Signal-based). The polling activity (built by
9
+ :meth:`services.plugin.polling.PollingTriggerNode.as_poll_activity`)
10
+ returns the raw email dict back to the workflow which spawns the child
11
+ MachinaWorkflow directly — no envelope-on-the-wire step is needed.
12
+
13
+ The factory below is kept for parity with the other plugin ``_events.py``
14
+ modules (and for any future ad-hoc emit usage); the legacy
15
+ ``dispatch_gmail_received`` shim was deleted in Wave 13 because it
16
+ dispatched to ``event_waiter`` waiters that were never registered in
17
+ canary-on mode (the polling workflow owns delivery).
18
+
19
+ OAuth completion broadcasts route through the cross-cutting
20
+ ``StatusBroadcaster.broadcast_credential_event("credential.oauth.connected", ...)``
21
+ path (RFC §6.4 cross-cutting tier) — NOT a plugin-named broadcast.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from typing import Any, Mapping
27
+
28
+ from services.events.envelope import WorkflowEvent
29
+
30
+
31
+ def gmail_message_received(email_data: Mapping[str, Any]) -> WorkflowEvent:
32
+ """Incoming Gmail message envelope. ``subject`` is the Gmail
33
+ message_id (correlation key for the consumer-side ``markAsRead``
34
+ + dedup paths)."""
35
+ payload = dict(email_data)
36
+ message_id = payload.get("message_id") or payload.get("id")
37
+ return WorkflowEvent(
38
+ source="machinaos://nodes/google",
39
+ type="com.machinaos.gmail.message.received",
40
+ subject=str(message_id) if message_id else None,
41
+ data=payload,
42
+ )
43
+
44
+
45
+ __all__ = [
46
+ "gmail_message_received",
47
+ ]
@@ -13,11 +13,11 @@ from typing import Callable, Dict
13
13
 
14
14
  def build_gmail_filter(params: Dict) -> Callable[[Dict], bool]:
15
15
  """Build filter function for Gmail email events."""
16
- label_filter = params.get('label_filter', 'INBOX')
16
+ label_filter = params.get("label_filter", "INBOX")
17
17
 
18
18
  def matches(data: Dict) -> bool:
19
- if label_filter and label_filter != 'all':
20
- labels = data.get('labels', [])
19
+ if label_filter and label_filter != "all":
20
+ labels = data.get("labels", [])
21
21
  if label_filter not in labels:
22
22
  return False
23
23
  return True
@@ -15,74 +15,95 @@ from ._base import run_sync
15
15
 
16
16
  async def poll_gmail_ids(service, query: str, max_results: int = 20) -> Set[str]:
17
17
  """Fetch message IDs matching a Gmail query."""
18
- result = await run_sync(lambda: service.users().messages().list(
19
- userId='me', q=query, maxResults=max_results,
20
- ).execute())
21
- return {m.get('id') for m in result.get('messages', []) if m.get('id')}
18
+ result = await run_sync(
19
+ lambda: service.users()
20
+ .messages()
21
+ .list(
22
+ userId="me",
23
+ q=query,
24
+ maxResults=max_results,
25
+ )
26
+ .execute()
27
+ )
28
+ return {m.get("id") for m in result.get("messages", []) if m.get("id")}
22
29
 
23
30
 
24
31
  async def fetch_email_details(service, message_id: str) -> Dict[str, Any]:
25
32
  """Fetch full email message + format it for output."""
26
- result = await run_sync(lambda: service.users().messages().get(
27
- userId='me', id=message_id, format='full',
28
- metadataHeaders=['From', 'To', 'Subject', 'Date', 'Cc', 'Bcc'],
29
- ).execute())
33
+ result = await run_sync(
34
+ lambda: service.users()
35
+ .messages()
36
+ .get(
37
+ userId="me",
38
+ id=message_id,
39
+ format="full",
40
+ metadataHeaders=["From", "To", "Subject", "Date", "Cc", "Bcc"],
41
+ )
42
+ .execute()
43
+ )
30
44
  return format_message(result, include_body=True)
31
45
 
32
46
 
33
47
  async def mark_email_as_read(service, message_id: str) -> None:
34
48
  """Remove the UNREAD label from a message."""
35
- await run_sync(lambda: service.users().messages().modify(
36
- userId='me', id=message_id, body={'removeLabelIds': ['UNREAD']},
37
- ).execute())
49
+ await run_sync(
50
+ lambda: service.users()
51
+ .messages()
52
+ .modify(
53
+ userId="me",
54
+ id=message_id,
55
+ body={"removeLabelIds": ["UNREAD"]},
56
+ )
57
+ .execute()
58
+ )
38
59
 
39
60
 
40
61
  def format_message(message: Dict[str, Any], include_body: bool = False) -> Dict[str, Any]:
41
62
  """Convert a raw Gmail message payload into a flat, LLM-friendly dict."""
42
63
  headers: Dict[str, str] = {}
43
- payload = message.get('payload', {})
44
- for header in payload.get('headers', []):
45
- name = header.get('name', '').lower()
46
- if name in ('from', 'to', 'subject', 'date', 'cc', 'bcc'):
47
- headers[name] = header.get('value', '')
64
+ payload = message.get("payload", {})
65
+ for header in payload.get("headers", []):
66
+ name = header.get("name", "").lower()
67
+ if name in ("from", "to", "subject", "date", "cc", "bcc"):
68
+ headers[name] = header.get("value", "")
48
69
 
49
70
  formatted: Dict[str, Any] = {
50
- 'message_id': message.get('id'),
51
- 'thread_id': message.get('threadId'),
52
- 'from': headers.get('from', ''),
53
- 'to': headers.get('to', ''),
54
- 'cc': headers.get('cc', ''),
55
- 'subject': headers.get('subject', ''),
56
- 'date': headers.get('date', ''),
57
- 'snippet': message.get('snippet', ''),
58
- 'labels': message.get('labelIds', []),
59
- 'size_estimate': message.get('sizeEstimate', 0),
71
+ "message_id": message.get("id"),
72
+ "thread_id": message.get("threadId"),
73
+ "from": headers.get("from", ""),
74
+ "to": headers.get("to", ""),
75
+ "cc": headers.get("cc", ""),
76
+ "subject": headers.get("subject", ""),
77
+ "date": headers.get("date", ""),
78
+ "snippet": message.get("snippet", ""),
79
+ "labels": message.get("labelIds", []),
80
+ "size_estimate": message.get("sizeEstimate", 0),
60
81
  }
61
82
 
62
83
  if include_body:
63
- formatted['body'] = _extract_body(payload)
84
+ formatted["body"] = _extract_body(payload)
64
85
 
65
86
  attachments = _extract_attachments(payload)
66
87
  if attachments:
67
- formatted['attachments'] = attachments
88
+ formatted["attachments"] = attachments
68
89
 
69
90
  return formatted
70
91
 
71
92
 
72
93
  def _extract_body(payload: Dict[str, Any]) -> str:
73
94
  """Extract text body from a (possibly multipart) Gmail payload."""
74
- if payload.get('body', {}).get('data'):
75
- return base64.urlsafe_b64decode(payload['body']['data']).decode('utf-8', errors='ignore')
95
+ if payload.get("body", {}).get("data"):
96
+ return base64.urlsafe_b64decode(payload["body"]["data"]).decode("utf-8", errors="ignore")
76
97
 
77
98
  body = ""
78
- for part in payload.get('parts', []):
79
- mime = part.get('mimeType', '')
80
- data = part.get('body', {}).get('data')
81
- if mime == 'text/plain' and data:
82
- return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
83
- if mime == 'text/html' and data and not body:
84
- body = base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
85
- elif mime.startswith('multipart/'):
99
+ for part in payload.get("parts", []):
100
+ mime = part.get("mimeType", "")
101
+ data = part.get("body", {}).get("data")
102
+ if mime == "text/plain" and data:
103
+ return base64.urlsafe_b64decode(data).decode("utf-8", errors="ignore")
104
+ if mime == "text/html" and data and not body:
105
+ body = base64.urlsafe_b64decode(data).decode("utf-8", errors="ignore")
106
+ elif mime.startswith("multipart/"):
86
107
  nested = _extract_body(part)
87
108
  if nested:
88
109
  return nested
@@ -92,15 +113,17 @@ def _extract_body(payload: Dict[str, Any]) -> str:
92
113
  def _extract_attachments(payload: Dict[str, Any]) -> List[Dict[str, Any]]:
93
114
  """Flatten attachment metadata from a multipart payload."""
94
115
  attachments: List[Dict[str, Any]] = []
95
- for part in payload.get('parts', []):
96
- filename = part.get('filename', '')
116
+ for part in payload.get("parts", []):
117
+ filename = part.get("filename", "")
97
118
  if filename:
98
- attachments.append({
99
- 'filename': filename,
100
- 'mime_type': part.get('mimeType', ''),
101
- 'size': part.get('body', {}).get('size', 0),
102
- 'attachment_id': part.get('body', {}).get('attachmentId', ''),
103
- })
104
- if part.get('parts'):
119
+ attachments.append(
120
+ {
121
+ "filename": filename,
122
+ "mime_type": part.get("mimeType", ""),
123
+ "size": part.get("body", {}).get("size", 0),
124
+ "attachment_id": part.get("body", {}).get("attachmentId", ""),
125
+ }
126
+ )
127
+ if part.get("parts"):
105
128
  attachments.extend(_extract_attachments(part))
106
129
  return attachments
@@ -22,7 +22,9 @@ from ._oauth import GoogleOAuth
22
22
 
23
23
 
24
24
  async def _google_oauth_factory(
25
- *, redirect_uri: Optional[str] = None, **_kwargs,
25
+ *,
26
+ redirect_uri: Optional[str] = None,
27
+ **_kwargs,
26
28
  ) -> GoogleOAuth:
27
29
  """Build a :class:`GoogleOAuth` from stored client credentials."""
28
30
  from services.plugin.deps import get_auth_service