machinaos 0.0.1 → 0.0.7
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.
- package/.env.template +71 -71
- package/LICENSE +21 -21
- package/README.md +163 -87
- package/bin/cli.js +62 -106
- package/client/.dockerignore +45 -45
- package/client/Dockerfile +68 -68
- package/client/dist/assets/index-DFSC53FP.css +1 -0
- package/client/dist/assets/index-fJ-1gTf5.js +613 -0
- package/client/dist/index.html +14 -0
- package/client/eslint.config.js +34 -16
- package/client/nginx.conf +66 -66
- package/client/package.json +61 -48
- package/client/src/App.tsx +27 -27
- package/client/src/Dashboard.tsx +1200 -1172
- package/client/src/ParameterPanel.tsx +302 -300
- package/client/src/components/AIAgentNode.tsx +315 -321
- package/client/src/components/APIKeyValidator.tsx +117 -117
- package/client/src/components/ClaudeChatModelNode.tsx +17 -17
- package/client/src/components/CredentialsModal.tsx +1200 -306
- package/client/src/components/GeminiChatModelNode.tsx +17 -17
- package/client/src/components/GenericNode.tsx +356 -356
- package/client/src/components/LocationParameterPanel.tsx +153 -153
- package/client/src/components/ModelNode.tsx +285 -285
- package/client/src/components/OpenAIChatModelNode.tsx +17 -17
- package/client/src/components/OutputPanel.tsx +470 -470
- package/client/src/components/ParameterRenderer.tsx +1873 -1873
- package/client/src/components/SkillEditorModal.tsx +3 -3
- package/client/src/components/SquareNode.tsx +812 -796
- package/client/src/components/ToolkitNode.tsx +365 -365
- package/client/src/components/auth/LoginPage.tsx +247 -247
- package/client/src/components/auth/ProtectedRoute.tsx +59 -59
- package/client/src/components/base/BaseChatModelNode.tsx +270 -270
- package/client/src/components/icons/AIProviderIcons.tsx +50 -50
- package/client/src/components/maps/GoogleMapsPicker.tsx +136 -136
- package/client/src/components/maps/MapsPreviewPanel.tsx +109 -109
- package/client/src/components/maps/index.ts +25 -25
- package/client/src/components/parameterPanel/InputSection.tsx +1094 -1094
- package/client/src/components/parameterPanel/LocationPanelLayout.tsx +64 -64
- package/client/src/components/parameterPanel/MapsSection.tsx +91 -91
- package/client/src/components/parameterPanel/MiddleSection.tsx +867 -571
- package/client/src/components/parameterPanel/OutputSection.tsx +80 -80
- package/client/src/components/parameterPanel/ParameterPanelLayout.tsx +81 -81
- package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +436 -436
- package/client/src/components/parameterPanel/index.ts +41 -41
- package/client/src/components/shared/DataPanel.tsx +142 -142
- package/client/src/components/shared/JSONTreeRenderer.tsx +105 -105
- package/client/src/components/ui/AIResultModal.tsx +203 -203
- package/client/src/components/ui/ApiKeyInput.tsx +93 -0
- package/client/src/components/ui/CodeEditor.tsx +81 -81
- package/client/src/components/ui/CollapsibleSection.tsx +87 -87
- package/client/src/components/ui/ComponentItem.tsx +153 -153
- package/client/src/components/ui/ComponentPalette.tsx +320 -320
- package/client/src/components/ui/ConsolePanel.tsx +151 -43
- package/client/src/components/ui/ErrorBoundary.tsx +195 -195
- package/client/src/components/ui/InputNodesPanel.tsx +203 -203
- package/client/src/components/ui/MapSelector.tsx +313 -313
- package/client/src/components/ui/Modal.tsx +151 -148
- package/client/src/components/ui/NodeOutputPanel.tsx +1150 -1150
- package/client/src/components/ui/OutputDisplayPanel.tsx +381 -381
- package/client/src/components/ui/QRCodeDisplay.tsx +182 -0
- package/client/src/components/ui/TopToolbar.tsx +736 -736
- package/client/src/components/ui/WorkflowSidebar.tsx +293 -293
- package/client/src/config/antdTheme.ts +186 -186
- package/client/src/contexts/AuthContext.tsx +221 -221
- package/client/src/contexts/ThemeContext.tsx +42 -42
- package/client/src/contexts/WebSocketContext.tsx +2144 -1971
- package/client/src/factories/baseChatModelFactory.ts +255 -255
- package/client/src/hooks/useAndroidOperations.ts +118 -164
- package/client/src/hooks/useApiKeyValidation.ts +106 -106
- package/client/src/hooks/useApiKeys.ts +238 -238
- package/client/src/hooks/useAppTheme.ts +17 -17
- package/client/src/hooks/useComponentPalette.ts +50 -50
- package/client/src/hooks/useDragAndDrop.ts +123 -123
- package/client/src/hooks/useDragVariable.ts +88 -88
- package/client/src/hooks/useExecution.ts +319 -313
- package/client/src/hooks/useParameterPanel.ts +176 -176
- package/client/src/hooks/useReactFlowNodes.ts +188 -188
- package/client/src/hooks/useToolSchema.ts +209 -209
- package/client/src/hooks/useWhatsApp.ts +196 -196
- package/client/src/hooks/useWorkflowManagement.ts +45 -45
- package/client/src/index.css +314 -314
- package/client/src/nodeDefinitions/aiAgentNodes.ts +335 -335
- package/client/src/nodeDefinitions/aiModelNodes.ts +340 -340
- package/client/src/nodeDefinitions/androidServiceNodes.ts +383 -383
- package/client/src/nodeDefinitions/chatNodes.ts +135 -135
- package/client/src/nodeDefinitions/codeNodes.ts +54 -54
- package/client/src/nodeDefinitions/index.ts +14 -14
- package/client/src/nodeDefinitions/locationNodes.ts +462 -462
- package/client/src/nodeDefinitions/schedulerNodes.ts +220 -220
- package/client/src/nodeDefinitions/skillNodes.ts +17 -5
- package/client/src/nodeDefinitions/utilityNodes.ts +284 -284
- package/client/src/nodeDefinitions/whatsappNodes.ts +821 -865
- package/client/src/nodeDefinitions.ts +101 -103
- package/client/src/services/dynamicParameterService.ts +95 -95
- package/client/src/services/execution/aiAgentExecutionService.ts +34 -34
- package/client/src/services/executionService.ts +227 -231
- package/client/src/services/workflowApi.ts +91 -91
- package/client/src/store/useAppStore.ts +578 -581
- package/client/src/styles/theme.ts +513 -508
- package/client/src/styles/zIndex.ts +16 -16
- package/client/src/types/ComponentTypes.ts +38 -38
- package/client/src/types/INodeProperties.ts +287 -287
- package/client/src/types/NodeTypes.ts +27 -27
- package/client/src/utils/formatters.ts +32 -32
- package/client/src/utils/googleMapsLoader.ts +139 -139
- package/client/src/utils/locationUtils.ts +84 -84
- package/client/src/utils/nodeUtils.ts +30 -30
- package/client/src/utils/workflow.ts +29 -29
- package/client/src/vite-env.d.ts +12 -12
- package/client/tailwind.config.js +59 -59
- package/client/tsconfig.json +25 -25
- package/client/vite.config.js +35 -35
- package/install.ps1 +308 -0
- package/install.sh +343 -0
- package/package.json +81 -70
- package/scripts/build.js +174 -51
- package/scripts/clean.js +40 -40
- package/scripts/start.js +234 -210
- package/scripts/stop.js +301 -325
- package/server/.dockerignore +44 -44
- package/server/Dockerfile +45 -45
- package/server/constants.py +244 -249
- package/server/core/cache.py +460 -460
- package/server/core/config.py +127 -127
- package/server/core/container.py +98 -98
- package/server/core/database.py +1296 -1210
- package/server/core/logging.py +313 -313
- package/server/main.py +288 -288
- package/server/middleware/__init__.py +5 -5
- package/server/middleware/auth.py +89 -89
- package/server/models/auth.py +52 -52
- package/server/models/cache.py +24 -24
- package/server/models/database.py +235 -210
- package/server/models/nodes.py +435 -455
- package/server/pyproject.toml +75 -72
- package/server/requirements.txt +83 -83
- package/server/routers/android.py +294 -294
- package/server/routers/auth.py +203 -203
- package/server/routers/database.py +150 -150
- package/server/routers/maps.py +141 -141
- package/server/routers/nodejs_compat.py +288 -288
- package/server/routers/webhook.py +90 -90
- package/server/routers/websocket.py +2239 -2127
- package/server/routers/whatsapp.py +761 -761
- package/server/routers/workflow.py +199 -199
- package/server/services/ai.py +2444 -2414
- package/server/services/android_service.py +588 -588
- package/server/services/auth.py +130 -130
- package/server/services/chat_client.py +160 -160
- package/server/services/deployment/manager.py +706 -706
- package/server/services/event_waiter.py +675 -785
- package/server/services/execution/executor.py +1351 -1351
- package/server/services/execution/models.py +1 -1
- package/server/services/handlers/__init__.py +122 -126
- package/server/services/handlers/ai.py +390 -355
- package/server/services/handlers/android.py +69 -260
- package/server/services/handlers/code.py +278 -278
- package/server/services/handlers/http.py +193 -193
- package/server/services/handlers/tools.py +146 -32
- package/server/services/handlers/triggers.py +107 -107
- package/server/services/handlers/utility.py +822 -822
- package/server/services/handlers/whatsapp.py +423 -476
- package/server/services/maps.py +288 -288
- package/server/services/memory_store.py +103 -103
- package/server/services/node_executor.py +372 -375
- package/server/services/scheduler.py +155 -155
- package/server/services/skill_loader.py +1 -1
- package/server/services/status_broadcaster.py +834 -826
- package/server/services/temporal/__init__.py +23 -23
- package/server/services/temporal/activities.py +344 -344
- package/server/services/temporal/client.py +76 -76
- package/server/services/temporal/executor.py +147 -147
- package/server/services/temporal/worker.py +251 -251
- package/server/services/temporal/workflow.py +355 -355
- package/server/services/temporal/ws_client.py +236 -236
- package/server/services/text.py +110 -110
- package/server/services/user_auth.py +172 -172
- package/server/services/websocket_client.py +29 -29
- package/server/services/workflow.py +597 -597
- package/server/skills/android-skill/SKILL.md +4 -4
- package/server/skills/code-skill/SKILL.md +123 -89
- package/server/skills/maps-skill/SKILL.md +3 -3
- package/server/skills/memory-skill/SKILL.md +1 -1
- package/server/skills/web-search-skill/SKILL.md +154 -0
- package/server/skills/whatsapp-skill/SKILL.md +3 -3
- package/server/uv.lock +461 -100
- package/server/whatsapp-rpc/.dockerignore +30 -30
- package/server/whatsapp-rpc/Dockerfile +44 -44
- package/server/whatsapp-rpc/Dockerfile.web +17 -17
- package/server/whatsapp-rpc/README.md +139 -139
- package/server/whatsapp-rpc/bin/whatsapp-rpc-server +0 -0
- package/server/whatsapp-rpc/cli.js +95 -95
- package/server/whatsapp-rpc/configs/config.yaml +6 -6
- package/server/whatsapp-rpc/docker-compose.yml +35 -35
- package/server/whatsapp-rpc/docs/API.md +410 -410
- package/server/whatsapp-rpc/node_modules/.package-lock.json +259 -0
- package/server/whatsapp-rpc/node_modules/chalk/license +9 -0
- package/server/whatsapp-rpc/node_modules/chalk/package.json +83 -0
- package/server/whatsapp-rpc/node_modules/chalk/readme.md +297 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/index.d.ts +325 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/index.js +225 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/utilities.js +33 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/server/whatsapp-rpc/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/server/whatsapp-rpc/node_modules/commander/LICENSE +22 -0
- package/server/whatsapp-rpc/node_modules/commander/Readme.md +1148 -0
- package/server/whatsapp-rpc/node_modules/commander/esm.mjs +16 -0
- package/server/whatsapp-rpc/node_modules/commander/index.js +26 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/argument.js +145 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/command.js +2179 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/error.js +43 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/help.js +462 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/option.js +329 -0
- package/server/whatsapp-rpc/node_modules/commander/lib/suggestSimilar.js +100 -0
- package/server/whatsapp-rpc/node_modules/commander/package-support.json +16 -0
- package/server/whatsapp-rpc/node_modules/commander/package.json +80 -0
- package/server/whatsapp-rpc/node_modules/commander/typings/esm.d.mts +3 -0
- package/server/whatsapp-rpc/node_modules/commander/typings/index.d.ts +884 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/README.md +89 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/index.js +39 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/enoent.js +59 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/parse.js +91 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/util/escape.js +47 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/util/readShebang.js +23 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/lib/util/resolveCommand.js +52 -0
- package/server/whatsapp-rpc/node_modules/cross-spawn/package.json +73 -0
- package/server/whatsapp-rpc/node_modules/execa/index.d.ts +955 -0
- package/server/whatsapp-rpc/node_modules/execa/index.js +309 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/command.js +119 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/error.js +87 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/kill.js +102 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/pipe.js +42 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/promise.js +36 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/stdio.js +49 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/stream.js +133 -0
- package/server/whatsapp-rpc/node_modules/execa/lib/verbose.js +19 -0
- package/server/whatsapp-rpc/node_modules/execa/license +9 -0
- package/server/whatsapp-rpc/node_modules/execa/package.json +90 -0
- package/server/whatsapp-rpc/node_modules/execa/readme.md +822 -0
- package/server/whatsapp-rpc/node_modules/get-stream/license +9 -0
- package/server/whatsapp-rpc/node_modules/get-stream/package.json +53 -0
- package/server/whatsapp-rpc/node_modules/get-stream/readme.md +291 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/array-buffer.js +84 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/array.js +32 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/buffer.js +20 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/contents.js +101 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/index.d.ts +119 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/index.js +5 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/string.js +36 -0
- package/server/whatsapp-rpc/node_modules/get-stream/source/utils.js +11 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/README.md +95 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/index.js +97 -0
- package/server/whatsapp-rpc/node_modules/get-them-args/package.json +36 -0
- package/server/whatsapp-rpc/node_modules/human-signals/LICENSE +201 -0
- package/server/whatsapp-rpc/node_modules/human-signals/README.md +168 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/core.js +273 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/main.d.ts +73 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/main.js +70 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/realtime.js +16 -0
- package/server/whatsapp-rpc/node_modules/human-signals/build/src/signals.js +34 -0
- package/server/whatsapp-rpc/node_modules/human-signals/package.json +61 -0
- package/server/whatsapp-rpc/node_modules/is-stream/index.d.ts +81 -0
- package/server/whatsapp-rpc/node_modules/is-stream/index.js +29 -0
- package/server/whatsapp-rpc/node_modules/is-stream/license +9 -0
- package/server/whatsapp-rpc/node_modules/is-stream/package.json +44 -0
- package/server/whatsapp-rpc/node_modules/is-stream/readme.md +60 -0
- package/server/whatsapp-rpc/node_modules/isexe/LICENSE +15 -0
- package/server/whatsapp-rpc/node_modules/isexe/README.md +51 -0
- package/server/whatsapp-rpc/node_modules/isexe/index.js +57 -0
- package/server/whatsapp-rpc/node_modules/isexe/mode.js +41 -0
- package/server/whatsapp-rpc/node_modules/isexe/package.json +31 -0
- package/server/whatsapp-rpc/node_modules/isexe/test/basic.js +221 -0
- package/server/whatsapp-rpc/node_modules/isexe/windows.js +42 -0
- package/server/whatsapp-rpc/node_modules/kill-port/.editorconfig +12 -0
- package/server/whatsapp-rpc/node_modules/kill-port/.gitattributes +1 -0
- package/server/whatsapp-rpc/node_modules/kill-port/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/kill-port/README.md +140 -0
- package/server/whatsapp-rpc/node_modules/kill-port/cli.js +25 -0
- package/server/whatsapp-rpc/node_modules/kill-port/example.js +21 -0
- package/server/whatsapp-rpc/node_modules/kill-port/index.js +46 -0
- package/server/whatsapp-rpc/node_modules/kill-port/logo.png +0 -0
- package/server/whatsapp-rpc/node_modules/kill-port/package.json +41 -0
- package/server/whatsapp-rpc/node_modules/kill-port/pnpm-lock.yaml +4606 -0
- package/server/whatsapp-rpc/node_modules/kill-port/test.js +16 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/README.md +78 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/index.js +41 -0
- package/server/whatsapp-rpc/node_modules/merge-stream/package.json +19 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/index.d.ts +52 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/index.js +71 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/license +9 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/package.json +45 -0
- package/server/whatsapp-rpc/node_modules/mimic-fn/readme.md +90 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/index.d.ts +90 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/index.js +52 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/license +9 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/index.d.ts +31 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/index.js +12 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/license +9 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/package.json +41 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/node_modules/path-key/readme.md +57 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/package.json +49 -0
- package/server/whatsapp-rpc/node_modules/npm-run-path/readme.md +104 -0
- package/server/whatsapp-rpc/node_modules/onetime/index.d.ts +59 -0
- package/server/whatsapp-rpc/node_modules/onetime/index.js +41 -0
- package/server/whatsapp-rpc/node_modules/onetime/license +9 -0
- package/server/whatsapp-rpc/node_modules/onetime/package.json +45 -0
- package/server/whatsapp-rpc/node_modules/onetime/readme.md +94 -0
- package/server/whatsapp-rpc/node_modules/path-key/index.d.ts +40 -0
- package/server/whatsapp-rpc/node_modules/path-key/index.js +16 -0
- package/server/whatsapp-rpc/node_modules/path-key/license +9 -0
- package/server/whatsapp-rpc/node_modules/path-key/package.json +39 -0
- package/server/whatsapp-rpc/node_modules/path-key/readme.md +61 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/index.js +19 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/license +9 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/package.json +34 -0
- package/server/whatsapp-rpc/node_modules/shebang-command/readme.md +34 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/index.d.ts +22 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/index.js +2 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/license +9 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/package.json +35 -0
- package/server/whatsapp-rpc/node_modules/shebang-regex/readme.md +33 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/LICENSE +21 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/README.md +60 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/index.js +47 -0
- package/server/whatsapp-rpc/node_modules/shell-exec/package.json +29 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/LICENSE.txt +16 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/README.md +74 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.d.ts +12 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.js +10 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/browser.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.d.ts +48 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.js +279 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/index.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/package.json +3 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.d.ts +29 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.js +42 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/cjs/signals.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.d.ts +12 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.js +4 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/browser.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.d.ts +48 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.js +275 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/index.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/package.json +3 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.d.ts +29 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.d.ts.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.js +39 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/dist/mjs/signals.js.map +1 -0
- package/server/whatsapp-rpc/node_modules/signal-exit/package.json +106 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/index.js +14 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/license +9 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/package.json +43 -0
- package/server/whatsapp-rpc/node_modules/strip-final-newline/readme.md +35 -0
- package/server/whatsapp-rpc/node_modules/which/CHANGELOG.md +166 -0
- package/server/whatsapp-rpc/node_modules/which/LICENSE +15 -0
- package/server/whatsapp-rpc/node_modules/which/README.md +54 -0
- package/server/whatsapp-rpc/node_modules/which/bin/node-which +52 -0
- package/server/whatsapp-rpc/node_modules/which/package.json +43 -0
- package/server/whatsapp-rpc/node_modules/which/which.js +125 -0
- package/server/whatsapp-rpc/package-lock.json +272 -0
- package/server/whatsapp-rpc/package.json +30 -30
- package/server/whatsapp-rpc/schema.json +1294 -1294
- package/server/whatsapp-rpc/scripts/clean.cjs +66 -66
- package/server/whatsapp-rpc/scripts/cli.js +162 -162
- package/server/whatsapp-rpc/src/go/whatsapp/history.go +166 -166
- package/server/whatsapp-rpc/src/python/pyproject.toml +15 -15
- package/server/whatsapp-rpc/src/python/whatsapp_rpc/__init__.py +4 -4
- package/server/whatsapp-rpc/src/python/whatsapp_rpc/client.py +427 -427
- package/server/whatsapp-rpc/web/app.py +609 -609
- package/server/whatsapp-rpc/web/requirements.txt +6 -6
- package/server/whatsapp-rpc/web/rpc_client.py +427 -427
- package/server/whatsapp-rpc/web/static/openapi.yaml +59 -59
- package/server/whatsapp-rpc/web/templates/base.html +149 -149
- package/server/whatsapp-rpc/web/templates/contacts.html +240 -240
- package/server/whatsapp-rpc/web/templates/dashboard.html +319 -319
- package/server/whatsapp-rpc/web/templates/groups.html +328 -328
- package/server/whatsapp-rpc/web/templates/messages.html +465 -465
- package/server/whatsapp-rpc/web/templates/messaging.html +680 -680
- package/server/whatsapp-rpc/web/templates/send.html +258 -258
- package/server/whatsapp-rpc/web/templates/settings.html +459 -459
- package/client/src/components/ui/AndroidSettingsPanel.tsx +0 -401
- package/client/src/components/ui/WhatsAppSettingsPanel.tsx +0 -345
- package/client/src/nodeDefinitions/androidDeviceNodes.ts +0 -140
- package/docker-compose.prod.yml +0 -107
- package/docker-compose.yml +0 -104
- package/docs-MachinaOs/README.md +0 -85
- package/docs-MachinaOs/deployment/docker.mdx +0 -228
- package/docs-MachinaOs/deployment/production.mdx +0 -345
- package/docs-MachinaOs/docs.json +0 -75
- package/docs-MachinaOs/faq.mdx +0 -309
- package/docs-MachinaOs/favicon.svg +0 -5
- package/docs-MachinaOs/installation.mdx +0 -160
- package/docs-MachinaOs/introduction.mdx +0 -114
- package/docs-MachinaOs/logo/dark.svg +0 -6
- package/docs-MachinaOs/logo/light.svg +0 -6
- package/docs-MachinaOs/nodes/ai-agent.mdx +0 -216
- package/docs-MachinaOs/nodes/ai-models.mdx +0 -240
- package/docs-MachinaOs/nodes/android.mdx +0 -411
- package/docs-MachinaOs/nodes/overview.mdx +0 -181
- package/docs-MachinaOs/nodes/schedulers.mdx +0 -316
- package/docs-MachinaOs/nodes/webhooks.mdx +0 -330
- package/docs-MachinaOs/nodes/whatsapp.mdx +0 -305
- package/docs-MachinaOs/quickstart.mdx +0 -119
- package/docs-MachinaOs/tutorials/ai-agent-workflow.mdx +0 -177
- package/docs-MachinaOs/tutorials/android-automation.mdx +0 -242
- package/docs-MachinaOs/tutorials/first-workflow.mdx +0 -134
- package/docs-MachinaOs/tutorials/whatsapp-automation.mdx +0 -185
- package/nul +0 -0
- package/scripts/check-ports.ps1 +0 -33
- package/scripts/kill-port.ps1 +0 -154
|
@@ -1,355 +1,355 @@
|
|
|
1
|
-
"""Temporal workflow - Pure orchestrator for distributed node execution.
|
|
2
|
-
|
|
3
|
-
The workflow ONLY orchestrates:
|
|
4
|
-
- Parses graph structure
|
|
5
|
-
- Filters config nodes (tools, memory, services)
|
|
6
|
-
- Determines execution order based on dependencies
|
|
7
|
-
- Schedules node activities (can run on ANY worker)
|
|
8
|
-
- Collects results and routes outputs to dependent nodes
|
|
9
|
-
|
|
10
|
-
NO business logic in workflow - all execution happens in activities.
|
|
11
|
-
This enables massive horizontal scaling and multi-tenant distribution.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from datetime import timedelta
|
|
15
|
-
from typing import Any, Dict, List, Set
|
|
16
|
-
|
|
17
|
-
from temporalio import workflow
|
|
18
|
-
from temporalio.common import RetryPolicy
|
|
19
|
-
|
|
20
|
-
# Config handles - nodes connecting via these are config nodes (not executed)
|
|
21
|
-
# AI Agent handles: input-memory, input-tools, input-model
|
|
22
|
-
#
|
|
23
|
-
CONFIG_HANDLES = {"input-tools", "input-memory", "input-model", "input-skill"}
|
|
24
|
-
|
|
25
|
-
# Android service types (connect to androidTool, not executed directly)
|
|
26
|
-
ANDROID_SERVICE_TYPES = {
|
|
27
|
-
"batteryMonitor", "locationService", "deviceState",
|
|
28
|
-
"systemInfo", "appList", "appLauncher",
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
# Skill node types (connect to
|
|
32
|
-
SKILL_NODE_TYPES = {
|
|
33
|
-
"assistantPersonality", "whatsappSkill", "memorySkill", "mapsSkill",
|
|
34
|
-
"httpSkill", "schedulerSkill", "androidSkill", "codeSkill", "customSkill",
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@workflow.defn(sandboxed=False)
|
|
38
|
-
class MachinaWorkflow:
|
|
39
|
-
"""Distributed workflow orchestrator.
|
|
40
|
-
|
|
41
|
-
This workflow ONLY orchestrates - all execution happens in activities
|
|
42
|
-
that can run on any worker in the cluster.
|
|
43
|
-
|
|
44
|
-
Features:
|
|
45
|
-
- Continuous scheduling (FIRST_COMPLETED pattern)
|
|
46
|
-
- Per-node retry policies
|
|
47
|
-
- Config node filtering (tools, memory, services)
|
|
48
|
-
- Multi-tenant support via tenant_id in context
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
@workflow.run
|
|
52
|
-
async def run(self, workflow_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
53
|
-
print("[Workflow] ========== RUN METHOD CALLED ==========")
|
|
54
|
-
"""Execute workflow by orchestrating node activities.
|
|
55
|
-
|
|
56
|
-
Args:
|
|
57
|
-
workflow_data: Dict containing:
|
|
58
|
-
- nodes: List of node definitions from React Flow
|
|
59
|
-
- edges: List of edge definitions from React Flow
|
|
60
|
-
- session_id: Session identifier
|
|
61
|
-
- workflow_id: Workflow ID for tracking
|
|
62
|
-
- tenant_id: Tenant identifier for multi-tenancy
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
Dict with success, outputs, execution_trace, and errors
|
|
66
|
-
"""
|
|
67
|
-
nodes = workflow_data.get("nodes", [])
|
|
68
|
-
edges = workflow_data.get("edges", [])
|
|
69
|
-
session_id = workflow_data.get("session_id", "default")
|
|
70
|
-
workflow_id = workflow_data.get("workflow_id")
|
|
71
|
-
tenant_id = workflow_data.get("tenant_id")
|
|
72
|
-
|
|
73
|
-
workflow.logger.info(
|
|
74
|
-
f"Starting workflow orchestration: {len(nodes)} nodes, {len(edges)} edges"
|
|
75
|
-
)
|
|
76
|
-
# Debug print for console visibility
|
|
77
|
-
print(f"[Workflow] Starting: {len(nodes)} nodes, {len(edges)} edges")
|
|
78
|
-
|
|
79
|
-
if not nodes:
|
|
80
|
-
return {
|
|
81
|
-
"success": False,
|
|
82
|
-
"error": "No nodes provided",
|
|
83
|
-
"outputs": {},
|
|
84
|
-
"execution_trace": [],
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
# 1. Filter out config nodes (tools, memory, services)
|
|
88
|
-
exec_nodes, exec_edges = self._filter_executable_graph(nodes, edges)
|
|
89
|
-
|
|
90
|
-
workflow.logger.info(
|
|
91
|
-
f"After filtering: {len(exec_nodes)} executable nodes "
|
|
92
|
-
f"(filtered {len(nodes) - len(exec_nodes)} config nodes)"
|
|
93
|
-
)
|
|
94
|
-
print(f"[Workflow] Executable: {len(exec_nodes)}, Config filtered: {len(nodes) - len(exec_nodes)}")
|
|
95
|
-
|
|
96
|
-
# 2. Build dependency maps
|
|
97
|
-
deps, node_map = self._build_dependency_maps(exec_nodes, exec_edges)
|
|
98
|
-
|
|
99
|
-
# 3. Initialize state
|
|
100
|
-
outputs: Dict[str, Any] = {} # node_id -> result
|
|
101
|
-
completed: Set[str] = set()
|
|
102
|
-
running: Dict[str, Any] = {} # node_id -> activity handle
|
|
103
|
-
errors: List[Dict] = []
|
|
104
|
-
execution_trace: List[str] = []
|
|
105
|
-
|
|
106
|
-
# 4. Handle pre-executed triggers (already have their output)
|
|
107
|
-
pre_executed_count = 0
|
|
108
|
-
for node in exec_nodes:
|
|
109
|
-
if node.get("_pre_executed"):
|
|
110
|
-
node_id = node["id"]
|
|
111
|
-
outputs[node_id] = {
|
|
112
|
-
"success": True,
|
|
113
|
-
"result": node.get("_trigger_output", {}),
|
|
114
|
-
"pre_executed": True,
|
|
115
|
-
}
|
|
116
|
-
completed.add(node_id)
|
|
117
|
-
execution_trace.append(node_id)
|
|
118
|
-
pre_executed_count += 1
|
|
119
|
-
workflow.logger.info(f"Pre-executed trigger: {node_id}")
|
|
120
|
-
|
|
121
|
-
workflow.logger.info(f"Pre-executed: {pre_executed_count}, To execute: {len(node_map) - pre_executed_count}")
|
|
122
|
-
print(f"[Workflow] Pre-executed: {pre_executed_count}, To execute: {len(node_map) - pre_executed_count}")
|
|
123
|
-
|
|
124
|
-
# 5. Retry policy for node activities
|
|
125
|
-
retry_policy = RetryPolicy(
|
|
126
|
-
initial_interval=timedelta(seconds=1),
|
|
127
|
-
maximum_interval=timedelta(seconds=30),
|
|
128
|
-
maximum_attempts=3,
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
# 6. Continuous scheduling loop
|
|
132
|
-
loop_count = 0
|
|
133
|
-
while True:
|
|
134
|
-
loop_count += 1
|
|
135
|
-
# Find ready nodes (all deps completed, not running/completed)
|
|
136
|
-
ready = self._find_ready_nodes(deps, completed, running, node_map)
|
|
137
|
-
workflow.logger.info(f"Loop {loop_count}: ready={len(ready)}, running={len(running)}, completed={len(completed)}")
|
|
138
|
-
print(f"[Workflow] Loop {loop_count}: ready={len(ready)}, running={len(running)}, completed={len(completed)}")
|
|
139
|
-
|
|
140
|
-
# Start activities for ready nodes
|
|
141
|
-
for node_id in ready:
|
|
142
|
-
node = node_map[node_id]
|
|
143
|
-
|
|
144
|
-
# Build immutable context for this node
|
|
145
|
-
context = {
|
|
146
|
-
"node_id": node_id,
|
|
147
|
-
"node_type": node.get("type", "unknown"),
|
|
148
|
-
"node_data": node.get("data", {}),
|
|
149
|
-
"inputs": self._get_node_inputs(node_id, deps, outputs),
|
|
150
|
-
"workflow_id": workflow_id,
|
|
151
|
-
"tenant_id": tenant_id,
|
|
152
|
-
"session_id": session_id,
|
|
153
|
-
"nodes": nodes, # Full list for tool/memory detection
|
|
154
|
-
"edges": edges, # Full list for tool/memory detection
|
|
155
|
-
# Include pre-executed info if applicable
|
|
156
|
-
"pre_executed": node.get("_pre_executed", False),
|
|
157
|
-
"trigger_output": node.get("_trigger_output"),
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
# Schedule activity by name (for class-based activities)
|
|
161
|
-
# The activity is registered as NodeExecutionActivities.execute_node_activity
|
|
162
|
-
handle = workflow.start_activity(
|
|
163
|
-
"execute_node_activity",
|
|
164
|
-
args=[context],
|
|
165
|
-
start_to_close_timeout=timedelta(minutes=10),
|
|
166
|
-
heartbeat_timeout=timedelta(minutes=2),
|
|
167
|
-
retry_policy=retry_policy,
|
|
168
|
-
)
|
|
169
|
-
running[node_id] = handle
|
|
170
|
-
|
|
171
|
-
workflow.logger.info(f"Scheduled activity for node: {node_id}")
|
|
172
|
-
print(f"[Workflow] Scheduled: {node_id}")
|
|
173
|
-
|
|
174
|
-
# Exit if nothing running and nothing ready
|
|
175
|
-
if not running:
|
|
176
|
-
break
|
|
177
|
-
|
|
178
|
-
# Wait for ANY activity to complete (FIRST_COMPLETED pattern)
|
|
179
|
-
done_id, result = await self._wait_any_complete(running)
|
|
180
|
-
|
|
181
|
-
if result.get("success"):
|
|
182
|
-
outputs[done_id] = result
|
|
183
|
-
completed.add(done_id)
|
|
184
|
-
execution_trace.append(done_id)
|
|
185
|
-
workflow.logger.info(f"Node completed: {done_id}")
|
|
186
|
-
else:
|
|
187
|
-
# Node failed after all retries
|
|
188
|
-
error_info = {
|
|
189
|
-
"node_id": done_id,
|
|
190
|
-
"error": result.get("error", "Unknown error"),
|
|
191
|
-
}
|
|
192
|
-
errors.append(error_info)
|
|
193
|
-
workflow.logger.error(f"Node failed: {done_id} - {error_info['error']}")
|
|
194
|
-
|
|
195
|
-
# Stop workflow on failure
|
|
196
|
-
# TODO: Could add option to continue with partial results
|
|
197
|
-
break
|
|
198
|
-
|
|
199
|
-
# Build final result
|
|
200
|
-
success = len(errors) == 0 and len(completed) == len(node_map)
|
|
201
|
-
|
|
202
|
-
workflow.logger.info(
|
|
203
|
-
f"Workflow complete: success={success}, "
|
|
204
|
-
f"executed={len(execution_trace)}/{len(node_map)}"
|
|
205
|
-
)
|
|
206
|
-
print(f"[Workflow] Complete: success={success}, executed={len(execution_trace)}/{len(node_map)}")
|
|
207
|
-
|
|
208
|
-
return {
|
|
209
|
-
"success": success,
|
|
210
|
-
"outputs": outputs,
|
|
211
|
-
"execution_trace": execution_trace,
|
|
212
|
-
"errors": errors if errors else None,
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
def _get_node_inputs(
|
|
216
|
-
self,
|
|
217
|
-
node_id: str,
|
|
218
|
-
deps: Dict[str, Set[str]],
|
|
219
|
-
outputs: Dict[str, Any],
|
|
220
|
-
) -> Dict[str, Any]:
|
|
221
|
-
"""Get outputs from upstream nodes as inputs for this node."""
|
|
222
|
-
inputs = {}
|
|
223
|
-
for dep_id in deps.get(node_id, set()):
|
|
224
|
-
if dep_id in outputs:
|
|
225
|
-
inputs[dep_id] = outputs[dep_id].get("result", {})
|
|
226
|
-
return inputs
|
|
227
|
-
|
|
228
|
-
async def _wait_any_complete(self, running: Dict[str, Any]) -> tuple:
|
|
229
|
-
"""Wait for any activity to complete, return (node_id, result).
|
|
230
|
-
|
|
231
|
-
Uses Temporal's native wait mechanism for efficient polling.
|
|
232
|
-
"""
|
|
233
|
-
# Convert to list for iteration
|
|
234
|
-
items = list(running.items())
|
|
235
|
-
|
|
236
|
-
# Check if any already done
|
|
237
|
-
for node_id, handle in items:
|
|
238
|
-
if handle.done():
|
|
239
|
-
del running[node_id]
|
|
240
|
-
try:
|
|
241
|
-
result = await handle
|
|
242
|
-
return node_id, result
|
|
243
|
-
except Exception as e:
|
|
244
|
-
return node_id, {"success": False, "error": str(e)}
|
|
245
|
-
|
|
246
|
-
# Wait for first completion using Temporal's wait
|
|
247
|
-
handles = [h for _, h in items]
|
|
248
|
-
|
|
249
|
-
# Use asyncio.wait pattern via workflow.wait
|
|
250
|
-
await workflow.wait_condition(
|
|
251
|
-
lambda: any(h.done() for _, h in items)
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
# Find the completed one
|
|
255
|
-
for node_id, handle in items:
|
|
256
|
-
if handle.done():
|
|
257
|
-
del running[node_id]
|
|
258
|
-
try:
|
|
259
|
-
result = await handle
|
|
260
|
-
return node_id, result
|
|
261
|
-
except Exception as e:
|
|
262
|
-
return node_id, {"success": False, "error": str(e)}
|
|
263
|
-
|
|
264
|
-
# Should not reach here
|
|
265
|
-
raise RuntimeError("No activity completed after wait")
|
|
266
|
-
|
|
267
|
-
def _filter_executable_graph(
|
|
268
|
-
self,
|
|
269
|
-
nodes: List[Dict],
|
|
270
|
-
edges: List[Dict],
|
|
271
|
-
) -> tuple:
|
|
272
|
-
"""Filter out config nodes based on edge handles.
|
|
273
|
-
|
|
274
|
-
Config nodes (tools, memory, model configs) connect via special handles
|
|
275
|
-
and are consumed by their target nodes, not executed independently.
|
|
276
|
-
|
|
277
|
-
Returns:
|
|
278
|
-
Tuple of (executable_nodes, executable_edges)
|
|
279
|
-
"""
|
|
280
|
-
node_map = {n["id"]: n for n in nodes}
|
|
281
|
-
config_ids = set()
|
|
282
|
-
|
|
283
|
-
for edge in edges:
|
|
284
|
-
handle = edge.get("targetHandle", "")
|
|
285
|
-
source_id = edge.get("source")
|
|
286
|
-
|
|
287
|
-
# Edges to config handles mean source is a config node
|
|
288
|
-
if handle in CONFIG_HANDLES:
|
|
289
|
-
config_ids.add(source_id)
|
|
290
|
-
|
|
291
|
-
# Android services connecting to androidTool
|
|
292
|
-
source_node = node_map.get(source_id, {})
|
|
293
|
-
if source_node.get("type") in ANDROID_SERVICE_TYPES:
|
|
294
|
-
config_ids.add(source_id)
|
|
295
|
-
|
|
296
|
-
# Skill nodes (always config, connect to
|
|
297
|
-
if source_node.get("type") in SKILL_NODE_TYPES:
|
|
298
|
-
config_ids.add(source_id)
|
|
299
|
-
|
|
300
|
-
# Filter nodes and edges
|
|
301
|
-
exec_nodes = [n for n in nodes if n["id"] not in config_ids]
|
|
302
|
-
exec_edges = [
|
|
303
|
-
e for e in edges
|
|
304
|
-
if e.get("source") not in config_ids
|
|
305
|
-
and e.get("target") not in config_ids
|
|
306
|
-
and e.get("targetHandle", "") not in CONFIG_HANDLES
|
|
307
|
-
]
|
|
308
|
-
|
|
309
|
-
return exec_nodes, exec_edges
|
|
310
|
-
|
|
311
|
-
def _build_dependency_maps(
|
|
312
|
-
self,
|
|
313
|
-
nodes: List[Dict],
|
|
314
|
-
edges: List[Dict],
|
|
315
|
-
) -> tuple:
|
|
316
|
-
"""Build dependency graph from nodes and edges.
|
|
317
|
-
|
|
318
|
-
Returns:
|
|
319
|
-
Tuple of (dependencies_map, node_map)
|
|
320
|
-
- dependencies_map: node_id -> set of node IDs it depends on
|
|
321
|
-
- node_map: node_id -> node definition
|
|
322
|
-
"""
|
|
323
|
-
node_map = {n["id"]: n for n in nodes}
|
|
324
|
-
node_ids = set(node_map.keys())
|
|
325
|
-
|
|
326
|
-
deps = {nid: set() for nid in node_ids}
|
|
327
|
-
|
|
328
|
-
for edge in edges:
|
|
329
|
-
src, tgt = edge.get("source"), edge.get("target")
|
|
330
|
-
if src in node_ids and tgt in node_ids:
|
|
331
|
-
deps[tgt].add(src)
|
|
332
|
-
|
|
333
|
-
return deps, node_map
|
|
334
|
-
|
|
335
|
-
def _find_ready_nodes(
|
|
336
|
-
self,
|
|
337
|
-
deps: Dict[str, Set[str]],
|
|
338
|
-
completed: Set[str],
|
|
339
|
-
running: Dict[str, Any],
|
|
340
|
-
node_map: Dict[str, Dict],
|
|
341
|
-
) -> List[str]:
|
|
342
|
-
"""Find nodes ready to execute.
|
|
343
|
-
|
|
344
|
-
A node is ready when:
|
|
345
|
-
- All its dependencies have completed
|
|
346
|
-
- It's not already running
|
|
347
|
-
- It's not already completed
|
|
348
|
-
"""
|
|
349
|
-
ready = []
|
|
350
|
-
for node_id in node_map:
|
|
351
|
-
if node_id in completed or node_id in running:
|
|
352
|
-
continue
|
|
353
|
-
if deps[node_id] <= completed:
|
|
354
|
-
ready.append(node_id)
|
|
355
|
-
return ready
|
|
1
|
+
"""Temporal workflow - Pure orchestrator for distributed node execution.
|
|
2
|
+
|
|
3
|
+
The workflow ONLY orchestrates:
|
|
4
|
+
- Parses graph structure
|
|
5
|
+
- Filters config nodes (tools, memory, services)
|
|
6
|
+
- Determines execution order based on dependencies
|
|
7
|
+
- Schedules node activities (can run on ANY worker)
|
|
8
|
+
- Collects results and routes outputs to dependent nodes
|
|
9
|
+
|
|
10
|
+
NO business logic in workflow - all execution happens in activities.
|
|
11
|
+
This enables massive horizontal scaling and multi-tenant distribution.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from datetime import timedelta
|
|
15
|
+
from typing import Any, Dict, List, Set
|
|
16
|
+
|
|
17
|
+
from temporalio import workflow
|
|
18
|
+
from temporalio.common import RetryPolicy
|
|
19
|
+
|
|
20
|
+
# Config handles - nodes connecting via these are config nodes (not executed)
|
|
21
|
+
# AI Agent handles: input-memory, input-tools, input-model
|
|
22
|
+
# Zeenie handles: input-skill, input-tools
|
|
23
|
+
CONFIG_HANDLES = {"input-tools", "input-memory", "input-model", "input-skill"}
|
|
24
|
+
|
|
25
|
+
# Android service types (connect to androidTool, not executed directly)
|
|
26
|
+
ANDROID_SERVICE_TYPES = {
|
|
27
|
+
"batteryMonitor", "locationService", "deviceState",
|
|
28
|
+
"systemInfo", "appList", "appLauncher",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Skill node types (connect to Zeenie's input-skill, not executed directly)
|
|
32
|
+
SKILL_NODE_TYPES = {
|
|
33
|
+
"assistantPersonality", "whatsappSkill", "memorySkill", "mapsSkill",
|
|
34
|
+
"httpSkill", "schedulerSkill", "androidSkill", "codeSkill", "customSkill",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@workflow.defn(sandboxed=False)
|
|
38
|
+
class MachinaWorkflow:
|
|
39
|
+
"""Distributed workflow orchestrator.
|
|
40
|
+
|
|
41
|
+
This workflow ONLY orchestrates - all execution happens in activities
|
|
42
|
+
that can run on any worker in the cluster.
|
|
43
|
+
|
|
44
|
+
Features:
|
|
45
|
+
- Continuous scheduling (FIRST_COMPLETED pattern)
|
|
46
|
+
- Per-node retry policies
|
|
47
|
+
- Config node filtering (tools, memory, services)
|
|
48
|
+
- Multi-tenant support via tenant_id in context
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
@workflow.run
|
|
52
|
+
async def run(self, workflow_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
53
|
+
print("[Workflow] ========== RUN METHOD CALLED ==========")
|
|
54
|
+
"""Execute workflow by orchestrating node activities.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
workflow_data: Dict containing:
|
|
58
|
+
- nodes: List of node definitions from React Flow
|
|
59
|
+
- edges: List of edge definitions from React Flow
|
|
60
|
+
- session_id: Session identifier
|
|
61
|
+
- workflow_id: Workflow ID for tracking
|
|
62
|
+
- tenant_id: Tenant identifier for multi-tenancy
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dict with success, outputs, execution_trace, and errors
|
|
66
|
+
"""
|
|
67
|
+
nodes = workflow_data.get("nodes", [])
|
|
68
|
+
edges = workflow_data.get("edges", [])
|
|
69
|
+
session_id = workflow_data.get("session_id", "default")
|
|
70
|
+
workflow_id = workflow_data.get("workflow_id")
|
|
71
|
+
tenant_id = workflow_data.get("tenant_id")
|
|
72
|
+
|
|
73
|
+
workflow.logger.info(
|
|
74
|
+
f"Starting workflow orchestration: {len(nodes)} nodes, {len(edges)} edges"
|
|
75
|
+
)
|
|
76
|
+
# Debug print for console visibility
|
|
77
|
+
print(f"[Workflow] Starting: {len(nodes)} nodes, {len(edges)} edges")
|
|
78
|
+
|
|
79
|
+
if not nodes:
|
|
80
|
+
return {
|
|
81
|
+
"success": False,
|
|
82
|
+
"error": "No nodes provided",
|
|
83
|
+
"outputs": {},
|
|
84
|
+
"execution_trace": [],
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# 1. Filter out config nodes (tools, memory, services)
|
|
88
|
+
exec_nodes, exec_edges = self._filter_executable_graph(nodes, edges)
|
|
89
|
+
|
|
90
|
+
workflow.logger.info(
|
|
91
|
+
f"After filtering: {len(exec_nodes)} executable nodes "
|
|
92
|
+
f"(filtered {len(nodes) - len(exec_nodes)} config nodes)"
|
|
93
|
+
)
|
|
94
|
+
print(f"[Workflow] Executable: {len(exec_nodes)}, Config filtered: {len(nodes) - len(exec_nodes)}")
|
|
95
|
+
|
|
96
|
+
# 2. Build dependency maps
|
|
97
|
+
deps, node_map = self._build_dependency_maps(exec_nodes, exec_edges)
|
|
98
|
+
|
|
99
|
+
# 3. Initialize state
|
|
100
|
+
outputs: Dict[str, Any] = {} # node_id -> result
|
|
101
|
+
completed: Set[str] = set()
|
|
102
|
+
running: Dict[str, Any] = {} # node_id -> activity handle
|
|
103
|
+
errors: List[Dict] = []
|
|
104
|
+
execution_trace: List[str] = []
|
|
105
|
+
|
|
106
|
+
# 4. Handle pre-executed triggers (already have their output)
|
|
107
|
+
pre_executed_count = 0
|
|
108
|
+
for node in exec_nodes:
|
|
109
|
+
if node.get("_pre_executed"):
|
|
110
|
+
node_id = node["id"]
|
|
111
|
+
outputs[node_id] = {
|
|
112
|
+
"success": True,
|
|
113
|
+
"result": node.get("_trigger_output", {}),
|
|
114
|
+
"pre_executed": True,
|
|
115
|
+
}
|
|
116
|
+
completed.add(node_id)
|
|
117
|
+
execution_trace.append(node_id)
|
|
118
|
+
pre_executed_count += 1
|
|
119
|
+
workflow.logger.info(f"Pre-executed trigger: {node_id}")
|
|
120
|
+
|
|
121
|
+
workflow.logger.info(f"Pre-executed: {pre_executed_count}, To execute: {len(node_map) - pre_executed_count}")
|
|
122
|
+
print(f"[Workflow] Pre-executed: {pre_executed_count}, To execute: {len(node_map) - pre_executed_count}")
|
|
123
|
+
|
|
124
|
+
# 5. Retry policy for node activities
|
|
125
|
+
retry_policy = RetryPolicy(
|
|
126
|
+
initial_interval=timedelta(seconds=1),
|
|
127
|
+
maximum_interval=timedelta(seconds=30),
|
|
128
|
+
maximum_attempts=3,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# 6. Continuous scheduling loop
|
|
132
|
+
loop_count = 0
|
|
133
|
+
while True:
|
|
134
|
+
loop_count += 1
|
|
135
|
+
# Find ready nodes (all deps completed, not running/completed)
|
|
136
|
+
ready = self._find_ready_nodes(deps, completed, running, node_map)
|
|
137
|
+
workflow.logger.info(f"Loop {loop_count}: ready={len(ready)}, running={len(running)}, completed={len(completed)}")
|
|
138
|
+
print(f"[Workflow] Loop {loop_count}: ready={len(ready)}, running={len(running)}, completed={len(completed)}")
|
|
139
|
+
|
|
140
|
+
# Start activities for ready nodes
|
|
141
|
+
for node_id in ready:
|
|
142
|
+
node = node_map[node_id]
|
|
143
|
+
|
|
144
|
+
# Build immutable context for this node
|
|
145
|
+
context = {
|
|
146
|
+
"node_id": node_id,
|
|
147
|
+
"node_type": node.get("type", "unknown"),
|
|
148
|
+
"node_data": node.get("data", {}),
|
|
149
|
+
"inputs": self._get_node_inputs(node_id, deps, outputs),
|
|
150
|
+
"workflow_id": workflow_id,
|
|
151
|
+
"tenant_id": tenant_id,
|
|
152
|
+
"session_id": session_id,
|
|
153
|
+
"nodes": nodes, # Full list for tool/memory detection
|
|
154
|
+
"edges": edges, # Full list for tool/memory detection
|
|
155
|
+
# Include pre-executed info if applicable
|
|
156
|
+
"pre_executed": node.get("_pre_executed", False),
|
|
157
|
+
"trigger_output": node.get("_trigger_output"),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Schedule activity by name (for class-based activities)
|
|
161
|
+
# The activity is registered as NodeExecutionActivities.execute_node_activity
|
|
162
|
+
handle = workflow.start_activity(
|
|
163
|
+
"execute_node_activity",
|
|
164
|
+
args=[context],
|
|
165
|
+
start_to_close_timeout=timedelta(minutes=10),
|
|
166
|
+
heartbeat_timeout=timedelta(minutes=2),
|
|
167
|
+
retry_policy=retry_policy,
|
|
168
|
+
)
|
|
169
|
+
running[node_id] = handle
|
|
170
|
+
|
|
171
|
+
workflow.logger.info(f"Scheduled activity for node: {node_id}")
|
|
172
|
+
print(f"[Workflow] Scheduled: {node_id}")
|
|
173
|
+
|
|
174
|
+
# Exit if nothing running and nothing ready
|
|
175
|
+
if not running:
|
|
176
|
+
break
|
|
177
|
+
|
|
178
|
+
# Wait for ANY activity to complete (FIRST_COMPLETED pattern)
|
|
179
|
+
done_id, result = await self._wait_any_complete(running)
|
|
180
|
+
|
|
181
|
+
if result.get("success"):
|
|
182
|
+
outputs[done_id] = result
|
|
183
|
+
completed.add(done_id)
|
|
184
|
+
execution_trace.append(done_id)
|
|
185
|
+
workflow.logger.info(f"Node completed: {done_id}")
|
|
186
|
+
else:
|
|
187
|
+
# Node failed after all retries
|
|
188
|
+
error_info = {
|
|
189
|
+
"node_id": done_id,
|
|
190
|
+
"error": result.get("error", "Unknown error"),
|
|
191
|
+
}
|
|
192
|
+
errors.append(error_info)
|
|
193
|
+
workflow.logger.error(f"Node failed: {done_id} - {error_info['error']}")
|
|
194
|
+
|
|
195
|
+
# Stop workflow on failure
|
|
196
|
+
# TODO: Could add option to continue with partial results
|
|
197
|
+
break
|
|
198
|
+
|
|
199
|
+
# Build final result
|
|
200
|
+
success = len(errors) == 0 and len(completed) == len(node_map)
|
|
201
|
+
|
|
202
|
+
workflow.logger.info(
|
|
203
|
+
f"Workflow complete: success={success}, "
|
|
204
|
+
f"executed={len(execution_trace)}/{len(node_map)}"
|
|
205
|
+
)
|
|
206
|
+
print(f"[Workflow] Complete: success={success}, executed={len(execution_trace)}/{len(node_map)}")
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
"success": success,
|
|
210
|
+
"outputs": outputs,
|
|
211
|
+
"execution_trace": execution_trace,
|
|
212
|
+
"errors": errors if errors else None,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
def _get_node_inputs(
|
|
216
|
+
self,
|
|
217
|
+
node_id: str,
|
|
218
|
+
deps: Dict[str, Set[str]],
|
|
219
|
+
outputs: Dict[str, Any],
|
|
220
|
+
) -> Dict[str, Any]:
|
|
221
|
+
"""Get outputs from upstream nodes as inputs for this node."""
|
|
222
|
+
inputs = {}
|
|
223
|
+
for dep_id in deps.get(node_id, set()):
|
|
224
|
+
if dep_id in outputs:
|
|
225
|
+
inputs[dep_id] = outputs[dep_id].get("result", {})
|
|
226
|
+
return inputs
|
|
227
|
+
|
|
228
|
+
async def _wait_any_complete(self, running: Dict[str, Any]) -> tuple:
|
|
229
|
+
"""Wait for any activity to complete, return (node_id, result).
|
|
230
|
+
|
|
231
|
+
Uses Temporal's native wait mechanism for efficient polling.
|
|
232
|
+
"""
|
|
233
|
+
# Convert to list for iteration
|
|
234
|
+
items = list(running.items())
|
|
235
|
+
|
|
236
|
+
# Check if any already done
|
|
237
|
+
for node_id, handle in items:
|
|
238
|
+
if handle.done():
|
|
239
|
+
del running[node_id]
|
|
240
|
+
try:
|
|
241
|
+
result = await handle
|
|
242
|
+
return node_id, result
|
|
243
|
+
except Exception as e:
|
|
244
|
+
return node_id, {"success": False, "error": str(e)}
|
|
245
|
+
|
|
246
|
+
# Wait for first completion using Temporal's wait
|
|
247
|
+
handles = [h for _, h in items]
|
|
248
|
+
|
|
249
|
+
# Use asyncio.wait pattern via workflow.wait
|
|
250
|
+
await workflow.wait_condition(
|
|
251
|
+
lambda: any(h.done() for _, h in items)
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Find the completed one
|
|
255
|
+
for node_id, handle in items:
|
|
256
|
+
if handle.done():
|
|
257
|
+
del running[node_id]
|
|
258
|
+
try:
|
|
259
|
+
result = await handle
|
|
260
|
+
return node_id, result
|
|
261
|
+
except Exception as e:
|
|
262
|
+
return node_id, {"success": False, "error": str(e)}
|
|
263
|
+
|
|
264
|
+
# Should not reach here
|
|
265
|
+
raise RuntimeError("No activity completed after wait")
|
|
266
|
+
|
|
267
|
+
def _filter_executable_graph(
|
|
268
|
+
self,
|
|
269
|
+
nodes: List[Dict],
|
|
270
|
+
edges: List[Dict],
|
|
271
|
+
) -> tuple:
|
|
272
|
+
"""Filter out config nodes based on edge handles.
|
|
273
|
+
|
|
274
|
+
Config nodes (tools, memory, model configs) connect via special handles
|
|
275
|
+
and are consumed by their target nodes, not executed independently.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Tuple of (executable_nodes, executable_edges)
|
|
279
|
+
"""
|
|
280
|
+
node_map = {n["id"]: n for n in nodes}
|
|
281
|
+
config_ids = set()
|
|
282
|
+
|
|
283
|
+
for edge in edges:
|
|
284
|
+
handle = edge.get("targetHandle", "")
|
|
285
|
+
source_id = edge.get("source")
|
|
286
|
+
|
|
287
|
+
# Edges to config handles mean source is a config node
|
|
288
|
+
if handle in CONFIG_HANDLES:
|
|
289
|
+
config_ids.add(source_id)
|
|
290
|
+
|
|
291
|
+
# Android services connecting to androidTool
|
|
292
|
+
source_node = node_map.get(source_id, {})
|
|
293
|
+
if source_node.get("type") in ANDROID_SERVICE_TYPES:
|
|
294
|
+
config_ids.add(source_id)
|
|
295
|
+
|
|
296
|
+
# Skill nodes (always config, connect to Zeenie)
|
|
297
|
+
if source_node.get("type") in SKILL_NODE_TYPES:
|
|
298
|
+
config_ids.add(source_id)
|
|
299
|
+
|
|
300
|
+
# Filter nodes and edges
|
|
301
|
+
exec_nodes = [n for n in nodes if n["id"] not in config_ids]
|
|
302
|
+
exec_edges = [
|
|
303
|
+
e for e in edges
|
|
304
|
+
if e.get("source") not in config_ids
|
|
305
|
+
and e.get("target") not in config_ids
|
|
306
|
+
and e.get("targetHandle", "") not in CONFIG_HANDLES
|
|
307
|
+
]
|
|
308
|
+
|
|
309
|
+
return exec_nodes, exec_edges
|
|
310
|
+
|
|
311
|
+
def _build_dependency_maps(
|
|
312
|
+
self,
|
|
313
|
+
nodes: List[Dict],
|
|
314
|
+
edges: List[Dict],
|
|
315
|
+
) -> tuple:
|
|
316
|
+
"""Build dependency graph from nodes and edges.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
Tuple of (dependencies_map, node_map)
|
|
320
|
+
- dependencies_map: node_id -> set of node IDs it depends on
|
|
321
|
+
- node_map: node_id -> node definition
|
|
322
|
+
"""
|
|
323
|
+
node_map = {n["id"]: n for n in nodes}
|
|
324
|
+
node_ids = set(node_map.keys())
|
|
325
|
+
|
|
326
|
+
deps = {nid: set() for nid in node_ids}
|
|
327
|
+
|
|
328
|
+
for edge in edges:
|
|
329
|
+
src, tgt = edge.get("source"), edge.get("target")
|
|
330
|
+
if src in node_ids and tgt in node_ids:
|
|
331
|
+
deps[tgt].add(src)
|
|
332
|
+
|
|
333
|
+
return deps, node_map
|
|
334
|
+
|
|
335
|
+
def _find_ready_nodes(
|
|
336
|
+
self,
|
|
337
|
+
deps: Dict[str, Set[str]],
|
|
338
|
+
completed: Set[str],
|
|
339
|
+
running: Dict[str, Any],
|
|
340
|
+
node_map: Dict[str, Dict],
|
|
341
|
+
) -> List[str]:
|
|
342
|
+
"""Find nodes ready to execute.
|
|
343
|
+
|
|
344
|
+
A node is ready when:
|
|
345
|
+
- All its dependencies have completed
|
|
346
|
+
- It's not already running
|
|
347
|
+
- It's not already completed
|
|
348
|
+
"""
|
|
349
|
+
ready = []
|
|
350
|
+
for node_id in node_map:
|
|
351
|
+
if node_id in completed or node_id in running:
|
|
352
|
+
continue
|
|
353
|
+
if deps[node_id] <= completed:
|
|
354
|
+
ready.append(node_id)
|
|
355
|
+
return ready
|