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
@@ -0,0 +1,227 @@
1
+ """Pydantic task specs (discriminated union) + result models.
2
+
3
+ The discriminated union lets each plugin's `Params.tasks` be hard-typed
4
+ to one variant (e.g. `list[ClaudeTaskSpec]`), so the LLM tool schema
5
+ fast-path at `services/ai.py:2898` produces a clean per-provider schema
6
+ with no `$defs`/`$ref`.
7
+
8
+ v1 ships Claude + Codex plugins fully wired. `GeminiTaskSpec` is part of
9
+ the union (and exported) so the type system, factory dispatch keys, and
10
+ config JSON are ready, but `create_cli_provider("gemini")` raises
11
+ `NotImplementedError`. v2 swaps the stub for the real impl.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Annotated, Any, Dict, List, Literal, Optional, Union
17
+
18
+ from pydantic import BaseModel, ConfigDict, Field
19
+
20
+ from services.cli_agent.protocol import CanonicalUsage
21
+
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Task specs (discriminated union)
25
+ # ---------------------------------------------------------------------------
26
+
27
+ class BaseAICliTaskSpec(BaseModel):
28
+ """Shared fields for every CLI task."""
29
+ task_id: Optional[str] = Field(
30
+ default=None,
31
+ description="Auto-assigned `t_<8hex>` if omitted.",
32
+ )
33
+ prompt: str = Field(
34
+ ...,
35
+ description="The task prompt sent to the CLI.",
36
+ json_schema_extra={"rows": 4},
37
+ )
38
+ branch: Optional[str] = Field(
39
+ default=None,
40
+ description="Branch name for the per-task git worktree. "
41
+ "Auto-named `machina/<task_id>` if omitted.",
42
+ )
43
+ model: Optional[str] = Field(default=None)
44
+ timeout_seconds: int = Field(
45
+ default=600, ge=10, le=3600,
46
+ description="Hard timeout per task. On expiry the session is "
47
+ "terminate_then_kill'd and a diagnostic dump is "
48
+ "written to ~/.claude-machina/logs/.",
49
+ )
50
+ system_prompt: Optional[str] = Field(
51
+ default=None,
52
+ json_schema_extra={"rows": 3},
53
+ )
54
+
55
+ # `extra="forbid"` surfaces typo'd task fields as Pydantic
56
+ # ValidationError at the spec boundary instead of silently dropping
57
+ # them and confusing downstream consumers.
58
+ model_config = ConfigDict(extra="forbid")
59
+
60
+
61
+ class ClaudeTaskSpec(BaseAICliTaskSpec):
62
+ """Claude Code CLI task. Full feature set: sessions, resume, budget,
63
+ turns, allowed_tools, permission_mode."""
64
+ provider: Literal["claude"] = "claude"
65
+ session_id: Optional[str] = Field(
66
+ default=None,
67
+ description="Start a named session. Pair with `resume_session_id` "
68
+ "to chain conversations.",
69
+ )
70
+ resume_session_id: Optional[str] = Field(
71
+ default=None,
72
+ description="Resume from a prior session_id (returned in a previous "
73
+ "task's `result` event).",
74
+ )
75
+ max_turns: Optional[int] = Field(
76
+ default=None, ge=1,
77
+ description="Per-task turn cap. Defaults to provider config.",
78
+ )
79
+ max_budget_usd: Optional[float] = Field(
80
+ default=None, ge=0,
81
+ description="Per-task USD budget. Defaults to provider config.",
82
+ )
83
+ allowed_tools: Optional[str] = Field(
84
+ default=None,
85
+ description="Comma-separated tool list. Defaults to "
86
+ "Read,Edit,Bash,Glob,Grep,Write.",
87
+ )
88
+ permission_mode: Literal["default", "acceptEdits", "plan", "auto", "dontAsk", "bypassPermissions"] = "acceptEdits"
89
+
90
+ # ---- optional documented CLI flags (cli-reference) ----
91
+ effort: Optional[Literal["low", "medium", "high", "xhigh", "max"]] = Field(
92
+ default=None,
93
+ description="Reasoning-effort level. Available levels depend on the model.",
94
+ )
95
+ fallback_model: Optional[str] = Field(
96
+ default=None,
97
+ description="Fallback model when the primary is overloaded (print mode).",
98
+ )
99
+ add_dir: List[str] = Field(
100
+ default_factory=list,
101
+ description="Extra working directories the CLI may read/edit.",
102
+ )
103
+ disallowed_tools: Optional[str] = Field(
104
+ default=None,
105
+ description="Comma-separated tools removed from Claude's context.",
106
+ )
107
+ agent: Optional[str] = Field(
108
+ default=None,
109
+ description="Override the configured `agent` setting for this task.",
110
+ )
111
+
112
+
113
+ class CodexTaskSpec(BaseAICliTaskSpec):
114
+ """OpenAI Codex CLI task. Sandbox-first; no session/resume/budget/turns."""
115
+ provider: Literal["codex"] = "codex"
116
+ sandbox: Literal["read-only", "workspace-write", "danger-full-access"] = (
117
+ "workspace-write"
118
+ )
119
+ ask_for_approval: Literal["untrusted", "on-request", "never"] = "never"
120
+
121
+
122
+ class GeminiTaskSpec(BaseAICliTaskSpec):
123
+ """Google Gemini CLI task (v2 — stub provider in v1).
124
+
125
+ Schema lives in v1 so the discriminated union JSON Schema for the
126
+ LLM tool fast-path doesn't change when v2 lands.
127
+ """
128
+ provider: Literal["gemini"] = "gemini"
129
+ session_id: Optional[str] = None
130
+ resume: Optional[str] = Field(
131
+ default=None,
132
+ description='"latest" | "<index>" | "<UUID>"',
133
+ )
134
+ yolo: bool = False
135
+ sandbox: bool = False
136
+
137
+
138
+ AICliTaskSpec = Annotated[
139
+ Union[ClaudeTaskSpec, CodexTaskSpec, GeminiTaskSpec],
140
+ Field(discriminator="provider"),
141
+ ]
142
+
143
+
144
+ # ---------------------------------------------------------------------------
145
+ # Result models (Pydantic for serialisation; mirror dataclasses in protocol.py)
146
+ # ---------------------------------------------------------------------------
147
+
148
+ class CanonicalUsagePydantic(BaseModel):
149
+ """Pydantic mirror of `protocol.CanonicalUsage` for output serialisation."""
150
+ input_tokens: int = 0
151
+ output_tokens: int = 0
152
+ cache_read: int = 0
153
+ cache_write: int = 0
154
+ reasoning_tokens: int = 0
155
+ request_count: int = 0
156
+
157
+
158
+ class SessionResultModel(BaseModel):
159
+ """Per-task result, JSON-serialisable."""
160
+ task_id: str
161
+ session_id: Optional[str] = None
162
+ provider: str = ""
163
+ prompt: str = ""
164
+ branch: Optional[str] = None
165
+ worktree_path: Optional[str] = None
166
+ response: str = ""
167
+ cost_usd: Optional[float] = None
168
+ duration_ms: Optional[int] = None
169
+ num_turns: Optional[int] = None
170
+ tool_calls: int = 0
171
+ canonical_usage: CanonicalUsagePydantic = Field(
172
+ default_factory=CanonicalUsagePydantic,
173
+ )
174
+ provider_data: Dict[str, Any] = Field(default_factory=dict)
175
+ success: bool = False
176
+ error: Optional[str] = None
177
+
178
+
179
+ class BatchSummary(BaseModel):
180
+ """Aggregated batch summary."""
181
+ n_tasks: int = 0
182
+ n_succeeded: int = 0
183
+ n_failed: int = 0
184
+ total_cost_usd: Optional[float] = None
185
+ wall_clock_ms: int = 0
186
+ budget_remaining_usd: Optional[float] = None
187
+
188
+
189
+ class BatchResultModel(BaseModel):
190
+ """Top-level batch result returned by `run_batch()`."""
191
+ tasks: List[SessionResultModel] = Field(default_factory=list)
192
+ summary: BatchSummary = Field(default_factory=BatchSummary)
193
+ provider: str = ""
194
+ timestamp: str = ""
195
+
196
+
197
+ # ---------------------------------------------------------------------------
198
+ # Helpers
199
+ # ---------------------------------------------------------------------------
200
+
201
+ def session_result_to_model(sr: Any) -> SessionResultModel:
202
+ """Convert a `protocol.SessionResult` dataclass to its Pydantic mirror."""
203
+ cu = CanonicalUsagePydantic(
204
+ input_tokens=sr.canonical_usage.input_tokens,
205
+ output_tokens=sr.canonical_usage.output_tokens,
206
+ cache_read=sr.canonical_usage.cache_read,
207
+ cache_write=sr.canonical_usage.cache_write,
208
+ reasoning_tokens=sr.canonical_usage.reasoning_tokens,
209
+ request_count=sr.canonical_usage.request_count,
210
+ )
211
+ return SessionResultModel(
212
+ task_id=sr.task_id,
213
+ session_id=sr.session_id,
214
+ provider=sr.provider,
215
+ prompt=sr.prompt,
216
+ branch=sr.branch,
217
+ worktree_path=sr.worktree_path,
218
+ response=sr.response,
219
+ cost_usd=sr.cost_usd,
220
+ duration_ms=sr.duration_ms,
221
+ num_turns=sr.num_turns,
222
+ tool_calls=sr.tool_calls,
223
+ canonical_usage=cu,
224
+ provider_data=sr.provider_data,
225
+ success=sr.success,
226
+ error=sr.error,
227
+ )
@@ -0,0 +1,233 @@
1
+ """Per-batch workflow-tool bridge for the FastMCP server.
2
+
3
+ When an agent batch wires nodes through ``input-tools``, each connected
4
+ node is exposed on the FastMCP server as its own
5
+ ``mcp__machinaos__<node_type>`` entry. The spawned ``claude -p`` sees
6
+ those tools on the very first ``tools/list`` and can invoke them
7
+ directly — no two-step generic-wrapper indirection.
8
+
9
+ Schema generation is delegated to FastMCP: we build a function whose
10
+ ``inspect.signature`` mirrors the plugin's Pydantic ``Params`` field-
11
+ for-field, so FastMCP advertises a flat ``inputSchema`` matching the
12
+ plugin Params. Per-batch scoping is enforced inside the handler via
13
+ ``_require_batch()`` so concurrent batches sharing the same tool name
14
+ are isolated; refcounts (``add_tool`` on first wire, ``remove_tool`` on
15
+ last unwire) keep the FastMCP registry tidy.
16
+
17
+ Public API:
18
+ - :func:`expose_workflow_tools(connected_tools)` — call from
19
+ ``mcp_server.register_batch``
20
+ - :func:`unexpose_workflow_tools(connected_tools)` — call from
21
+ ``mcp_server.unregister_batch``
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ import asyncio
27
+ import inspect
28
+ from typing import Any, Dict, List, Optional
29
+
30
+ from core.logging import get_logger
31
+
32
+ logger = get_logger(__name__)
33
+
34
+
35
+ # node_type -> count of active batches that wired it. Tools are added
36
+ # to FastMCP on first wire, removed on last unwire — per-handler scope
37
+ # checks ``_require_batch`` against the calling batch's connected_tools.
38
+ _active_tool_refcounts: Dict[str, int] = {}
39
+
40
+
41
+ def expose_workflow_tools(connected_tools: List[Dict[str, Any]]) -> None:
42
+ """Add one MCP tool per connected workflow-tool node."""
43
+ mcp = _get_mcp()
44
+ if mcp is None or not connected_tools:
45
+ return
46
+ from services.node_registry import get_node_class
47
+
48
+ for entry in connected_tools:
49
+ node_type = entry.get("node_type")
50
+ if not node_type:
51
+ continue
52
+ prev = _active_tool_refcounts.get(node_type, 0)
53
+ _active_tool_refcounts[node_type] = prev + 1
54
+ if prev > 0:
55
+ continue # already exposed by another concurrent batch
56
+ cls = get_node_class(node_type)
57
+ if cls is None or getattr(cls, "Params", None) is None:
58
+ logger.warning(
59
+ "[CC-Agent MCP] cannot expose %s: class or Params missing",
60
+ node_type,
61
+ )
62
+ continue
63
+ try:
64
+ handler = _build_handler(node_type, cls.Params)
65
+ mcp.add_tool(
66
+ handler, name=node_type,
67
+ description=(getattr(cls, "description", None)
68
+ or f"MachinaOs workflow tool: {node_type}"),
69
+ )
70
+ logger.info("[CC-Agent MCP] exposed mcp__machinaos__%s", node_type)
71
+ except Exception as exc: # pragma: no cover
72
+ logger.warning("[CC-Agent MCP] add_tool(%s) failed: %s", node_type, exc)
73
+ _schedule_list_changed_notify()
74
+
75
+
76
+ def unexpose_workflow_tools(connected_tools: List[Dict[str, Any]]) -> None:
77
+ """Decrement refcount; remove the MCP tool when no batch references it."""
78
+ mcp = _get_mcp()
79
+ if mcp is None:
80
+ return
81
+ for entry in connected_tools:
82
+ node_type = entry.get("node_type")
83
+ if not node_type:
84
+ continue
85
+ remaining = _active_tool_refcounts.get(node_type, 0) - 1
86
+ if remaining > 0:
87
+ _active_tool_refcounts[node_type] = remaining
88
+ continue
89
+ _active_tool_refcounts.pop(node_type, None)
90
+ try:
91
+ mcp.remove_tool(node_type)
92
+ logger.info("[CC-Agent MCP] removed mcp__machinaos__%s", node_type)
93
+ except Exception as exc: # pragma: no cover
94
+ logger.debug("[CC-Agent MCP] remove_tool(%s): %s", node_type, exc)
95
+ _schedule_list_changed_notify()
96
+
97
+
98
+ # ---------------------------------------------------------------------------
99
+ # Internals
100
+ # ---------------------------------------------------------------------------
101
+
102
+ def _get_mcp() -> Optional[Any]:
103
+ """Late import to avoid a circular import with ``mcp_server``."""
104
+ from services.cli_agent import mcp_server
105
+ return mcp_server._mcp_singleton
106
+
107
+
108
+ def _schedule_list_changed_notify() -> None:
109
+ """Fire-and-forget ``notifications/tools/list_changed`` to the
110
+ connected MCP client.
111
+
112
+ FastMCP does NOT emit this automatically on ``add_tool`` /
113
+ ``remove_tool`` (verified at
114
+ ``mcp/server/fastmcp/tools/tool_manager.py`` — both methods only
115
+ mutate the ``_tools`` dict, with no notification dispatch). Without
116
+ this manual notify, tools registered after the agent's first
117
+ ``tools/list`` request stay invisible until reconnect.
118
+
119
+ Best-effort: requires a running asyncio loop (always true in the
120
+ ``service.run_batch`` call path). Failures log at WARN and don't
121
+ abort the batch.
122
+ """
123
+ mcp = _get_mcp()
124
+ if mcp is None:
125
+ return
126
+ try:
127
+ loop = asyncio.get_running_loop()
128
+ except RuntimeError:
129
+ return # no running loop — sync test path
130
+
131
+ async def _do_notify() -> None:
132
+ try:
133
+ session = (
134
+ getattr(mcp, "session", None)
135
+ or getattr(getattr(mcp, "_mcp_server", None), "session", None)
136
+ )
137
+ if session is not None and hasattr(session, "send_tool_list_changed"):
138
+ await session.send_tool_list_changed()
139
+ except Exception as exc:
140
+ logger.warning(
141
+ "[CC-Agent workflow_tools] tools/list_changed notify failed: %s",
142
+ exc,
143
+ )
144
+
145
+ loop.create_task(_do_notify())
146
+
147
+
148
+ def _build_handler(node_type: str, params_cls: type):
149
+ """Build an async handler whose ``inspect.signature`` mirrors the
150
+ plugin Params field-for-field. FastMCP iterates that signature to
151
+ derive the ``inputSchema``; flat fields → flat MCP arguments.
152
+ """
153
+ from pydantic_core import PydanticUndefined
154
+
155
+ fields = getattr(params_cls, "model_fields", {}) or {}
156
+ parameters: List[inspect.Parameter] = []
157
+ annotations: Dict[str, Any] = {"return": Dict[str, Any]}
158
+ for fname, finfo in fields.items():
159
+ annotations[fname] = finfo.annotation
160
+ if finfo.is_required():
161
+ default: Any = inspect.Parameter.empty
162
+ elif finfo.default_factory is not None: # type: ignore[truthy-function]
163
+ try:
164
+ default = finfo.default_factory() # materialize once for the signature
165
+ except Exception:
166
+ default = None
167
+ elif finfo.default is PydanticUndefined:
168
+ default = None
169
+ else:
170
+ default = finfo.default
171
+ parameters.append(inspect.Parameter(
172
+ fname, inspect.Parameter.KEYWORD_ONLY,
173
+ annotation=finfo.annotation, default=default,
174
+ ))
175
+
176
+ async def _handler(**kwargs: Any) -> Dict[str, Any]:
177
+ from services.cli_agent.mcp_server import _require_batch
178
+ ctx = _require_batch()
179
+ entry = next(
180
+ (t for t in ctx.connected_tools if t.get("node_type") == node_type),
181
+ None,
182
+ )
183
+ if entry is None:
184
+ return {
185
+ "error": f"tool {node_type!r} not connected to this batch",
186
+ "status": 403,
187
+ }
188
+ # Validate via the plugin's own Params model, then dump back to
189
+ # a plain dict for execute_tool. `exclude_unset=True` drops
190
+ # defaults the agent didn't supply.
191
+ try:
192
+ validated = params_cls(**kwargs)
193
+ args = validated.model_dump(exclude_unset=True)
194
+ except Exception:
195
+ args = dict(kwargs)
196
+ logger.info(
197
+ "[CC-Agent MCP %s] node=%s wf=%s args_keys=%s",
198
+ node_type, ctx.node_id, ctx.workflow_id, list(args.keys()),
199
+ )
200
+ from services.handlers.tools import execute_tool
201
+ config: Dict[str, Any] = {
202
+ "node_type": node_type,
203
+ "node_id": entry.get("node_id"),
204
+ "workflow_id": ctx.workflow_id,
205
+ "label": entry.get("label") or node_type,
206
+ "parameters": dict(entry.get("parameters") or {}),
207
+ }
208
+ result = await execute_tool(node_type, args, config)
209
+ if not isinstance(result, dict):
210
+ result = {"result": result}
211
+ if "error" in result:
212
+ logger.warning(
213
+ "[CC-Agent MCP %s] node=%s ERROR: %s",
214
+ node_type, entry.get("node_id"), result.get("error"),
215
+ )
216
+ else:
217
+ logger.info(
218
+ "[CC-Agent MCP %s] node=%s OK (result_keys=%s)",
219
+ node_type, entry.get("node_id"), list(result.keys())[:8],
220
+ )
221
+ return result
222
+
223
+ _handler.__name__ = node_type
224
+ _handler.__annotations__ = annotations
225
+ _handler.__signature__ = inspect.Signature( # type: ignore[attr-defined]
226
+ parameters, return_annotation=Dict[str, Any],
227
+ )
228
+ return _handler
229
+
230
+
231
+ def _reset_for_tests() -> None: # pragma: no cover
232
+ """Wipe the refcount registry. ONLY use in tests."""
233
+ _active_tool_refcounts.clear()
@@ -44,6 +44,10 @@ class CredentialRegistry:
44
44
  self._raw: Optional[Dict[str, Any]] = None
45
45
  self._resolved_providers: Optional[Dict[str, Dict[str, Any]]] = None
46
46
  self._version: Optional[str] = None
47
+ # Bumped on every credential mutation; folded into the version
48
+ # hash so the conditional fetch returns fresh ``stored`` flags.
49
+ # See ``get_version()`` + ``invalidate_version()``.
50
+ self._mutation_seq: int = 0
47
51
 
48
52
  @classmethod
49
53
  def get_instance(cls) -> "CredentialRegistry":
@@ -162,21 +166,42 @@ class CredentialRegistry:
162
166
  return out
163
167
 
164
168
  def get_version(self) -> str:
165
- """Content-sha256 of the resolved catalogue (providers + categories).
169
+ """Content-sha256 of the resolved catalogue (providers + categories +
170
+ mutation counter).
166
171
 
167
172
  Used by clients for warm-start cache invalidation: when the hash
168
173
  changes, the client fetches a fresh catalogue; otherwise it serves
169
174
  from IndexedDB with zero network traffic.
175
+
176
+ The mutation counter is bumped by ``invalidate_version()`` on every
177
+ credential save / delete / oauth-disconnect — this is what makes
178
+ the conditional fetch ("`since: <prior version>`") actually return
179
+ fresh data after a mutation. Without it the hash would only depend
180
+ on the static catalogue JSON, the version would be constant for
181
+ the life of the process, and the conditional fetch would always
182
+ return ``{unchanged: true}`` even after a key was deleted — leaving
183
+ the per-provider ``stored`` flag stuck at ``true`` on every client.
170
184
  """
171
185
  if self._version is None:
172
186
  payload = {
173
187
  "providers": self.get_all_providers(),
174
188
  "categories": self.get_categories(),
189
+ "mutation_seq": self._mutation_seq,
175
190
  }
176
191
  encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
177
192
  self._version = hashlib.sha256(encoded).hexdigest()
178
193
  return self._version
179
194
 
195
+ def invalidate_version(self) -> None:
196
+ """Bump the mutation counter so the next ``get_version()`` returns a
197
+ new hash. Call this from every credential mutation path (store /
198
+ remove / oauth-disconnect) so the frontend's conditional fetch
199
+ actually returns fresh ``stored`` flags. Cheap — just a counter
200
+ increment + clearing the cached hash.
201
+ """
202
+ self._mutation_seq += 1
203
+ self._version = None
204
+
180
205
  def get_catalogue(self) -> Dict[str, Any]:
181
206
  """Full payload returned by the `get_credential_catalogue` WebSocket handler."""
182
207
  return {