machinaos 0.0.76 → 0.0.78

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 (393) hide show
  1. package/README.md +143 -107
  2. package/client/dist/assets/ActionBar-Du2MSFSz.js +1 -0
  3. package/client/dist/assets/ApiKeyInput-k2LBmBjb.js +1 -0
  4. package/client/dist/assets/ApiKeyPanel-C_bV9U0X.js +1 -0
  5. package/client/dist/assets/ApiUsageSection-CmVfwZzL.js +1 -0
  6. package/client/dist/assets/EmailPanel-CeKIMGu-.js +1 -0
  7. package/client/dist/assets/OAuthPanel-KA3t3Q2K.js +1 -0
  8. package/client/dist/assets/QrPairingPanel-NgNpJNuk.js +1 -0
  9. package/client/dist/assets/RateLimitSection-Du5YNVIA.js +1 -0
  10. package/client/dist/assets/StatusCard-DNLyayXc.js +1 -0
  11. package/client/dist/assets/index-DQ0nwhec.js +257 -0
  12. package/client/dist/assets/index-DxmbVskS.css +1 -0
  13. package/client/dist/assets/vendor-flow-CZmBvHRo.js +1 -0
  14. package/client/dist/assets/vendor-icons-CVrPjN2Q.js +22 -0
  15. package/client/dist/assets/vendor-markdown-CRou3yQ5.js +62 -0
  16. package/client/dist/assets/vendor-misc-C4VxKHs5.js +1 -0
  17. package/client/dist/assets/vendor-query-SzWcOU0G.js +1 -0
  18. package/client/dist/assets/vendor-radix-Dnos29jG.js +56 -0
  19. package/client/dist/assets/vendor-react-DvWIbVx0.js +1 -0
  20. package/client/dist/index.html +37 -3
  21. package/client/index.html +28 -1
  22. package/client/package.json +44 -40
  23. package/client/src/App.tsx +2 -0
  24. package/client/src/Dashboard.tsx +157 -45
  25. package/client/src/ParameterPanel.tsx +3 -5
  26. package/client/src/adapters/nodeSpecToDescription.ts +1 -0
  27. package/client/src/assets/icons/NodeIcon.tsx +32 -0
  28. package/client/src/assets/icons/index.ts +4 -0
  29. package/client/src/assets/icons/stripe.svg +1 -0
  30. package/client/src/assets/icons/themedGlyphs.ts +404 -0
  31. package/client/src/components/AIAgentNode.tsx +77 -53
  32. package/client/src/components/GenericNode.tsx +34 -52
  33. package/client/src/components/OutputPanel.tsx +64 -147
  34. package/client/src/components/ParameterRenderer.tsx +5 -3
  35. package/client/src/components/SkillEditorModal.tsx +9 -18
  36. package/client/src/components/SquareNode.tsx +97 -115
  37. package/client/src/components/StartNode.tsx +32 -42
  38. package/client/src/components/SvgFilterDefs.tsx +54 -0
  39. package/client/src/components/TeamMonitorNode.tsx +12 -14
  40. package/client/src/components/ToolkitNode.tsx +35 -60
  41. package/client/src/components/TriggerNode.tsx +43 -77
  42. package/client/src/components/__tests__/CredentialsModal.test.tsx +49 -45
  43. package/client/src/components/credentials/CredentialsModal.tsx +98 -30
  44. package/client/src/components/credentials/CredentialsPalette.tsx +73 -5
  45. package/client/src/components/credentials/catalogueAdapter.ts +17 -1
  46. package/client/src/components/credentials/panels/ApiKeyPanel.tsx +102 -37
  47. package/client/src/components/credentials/panels/EmailPanel.tsx +7 -19
  48. package/client/src/components/credentials/panels/OAuthPanel.tsx +5 -1
  49. package/client/src/components/credentials/panels/QrPairingPanel.tsx +1 -3
  50. package/client/src/components/credentials/primitives/ActionBar.tsx +7 -11
  51. package/client/src/components/credentials/primitives/OAuthConnect.tsx +19 -28
  52. package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +24 -3
  53. package/client/src/components/credentials/types.ts +12 -2
  54. package/client/src/components/credentials/useCredentialPanel.ts +43 -19
  55. package/client/src/components/icons/AIProviderIcons.tsx +16 -0
  56. package/client/src/components/onboarding/OnboardingWizard.tsx +23 -63
  57. package/client/src/components/onboarding/nodeRoleClasses.ts +23 -0
  58. package/client/src/components/onboarding/steps/CanvasStep.tsx +15 -21
  59. package/client/src/components/onboarding/steps/ConceptsStep.tsx +2 -11
  60. package/client/src/components/onboarding/steps/GetStartedStep.tsx +2 -10
  61. package/client/src/components/parameterPanel/InputSection.tsx +9 -7
  62. package/client/src/components/parameterPanel/MasterSkillEditor.tsx +84 -198
  63. package/client/src/components/parameterPanel/MiddleSection.tsx +57 -80
  64. package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +31 -25
  65. package/client/src/components/parameterPanel/__tests__/InputSection.test.tsx +7 -2
  66. package/client/src/components/ui/AIResultModal.tsx +1 -1
  67. package/client/src/components/ui/CollapsibleSection.tsx +9 -5
  68. package/client/src/components/ui/CommandPalette.tsx +147 -0
  69. package/client/src/components/ui/CommandPaletteHost.tsx +189 -0
  70. package/client/src/components/ui/ComponentItem.tsx +13 -7
  71. package/client/src/components/ui/ComponentPalette.tsx +24 -13
  72. package/client/src/components/ui/ConsolePanel.tsx +19 -11
  73. package/client/src/components/ui/DropCap.tsx +28 -0
  74. package/client/src/components/ui/EditableNodeLabel.tsx +10 -2
  75. package/client/src/components/ui/InputNodesPanel.tsx +1 -1
  76. package/client/src/components/ui/Modal.tsx +38 -6
  77. package/client/src/components/ui/OutputDisplayPanel.tsx +1 -1
  78. package/client/src/components/ui/SettingsPanel.tsx +42 -13
  79. package/client/src/components/ui/StatusBar.tsx +108 -0
  80. package/client/src/components/ui/ThemeSwitcher.tsx +109 -0
  81. package/client/src/components/ui/TopToolbar.tsx +42 -25
  82. package/client/src/components/ui/WorkflowSidebar.tsx +32 -16
  83. package/client/src/components/ui/action-button.tsx +40 -15
  84. package/client/src/components/ui/button.tsx +24 -1
  85. package/client/src/components/ui/dropdown-menu.tsx +24 -2
  86. package/client/src/components/ui/input.tsx +19 -2
  87. package/client/src/components/ui/select.tsx +15 -0
  88. package/client/src/components/ui/textarea.tsx +15 -2
  89. package/client/src/contexts/AuthContext.tsx +148 -109
  90. package/client/src/contexts/ThemeContext.tsx +93 -17
  91. package/client/src/contexts/WebSocketContext.tsx +373 -206
  92. package/client/src/contexts/__tests__/AuthContext.test.tsx +221 -0
  93. package/client/src/hooks/__tests__/useDragVariable.test.ts +7 -1
  94. package/client/src/hooks/__tests__/useWorkflowOpsListener.test.ts +142 -0
  95. package/client/src/hooks/useAppTheme.ts +209 -7
  96. package/client/src/hooks/useAutoSkillEdges.ts +7 -2
  97. package/client/src/hooks/useCatalogueQuery.ts +67 -1
  98. package/client/src/hooks/useDragVariable.ts +1 -1
  99. package/client/src/hooks/useNodeAllowlist.ts +115 -8
  100. package/client/src/hooks/useOnboarding.ts +20 -8
  101. package/client/src/hooks/useParameterPanel.ts +2 -1
  102. package/client/src/hooks/useReactFlowNodes.ts +2 -1
  103. package/client/src/hooks/useSound.ts +185 -0
  104. package/client/src/hooks/useWorkflowManagement.ts +6 -8
  105. package/client/src/hooks/useWorkflowOpsListener.ts +90 -0
  106. package/client/src/index.css +65 -3
  107. package/client/src/lib/__tests__/connectionConfig.test.ts +91 -0
  108. package/client/src/lib/aiModelProviders.ts +8 -0
  109. package/client/src/lib/connectionConfig.ts +107 -0
  110. package/client/src/lib/queryPersist.ts +13 -5
  111. package/client/src/lib/sound.ts +393 -0
  112. package/client/src/main.tsx +20 -0
  113. package/client/src/store/useAppStore.ts +26 -0
  114. package/client/src/styles/canvasAnimations.ts +37 -36
  115. package/client/src/styles/theme.ts +36 -20
  116. package/client/src/test/setup.ts +1 -0
  117. package/client/src/themes/atomic.css +253 -0
  118. package/client/src/themes/base.css +373 -0
  119. package/client/src/themes/cyber.css +890 -0
  120. package/client/src/themes/dark.css +70 -0
  121. package/client/src/themes/edo.css +246 -0
  122. package/client/src/themes/greek.css +293 -0
  123. package/client/src/themes/light.css +78 -0
  124. package/client/src/themes/plague.css +253 -0
  125. package/client/src/themes/renaissance.css +727 -0
  126. package/client/src/themes/rot.css +249 -0
  127. package/client/src/themes/steampunk.css +272 -0
  128. package/client/src/themes/surveillance.css +289 -0
  129. package/client/src/themes/wasteland.css +250 -0
  130. package/client/src/types/INodeProperties.ts +5 -0
  131. package/client/src/types/NodeTypes.ts +11 -1
  132. package/client/src/types/__tests__/cloudEvents.test.ts +99 -0
  133. package/client/src/types/cloudEvents.ts +78 -0
  134. package/client/src/vite-env.d.ts +7 -0
  135. package/client/tsconfig.json +1 -1
  136. package/client/vite.config.js +62 -2
  137. package/install.ps1 +1 -1
  138. package/install.sh +1 -1
  139. package/machina/commands/build.py +51 -7
  140. package/machina/pyproject.toml +4 -0
  141. package/machina/supervisor.py +12 -2
  142. package/machina/tree.py +71 -21
  143. package/package.json +4 -4
  144. package/scripts/install.js +16 -1
  145. package/server/config/ai_cli_providers.json +54 -0
  146. package/server/config/credential_providers.json +109 -2
  147. package/server/config/llm_defaults.json +24 -0
  148. package/server/config/model_registry.json +338 -499
  149. package/server/config/node_allowlist.json +16 -1
  150. package/server/config/pricing.json +8 -0
  151. package/server/constants.py +38 -15
  152. package/server/core/container.py +2 -2
  153. package/server/core/credentials_database.py +35 -2
  154. package/server/core/logging.py +4 -3
  155. package/server/main.py +99 -13
  156. package/server/models/node_metadata.py +1 -0
  157. package/server/nodejs/package.json +8 -6
  158. package/server/nodejs/src/index.ts +22 -5
  159. package/server/nodes/README.md +31 -4
  160. package/server/nodes/agent/_inline.py +2 -0
  161. package/server/nodes/agent/_specialized.py +6 -3
  162. package/server/nodes/agent/ai_agent.py +13 -3
  163. package/server/nodes/agent/chat_agent.py +6 -3
  164. package/server/nodes/agent/claude_code_agent.py +287 -75
  165. package/server/nodes/agent/codex_agent.py +239 -0
  166. package/server/nodes/agent/deep_agent.py +3 -3
  167. package/server/nodes/agent/rlm_agent.py +3 -3
  168. package/server/nodes/android/__init__.py +31 -1
  169. package/server/nodes/android/_base.py +9 -5
  170. package/server/{services/android_service.py → nodes/android/_dispatcher.py} +2 -2
  171. package/server/nodes/android/_handlers.py +154 -0
  172. package/server/nodes/android/_option_loaders.py +44 -0
  173. package/server/nodes/android/_refresh.py +127 -0
  174. package/server/{services/android → nodes/android/_relay}/client.py +4 -4
  175. package/server/{routers/android.py → nodes/android/_router.py} +27 -8
  176. package/server/nodes/browser/browser.py +2 -2
  177. package/server/nodes/code/_base.py +6 -2
  178. package/server/nodes/code/_claude_code.py +134 -0
  179. package/server/nodes/document/embedding_generator.py +3 -3
  180. package/server/nodes/document/http_scraper.py +3 -3
  181. package/server/nodes/document/vector_store.py +5 -5
  182. package/server/nodes/email/__init__.py +11 -1
  183. package/server/nodes/email/_filters.py +21 -0
  184. package/server/{services/himalaya_service.py → nodes/email/_himalaya.py} +6 -10
  185. package/server/{services/email_service.py → nodes/email/_service.py} +9 -13
  186. package/server/nodes/email/email_read.py +1 -1
  187. package/server/nodes/email/email_receive.py +54 -5
  188. package/server/nodes/email/email_send.py +1 -1
  189. package/server/nodes/filesystem/shell.py +24 -1
  190. package/server/nodes/google/__init__.py +55 -1
  191. package/server/{services/handlers/google_auth.py → nodes/google/_auth_helper.py} +8 -5
  192. package/server/nodes/google/_base.py +2 -2
  193. package/server/nodes/google/_credentials.py +5 -5
  194. package/server/nodes/google/_filters.py +25 -0
  195. package/server/nodes/google/_handlers.py +57 -0
  196. package/server/{services/google_oauth.py → nodes/google/_oauth.py} +195 -162
  197. package/server/nodes/google/_option_loaders.py +107 -0
  198. package/server/nodes/google/_refresh.py +66 -0
  199. package/server/nodes/google/_router.py +131 -0
  200. package/server/nodes/google/gmail_receive.py +41 -4
  201. package/server/nodes/groups.py +1 -0
  202. package/server/nodes/location/_credentials.py +45 -1
  203. package/server/{services/maps.py → nodes/location/_service.py} +18 -3
  204. package/server/nodes/location/gmaps_create.py +4 -4
  205. package/server/nodes/location/gmaps_locations.py +4 -4
  206. package/server/nodes/location/gmaps_nearby_places.py +4 -4
  207. package/server/nodes/model/_base.py +8 -3
  208. package/server/nodes/model/_credentials.py +96 -8
  209. package/server/nodes/model/_local_validator.py +345 -0
  210. package/server/nodes/model/lmstudio_chat_model.py +23 -0
  211. package/server/nodes/model/ollama_chat_model.py +25 -0
  212. package/server/nodes/proxy/_usage.py +2 -2
  213. package/server/nodes/proxy/proxy_config.py +14 -14
  214. package/server/nodes/proxy/proxy_request.py +4 -4
  215. package/server/nodes/scraper/_credentials.py +29 -1
  216. package/server/nodes/scraper/apify_actor.py +9 -9
  217. package/server/nodes/scraper/crawlee_scraper.py +5 -5
  218. package/server/nodes/search/brave_search.py +4 -0
  219. package/server/nodes/search/perplexity_search.py +9 -0
  220. package/server/nodes/search/serper_search.py +3 -0
  221. package/server/nodes/skill/simple_memory.py +12 -0
  222. package/server/nodes/social/_base.py +2 -2
  223. package/server/nodes/stripe/__init__.py +46 -0
  224. package/server/nodes/stripe/_credentials.py +33 -0
  225. package/server/nodes/stripe/_handlers.py +270 -0
  226. package/server/nodes/stripe/_install.py +127 -0
  227. package/server/nodes/stripe/_source.py +174 -0
  228. package/server/nodes/stripe/stripe_action.py +81 -0
  229. package/server/nodes/stripe/stripe_receive.py +92 -0
  230. package/server/nodes/telegram/_credentials.py +52 -1
  231. package/server/nodes/telegram/_handlers.py +19 -18
  232. package/server/nodes/telegram/_service.py +134 -32
  233. package/server/nodes/telegram/telegram_send.py +5 -6
  234. package/server/nodes/text/file_handler.py +2 -2
  235. package/server/nodes/text/text_generator.py +2 -2
  236. package/server/nodes/tool/agent_builder.py +630 -0
  237. package/server/nodes/tool/task_manager.py +144 -2
  238. package/server/nodes/twitter/__init__.py +38 -1
  239. package/server/nodes/twitter/_base.py +7 -7
  240. package/server/nodes/twitter/_credentials.py +1 -1
  241. package/server/nodes/twitter/_filters.py +37 -0
  242. package/server/nodes/twitter/_handlers.py +77 -0
  243. package/server/nodes/twitter/_oauth.py +124 -0
  244. package/server/nodes/twitter/_refresh.py +78 -0
  245. package/server/nodes/twitter/_router.py +29 -0
  246. package/server/nodes/twitter/twitter_receive.py +4 -0
  247. package/server/nodes/visuals.json +64 -19
  248. package/server/nodes/whatsapp/__init__.py +45 -5
  249. package/server/nodes/whatsapp/_base.py +3 -3
  250. package/server/nodes/whatsapp/_filters.py +137 -0
  251. package/server/nodes/whatsapp/_handlers.py +167 -0
  252. package/server/nodes/whatsapp/_option_loaders.py +68 -0
  253. package/server/nodes/whatsapp/_refresh.py +62 -0
  254. package/server/nodes/whatsapp/_runtime.py +1 -1
  255. package/server/pyproject.toml +29 -7
  256. package/server/routers/schemas.py +2 -2
  257. package/server/routers/webhook.py +26 -9
  258. package/server/routers/websocket.py +149 -810
  259. package/server/services/ai.py +89 -8
  260. package/server/services/auth.py +220 -43
  261. package/server/services/claude_oauth.py +126 -100
  262. package/server/services/cli_agent/__init__.py +78 -0
  263. package/server/services/cli_agent/_handlers.py +237 -0
  264. package/server/services/cli_agent/config.py +112 -0
  265. package/server/services/cli_agent/factory.py +48 -0
  266. package/server/services/cli_agent/lockfile.py +141 -0
  267. package/server/services/cli_agent/mcp_server.py +482 -0
  268. package/server/services/cli_agent/protocol.py +173 -0
  269. package/server/services/cli_agent/providers/__init__.py +9 -0
  270. package/server/services/cli_agent/providers/anthropic_claude.py +419 -0
  271. package/server/services/cli_agent/providers/google_gemini.py +80 -0
  272. package/server/services/cli_agent/providers/openai_codex.py +310 -0
  273. package/server/services/cli_agent/service.py +607 -0
  274. package/server/services/cli_agent/session.py +618 -0
  275. package/server/services/cli_agent/types.py +227 -0
  276. package/server/services/cli_agent/workflow_tools.py +233 -0
  277. package/server/services/credential_registry.py +26 -1
  278. package/server/services/deployment/manager.py +26 -145
  279. package/server/services/deployment/poll_registry.py +59 -0
  280. package/server/services/event_waiter.py +76 -246
  281. package/server/services/events/__init__.py +54 -0
  282. package/server/services/events/cli.py +78 -0
  283. package/server/services/events/daemon.py +163 -0
  284. package/server/services/events/envelope.py +281 -0
  285. package/server/services/events/lifecycle.py +99 -0
  286. package/server/services/events/oauth_lifecycle.py +534 -0
  287. package/server/services/events/polling.py +60 -0
  288. package/server/services/events/push.py +36 -0
  289. package/server/services/events/source.py +63 -0
  290. package/server/services/events/triggers.py +118 -0
  291. package/server/services/events/verifiers/__init__.py +25 -0
  292. package/server/services/events/verifiers/base.py +28 -0
  293. package/server/services/events/verifiers/github.py +25 -0
  294. package/server/services/events/verifiers/hmac_basic.py +32 -0
  295. package/server/services/events/verifiers/standard_webhooks.py +47 -0
  296. package/server/services/events/verifiers/stripe.py +42 -0
  297. package/server/services/events/webhook.py +105 -0
  298. package/server/services/handlers/tools.py +28 -186
  299. package/server/services/llm/config.py +7 -0
  300. package/server/services/llm/factory.py +8 -2
  301. package/server/services/memory/__init__.py +52 -0
  302. package/server/services/memory/jsonl.py +80 -0
  303. package/server/services/memory/markdown.py +65 -0
  304. package/server/services/memory/state.py +112 -0
  305. package/server/services/memory/vector_store.py +40 -0
  306. package/server/services/model_registry.py +76 -0
  307. package/server/services/node_allowlist.py +71 -15
  308. package/server/services/node_executor.py +2 -2
  309. package/server/services/node_output_schemas.py +21 -10
  310. package/server/services/node_spec.py +1 -1
  311. package/server/services/oauth_utils.py +1 -1
  312. package/server/services/plugin/__init__.py +2 -0
  313. package/server/services/plugin/base.py +44 -2
  314. package/server/services/plugin/credential.py +288 -1
  315. package/server/services/plugin/deps.py +105 -0
  316. package/server/services/plugin/edge_walker.py +12 -4
  317. package/server/services/plugin/oauth.py +381 -0
  318. package/server/services/plugin/polling.py +247 -0
  319. package/server/services/plugin/registry.py +145 -0
  320. package/server/services/plugin/singleton.py +65 -0
  321. package/server/services/plugin/ws.py +81 -0
  322. package/server/services/process_service.py +31 -2
  323. package/server/services/status_broadcaster.py +155 -238
  324. package/server/services/temporal/workflow.py +7 -7
  325. package/server/services/workflow.py +21 -3
  326. package/server/services/ws_handler_registry.py +111 -28
  327. package/server/skills/GUIDE.md +16 -1
  328. package/server/skills/assistant/agent-builder-skill/SKILL.md +166 -0
  329. package/server/skills/payments_agent/stripe-skill/SKILL.md +306 -0
  330. package/server/tests/credentials/test_auth_service.py +16 -9
  331. package/server/tests/credentials/test_credential_broadcasts.py +219 -0
  332. package/server/tests/credentials/test_google_oauth.py +6 -6
  333. package/server/tests/credentials/test_oauth_utils.py +1 -1
  334. package/server/tests/credentials/test_twitter_oauth.py +2 -2
  335. package/server/tests/credentials/test_websocket_handlers.py +44 -20
  336. package/server/tests/llm/test_factory.py +1 -0
  337. package/server/tests/llm/test_wiring.py +5 -1
  338. package/server/tests/nodes/_compat.py +24 -24
  339. package/server/tests/nodes/test_agent_builder.py +439 -0
  340. package/server/tests/nodes/test_ai_tools.py +18 -14
  341. package/server/tests/nodes/test_code_fs_process.py +17 -8
  342. package/server/tests/nodes/test_email.py +10 -9
  343. package/server/tests/nodes/test_google_workspace.py +2 -2
  344. package/server/tests/nodes/test_specialized_agents.py +100 -53
  345. package/server/tests/nodes/test_stripe_plugin.py +293 -0
  346. package/server/tests/nodes/test_telegram_social.py +4 -4
  347. package/server/tests/nodes/test_twitter.py +1 -1
  348. package/server/tests/nodes/test_web_automation.py +2 -2
  349. package/server/tests/nodes/test_whatsapp.py +9 -9
  350. package/server/tests/services/cli_agent/__init__.py +0 -0
  351. package/server/tests/services/cli_agent/test_mcp_server.py +432 -0
  352. package/server/tests/services/cli_agent/test_providers.py +358 -0
  353. package/server/tests/services/cli_agent/test_service.py +298 -0
  354. package/server/tests/services/memory/__init__.py +0 -0
  355. package/server/tests/services/memory/test_jsonl.py +188 -0
  356. package/server/tests/services/test_events.py +333 -0
  357. package/server/tests/test_node_spec.py +56 -16
  358. package/server/tests/test_plugin_helpers.py +116 -0
  359. package/server/tests/test_plugin_self_containment.py +486 -0
  360. package/server/tests/test_status_broadcasts.py +425 -0
  361. package/workflows/{AI Assistant_workflow-1777421105154-0m4snkzjf.json → AI Assistant_workflow-1778504793388-ou1m1tz2x.json } +70 -266
  362. package/workflows/{AI Employee_workflow-1777720598005-u4cm858dv.json → AI Employee_example_workflow-1777720598005-u4cm858dv.json } +112 -112
  363. package/workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json +709 -0
  364. package/client/dist/assets/ActionBar-vzPpSR77.js +0 -1
  365. package/client/dist/assets/ApiKeyInput-Ds7AKFe8.js +0 -1
  366. package/client/dist/assets/ApiKeyPanel-gfblELep.js +0 -1
  367. package/client/dist/assets/ApiUsageSection-BMNWTe2r.js +0 -1
  368. package/client/dist/assets/EmailPanel-B1Om64p5.js +0 -1
  369. package/client/dist/assets/OAuthPanel-CXyQYGBz.js +0 -1
  370. package/client/dist/assets/QrPairingPanel-BgNuI1we.js +0 -1
  371. package/client/dist/assets/RateLimitSection-YYK8sx1T.js +0 -1
  372. package/client/dist/assets/StatusCard-DuYA5hJR.js +0 -1
  373. package/client/dist/assets/index-D9tZfgvi.js +0 -363
  374. package/client/dist/assets/index-al7snTkG.css +0 -1
  375. package/client/src/components/credentials/providers.tsx +0 -177
  376. package/server/routers/google.py +0 -277
  377. package/server/routers/maps.py +0 -142
  378. package/server/routers/twitter.py +0 -365
  379. package/server/services/claude_code_service.py +0 -106
  380. package/server/services/memory.py +0 -159
  381. package/server/services/node_option_loaders/__init__.py +0 -77
  382. package/server/services/node_option_loaders/android_loaders.py +0 -55
  383. package/server/services/node_option_loaders/google_loaders.py +0 -97
  384. package/server/services/node_option_loaders/whatsapp_loaders.py +0 -69
  385. package/server/services/twitter_oauth.py +0 -411
  386. package/server/services/websocket_client.py +0 -29
  387. /package/server/{services/android → nodes/android/_relay}/__init__.py +0 -0
  388. /package/server/{services/android → nodes/android/_relay}/broadcaster.py +0 -0
  389. /package/server/{services/android → nodes/android/_relay}/manager.py +0 -0
  390. /package/server/{services/android → nodes/android/_relay}/protocol.py +0 -0
  391. /package/server/{services/browser_service.py → nodes/browser/_service.py} +0 -0
  392. /package/server/{services/whatsapp_service.py → nodes/whatsapp/_service.py} +0 -0
  393. /package/server/skills/{task_agent → assistant}/write-todos-skill/SKILL.md +0 -0
@@ -1,365 +0,0 @@
1
- """
2
- Twitter/X OAuth 2.0 callback and API routes.
3
-
4
- OAuth flow:
5
- 1. Frontend calls WebSocket 'twitter_oauth_login' handler
6
- 2. Backend generates authorization URL, opens browser
7
- 3. User authorizes on Twitter
8
- 4. Twitter redirects to /api/twitter/callback with code
9
- 5. Backend exchanges code for tokens, stores them via auth_service
10
- 6. Frontend polls WebSocket 'twitter_oauth_status' for completion
11
-
12
- Tokens stored as API keys with provider prefixes:
13
- - twitter_access_token: OAuth access token (expires in 2 hours)
14
- - twitter_refresh_token: OAuth refresh token (for token renewal)
15
- """
16
-
17
- from typing import Optional
18
-
19
- from fastapi import APIRouter, Query, Request
20
- from fastapi.responses import HTMLResponse
21
-
22
- from core.container import container
23
- from core.logging import get_logger
24
- from services.twitter_oauth import TwitterOAuth, get_pending_state
25
-
26
- logger = get_logger(__name__)
27
- router = APIRouter(prefix="/api/twitter", tags=["twitter"])
28
-
29
-
30
- def get_auth_service():
31
- """Get auth service for API key storage."""
32
- return container.auth_service()
33
-
34
-
35
- @router.get("/callback")
36
- async def twitter_oauth_callback(
37
- code: Optional[str] = Query(None),
38
- state: Optional[str] = Query(None),
39
- error: Optional[str] = Query(None),
40
- error_description: Optional[str] = Query(None),
41
- ):
42
- """
43
- Handle Twitter OAuth callback.
44
-
45
- Twitter redirects here after user authorizes (or denies) the app.
46
- We exchange the code for tokens and store them via auth_service.
47
- """
48
- # Handle authorization denied
49
- if error:
50
- logger.warning(f"Twitter OAuth denied: {error} - {error_description}")
51
- return HTMLResponse(
52
- content=_callback_html(
53
- success=False,
54
- error=error_description or error,
55
- ),
56
- status_code=200,
57
- )
58
-
59
- # Validate required parameters
60
- if not code or not state:
61
- logger.error("Twitter OAuth callback missing code or state")
62
- return HTMLResponse(
63
- content=_callback_html(
64
- success=False,
65
- error="Missing authorization code or state parameter",
66
- ),
67
- status_code=400,
68
- )
69
-
70
- # Verify state exists (CSRF protection)
71
- pending_state = get_pending_state(state)
72
- if not pending_state:
73
- logger.error("Twitter OAuth callback with invalid/expired state")
74
- return HTMLResponse(
75
- content=_callback_html(
76
- success=False,
77
- error="Invalid or expired authorization state. Please try again.",
78
- ),
79
- status_code=400,
80
- )
81
-
82
- # Retrieve redirect_uri from state (set during auth initiation)
83
- redirect_uri = pending_state.get("redirect_uri")
84
- if not redirect_uri:
85
- logger.error("Twitter OAuth callback missing redirect_uri in state")
86
- return HTMLResponse(
87
- content=_callback_html(
88
- success=False,
89
- error="Invalid state: missing redirect URI. Please try again.",
90
- ),
91
- status_code=400,
92
- )
93
-
94
- # Get stored client credentials to create OAuth instance
95
- auth_service = get_auth_service()
96
- client_id = await auth_service.get_api_key("twitter_client_id") or ""
97
- client_secret = await auth_service.get_api_key("twitter_client_secret")
98
-
99
- oauth = TwitterOAuth(
100
- client_id=client_id,
101
- client_secret=client_secret,
102
- redirect_uri=redirect_uri,
103
- )
104
-
105
- # Exchange code for tokens
106
- result = await oauth.exchange_code(code=code, state=state)
107
-
108
- if not result.get("success"):
109
- logger.error(f"Twitter token exchange failed: {result.get('error')}")
110
- return HTMLResponse(
111
- content=_callback_html(
112
- success=False,
113
- error=result.get("error", "Token exchange failed"),
114
- ),
115
- status_code=400,
116
- )
117
-
118
- # Get user info to display and store
119
- access_token = result.get("access_token")
120
- refresh_token = result.get("refresh_token")
121
- user_info = await oauth.get_user_info(access_token)
122
-
123
- if not user_info.get("success"):
124
- logger.warning(f"Failed to get Twitter user info: {user_info.get('error')}")
125
- username = "Unknown"
126
- else:
127
- username = user_info.get("username", "Unknown")
128
-
129
- # Store encrypted OAuth tokens via auth_service
130
- await auth_service.store_oauth_tokens(
131
- provider="twitter",
132
- access_token=access_token,
133
- refresh_token=refresh_token or "",
134
- email=f"@{username}", # Use @username as identifier (Twitter doesn't provide email)
135
- name=user_info.get("name", "") if user_info.get("success") else "",
136
- scopes=",".join(result.get("scope", "").split()) if result.get("scope") else "",
137
- customer_id="owner",
138
- )
139
-
140
- # Broadcast completion event to frontend
141
- from services.status_broadcaster import get_status_broadcaster
142
- broadcaster = get_status_broadcaster()
143
-
144
- await broadcaster.broadcast({
145
- "type": "twitter_oauth_complete",
146
- "data": {
147
- "success": True,
148
- "username": username,
149
- "user_id": user_info.get("id"),
150
- "name": user_info.get("name"),
151
- "profile_image_url": user_info.get("profile_image_url"),
152
- }
153
- })
154
-
155
- logger.info(f"Twitter OAuth successful for @{username}")
156
-
157
- return HTMLResponse(
158
- content=_callback_html(
159
- success=True,
160
- username=username,
161
- ),
162
- status_code=200,
163
- )
164
-
165
-
166
- @router.get("/status")
167
- async def get_twitter_status(request: Request):
168
- """
169
- Get Twitter connection status.
170
-
171
- Returns whether the user is authenticated with Twitter.
172
- """
173
- from services.oauth_utils import get_redirect_uri
174
-
175
- auth_service = get_auth_service()
176
-
177
- # Try to get stored tokens via auth_service
178
- tokens = await auth_service.get_oauth_tokens("twitter", customer_id="owner")
179
-
180
- if not tokens:
181
- return {
182
- "connected": False,
183
- "username": None,
184
- "user_id": None,
185
- }
186
-
187
- access_token = tokens.get("access_token")
188
- refresh_token = tokens.get("refresh_token")
189
-
190
- # Get stored client credentials (these remain in auth_service as they're app-level)
191
- client_id = await auth_service.get_api_key("twitter_client_id") or ""
192
- client_secret = await auth_service.get_api_key("twitter_client_secret")
193
- redirect_uri = get_redirect_uri(request, "twitter")
194
-
195
- oauth = TwitterOAuth(
196
- client_id=client_id,
197
- client_secret=client_secret,
198
- redirect_uri=redirect_uri,
199
- )
200
-
201
- # Verify token is still valid by getting user info
202
- user_info = await oauth.get_user_info(access_token)
203
-
204
- if not user_info.get("success"):
205
- # Token may be expired, try to refresh
206
- if refresh_token:
207
- refresh_result = await oauth.refresh_access_token(refresh_token)
208
- if refresh_result.get("success"):
209
- # Store new tokens via auth_service
210
- await auth_service.store_oauth_tokens(
211
- provider="twitter",
212
- access_token=refresh_result["access_token"],
213
- refresh_token=refresh_result.get("refresh_token") or refresh_token,
214
- email=tokens.get("email"),
215
- name=tokens.get("name"),
216
- scopes=tokens.get("scopes"),
217
- customer_id="owner",
218
- )
219
-
220
- # Retry user info
221
- user_info = await oauth.get_user_info(refresh_result["access_token"])
222
-
223
- if not user_info.get("success"):
224
- return {
225
- "connected": False,
226
- "username": None,
227
- "user_id": None,
228
- "error": user_info.get("error"),
229
- }
230
-
231
- return {
232
- "connected": True,
233
- "username": user_info.get("username"),
234
- "user_id": user_info.get("id"),
235
- "name": user_info.get("name"),
236
- "profile_image_url": user_info.get("profile_image_url"),
237
- "verified": user_info.get("verified"),
238
- }
239
-
240
-
241
- @router.post("/logout")
242
- async def twitter_logout(request: Request):
243
- """
244
- Disconnect Twitter by revoking tokens and clearing stored credentials.
245
- """
246
- from services.oauth_utils import get_redirect_uri
247
-
248
- auth_service = get_auth_service()
249
-
250
- # Get stored tokens via auth_service
251
- tokens = await auth_service.get_oauth_tokens("twitter", customer_id="owner")
252
-
253
- if tokens:
254
- access_token = tokens.get("access_token")
255
- refresh_token = tokens.get("refresh_token")
256
-
257
- # Get client credentials for revocation (app-level, in auth_service)
258
- client_id = await auth_service.get_api_key("twitter_client_id") or ""
259
- client_secret = await auth_service.get_api_key("twitter_client_secret")
260
- redirect_uri = get_redirect_uri(request, "twitter")
261
-
262
- oauth = TwitterOAuth(
263
- client_id=client_id,
264
- client_secret=client_secret,
265
- redirect_uri=redirect_uri,
266
- )
267
-
268
- # Revoke tokens
269
- if access_token:
270
- await oauth.revoke_token(access_token, "access_token")
271
-
272
- if refresh_token:
273
- await oauth.revoke_token(refresh_token, "refresh_token")
274
-
275
- # Clear stored credentials via auth_service
276
- await auth_service.remove_oauth_tokens("twitter", customer_id="owner")
277
-
278
- logger.info("Twitter disconnected and tokens revoked")
279
-
280
- return {"success": True, "message": "Twitter disconnected"}
281
-
282
-
283
- def _callback_html(success: bool, username: str = None, error: str = None) -> str:
284
- """Generate callback HTML page that closes itself and notifies parent."""
285
- if success:
286
- title = "Twitter Connected"
287
- message = f"Successfully connected as @{username}!"
288
- color = "#00ba7c" # Green
289
- else:
290
- title = "Connection Failed"
291
- message = error or "Failed to connect to Twitter"
292
- color = "#f4212e" # Red
293
-
294
- escaped_error = error.replace("'", "\\'") if error else ""
295
- return f"""
296
- <!DOCTYPE html>
297
- <html>
298
- <head>
299
- <title>{title}</title>
300
- <style>
301
- * {{ margin: 0; padding: 0; box-sizing: border-box; }}
302
- body {{
303
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
304
- background: linear-gradient(135deg, #15202b 0%, #1a1a2e 100%);
305
- min-height: 100vh;
306
- display: flex;
307
- align-items: center;
308
- justify-content: center;
309
- color: #fff;
310
- }}
311
- .container {{
312
- text-align: center;
313
- padding: 40px;
314
- background: rgba(255, 255, 255, 0.05);
315
- border-radius: 16px;
316
- border: 1px solid rgba(255, 255, 255, 0.1);
317
- max-width: 400px;
318
- }}
319
- .icon {{
320
- width: 64px;
321
- height: 64px;
322
- margin-bottom: 20px;
323
- color: {color};
324
- }}
325
- h1 {{
326
- font-size: 24px;
327
- margin-bottom: 12px;
328
- color: {color};
329
- }}
330
- p {{
331
- font-size: 16px;
332
- color: rgba(255, 255, 255, 0.8);
333
- margin-bottom: 20px;
334
- }}
335
- .close-text {{
336
- font-size: 14px;
337
- color: rgba(255, 255, 255, 0.5);
338
- }}
339
- </style>
340
- </head>
341
- <body>
342
- <div class="container">
343
- <svg class="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
344
- {"<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'/>" if success else "<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z'/>"}
345
- </svg>
346
- <h1>{title}</h1>
347
- <p>{message}</p>
348
- <p class="close-text">This window will close automatically...</p>
349
- </div>
350
- <script>
351
- // Notify parent window and close
352
- if (window.opener) {{
353
- window.opener.postMessage({{
354
- type: 'twitter_oauth_callback',
355
- success: {str(success).lower()},
356
- {"username: '" + username + "'," if username else ""}
357
- {"error: '" + escaped_error + "'," if error else ""}
358
- }}, '*');
359
- }}
360
- // Close after 2 seconds
361
- setTimeout(function() {{ window.close(); }}, 2000);
362
- </script>
363
- </body>
364
- </html>
365
- """
@@ -1,106 +0,0 @@
1
- """Claude Code service - manages CLI execution with session persistence."""
2
-
3
- import asyncio
4
- import json
5
- import os
6
- import shutil
7
- from typing import Any, Dict, List, Optional
8
-
9
- from core.logging import get_logger
10
-
11
- logger = get_logger(__name__)
12
-
13
-
14
- def _find_claude_cmd() -> List[str]:
15
- """Find claude CLI cross-platform."""
16
- if shutil.which("claude"):
17
- return ["claude"]
18
- npx = shutil.which("npx")
19
- if npx:
20
- return [npx, "-y", "@anthropic-ai/claude-code"]
21
- raise FileNotFoundError("Neither 'claude' nor 'npx' found in PATH")
22
-
23
-
24
- class ClaudeCodeService:
25
- """Executes tasks via Claude Code CLI with session tracking."""
26
-
27
- def __init__(self):
28
- self._session_map: Dict[str, str] = {} # node_id -> session_id
29
-
30
- async def execute(
31
- self,
32
- prompt: str,
33
- node_id: str = "",
34
- model: str = "claude-sonnet-4-6",
35
- cwd: Optional[str] = None,
36
- allowed_tools: str = "Read,Edit,Bash,Glob,Grep,Write",
37
- max_turns: int = 10,
38
- max_budget_usd: float = 5.0,
39
- system_prompt: Optional[str] = None,
40
- ) -> Dict[str, Any]:
41
- """Run claude CLI and return parsed JSON result."""
42
- cmd = _find_claude_cmd() + [
43
- "-p", prompt,
44
- "--output-format", "json",
45
- "--model", model,
46
- "--max-turns", str(max_turns),
47
- "--allowedTools", allowed_tools,
48
- ]
49
-
50
- if max_budget_usd > 0:
51
- cmd += ["--max-budget-usd", str(max_budget_usd)]
52
-
53
- # Resume existing session for this node
54
- session_id = self._session_map.get(node_id)
55
- if session_id:
56
- cmd += ["--resume", session_id]
57
-
58
- if system_prompt:
59
- cmd += ["--append-system-prompt", system_prompt]
60
-
61
- if not cwd:
62
- from core.config import Settings
63
- cwd = os.path.join(Settings().workspace_base_resolved, 'default')
64
- os.makedirs(cwd, exist_ok=True)
65
- work_dir = cwd
66
-
67
- proc = await asyncio.create_subprocess_exec(
68
- *cmd,
69
- stdout=asyncio.subprocess.PIPE,
70
- stderr=asyncio.subprocess.PIPE,
71
- cwd=work_dir,
72
- )
73
- stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=300)
74
-
75
- if proc.returncode != 0:
76
- err = stderr.decode("utf-8", errors="replace").strip()
77
- logger.error("Claude Code failed (exit %d): %s", proc.returncode, err)
78
- raise RuntimeError(err or f"Exit code {proc.returncode}")
79
-
80
- raw = stdout.decode("utf-8", errors="replace").strip()
81
- try:
82
- data = json.loads(raw)
83
- except json.JSONDecodeError:
84
- data = {"result": raw}
85
-
86
- # Track session for future resume
87
- if data.get("session_id") and node_id:
88
- self._session_map[node_id] = data["session_id"]
89
-
90
- return data
91
-
92
- def get_session_id(self, node_id: str) -> Optional[str]:
93
- return self._session_map.get(node_id)
94
-
95
- def clear_session(self, node_id: str) -> None:
96
- self._session_map.pop(node_id, None)
97
-
98
-
99
- _instance: Optional[ClaudeCodeService] = None
100
-
101
-
102
- def get_claude_code_service() -> ClaudeCodeService:
103
- global _instance
104
- if _instance is None:
105
- _instance = ClaudeCodeService()
106
- return _instance
@@ -1,159 +0,0 @@
1
- """Markdown-based conversation memory helpers.
2
-
3
- Parse, append, trim, and archive conversation history stored in markdown format.
4
- Used by AI Agent and Chat Agent for persistent memory across turns.
5
- """
6
-
7
- import re
8
- from datetime import datetime
9
- from typing import Dict, Any, List
10
-
11
- from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
12
-
13
- from core.logging import get_logger
14
-
15
- logger = get_logger(__name__)
16
-
17
-
18
- def parse_memory_markdown(content: str) -> List[BaseMessage]:
19
- """Parse markdown memory content into LangChain messages.
20
-
21
- Markdown format:
22
- ### **Human** (timestamp)
23
- message content
24
-
25
- ### **Assistant** (timestamp)
26
- response content
27
- """
28
- messages = []
29
- pattern = r'### \*\*(Human|Assistant)\*\*[^\n]*\n(.*?)(?=\n### \*\*|$)'
30
- for role, text in re.findall(pattern, content, re.DOTALL):
31
- text = text.strip()
32
- if text:
33
- msg_class = HumanMessage if role == 'Human' else AIMessage
34
- messages.append(msg_class(content=text))
35
- return messages
36
-
37
-
38
- def append_to_memory_markdown(content: str, role: str, message: str) -> str:
39
- """Append a message to markdown memory content."""
40
- ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
41
- label = "Human" if role == "human" else "Assistant"
42
- entry = f"\n### **{label}** ({ts})\n{message}\n"
43
- # Remove empty state message if present
44
- return content.replace("*No messages yet.*\n", "") + entry
45
-
46
-
47
- def trim_markdown_window(content: str, window_size: int) -> tuple:
48
- """Keep last N message pairs, return (trimmed_content, removed_texts).
49
-
50
- Args:
51
- content: Full markdown content
52
- window_size: Number of message PAIRS to keep (human+assistant)
53
-
54
- Returns:
55
- Tuple of (trimmed markdown, list of removed message texts for archival)
56
- """
57
- pattern = r'(### \*\*(Human|Assistant)\*\*[^\n]*\n.*?)(?=\n### \*\*|$)'
58
- blocks = [m[0] for m in re.findall(pattern, content, re.DOTALL)]
59
-
60
- if len(blocks) <= window_size * 2:
61
- return content, []
62
-
63
- keep = blocks[-(window_size * 2):]
64
- removed = blocks[:-(window_size * 2)]
65
-
66
- # Extract text from removed blocks for vector storage
67
- removed_texts = []
68
- for block in removed:
69
- match = re.search(r'\n(.*)$', block, re.DOTALL)
70
- if match:
71
- removed_texts.append(match.group(1).strip())
72
-
73
- return "# Conversation History\n" + "\n".join(keep), removed_texts
74
-
75
-
76
- # Global cache for vector stores per session (InMemoryVectorStore)
77
- _memory_vector_stores: Dict[str, Any] = {}
78
-
79
-
80
- def get_memory_vector_store(session_id: str):
81
- """Get or create InMemoryVectorStore for a session."""
82
- if session_id not in _memory_vector_stores:
83
- try:
84
- from langchain_core.vectorstores import InMemoryVectorStore
85
- from langchain_huggingface import HuggingFaceEmbeddings
86
-
87
- embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-en-v1.5")
88
- _memory_vector_stores[session_id] = InMemoryVectorStore(embeddings)
89
- logger.debug(f"[Memory] Created vector store for session '{session_id}'")
90
- except ImportError as e:
91
- logger.warning(f"[Memory] Vector store not available: {e}")
92
- return None
93
- return _memory_vector_stores[session_id]
94
-
95
-
96
- def clear_agent_session_state(
97
- session_id: str,
98
- workflow_id: str = None,
99
- clear_long_term: bool = False,
100
- ) -> Dict[str, Any]:
101
- """Clear every store keyed by an agent's conversational scope.
102
-
103
- "Memory" from the user's perspective is not just the markdown
104
- transcript — it's every piece of state an agent reuses across
105
- iterations of a conversation. ``simpleMemory.memory_content`` is the
106
- visible part; the long-term vector store and ``TodoService``
107
- plan-work-update lists are the invisible parts that quietly bloat
108
- subsequent runs (notably ``task_agent``, whose default skill bundle
109
- instructs the LLM to read accumulated todos every run).
110
-
111
- ``TodoService`` is keyed by ``ctx.workflow_id or ctx.node_id or
112
- "default"`` (see ``server/nodes/tool/write_todos.py``). We clear all
113
- three candidate keys to match whichever fallback the agent actually
114
- used at write time.
115
-
116
- Args:
117
- session_id: ``simpleMemory`` node's ``session_id`` parameter.
118
- workflow_id: Active workflow id (passed by the frontend so we
119
- can clear ``TodoService`` entries written under it).
120
- clear_long_term: When ``True``, drop the per-session vector
121
- store too.
122
-
123
- Returns:
124
- Dict with ``cleared_vector_store`` (bool) and ``cleared_todo_keys``
125
- (list[str]) for caller-visible diagnostics. Markdown reset is
126
- signalled by returning the default content, owned by the WS
127
- handler so the wire shape stays in one place.
128
- """
129
- # The live vector-store cache lives in ``services.ai`` (the dict in
130
- # this module is dormant — nothing imports it). Lazy import keeps
131
- # ``services.ai``'s heavy LangChain deps off the hot path.
132
- from services.ai import _memory_vector_stores as _live_vector_stores
133
- from services.todo_service import get_todo_service
134
-
135
- cleared_vector_store = False
136
- if clear_long_term and session_id in _live_vector_stores:
137
- del _live_vector_stores[session_id]
138
- cleared_vector_store = True
139
- logger.info(f"[Memory] Cleared vector store for session '{session_id}'")
140
-
141
- todo_service = get_todo_service()
142
- cleared_todo_keys: List[str] = []
143
- seen = set()
144
- for key in (workflow_id, session_id, "default"):
145
- if key and key not in seen:
146
- seen.add(key)
147
- todo_service.clear(key)
148
- cleared_todo_keys.append(key)
149
-
150
- logger.info(
151
- "[Memory] Cleared agent session state session=%s workflow_id=%s "
152
- "vector_store=%s todo_keys=%s",
153
- session_id, workflow_id, cleared_vector_store, cleared_todo_keys,
154
- )
155
-
156
- return {
157
- "cleared_vector_store": cleared_vector_store,
158
- "cleared_todo_keys": cleared_todo_keys,
159
- }