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,167 @@
|
|
|
1
|
+
"""Wave 12 B3: CloudEvents factories + broadcaster wrappers for telegram.
|
|
2
|
+
|
|
3
|
+
Plugin-specific event emission — replaces:
|
|
4
|
+
- ``broadcaster.update_telegram_status(...)`` call inside the
|
|
5
|
+
telegram service's ``_broadcast_status`` method
|
|
6
|
+
- ``event_waiter.dispatch("telegram_message_received", event_data)``
|
|
7
|
+
inside the message-receive handler
|
|
8
|
+
|
|
9
|
+
After B3 every telegram wire frame originates from one wrapper here —
|
|
10
|
+
single source of truth for shape. The cross-plugin
|
|
11
|
+
``_emit_connection_typed`` helper on ``StatusBroadcaster`` retires in
|
|
12
|
+
the same commit since android (B1) + whatsapp (B2) + telegram (B3) are
|
|
13
|
+
the only callers.
|
|
14
|
+
|
|
15
|
+
Per RFC plugin_authoring_rfc.md §6.4: plugin-specific factories live in
|
|
16
|
+
the plugin folder.
|
|
17
|
+
|
|
18
|
+
Wire format (Wave 12 D4 — legacy ``telegram_status`` raw frame retired):
|
|
19
|
+
- Status: typed CloudEvent on ``plugin_connection_status`` (FE routes
|
|
20
|
+
by ``envelope.source``).
|
|
21
|
+
- Message: typed CloudEvent dispatched to ``event_waiter`` so
|
|
22
|
+
``telegramReceive`` trigger nodes match it; legacy wire key
|
|
23
|
+
``telegram_message_received`` preserved for FE.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import time
|
|
29
|
+
from typing import Any, Dict, Mapping, Optional
|
|
30
|
+
|
|
31
|
+
from services.events.envelope import WorkflowEvent
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ---- Wire-routing keys -----------------------------------------------------
|
|
35
|
+
|
|
36
|
+
_STATUS_TYPED_WIRE_KEY = "plugin_connection_status"
|
|
37
|
+
|
|
38
|
+
# Legacy event_type the event_waiter dispatches by; trigger nodes
|
|
39
|
+
# subscribe on this string. Keep until Phase B11 FE migration.
|
|
40
|
+
_MESSAGE_LEGACY_EVENT_TYPE = "telegram_message_received"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ---- Typed factories (plugin-specific per RFC §6.4) ------------------------
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def telegram_connection_status(
|
|
47
|
+
*,
|
|
48
|
+
connected: bool,
|
|
49
|
+
bot_id: Optional[int] = None,
|
|
50
|
+
bot_username: Optional[str] = None,
|
|
51
|
+
bot_name: Optional[str] = None,
|
|
52
|
+
owner_chat_id: Optional[int] = None,
|
|
53
|
+
has_stored_token: Optional[bool] = None,
|
|
54
|
+
) -> WorkflowEvent:
|
|
55
|
+
"""Bot connection-state envelope. ``subject`` is the bot username
|
|
56
|
+
so the FE can route per-bot updates.
|
|
57
|
+
|
|
58
|
+
``has_stored_token`` distinguishes "not connected, no token stored"
|
|
59
|
+
(user hasn't added a token yet) from "not connected, token stored
|
|
60
|
+
but bot offline" (network failure / token revoked). Used by the
|
|
61
|
+
auto-reconnect refresh callback (see :mod:`._refresh`).
|
|
62
|
+
"""
|
|
63
|
+
data: Dict[str, Any] = {
|
|
64
|
+
"connected": connected,
|
|
65
|
+
"bot_id": bot_id,
|
|
66
|
+
"bot_username": bot_username,
|
|
67
|
+
"bot_name": bot_name,
|
|
68
|
+
"owner_chat_id": owner_chat_id,
|
|
69
|
+
}
|
|
70
|
+
if has_stored_token is not None:
|
|
71
|
+
data["has_stored_token"] = has_stored_token
|
|
72
|
+
return WorkflowEvent(
|
|
73
|
+
source="machinaos://nodes/telegram",
|
|
74
|
+
type=("com.machinaos.telegram.connection.opened" if connected else "com.machinaos.telegram.connection.closed"),
|
|
75
|
+
subject=bot_username,
|
|
76
|
+
data=data,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def telegram_message_received(event_data: Mapping[str, Any]) -> WorkflowEvent:
|
|
81
|
+
"""Incoming Telegram message envelope. ``subject`` is the chat_id
|
|
82
|
+
(cast to str — Telegram chat IDs are numeric, the envelope spec
|
|
83
|
+
requires a string subject)."""
|
|
84
|
+
payload = dict(event_data)
|
|
85
|
+
chat_id = payload.get("chat_id")
|
|
86
|
+
return WorkflowEvent(
|
|
87
|
+
source="machinaos://nodes/telegram",
|
|
88
|
+
type="com.machinaos.telegram.message.received",
|
|
89
|
+
subject=str(chat_id) if chat_id is not None else None,
|
|
90
|
+
data=payload,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ---- Broadcaster wrappers --------------------------------------------------
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
async def broadcast_telegram_status(
|
|
98
|
+
*,
|
|
99
|
+
connected: bool,
|
|
100
|
+
bot_id: Optional[int] = None,
|
|
101
|
+
bot_username: Optional[str] = None,
|
|
102
|
+
bot_name: Optional[str] = None,
|
|
103
|
+
owner_chat_id: Optional[int] = None,
|
|
104
|
+
has_stored_token: Optional[bool] = None,
|
|
105
|
+
) -> None:
|
|
106
|
+
"""Update the telegram status cache + emit the typed
|
|
107
|
+
``plugin_connection_status`` CloudEvents envelope.
|
|
108
|
+
|
|
109
|
+
Replaces ``StatusBroadcaster.update_telegram_status``. Legacy raw
|
|
110
|
+
``telegram_status`` frame retired in Wave 12 D4 — FE consumes via
|
|
111
|
+
the envelope-aware ``plugin_connection_status`` case.
|
|
112
|
+
"""
|
|
113
|
+
from services.status_broadcaster import get_status_broadcaster
|
|
114
|
+
|
|
115
|
+
broadcaster = get_status_broadcaster()
|
|
116
|
+
|
|
117
|
+
payload: Dict[str, Any] = {
|
|
118
|
+
"connected": connected,
|
|
119
|
+
"bot_id": bot_id,
|
|
120
|
+
"bot_username": bot_username,
|
|
121
|
+
"bot_name": bot_name,
|
|
122
|
+
"owner_chat_id": owner_chat_id,
|
|
123
|
+
"timestamp": time.time(),
|
|
124
|
+
}
|
|
125
|
+
if has_stored_token is not None:
|
|
126
|
+
payload["has_stored_token"] = has_stored_token
|
|
127
|
+
broadcaster._status["telegram"] = payload
|
|
128
|
+
|
|
129
|
+
event = telegram_connection_status(
|
|
130
|
+
connected=connected,
|
|
131
|
+
bot_id=bot_id,
|
|
132
|
+
bot_username=bot_username,
|
|
133
|
+
bot_name=bot_name,
|
|
134
|
+
owner_chat_id=owner_chat_id,
|
|
135
|
+
has_stored_token=has_stored_token,
|
|
136
|
+
)
|
|
137
|
+
await broadcaster.broadcast(
|
|
138
|
+
{
|
|
139
|
+
"type": _STATUS_TYPED_WIRE_KEY,
|
|
140
|
+
"data": event.model_dump(mode="json"),
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
async def dispatch_telegram_message_received(event_data: Mapping[str, Any]) -> None:
|
|
146
|
+
"""Dispatch an incoming Telegram message via the canary CloudEvents path.
|
|
147
|
+
|
|
148
|
+
Single delivery: :func:`services.events.dispatch.emit` Signals running
|
|
149
|
+
:class:`TriggerListenerWorkflow` consumers via Temporal Visibility AND
|
|
150
|
+
broadcasts the envelope to FE on the ``telegram_message_received``
|
|
151
|
+
wire key. telegramReceive is canary-registered so no legacy
|
|
152
|
+
``event_waiter`` waiter is ever registered for it.
|
|
153
|
+
"""
|
|
154
|
+
from services.events.dispatch import emit
|
|
155
|
+
|
|
156
|
+
await emit(
|
|
157
|
+
telegram_message_received(dict(event_data)),
|
|
158
|
+
wire_routing_key=_MESSAGE_LEGACY_EVENT_TYPE,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
__all__ = [
|
|
163
|
+
"broadcast_telegram_status",
|
|
164
|
+
"dispatch_telegram_message_received",
|
|
165
|
+
"telegram_connection_status",
|
|
166
|
+
"telegram_message_received",
|
|
167
|
+
]
|
|
@@ -55,16 +55,11 @@ def build_telegram_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
|
55
55
|
content_type_filter = params.get("content_type_filter", "all")
|
|
56
56
|
chat_id_filter = params.get("chat_id", "")
|
|
57
57
|
from_user_filter = params.get("from_user", "")
|
|
58
|
-
keywords = [
|
|
59
|
-
k.strip().lower() for k in params.get("keywords", "").split(",") if k.strip()
|
|
60
|
-
]
|
|
58
|
+
keywords = [k.strip().lower() for k in params.get("keywords", "").split(",") if k.strip()]
|
|
61
59
|
ignore_bots = params.get("ignore_bots", True)
|
|
62
60
|
owner_chat_id = params.get("_owner_chat_id")
|
|
63
61
|
|
|
64
|
-
logger.debug(
|
|
65
|
-
f"[TelegramFilter] Built: sender={sender_filter}, "
|
|
66
|
-
f"content_type={content_type_filter}, owner_chat_id={owner_chat_id}"
|
|
67
|
-
)
|
|
62
|
+
logger.debug(f"[TelegramFilter] Built: sender={sender_filter}, " f"content_type={content_type_filter}, owner_chat_id={owner_chat_id}")
|
|
68
63
|
|
|
69
64
|
def _get_owner_chat_id() -> object:
|
|
70
65
|
"""Lazy lookup from the local service -- handles owner detected
|
|
@@ -113,10 +108,7 @@ def build_telegram_filter(params: Dict) -> Callable[[Dict], bool]:
|
|
|
113
108
|
if sender_filter != "self" and ignore_bots and m.get("is_bot", False):
|
|
114
109
|
return False
|
|
115
110
|
|
|
116
|
-
logger.debug(
|
|
117
|
-
f"[TelegramFilter] Matched message from "
|
|
118
|
-
f"{m.get('from_username', m.get('from_id'))}"
|
|
119
|
-
)
|
|
111
|
+
logger.debug(f"[TelegramFilter] Matched message from " f"{m.get('from_username', m.get('from_id'))}")
|
|
120
112
|
return True
|
|
121
113
|
|
|
122
114
|
return matches
|
|
@@ -38,7 +38,9 @@ def _send_text(svc, data, parse_mode):
|
|
|
38
38
|
if not text:
|
|
39
39
|
return None, "text required for text message"
|
|
40
40
|
return svc.send_message(
|
|
41
|
-
chat_id=data["chat_id"],
|
|
41
|
+
chat_id=data["chat_id"],
|
|
42
|
+
text=text,
|
|
43
|
+
parse_mode=parse_mode,
|
|
42
44
|
), None
|
|
43
45
|
|
|
44
46
|
|
|
@@ -47,8 +49,10 @@ def _send_photo(svc, data, parse_mode):
|
|
|
47
49
|
if not photo_url:
|
|
48
50
|
return None, "media_url required for photo"
|
|
49
51
|
return svc.send_photo(
|
|
50
|
-
chat_id=data["chat_id"],
|
|
51
|
-
|
|
52
|
+
chat_id=data["chat_id"],
|
|
53
|
+
photo=photo_url,
|
|
54
|
+
caption=data.get("caption"),
|
|
55
|
+
parse_mode=parse_mode,
|
|
52
56
|
), None
|
|
53
57
|
|
|
54
58
|
|
|
@@ -57,8 +61,10 @@ def _send_document(svc, data, parse_mode):
|
|
|
57
61
|
if not doc_url:
|
|
58
62
|
return None, "media_url required for document"
|
|
59
63
|
return svc.send_document(
|
|
60
|
-
chat_id=data["chat_id"],
|
|
61
|
-
|
|
64
|
+
chat_id=data["chat_id"],
|
|
65
|
+
document=doc_url,
|
|
66
|
+
caption=data.get("caption"),
|
|
67
|
+
parse_mode=parse_mode,
|
|
62
68
|
), None
|
|
63
69
|
|
|
64
70
|
|
|
@@ -67,7 +73,9 @@ def _send_location(svc, data, parse_mode):
|
|
|
67
73
|
if lat is None or lon is None:
|
|
68
74
|
return None, "latitude and longitude required"
|
|
69
75
|
return svc.send_location(
|
|
70
|
-
chat_id=data["chat_id"],
|
|
76
|
+
chat_id=data["chat_id"],
|
|
77
|
+
latitude=float(lat),
|
|
78
|
+
longitude=float(lon),
|
|
71
79
|
), None
|
|
72
80
|
|
|
73
81
|
|
|
@@ -76,7 +84,9 @@ def _send_contact(svc, data, parse_mode):
|
|
|
76
84
|
if not phone or not first_name:
|
|
77
85
|
return None, "phone_number and first_name required"
|
|
78
86
|
return svc.send_contact(
|
|
79
|
-
chat_id=data["chat_id"],
|
|
87
|
+
chat_id=data["chat_id"],
|
|
88
|
+
phone_number=phone,
|
|
89
|
+
first_name=first_name,
|
|
80
90
|
last_name=data.get("last_name"),
|
|
81
91
|
), None
|
|
82
92
|
|
|
@@ -15,7 +15,7 @@ into the broadcaster cache.
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import logging
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import Dict, TYPE_CHECKING
|
|
19
19
|
|
|
20
20
|
from opentelemetry import trace
|
|
21
21
|
|
|
@@ -32,55 +32,49 @@ async def refresh_telegram_status(broadcaster: "StatusBroadcaster") -> None:
|
|
|
32
32
|
Called once per ``_refresh_all_services`` cycle. OTel span emitted
|
|
33
33
|
so cold-start ``getMe`` time is observable -- the historical
|
|
34
34
|
bottleneck on local DNS for the first WebSocket connect.
|
|
35
|
+
|
|
36
|
+
Wave 12 B3: routes through plugin _events.py wrapper. Cache write
|
|
37
|
+
+ dual-emit (legacy raw + typed sibling) all in one call.
|
|
35
38
|
"""
|
|
36
39
|
with tracer.start_as_current_span("broadcaster.refresh_telegram") as span:
|
|
37
40
|
try:
|
|
41
|
+
from ._events import broadcast_telegram_status
|
|
38
42
|
from ._service import get_telegram_service
|
|
39
43
|
|
|
40
44
|
service = get_telegram_service()
|
|
41
45
|
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
46
|
+
async def _emit(connected: bool, has_token: bool) -> None:
|
|
47
|
+
"""Snapshot service state and broadcast (cache write + WS)."""
|
|
48
|
+
s = service.get_status() if connected else {}
|
|
49
|
+
await broadcast_telegram_status(
|
|
50
|
+
connected=connected,
|
|
51
|
+
bot_id=s.get("bot_id") if connected else None,
|
|
52
|
+
bot_username=s.get("bot_username") if connected else None,
|
|
53
|
+
bot_name=s.get("bot_name") if connected else None,
|
|
54
|
+
owner_chat_id=s.get("owner_chat_id") if connected else None,
|
|
55
|
+
has_stored_token=has_token,
|
|
56
|
+
)
|
|
52
57
|
|
|
53
58
|
if service.connected:
|
|
54
|
-
|
|
59
|
+
await _emit(True, True)
|
|
55
60
|
span.set_attribute("path", "already_connected")
|
|
56
61
|
elif not await service.has_stored_token():
|
|
57
|
-
|
|
62
|
+
await _emit(False, False)
|
|
58
63
|
span.set_attribute("path", "no_token")
|
|
59
64
|
else:
|
|
60
65
|
span.set_attribute("path", "auto_reconnect")
|
|
61
66
|
logger.info("[StatusBroadcaster] Auto-reconnecting Telegram bot...")
|
|
62
67
|
result = await service.connect()
|
|
63
68
|
ok = bool(result.get("success"))
|
|
64
|
-
|
|
69
|
+
await _emit(ok, True)
|
|
65
70
|
span.set_attribute("reconnect_ok", ok)
|
|
66
71
|
if ok:
|
|
67
72
|
bot_username = broadcaster._status["telegram"].get("bot_username")
|
|
68
|
-
logger.info(
|
|
69
|
-
f"[StatusBroadcaster] Telegram auto-reconnected: @{bot_username}"
|
|
70
|
-
)
|
|
73
|
+
logger.info(f"[StatusBroadcaster] Telegram auto-reconnected: @{bot_username}")
|
|
71
74
|
else:
|
|
72
|
-
logger.warning(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
await broadcaster.broadcast({
|
|
78
|
-
"type": "telegram_status",
|
|
79
|
-
"data": broadcaster._status["telegram"],
|
|
80
|
-
})
|
|
81
|
-
span.set_attribute(
|
|
82
|
-
"connected", bool(broadcaster._status["telegram"]["connected"])
|
|
83
|
-
)
|
|
75
|
+
logger.warning(f"[StatusBroadcaster] Telegram auto-reconnect failed: " f"{result.get('error')}")
|
|
76
|
+
|
|
77
|
+
span.set_attribute("connected", bool(broadcaster._status["telegram"]["connected"]))
|
|
84
78
|
except Exception as e:
|
|
85
79
|
span.record_exception(e)
|
|
86
80
|
logger.debug(f"[StatusBroadcaster] Could not refresh Telegram status: {e}")
|
|
@@ -98,9 +92,5 @@ async def precheck_telegram_trigger(parameters: Dict) -> str | None:
|
|
|
98
92
|
if not service.connected:
|
|
99
93
|
return "Telegram bot not connected. Add bot token in Credentials."
|
|
100
94
|
sender_filter = parameters.get("sender_filter", "all")
|
|
101
|
-
logger.info(
|
|
102
|
-
"[TelegramTrigger] starting "
|
|
103
|
-
f"sender_filter={sender_filter} "
|
|
104
|
-
f"owner_detected={service.owner_chat_id is not None}"
|
|
105
|
-
)
|
|
95
|
+
logger.info("[TelegramTrigger] starting " f"sender_filter={sender_filter} " f"owner_detected={service.owner_chat_id is not None}")
|
|
106
96
|
return None
|
|
@@ -30,7 +30,7 @@ Public surface (consumed by `_handlers.py`, `telegram_send.py`,
|
|
|
30
30
|
handlers.
|
|
31
31
|
|
|
32
32
|
Auth lookups go through :class:`TelegramCredential.resolve` (lifted from
|
|
33
|
-
the per-key ``auth.get_api_key("
|
|
33
|
+
the per-key ``auth.get_api_key("telegram")`` / ``..._owner_chat_id``
|
|
34
34
|
calls scattered across the previous handler/router code). The credential
|
|
35
35
|
class stays declarative — :class:`ApiKeyCredential` does the heavy lifting,
|
|
36
36
|
this service just consumes the resolved dict.
|
|
@@ -165,7 +165,7 @@ class TelegramService(ServiceSingleton):
|
|
|
165
165
|
# =========================================================================
|
|
166
166
|
|
|
167
167
|
async def has_stored_token(self) -> bool:
|
|
168
|
-
"""Whether `
|
|
168
|
+
"""Whether the `telegram` bot-token credential is persisted in auth."""
|
|
169
169
|
try:
|
|
170
170
|
secrets = await TelegramCredential.resolve()
|
|
171
171
|
return bool(secrets.get("api_key"))
|
|
@@ -175,17 +175,16 @@ class TelegramService(ServiceSingleton):
|
|
|
175
175
|
async def connect(self, token: Optional[str] = None) -> Dict[str, Any]:
|
|
176
176
|
"""Connect to Telegram with bot token and start polling.
|
|
177
177
|
|
|
178
|
-
When ``token`` is omitted, falls back to the stored
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
calls connect.
|
|
178
|
+
When ``token`` is omitted, falls back to the stored ``telegram``
|
|
179
|
+
bot-token credential — matches the Twitter/Google OAuth pattern
|
|
180
|
+
where the frontend saves credentials first and then calls connect.
|
|
182
181
|
|
|
183
182
|
Idempotent: if already connected, returns success without tearing
|
|
184
183
|
down the working bot. See the in-line comment block for the race
|
|
185
184
|
this guards against.
|
|
186
185
|
"""
|
|
187
186
|
# Resolve credentials via the declarative class instead of raw
|
|
188
|
-
# ``auth.get_api_key("
|
|
187
|
+
# ``auth.get_api_key("telegram")`` / ``..._owner_chat_id``
|
|
189
188
|
# lookups. Keeps the credential id in one place.
|
|
190
189
|
secrets: Dict[str, Any] = {}
|
|
191
190
|
if not token:
|
|
@@ -204,15 +203,12 @@ class TelegramService(ServiceSingleton):
|
|
|
204
203
|
# tasks fired on overlapping WebSocket connects.
|
|
205
204
|
if self._connected:
|
|
206
205
|
logger.debug(
|
|
207
|
-
"[Telegram] connect() called while already connected to "
|
|
208
|
-
f"@{self._bot_info.get('username')}, returning success",
|
|
206
|
+
"[Telegram] connect() called while already connected to " f"@{self._bot_info.get('username')}, returning success",
|
|
209
207
|
)
|
|
210
208
|
return {
|
|
211
209
|
"success": True,
|
|
212
210
|
"bot": self._bot_info,
|
|
213
|
-
"message": (
|
|
214
|
-
f"Already connected to @{self._bot_info.get('username')}"
|
|
215
|
-
),
|
|
211
|
+
"message": (f"Already connected to @{self._bot_info.get('username')}"),
|
|
216
212
|
}
|
|
217
213
|
|
|
218
214
|
try:
|
|
@@ -241,9 +237,7 @@ class TelegramService(ServiceSingleton):
|
|
|
241
237
|
)
|
|
242
238
|
self._bot = self._application.bot
|
|
243
239
|
self._token = token
|
|
244
|
-
self._application.add_handler(
|
|
245
|
-
MessageHandler(filters.ALL, self._on_message_received)
|
|
246
|
-
)
|
|
240
|
+
self._application.add_handler(MessageHandler(filters.ALL, self._on_message_received))
|
|
247
241
|
|
|
248
242
|
await self._application.initialize()
|
|
249
243
|
|
|
@@ -265,9 +259,7 @@ class TelegramService(ServiceSingleton):
|
|
|
265
259
|
saved_owner = secrets.get("telegram_owner_chat_id")
|
|
266
260
|
if saved_owner is None:
|
|
267
261
|
try:
|
|
268
|
-
saved_owner = (await TelegramCredential.resolve()).get(
|
|
269
|
-
"telegram_owner_chat_id"
|
|
270
|
-
)
|
|
262
|
+
saved_owner = (await TelegramCredential.resolve()).get("telegram_owner_chat_id")
|
|
271
263
|
except PermissionError:
|
|
272
264
|
saved_owner = None
|
|
273
265
|
if saved_owner:
|
|
@@ -411,6 +403,7 @@ class TelegramService(ServiceSingleton):
|
|
|
411
403
|
captured_id = m.from_user.id
|
|
412
404
|
try:
|
|
413
405
|
from services.plugin.deps import get_auth_service
|
|
406
|
+
|
|
414
407
|
await get_auth_service().store_api_key(
|
|
415
408
|
"telegram_owner_chat_id",
|
|
416
409
|
str(captured_id),
|
|
@@ -425,10 +418,7 @@ class TelegramService(ServiceSingleton):
|
|
|
425
418
|
)
|
|
426
419
|
return
|
|
427
420
|
self._owner_chat_id = captured_id
|
|
428
|
-
logger.info(
|
|
429
|
-
f"[Telegram] Owner retroactively captured from pending "
|
|
430
|
-
f"updates: @{m.from_user.username} (ID: {captured_id})"
|
|
431
|
-
)
|
|
421
|
+
logger.info(f"[Telegram] Owner retroactively captured from pending " f"updates: @{m.from_user.username} (ID: {captured_id})")
|
|
432
422
|
return
|
|
433
423
|
|
|
434
424
|
async def _on_message_received(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
@@ -449,15 +439,12 @@ class TelegramService(ServiceSingleton):
|
|
|
449
439
|
# what went wrong. The new order preserves the invariant
|
|
450
440
|
# "in-memory has owner => DB has owner" so a restart can
|
|
451
441
|
# always re-capture from the next inbound private message.
|
|
452
|
-
if
|
|
453
|
-
self._owner_chat_id is None
|
|
454
|
-
and msg.chat.type == "private"
|
|
455
|
-
and msg.from_user
|
|
456
|
-
):
|
|
442
|
+
if self._owner_chat_id is None and msg.chat.type == "private" and msg.from_user:
|
|
457
443
|
captured_id = msg.from_user.id
|
|
458
444
|
persist_ok = False
|
|
459
445
|
try:
|
|
460
446
|
from services.plugin.deps import get_auth_service
|
|
447
|
+
|
|
461
448
|
await get_auth_service().store_api_key(
|
|
462
449
|
"telegram_owner_chat_id",
|
|
463
450
|
str(captured_id),
|
|
@@ -481,10 +468,7 @@ class TelegramService(ServiceSingleton):
|
|
|
481
468
|
)
|
|
482
469
|
if persist_ok:
|
|
483
470
|
self._owner_chat_id = captured_id
|
|
484
|
-
logger.info(
|
|
485
|
-
f"[Telegram] Owner detected and persisted: "
|
|
486
|
-
f"@{msg.from_user.username} (ID: {captured_id})"
|
|
487
|
-
)
|
|
471
|
+
logger.info(f"[Telegram] Owner detected and persisted: " f"@{msg.from_user.username} (ID: {captured_id})")
|
|
488
472
|
await self._broadcast_status()
|
|
489
473
|
|
|
490
474
|
event_data = self._format_message(msg)
|
|
@@ -494,9 +478,11 @@ class TelegramService(ServiceSingleton):
|
|
|
494
478
|
f"chat_type={event_data.get('chat_type')}"
|
|
495
479
|
)
|
|
496
480
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
481
|
+
# Route via plugin _events.py wrapper — canary CloudEvents
|
|
482
|
+
# path (Visibility-query Signal + WS broadcast).
|
|
483
|
+
from . import dispatch_telegram_message_received
|
|
484
|
+
|
|
485
|
+
await dispatch_telegram_message_received(event_data)
|
|
500
486
|
except Exception as e:
|
|
501
487
|
logger.error(f"[Telegram] Message handler error: {e}")
|
|
502
488
|
|
|
@@ -570,9 +556,10 @@ class TelegramService(ServiceSingleton):
|
|
|
570
556
|
|
|
571
557
|
async def _broadcast_status(self):
|
|
572
558
|
try:
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
559
|
+
# Wave 12 B3: route via plugin _events.py wrapper.
|
|
560
|
+
from . import broadcast_telegram_status
|
|
561
|
+
|
|
562
|
+
await broadcast_telegram_status(
|
|
576
563
|
connected=self._connected,
|
|
577
564
|
bot_id=self._bot_info.get("id"),
|
|
578
565
|
bot_username=self._bot_info.get("username"),
|
|
@@ -601,12 +588,11 @@ class TelegramService(ServiceSingleton):
|
|
|
601
588
|
if not text:
|
|
602
589
|
return text, "HTML"
|
|
603
590
|
from services.markdown_formatter import to_telegram_html
|
|
591
|
+
|
|
604
592
|
return to_telegram_html(text), "HTML"
|
|
605
593
|
|
|
606
594
|
@classmethod
|
|
607
|
-
def _resolve_body(
|
|
608
|
-
cls, body: Optional[str], parse_mode: Optional[str]
|
|
609
|
-
) -> tuple[Optional[str], Optional[str]]:
|
|
595
|
+
def _resolve_body(cls, body: Optional[str], parse_mode: Optional[str]) -> tuple[Optional[str], Optional[str]]:
|
|
610
596
|
"""Apply parse-mode preprocessing to a text/caption. Returns
|
|
611
597
|
``(body, effective_parse_mode)``."""
|
|
612
598
|
if parse_mode == "Auto":
|
|
@@ -636,10 +622,7 @@ class TelegramService(ServiceSingleton):
|
|
|
636
622
|
)
|
|
637
623
|
except BadRequest as e:
|
|
638
624
|
if "can't parse entities" in str(e).lower() and effective_pm:
|
|
639
|
-
logger.warning(
|
|
640
|
-
f"[Telegram] Parse mode {effective_pm} failed for "
|
|
641
|
-
f"{method.__name__}, sending as plain text"
|
|
642
|
-
)
|
|
625
|
+
logger.warning(f"[Telegram] Parse mode {effective_pm} failed for " f"{method.__name__}, sending as plain text")
|
|
643
626
|
return await method(
|
|
644
627
|
**{body_kw: body},
|
|
645
628
|
parse_mode=None,
|
|
@@ -670,7 +653,8 @@ class TelegramService(ServiceSingleton):
|
|
|
670
653
|
if len(chunks) > 1:
|
|
671
654
|
logger.info(
|
|
672
655
|
"[Telegram] Splitting %d-char message into %d parts",
|
|
673
|
-
len(text),
|
|
656
|
+
len(text),
|
|
657
|
+
len(chunks),
|
|
674
658
|
)
|
|
675
659
|
|
|
676
660
|
first_msg: Any = None
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#0088CC">
|
|
2
|
+
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/>
|
|
3
|
+
</svg>
|
|
@@ -23,15 +23,31 @@ class TelegramReceiveParams(BaseModel):
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
content_type_filter: Literal[
|
|
26
|
-
"all",
|
|
27
|
-
"
|
|
26
|
+
"all",
|
|
27
|
+
"text",
|
|
28
|
+
"photo",
|
|
29
|
+
"video",
|
|
30
|
+
"audio",
|
|
31
|
+
"voice",
|
|
32
|
+
"document",
|
|
33
|
+
"sticker",
|
|
34
|
+
"location",
|
|
35
|
+
"contact",
|
|
36
|
+
"poll",
|
|
28
37
|
] = Field(
|
|
29
38
|
default="all",
|
|
30
39
|
description="Filter by message content type",
|
|
31
40
|
)
|
|
32
41
|
sender_filter: Literal[
|
|
33
|
-
"all",
|
|
34
|
-
"
|
|
42
|
+
"all",
|
|
43
|
+
"self",
|
|
44
|
+
"private",
|
|
45
|
+
"group",
|
|
46
|
+
"supergroup",
|
|
47
|
+
"channel",
|
|
48
|
+
"specific_chat",
|
|
49
|
+
"specific_user",
|
|
50
|
+
"keywords",
|
|
35
51
|
] = Field(
|
|
36
52
|
default="all",
|
|
37
53
|
description="Filter which messages trigger the workflow",
|
|
@@ -61,10 +77,20 @@ class TelegramReceiveParams(BaseModel):
|
|
|
61
77
|
default=True,
|
|
62
78
|
description="Do not trigger on messages from other bots",
|
|
63
79
|
json_schema_extra={
|
|
64
|
-
"displayOptions": {
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
"displayOptions": {
|
|
81
|
+
"show": {
|
|
82
|
+
"sender_filter": [
|
|
83
|
+
"all",
|
|
84
|
+
"private",
|
|
85
|
+
"group",
|
|
86
|
+
"supergroup",
|
|
87
|
+
"channel",
|
|
88
|
+
"specific_chat",
|
|
89
|
+
"specific_user",
|
|
90
|
+
"keywords",
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
},
|
|
68
94
|
},
|
|
69
95
|
)
|
|
70
96
|
|
|
@@ -100,10 +126,7 @@ class TelegramReceiveNode(TriggerNode):
|
|
|
100
126
|
group = ("social", "trigger")
|
|
101
127
|
description = "Trigger workflow when Telegram message is received"
|
|
102
128
|
component_kind = "trigger"
|
|
103
|
-
handles = (
|
|
104
|
-
{"name": "output-main", "kind": "output", "position": "right",
|
|
105
|
-
"label": "Output", "role": "main"},
|
|
106
|
-
)
|
|
129
|
+
handles = ({"name": "output-main", "kind": "output", "position": "right", "label": "Output", "role": "main"},)
|
|
107
130
|
credentials = (TelegramCredential,)
|
|
108
131
|
task_queue = TaskQueue.TRIGGERS_EVENT
|
|
109
132
|
mode = "event"
|
|
@@ -116,6 +139,7 @@ class TelegramReceiveNode(TriggerNode):
|
|
|
116
139
|
# Delegate to legacy filter builder for full feature parity —
|
|
117
140
|
# 11.F ports the body and removes the legacy registry entry.
|
|
118
141
|
from services.event_waiter import build_telegram_filter
|
|
142
|
+
|
|
119
143
|
return build_telegram_filter(params.model_dump())
|
|
120
144
|
|
|
121
145
|
async def execute(
|
|
@@ -136,14 +160,10 @@ class TelegramReceiveNode(TriggerNode):
|
|
|
136
160
|
if not getattr(svc, "connected", False):
|
|
137
161
|
return self._wrap_error(
|
|
138
162
|
start_time=time.time(),
|
|
139
|
-
error=(
|
|
140
|
-
"Telegram bot not connected. Add bot token in Credentials."
|
|
141
|
-
),
|
|
163
|
+
error=("Telegram bot not connected. Add bot token in Credentials."),
|
|
142
164
|
)
|
|
143
165
|
return await super().execute(node_id, parameters, context)
|
|
144
166
|
|
|
145
167
|
@Operation("wait")
|
|
146
168
|
async def wait(self, ctx: NodeContext, params: TelegramReceiveParams) -> TelegramReceiveOutput:
|
|
147
|
-
raise NotImplementedError(
|
|
148
|
-
"Event triggers return via TriggerNode.execute, not the op body"
|
|
149
|
-
)
|
|
169
|
+
raise NotImplementedError("Event triggers return via TriggerNode.execute, not the op body")
|