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
|
@@ -37,14 +37,10 @@ PollCoroutine = Callable[[asyncio.Queue, Callable[[], bool]], Awaitable[None]]
|
|
|
37
37
|
PollCoroutineFactory = Callable[[str, Dict[str, Any]], PollCoroutine]
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
_REGISTRY: IdempotentRegistry[str, PollCoroutineFactory] = IdempotentRegistry(
|
|
41
|
-
"poll_coroutine_factory"
|
|
42
|
-
)
|
|
40
|
+
_REGISTRY: IdempotentRegistry[str, PollCoroutineFactory] = IdempotentRegistry("poll_coroutine_factory")
|
|
43
41
|
|
|
44
42
|
|
|
45
|
-
def register_poll_coroutine_factory(
|
|
46
|
-
node_type: str, factory: PollCoroutineFactory
|
|
47
|
-
) -> None:
|
|
43
|
+
def register_poll_coroutine_factory(node_type: str, factory: PollCoroutineFactory) -> None:
|
|
48
44
|
"""Publish a polling-coroutine factory for a trigger node type.
|
|
49
45
|
|
|
50
46
|
Idempotent on re-import (same callable for the same key is a
|
|
@@ -8,6 +8,7 @@ from typing import Dict, Any, List, Optional
|
|
|
8
8
|
@dataclass
|
|
9
9
|
class DeploymentState:
|
|
10
10
|
"""Immutable deployment state."""
|
|
11
|
+
|
|
11
12
|
deployment_id: str
|
|
12
13
|
workflow_id: str
|
|
13
14
|
is_running: bool
|
|
@@ -33,6 +34,7 @@ class DeploymentState:
|
|
|
33
34
|
@dataclass
|
|
34
35
|
class TriggerInfo:
|
|
35
36
|
"""Info about a registered trigger."""
|
|
37
|
+
|
|
36
38
|
node_id: str
|
|
37
39
|
node_type: str
|
|
38
40
|
job_id: Optional[str] = None # For cron triggers
|
|
@@ -33,8 +33,7 @@ class TriggerManager:
|
|
|
33
33
|
# CRON TRIGGERS
|
|
34
34
|
# =========================================================================
|
|
35
35
|
|
|
36
|
-
def setup_cron(self, node_id: str, cron_expr: str, timezone: str,
|
|
37
|
-
on_tick: Callable[[], None]) -> str:
|
|
36
|
+
def setup_cron(self, node_id: str, cron_expr: str, timezone: str, on_tick: Callable[[], None]) -> str:
|
|
38
37
|
"""Setup a cron trigger that calls on_tick on schedule."""
|
|
39
38
|
job_id = f"cron_{node_id}"
|
|
40
39
|
|
|
@@ -43,12 +42,7 @@ class TriggerManager:
|
|
|
43
42
|
return
|
|
44
43
|
on_tick()
|
|
45
44
|
|
|
46
|
-
cron_scheduler.register_cron_job(
|
|
47
|
-
job_id=job_id,
|
|
48
|
-
cron_expression=cron_expr,
|
|
49
|
-
callback=tick_callback,
|
|
50
|
-
timezone=timezone
|
|
51
|
-
)
|
|
45
|
+
cron_scheduler.register_cron_job(job_id=job_id, cron_expression=cron_expr, callback=tick_callback, timezone=timezone)
|
|
52
46
|
|
|
53
47
|
self._active_cron_jobs[node_id] = job_id
|
|
54
48
|
logger.info("Cron trigger setup", job_id=job_id, expr=cron_expr)
|
|
@@ -81,11 +75,15 @@ class TriggerManager:
|
|
|
81
75
|
# EVENT TRIGGERS (Webhook, WhatsApp, etc.)
|
|
82
76
|
# =========================================================================
|
|
83
77
|
|
|
84
|
-
async def setup_event_trigger(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
78
|
+
async def setup_event_trigger(
|
|
79
|
+
self,
|
|
80
|
+
node_id: str,
|
|
81
|
+
node_type: str,
|
|
82
|
+
parameters: Dict[str, Any],
|
|
83
|
+
on_event: Callable[[Dict], Any],
|
|
84
|
+
broadcaster: Any,
|
|
85
|
+
workflow_id: Optional[str] = None,
|
|
86
|
+
) -> None:
|
|
89
87
|
"""Setup an event-based trigger with queue-based sequential processing.
|
|
90
88
|
|
|
91
89
|
Args:
|
|
@@ -111,12 +109,12 @@ class TriggerManager:
|
|
|
111
109
|
msg = f"Waiting for {config.display_name}..."
|
|
112
110
|
if queue_size > 0:
|
|
113
111
|
msg = f"Waiting... ({queue_size} queued)"
|
|
114
|
-
await broadcaster.update_node_status(
|
|
115
|
-
|
|
116
|
-
"
|
|
117
|
-
"waiter_id": waiter.id,
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
await broadcaster.update_node_status(
|
|
113
|
+
node_id,
|
|
114
|
+
"waiting",
|
|
115
|
+
{"message": msg, "event_type": config.event_type, "waiter_id": waiter.id, "queue_size": queue_size},
|
|
116
|
+
workflow_id=workflow_id,
|
|
117
|
+
)
|
|
120
118
|
|
|
121
119
|
event_data = await event_waiter.wait_for_event(waiter)
|
|
122
120
|
if self._is_running:
|
|
@@ -143,10 +141,9 @@ class TriggerManager:
|
|
|
143
141
|
config = event_waiter.get_trigger_config(node_type)
|
|
144
142
|
|
|
145
143
|
# Clear waiting indicator during execution
|
|
146
|
-
await broadcaster.update_node_status(
|
|
147
|
-
"message": "Graph executing...",
|
|
148
|
-
|
|
149
|
-
}, workflow_id=workflow_id)
|
|
144
|
+
await broadcaster.update_node_status(
|
|
145
|
+
node_id, "idle", {"message": "Graph executing...", "is_processing": True}, workflow_id=workflow_id
|
|
146
|
+
)
|
|
150
147
|
|
|
151
148
|
try:
|
|
152
149
|
await on_event(event_data)
|
|
@@ -159,11 +156,9 @@ class TriggerManager:
|
|
|
159
156
|
queue_size = event_queue.qsize()
|
|
160
157
|
name = config.display_name if config else node_type
|
|
161
158
|
msg = f"Waiting for {name}..." if queue_size == 0 else f"Processing next... ({queue_size} queued)"
|
|
162
|
-
await broadcaster.update_node_status(
|
|
163
|
-
"message": msg,
|
|
164
|
-
|
|
165
|
-
"is_processing": False
|
|
166
|
-
}, workflow_id=workflow_id)
|
|
159
|
+
await broadcaster.update_node_status(
|
|
160
|
+
node_id, "waiting", {"message": msg, "queue_size": queue_size, "is_processing": False}, workflow_id=workflow_id
|
|
161
|
+
)
|
|
167
162
|
|
|
168
163
|
except asyncio.CancelledError:
|
|
169
164
|
break
|
|
@@ -184,12 +179,16 @@ class TriggerManager:
|
|
|
184
179
|
task = asyncio.create_task(combined())
|
|
185
180
|
self._active_listeners[node_id] = task
|
|
186
181
|
|
|
187
|
-
async def setup_polling_trigger(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
182
|
+
async def setup_polling_trigger(
|
|
183
|
+
self,
|
|
184
|
+
node_id: str,
|
|
185
|
+
node_type: str,
|
|
186
|
+
parameters: Dict[str, Any],
|
|
187
|
+
poll_coroutine: Callable,
|
|
188
|
+
on_event: Callable[[Dict], Any],
|
|
189
|
+
broadcaster: Any,
|
|
190
|
+
workflow_id: Optional[str] = None,
|
|
191
|
+
) -> None:
|
|
193
192
|
"""Setup a polling-based trigger with queue-based sequential processing.
|
|
194
193
|
|
|
195
194
|
Unlike event triggers that wait for externally dispatched events via
|
|
@@ -211,10 +210,9 @@ class TriggerManager:
|
|
|
211
210
|
# Broadcast initial "waiting" status immediately
|
|
212
211
|
config = event_waiter.get_trigger_config(node_type)
|
|
213
212
|
display_name = config.display_name if config else node_type
|
|
214
|
-
await broadcaster.update_node_status(
|
|
215
|
-
"message": f"Waiting for {display_name} (polling)...",
|
|
216
|
-
|
|
217
|
-
}, workflow_id=workflow_id)
|
|
213
|
+
await broadcaster.update_node_status(
|
|
214
|
+
node_id, "waiting", {"message": f"Waiting for {display_name} (polling)...", "is_processing": False}, workflow_id=workflow_id
|
|
215
|
+
)
|
|
218
216
|
|
|
219
217
|
async def poller():
|
|
220
218
|
"""Run the polling coroutine to collect events."""
|
|
@@ -238,10 +236,9 @@ class TriggerManager:
|
|
|
238
236
|
is_executing = True
|
|
239
237
|
config = event_waiter.get_trigger_config(node_type)
|
|
240
238
|
|
|
241
|
-
await broadcaster.update_node_status(
|
|
242
|
-
"message": "Graph executing...",
|
|
243
|
-
|
|
244
|
-
}, workflow_id=workflow_id)
|
|
239
|
+
await broadcaster.update_node_status(
|
|
240
|
+
node_id, "idle", {"message": "Graph executing...", "is_processing": True}, workflow_id=workflow_id
|
|
241
|
+
)
|
|
245
242
|
|
|
246
243
|
try:
|
|
247
244
|
await on_event(event_data)
|
|
@@ -253,11 +250,9 @@ class TriggerManager:
|
|
|
253
250
|
queue_size = event_queue.qsize()
|
|
254
251
|
name = config.display_name if config else node_type
|
|
255
252
|
msg = f"Waiting for {name} (polling)..." if queue_size == 0 else f"Processing next... ({queue_size} queued)"
|
|
256
|
-
await broadcaster.update_node_status(
|
|
257
|
-
"message": msg,
|
|
258
|
-
|
|
259
|
-
"is_processing": False
|
|
260
|
-
}, workflow_id=workflow_id)
|
|
253
|
+
await broadcaster.update_node_status(
|
|
254
|
+
node_id, "waiting", {"message": msg, "queue_size": queue_size, "is_processing": False}, workflow_id=workflow_id
|
|
255
|
+
)
|
|
261
256
|
|
|
262
257
|
except asyncio.CancelledError:
|
|
263
258
|
break
|
|
@@ -303,48 +298,48 @@ class TriggerManager:
|
|
|
303
298
|
@staticmethod
|
|
304
299
|
def build_cron_expression(parameters: Dict[str, Any]) -> Optional[str]:
|
|
305
300
|
"""Build cron expression from user-friendly parameters."""
|
|
306
|
-
frequency = parameters.get(
|
|
307
|
-
|
|
308
|
-
second, minute, hour =
|
|
309
|
-
day, month, weekday =
|
|
310
|
-
|
|
311
|
-
if frequency ==
|
|
312
|
-
interval = str(parameters.get(
|
|
313
|
-
second, minute = f
|
|
314
|
-
|
|
315
|
-
elif frequency ==
|
|
316
|
-
interval = str(parameters.get(
|
|
317
|
-
minute = f
|
|
318
|
-
|
|
319
|
-
elif frequency ==
|
|
320
|
-
interval = str(parameters.get(
|
|
321
|
-
minute =
|
|
322
|
-
hour = f
|
|
323
|
-
|
|
324
|
-
elif frequency ==
|
|
325
|
-
time_str = parameters.get(
|
|
326
|
-
parts = time_str.split(
|
|
327
|
-
hour = parts[0] if parts else
|
|
328
|
-
minute = parts[1] if len(parts) > 1 else
|
|
329
|
-
|
|
330
|
-
elif frequency ==
|
|
331
|
-
time_str = parameters.get(
|
|
332
|
-
parts = time_str.split(
|
|
333
|
-
hour = parts[0] if parts else
|
|
334
|
-
minute = parts[1] if len(parts) > 1 else
|
|
335
|
-
weekday = parameters.get(
|
|
336
|
-
|
|
337
|
-
elif frequency ==
|
|
338
|
-
time_str = parameters.get(
|
|
339
|
-
parts = time_str.split(
|
|
340
|
-
hour = parts[0] if parts else
|
|
341
|
-
minute = parts[1] if len(parts) > 1 else
|
|
342
|
-
day = parameters.get(
|
|
343
|
-
|
|
344
|
-
elif frequency ==
|
|
301
|
+
frequency = parameters.get("frequency", "minutes")
|
|
302
|
+
|
|
303
|
+
second, minute, hour = "0", "*/5", "*"
|
|
304
|
+
day, month, weekday = "*", "*", "*"
|
|
305
|
+
|
|
306
|
+
if frequency == "seconds":
|
|
307
|
+
interval = str(parameters.get("interval", 30))
|
|
308
|
+
second, minute = f"*/{interval}", "*"
|
|
309
|
+
|
|
310
|
+
elif frequency == "minutes":
|
|
311
|
+
interval = str(parameters.get("interval_minutes", 5))
|
|
312
|
+
minute = f"*/{interval}" if interval != "1" else "*"
|
|
313
|
+
|
|
314
|
+
elif frequency == "hours":
|
|
315
|
+
interval = str(parameters.get("interval_hours", 1))
|
|
316
|
+
minute = "0"
|
|
317
|
+
hour = f"*/{interval}" if interval != "1" else "*"
|
|
318
|
+
|
|
319
|
+
elif frequency == "days":
|
|
320
|
+
time_str = parameters.get("daily_time", "09:00")
|
|
321
|
+
parts = time_str.split(":")
|
|
322
|
+
hour = parts[0] if parts else "9"
|
|
323
|
+
minute = parts[1] if len(parts) > 1 else "0"
|
|
324
|
+
|
|
325
|
+
elif frequency == "weeks":
|
|
326
|
+
time_str = parameters.get("weekly_time", "09:00")
|
|
327
|
+
parts = time_str.split(":")
|
|
328
|
+
hour = parts[0] if parts else "9"
|
|
329
|
+
minute = parts[1] if len(parts) > 1 else "0"
|
|
330
|
+
weekday = parameters.get("weekday", "1")
|
|
331
|
+
|
|
332
|
+
elif frequency == "months":
|
|
333
|
+
time_str = parameters.get("monthly_time", "09:00")
|
|
334
|
+
parts = time_str.split(":")
|
|
335
|
+
hour = parts[0] if parts else "9"
|
|
336
|
+
minute = parts[1] if len(parts) > 1 else "0"
|
|
337
|
+
day = parameters.get("month_day", "1")
|
|
338
|
+
|
|
339
|
+
elif frequency == "once":
|
|
345
340
|
return None
|
|
346
341
|
|
|
347
|
-
return f
|
|
342
|
+
return f"{second} {minute} {hour} {day} {month} {weekday}"
|
|
348
343
|
|
|
349
344
|
@staticmethod
|
|
350
345
|
def find_trigger_nodes(nodes: list, edges: list) -> tuple:
|
|
@@ -355,16 +350,15 @@ class TriggerManager:
|
|
|
355
350
|
after an AI agent). Each trigger listens for its event type and, when fired,
|
|
356
351
|
executes its downstream subgraph independently.
|
|
357
352
|
"""
|
|
358
|
-
trigger_types_no_cron = WORKFLOW_TRIGGER_TYPES - {
|
|
359
|
-
triggers = [n for n in nodes
|
|
360
|
-
if n.get('type') in trigger_types_no_cron]
|
|
353
|
+
trigger_types_no_cron = WORKFLOW_TRIGGER_TYPES - {"cronScheduler"}
|
|
354
|
+
triggers = [n for n in nodes if n.get("type") in trigger_types_no_cron]
|
|
361
355
|
|
|
362
|
-
start_nodes = [n for n in triggers if n.get(
|
|
363
|
-
event_triggers = [n for n in triggers if n.get(
|
|
356
|
+
start_nodes = [n for n in triggers if n.get("type") == "start"]
|
|
357
|
+
event_triggers = [n for n in triggers if n.get("type") != "start"]
|
|
364
358
|
|
|
365
359
|
return start_nodes, event_triggers
|
|
366
360
|
|
|
367
361
|
@staticmethod
|
|
368
362
|
def find_cron_nodes(nodes: list) -> list:
|
|
369
363
|
"""Find all cron scheduler nodes."""
|
|
370
|
-
return [n for n in nodes if n.get(
|
|
364
|
+
return [n for n in nodes if n.get("type") == "cronScheduler"]
|
|
@@ -7,6 +7,7 @@ Architecture:
|
|
|
7
7
|
- Redis mode: Events stored in Redis Streams, waiters poll streams with blocking XREAD
|
|
8
8
|
- Memory mode: Events dispatched to in-memory asyncio.Future waiters
|
|
9
9
|
"""
|
|
10
|
+
|
|
10
11
|
import asyncio
|
|
11
12
|
import json
|
|
12
13
|
import uuid
|
|
@@ -74,9 +75,11 @@ def is_redis_mode() -> bool:
|
|
|
74
75
|
# TRIGGER CONFIGURATION REGISTRY
|
|
75
76
|
# =============================================================================
|
|
76
77
|
|
|
78
|
+
|
|
77
79
|
@dataclass
|
|
78
80
|
class TriggerConfig:
|
|
79
81
|
"""Configuration for a trigger node type."""
|
|
82
|
+
|
|
80
83
|
node_type: str
|
|
81
84
|
event_type: str # Event to wait for (e.g., 'whatsapp_message_received')
|
|
82
85
|
display_name: str
|
|
@@ -86,26 +89,10 @@ class TriggerConfig:
|
|
|
86
89
|
# Note: cronScheduler is NOT an event-based trigger - it uses APScheduler directly
|
|
87
90
|
TRIGGER_REGISTRY: Dict[str, TriggerConfig] = {
|
|
88
91
|
# Framework-level triggers — not owned by any plugin domain.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
),
|
|
94
|
-
'webhookTrigger': TriggerConfig(
|
|
95
|
-
node_type='webhookTrigger',
|
|
96
|
-
event_type='webhook_received',
|
|
97
|
-
display_name='Webhook Request'
|
|
98
|
-
),
|
|
99
|
-
'chatTrigger': TriggerConfig(
|
|
100
|
-
node_type='chatTrigger',
|
|
101
|
-
event_type='chat_message_received',
|
|
102
|
-
display_name='Chat Message'
|
|
103
|
-
),
|
|
104
|
-
'taskTrigger': TriggerConfig(
|
|
105
|
-
node_type='taskTrigger',
|
|
106
|
-
event_type='task_completed',
|
|
107
|
-
display_name='Task Completed'
|
|
108
|
-
),
|
|
92
|
+
"start": TriggerConfig(node_type="start", event_type="deploy_triggered", display_name="Deploy Start"),
|
|
93
|
+
"webhookTrigger": TriggerConfig(node_type="webhookTrigger", event_type="webhook_received", display_name="Webhook Request"),
|
|
94
|
+
"chatTrigger": TriggerConfig(node_type="chatTrigger", event_type="chat_message_received", display_name="Chat Message"),
|
|
95
|
+
"taskTrigger": TriggerConfig(node_type="taskTrigger", event_type="task_completed", display_name="Task Completed"),
|
|
109
96
|
# Plugin-owned trigger entries (whatsappReceive, twitterReceive,
|
|
110
97
|
# telegramReceive, emailReceive, googleGmailReceive) live in their
|
|
111
98
|
# plugin folders' ``_filters.py`` and are backfilled here from each
|
|
@@ -175,6 +162,7 @@ def is_trigger_node(node_type: str) -> bool:
|
|
|
175
162
|
This includes all trigger types: start, cronScheduler, and event-based triggers.
|
|
176
163
|
"""
|
|
177
164
|
from constants import WORKFLOW_TRIGGER_TYPES
|
|
165
|
+
|
|
178
166
|
return node_type in WORKFLOW_TRIGGER_TYPES
|
|
179
167
|
|
|
180
168
|
|
|
@@ -199,6 +187,7 @@ def get_trigger_config(node_type: str) -> Optional[TriggerConfig]:
|
|
|
199
187
|
# FILTER BUILDERS - One per trigger type
|
|
200
188
|
# =============================================================================
|
|
201
189
|
|
|
190
|
+
|
|
202
191
|
def build_webhook_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
203
192
|
"""Build filter function for webhook requests.
|
|
204
193
|
|
|
@@ -210,10 +199,10 @@ def build_webhook_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
|
210
199
|
Returns:
|
|
211
200
|
Filter function that checks if event path matches
|
|
212
201
|
"""
|
|
213
|
-
webhook_path = params.get(
|
|
202
|
+
webhook_path = params.get("path", "")
|
|
214
203
|
|
|
215
204
|
def matches(data: Dict) -> bool:
|
|
216
|
-
event_path = data.get(
|
|
205
|
+
event_path = data.get("path", "")
|
|
217
206
|
if webhook_path and event_path != webhook_path:
|
|
218
207
|
return False
|
|
219
208
|
return True
|
|
@@ -231,11 +220,11 @@ def build_chat_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
|
231
220
|
Returns:
|
|
232
221
|
Filter function that checks if event session_id matches
|
|
233
222
|
"""
|
|
234
|
-
session_id = params.get(
|
|
223
|
+
session_id = params.get("session_id", "default")
|
|
235
224
|
|
|
236
225
|
def matches(data: Dict) -> bool:
|
|
237
|
-
event_session = data.get(
|
|
238
|
-
if session_id !=
|
|
226
|
+
event_session = data.get("session_id", "default")
|
|
227
|
+
if session_id != "default" and event_session != session_id:
|
|
239
228
|
return False
|
|
240
229
|
return True
|
|
241
230
|
|
|
@@ -257,33 +246,33 @@ def build_task_completed_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
|
257
246
|
Returns:
|
|
258
247
|
Filter function that checks if event matches criteria
|
|
259
248
|
"""
|
|
260
|
-
task_id_filter = params.get(
|
|
261
|
-
agent_name_filter = params.get(
|
|
262
|
-
status_filter = params.get(
|
|
263
|
-
parent_node_id = params.get(
|
|
249
|
+
task_id_filter = params.get("task_id", "")
|
|
250
|
+
agent_name_filter = params.get("agent_name", "")
|
|
251
|
+
status_filter = params.get("status_filter", "all") # all, completed, error
|
|
252
|
+
parent_node_id = params.get("parent_node_id", "")
|
|
264
253
|
|
|
265
254
|
def matches(data: Dict) -> bool:
|
|
266
255
|
# Task ID filter (exact match if specified)
|
|
267
256
|
if task_id_filter:
|
|
268
|
-
if data.get(
|
|
257
|
+
if data.get("task_id") != task_id_filter:
|
|
269
258
|
return False
|
|
270
259
|
|
|
271
260
|
# Agent name filter (contains match)
|
|
272
261
|
if agent_name_filter:
|
|
273
|
-
event_agent = data.get(
|
|
262
|
+
event_agent = data.get("agent_name", "")
|
|
274
263
|
if agent_name_filter.lower() not in event_agent.lower():
|
|
275
264
|
return False
|
|
276
265
|
|
|
277
266
|
# Status filter
|
|
278
|
-
event_status = data.get(
|
|
279
|
-
if status_filter ==
|
|
267
|
+
event_status = data.get("status", "")
|
|
268
|
+
if status_filter == "completed" and event_status != "completed":
|
|
280
269
|
return False
|
|
281
|
-
if status_filter ==
|
|
270
|
+
if status_filter == "error" and event_status != "error":
|
|
282
271
|
return False
|
|
283
272
|
|
|
284
273
|
# Parent node filter (for scoping to specific parent agent)
|
|
285
274
|
if parent_node_id:
|
|
286
|
-
if data.get(
|
|
275
|
+
if data.get("parent_node_id") != parent_node_id:
|
|
287
276
|
return False
|
|
288
277
|
|
|
289
278
|
return True
|
|
@@ -301,17 +290,17 @@ def build_task_completed_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
|
301
290
|
# googleGmailReceive, emailReceive) live in their plugin folders'
|
|
302
291
|
# ``_filters.py`` and self-register at import time.
|
|
303
292
|
FILTER_BUILDERS: Dict[str, Callable[[Dict], Callable[[Dict], bool]]] = {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
293
|
+
"webhookTrigger": build_webhook_filter,
|
|
294
|
+
"chatTrigger": build_chat_filter,
|
|
295
|
+
"taskTrigger": build_task_completed_filter,
|
|
307
296
|
}
|
|
308
297
|
|
|
309
298
|
from services.plugin.registry import IdempotentRegistry as _IdempotentRegistry # noqa: E402
|
|
310
299
|
|
|
311
300
|
# Backed by the module-level FILTER_BUILDERS dict so existing readers
|
|
312
301
|
# (e.g. build_filter, _ensure_populated, tests) keep working.
|
|
313
|
-
_FILTER_REGISTRY: _IdempotentRegistry[str, Callable[[Dict], Callable[[Dict], bool]]] = (
|
|
314
|
-
|
|
302
|
+
_FILTER_REGISTRY: _IdempotentRegistry[str, Callable[[Dict], Callable[[Dict], bool]]] = _IdempotentRegistry(
|
|
303
|
+
"filter_builder", items=FILTER_BUILDERS
|
|
315
304
|
)
|
|
316
305
|
|
|
317
306
|
|
|
@@ -361,9 +350,7 @@ import inspect as _inspect
|
|
|
361
350
|
|
|
362
351
|
_TriggerPrecheck = Callable[[Dict[str, Any]], Any]
|
|
363
352
|
_TRIGGER_PRECHECKS: Dict[str, _TriggerPrecheck] = {}
|
|
364
|
-
_TRIGGER_PRECHECK_REGISTRY: _IdempotentRegistry[str, _TriggerPrecheck] = (
|
|
365
|
-
_IdempotentRegistry("trigger_precheck", items=_TRIGGER_PRECHECKS)
|
|
366
|
-
)
|
|
353
|
+
_TRIGGER_PRECHECK_REGISTRY: _IdempotentRegistry[str, _TriggerPrecheck] = _IdempotentRegistry("trigger_precheck", items=_TRIGGER_PRECHECKS)
|
|
367
354
|
|
|
368
355
|
|
|
369
356
|
def register_trigger_precheck(node_type: str, fn: _TriggerPrecheck) -> None:
|
|
@@ -394,6 +381,7 @@ async def run_trigger_precheck(node_type: str, parameters: Dict) -> Any:
|
|
|
394
381
|
# WAITER DATA STRUCTURES
|
|
395
382
|
# =============================================================================
|
|
396
383
|
|
|
384
|
+
|
|
397
385
|
@dataclass
|
|
398
386
|
class Waiter:
|
|
399
387
|
"""Single event waiter.
|
|
@@ -401,6 +389,7 @@ class Waiter:
|
|
|
401
389
|
In memory mode: uses asyncio.Future
|
|
402
390
|
In Redis mode: uses stream polling with stored metadata
|
|
403
391
|
"""
|
|
392
|
+
|
|
404
393
|
id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
405
394
|
node_id: str = ""
|
|
406
395
|
node_type: str = ""
|
|
@@ -433,6 +422,7 @@ def _get_stream_name(event_type: str) -> str:
|
|
|
433
422
|
# WAITER REGISTRATION
|
|
434
423
|
# =============================================================================
|
|
435
424
|
|
|
425
|
+
|
|
436
426
|
async def register(node_type: str, node_id: str, params: Dict) -> Waiter:
|
|
437
427
|
"""Register a waiter for a trigger node.
|
|
438
428
|
|
|
@@ -480,7 +470,7 @@ async def register(node_type: str, node_id: str, params: Dict) -> Waiter:
|
|
|
480
470
|
# Create unique consumer group for this waiter
|
|
481
471
|
# start_id='$' means only new messages from this point forward
|
|
482
472
|
stream_name = _get_stream_name(config.event_type)
|
|
483
|
-
await cache.stream_create_group(stream_name, consumer_group, start_id=
|
|
473
|
+
await cache.stream_create_group(stream_name, consumer_group, start_id="$")
|
|
484
474
|
|
|
485
475
|
logger.debug(f"[EventWaiter] Registered {node_type} waiter {waiter.id} (Redis)")
|
|
486
476
|
else:
|
|
@@ -560,9 +550,9 @@ async def _wait_redis(waiter: Waiter, timeout: Optional[float]) -> Dict:
|
|
|
560
550
|
result = await cache.stream_read_group(
|
|
561
551
|
consumer_group, # Each waiter has its own group
|
|
562
552
|
consumer_name,
|
|
563
|
-
{stream_name:
|
|
553
|
+
{stream_name: ">"}, # '>' = new messages for this consumer
|
|
564
554
|
count=10,
|
|
565
|
-
block=block_ms
|
|
555
|
+
block=block_ms,
|
|
566
556
|
)
|
|
567
557
|
|
|
568
558
|
if not result:
|
|
@@ -616,6 +606,7 @@ def _cleanup_waiter(waiter_id: str) -> None:
|
|
|
616
606
|
# EVENT DISPATCH
|
|
617
607
|
# =============================================================================
|
|
618
608
|
|
|
609
|
+
|
|
619
610
|
def _unpack_event(
|
|
620
611
|
event: "Any",
|
|
621
612
|
data: Optional[Dict] = None,
|
|
@@ -638,10 +629,7 @@ def _unpack_event(
|
|
|
638
629
|
return event.type, event.data if isinstance(event.data, dict) else {"data": event.data}
|
|
639
630
|
if isinstance(event, str):
|
|
640
631
|
return event, data or {}
|
|
641
|
-
raise TypeError(
|
|
642
|
-
f"dispatch expects a WorkflowEvent or (event_type: str, data: Dict); "
|
|
643
|
-
f"got {type(event).__name__}"
|
|
644
|
-
)
|
|
632
|
+
raise TypeError(f"dispatch expects a WorkflowEvent or (event_type: str, data: Dict); " f"got {type(event).__name__}")
|
|
645
633
|
|
|
646
634
|
|
|
647
635
|
async def dispatch_async(
|
|
@@ -713,14 +701,17 @@ def dispatch(
|
|
|
713
701
|
resolved = 0
|
|
714
702
|
to_remove = []
|
|
715
703
|
|
|
716
|
-
matching_waiters = [(wid, w) for wid, w in _waiters.items()
|
|
717
|
-
if w.event_type == event_type and w.future and not w.future.done()]
|
|
704
|
+
matching_waiters = [(wid, w) for wid, w in _waiters.items() if w.event_type == event_type and w.future and not w.future.done()]
|
|
718
705
|
|
|
719
706
|
if not matching_waiters:
|
|
720
707
|
logger.debug(f"[EventWaiter] No active waiters for {event_type} (total waiters: {len(_waiters)})")
|
|
721
708
|
else:
|
|
722
|
-
logger.info(
|
|
723
|
-
|
|
709
|
+
logger.info(
|
|
710
|
+
f"[EventWaiter] Dispatching {event_type} to {len(matching_waiters)} waiter(s)",
|
|
711
|
+
event_type=event_type,
|
|
712
|
+
from_id=data.get("from_id"),
|
|
713
|
+
text=str(data.get("text", ""))[:50],
|
|
714
|
+
)
|
|
724
715
|
|
|
725
716
|
for wid, w in matching_waiters:
|
|
726
717
|
try:
|
|
@@ -744,6 +735,7 @@ def dispatch(
|
|
|
744
735
|
# WAITER CANCELLATION
|
|
745
736
|
# =============================================================================
|
|
746
737
|
|
|
738
|
+
|
|
747
739
|
def cancel(waiter_id: str) -> bool:
|
|
748
740
|
"""Cancel a waiter by ID."""
|
|
749
741
|
if w := _waiters.pop(waiter_id, None):
|
|
@@ -776,6 +768,7 @@ def cancel_for_node(node_id: str) -> int:
|
|
|
776
768
|
# UTILITY FUNCTIONS
|
|
777
769
|
# =============================================================================
|
|
778
770
|
|
|
771
|
+
|
|
779
772
|
def get_active_waiters() -> List[Dict[str, Any]]:
|
|
780
773
|
"""Get info about active waiters (for debugging/UI)."""
|
|
781
774
|
return [
|
|
@@ -32,6 +32,17 @@ from .verifiers import (
|
|
|
32
32
|
GitHubVerifier,
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
+
# Wave 12 D3: publish the Visibility admin WS handlers into the central
|
|
36
|
+
# WS dispatcher on package import. Even though ``admin_handlers.py`` is
|
|
37
|
+
# framework code (not plugin code), routing it through the same
|
|
38
|
+
# ws_handler_registry keeps the router's dispatch surface uniform —
|
|
39
|
+
# the registry queries don't care whether the caller is plugin or
|
|
40
|
+
# framework.
|
|
41
|
+
from .admin_handlers import WS_HANDLERS as _ADMIN_WS_HANDLERS # noqa: E402
|
|
42
|
+
from services.ws_handler_registry import register_ws_handlers as _register_ws_handlers # noqa: E402
|
|
43
|
+
|
|
44
|
+
_register_ws_handlers(_ADMIN_WS_HANDLERS)
|
|
45
|
+
|
|
35
46
|
__all__ = [
|
|
36
47
|
"BaseTriggerParams",
|
|
37
48
|
"DaemonEventSource",
|