machinaos 0.0.64 → 0.0.73

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 (625) hide show
  1. package/client/components.json +25 -0
  2. package/client/dist/assets/ActionBar-vzPpSR77.js +1 -0
  3. package/client/dist/assets/ApiKeyInput-Ds7AKFe8.js +1 -0
  4. package/client/dist/assets/ApiKeyPanel-gfblELep.js +1 -0
  5. package/client/dist/assets/ApiUsageSection-BMNWTe2r.js +1 -0
  6. package/client/dist/assets/EmailPanel-B1Om64p5.js +1 -0
  7. package/client/dist/assets/OAuthPanel-CXyQYGBz.js +1 -0
  8. package/client/dist/assets/QrPairingPanel-BgNuI1we.js +1 -0
  9. package/client/dist/assets/RateLimitSection-YYK8sx1T.js +1 -0
  10. package/client/dist/assets/StatusCard-DuYA5hJR.js +1 -0
  11. package/client/dist/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
  12. package/client/dist/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
  13. package/client/dist/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
  14. package/client/dist/assets/index-D9tZfgvi.js +363 -0
  15. package/client/dist/assets/index-al7snTkG.css +1 -0
  16. package/client/dist/index.html +2 -2
  17. package/client/package.json +42 -8
  18. package/client/src/App.tsx +16 -12
  19. package/client/src/Dashboard.tsx +211 -266
  20. package/client/src/ParameterPanel.tsx +42 -124
  21. package/client/src/adapters/__tests__/nodeSpecToDescription.test.ts +352 -0
  22. package/client/src/adapters/nodeSpecToDescription.ts +349 -0
  23. package/client/src/assets/icons/NodeIcon.tsx +73 -0
  24. package/client/src/assets/icons/chat/chat.svg +1 -0
  25. package/client/src/assets/icons/code/javascript.svg +1 -0
  26. package/client/src/assets/icons/code/python.svg +1 -0
  27. package/client/src/assets/icons/code/typescript.svg +1 -0
  28. package/client/src/assets/icons/index.test.ts +74 -0
  29. package/client/src/assets/icons/index.ts +176 -0
  30. package/client/src/assets/icons/social/social.svg +1 -0
  31. package/client/src/assets/icons/twitter/x.svg +1 -0
  32. package/client/src/assets/icons/whatsapp/whatsapp-db.svg +1 -0
  33. package/client/src/assets/icons/whatsapp/whatsapp-receive.svg +1 -0
  34. package/client/src/assets/icons/whatsapp/whatsapp-send.svg +1 -0
  35. package/client/src/assets/icons/whatsapp/whatsapp.svg +1 -0
  36. package/client/src/components/AIAgentNode.tsx +160 -583
  37. package/client/src/components/APIKeyValidator.tsx +52 -54
  38. package/client/src/components/ConditionalEdge.tsx +24 -84
  39. package/client/src/components/CredentialsModal.tsx +1 -3151
  40. package/client/src/components/EdgeConditionEditor.tsx +162 -330
  41. package/client/src/components/GenericNode.tsx +40 -170
  42. package/client/src/components/LocationParameterPanel.tsx +17 -58
  43. package/client/src/components/OutputPanel.tsx +10 -8
  44. package/client/src/components/ParameterRenderer.tsx +161 -58
  45. package/client/src/components/PricingConfigModal.tsx +134 -159
  46. package/client/src/components/SkillEditorModal.tsx +320 -324
  47. package/client/src/components/SquareNode.tsx +122 -431
  48. package/client/src/components/StartNode.tsx +22 -100
  49. package/client/src/components/TeamMonitorNode.tsx +6 -4
  50. package/client/src/components/ToolkitNode.tsx +31 -134
  51. package/client/src/components/TriggerNode.tsx +38 -169
  52. package/client/src/components/__tests__/CredentialsModal.test.tsx +231 -0
  53. package/client/src/components/auth/LoginPage.tsx +75 -180
  54. package/client/src/components/auth/ProtectedRoute.tsx +4 -23
  55. package/client/src/components/credentials/CredentialsModal.tsx +118 -0
  56. package/client/src/components/credentials/CredentialsPalette.tsx +305 -0
  57. package/client/src/components/credentials/PanelRenderer.tsx +92 -0
  58. package/client/src/components/credentials/catalogueAdapter.ts +199 -0
  59. package/client/src/components/credentials/hooks.ts +15 -0
  60. package/client/src/components/credentials/index.ts +3 -0
  61. package/client/src/components/credentials/panels/ApiKeyPanel.tsx +116 -0
  62. package/client/src/components/credentials/panels/EmailPanel.tsx +371 -0
  63. package/client/src/components/credentials/panels/OAuthPanel.tsx +52 -0
  64. package/client/src/components/credentials/panels/QrPairingPanel.tsx +91 -0
  65. package/client/src/components/credentials/panels/schemas/email.ts +64 -0
  66. package/client/src/components/credentials/primitives/ActionBar.tsx +54 -0
  67. package/client/src/components/credentials/primitives/FieldRenderer.tsx +91 -0
  68. package/client/src/components/credentials/primitives/OAuthConnect.tsx +123 -0
  69. package/client/src/components/credentials/primitives/StatusCard.tsx +47 -0
  70. package/client/src/components/credentials/primitives/index.ts +5 -0
  71. package/client/src/components/credentials/providers.tsx +177 -0
  72. package/client/src/components/credentials/schema/extends.ts +168 -0
  73. package/client/src/components/credentials/sections/ApiUsageSection.tsx +120 -0
  74. package/client/src/components/credentials/sections/LlmUsageSection.tsx +146 -0
  75. package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +366 -0
  76. package/client/src/components/credentials/sections/RateLimitSection.tsx +306 -0
  77. package/client/src/components/credentials/sections/index.ts +4 -0
  78. package/client/src/components/credentials/types.ts +128 -0
  79. package/client/src/components/credentials/useCredentialPanel.ts +193 -0
  80. package/client/src/components/icons/AIProviderIcons.tsx +28 -14
  81. package/client/src/components/nodeMemoEquality.ts +28 -0
  82. package/client/src/components/onboarding/OnboardingWizard.tsx +49 -22
  83. package/client/src/components/onboarding/steps/ApiKeyStep.tsx +28 -49
  84. package/client/src/components/onboarding/steps/CanvasStep.tsx +61 -103
  85. package/client/src/components/onboarding/steps/ConceptsStep.tsx +69 -87
  86. package/client/src/components/onboarding/steps/GetStartedStep.tsx +82 -89
  87. package/client/src/components/onboarding/steps/WelcomeStep.tsx +27 -45
  88. package/client/src/components/output/OutputPanel.tsx +175 -0
  89. package/client/src/components/parameterPanel/InputSection.tsx +291 -1248
  90. package/client/src/components/parameterPanel/LocationPanelLayout.tsx +4 -4
  91. package/client/src/components/parameterPanel/MapsSection.tsx +1 -9
  92. package/client/src/components/parameterPanel/MasterSkillEditor.tsx +349 -370
  93. package/client/src/components/parameterPanel/MiddleSection.tsx +563 -846
  94. package/client/src/components/parameterPanel/OutputSection.tsx +34 -26
  95. package/client/src/components/parameterPanel/ParameterPanelLayout.tsx +4 -4
  96. package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +317 -335
  97. package/client/src/components/parameterPanel/__tests__/InputSection.test.tsx +200 -0
  98. package/client/src/components/parameterPanel/__tests__/MiddleSection.test.tsx +150 -0
  99. package/client/src/components/parameterPanel/__tests__/OutputSection.test.tsx +295 -0
  100. package/client/src/components/shared/DataPanel.tsx +26 -97
  101. package/client/src/components/shared/JSONTreeRenderer.tsx +105 -87
  102. package/client/src/components/ui/AIResultModal.tsx +39 -141
  103. package/client/src/components/ui/ApiKeyInput.tsx +40 -45
  104. package/client/src/components/ui/CodeEditor.tsx +6 -28
  105. package/client/src/components/ui/CollapsibleSection.tsx +25 -64
  106. package/client/src/components/ui/ComponentItem.tsx +35 -126
  107. package/client/src/components/ui/ComponentPalette.tsx +111 -230
  108. package/client/src/components/ui/ConsolePanel.tsx +446 -881
  109. package/client/src/components/ui/EditableNodeLabel.tsx +122 -0
  110. package/client/src/components/ui/ErrorBoundary.tsx +40 -151
  111. package/client/src/components/ui/InputNodesPanel.tsx +53 -100
  112. package/client/src/components/ui/Modal.tsx +83 -113
  113. package/client/src/components/ui/NodeContextMenu.tsx +39 -71
  114. package/client/src/components/ui/OutputDisplayPanel.tsx +180 -359
  115. package/client/src/components/ui/QRCodeDisplay.tsx +32 -64
  116. package/client/src/components/ui/SettingsPanel.tsx +248 -417
  117. package/client/src/components/ui/TopToolbar.tsx +248 -633
  118. package/client/src/components/ui/WorkflowSidebar.tsx +109 -252
  119. package/client/src/components/ui/accordion.tsx +79 -0
  120. package/client/src/components/ui/action-button.tsx +61 -0
  121. package/client/src/components/ui/alert-dialog.tsx +197 -0
  122. package/client/src/components/ui/alert.tsx +82 -0
  123. package/client/src/components/ui/badge.tsx +52 -0
  124. package/client/src/components/ui/button.tsx +67 -0
  125. package/client/src/components/ui/card.tsx +103 -0
  126. package/client/src/components/ui/checkbox.tsx +31 -0
  127. package/client/src/components/ui/collapsible.tsx +31 -0
  128. package/client/src/components/ui/dialog.tsx +168 -0
  129. package/client/src/components/ui/dropdown-menu.tsx +269 -0
  130. package/client/src/components/ui/form.tsx +167 -0
  131. package/client/src/components/ui/input.tsx +19 -0
  132. package/client/src/components/ui/label.tsx +24 -0
  133. package/client/src/components/ui/popover.tsx +89 -0
  134. package/client/src/components/ui/progress.tsx +29 -0
  135. package/client/src/components/ui/select.tsx +192 -0
  136. package/client/src/components/ui/settingsPanel/schema.ts +64 -0
  137. package/client/src/components/ui/skeleton.tsx +13 -0
  138. package/client/src/components/ui/slider.tsx +57 -0
  139. package/client/src/components/ui/sonner.tsx +48 -0
  140. package/client/src/components/ui/switch.tsx +31 -0
  141. package/client/src/components/ui/tabs.tsx +88 -0
  142. package/client/src/components/ui/textarea.tsx +18 -0
  143. package/client/src/components/ui/tooltip.tsx +55 -0
  144. package/client/src/contexts/WebSocketContext.tsx +566 -128
  145. package/client/src/hooks/__tests__/useApiKeys.test.ts +411 -0
  146. package/client/src/hooks/__tests__/useDragVariable.test.ts +223 -0
  147. package/client/src/hooks/useApiKeyValidation.ts +7 -7
  148. package/client/src/hooks/useAutoSkillEdges.ts +132 -0
  149. package/client/src/hooks/useCatalogueQuery.ts +314 -0
  150. package/client/src/hooks/useComponentPalette.ts +4 -3
  151. package/client/src/hooks/useCopyPaste.ts +2 -3
  152. package/client/src/hooks/useDragAndDrop.ts +14 -7
  153. package/client/src/hooks/useDragVariable.ts +2 -2
  154. package/client/src/hooks/useExecution.ts +7 -7
  155. package/client/src/hooks/useFolderSkills.ts +73 -0
  156. package/client/src/hooks/useNodeAllowlist.ts +49 -0
  157. package/client/src/hooks/useNodeParamsQuery.ts +66 -0
  158. package/client/src/hooks/useOnboarding.ts +45 -47
  159. package/client/src/hooks/useParameterPanel.ts +89 -111
  160. package/client/src/hooks/useReactFlowNodes.ts +3 -3
  161. package/client/src/hooks/useUserSettingsQuery.ts +53 -0
  162. package/client/src/hooks/useWorkflowManagement.ts +5 -3
  163. package/client/src/hooks/useWorkflowsQuery.ts +96 -0
  164. package/client/src/index.css +450 -215
  165. package/client/src/lib/__tests__/workflowOps.test.ts +435 -0
  166. package/client/src/lib/aiModelProviders.ts +34 -0
  167. package/client/src/lib/featureFlags.ts +36 -0
  168. package/client/src/lib/nodeSpec.ts +327 -0
  169. package/client/src/lib/queryClient.ts +72 -0
  170. package/client/src/lib/queryConfig.ts +81 -0
  171. package/client/src/lib/queryPersist.ts +79 -0
  172. package/client/src/lib/utils.ts +6 -0
  173. package/client/src/lib/workflowOps.ts +291 -0
  174. package/client/src/main.tsx +29 -7
  175. package/client/src/services/executionService.ts +25 -83
  176. package/client/src/store/useAppStore.ts +12 -58
  177. package/client/src/store/useCredentialRegistry.ts +45 -0
  178. package/client/src/stores/nodeStatusStore.ts +134 -0
  179. package/client/src/styles/canvasAnimations.ts +112 -0
  180. package/client/src/styles/theme.ts +68 -1
  181. package/client/src/test/README.md +34 -0
  182. package/client/src/test/builders.ts +90 -0
  183. package/client/src/test/nodeDefinitionContract.ts +182 -0
  184. package/client/src/test/providers.tsx +80 -0
  185. package/client/src/test/setup.ts +62 -0
  186. package/client/src/types/ComponentTypes.ts +3 -1
  187. package/client/src/types/INodeProperties.ts +51 -2
  188. package/client/src/utils/formatters.ts +2 -2
  189. package/client/src/utils/parameterVisibility.ts +29 -0
  190. package/client/tailwind.config.js +39 -2
  191. package/client/tsconfig.json +5 -1
  192. package/client/vite.config.js +59 -1
  193. package/client/vitest.config.ts +29 -0
  194. package/package.json +20 -23
  195. package/scripts/migrate_icons.py +143 -0
  196. package/scripts/migrate_skill_icons.py +186 -0
  197. package/scripts/postinstall.js +25 -5
  198. package/server/config/credential_providers.json +400 -0
  199. package/server/config/llm_defaults.json +44 -24
  200. package/server/config/model_registry.json +1292 -541
  201. package/server/config/node_allowlist.json +29 -0
  202. package/server/core/config.py +13 -2
  203. package/server/core/database.py +35 -5
  204. package/server/core/logging.py +1 -1
  205. package/server/core/tracing.py +82 -0
  206. package/server/main.py +34 -3
  207. package/server/models/database.py +1 -0
  208. package/server/models/node_metadata.py +109 -0
  209. package/server/nodes/README.md +351 -0
  210. package/server/nodes/__init__.py +113 -0
  211. package/server/nodes/_visuals.py +81 -0
  212. package/server/nodes/agent/__init__.py +1 -0
  213. package/server/nodes/agent/_handles.py +55 -0
  214. package/server/nodes/agent/_inline.py +154 -0
  215. package/server/nodes/agent/_specialized.py +125 -0
  216. package/server/nodes/agent/ai_agent.py +132 -0
  217. package/server/nodes/agent/ai_employee.py +11 -0
  218. package/server/nodes/agent/android_agent.py +9 -0
  219. package/server/nodes/agent/autonomous_agent.py +9 -0
  220. package/server/nodes/agent/chat_agent.py +118 -0
  221. package/server/nodes/agent/claude_code_agent.py +133 -0
  222. package/server/nodes/agent/coding_agent.py +9 -0
  223. package/server/nodes/agent/consumer_agent.py +9 -0
  224. package/server/nodes/agent/deep_agent.py +103 -0
  225. package/server/nodes/agent/orchestrator_agent.py +11 -0
  226. package/server/nodes/agent/payments_agent.py +9 -0
  227. package/server/nodes/agent/productivity_agent.py +9 -0
  228. package/server/nodes/agent/rlm_agent.py +98 -0
  229. package/server/nodes/agent/social_agent.py +9 -0
  230. package/server/nodes/agent/task_agent.py +9 -0
  231. package/server/nodes/agent/tool_agent.py +9 -0
  232. package/server/nodes/agent/travel_agent.py +9 -0
  233. package/server/nodes/agent/web_agent.py +9 -0
  234. package/server/nodes/android/__init__.py +1 -0
  235. package/server/nodes/android/_base.py +330 -0
  236. package/server/nodes/android/airplane_mode_control.py +7 -0
  237. package/server/nodes/android/app_launcher.py +29 -0
  238. package/server/nodes/android/app_list.py +7 -0
  239. package/server/nodes/android/audio_automation.py +7 -0
  240. package/server/nodes/android/battery_monitor.py +7 -0
  241. package/server/nodes/android/bluetooth_automation.py +7 -0
  242. package/server/nodes/android/camera_control.py +7 -0
  243. package/server/nodes/android/device_state_automation.py +7 -0
  244. package/server/nodes/android/environmental_sensors.py +7 -0
  245. package/server/nodes/android/location.py +7 -0
  246. package/server/nodes/android/media_control.py +7 -0
  247. package/server/nodes/android/motion_detection.py +7 -0
  248. package/server/nodes/android/network_monitor.py +7 -0
  249. package/server/nodes/android/screen_control_automation.py +7 -0
  250. package/server/nodes/android/system_info.py +7 -0
  251. package/server/nodes/android/wifi_automation.py +7 -0
  252. package/server/nodes/browser/__init__.py +1 -0
  253. package/server/nodes/browser/browser.py +364 -0
  254. package/server/nodes/chat/__init__.py +1 -0
  255. package/server/nodes/chat/chat_history.py +67 -0
  256. package/server/nodes/chat/chat_send.py +79 -0
  257. package/server/nodes/code/__init__.py +1 -0
  258. package/server/nodes/code/_base.py +47 -0
  259. package/server/nodes/code/_nodejs.py +22 -0
  260. package/server/nodes/code/javascript_executor.py +57 -0
  261. package/server/nodes/code/python_executor.py +123 -0
  262. package/server/nodes/code/typescript_executor.py +53 -0
  263. package/server/nodes/document/__init__.py +1 -0
  264. package/server/nodes/document/document_parser.py +115 -0
  265. package/server/nodes/document/embedding_generator.py +110 -0
  266. package/server/nodes/document/file_downloader.py +111 -0
  267. package/server/nodes/document/http_scraper.py +193 -0
  268. package/server/nodes/document/text_chunker.py +77 -0
  269. package/server/nodes/document/vector_store.py +279 -0
  270. package/server/nodes/email/__init__.py +1 -0
  271. package/server/nodes/email/email_read.py +124 -0
  272. package/server/nodes/email/email_receive.py +141 -0
  273. package/server/nodes/email/email_send.py +58 -0
  274. package/server/nodes/filesystem/__init__.py +1 -0
  275. package/server/nodes/filesystem/_backend.py +189 -0
  276. package/server/nodes/filesystem/file_modify.py +101 -0
  277. package/server/nodes/filesystem/file_read.py +64 -0
  278. package/server/nodes/filesystem/fs_search.py +90 -0
  279. package/server/nodes/filesystem/shell.py +83 -0
  280. package/server/nodes/google/__init__.py +1 -0
  281. package/server/nodes/google/_base.py +84 -0
  282. package/server/nodes/google/_credentials.py +61 -0
  283. package/server/nodes/google/_gmail.py +106 -0
  284. package/server/nodes/google/calendar.py +238 -0
  285. package/server/nodes/google/contacts.py +243 -0
  286. package/server/nodes/google/drive.py +272 -0
  287. package/server/nodes/google/gmail.py +196 -0
  288. package/server/nodes/google/gmail_receive.py +172 -0
  289. package/server/nodes/google/sheets.py +174 -0
  290. package/server/nodes/google/tasks.py +175 -0
  291. package/server/nodes/groups.py +57 -0
  292. package/server/nodes/location/__init__.py +1 -0
  293. package/server/nodes/location/_credentials.py +21 -0
  294. package/server/nodes/location/gmaps_create.py +72 -0
  295. package/server/nodes/location/gmaps_locations.py +83 -0
  296. package/server/nodes/location/gmaps_nearby_places.py +62 -0
  297. package/server/nodes/model/__init__.py +1 -0
  298. package/server/nodes/model/_base.py +108 -0
  299. package/server/nodes/model/_credentials.py +97 -0
  300. package/server/nodes/model/anthropic_chat_model.py +27 -0
  301. package/server/nodes/model/cerebras_chat_model.py +26 -0
  302. package/server/nodes/model/deepseek_chat_model.py +27 -0
  303. package/server/nodes/model/gemini_chat_model.py +28 -0
  304. package/server/nodes/model/groq_chat_model.py +26 -0
  305. package/server/nodes/model/kimi_chat_model.py +12 -0
  306. package/server/nodes/model/mistral_chat_model.py +12 -0
  307. package/server/nodes/model/openai_chat_model.py +35 -0
  308. package/server/nodes/model/openrouter_chat_model.py +27 -0
  309. package/server/nodes/proxy/__init__.py +1 -0
  310. package/server/nodes/proxy/_usage.py +52 -0
  311. package/server/nodes/proxy/proxy_config.py +388 -0
  312. package/server/nodes/proxy/proxy_request.py +168 -0
  313. package/server/nodes/proxy/proxy_status.py +55 -0
  314. package/server/nodes/scheduler/__init__.py +1 -0
  315. package/server/nodes/scheduler/cron_scheduler.py +239 -0
  316. package/server/nodes/scheduler/timer.py +92 -0
  317. package/server/nodes/scraper/__init__.py +1 -0
  318. package/server/nodes/scraper/_credentials.py +19 -0
  319. package/server/nodes/scraper/apify_actor.py +314 -0
  320. package/server/nodes/scraper/crawlee_scraper.py +347 -0
  321. package/server/nodes/search/__init__.py +1 -0
  322. package/server/nodes/search/brave_search.py +124 -0
  323. package/server/nodes/search/duckduckgo_search.py +76 -0
  324. package/server/nodes/search/perplexity_search.py +128 -0
  325. package/server/nodes/search/serper_search.py +145 -0
  326. package/server/nodes/skill/__init__.py +1 -0
  327. package/server/nodes/skill/master_skill.py +64 -0
  328. package/server/nodes/skill/simple_memory.py +123 -0
  329. package/server/nodes/social/__init__.py +1 -0
  330. package/server/{services/handlers/social.py → nodes/social/_base.py} +33 -28
  331. package/server/nodes/social/social_receive.py +156 -0
  332. package/server/nodes/social/social_send.py +371 -0
  333. package/server/nodes/telegram/__init__.py +65 -0
  334. package/server/nodes/telegram/_credentials.py +19 -0
  335. package/server/nodes/telegram/_filters.py +122 -0
  336. package/server/nodes/telegram/_handlers.py +193 -0
  337. package/server/nodes/telegram/_refresh.py +106 -0
  338. package/server/{services/telegram_service.py → nodes/telegram/_service.py} +314 -272
  339. package/server/nodes/telegram/telegram_receive.py +149 -0
  340. package/server/nodes/telegram/telegram_send.py +269 -0
  341. package/server/nodes/text/__init__.py +1 -0
  342. package/server/nodes/text/file_handler.py +80 -0
  343. package/server/nodes/text/text_generator.py +55 -0
  344. package/server/nodes/tool/__init__.py +1 -0
  345. package/server/nodes/tool/calculator_tool.py +85 -0
  346. package/server/nodes/tool/current_time_tool.py +59 -0
  347. package/server/nodes/tool/task_manager.py +55 -0
  348. package/server/nodes/tool/write_todos.py +77 -0
  349. package/server/nodes/trigger/__init__.py +1 -0
  350. package/server/nodes/trigger/chat_trigger.py +71 -0
  351. package/server/nodes/trigger/task_trigger.py +80 -0
  352. package/server/nodes/trigger/webhook_trigger.py +110 -0
  353. package/server/nodes/twitter/__init__.py +1 -0
  354. package/server/nodes/twitter/_base.py +311 -0
  355. package/server/nodes/twitter/_credentials.py +35 -0
  356. package/server/nodes/twitter/twitter_receive.py +68 -0
  357. package/server/nodes/twitter/twitter_search.py +109 -0
  358. package/server/nodes/twitter/twitter_send.py +193 -0
  359. package/server/nodes/twitter/twitter_user.py +151 -0
  360. package/server/nodes/utility/__init__.py +1 -0
  361. package/server/nodes/utility/console.py +208 -0
  362. package/server/nodes/utility/http_request.py +164 -0
  363. package/server/nodes/utility/process_manager.py +111 -0
  364. package/server/nodes/utility/team_monitor.py +81 -0
  365. package/server/nodes/utility/webhook_response.py +85 -0
  366. package/server/nodes/visuals.json +471 -0
  367. package/server/nodes/whatsapp/__init__.py +24 -0
  368. package/server/{services/handlers/whatsapp.py → nodes/whatsapp/_base.py} +9 -3
  369. package/server/nodes/whatsapp/_runtime.py +116 -0
  370. package/server/nodes/whatsapp/whatsapp_db.py +348 -0
  371. package/server/nodes/whatsapp/whatsapp_receive.py +121 -0
  372. package/server/nodes/whatsapp/whatsapp_send.py +270 -0
  373. package/server/nodes/workflow/__init__.py +1 -0
  374. package/server/nodes/workflow/start.py +64 -0
  375. package/server/package-lock.json +1644 -0
  376. package/server/package.json +6 -1
  377. package/server/pyproject.toml +49 -9
  378. package/server/routers/credentials.py +88 -0
  379. package/server/routers/schemas.py +128 -0
  380. package/server/routers/websocket.py +527 -298
  381. package/server/services/_supervisor/__init__.py +36 -0
  382. package/server/services/_supervisor/base.py +153 -0
  383. package/server/services/_supervisor/client.py +55 -0
  384. package/server/services/_supervisor/process.py +125 -0
  385. package/server/services/_supervisor/registry.py +63 -0
  386. package/server/services/_supervisor/util.py +114 -0
  387. package/server/services/agents/adapters.py +18 -23
  388. package/server/services/agents/service.py +12 -9
  389. package/server/services/ai.py +336 -1220
  390. package/server/services/auth.py +86 -0
  391. package/server/services/auto_skill.py +152 -0
  392. package/server/services/browser_service.py +2 -31
  393. package/server/services/circuit_breaker.py +258 -0
  394. package/server/services/compaction.py +16 -17
  395. package/server/services/credential_registry.py +271 -0
  396. package/server/services/deployment/manager.py +13 -11
  397. package/server/services/deployment/triggers.py +6 -6
  398. package/server/services/event_waiter.py +146 -133
  399. package/server/services/google_oauth.py +22 -0
  400. package/server/services/handlers/__init__.py +22 -228
  401. package/server/services/handlers/todo.py +41 -49
  402. package/server/services/handlers/tools.py +235 -1814
  403. package/server/services/handlers/triggers.py +14 -18
  404. package/server/services/idempotency.py +198 -0
  405. package/server/services/llm/config.py +1 -1
  406. package/server/services/memory.py +66 -0
  407. package/server/services/model_registry.py +10 -0
  408. package/server/services/node_allowlist.py +68 -0
  409. package/server/services/node_executor.py +72 -175
  410. package/server/services/node_input_schemas.py +96 -0
  411. package/server/services/node_option_loaders/__init__.py +77 -0
  412. package/server/services/node_option_loaders/android_loaders.py +55 -0
  413. package/server/services/node_option_loaders/google_loaders.py +97 -0
  414. package/server/services/node_option_loaders/whatsapp_loaders.py +69 -0
  415. package/server/services/node_output_schemas.py +889 -0
  416. package/server/services/node_registry.py +129 -0
  417. package/server/services/node_spec.py +180 -0
  418. package/server/services/parameter_resolver.py +17 -7
  419. package/server/services/plugin/__init__.py +74 -0
  420. package/server/services/plugin/action.py +21 -0
  421. package/server/services/plugin/base.py +439 -0
  422. package/server/services/plugin/connection.py +136 -0
  423. package/server/services/plugin/context.py +80 -0
  424. package/server/services/plugin/credential.py +175 -0
  425. package/server/services/plugin/edge_walker.py +448 -0
  426. package/server/services/plugin/interceptor.py +70 -0
  427. package/server/services/plugin/operation.py +88 -0
  428. package/server/services/plugin/routing.py +186 -0
  429. package/server/services/plugin/scaling.py +78 -0
  430. package/server/services/plugin/tool.py +51 -0
  431. package/server/services/plugin/trigger.py +119 -0
  432. package/server/services/process_service.py +25 -28
  433. package/server/services/proxy/service.py +10 -7
  434. package/server/services/rlm/adapters.py +1 -1
  435. package/server/services/rlm/service.py +7 -7
  436. package/server/services/skill_loader.py +28 -6
  437. package/server/services/status_broadcaster.py +363 -186
  438. package/server/services/temporal/plugin_activities.py +109 -0
  439. package/server/services/temporal/worker.py +150 -34
  440. package/server/services/temporal/workflow.py +4 -7
  441. package/server/services/text.py +3 -3
  442. package/server/services/todo_service.py +2 -1
  443. package/server/{routers/whatsapp.py → services/whatsapp_service.py} +11 -0
  444. package/server/services/workflow.py +50 -14
  445. package/server/services/workflow_ops.py +241 -0
  446. package/server/services/ws_handler_registry.py +61 -0
  447. package/server/skills/GUIDE.md +2 -4
  448. package/server/skills/android_agent/app-launcher-skill/SKILL.md +1 -2
  449. package/server/skills/android_agent/app-list-skill/SKILL.md +1 -2
  450. package/server/skills/android_agent/audio-skill/SKILL.md +1 -2
  451. package/server/skills/android_agent/battery-skill/SKILL.md +1 -2
  452. package/server/skills/android_agent/bluetooth-skill/SKILL.md +1 -2
  453. package/server/skills/android_agent/camera-skill/SKILL.md +1 -2
  454. package/server/skills/android_agent/environmental-skill/SKILL.md +1 -2
  455. package/server/skills/android_agent/location-skill/SKILL.md +1 -2
  456. package/server/skills/android_agent/motion-skill/SKILL.md +1 -2
  457. package/server/skills/android_agent/personality/SKILL.md +1 -0
  458. package/server/skills/android_agent/screen-control-skill/SKILL.md +1 -2
  459. package/server/skills/android_agent/wifi-skill/SKILL.md +1 -2
  460. package/server/skills/assistant/assistant-personality/SKILL.md +1 -0
  461. package/server/skills/assistant/compaction-skill/SKILL.md +1 -0
  462. package/server/skills/assistant/humanify-skill/SKILL.md +1 -0
  463. package/server/skills/assistant/memory-skill/SKILL.md +1 -0
  464. package/server/skills/assistant/subagent-skill/SKILL.md +1 -0
  465. package/server/skills/autonomous/agentic-loop-skill/SKILL.md +2 -3
  466. package/server/skills/autonomous/code-mode-skill/SKILL.md +2 -3
  467. package/server/skills/autonomous/error-recovery-skill/SKILL.md +2 -3
  468. package/server/skills/autonomous/multi-tool-orchestration-skill/SKILL.md +2 -3
  469. package/server/skills/autonomous/progressive-discovery-skill/SKILL.md +1 -0
  470. package/server/skills/coding_agent/file-modify-skill/SKILL.md +8 -9
  471. package/server/skills/coding_agent/file-read-skill/SKILL.md +1 -2
  472. package/server/skills/coding_agent/fs-search-skill/SKILL.md +1 -2
  473. package/server/skills/coding_agent/javascript-skill/SKILL.md +2 -3
  474. package/server/skills/coding_agent/python-skill/SKILL.md +19 -18
  475. package/server/skills/productivity_agent/{calendar-skill → google-calendar-skill}/SKILL.md +3 -4
  476. package/server/skills/productivity_agent/{contacts-skill → google-contacts-skill}/SKILL.md +3 -4
  477. package/server/skills/productivity_agent/{drive-skill → google-drive-skill}/SKILL.md +3 -4
  478. package/server/skills/productivity_agent/{gmail-skill → google-gmail-skill}/SKILL.md +3 -4
  479. package/server/skills/productivity_agent/{sheets-skill → google-sheets-skill}/SKILL.md +3 -4
  480. package/server/skills/productivity_agent/{tasks-skill → google-tasks-skill}/SKILL.md +3 -4
  481. package/server/skills/rlm_agent/rlm-reasoning-skill/SKILL.md +2 -1
  482. package/server/skills/social_agent/twitter-search-skill/SKILL.md +44 -10
  483. package/server/skills/social_agent/twitter-send-skill/SKILL.md +1 -2
  484. package/server/skills/social_agent/twitter-user-skill/SKILL.md +1 -2
  485. package/server/skills/social_agent/whatsapp-db-skill/SKILL.md +1 -2
  486. package/server/skills/social_agent/whatsapp-send-skill/SKILL.md +1 -2
  487. package/server/skills/task_agent/cron-scheduler-skill/SKILL.md +1 -2
  488. package/server/skills/task_agent/task-manager-skill/SKILL.md +1 -2
  489. package/server/skills/task_agent/timer-skill/SKILL.md +1 -2
  490. package/server/skills/task_agent/write-todos-skill/SKILL.md +1 -2
  491. package/server/skills/terminal/bash-skill/SKILL.md +2 -3
  492. package/server/skills/terminal/powershell-skill/SKILL.md +2 -3
  493. package/server/skills/terminal/process-manager-skill/SKILL.md +1 -2
  494. package/server/skills/terminal/shell-skill/SKILL.md +107 -70
  495. package/server/skills/terminal/wsl-skill/SKILL.md +2 -3
  496. package/server/skills/travel_agent/geocoding-skill/SKILL.md +2 -3
  497. package/server/skills/travel_agent/nearby-places-skill/SKILL.md +2 -3
  498. package/server/skills/web_agent/apify-skill/SKILL.md +2 -3
  499. package/server/skills/web_agent/brave-search-skill/SKILL.md +1 -2
  500. package/server/skills/web_agent/browser-skill/SKILL.md +1 -2
  501. package/server/skills/web_agent/crawlee-scraper-skill/SKILL.md +2 -3
  502. package/server/skills/web_agent/duckduckgo-search-skill/SKILL.md +2 -3
  503. package/server/skills/web_agent/http-request-skill/SKILL.md +1 -2
  504. package/server/skills/web_agent/perplexity-search-skill/SKILL.md +1 -2
  505. package/server/skills/web_agent/proxy-config-skill/SKILL.md +2 -3
  506. package/server/skills/web_agent/serper-search-skill/SKILL.md +1 -2
  507. package/server/tests/conftest.py +144 -9
  508. package/server/tests/credentials/README.md +41 -0
  509. package/server/tests/credentials/__init__.py +0 -0
  510. package/server/tests/credentials/conftest.py +106 -0
  511. package/server/tests/credentials/test_auth_service.py +175 -0
  512. package/server/tests/credentials/test_credentials_database.py +223 -0
  513. package/server/tests/credentials/test_encryption.py +107 -0
  514. package/server/tests/credentials/test_google_oauth.py +116 -0
  515. package/server/tests/credentials/test_oauth_utils.py +89 -0
  516. package/server/tests/credentials/test_twitter_oauth.py +275 -0
  517. package/server/tests/credentials/test_websocket_handlers.py +293 -0
  518. package/server/tests/llm/test_factory.py +4 -1
  519. package/server/tests/llm/test_wiring.py +2 -2
  520. package/server/tests/nodes/__init__.py +6 -0
  521. package/server/tests/nodes/_compat.py +168 -0
  522. package/server/tests/nodes/_harness.py +274 -0
  523. package/server/tests/nodes/_mocks.py +235 -0
  524. package/server/tests/nodes/test_ai_agents.py +478 -0
  525. package/server/tests/nodes/test_ai_chat_models.py +383 -0
  526. package/server/tests/nodes/test_ai_tools.py +481 -0
  527. package/server/tests/nodes/test_android.py +463 -0
  528. package/server/tests/nodes/test_chat_utility.py +496 -0
  529. package/server/tests/nodes/test_code_fs_process.py +777 -0
  530. package/server/tests/nodes/test_document.py +591 -0
  531. package/server/tests/nodes/test_email.py +311 -0
  532. package/server/tests/nodes/test_google_workspace.py +764 -0
  533. package/server/tests/nodes/test_http_proxy.py +399 -0
  534. package/server/tests/nodes/test_search.py +327 -0
  535. package/server/tests/nodes/test_specialized_agents.py +590 -0
  536. package/server/tests/nodes/test_telegram_social.py +596 -0
  537. package/server/tests/nodes/test_twitter.py +659 -0
  538. package/server/tests/nodes/test_web_automation.py +461 -0
  539. package/server/tests/nodes/test_whatsapp.py +437 -0
  540. package/server/tests/nodes/test_workflow_triggers.py +492 -0
  541. package/server/tests/services/__init__.py +0 -0
  542. package/server/tests/services/test_supervisor.py +286 -0
  543. package/server/tests/test_auto_skill.py +306 -0
  544. package/server/tests/test_node_spec.py +1020 -0
  545. package/server/tests/test_parameter_resolver.py +109 -0
  546. package/server/tests/test_plugin_contract.py +208 -0
  547. package/server/tests/test_workflow_ops.py +230 -0
  548. package/workflows/zeenie-agent.json +2 -2
  549. package/client/dist/assets/index-C2IQ3pBs.js +0 -900
  550. package/client/dist/assets/index-DFSC53FP.css +0 -1
  551. package/client/src/components/ClaudeChatModelNode.tsx +0 -18
  552. package/client/src/components/GeminiChatModelNode.tsx +0 -18
  553. package/client/src/components/ModelNode.tsx +0 -282
  554. package/client/src/components/OpenAIChatModelNode.tsx +0 -18
  555. package/client/src/components/base/BaseChatModelNode.tsx +0 -271
  556. package/client/src/components/ui/NodeOutputPanel.tsx +0 -1512
  557. package/client/src/config/antdTheme.ts +0 -186
  558. package/client/src/factories/baseChatModelFactory.ts +0 -275
  559. package/client/src/nodeDefinitions/aiAgentNodes.ts +0 -382
  560. package/client/src/nodeDefinitions/aiModelNodes.ts +0 -281
  561. package/client/src/nodeDefinitions/androidServiceNodes.ts +0 -383
  562. package/client/src/nodeDefinitions/apifyNodes.ts +0 -253
  563. package/client/src/nodeDefinitions/browserNodes.ts +0 -306
  564. package/client/src/nodeDefinitions/chatNodes.ts +0 -135
  565. package/client/src/nodeDefinitions/codeNodes.ts +0 -78
  566. package/client/src/nodeDefinitions/crawleeNodes.ts +0 -254
  567. package/client/src/nodeDefinitions/documentNodes.ts +0 -404
  568. package/client/src/nodeDefinitions/emailNodes.ts +0 -120
  569. package/client/src/nodeDefinitions/filesystemNodes.ts +0 -208
  570. package/client/src/nodeDefinitions/googleWorkspaceNodes.ts +0 -1529
  571. package/client/src/nodeDefinitions/index.ts +0 -15
  572. package/client/src/nodeDefinitions/locationNodes.ts +0 -463
  573. package/client/src/nodeDefinitions/processNodes.ts +0 -104
  574. package/client/src/nodeDefinitions/proxyNodes.ts +0 -358
  575. package/client/src/nodeDefinitions/schedulerNodes.ts +0 -236
  576. package/client/src/nodeDefinitions/searchNodes.ts +0 -323
  577. package/client/src/nodeDefinitions/skillNodes.ts +0 -56
  578. package/client/src/nodeDefinitions/socialNodes.ts +0 -750
  579. package/client/src/nodeDefinitions/specializedAgentNodes.ts +0 -564
  580. package/client/src/nodeDefinitions/telegramNodes.ts +0 -350
  581. package/client/src/nodeDefinitions/toolNodes.ts +0 -276
  582. package/client/src/nodeDefinitions/twitterNodes.ts +0 -441
  583. package/client/src/nodeDefinitions/utilityNodes.ts +0 -364
  584. package/client/src/nodeDefinitions/whatsappNodes.ts +0 -1145
  585. package/client/src/nodeDefinitions/workflowNodes.ts +0 -95
  586. package/client/src/nodeDefinitions.ts +0 -179
  587. package/scripts/build.js +0 -208
  588. package/scripts/clean.js +0 -77
  589. package/scripts/daemon.js +0 -451
  590. package/scripts/dev.js +0 -138
  591. package/scripts/port_kill.py +0 -189
  592. package/scripts/start.js +0 -205
  593. package/scripts/stop.js +0 -61
  594. package/scripts/sync-version.js +0 -108
  595. package/scripts/utils.js +0 -352
  596. package/server/models/nodes.py +0 -511
  597. package/server/services/handlers/ai.py +0 -628
  598. package/server/services/handlers/android.py +0 -88
  599. package/server/services/handlers/apify.py +0 -261
  600. package/server/services/handlers/browser.py +0 -212
  601. package/server/services/handlers/calendar.py +0 -448
  602. package/server/services/handlers/claude_code.py +0 -97
  603. package/server/services/handlers/code.py +0 -320
  604. package/server/services/handlers/contacts.py +0 -537
  605. package/server/services/handlers/crawlee.py +0 -324
  606. package/server/services/handlers/deep_agent.py +0 -84
  607. package/server/services/handlers/document.py +0 -625
  608. package/server/services/handlers/drive.py +0 -465
  609. package/server/services/handlers/email.py +0 -86
  610. package/server/services/handlers/filesystem.py +0 -169
  611. package/server/services/handlers/gmail.py +0 -589
  612. package/server/services/handlers/http.py +0 -221
  613. package/server/services/handlers/polyglot.py +0 -105
  614. package/server/services/handlers/process.py +0 -83
  615. package/server/services/handlers/proxy.py +0 -326
  616. package/server/services/handlers/rlm.py +0 -78
  617. package/server/services/handlers/search.py +0 -385
  618. package/server/services/handlers/sheets.py +0 -314
  619. package/server/services/handlers/tasks.py +0 -452
  620. package/server/services/handlers/telegram.py +0 -244
  621. package/server/services/handlers/twitter.py +0 -652
  622. package/server/services/handlers/utility.py +0 -913
  623. package/server/services/polyglot_client.py +0 -169
  624. package/workflows/ai-employee-experimental.json +0 -1400
  625. package/workflows/zeenie-assistant.json +0 -1871
@@ -1,385 +0,0 @@
1
- """Search API node handlers - Brave Search, Serper, Perplexity Sonar.
2
-
3
- Each handler fetches the API key from the encrypted credentials system
4
- via auth_service, then calls the provider's API.
5
- """
6
-
7
- import time
8
- from typing import Dict, Any
9
-
10
- import httpx
11
-
12
- from core.logging import get_logger
13
- from services.pricing import get_pricing_service
14
-
15
- logger = get_logger(__name__)
16
-
17
-
18
- async def _track_search_usage(
19
- node_id: str,
20
- service: str,
21
- action: str,
22
- resource_count: int = 1,
23
- workflow_id: str = None,
24
- session_id: str = "default"
25
- ) -> Dict[str, float]:
26
- """Track search API usage for cost calculation."""
27
- from core.container import container
28
-
29
- pricing = get_pricing_service()
30
- cost_data = pricing.calculate_api_cost(service, action, resource_count)
31
-
32
- db = container.database()
33
- await db.save_api_usage_metric({
34
- 'session_id': session_id,
35
- 'node_id': node_id,
36
- 'workflow_id': workflow_id,
37
- 'service': service,
38
- 'operation': cost_data.get('operation', action),
39
- 'endpoint': action,
40
- 'resource_count': resource_count,
41
- 'cost': cost_data.get('total_cost', 0.0)
42
- })
43
-
44
- logger.debug(f"[Search] Tracked {service} usage: {action} x{resource_count} = ${cost_data.get('total_cost', 0):.6f}")
45
- return cost_data
46
-
47
-
48
- async def _get_api_key(provider: str) -> str:
49
- """Get API key from encrypted credentials."""
50
- from core.container import container
51
- auth_service = container.auth_service()
52
- api_key = await auth_service.get_api_key(provider)
53
- if not api_key:
54
- raise ValueError(
55
- f"{provider} API key not configured. "
56
- f"Please add it in Credentials > Search."
57
- )
58
- return api_key
59
-
60
-
61
- # =============================================================================
62
- # BRAVE SEARCH HANDLER
63
- # =============================================================================
64
-
65
- async def handle_brave_search(
66
- node_id: str,
67
- node_type: str,
68
- parameters: Dict[str, Any],
69
- context: Dict[str, Any]
70
- ) -> Dict[str, Any]:
71
- """Handle Brave Search API requests.
72
-
73
- API: GET https://api.search.brave.com/res/v1/web/search
74
- Auth: X-Subscription-Token header
75
- """
76
- start_time = time.time()
77
-
78
- query = parameters.get('query', '').strip()
79
- if not query:
80
- return {"success": False, "error": "Search query is required"}
81
-
82
- max_results = parameters.get('maxResults', 10)
83
- country = parameters.get('country', '')
84
- search_lang = parameters.get('searchLang', '')
85
- safe_search = parameters.get('safeSearch', 'moderate')
86
-
87
- try:
88
- api_key = await _get_api_key('brave_search')
89
-
90
- params = {
91
- 'q': query,
92
- 'count': min(max_results, 100),
93
- }
94
- if country:
95
- params['country'] = country
96
- if search_lang:
97
- params['search_lang'] = search_lang
98
- if safe_search:
99
- params['safesearch'] = safe_search
100
-
101
- async with httpx.AsyncClient(timeout=30.0) as client:
102
- response = await client.get(
103
- 'https://api.search.brave.com/res/v1/web/search',
104
- headers={
105
- 'X-Subscription-Token': api_key,
106
- 'Accept': 'application/json',
107
- },
108
- params=params,
109
- )
110
- response.raise_for_status()
111
- data = response.json()
112
-
113
- # Extract web results
114
- web_results = data.get('web', {}).get('results', [])
115
- results = []
116
- for item in web_results[:max_results]:
117
- results.append({
118
- 'title': item.get('title', ''),
119
- 'snippet': item.get('description', ''),
120
- 'url': item.get('url', ''),
121
- })
122
-
123
- execution_time = time.time() - start_time
124
-
125
- # Track usage
126
- workflow_id = context.get('workflow_id')
127
- session_id = context.get('session_id', 'default')
128
- await _track_search_usage(node_id, 'brave_search', 'web_search', 1, workflow_id, session_id)
129
-
130
- return {
131
- "success": True,
132
- "result": {
133
- "query": query,
134
- "results": results,
135
- "result_count": len(results),
136
- "provider": "brave_search",
137
- },
138
- "execution_time": round(execution_time, 3),
139
- }
140
-
141
- except httpx.HTTPStatusError as e:
142
- logger.error(f"[BraveSearch] API error: {e.response.status_code} - {e.response.text}")
143
- return {"success": False, "error": f"Brave Search API error: {e.response.status_code}"}
144
- except ValueError as e:
145
- return {"success": False, "error": str(e)}
146
- except Exception as e:
147
- logger.error(f"[BraveSearch] Error: {e}")
148
- return {"success": False, "error": f"Brave Search failed: {str(e)}"}
149
-
150
-
151
- # =============================================================================
152
- # SERPER SEARCH HANDLER
153
- # =============================================================================
154
-
155
- async def handle_serper_search(
156
- node_id: str,
157
- node_type: str,
158
- parameters: Dict[str, Any],
159
- context: Dict[str, Any]
160
- ) -> Dict[str, Any]:
161
- """Handle Serper (Google) Search API requests.
162
-
163
- API: POST https://google.serper.dev/search
164
- Auth: X-API-KEY header
165
- """
166
- start_time = time.time()
167
-
168
- query = parameters.get('query', '').strip()
169
- if not query:
170
- return {"success": False, "error": "Search query is required"}
171
-
172
- max_results = parameters.get('maxResults', 10)
173
- search_type = parameters.get('searchType', 'search')
174
- country = parameters.get('country', '')
175
- language = parameters.get('language', '')
176
-
177
- try:
178
- api_key = await _get_api_key('serper')
179
-
180
- body: Dict[str, Any] = {
181
- 'q': query,
182
- 'num': min(max_results, 100),
183
- }
184
- if country:
185
- body['gl'] = country
186
- if language:
187
- body['hl'] = language
188
-
189
- # Map search type to endpoint
190
- endpoint_map = {
191
- 'search': 'https://google.serper.dev/search',
192
- 'news': 'https://google.serper.dev/news',
193
- 'images': 'https://google.serper.dev/images',
194
- 'places': 'https://google.serper.dev/places',
195
- }
196
- endpoint = endpoint_map.get(search_type, 'https://google.serper.dev/search')
197
-
198
- async with httpx.AsyncClient(timeout=30.0) as client:
199
- response = await client.post(
200
- endpoint,
201
- headers={
202
- 'X-API-KEY': api_key,
203
- 'Content-Type': 'application/json',
204
- },
205
- json=body,
206
- )
207
- response.raise_for_status()
208
- data = response.json()
209
-
210
- # Extract results based on search type
211
- results = []
212
- if search_type == 'search':
213
- for item in data.get('organic', [])[:max_results]:
214
- results.append({
215
- 'title': item.get('title', ''),
216
- 'snippet': item.get('snippet', ''),
217
- 'url': item.get('link', ''),
218
- 'position': item.get('position'),
219
- })
220
- elif search_type == 'news':
221
- for item in data.get('news', [])[:max_results]:
222
- results.append({
223
- 'title': item.get('title', ''),
224
- 'snippet': item.get('snippet', ''),
225
- 'url': item.get('link', ''),
226
- 'date': item.get('date', ''),
227
- 'source': item.get('source', ''),
228
- })
229
- elif search_type == 'images':
230
- for item in data.get('images', [])[:max_results]:
231
- results.append({
232
- 'title': item.get('title', ''),
233
- 'imageUrl': item.get('imageUrl', ''),
234
- 'url': item.get('link', ''),
235
- })
236
- elif search_type == 'places':
237
- for item in data.get('places', [])[:max_results]:
238
- results.append({
239
- 'title': item.get('title', ''),
240
- 'address': item.get('address', ''),
241
- 'rating': item.get('rating'),
242
- 'url': item.get('website', ''),
243
- })
244
-
245
- # Include knowledge graph if available
246
- knowledge_graph = data.get('knowledgeGraph')
247
-
248
- execution_time = time.time() - start_time
249
-
250
- # Track usage
251
- workflow_id = context.get('workflow_id')
252
- session_id = context.get('session_id', 'default')
253
- await _track_search_usage(node_id, 'serper', 'web_search', 1, workflow_id, session_id)
254
-
255
- result = {
256
- "query": query,
257
- "results": results,
258
- "result_count": len(results),
259
- "search_type": search_type,
260
- "provider": "serper",
261
- }
262
- if knowledge_graph:
263
- result["knowledge_graph"] = knowledge_graph
264
-
265
- return {
266
- "success": True,
267
- "result": result,
268
- "execution_time": round(execution_time, 3),
269
- }
270
-
271
- except httpx.HTTPStatusError as e:
272
- logger.error(f"[Serper] API error: {e.response.status_code} - {e.response.text}")
273
- return {"success": False, "error": f"Serper API error: {e.response.status_code}"}
274
- except ValueError as e:
275
- return {"success": False, "error": str(e)}
276
- except Exception as e:
277
- logger.error(f"[Serper] Error: {e}")
278
- return {"success": False, "error": f"Serper search failed: {str(e)}"}
279
-
280
-
281
- # =============================================================================
282
- # PERPLEXITY SEARCH HANDLER
283
- # =============================================================================
284
-
285
- async def handle_perplexity_search(
286
- node_id: str,
287
- node_type: str,
288
- parameters: Dict[str, Any],
289
- context: Dict[str, Any]
290
- ) -> Dict[str, Any]:
291
- """Handle Perplexity Sonar AI search requests.
292
-
293
- API: POST https://api.perplexity.ai/chat/completions
294
- Auth: Authorization: Bearer header
295
- """
296
- start_time = time.time()
297
-
298
- query = parameters.get('query', '').strip()
299
- if not query:
300
- return {"success": False, "error": "Search query is required"}
301
-
302
- model = parameters.get('model', 'sonar')
303
- search_recency_filter = parameters.get('searchRecencyFilter', '')
304
- return_images = parameters.get('returnImages', False)
305
- return_related_questions = parameters.get('returnRelatedQuestions', False)
306
-
307
- try:
308
- api_key = await _get_api_key('perplexity')
309
-
310
- body: Dict[str, Any] = {
311
- 'model': model,
312
- 'messages': [
313
- {'role': 'user', 'content': query}
314
- ],
315
- }
316
-
317
- if search_recency_filter:
318
- body['search_recency_filter'] = search_recency_filter
319
- if return_images:
320
- body['return_images'] = True
321
- if return_related_questions:
322
- body['return_related_questions'] = True
323
-
324
- async with httpx.AsyncClient(timeout=60.0) as client:
325
- response = await client.post(
326
- 'https://api.perplexity.ai/chat/completions',
327
- headers={
328
- 'Authorization': f'Bearer {api_key}',
329
- 'Content-Type': 'application/json',
330
- },
331
- json=body,
332
- )
333
- response.raise_for_status()
334
- data = response.json()
335
-
336
- # Extract answer and citations
337
- choices = data.get('choices', [])
338
- answer = ''
339
- if choices:
340
- message = choices[0].get('message', {})
341
- answer = message.get('content', '')
342
-
343
- citations = data.get('citations', [])
344
- images = data.get('images', [])
345
- related_questions = data.get('related_questions', [])
346
-
347
- # Build results from citations
348
- results = []
349
- for url in citations:
350
- results.append({'url': url})
351
-
352
- execution_time = time.time() - start_time
353
-
354
- # Track usage
355
- workflow_id = context.get('workflow_id')
356
- session_id = context.get('session_id', 'default')
357
- await _track_search_usage(node_id, 'perplexity', 'sonar_search', 1, workflow_id, session_id)
358
-
359
- result: Dict[str, Any] = {
360
- "query": query,
361
- "answer": answer,
362
- "citations": citations,
363
- "results": results,
364
- "model": model,
365
- "provider": "perplexity",
366
- }
367
- if images:
368
- result["images"] = images
369
- if related_questions:
370
- result["related_questions"] = related_questions
371
-
372
- return {
373
- "success": True,
374
- "result": result,
375
- "execution_time": round(execution_time, 3),
376
- }
377
-
378
- except httpx.HTTPStatusError as e:
379
- logger.error(f"[Perplexity] API error: {e.response.status_code} - {e.response.text}")
380
- return {"success": False, "error": f"Perplexity API error: {e.response.status_code}"}
381
- except ValueError as e:
382
- return {"success": False, "error": str(e)}
383
- except Exception as e:
384
- logger.error(f"[Perplexity] Error: {e}")
385
- return {"success": False, "error": f"Perplexity search failed: {str(e)}"}
@@ -1,314 +0,0 @@
1
- """Google Sheets node handlers using Google API Python client.
2
-
3
- API Reference: https://developers.google.com/workspace/sheets/api/reference/rest
4
- """
5
-
6
- import asyncio
7
- import time
8
- from typing import Any, Dict
9
-
10
- from googleapiclient.discovery import build
11
-
12
- from core.logging import get_logger
13
- from services.handlers.google_auth import get_google_credentials
14
- from services.pricing import get_pricing_service
15
-
16
- logger = get_logger(__name__)
17
-
18
-
19
- async def _track_sheets_usage(
20
- node_id: str,
21
- action: str,
22
- resource_count: int = 1,
23
- workflow_id: str = None,
24
- session_id: str = "default"
25
- ) -> Dict[str, float]:
26
- """Track Google Sheets API usage for analytics.
27
-
28
- Note: Sheets API is free but rate limited (300 requests/min).
29
- We track for analytics purposes with $0 cost.
30
- """
31
- from core.container import container
32
-
33
- pricing = get_pricing_service()
34
- cost_data = pricing.calculate_api_cost('google_sheets', action, resource_count)
35
-
36
- db = container.database()
37
- await db.save_api_usage_metric({
38
- 'session_id': session_id,
39
- 'node_id': node_id,
40
- 'workflow_id': workflow_id,
41
- 'service': 'google_sheets',
42
- 'operation': cost_data.get('operation', action),
43
- 'endpoint': action,
44
- 'resource_count': resource_count,
45
- 'cost': cost_data.get('total_cost', 0.0)
46
- })
47
-
48
- logger.debug(f"[Sheets] Tracked usage: {action} x{resource_count}")
49
- return cost_data
50
-
51
-
52
- async def _get_sheets_service(
53
- parameters: Dict[str, Any],
54
- context: Dict[str, Any]
55
- ):
56
- """Get authenticated Google Sheets service."""
57
- creds = await get_google_credentials(parameters, context)
58
-
59
- def build_service():
60
- return build("sheets", "v4", credentials=creds)
61
-
62
- loop = asyncio.get_event_loop()
63
- return await loop.run_in_executor(None, build_service)
64
-
65
-
66
- async def handle_sheets_read(
67
- node_id: str,
68
- node_type: str,
69
- parameters: Dict[str, Any],
70
- context: Dict[str, Any]
71
- ) -> Dict[str, Any]:
72
- """Read data from a Google Sheets spreadsheet.
73
-
74
- Parameters:
75
- spreadsheet_id: ID of the spreadsheet (required)
76
- range: A1 notation range (e.g., "Sheet1!A1:D10") (required)
77
- value_render_option: How values should be rendered ('FORMATTED_VALUE', 'UNFORMATTED_VALUE', 'FORMULA')
78
- major_dimension: Rows or columns first ('ROWS', 'COLUMNS')
79
- """
80
- start_time = time.time()
81
-
82
- try:
83
- service = await _get_sheets_service(parameters, context)
84
-
85
- spreadsheet_id = parameters.get('spreadsheet_id', '')
86
- range_notation = parameters.get('range', '')
87
- value_render = parameters.get('value_render_option', 'FORMATTED_VALUE')
88
- major_dimension = parameters.get('major_dimension', 'ROWS')
89
-
90
- if not spreadsheet_id:
91
- raise ValueError("Spreadsheet ID is required")
92
- if not range_notation:
93
- raise ValueError("Range is required (e.g., 'Sheet1!A1:D10')")
94
-
95
- workflow_id = context.get('workflow_id')
96
- session_id = context.get('session_id', 'default')
97
-
98
- def read_values():
99
- return service.spreadsheets().values().get(
100
- spreadsheetId=spreadsheet_id,
101
- range=range_notation,
102
- valueRenderOption=value_render,
103
- majorDimension=major_dimension
104
- ).execute()
105
-
106
- loop = asyncio.get_event_loop()
107
- result = await loop.run_in_executor(None, read_values)
108
-
109
- values = result.get('values', [])
110
-
111
- await _track_sheets_usage(node_id, 'read', len(values), workflow_id, session_id)
112
-
113
- return {
114
- "success": True,
115
- "result": {
116
- "values": values,
117
- "range": result.get('range'),
118
- "rows": len(values),
119
- "columns": len(values[0]) if values else 0,
120
- "major_dimension": result.get('majorDimension'),
121
- },
122
- "execution_time": time.time() - start_time
123
- }
124
-
125
- except Exception as e:
126
- logger.error(f"Sheets read error: {e}")
127
- return {"success": False, "error": str(e), "execution_time": time.time() - start_time}
128
-
129
-
130
- async def handle_sheets_write(
131
- node_id: str,
132
- node_type: str,
133
- parameters: Dict[str, Any],
134
- context: Dict[str, Any]
135
- ) -> Dict[str, Any]:
136
- """Write data to a Google Sheets spreadsheet.
137
-
138
- Parameters:
139
- spreadsheet_id: ID of the spreadsheet (required)
140
- range: A1 notation range (e.g., "Sheet1!A1") (required)
141
- values: 2D array of values to write (required)
142
- value_input_option: How input values should be interpreted ('RAW', 'USER_ENTERED')
143
- """
144
- start_time = time.time()
145
-
146
- try:
147
- service = await _get_sheets_service(parameters, context)
148
-
149
- spreadsheet_id = parameters.get('spreadsheet_id', '')
150
- range_notation = parameters.get('range', '')
151
- values = parameters.get('values', [])
152
- value_input = parameters.get('value_input_option', 'USER_ENTERED')
153
-
154
- if not spreadsheet_id:
155
- raise ValueError("Spreadsheet ID is required")
156
- if not range_notation:
157
- raise ValueError("Range is required (e.g., 'Sheet1!A1')")
158
- if not values:
159
- raise ValueError("Values are required")
160
-
161
- # Parse values if string (JSON format)
162
- if isinstance(values, str):
163
- import json
164
- values = json.loads(values)
165
-
166
- # Ensure values is a 2D array
167
- if values and not isinstance(values[0], list):
168
- values = [values]
169
-
170
- workflow_id = context.get('workflow_id')
171
- session_id = context.get('session_id', 'default')
172
-
173
- body = {'values': values}
174
-
175
- def write_values():
176
- return service.spreadsheets().values().update(
177
- spreadsheetId=spreadsheet_id,
178
- range=range_notation,
179
- valueInputOption=value_input,
180
- body=body
181
- ).execute()
182
-
183
- loop = asyncio.get_event_loop()
184
- result = await loop.run_in_executor(None, write_values)
185
-
186
- await _track_sheets_usage(node_id, 'write', result.get('updatedCells', 0), workflow_id, session_id)
187
-
188
- return {
189
- "success": True,
190
- "result": {
191
- "updated_range": result.get('updatedRange'),
192
- "updated_rows": result.get('updatedRows'),
193
- "updated_columns": result.get('updatedColumns'),
194
- "updated_cells": result.get('updatedCells'),
195
- },
196
- "execution_time": time.time() - start_time
197
- }
198
-
199
- except Exception as e:
200
- logger.error(f"Sheets write error: {e}")
201
- return {"success": False, "error": str(e), "execution_time": time.time() - start_time}
202
-
203
-
204
- async def handle_sheets_append(
205
- node_id: str,
206
- node_type: str,
207
- parameters: Dict[str, Any],
208
- context: Dict[str, Any]
209
- ) -> Dict[str, Any]:
210
- """Append rows to a Google Sheets spreadsheet.
211
-
212
- Parameters:
213
- spreadsheet_id: ID of the spreadsheet (required)
214
- range: A1 notation range (e.g., "Sheet1!A:D") (required)
215
- values: 2D array of values to append (required)
216
- value_input_option: How input values should be interpreted ('RAW', 'USER_ENTERED')
217
- insert_data_option: How the input data should be inserted ('OVERWRITE', 'INSERT_ROWS')
218
- """
219
- start_time = time.time()
220
-
221
- try:
222
- service = await _get_sheets_service(parameters, context)
223
-
224
- spreadsheet_id = parameters.get('spreadsheet_id', '')
225
- range_notation = parameters.get('range', '')
226
- values = parameters.get('values', [])
227
- value_input = parameters.get('value_input_option', 'USER_ENTERED')
228
- insert_option = parameters.get('insert_data_option', 'INSERT_ROWS')
229
-
230
- if not spreadsheet_id:
231
- raise ValueError("Spreadsheet ID is required")
232
- if not range_notation:
233
- raise ValueError("Range is required (e.g., 'Sheet1!A:D')")
234
- if not values:
235
- raise ValueError("Values are required")
236
-
237
- # Parse values if string (JSON format)
238
- if isinstance(values, str):
239
- import json
240
- values = json.loads(values)
241
-
242
- # Ensure values is a 2D array
243
- if values and not isinstance(values[0], list):
244
- values = [values]
245
-
246
- workflow_id = context.get('workflow_id')
247
- session_id = context.get('session_id', 'default')
248
-
249
- body = {'values': values}
250
-
251
- def append_values():
252
- return service.spreadsheets().values().append(
253
- spreadsheetId=spreadsheet_id,
254
- range=range_notation,
255
- valueInputOption=value_input,
256
- insertDataOption=insert_option,
257
- body=body
258
- ).execute()
259
-
260
- loop = asyncio.get_event_loop()
261
- result = await loop.run_in_executor(None, append_values)
262
-
263
- updates = result.get('updates', {})
264
-
265
- await _track_sheets_usage(node_id, 'append', updates.get('updatedCells', 0), workflow_id, session_id)
266
-
267
- return {
268
- "success": True,
269
- "result": {
270
- "updated_range": updates.get('updatedRange'),
271
- "updated_rows": updates.get('updatedRows'),
272
- "updated_columns": updates.get('updatedColumns'),
273
- "updated_cells": updates.get('updatedCells'),
274
- "table_range": result.get('tableRange'),
275
- },
276
- "execution_time": time.time() - start_time
277
- }
278
-
279
- except Exception as e:
280
- logger.error(f"Sheets append error: {e}")
281
- return {"success": False, "error": str(e), "execution_time": time.time() - start_time}
282
-
283
-
284
- # ============================================================================
285
- # CONSOLIDATED DISPATCHER
286
- # ============================================================================
287
-
288
- async def handle_google_sheets(
289
- node_id: str,
290
- node_type: str,
291
- parameters: Dict[str, Any],
292
- context: Dict[str, Any]
293
- ) -> Dict[str, Any]:
294
- """Consolidated Sheets handler with operation dispatcher.
295
-
296
- Routes to appropriate handler based on 'operation' parameter:
297
- - read: Read data from spreadsheet
298
- - write: Write data to spreadsheet
299
- - append: Append rows to spreadsheet
300
- """
301
- operation = parameters.get('operation', 'read')
302
-
303
- if operation == 'read':
304
- return await handle_sheets_read(node_id, node_type, parameters, context)
305
- elif operation == 'write':
306
- return await handle_sheets_write(node_id, node_type, parameters, context)
307
- elif operation == 'append':
308
- return await handle_sheets_append(node_id, node_type, parameters, context)
309
- else:
310
- return {
311
- "success": False,
312
- "error": f"Unknown Sheets operation: {operation}. Supported: read, write, append",
313
- "execution_time": 0
314
- }