machinaos 0.0.78 → 0.0.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.template +74 -5
- package/{workflows/AI Assistant_workflow-1778504793388-ou1m1tz2x.json → .machina/workflows/AI Assistant_example_workflow-1779017037684-e2e5da7a.json } +164 -105
- package/{workflows/AI Employee_example_workflow-1777720598005-u4cm858dv.json → .machina/workflows/AI Employee_example_workflow-1779102911870-cbc76c82.json } +582 -328
- package/{workflows/Claude Assistant_workflow-1778380124051-mdibn807c.json → .machina/workflows/Claude Assistant_example_workflow-1779095939967-2369cff4.json } +152 -83
- package/README.md +5 -2
- package/bin/cli.js +2 -2
- package/{machina → cli}/__main__.py +11 -7
- package/cli/_common.py +122 -0
- package/cli/buildenv.py +40 -0
- package/cli/cli.py +204 -0
- package/{machina → cli}/colors.py +10 -2
- package/cli/commands/__init__.py +1 -0
- package/cli/commands/_temporal_specs.py +59 -0
- package/{machina → cli}/commands/build.py +35 -45
- package/cli/commands/clean.py +141 -0
- package/cli/commands/daemon/__init__.py +47 -0
- package/cli/commands/daemon/_state.py +97 -0
- package/cli/commands/daemon/restart.py +14 -0
- package/cli/commands/daemon/start.py +49 -0
- package/cli/commands/daemon/status.py +20 -0
- package/cli/commands/daemon/stop.py +22 -0
- package/{machina → cli}/commands/dev.py +32 -42
- package/{machina → cli}/commands/docs.py +13 -11
- package/{machina → cli}/commands/start.py +69 -62
- package/{machina → cli}/commands/stop.py +7 -10
- package/{machina → cli}/commands/version.py +12 -6
- package/cli/config.py +170 -0
- package/cli/platform_.py +169 -0
- package/{machina → cli}/ports.py +42 -3
- package/{machina → cli}/run.py +29 -2
- package/{machina → cli}/supervisor.py +29 -12
- package/{machina → cli}/tcp.py +6 -2
- package/{machina → cli}/tree.py +38 -11
- package/client/dist/assets/{ActionBar-Du2MSFSz.js → ActionBar-Cjr3TF7g.js} +1 -1
- package/client/dist/assets/{ApiKeyInput-k2LBmBjb.js → ApiKeyInput-DIJE2PVA.js} +1 -1
- package/client/dist/assets/{ApiKeyPanel-C_bV9U0X.js → ApiKeyPanel-CPmye7uh.js} +1 -1
- package/client/dist/assets/{ApiUsageSection-CmVfwZzL.js → ApiUsageSection-TF_7gH2D.js} +1 -1
- package/client/dist/assets/{EmailPanel-CeKIMGu-.js → EmailPanel-Bs-xvbKR.js} +1 -1
- package/client/dist/assets/{OAuthPanel-KA3t3Q2K.js → OAuthPanel-BDtVJhAV.js} +1 -1
- package/client/dist/assets/{QrPairingPanel-NgNpJNuk.js → QrPairingPanel-BwJehTuZ.js} +1 -1
- package/client/dist/assets/{RateLimitSection-Du5YNVIA.js → RateLimitSection-CfNOoPIS.js} +1 -1
- package/client/dist/assets/{StatusCard-DNLyayXc.js → StatusCard-DkwIrgdP.js} +1 -1
- package/client/dist/assets/index-P2FzntoL.js +165 -0
- package/client/dist/index.html +1 -1
- package/client/package.json +1 -1
- package/client/src/Dashboard.tsx +128 -76
- package/client/src/adapters/nodeSpecToDescription.ts +7 -0
- package/client/src/assets/icons/index.test.ts +10 -0
- package/client/src/assets/icons/index.ts +16 -3
- package/client/src/components/AIAgentNode.tsx +8 -8
- package/client/src/components/ParameterRenderer.tsx +6 -3
- package/client/src/components/SkillEditorModal.tsx +1 -0
- package/client/src/components/credentials/panels/EmailPanel.tsx +2 -0
- package/client/src/components/credentials/sections/ProviderDefaultsSection.tsx +2 -0
- package/client/src/components/credentials/sections/RateLimitSection.tsx +1 -0
- package/client/src/components/icons/AIProviderIcons.tsx +1 -0
- package/client/src/components/maps/GoogleMapsPicker.tsx +1 -0
- package/client/src/components/parameterPanel/InputSection.tsx +1 -0
- package/client/src/components/parameterPanel/MasterSkillEditor.tsx +1 -0
- package/client/src/components/parameterPanel/OutputSection.tsx +1 -0
- package/client/src/components/ui/ComponentPalette.tsx +1 -0
- package/client/src/components/ui/MapSelector.tsx +1 -0
- package/client/src/components/ui/NodeContextMenu.tsx +3 -3
- package/client/src/components/ui/SettingsPanel.tsx +1 -0
- package/client/src/components/ui/action-button.tsx +1 -0
- package/client/src/components/ui/badge.tsx +1 -0
- package/client/src/components/ui/button.tsx +1 -0
- package/client/src/components/ui/form.tsx +1 -0
- package/client/src/components/ui/tabs.tsx +1 -0
- package/client/src/contexts/AuthContext.tsx +1 -0
- package/client/src/contexts/ThemeContext.tsx +1 -0
- package/client/src/contexts/WebSocketContext.tsx +104 -34
- package/client/src/hooks/__tests__/useApiKeys.test.ts +2 -2
- package/client/src/hooks/useReactFlowNodes.ts +1 -0
- package/client/src/hooks/useWorkflowValidation.ts +142 -0
- package/client/src/lib/nodeSpec.ts +1 -0
- package/client/src/test/providers.tsx +1 -0
- package/client/src/types/__tests__/cloudEvents.test.ts +5 -2
- package/client/src/types/cloudEvents.ts +19 -7
- package/client/src/utils/nodeUtils.ts +1 -1
- package/client/src/utils/workflow.ts +8 -2
- package/client/src/utils/workflowExport.ts +60 -3
- package/package.json +24 -23
- package/scripts/install.js +16 -27
- package/scripts/migrate_icons.py +3 -1
- package/scripts/migrate_skill_icons.py +6 -7
- package/scripts/postinstall.js +11 -9
- package/server/config/ai_cli_providers.json +2 -3
- package/server/config/credential_providers.json +15 -15
- package/server/config/llm_defaults.json +1 -1
- package/server/config/model_registry.json +416 -611
- package/server/constants.py +285 -223
- package/server/core/__init__.py +1 -1
- package/server/core/cache.py +9 -29
- package/server/core/cleanup.py +12 -24
- package/server/core/config.py +148 -24
- package/server/core/container.py +68 -59
- package/server/core/credential_backends.py +5 -13
- package/server/core/credentials_database.py +13 -43
- package/server/core/database.py +292 -353
- package/server/core/health.py +4 -5
- package/server/core/logging.py +241 -87
- package/server/core/paths.py +285 -0
- package/server/core/tracing.py +2 -8
- package/server/gunicorn.conf.py +1 -0
- package/server/main.py +150 -74
- package/server/middleware/auth.py +18 -24
- package/server/models/__init__.py +1 -1
- package/server/models/auth.py +5 -12
- package/server/models/database.py +36 -68
- package/server/models/node_metadata.py +25 -18
- package/server/nodejs/dist/index.js +107 -0
- package/server/nodes/README.md +11 -5
- package/server/nodes/__init__.py +1 -1
- package/server/nodes/_visuals.py +146 -14
- package/server/nodes/agent/_events.py +124 -0
- package/server/nodes/agent/_handles.py +15 -29
- package/server/nodes/agent/_inline.py +28 -25
- package/server/nodes/agent/_specialized.py +30 -15
- package/server/nodes/agent/{ai_agent.py → ai_agent/__init__.py} +33 -17
- package/server/nodes/agent/ai_agent/meta.json +3 -0
- package/server/nodes/agent/{ai_employee.py → ai_employee/__init__.py} +5 -2
- package/server/nodes/agent/ai_employee/meta.json +3 -0
- package/server/nodes/agent/{android_agent.py → android_agent/__init__.py} +1 -1
- package/server/nodes/agent/android_agent/meta.json +3 -0
- package/server/nodes/agent/{autonomous_agent.py → autonomous_agent/__init__.py} +2 -1
- package/server/nodes/agent/autonomous_agent/meta.json +3 -0
- package/server/nodes/agent/{chat_agent.py → chat_agent/__init__.py} +29 -12
- package/server/nodes/agent/chat_agent/meta.json +3 -0
- package/server/nodes/agent/{claude_code_agent.py → claude_code_agent/__init__.py} +192 -95
- package/server/nodes/agent/claude_code_agent/_handlers.py +169 -0
- package/server/{services/claude_oauth.py → nodes/agent/claude_code_agent/_oauth.py} +26 -13
- package/server/nodes/agent/claude_code_agent/_pool.py +1020 -0
- package/server/nodes/agent/claude_code_agent/_provider.py +513 -0
- package/server/nodes/agent/claude_code_agent/_skills.py +245 -0
- package/server/nodes/agent/claude_code_agent/meta.json +3 -0
- package/server/nodes/agent/{codex_agent.py → codex_agent/__init__.py} +26 -35
- package/server/nodes/agent/codex_agent/meta.json +3 -0
- package/server/nodes/agent/{coding_agent.py → coding_agent/__init__.py} +1 -1
- package/server/nodes/agent/coding_agent/meta.json +3 -0
- package/server/nodes/agent/{consumer_agent.py → consumer_agent/__init__.py} +1 -1
- package/server/nodes/agent/consumer_agent/meta.json +3 -0
- package/server/nodes/agent/{orchestrator_agent.py → orchestrator_agent/__init__.py} +5 -2
- package/server/nodes/agent/orchestrator_agent/meta.json +3 -0
- package/server/nodes/agent/{payments_agent.py → payments_agent/__init__.py} +1 -1
- package/server/nodes/agent/payments_agent/meta.json +3 -0
- package/server/nodes/agent/{productivity_agent.py → productivity_agent/__init__.py} +1 -1
- package/server/nodes/agent/productivity_agent/meta.json +3 -0
- package/server/nodes/agent/{rlm_agent.py → rlm_agent/__init__.py} +18 -17
- package/server/nodes/agent/rlm_agent/meta.json +3 -0
- package/server/nodes/agent/{social_agent.py → social_agent/__init__.py} +1 -1
- package/server/nodes/agent/social_agent/meta.json +3 -0
- package/server/nodes/agent/{task_agent.py → task_agent/__init__.py} +1 -1
- package/server/nodes/agent/task_agent/meta.json +3 -0
- package/server/nodes/agent/{tool_agent.py → tool_agent/__init__.py} +1 -1
- package/server/nodes/agent/tool_agent/meta.json +3 -0
- package/server/nodes/agent/{travel_agent.py → travel_agent/__init__.py} +1 -1
- package/server/nodes/agent/travel_agent/meta.json +3 -0
- package/server/nodes/agent/{web_agent.py → web_agent/__init__.py} +1 -1
- package/server/nodes/agent/web_agent/meta.json +3 -0
- package/server/nodes/android/__init__.py +24 -0
- package/server/nodes/android/_base.py +93 -76
- package/server/nodes/android/_dispatcher.py +140 -223
- package/server/nodes/android/_events.py +154 -0
- package/server/nodes/android/_handlers.py +13 -7
- package/server/nodes/android/_option_loaders.py +1 -4
- package/server/nodes/android/_refresh.py +27 -37
- package/server/nodes/android/_relay/broadcaster.py +25 -41
- package/server/nodes/android/_relay/client.py +23 -42
- package/server/nodes/android/_relay/manager.py +1 -0
- package/server/nodes/android/_relay/protocol.py +6 -0
- package/server/nodes/android/_router.py +48 -133
- package/server/nodes/android/{airplane_mode_control.py → airplane_mode_control/__init__.py} +2 -1
- package/server/nodes/android/airplane_mode_control/meta.json +3 -0
- package/server/nodes/android/{app_launcher.py → app_launcher/__init__.py} +2 -1
- package/server/nodes/android/app_launcher/meta.json +3 -0
- package/server/nodes/android/{app_list.py → app_list/__init__.py} +2 -1
- package/server/nodes/android/app_list/meta.json +3 -0
- package/server/nodes/android/{audio_automation.py → audio_automation/__init__.py} +2 -1
- package/server/nodes/android/audio_automation/meta.json +3 -0
- package/server/nodes/android/{battery_monitor.py → battery_monitor/__init__.py} +2 -1
- package/server/nodes/android/battery_monitor/meta.json +3 -0
- package/server/nodes/android/{bluetooth_automation.py → bluetooth_automation/__init__.py} +2 -1
- package/server/nodes/android/bluetooth_automation/meta.json +3 -0
- package/server/nodes/android/{camera_control.py → camera_control/__init__.py} +2 -1
- package/server/nodes/android/camera_control/meta.json +3 -0
- package/server/nodes/android/{device_state_automation.py → device_state_automation/__init__.py} +2 -1
- package/server/nodes/android/device_state_automation/meta.json +3 -0
- package/server/nodes/android/{environmental_sensors.py → environmental_sensors/__init__.py} +2 -1
- package/server/nodes/android/environmental_sensors/meta.json +3 -0
- package/server/nodes/android/{location.py → location/__init__.py} +2 -1
- package/server/nodes/android/location/meta.json +3 -0
- package/server/nodes/android/{media_control.py → media_control/__init__.py} +2 -1
- package/server/nodes/android/media_control/meta.json +3 -0
- package/server/nodes/android/{motion_detection.py → motion_detection/__init__.py} +2 -1
- package/server/nodes/android/motion_detection/meta.json +3 -0
- package/server/nodes/android/{network_monitor.py → network_monitor/__init__.py} +2 -1
- package/server/nodes/android/network_monitor/meta.json +3 -0
- package/server/nodes/android/{screen_control_automation.py → screen_control_automation/__init__.py} +2 -1
- package/server/nodes/android/screen_control_automation/meta.json +3 -0
- package/server/nodes/android/{system_info.py → system_info/__init__.py} +2 -1
- package/server/nodes/android/system_info/meta.json +3 -0
- package/server/nodes/android/{wifi_automation.py → wifi_automation/__init__.py} +2 -1
- package/server/nodes/android/wifi_automation/meta.json +3 -0
- package/server/nodes/browser/__init__.py +22 -1
- package/server/nodes/browser/_install.py +63 -0
- package/server/nodes/browser/_service.py +21 -25
- package/server/nodes/browser/{browser.py → browser/__init__.py} +58 -25
- package/server/nodes/browser/browser/meta.json +3 -0
- package/server/nodes/chat/{chat_history.py → chat_history/__init__.py} +2 -4
- package/server/nodes/chat/chat_history/meta.json +3 -0
- package/server/nodes/chat/{chat_send.py → chat_send/__init__.py} +2 -4
- package/server/nodes/chat/chat_send/icon.svg +1 -0
- package/server/nodes/chat/chat_send/meta.json +3 -0
- package/server/nodes/code/_base.py +1 -1
- package/server/nodes/code/{javascript_executor.py → javascript_executor/__init__.py} +5 -5
- package/server/nodes/code/javascript_executor/meta.json +3 -0
- package/server/nodes/code/{python_executor.py → python_executor/__init__.py} +32 -14
- package/server/nodes/code/python_executor/meta.json +3 -0
- package/server/nodes/code/{typescript_executor.py → typescript_executor/__init__.py} +5 -5
- package/server/nodes/code/typescript_executor/meta.json +3 -0
- package/server/nodes/document/{document_parser.py → document_parser/__init__.py} +26 -15
- package/server/nodes/document/document_parser/meta.json +3 -0
- package/server/nodes/document/{embedding_generator.py → embedding_generator/__init__.py} +16 -9
- package/server/nodes/document/embedding_generator/meta.json +3 -0
- package/server/nodes/document/{file_downloader.py → file_downloader/__init__.py} +30 -20
- package/server/nodes/document/file_downloader/meta.json +3 -0
- package/server/nodes/document/{http_scraper.py → http_scraper/__init__.py} +31 -21
- package/server/nodes/document/http_scraper/meta.json +3 -0
- package/server/nodes/document/{text_chunker.py → text_chunker/__init__.py} +17 -12
- package/server/nodes/document/text_chunker/meta.json +3 -0
- package/server/nodes/document/{vector_store.py → vector_store/__init__.py} +88 -72
- package/server/nodes/document/vector_store/meta.json +3 -0
- package/server/nodes/email/__init__.py +9 -2
- package/server/nodes/email/_events.py +54 -0
- package/server/nodes/email/_filters.py +3 -3
- package/server/nodes/email/_himalaya.py +95 -50
- package/server/nodes/email/_service.py +23 -13
- package/server/nodes/email/{email_read.py → email_read/__init__.py} +23 -11
- package/server/nodes/email/email_read/icon.svg +6 -0
- package/server/nodes/email/email_read/meta.json +3 -0
- package/server/nodes/email/{email_receive.py → email_receive/__init__.py} +45 -23
- package/server/nodes/email/email_receive/meta.json +3 -0
- package/server/nodes/email/{email_send.py → email_send/__init__.py} +13 -7
- package/server/nodes/email/email_send/meta.json +3 -0
- package/server/nodes/filesystem/_backend.py +1 -5
- package/server/nodes/filesystem/{file_modify.py → file_modify/__init__.py} +10 -5
- package/server/nodes/filesystem/file_modify/meta.json +3 -0
- package/server/nodes/filesystem/{file_read.py → file_read/__init__.py} +7 -3
- package/server/nodes/filesystem/file_read/meta.json +3 -0
- package/server/nodes/filesystem/{fs_search.py → fs_search/__init__.py} +11 -3
- package/server/nodes/filesystem/fs_search/meta.json +3 -0
- package/server/nodes/filesystem/{shell.py → shell/__init__.py} +12 -5
- package/server/nodes/filesystem/shell/meta.json +3 -0
- package/server/nodes/google/__init__.py +12 -0
- package/server/nodes/google/_auth_helper.py +7 -13
- package/server/nodes/google/_base.py +14 -11
- package/server/nodes/google/_credentials.py +2 -1
- package/server/nodes/google/_events.py +47 -0
- package/server/nodes/google/_filters.py +3 -3
- package/server/nodes/google/_gmail.py +70 -47
- package/server/nodes/google/_handlers.py +3 -1
- package/server/nodes/google/_oauth.py +25 -11
- package/server/nodes/google/_option_loaders.py +9 -30
- package/server/nodes/google/_refresh.py +8 -12
- package/server/nodes/google/_router.py +4 -5
- package/server/nodes/google/{calendar.py → calendar/__init__.py} +87 -64
- package/server/nodes/google/calendar/meta.json +3 -0
- package/server/nodes/google/{contacts.py → contacts/__init__.py} +84 -72
- package/server/nodes/google/contacts/meta.json +3 -0
- package/server/nodes/google/{drive.py → drive/__init__.py} +87 -72
- package/server/nodes/google/drive/meta.json +3 -0
- package/server/nodes/google/{gmail.py → gmail/__init__.py} +73 -39
- package/server/nodes/google/gmail/meta.json +3 -0
- package/server/nodes/google/{gmail_receive.py → gmail_receive/__init__.py} +31 -24
- package/server/nodes/google/gmail_receive/icon.svg +7 -0
- package/server/nodes/google/gmail_receive/meta.json +3 -0
- package/server/nodes/google/google.svg +7 -0
- package/server/nodes/google/{sheets.py → sheets/__init__.py} +54 -42
- package/server/nodes/google/sheets/meta.json +3 -0
- package/server/nodes/google/{tasks.py → tasks/__init__.py} +56 -43
- package/server/nodes/google/tasks/meta.json +3 -0
- package/server/nodes/groups.py +28 -28
- package/server/nodes/location/__init__.py +31 -1
- package/server/nodes/location/_credentials.py +1 -6
- package/server/nodes/location/_service.py +88 -107
- package/server/nodes/location/{gmaps_create.py → gmaps_create/__init__.py} +6 -6
- package/server/nodes/location/gmaps_create/meta.json +3 -0
- package/server/nodes/location/{gmaps_locations.py → gmaps_locations/__init__.py} +8 -6
- package/server/nodes/location/gmaps_locations/meta.json +3 -0
- package/server/nodes/location/{gmaps_nearby_places.py → gmaps_nearby_places/__init__.py} +8 -6
- package/server/nodes/location/gmaps_nearby_places/meta.json +3 -0
- package/server/nodes/model/_base.py +10 -7
- package/server/nodes/model/_credentials.py +10 -10
- package/server/nodes/model/_local_validator.py +28 -24
- package/server/nodes/model/{anthropic_chat_model.py → anthropic_chat_model/__init__.py} +5 -3
- package/server/nodes/model/anthropic_chat_model/meta.json +3 -0
- package/server/nodes/model/{cerebras_chat_model.py → cerebras_chat_model/__init__.py} +5 -3
- package/server/nodes/model/cerebras_chat_model/meta.json +3 -0
- package/server/nodes/model/{deepseek_chat_model.py → deepseek_chat_model/__init__.py} +8 -4
- package/server/nodes/model/deepseek_chat_model/meta.json +3 -0
- package/server/nodes/model/{gemini_chat_model.py → gemini_chat_model/__init__.py} +5 -3
- package/server/nodes/model/gemini_chat_model/meta.json +3 -0
- package/server/nodes/model/{groq_chat_model.py → groq_chat_model/__init__.py} +2 -2
- package/server/nodes/model/groq_chat_model/meta.json +3 -0
- package/server/nodes/model/{kimi_chat_model.py → kimi_chat_model/__init__.py} +2 -2
- package/server/nodes/model/kimi_chat_model/meta.json +3 -0
- package/server/nodes/model/{lmstudio_chat_model.py → lmstudio_chat_model/__init__.py} +2 -2
- package/server/nodes/model/lmstudio_chat_model/meta.json +3 -0
- package/server/nodes/model/{mistral_chat_model.py → mistral_chat_model/__init__.py} +2 -2
- package/server/nodes/model/mistral_chat_model/meta.json +3 -0
- package/server/nodes/model/{ollama_chat_model.py → ollama_chat_model/__init__.py} +2 -2
- package/server/nodes/model/ollama_chat_model/meta.json +3 -0
- package/server/nodes/model/{openai_chat_model.py → openai_chat_model/__init__.py} +8 -4
- package/server/nodes/model/openai_chat_model/meta.json +3 -0
- package/server/nodes/model/{openrouter_chat_model.py → openrouter_chat_model/__init__.py} +8 -4
- package/server/nodes/model/openrouter_chat_model/meta.json +3 -0
- package/server/nodes/proxy/_usage.py +14 -15
- package/server/nodes/proxy/{proxy_config.py → proxy_config/__init__.py} +39 -30
- package/server/nodes/proxy/proxy_config/meta.json +3 -0
- package/server/nodes/proxy/{proxy_request.py → proxy_request/__init__.py} +30 -16
- package/server/nodes/proxy/proxy_request/meta.json +3 -0
- package/server/nodes/proxy/{proxy_status.py → proxy_status/__init__.py} +2 -0
- package/server/nodes/proxy/proxy_status/meta.json +3 -0
- package/server/nodes/scheduler/{cron_scheduler.py → cron_scheduler/__init__.py} +96 -23
- package/server/nodes/scheduler/cron_scheduler/_workflow.py +155 -0
- package/server/nodes/scheduler/cron_scheduler/meta.json +3 -0
- package/server/nodes/scheduler/{timer.py → timer/__init__.py} +6 -5
- package/server/nodes/scheduler/timer/meta.json +3 -0
- package/server/nodes/scraper/_credentials.py +0 -1
- package/server/nodes/scraper/{apify_actor.py → apify_actor/__init__.py} +44 -35
- package/server/nodes/scraper/apify_actor/icon.svg +5 -0
- package/server/nodes/scraper/apify_actor/meta.json +3 -0
- package/server/nodes/scraper/{crawlee_scraper.py → crawlee_scraper/__init__.py} +96 -57
- package/server/nodes/scraper/crawlee_scraper/meta.json +3 -0
- package/server/nodes/search/{brave_search.py → brave_search/__init__.py} +6 -5
- package/server/nodes/search/brave_search/icon.svg +3 -0
- package/server/nodes/search/brave_search/meta.json +3 -0
- package/server/nodes/search/{duckduckgo_search.py → duckduckgo_search/__init__.py} +17 -6
- package/server/nodes/search/duckduckgo_search/meta.json +3 -0
- package/server/nodes/search/{perplexity_search.py → perplexity_search/__init__.py} +4 -5
- package/server/nodes/search/perplexity_search/icon.svg +3 -0
- package/server/nodes/search/perplexity_search/meta.json +3 -0
- package/server/nodes/search/{serper_search.py → serper_search/__init__.py} +32 -25
- package/server/nodes/search/serper_search/icon.svg +3 -0
- package/server/nodes/search/serper_search/meta.json +3 -0
- package/server/nodes/skill/__init__.py +21 -1
- package/server/nodes/skill/_expander.py +75 -0
- package/server/nodes/skill/{master_skill.py → master_skill/__init__.py} +2 -8
- package/server/nodes/skill/master_skill/_events.py +84 -0
- package/server/nodes/skill/master_skill/meta.json +3 -0
- package/server/nodes/skill/{simple_memory.py → simple_memory/__init__.py} +8 -16
- package/server/nodes/skill/simple_memory/meta.json +3 -0
- package/server/nodes/social/_base.py +223 -231
- package/server/nodes/social/{social_receive.py → social_receive/__init__.py} +38 -13
- package/server/nodes/social/social_receive/meta.json +3 -0
- package/server/nodes/social/{social_send.py → social_send/__init__.py} +71 -29
- package/server/nodes/social/social_send/icon.svg +1 -0
- package/server/nodes/social/social_send/meta.json +3 -0
- package/server/nodes/stripe/__init__.py +7 -3
- package/server/nodes/stripe/_credentials.py +0 -1
- package/server/nodes/stripe/_handlers.py +18 -7
- package/server/nodes/stripe/_install.py +14 -15
- package/server/nodes/stripe/_source.py +5 -5
- package/server/nodes/stripe/icon.svg +1 -0
- package/server/nodes/stripe/meta.json +3 -0
- package/server/nodes/stripe/stripe_action.py +4 -4
- package/server/nodes/stripe/stripe_receive.py +6 -9
- package/server/nodes/telegram/__init__.py +13 -0
- package/server/nodes/telegram/_credentials.py +2 -7
- package/server/nodes/telegram/_events.py +167 -0
- package/server/nodes/telegram/_filters.py +3 -11
- package/server/nodes/telegram/_handlers.py +17 -7
- package/server/nodes/telegram/_refresh.py +24 -34
- package/server/nodes/telegram/_service.py +29 -45
- package/server/nodes/telegram/meta.json +3 -0
- package/server/nodes/telegram/telegram.svg +3 -0
- package/server/nodes/telegram/telegram_receive.py +38 -18
- package/server/nodes/telegram/telegram_send.py +21 -19
- package/server/nodes/text/{file_handler.py → file_handler/__init__.py} +7 -1
- package/server/nodes/text/file_handler/meta.json +3 -0
- package/server/nodes/text/{text_generator.py → text_generator/__init__.py} +2 -1
- package/server/nodes/text/text_generator/meta.json +3 -0
- package/server/nodes/tool/{agent_builder.py → agent_builder/__init__.py} +105 -100
- package/server/nodes/tool/agent_builder/_events.py +91 -0
- package/server/nodes/tool/agent_builder/meta.json +3 -0
- package/server/nodes/tool/{calculator_tool.py → calculator_tool/__init__.py} +19 -7
- package/server/nodes/tool/calculator_tool/meta.json +3 -0
- package/server/nodes/tool/{current_time_tool.py → current_time_tool/__init__.py} +6 -4
- package/server/nodes/tool/current_time_tool/meta.json +3 -0
- package/server/nodes/tool/{task_manager.py → task_manager/__init__.py} +17 -18
- package/server/nodes/tool/task_manager/meta.json +3 -0
- package/server/nodes/tool/{write_todos.py → write_todos/__init__.py} +20 -6
- package/server/nodes/tool/write_todos/meta.json +3 -0
- package/server/nodes/trigger/{chat_trigger.py → chat_trigger/__init__.py} +11 -7
- package/server/nodes/trigger/chat_trigger/_events.py +53 -0
- package/server/nodes/trigger/chat_trigger/meta.json +3 -0
- package/server/nodes/trigger/{task_trigger.py → task_trigger/__init__.py} +10 -7
- package/server/nodes/trigger/task_trigger/meta.json +3 -0
- package/server/nodes/trigger/{webhook_trigger.py → webhook_trigger/__init__.py} +10 -7
- package/server/nodes/trigger/webhook_trigger/_events.py +54 -0
- package/server/nodes/trigger/webhook_trigger/meta.json +3 -0
- package/server/nodes/twitter/__init__.py +7 -1
- package/server/nodes/twitter/_base.py +86 -61
- package/server/nodes/twitter/_credentials.py +7 -5
- package/server/nodes/twitter/_events.py +101 -0
- package/server/nodes/twitter/_filters.py +9 -9
- package/server/nodes/twitter/_handlers.py +3 -1
- package/server/nodes/twitter/_oauth.py +1 -2
- package/server/nodes/twitter/_refresh.py +8 -12
- package/server/nodes/twitter/{twitter_receive.py → twitter_receive/__init__.py} +7 -7
- package/server/nodes/twitter/twitter_receive/icon.svg +1 -0
- package/server/nodes/twitter/twitter_receive/meta.json +3 -0
- package/server/nodes/twitter/{twitter_search.py → twitter_search/__init__.py} +16 -11
- package/server/nodes/twitter/twitter_search/icon.svg +1 -0
- package/server/nodes/twitter/twitter_search/meta.json +3 -0
- package/server/nodes/twitter/{twitter_send.py → twitter_send/__init__.py} +60 -27
- package/server/nodes/twitter/twitter_send/icon.svg +1 -0
- package/server/nodes/twitter/twitter_send/meta.json +3 -0
- package/server/nodes/twitter/{twitter_user.py → twitter_user/__init__.py} +34 -19
- package/server/nodes/twitter/twitter_user/icon.svg +1 -0
- package/server/nodes/twitter/twitter_user/meta.json +3 -0
- package/server/nodes/utility/{console.py → console/__init__.py} +17 -22
- package/server/nodes/utility/console/meta.json +3 -0
- package/server/nodes/utility/{http_request.py → http_request/__init__.py} +9 -6
- package/server/nodes/utility/http_request/meta.json +3 -0
- package/server/nodes/utility/{process_manager.py → process_manager/__init__.py} +10 -6
- package/server/nodes/utility/process_manager/meta.json +3 -0
- package/server/nodes/utility/team_monitor/meta.json +3 -0
- package/server/nodes/utility/{webhook_response.py → webhook_response/__init__.py} +12 -7
- package/server/nodes/utility/webhook_response/meta.json +3 -0
- package/server/nodes/visuals.json +69 -251
- package/server/nodes/whatsapp/__init__.py +24 -0
- package/server/nodes/whatsapp/_base.py +283 -338
- package/server/nodes/whatsapp/_credentials.py +44 -0
- package/server/nodes/whatsapp/_events.py +277 -0
- package/server/nodes/whatsapp/_filters.py +36 -37
- package/server/nodes/whatsapp/_handlers.py +2 -0
- package/server/nodes/whatsapp/_option_loaders.py +1 -3
- package/server/nodes/whatsapp/_refresh.py +13 -18
- package/server/nodes/whatsapp/_runtime.py +9 -6
- package/server/nodes/whatsapp/_service.py +89 -152
- package/server/nodes/whatsapp/meta.json +3 -0
- package/server/nodes/whatsapp/whatsapp_db.py +116 -54
- package/server/nodes/whatsapp/whatsapp_receive.py +30 -13
- package/server/nodes/whatsapp/whatsapp_send.py +60 -37
- package/server/nodes/workflow/{start.py → start/__init__.py} +1 -4
- package/server/nodes/workflow/start/meta.json +3 -0
- package/server/package-lock.json +3 -3
- package/server/package.json +3 -0
- package/server/pyproject.toml +39 -10
- package/server/requirements.txt +3 -5
- package/server/routers/__init__.py +1 -1
- package/server/routers/auth.py +16 -56
- package/server/routers/database.py +27 -50
- package/server/routers/nodejs_compat.py +25 -87
- package/server/routers/schemas.py +66 -2
- package/server/routers/webhook.py +12 -12
- package/server/routers/websocket.py +312 -1716
- package/server/routers/workflow.py +28 -53
- package/server/scripts/smoke_test_skills.py +178 -0
- package/server/services/__init__.py +1 -1
- package/server/services/_supervisor/process.py +9 -3
- package/server/services/_supervisor/registry.py +3 -3
- package/server/services/_supervisor/util.py +1 -1
- package/server/services/agent_team.py +15 -43
- package/server/services/agent_teams/__init__.py +17 -0
- package/server/services/agent_teams/handlers.py +195 -0
- package/server/services/ai.py +853 -1108
- package/server/services/auth.py +10 -34
- package/server/services/chat_client.py +5 -34
- package/server/services/circuit_breaker.py +2 -6
- package/server/services/cli_agent/__init__.py +28 -4
- package/server/services/cli_agent/_cli_auth.py +61 -0
- package/server/services/cli_agent/_handlers.py +24 -183
- package/server/services/cli_agent/config.py +5 -8
- package/server/services/cli_agent/factory.py +168 -22
- package/server/services/cli_agent/jsonl_watcher.py +380 -0
- package/server/services/cli_agent/lockfile.py +9 -2
- package/server/services/cli_agent/mcp_server.py +110 -34
- package/server/services/cli_agent/protocol.py +37 -19
- package/server/services/cli_agent/providers/__init__.py +8 -4
- package/server/services/cli_agent/providers/google_gemini.py +11 -5
- package/server/services/cli_agent/providers/openai_codex.py +34 -34
- package/server/services/cli_agent/service.py +245 -83
- package/server/services/cli_agent/session.py +409 -229
- package/server/services/cli_agent/transports/__init__.py +47 -0
- package/server/services/cli_agent/transports/base.py +111 -0
- package/server/services/cli_agent/transports/posix.py +196 -0
- package/server/services/cli_agent/transports/windows.py +189 -0
- package/server/services/cli_agent/types.py +45 -18
- package/server/services/cli_agent/workflow_tools.py +28 -15
- package/server/services/compaction.py +68 -52
- package/server/services/credential_registry.py +6 -20
- package/server/services/credentials/__init__.py +18 -0
- package/server/services/credentials/handlers.py +196 -0
- package/server/services/deployment/__init__.py +12 -1
- package/server/services/deployment/canary_registry.py +137 -0
- package/server/services/deployment/handlers.py +382 -0
- package/server/services/deployment/manager.py +653 -163
- package/server/services/deployment/poll_registry.py +2 -6
- package/server/services/deployment/state.py +2 -0
- package/server/services/deployment/triggers.py +87 -93
- package/server/services/event_waiter.py +47 -54
- package/server/services/events/__init__.py +11 -0
- package/server/services/events/admin_handlers.py +368 -0
- package/server/services/events/daemon.py +3 -1
- package/server/services/events/dispatch.py +188 -0
- package/server/services/events/envelope.py +264 -45
- package/server/services/events/oauth_lifecycle.py +98 -42
- package/server/services/events/triggers.py +3 -13
- package/server/services/events/verifiers/hmac_basic.py +1 -1
- package/server/services/events/verifiers/standard_webhooks.py +2 -4
- package/server/services/events/webhook.py +2 -3
- package/server/services/example_loader.py +73 -15
- package/server/services/execution/cache.py +36 -76
- package/server/services/execution/conditions.py +7 -20
- package/server/services/execution/dlq.py +20 -24
- package/server/services/execution/executor.py +234 -265
- package/server/services/execution/models.py +40 -46
- package/server/services/execution/recovery.py +23 -46
- package/server/services/handlers/__init__.py +12 -16
- package/server/services/handlers/todo.py +3 -6
- package/server/services/handlers/tools.py +143 -194
- package/server/services/handlers/triggers.py +24 -23
- package/server/services/llm/config.py +10 -1
- package/server/services/llm/factory.py +16 -4
- package/server/services/llm/messages.py +1 -5
- package/server/services/llm/protocol.py +9 -1
- package/server/services/llm/providers/anthropic.py +23 -12
- package/server/services/llm/providers/gemini.py +43 -22
- package/server/services/llm/providers/openai.py +14 -6
- package/server/services/llm/providers/openrouter.py +6 -1
- package/server/services/markdown_formatter.py +1 -2
- package/server/services/memory/__init__.py +2 -2
- package/server/services/memory/jsonl.py +6 -2
- package/server/services/memory/markdown.py +6 -6
- package/server/services/memory/state.py +6 -5
- package/server/services/memory_store.py +8 -12
- package/server/services/model_registry.py +22 -20
- package/server/services/node_executor.py +85 -80
- package/server/services/node_output_schemas.py +4 -7
- package/server/services/node_registry.py +40 -4
- package/server/services/node_spec.py +3 -7
- package/server/services/nodejs_client.py +4 -14
- package/server/services/oauth_utils.py +11 -7
- package/server/services/parameter_resolver.py +30 -36
- package/server/services/plugin/base.py +321 -38
- package/server/services/plugin/connection.py +12 -7
- package/server/services/plugin/credential.py +80 -22
- package/server/services/plugin/edge_walker.py +128 -105
- package/server/services/plugin/identifiers.py +48 -0
- package/server/services/plugin/interceptor.py +1 -1
- package/server/services/plugin/oauth.py +25 -21
- package/server/services/plugin/operation.py +1 -1
- package/server/services/plugin/polling.py +151 -26
- package/server/services/plugin/registry.py +52 -4
- package/server/services/plugin/routing.py +6 -9
- package/server/services/plugin/scaling.py +36 -18
- package/server/services/plugin/service_factories.py +95 -0
- package/server/services/plugin/shutdown_hooks.py +103 -0
- package/server/services/plugin/social_provider_registry.py +80 -0
- package/server/services/plugin/ws.py +2 -1
- package/server/services/pricing.py +26 -40
- package/server/services/pricing_handlers.py +90 -0
- package/server/services/process_service.py +33 -32
- package/server/services/proxy/models.py +15 -9
- package/server/services/proxy/service.py +26 -40
- package/server/services/rlm/adapters.py +43 -40
- package/server/services/rlm/constants.py +9 -9
- package/server/services/rlm/service.py +57 -45
- package/server/services/scheduler.py +8 -39
- package/server/services/settings/__init__.py +16 -0
- package/server/services/settings/handlers.py +275 -0
- package/server/services/skill_loader.py +53 -45
- package/server/services/skill_prompt.py +8 -6
- package/server/services/skills/__init__.py +23 -0
- package/server/services/skills/handlers.py +479 -0
- package/server/services/status_broadcaster.py +314 -291
- package/server/services/temporal/__init__.py +22 -1
- package/server/services/temporal/_handlers.py +65 -0
- package/server/services/temporal/_install.py +158 -0
- package/server/services/temporal/_refresh.py +57 -0
- package/server/services/temporal/_retry_policies.py +85 -0
- package/server/services/temporal/_runtime.py +181 -0
- package/server/services/temporal/_supervised_runtime.py +102 -0
- package/server/services/temporal/activities.py +168 -11
- package/server/services/temporal/agent_activities.py +683 -0
- package/server/services/temporal/agent_workflow.py +601 -0
- package/server/services/temporal/client.py +58 -13
- package/server/services/temporal/executor.py +2 -3
- package/server/services/temporal/plugin_activities.py +37 -2
- package/server/services/temporal/plugin_registry.py +82 -0
- package/server/services/temporal/polling_trigger_workflow.py +267 -0
- package/server/services/temporal/schedules.py +220 -0
- package/server/services/temporal/search_attributes.py +177 -0
- package/server/services/temporal/trigger_listener_workflow.py +378 -0
- package/server/services/temporal/worker.py +111 -18
- package/server/services/temporal/workflow.py +259 -40
- package/server/services/temporal/ws_client.py +22 -11
- package/server/services/text.py +14 -28
- package/server/services/tracked_http.py +29 -49
- package/server/services/user_auth.py +7 -21
- package/server/services/workflow.py +28 -20
- package/server/services/workflow_import.py +351 -0
- package/server/services/workflow_ops.py +4 -0
- package/server/services/workflow_storage/__init__.py +18 -0
- package/server/services/workflow_storage/handlers.py +132 -0
- package/server/services/workflow_validator.py +209 -0
- package/server/services/ws_handler_registry.py +80 -9
- package/server/skills/assistant/agent-builder-skill/SKILL.md +6 -6
- package/server/tests/conftest.py +54 -3
- package/server/tests/credentials/test_auth_service.py +9 -21
- package/server/tests/credentials/test_credential_broadcasts.py +116 -22
- package/server/tests/credentials/test_credentials_database.py +12 -38
- package/server/tests/credentials/test_encryption.py +3 -9
- package/server/tests/credentials/test_google_oauth.py +1 -3
- package/server/tests/credentials/test_oauth_utils.py +31 -38
- package/server/tests/credentials/test_twitter_oauth.py +1 -3
- package/server/tests/credentials/test_websocket_handlers.py +37 -72
- package/server/tests/fixtures/tool_names_snapshot.json +78 -0
- package/server/tests/llm/test_factory.py +12 -4
- package/server/tests/llm/test_providers.py +25 -32
- package/server/tests/llm/test_wiring.py +27 -22
- package/server/tests/nodes/_compat.py +4 -5
- package/server/tests/nodes/_harness.py +31 -24
- package/server/tests/nodes/_mocks.py +2 -6
- package/server/tests/nodes/test_agent_builder.py +43 -35
- package/server/tests/nodes/test_ai_agents.py +29 -24
- package/server/tests/nodes/test_ai_chat_models.py +3 -9
- package/server/tests/nodes/test_ai_tools.py +29 -24
- package/server/tests/nodes/test_android.py +34 -64
- package/server/tests/nodes/test_chat_utility.py +2 -2
- package/server/tests/nodes/test_code_fs_process.py +26 -84
- package/server/tests/nodes/test_document.py +23 -47
- package/server/tests/nodes/test_email.py +88 -51
- package/server/tests/nodes/test_google_workspace.py +26 -20
- package/server/tests/nodes/test_http_proxy.py +43 -89
- package/server/tests/nodes/test_search.py +3 -9
- package/server/tests/nodes/test_specialized_agents.py +58 -162
- package/server/tests/nodes/test_stripe_plugin.py +25 -5
- package/server/tests/nodes/test_telegram_social.py +33 -37
- package/server/tests/nodes/test_twitter.py +59 -150
- package/server/tests/nodes/test_web_automation.py +21 -51
- package/server/tests/nodes/test_whatsapp.py +13 -19
- package/server/tests/nodes/test_workflow_triggers.py +16 -45
- package/server/tests/services/cli_agent/test_claude_session_events.py +201 -0
- package/server/tests/services/cli_agent/test_jsonl_watcher.py +190 -0
- package/server/tests/services/cli_agent/test_mcp_server.py +67 -29
- package/server/tests/services/cli_agent/test_providers.py +236 -47
- package/server/tests/services/cli_agent/test_service.py +9 -7
- package/server/tests/services/memory/test_jsonl.py +30 -25
- package/server/tests/services/test_events.py +26 -7
- package/server/tests/services/test_identifiers.py +122 -0
- package/server/tests/services/test_process_lifecycle.py +129 -0
- package/server/tests/services/test_supervisor.py +0 -1
- package/server/tests/temporal/__init__.py +0 -0
- package/server/tests/temporal/test_agent_workflow.py +215 -0
- package/server/tests/temporal/test_dispatch.py +231 -0
- package/server/tests/test_admin_handlers.py +394 -0
- package/server/tests/test_auto_skill.py +4 -2
- package/server/tests/test_canary_registry.py +310 -0
- package/server/tests/test_chat_trigger_canary_producer.py +101 -0
- package/server/tests/test_cloudevents_node_parameters.py +129 -0
- package/server/tests/test_credential_icon.py +115 -0
- package/server/tests/test_cron_canary.py +511 -0
- package/server/tests/test_deployment_canary_listener.py +692 -0
- package/server/tests/test_event_framework_phase_a.py +537 -0
- package/server/tests/test_no_raw_prints.py +131 -0
- package/server/tests/test_node_spec.py +196 -103
- package/server/tests/test_parameter_resolver.py +20 -20
- package/server/tests/test_plugin_contract.py +76 -49
- package/server/tests/test_plugin_helpers.py +0 -1
- package/server/tests/test_plugin_self_containment.py +40 -47
- package/server/tests/test_polling_trigger_workflow.py +572 -0
- package/server/tests/test_retry_policies.py +146 -0
- package/server/tests/test_service_factories.py +168 -0
- package/server/tests/test_shutdown_hooks.py +199 -0
- package/server/tests/test_social_provider_registry.py +177 -0
- package/server/tests/test_status_broadcasts.py +214 -63
- package/server/tests/test_task_trigger_canary_producer.py +131 -0
- package/server/tests/test_telegram_trigger_canary_producer.py +113 -0
- package/server/tests/test_tool_registry.py +110 -0
- package/server/tests/test_trigger_listener_workflow.py +365 -0
- package/server/tests/test_whatsapp_trigger_canary_producer.py +164 -0
- package/server/tests/test_workflow_ops.py +1 -3
- package/server/tests/test_workflow_validator.py +791 -0
- package/server/uv.lock +3539 -0
- package/client/dist/assets/index-DQ0nwhec.js +0 -257
- package/client/src/assets/icons/apify/index.ts +0 -19
- package/client/src/assets/icons/browser/index.ts +0 -17
- package/client/src/assets/icons/email/index.ts +0 -22
- package/client/src/assets/icons/google/index.ts +0 -34
- package/client/src/assets/icons/llm/deepseek.svg +0 -1
- package/client/src/assets/icons/llm/index.ts +0 -18
- package/client/src/assets/icons/llm/kimi.svg +0 -1
- package/client/src/assets/icons/llm/mistral.svg +0 -1
- package/client/src/assets/icons/search/index.ts +0 -28
- package/client/src/assets/icons/telegram/index.ts +0 -19
- package/machina/buildenv.py +0 -44
- package/machina/cli.py +0 -55
- package/machina/commands/__init__.py +0 -1
- package/machina/commands/clean.py +0 -80
- package/machina/commands/daemon.py +0 -150
- package/machina/config.py +0 -93
- package/machina/platform_.py +0 -37
- package/machina/pyproject.toml +0 -33
- package/server/nodes/agent/deep_agent.py +0 -103
- package/server/services/agents/__init__.py +0 -9
- package/server/services/agents/adapters.py +0 -199
- package/server/services/agents/constants.py +0 -10
- package/server/services/agents/service.py +0 -297
- package/server/services/cli_agent/providers/anthropic_claude.py +0 -419
- /package/{machina → cli}/README.md +0 -0
- /package/{machina → cli}/__init__.py +0 -0
- /package/{client/src/assets/icons/apify → server/credentials/icons}/apify.svg +0 -0
- /package/{client/src/assets/icons/search/brave.svg → server/credentials/icons/brave_search.svg} +0 -0
- /package/{client/src/assets/icons/email/read.svg → server/credentials/icons/email_himalaya.svg} +0 -0
- /package/{client/src/assets/icons/search → server/credentials/icons}/perplexity.svg +0 -0
- /package/{client/src/assets/icons/search/google.svg → server/credentials/icons/serper.svg} +0 -0
- /package/{client/src/assets → server/credentials}/icons/stripe.svg +0 -0
- /package/{client/src/assets/icons/twitter/x.svg → server/credentials/icons/twitter.svg} +0 -0
- /package/{client/src/assets/icons/browser/chrome.svg → server/nodes/browser/browser/icon.svg} +0 -0
- /package/{client/src/assets/icons/chat/chat.svg → server/nodes/chat/chat_history/icon.svg} +0 -0
- /package/{client/src/assets/icons/code/javascript.svg → server/nodes/code/javascript_executor/icon.svg} +0 -0
- /package/{client/src/assets/icons/code/python.svg → server/nodes/code/python_executor/icon.svg} +0 -0
- /package/{client/src/assets/icons/code/typescript.svg → server/nodes/code/typescript_executor/icon.svg} +0 -0
- /package/{client/src/assets/icons/email/receive.svg → server/nodes/email/email_receive/icon.svg} +0 -0
- /package/{client/src/assets/icons/email/send.svg → server/nodes/email/email_send/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/calendar.svg → server/nodes/google/calendar/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/contacts.svg → server/nodes/google/contacts/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/drive.svg → server/nodes/google/drive/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/gmail.svg → server/nodes/google/gmail/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/sheets.svg → server/nodes/google/sheets/icon.svg} +0 -0
- /package/{client/src/assets/icons/google/tasks.svg → server/nodes/google/tasks/icon.svg} +0 -0
- /package/{client/src/assets/icons/search/duckduckgo.svg → server/nodes/search/duckduckgo_search/icon.svg} +0 -0
- /package/{client/src/assets/icons/social/social.svg → server/nodes/social/social_receive/icon.svg} +0 -0
- /package/{client/src/assets/icons/telegram/telegram.svg → server/nodes/telegram/icon.svg} +0 -0
- /package/server/nodes/utility/{team_monitor.py → team_monitor/__init__.py} +0 -0
- /package/{client/src/assets/icons/whatsapp/whatsapp-db.svg → server/nodes/whatsapp/icon_whatsappDb.svg} +0 -0
- /package/{client/src/assets/icons/whatsapp/whatsapp-receive.svg → server/nodes/whatsapp/icon_whatsappReceive.svg} +0 -0
- /package/{client/src/assets/icons/whatsapp/whatsapp-send.svg → server/nodes/whatsapp/icon_whatsappSend.svg} +0 -0
- /package/{client/src/assets/icons → server/nodes}/whatsapp/whatsapp.svg +0 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
"""Wave 12 C1 (canary): long-lived Temporal workflow that owns a trigger's wait.
|
|
2
|
+
|
|
3
|
+
One :class:`TriggerListenerWorkflow` runs per (deployment, event-trigger)
|
|
4
|
+
pair. It survives FastAPI process restarts because Temporal replays its
|
|
5
|
+
state from Event History — the durability gap that the in-process
|
|
6
|
+
``services/deployment/triggers.py:setup_event_trigger`` collector/processor
|
|
7
|
+
``asyncio.Task`` pair leaves open.
|
|
8
|
+
|
|
9
|
+
Flow per signal:
|
|
10
|
+
|
|
11
|
+
1. ``dispatch.emit(event)`` runs a Visibility query
|
|
12
|
+
``EventType='<type>' AND ExecutionStatus='Running'`` and signals each
|
|
13
|
+
matching listener (this class) with ``on_event``.
|
|
14
|
+
2. ``on_event`` dedups by ``event.id`` (per-run state, reconstructed
|
|
15
|
+
deterministically from Event History on replay) and queues the
|
|
16
|
+
payload.
|
|
17
|
+
3. The main ``run`` loop ``wait_condition``s for any queued event, pops
|
|
18
|
+
the head, builds the filtered downstream graph, and starts a child
|
|
19
|
+
:class:`MachinaWorkflow` with the trigger node marked ``_pre_executed``.
|
|
20
|
+
4. Child workflow uses ``parent_close_policy=ABANDON`` so listener
|
|
21
|
+
cancellation never kills in-flight execution runs.
|
|
22
|
+
|
|
23
|
+
Canary scope (2026-05-14): only ``webhookTrigger`` ships with this
|
|
24
|
+
wiring on the deployment-manager side. Other trigger types stay on the
|
|
25
|
+
legacy collector/processor path until the canary proves out. The
|
|
26
|
+
workflow itself is type-agnostic — the listener treats the event
|
|
27
|
+
payload as opaque and the filter shape is provided by the deployment
|
|
28
|
+
at workflow start.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
from datetime import timedelta
|
|
34
|
+
from typing import Any, Dict, List, Optional, Set
|
|
35
|
+
|
|
36
|
+
from temporalio import workflow
|
|
37
|
+
from temporalio.common import WorkflowIDReusePolicy
|
|
38
|
+
from temporalio.workflow import ParentClosePolicy
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# 50K events is the Temporal Event-History soft ceiling per the
|
|
42
|
+
# very-long-running-workflows blog post — past it the workflow
|
|
43
|
+
# spends more time replaying history than doing work. The listener
|
|
44
|
+
# does ~2-3 events per inbound trigger (signal accept + child spawn),
|
|
45
|
+
# so this caps at ~16K triggers between continueAsNew checkpoints.
|
|
46
|
+
# Per-event histogram is empirical; tune later.
|
|
47
|
+
_MAX_EVENTS_BEFORE_CONTINUE_AS_NEW = 16_000
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@workflow.defn(name="TriggerListenerWorkflow", sandboxed=False)
|
|
51
|
+
class TriggerListenerWorkflow:
|
|
52
|
+
"""Long-lived listener that funnels signals into child MachinaWorkflow runs.
|
|
53
|
+
|
|
54
|
+
Determinism note: all state lives on ``self`` and is reconstructed
|
|
55
|
+
from Event History on replay. The ``_seen_event_ids`` set drains
|
|
56
|
+
on ``continueAsNew`` (intentional — different listener runs are
|
|
57
|
+
different consumers).
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self) -> None:
|
|
61
|
+
self._seen_event_ids: Set[str] = set()
|
|
62
|
+
self._matched_events: List[Dict[str, Any]] = []
|
|
63
|
+
self._processed_count: int = 0
|
|
64
|
+
|
|
65
|
+
@workflow.signal
|
|
66
|
+
async def on_event(self, event_payload: Dict[str, Any]) -> None:
|
|
67
|
+
"""Receive an event from ``services.events.dispatch.emit``.
|
|
68
|
+
|
|
69
|
+
Same shape + dedup contract as :meth:`MachinaWorkflow.on_event`.
|
|
70
|
+
Malformed payloads (missing ``id``) are dropped — every other
|
|
71
|
+
path mints an id at envelope construction, so missing-id means
|
|
72
|
+
a producer wired itself wrong.
|
|
73
|
+
"""
|
|
74
|
+
event_id = event_payload.get("id")
|
|
75
|
+
if not event_id:
|
|
76
|
+
workflow.logger.warning("TriggerListener.on_event: skipping malformed envelope without 'id'")
|
|
77
|
+
return
|
|
78
|
+
if event_id in self._seen_event_ids:
|
|
79
|
+
workflow.logger.debug(f"TriggerListener.on_event: dedup hit for event.id={event_id}")
|
|
80
|
+
return
|
|
81
|
+
self._seen_event_ids.add(event_id)
|
|
82
|
+
self._matched_events.append(event_payload)
|
|
83
|
+
|
|
84
|
+
@workflow.run
|
|
85
|
+
async def run(self, listener_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
86
|
+
"""Loop forever spawning a child :class:`MachinaWorkflow` per matched event.
|
|
87
|
+
|
|
88
|
+
``listener_data`` shape (deployment-supplied):
|
|
89
|
+
{
|
|
90
|
+
"workflow_id": str, # MachinaOs deployment workflow_id
|
|
91
|
+
"trigger_node_id": str, # node id that "fires" on each event
|
|
92
|
+
"node_type": str, # e.g. "webhookTrigger"
|
|
93
|
+
"event_type": str, # e.g. "com.machinaos.webhook.received"
|
|
94
|
+
"filter_params": Dict, # used by the event-side filter via dispatch.emit
|
|
95
|
+
"nodes": List[Dict], # full deployment graph snapshot
|
|
96
|
+
"edges": List[Dict],
|
|
97
|
+
"session_id": str,
|
|
98
|
+
"tenant_id": Optional[str],
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Returns when ``continueAsNew`` fires — the new run picks up
|
|
102
|
+
immediately under the same workflow-id. Cancellation by the
|
|
103
|
+
deployment manager cancels the workflow normally.
|
|
104
|
+
"""
|
|
105
|
+
workflow.logger.info(
|
|
106
|
+
f"TriggerListener started: workflow_id={listener_data.get('workflow_id')} "
|
|
107
|
+
f"node={listener_data.get('trigger_node_id')} "
|
|
108
|
+
f"event_type={listener_data.get('event_type')}"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
while True:
|
|
112
|
+
await workflow.wait_condition(lambda: bool(self._matched_events))
|
|
113
|
+
event = self._matched_events.pop(0) if self._matched_events else None
|
|
114
|
+
if event is None:
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
await self._spawn_child_run(event, listener_data)
|
|
119
|
+
except Exception as exc: # noqa: BLE001
|
|
120
|
+
# Per-event spawn failures don't kill the listener.
|
|
121
|
+
# Log and move on; the rejected event still counts as
|
|
122
|
+
# "seen" so a producer retry with the same id won't
|
|
123
|
+
# re-fire (correct: server-side dedup applies even on
|
|
124
|
+
# downstream failure).
|
|
125
|
+
workflow.logger.error(f"TriggerListener spawn failed for event.id={event.get('id')}: {exc}")
|
|
126
|
+
|
|
127
|
+
self._processed_count += 1
|
|
128
|
+
if self._processed_count >= _MAX_EVENTS_BEFORE_CONTINUE_AS_NEW:
|
|
129
|
+
workflow.logger.info(f"TriggerListener continue_as_new: processed={self._processed_count}")
|
|
130
|
+
workflow.continue_as_new(args=[listener_data])
|
|
131
|
+
|
|
132
|
+
async def _spawn_child_run(
|
|
133
|
+
self,
|
|
134
|
+
event: Dict[str, Any],
|
|
135
|
+
listener_data: Dict[str, Any],
|
|
136
|
+
) -> None:
|
|
137
|
+
"""Build the filtered downstream graph + start a child MachinaWorkflow.
|
|
138
|
+
|
|
139
|
+
The trigger node is marked ``_pre_executed=True`` with the event
|
|
140
|
+
envelope's ``data`` payload as its output. Sibling triggers in
|
|
141
|
+
the same deployment are marked ``_pre_executed=True`` with
|
|
142
|
+
``{not_triggered: True}`` so MachinaWorkflow doesn't block on
|
|
143
|
+
them (mirrors ``DeploymentManager._execute_from_trigger``).
|
|
144
|
+
|
|
145
|
+
Status broadcast lifecycle (matches legacy
|
|
146
|
+
``deployment/triggers.py`` collector/processor):
|
|
147
|
+
- Before spawn → trigger node ``"idle"`` with "Graph executing..."
|
|
148
|
+
- After spawn returns → trigger node ``"waiting"`` (child runs
|
|
149
|
+
independently per ``parent_close_policy=ABANDON``).
|
|
150
|
+
"""
|
|
151
|
+
trigger_node_id = listener_data["trigger_node_id"]
|
|
152
|
+
nodes = listener_data["nodes"]
|
|
153
|
+
edges = listener_data["edges"]
|
|
154
|
+
session_id = listener_data.get("session_id", "default")
|
|
155
|
+
workflow_id = listener_data.get("workflow_id")
|
|
156
|
+
tenant_id = listener_data.get("tenant_id")
|
|
157
|
+
|
|
158
|
+
# event.data is the producer-supplied payload (webhook body /
|
|
159
|
+
# message details / etc.). The full envelope (specversion, type,
|
|
160
|
+
# subject, …) stays in event for any downstream introspection
|
|
161
|
+
# via the agent layer, but the trigger output is the data dict.
|
|
162
|
+
trigger_output = event.get("data") if isinstance(event.get("data"), dict) else {}
|
|
163
|
+
trigger_output = {**trigger_output, "_event_envelope": event}
|
|
164
|
+
|
|
165
|
+
filtered_nodes, filtered_edges = _build_run_graph(
|
|
166
|
+
trigger_node_id=trigger_node_id,
|
|
167
|
+
trigger_output=trigger_output,
|
|
168
|
+
nodes=nodes,
|
|
169
|
+
edges=edges,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Stable child workflow ID derived from event.id gives free
|
|
173
|
+
# idempotency via WorkflowIDReusePolicy.ALLOW_DUPLICATE_FAILED_ONLY:
|
|
174
|
+
# if the same event.id arrives twice (producer retry across
|
|
175
|
+
# listener restart), Temporal rejects the duplicate start.
|
|
176
|
+
# Lazy fallback to workflow.uuid4() only if event.id is missing
|
|
177
|
+
# (shouldn't happen — on_event drops malformed payloads).
|
|
178
|
+
event_id = event.get("id") or workflow.uuid4().hex
|
|
179
|
+
child_id = f"run-{workflow_id}-{event_id}"
|
|
180
|
+
|
|
181
|
+
await _broadcast_trigger_idle(
|
|
182
|
+
node_id=trigger_node_id,
|
|
183
|
+
workflow_id=workflow_id,
|
|
184
|
+
event_id=event_id,
|
|
185
|
+
event_type=event.get("type", ""),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
await workflow.start_child_workflow(
|
|
189
|
+
"MachinaWorkflow",
|
|
190
|
+
args=[
|
|
191
|
+
{
|
|
192
|
+
"nodes": filtered_nodes,
|
|
193
|
+
"edges": filtered_edges,
|
|
194
|
+
"session_id": session_id,
|
|
195
|
+
"workflow_id": workflow_id,
|
|
196
|
+
"tenant_id": tenant_id,
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
id=child_id,
|
|
200
|
+
parent_close_policy=ParentClosePolicy.ABANDON,
|
|
201
|
+
id_reuse_policy=WorkflowIDReusePolicy.ALLOW_DUPLICATE_FAILED_ONLY,
|
|
202
|
+
execution_timeout=timedelta(hours=1),
|
|
203
|
+
run_timeout=timedelta(hours=1),
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
workflow.logger.info(
|
|
207
|
+
f"TriggerListener spawned child run: child_id={child_id} " f"event.id={event.get('id')} event.type={event.get('type')}"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
await _broadcast_trigger_waiting(
|
|
211
|
+
node_id=trigger_node_id,
|
|
212
|
+
workflow_id=workflow_id,
|
|
213
|
+
event_type=listener_data.get("event_type", ""),
|
|
214
|
+
processed_count=self._processed_count + 1,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
# Status-broadcast helpers — thin wrappers around the activity so the
|
|
220
|
+
# spawn loop reads cleanly. Activity name string matches the @activity.defn
|
|
221
|
+
# registration in services/temporal/activities.py.
|
|
222
|
+
# ---------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
_STATUS_ACTIVITY_NAME = "broadcast_trigger_status_activity"
|
|
226
|
+
_STATUS_ACTIVITY_TIMEOUT = timedelta(seconds=5)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
async def _broadcast_trigger_idle(
|
|
230
|
+
*,
|
|
231
|
+
node_id: str,
|
|
232
|
+
workflow_id: Optional[str],
|
|
233
|
+
event_id: str,
|
|
234
|
+
event_type: str,
|
|
235
|
+
) -> None:
|
|
236
|
+
"""Broadcast trigger node ``"idle"`` status with a "Graph executing..."
|
|
237
|
+
message — matches the legacy collector/processor transition so FE
|
|
238
|
+
shows a firing pulse instead of a stuck "waiting" indicator."""
|
|
239
|
+
await workflow.execute_activity(
|
|
240
|
+
_STATUS_ACTIVITY_NAME,
|
|
241
|
+
{
|
|
242
|
+
"node_id": node_id,
|
|
243
|
+
"status": "idle",
|
|
244
|
+
"data": {
|
|
245
|
+
"message": "Graph executing...",
|
|
246
|
+
"is_processing": True,
|
|
247
|
+
"event_id": event_id,
|
|
248
|
+
"event_type": event_type,
|
|
249
|
+
},
|
|
250
|
+
"workflow_id": workflow_id,
|
|
251
|
+
},
|
|
252
|
+
start_to_close_timeout=_STATUS_ACTIVITY_TIMEOUT,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
async def _broadcast_trigger_waiting(
|
|
257
|
+
*,
|
|
258
|
+
node_id: str,
|
|
259
|
+
workflow_id: Optional[str],
|
|
260
|
+
event_type: str,
|
|
261
|
+
processed_count: int,
|
|
262
|
+
) -> None:
|
|
263
|
+
"""Broadcast trigger node back to ``"waiting"`` after the child run
|
|
264
|
+
has been spawned (child completes independently per
|
|
265
|
+
``parent_close_policy=ABANDON``)."""
|
|
266
|
+
await workflow.execute_activity(
|
|
267
|
+
_STATUS_ACTIVITY_NAME,
|
|
268
|
+
{
|
|
269
|
+
"node_id": node_id,
|
|
270
|
+
"status": "waiting",
|
|
271
|
+
"data": {
|
|
272
|
+
"message": "Waiting for next event...",
|
|
273
|
+
"is_processing": False,
|
|
274
|
+
"event_type": event_type,
|
|
275
|
+
"processed_count": processed_count,
|
|
276
|
+
},
|
|
277
|
+
"workflow_id": workflow_id,
|
|
278
|
+
},
|
|
279
|
+
start_to_close_timeout=_STATUS_ACTIVITY_TIMEOUT,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# ---------------------------------------------------------------------------
|
|
284
|
+
# Pure graph builder — kept in this module on purpose: the only consumer is
|
|
285
|
+
# this workflow class, and inlining keeps the import surface deterministic
|
|
286
|
+
# (workflow.defn(sandboxed=False) still benefits from minimal imports).
|
|
287
|
+
# Mirrors the logic in DeploymentManager._execute_from_trigger + ._get_downstream_nodes
|
|
288
|
+
# but specialised for the listener's "trigger fires once, spawn run" path.
|
|
289
|
+
# ---------------------------------------------------------------------------
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _build_run_graph(
|
|
293
|
+
*,
|
|
294
|
+
trigger_node_id: str,
|
|
295
|
+
trigger_output: Dict[str, Any],
|
|
296
|
+
nodes: List[Dict[str, Any]],
|
|
297
|
+
edges: List[Dict[str, Any]],
|
|
298
|
+
) -> tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
|
|
299
|
+
"""Build filtered (nodes, edges) for one execution run.
|
|
300
|
+
|
|
301
|
+
Marks the firing trigger ``_pre_executed=True`` with ``trigger_output``;
|
|
302
|
+
marks sibling triggers ``_pre_executed=True`` with ``{not_triggered:
|
|
303
|
+
True}`` so MachinaWorkflow doesn't try to wait on them.
|
|
304
|
+
"""
|
|
305
|
+
from constants import (
|
|
306
|
+
AI_AGENT_TYPES,
|
|
307
|
+
TOOLKIT_NODE_TYPES,
|
|
308
|
+
WORKFLOW_TRIGGER_TYPES,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
node_types = {n["id"]: n.get("type", "") for n in nodes}
|
|
312
|
+
|
|
313
|
+
downstream_ids: Set[str] = set()
|
|
314
|
+
|
|
315
|
+
def _collect(current_id: str) -> None:
|
|
316
|
+
for edge in edges:
|
|
317
|
+
if edge.get("source") != current_id:
|
|
318
|
+
continue
|
|
319
|
+
target_id = edge.get("target")
|
|
320
|
+
if not target_id or target_id in downstream_ids:
|
|
321
|
+
continue
|
|
322
|
+
target_type = node_types.get(target_id, "")
|
|
323
|
+
if target_type in WORKFLOW_TRIGGER_TYPES:
|
|
324
|
+
# Stop at trigger nodes — independent event listeners.
|
|
325
|
+
continue
|
|
326
|
+
downstream_ids.add(target_id)
|
|
327
|
+
_collect(target_id)
|
|
328
|
+
|
|
329
|
+
_collect(trigger_node_id)
|
|
330
|
+
|
|
331
|
+
# Config nodes (memory, tools, etc.) connected to downstream nodes.
|
|
332
|
+
for edge in edges:
|
|
333
|
+
target = edge.get("target")
|
|
334
|
+
source = edge.get("source")
|
|
335
|
+
handle = edge.get("targetHandle", "")
|
|
336
|
+
is_config = handle and handle.startswith("input-") and handle != "input-main"
|
|
337
|
+
if is_config and target in downstream_ids and source not in downstream_ids:
|
|
338
|
+
if node_types.get(source, "") in WORKFLOW_TRIGGER_TYPES:
|
|
339
|
+
continue
|
|
340
|
+
downstream_ids.add(source)
|
|
341
|
+
|
|
342
|
+
# Sub-nodes connected to toolkit nodes (n8n Sub-Node pattern).
|
|
343
|
+
toolkit_ids = {n["id"] for n in nodes if n.get("type") in TOOLKIT_NODE_TYPES and n["id"] in downstream_ids}
|
|
344
|
+
for edge in edges:
|
|
345
|
+
target = edge.get("target")
|
|
346
|
+
source = edge.get("source")
|
|
347
|
+
if target in toolkit_ids and source not in downstream_ids:
|
|
348
|
+
downstream_ids.add(source)
|
|
349
|
+
|
|
350
|
+
# Tool nodes connected to AI Agent's input-tools handle.
|
|
351
|
+
agent_ids = {n["id"] for n in nodes if n.get("type") in AI_AGENT_TYPES and n["id"] in downstream_ids}
|
|
352
|
+
for edge in edges:
|
|
353
|
+
target = edge.get("target")
|
|
354
|
+
source = edge.get("source")
|
|
355
|
+
if target in agent_ids and edge.get("targetHandle", "") == "input-tools" and source not in downstream_ids:
|
|
356
|
+
downstream_ids.add(source)
|
|
357
|
+
|
|
358
|
+
run_filter = {trigger_node_id} | downstream_ids
|
|
359
|
+
filtered_nodes: List[Dict[str, Any]] = []
|
|
360
|
+
for node in nodes:
|
|
361
|
+
if node["id"] not in run_filter:
|
|
362
|
+
continue
|
|
363
|
+
node_copy = dict(node)
|
|
364
|
+
node_type = node.get("type", "")
|
|
365
|
+
if node["id"] == trigger_node_id:
|
|
366
|
+
node_copy["_pre_executed"] = True
|
|
367
|
+
node_copy["_trigger_output"] = trigger_output
|
|
368
|
+
elif node_type in WORKFLOW_TRIGGER_TYPES:
|
|
369
|
+
node_copy["_pre_executed"] = True
|
|
370
|
+
node_copy["_trigger_output"] = {"not_triggered": True}
|
|
371
|
+
filtered_nodes.append(node_copy)
|
|
372
|
+
|
|
373
|
+
filtered_edges = [e for e in edges if e.get("source") in run_filter and e.get("target") in run_filter]
|
|
374
|
+
|
|
375
|
+
return filtered_nodes, filtered_edges
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
__all__ = ["TriggerListenerWorkflow", "_build_run_graph"]
|
|
@@ -16,6 +16,7 @@ References:
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
import asyncio
|
|
19
|
+
from datetime import timedelta
|
|
19
20
|
from typing import Optional
|
|
20
21
|
|
|
21
22
|
import aiohttp
|
|
@@ -26,6 +27,9 @@ from temporalio.worker import Worker
|
|
|
26
27
|
|
|
27
28
|
from core.logging import get_logger
|
|
28
29
|
from .workflow import MachinaWorkflow
|
|
30
|
+
from .trigger_listener_workflow import TriggerListenerWorkflow
|
|
31
|
+
from .polling_trigger_workflow import PollingTriggerWorkflow
|
|
32
|
+
from .plugin_registry import temporal_plugins
|
|
29
33
|
from .activities import (
|
|
30
34
|
NodeExecutionActivities,
|
|
31
35
|
create_shared_session,
|
|
@@ -35,6 +39,18 @@ logger = get_logger(__name__)
|
|
|
35
39
|
tracer = trace.get_tracer(__name__)
|
|
36
40
|
|
|
37
41
|
|
|
42
|
+
def _graceful_shutdown_timeout() -> timedelta:
|
|
43
|
+
"""Wave 12 A3: SIGTERM grace window for Temporal workers.
|
|
44
|
+
|
|
45
|
+
Read from ``Settings.temporal_graceful_shutdown_seconds`` at the
|
|
46
|
+
moment each Worker is instantiated (rather than module load) so
|
|
47
|
+
test fixtures + env reloads pick up overrides.
|
|
48
|
+
"""
|
|
49
|
+
from core.config import Settings
|
|
50
|
+
|
|
51
|
+
return timedelta(seconds=Settings().temporal_graceful_shutdown_seconds)
|
|
52
|
+
|
|
53
|
+
|
|
38
54
|
def create_runtime() -> Runtime:
|
|
39
55
|
"""Create a Temporal runtime with worker heartbeating disabled.
|
|
40
56
|
|
|
@@ -101,26 +117,78 @@ class TemporalWorkerManager:
|
|
|
101
117
|
# Create activity instance with shared session
|
|
102
118
|
self._activities = NodeExecutionActivities(self._session)
|
|
103
119
|
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
120
|
+
# F4.A: register per-type activities alongside the legacy
|
|
121
|
+
# `execute_node_activity` dispatcher. The orchestrator at
|
|
122
|
+
# workflow.py:_resolve_activity picks one of the two paths per node
|
|
123
|
+
# based on the temporal_per_type_dispatch flag; both must be served
|
|
124
|
+
# by the worker. Per-type activities register WITHOUT a task_queue
|
|
125
|
+
# filter (cls.task_queue is the *declared* preference; the single
|
|
126
|
+
# worker actually polls self.task_queue regardless). When
|
|
127
|
+
# TemporalWorkerPool is wired (future enhancement), per-queue
|
|
128
|
+
# filtering will move there. Registration cost: ~1.6s startup;
|
|
129
|
+
# zero runtime cost when the flag is off (orchestrator routes to
|
|
130
|
+
# execute_node_activity, per-type entries sit idle).
|
|
131
|
+
#
|
|
132
|
+
# F4.B: register AgentWorkflow + its three activities
|
|
133
|
+
# (execute_llm_step / persist_turn / compact_memory). The
|
|
134
|
+
# orchestrator schedules AgentWorkflow as a child workflow
|
|
135
|
+
# for the 15 migrating agent types when
|
|
136
|
+
# ``temporal_agent_workflow_enabled`` is on.
|
|
137
|
+
from services.temporal.plugin_activities import (
|
|
138
|
+
collect_plugin_activities,
|
|
139
|
+
collect_polling_activities,
|
|
140
|
+
)
|
|
141
|
+
from services.temporal.agent_activities import collect_agent_activities
|
|
142
|
+
from services.temporal.agent_workflow import AgentWorkflow
|
|
143
|
+
from services.temporal.activities import (
|
|
144
|
+
broadcast_trigger_status_activity,
|
|
145
|
+
store_node_output_activity,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
per_type = collect_plugin_activities() # no queue filter; all plugins
|
|
149
|
+
agent_activities = collect_agent_activities()
|
|
150
|
+
polling_activities = collect_polling_activities()
|
|
151
|
+
# Plugin-owned workflow classes (e.g. cron's
|
|
152
|
+
# CronTriggerWorkflow) self-register a SimplePlugin via
|
|
153
|
+
# services.temporal.plugin_registry.register_temporal_plugin
|
|
154
|
+
# from their plugin __init__.py. The Temporal SDK's plugin
|
|
155
|
+
# chain merges each registered plugin's workflows / activities
|
|
156
|
+
# / interceptors into the effective worker configuration —
|
|
157
|
+
# the framework worker stays plugin-agnostic.
|
|
158
|
+
plugin_list = temporal_plugins()
|
|
111
159
|
self._worker = Worker(
|
|
112
160
|
self.client,
|
|
113
161
|
task_queue=self.task_queue,
|
|
114
|
-
|
|
115
|
-
|
|
162
|
+
plugins=plugin_list,
|
|
163
|
+
workflows=[
|
|
164
|
+
MachinaWorkflow,
|
|
165
|
+
AgentWorkflow,
|
|
166
|
+
TriggerListenerWorkflow,
|
|
167
|
+
PollingTriggerWorkflow,
|
|
168
|
+
],
|
|
169
|
+
activities=[
|
|
170
|
+
self._activities.execute_node_activity,
|
|
171
|
+
broadcast_trigger_status_activity,
|
|
172
|
+
store_node_output_activity,
|
|
173
|
+
*per_type,
|
|
174
|
+
*agent_activities,
|
|
175
|
+
*polling_activities,
|
|
176
|
+
],
|
|
116
177
|
# Allow concurrent activity execution for parallel branches
|
|
117
178
|
max_concurrent_activities=self.pool_size,
|
|
118
179
|
max_concurrent_workflow_tasks=10,
|
|
180
|
+
graceful_shutdown_timeout=_graceful_shutdown_timeout(),
|
|
181
|
+
)
|
|
182
|
+
logger.info(
|
|
183
|
+
"Registered Temporal activities",
|
|
184
|
+
legacy=1,
|
|
185
|
+
per_type=len(per_type),
|
|
186
|
+
agent=len(agent_activities),
|
|
187
|
+
task_queue=self.task_queue,
|
|
119
188
|
)
|
|
120
189
|
span.set_attribute("task_queue", self.task_queue)
|
|
121
190
|
span.set_attribute("pool_size", self.pool_size)
|
|
122
191
|
|
|
123
|
-
print(f"[Temporal] Worker started (queue={self.task_queue}, pool={self.pool_size})", flush=True)
|
|
124
192
|
logger.info(
|
|
125
193
|
"Starting Temporal worker",
|
|
126
194
|
task_queue=self.task_queue,
|
|
@@ -246,14 +314,12 @@ class TemporalWorkerPool:
|
|
|
246
314
|
activities=activities,
|
|
247
315
|
max_concurrent_activities=concurrency,
|
|
248
316
|
max_concurrent_workflow_tasks=10,
|
|
317
|
+
graceful_shutdown_timeout=_graceful_shutdown_timeout(),
|
|
249
318
|
)
|
|
250
319
|
task = asyncio.create_task(worker.run(), name=f"worker-{queue}")
|
|
251
320
|
self._workers.append(worker)
|
|
252
321
|
self._tasks.append(task)
|
|
253
|
-
logger.info(
|
|
254
|
-
f"[Pool] Started worker queue={queue!r} "
|
|
255
|
-
f"activities={len(activities)} concurrency={concurrency}"
|
|
256
|
-
)
|
|
322
|
+
logger.info(f"[Pool] Started worker queue={queue!r} " f"activities={len(activities)} concurrency={concurrency}")
|
|
257
323
|
|
|
258
324
|
async def stop(self) -> None:
|
|
259
325
|
for task in self._tasks:
|
|
@@ -321,14 +387,28 @@ async def run_standalone_worker(
|
|
|
321
387
|
session = await create_shared_session(pool_size)
|
|
322
388
|
activities = NodeExecutionActivities(session)
|
|
323
389
|
|
|
390
|
+
from services.temporal.activities import (
|
|
391
|
+
broadcast_trigger_status_activity,
|
|
392
|
+
store_node_output_activity,
|
|
393
|
+
)
|
|
394
|
+
|
|
324
395
|
try:
|
|
325
396
|
worker = Worker(
|
|
326
397
|
client,
|
|
327
398
|
task_queue=task_queue,
|
|
328
|
-
workflows=[
|
|
329
|
-
|
|
399
|
+
workflows=[
|
|
400
|
+
MachinaWorkflow,
|
|
401
|
+
TriggerListenerWorkflow,
|
|
402
|
+
PollingTriggerWorkflow,
|
|
403
|
+
],
|
|
404
|
+
activities=[
|
|
405
|
+
activities.execute_node_activity,
|
|
406
|
+
broadcast_trigger_status_activity,
|
|
407
|
+
store_node_output_activity,
|
|
408
|
+
],
|
|
330
409
|
max_concurrent_activities=pool_size,
|
|
331
410
|
max_concurrent_workflow_tasks=10,
|
|
411
|
+
graceful_shutdown_timeout=_graceful_shutdown_timeout(),
|
|
332
412
|
)
|
|
333
413
|
|
|
334
414
|
logger.info("Worker running. Press Ctrl+C to stop.")
|
|
@@ -359,14 +439,27 @@ async def create_worker(
|
|
|
359
439
|
session = await create_shared_session()
|
|
360
440
|
|
|
361
441
|
activities = NodeExecutionActivities(session)
|
|
442
|
+
from services.temporal.activities import (
|
|
443
|
+
broadcast_trigger_status_activity,
|
|
444
|
+
store_node_output_activity,
|
|
445
|
+
)
|
|
362
446
|
|
|
363
447
|
return Worker(
|
|
364
448
|
client,
|
|
365
449
|
task_queue=task_queue,
|
|
366
|
-
workflows=[
|
|
367
|
-
|
|
450
|
+
workflows=[
|
|
451
|
+
MachinaWorkflow,
|
|
452
|
+
TriggerListenerWorkflow,
|
|
453
|
+
PollingTriggerWorkflow,
|
|
454
|
+
],
|
|
455
|
+
activities=[
|
|
456
|
+
activities.execute_node_activity,
|
|
457
|
+
broadcast_trigger_status_activity,
|
|
458
|
+
store_node_output_activity,
|
|
459
|
+
],
|
|
368
460
|
max_concurrent_activities=100,
|
|
369
461
|
max_concurrent_workflow_tasks=10,
|
|
462
|
+
graceful_shutdown_timeout=_graceful_shutdown_timeout(),
|
|
370
463
|
)
|
|
371
464
|
|
|
372
465
|
|