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
|
@@ -26,7 +26,6 @@ Tools deferred to v2: ``getDiagnostics``, ``executeCode``.
|
|
|
26
26
|
from __future__ import annotations
|
|
27
27
|
|
|
28
28
|
import contextvars
|
|
29
|
-
import logging
|
|
30
29
|
import secrets
|
|
31
30
|
from dataclasses import dataclass, field
|
|
32
31
|
from pathlib import Path
|
|
@@ -35,7 +34,6 @@ from typing import Any, Awaitable, Callable, Dict, List, Optional, Set
|
|
|
35
34
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
36
35
|
from starlette.requests import Request
|
|
37
36
|
from starlette.responses import JSONResponse, Response
|
|
38
|
-
from starlette.routing import Mount
|
|
39
37
|
|
|
40
38
|
from core.logging import get_logger
|
|
41
39
|
|
|
@@ -46,6 +44,7 @@ logger = get_logger(__name__)
|
|
|
46
44
|
# BatchContext + token registry
|
|
47
45
|
# ---------------------------------------------------------------------------
|
|
48
46
|
|
|
47
|
+
|
|
49
48
|
@dataclass
|
|
50
49
|
class BatchContext:
|
|
51
50
|
"""Scoping data attached to one batch's bearer token.
|
|
@@ -54,6 +53,7 @@ class BatchContext:
|
|
|
54
53
|
``finally`` block. Tools dereference the calling batch via the
|
|
55
54
|
bearer token in `Authorization` header.
|
|
56
55
|
"""
|
|
56
|
+
|
|
57
57
|
workflow_id: str
|
|
58
58
|
node_id: str
|
|
59
59
|
workspace_dir: Path
|
|
@@ -91,15 +91,18 @@ def register_batch(token: str, ctx: BatchContext) -> None:
|
|
|
91
91
|
_active_tokens[token] = ctx
|
|
92
92
|
tool_names = [t.get("node_type") for t in ctx.connected_tools]
|
|
93
93
|
logger.info(
|
|
94
|
-
"[CC-Agent MCP register_batch] node=%s wf=%s token=%s... "
|
|
95
|
-
|
|
96
|
-
ctx.
|
|
97
|
-
|
|
94
|
+
"[CC-Agent MCP register_batch] node=%s wf=%s token=%s... " "skills=%d tools=%d creds=%d %s",
|
|
95
|
+
ctx.node_id,
|
|
96
|
+
ctx.workflow_id,
|
|
97
|
+
token[:8],
|
|
98
|
+
len(ctx.connected_skill_names),
|
|
99
|
+
len(ctx.connected_tools),
|
|
98
100
|
len(ctx.allowed_credentials),
|
|
99
101
|
f"tools={tool_names}" if tool_names else "(no tools wired)",
|
|
100
102
|
)
|
|
101
103
|
# Per-batch workflow-tool exposure lives in workflow_tools.py.
|
|
102
104
|
from services.cli_agent.workflow_tools import expose_workflow_tools
|
|
105
|
+
|
|
103
106
|
expose_workflow_tools(ctx.connected_tools)
|
|
104
107
|
|
|
105
108
|
|
|
@@ -111,6 +114,7 @@ def unregister_batch(token: str) -> None:
|
|
|
111
114
|
return
|
|
112
115
|
logger.debug("[CC-Agent MCP] unregistered batch token=%s...", token[:8])
|
|
113
116
|
from services.cli_agent.workflow_tools import unexpose_workflow_tools
|
|
117
|
+
|
|
114
118
|
unexpose_workflow_tools(ctx.connected_tools)
|
|
115
119
|
|
|
116
120
|
|
|
@@ -118,6 +122,72 @@ def lookup_batch(token: str) -> Optional[BatchContext]:
|
|
|
118
122
|
return _active_tokens.get(token)
|
|
119
123
|
|
|
120
124
|
|
|
125
|
+
def rebind_batch(
|
|
126
|
+
token: str,
|
|
127
|
+
*,
|
|
128
|
+
connected_tools: Optional[List[Dict[str, Any]]] = None,
|
|
129
|
+
connected_skill_names: Optional[Set[str]] = None,
|
|
130
|
+
allowed_credentials: Optional[Set[str]] = None,
|
|
131
|
+
workspace_dir: Optional[Path] = None,
|
|
132
|
+
) -> Optional[BatchContext]:
|
|
133
|
+
"""In-place rebind of an existing batch's surface.
|
|
134
|
+
|
|
135
|
+
Used by :class:`ClaudeSessionPool` on warm-subprocess reuse:
|
|
136
|
+
claude bakes the bearer token into its argv at spawn time (via
|
|
137
|
+
``--mcp-config``), so a warm subprocess keeps hitting the SAME
|
|
138
|
+
token across batches. If the operator disconnects a tool between
|
|
139
|
+
batches, the bearer-token's :class:`BatchContext` must be updated
|
|
140
|
+
in place — otherwise the per-handler scope check in
|
|
141
|
+
``workflow_tools._build_handler`` still sees the stale
|
|
142
|
+
``connected_tools`` and lets disconnected tools fire.
|
|
143
|
+
|
|
144
|
+
For ``connected_tools``: refcount diff is applied to FastMCP — any
|
|
145
|
+
node_type that's in the OLD list but not the new gets one
|
|
146
|
+
:func:`unexpose_workflow_tools` decrement (may remove the tool
|
|
147
|
+
from FastMCP when its refcount hits zero); any node_type that's
|
|
148
|
+
new gets one :func:`expose_workflow_tools` increment. Tools that
|
|
149
|
+
survive in both lists are left alone but their ``parameters`` /
|
|
150
|
+
``label`` fields are refreshed via the in-place list assignment.
|
|
151
|
+
|
|
152
|
+
Returns the rebound context, or ``None`` if the token is unknown.
|
|
153
|
+
"""
|
|
154
|
+
ctx = _active_tokens.get(token)
|
|
155
|
+
if ctx is None:
|
|
156
|
+
return None
|
|
157
|
+
if connected_tools is not None:
|
|
158
|
+
from services.cli_agent.workflow_tools import (
|
|
159
|
+
expose_workflow_tools,
|
|
160
|
+
unexpose_workflow_tools,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
old_by_type = {t.get("node_type"): t for t in ctx.connected_tools if t.get("node_type")}
|
|
164
|
+
new_by_type = {t.get("node_type"): t for t in connected_tools if t.get("node_type")}
|
|
165
|
+
added = [v for k, v in new_by_type.items() if k not in old_by_type]
|
|
166
|
+
removed = [v for k, v in old_by_type.items() if k not in new_by_type]
|
|
167
|
+
if removed:
|
|
168
|
+
unexpose_workflow_tools(removed)
|
|
169
|
+
if added:
|
|
170
|
+
expose_workflow_tools(added)
|
|
171
|
+
ctx.connected_tools = list(connected_tools)
|
|
172
|
+
logger.info(
|
|
173
|
+
"[CC-Agent MCP rebind_batch] node=%s wf=%s token=%s... " "+%d -%d kept=%d (now %d tools)",
|
|
174
|
+
ctx.node_id,
|
|
175
|
+
ctx.workflow_id,
|
|
176
|
+
token[:8],
|
|
177
|
+
len(added),
|
|
178
|
+
len(removed),
|
|
179
|
+
len(old_by_type.keys() & new_by_type.keys()),
|
|
180
|
+
len(ctx.connected_tools),
|
|
181
|
+
)
|
|
182
|
+
if connected_skill_names is not None:
|
|
183
|
+
ctx.connected_skill_names = set(connected_skill_names)
|
|
184
|
+
if allowed_credentials is not None:
|
|
185
|
+
ctx.allowed_credentials = set(allowed_credentials)
|
|
186
|
+
if workspace_dir is not None:
|
|
187
|
+
ctx.workspace_dir = Path(workspace_dir).resolve()
|
|
188
|
+
return ctx
|
|
189
|
+
|
|
190
|
+
|
|
121
191
|
def active_batch_count() -> int:
|
|
122
192
|
return len(_active_tokens)
|
|
123
193
|
|
|
@@ -126,18 +196,13 @@ def active_batch_count() -> int:
|
|
|
126
196
|
# ContextVar — thread/task-local handle to the current batch
|
|
127
197
|
# ---------------------------------------------------------------------------
|
|
128
198
|
|
|
129
|
-
_current_batch: contextvars.ContextVar[Optional[BatchContext]] = (
|
|
130
|
-
contextvars.ContextVar("machina_current_batch", default=None)
|
|
131
|
-
)
|
|
199
|
+
_current_batch: contextvars.ContextVar[Optional[BatchContext]] = contextvars.ContextVar("machina_current_batch", default=None)
|
|
132
200
|
|
|
133
201
|
|
|
134
202
|
def _require_batch() -> BatchContext:
|
|
135
203
|
ctx = _current_batch.get()
|
|
136
204
|
if ctx is None:
|
|
137
|
-
raise RuntimeError(
|
|
138
|
-
"MCP tool called without an active batch context. "
|
|
139
|
-
"This indicates the auth middleware was bypassed."
|
|
140
|
-
)
|
|
205
|
+
raise RuntimeError("MCP tool called without an active batch context. " "This indicates the auth middleware was bypassed.")
|
|
141
206
|
return ctx
|
|
142
207
|
|
|
143
208
|
|
|
@@ -152,6 +217,7 @@ def _require_batch() -> BatchContext:
|
|
|
152
217
|
# Auth middleware
|
|
153
218
|
# ---------------------------------------------------------------------------
|
|
154
219
|
|
|
220
|
+
|
|
155
221
|
class _BearerAuthMiddleware(BaseHTTPMiddleware):
|
|
156
222
|
"""Validate `Authorization: Bearer <token>` against the registry.
|
|
157
223
|
|
|
@@ -173,9 +239,7 @@ class _BearerAuthMiddleware(BaseHTTPMiddleware):
|
|
|
173
239
|
if path.endswith("/healthz"):
|
|
174
240
|
return await call_next(request)
|
|
175
241
|
|
|
176
|
-
auth = request.headers.get("authorization") or request.headers.get(
|
|
177
|
-
"Authorization"
|
|
178
|
-
)
|
|
242
|
+
auth = request.headers.get("authorization") or request.headers.get("Authorization")
|
|
179
243
|
token: Optional[str] = None
|
|
180
244
|
if auth and auth.lower().startswith("bearer "):
|
|
181
245
|
token = auth[7:].strip() or None
|
|
@@ -186,7 +250,10 @@ class _BearerAuthMiddleware(BaseHTTPMiddleware):
|
|
|
186
250
|
"[CC-Agent MCP auth] %s %s -> 401 (no Bearer token; "
|
|
187
251
|
"auth_header=%r ua=%r) — claude CLI either didn't read the "
|
|
188
252
|
"lockfile or is hitting the wrong URL.",
|
|
189
|
-
method,
|
|
253
|
+
method,
|
|
254
|
+
path,
|
|
255
|
+
auth,
|
|
256
|
+
ua,
|
|
190
257
|
)
|
|
191
258
|
return JSONResponse(
|
|
192
259
|
{"error": "missing or malformed Authorization header"},
|
|
@@ -196,9 +263,10 @@ class _BearerAuthMiddleware(BaseHTTPMiddleware):
|
|
|
196
263
|
ctx = lookup_batch(token)
|
|
197
264
|
if ctx is None:
|
|
198
265
|
logger.warning(
|
|
199
|
-
"[CC-Agent MCP auth] %s %s -> 401 (token=%s... not in "
|
|
200
|
-
|
|
201
|
-
|
|
266
|
+
"[CC-Agent MCP auth] %s %s -> 401 (token=%s... not in " "active registry — batch may have ended)",
|
|
267
|
+
method,
|
|
268
|
+
path,
|
|
269
|
+
token[:8],
|
|
202
270
|
)
|
|
203
271
|
return JSONResponse(
|
|
204
272
|
{"error": "invalid or expired token"},
|
|
@@ -207,7 +275,11 @@ class _BearerAuthMiddleware(BaseHTTPMiddleware):
|
|
|
207
275
|
|
|
208
276
|
logger.info(
|
|
209
277
|
"[CC-Agent MCP auth] %s %s -> OK (node=%s wf=%s token=%s...)",
|
|
210
|
-
method,
|
|
278
|
+
method,
|
|
279
|
+
path,
|
|
280
|
+
ctx.node_id,
|
|
281
|
+
ctx.workflow_id,
|
|
282
|
+
token[:8],
|
|
211
283
|
)
|
|
212
284
|
|
|
213
285
|
reset_token = _current_batch.set(ctx)
|
|
@@ -221,6 +293,7 @@ class _BearerAuthMiddleware(BaseHTTPMiddleware):
|
|
|
221
293
|
# Tool registration helper — defers FastMCP import so module import is cheap
|
|
222
294
|
# ---------------------------------------------------------------------------
|
|
223
295
|
|
|
296
|
+
|
|
224
297
|
def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
225
298
|
"""Register the 5 v1 tools on a `FastMCP` instance."""
|
|
226
299
|
|
|
@@ -272,9 +345,7 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
272
345
|
}
|
|
273
346
|
if read and p.stat().st_size <= max_bytes:
|
|
274
347
|
try:
|
|
275
|
-
info["content"] = p.read_text(
|
|
276
|
-
encoding="utf-8", errors="replace"
|
|
277
|
-
)
|
|
348
|
+
info["content"] = p.read_text(encoding="utf-8", errors="replace")
|
|
278
349
|
except OSError as exc:
|
|
279
350
|
info["read_error"] = str(exc)
|
|
280
351
|
entries.append(info)
|
|
@@ -301,6 +372,7 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
301
372
|
ctx = _require_batch()
|
|
302
373
|
try:
|
|
303
374
|
from services.skill_loader import get_skill_loader
|
|
375
|
+
|
|
304
376
|
loader = get_skill_loader()
|
|
305
377
|
registry = loader.scan_skills()
|
|
306
378
|
results = []
|
|
@@ -308,15 +380,14 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
308
380
|
meta = registry.get(name)
|
|
309
381
|
if meta is None:
|
|
310
382
|
continue
|
|
311
|
-
results.append(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
meta.metadata.get("category")
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
})
|
|
383
|
+
results.append(
|
|
384
|
+
{
|
|
385
|
+
"name": meta.name,
|
|
386
|
+
"description": meta.description,
|
|
387
|
+
"allowed_tools": list(meta.allowed_tools),
|
|
388
|
+
"category": (meta.metadata.get("category") if isinstance(meta.metadata, dict) else None),
|
|
389
|
+
}
|
|
390
|
+
)
|
|
320
391
|
return {"skills": results}
|
|
321
392
|
except Exception as exc: # pragma: no cover
|
|
322
393
|
logger.exception("[CC-Agent MCP] listSkills failed")
|
|
@@ -339,6 +410,7 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
339
410
|
}
|
|
340
411
|
try:
|
|
341
412
|
from services.skill_loader import get_skill_loader
|
|
413
|
+
|
|
342
414
|
loader = get_skill_loader()
|
|
343
415
|
skill = loader.load_skill(name)
|
|
344
416
|
if skill is None:
|
|
@@ -375,6 +447,7 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
375
447
|
}
|
|
376
448
|
try:
|
|
377
449
|
from core.container import container
|
|
450
|
+
|
|
378
451
|
auth = container.auth_service()
|
|
379
452
|
value = await auth.get_api_key(name)
|
|
380
453
|
if not value:
|
|
@@ -413,6 +486,7 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
413
486
|
broadcaster = ctx.broadcaster
|
|
414
487
|
if broadcaster is None:
|
|
415
488
|
from services.status_broadcaster import get_status_broadcaster
|
|
489
|
+
|
|
416
490
|
broadcaster = get_status_broadcaster()
|
|
417
491
|
payload = {
|
|
418
492
|
"source": source or f"mcp:{ctx.node_id}",
|
|
@@ -432,7 +506,7 @@ def _build_tools(mcp: Any) -> None: # FastMCP type
|
|
|
432
506
|
|
|
433
507
|
_app_singleton: Optional[Any] = None # Starlette app
|
|
434
508
|
_mcp_singleton: Optional[Any] = None # FastMCP instance — used by per-batch
|
|
435
|
-
|
|
509
|
+
# dynamic tool (un)registration.
|
|
436
510
|
|
|
437
511
|
|
|
438
512
|
def get_mcp_app() -> Any:
|
|
@@ -471,6 +545,7 @@ def get_mcp_app() -> Any:
|
|
|
471
545
|
# Test/diagnostic helpers (used by tests + verification step #11/#12)
|
|
472
546
|
# ---------------------------------------------------------------------------
|
|
473
547
|
|
|
548
|
+
|
|
474
549
|
def _reset_for_tests() -> None: # pragma: no cover
|
|
475
550
|
"""Wipe the token registry + per-batch workflow-tool refcounts.
|
|
476
551
|
ONLY use in tests."""
|
|
@@ -479,4 +554,5 @@ def _reset_for_tests() -> None: # pragma: no cover
|
|
|
479
554
|
_app_singleton = None
|
|
480
555
|
_mcp_singleton = None
|
|
481
556
|
from services.cli_agent.workflow_tools import _reset_for_tests as _wt_reset
|
|
557
|
+
|
|
482
558
|
_wt_reset()
|
|
@@ -25,6 +25,7 @@ from typing import Any, Dict, List, Optional, Protocol, runtime_checkable
|
|
|
25
25
|
# Shared data types
|
|
26
26
|
# ---------------------------------------------------------------------------
|
|
27
27
|
|
|
28
|
+
|
|
28
29
|
@dataclass
|
|
29
30
|
class CanonicalUsage:
|
|
30
31
|
"""Vendor-normalised token counts.
|
|
@@ -34,6 +35,7 @@ class CanonicalUsage:
|
|
|
34
35
|
differently) maps into this so the existing `services/pricing.py`
|
|
35
36
|
can compute USD without per-vendor branches.
|
|
36
37
|
"""
|
|
38
|
+
|
|
37
39
|
input_tokens: int = 0
|
|
38
40
|
output_tokens: int = 0
|
|
39
41
|
cache_read: int = 0
|
|
@@ -48,6 +50,7 @@ class SessionResult:
|
|
|
48
50
|
|
|
49
51
|
Shared keys are the schema; vendor extras live in `provider_data`.
|
|
50
52
|
"""
|
|
53
|
+
|
|
51
54
|
task_id: str
|
|
52
55
|
session_id: Optional[str] = None
|
|
53
56
|
provider: str = ""
|
|
@@ -68,6 +71,7 @@ class SessionResult:
|
|
|
68
71
|
@dataclass
|
|
69
72
|
class BatchResult:
|
|
70
73
|
"""Aggregated result returned by `AICliService.run_batch()`."""
|
|
74
|
+
|
|
71
75
|
tasks: List[SessionResult] = field(default_factory=list)
|
|
72
76
|
n_tasks: int = 0
|
|
73
77
|
n_succeeded: int = 0
|
|
@@ -83,48 +87,57 @@ class BatchResult:
|
|
|
83
87
|
# Provider protocol (structural typing)
|
|
84
88
|
# ---------------------------------------------------------------------------
|
|
85
89
|
|
|
90
|
+
|
|
86
91
|
@runtime_checkable
|
|
87
92
|
class AICliProvider(Protocol):
|
|
88
93
|
"""Structural Protocol for an AI CLI provider.
|
|
89
94
|
|
|
90
95
|
Concrete classes:
|
|
91
|
-
- `
|
|
96
|
+
- `nodes.agent.claude_code_agent._provider.AnthropicClaudeProvider`
|
|
92
97
|
- `providers.openai_codex.OpenAICodexProvider`
|
|
93
98
|
- `providers.google_gemini.GoogleGeminiProvider` (v2 stub)
|
|
94
99
|
"""
|
|
95
100
|
|
|
96
|
-
name: str
|
|
97
|
-
package_name: str
|
|
98
|
-
binary_name: str
|
|
99
|
-
ide_lock_env_var: Optional[str]
|
|
100
|
-
ide_lockfile_dir: Optional[Path]
|
|
101
|
+
name: str # "claude" | "codex" | "gemini"
|
|
102
|
+
package_name: str # npm package
|
|
103
|
+
binary_name: str # "claude" | "codex" | "gemini"
|
|
104
|
+
ide_lock_env_var: Optional[str] # CLAUDE_IDE_LOCK | GEMINI_IDE_LOCK | None
|
|
105
|
+
ide_lockfile_dir: Optional[Path] # <MACHINA_CLAUDE_DIR>/ide | <tmpdir>/gemini/ide
|
|
101
106
|
|
|
102
107
|
# ---- spawn surface ---------------------------------------------------
|
|
103
108
|
|
|
104
|
-
def binary_path(self) -> Path:
|
|
109
|
+
def binary_path(self) -> Path:
|
|
110
|
+
...
|
|
105
111
|
# Resolve the CLI binary. Resolution chain (Composio pattern):
|
|
106
112
|
# 1) shutil.which(<binary_name>)
|
|
107
113
|
# 2) `npx --yes <package_name>` shim path
|
|
108
114
|
# Raises FileNotFoundError if neither is available.
|
|
109
115
|
|
|
110
|
-
def
|
|
111
|
-
|
|
112
|
-
#
|
|
113
|
-
#
|
|
116
|
+
def interactive_argv(self, task: Any, *, defaults: Dict[str, Any]) -> List[str]:
|
|
117
|
+
...
|
|
118
|
+
# Build the full argv (binary + flags) for spawning a session
|
|
119
|
+
# over `task` (a `<Provider>TaskSpec` Pydantic model). For
|
|
120
|
+
# Claude, this is the interactive-TUI shape (no `-p`, prompt as
|
|
121
|
+
# positional after `--`); for Codex, it's `codex exec --json`
|
|
122
|
+
# since that's Codex's automation surface. `defaults` comes
|
|
123
|
+
# from `ai_cli_providers.json` for this provider.
|
|
114
124
|
|
|
115
125
|
# ---- native auth (no token wrapping) --------------------------------
|
|
116
126
|
|
|
117
|
-
def login_argv(self) -> List[str]:
|
|
127
|
+
def login_argv(self) -> List[str]:
|
|
128
|
+
...
|
|
118
129
|
# CLI's own login command, e.g. ["claude", "login"]. Spawned
|
|
119
130
|
# interactively from the Credentials Modal. CLI stores its own
|
|
120
131
|
# credentials in `~/.claude/`, `~/.codex/`, `~/.gemini/`.
|
|
121
132
|
|
|
122
|
-
def auth_status_argv(self) -> Optional[List[str]]:
|
|
133
|
+
def auth_status_argv(self) -> Optional[List[str]]:
|
|
134
|
+
...
|
|
123
135
|
# No-op invocation to verify auth, e.g. ["claude", "--print", "-p", "ok"].
|
|
124
136
|
# Returns None if no cheap probe exists; in that case the framework
|
|
125
137
|
# infers from the first session's stderr.
|
|
126
138
|
|
|
127
|
-
def detect_auth_error(self, stderr: str, exit_code: int) -> bool:
|
|
139
|
+
def detect_auth_error(self, stderr: str, exit_code: int) -> bool:
|
|
140
|
+
...
|
|
128
141
|
# Match "not logged in" patterns:
|
|
129
142
|
# Claude: "Please run 'claude login'"
|
|
130
143
|
# Codex: HTTP 401 / "OPENAI_API_KEY not set"
|
|
@@ -132,11 +145,13 @@ class AICliProvider(Protocol):
|
|
|
132
145
|
|
|
133
146
|
# ---- streaming output parsing ---------------------------------------
|
|
134
147
|
|
|
135
|
-
def parse_event(self, line: str) -> Optional[Dict[str, Any]]:
|
|
148
|
+
def parse_event(self, line: str) -> Optional[Dict[str, Any]]:
|
|
149
|
+
...
|
|
136
150
|
# Parse a single NDJSON line from stdout. Return None for
|
|
137
151
|
# un-parseable garbage.
|
|
138
152
|
|
|
139
|
-
def is_final_event(self, event: Dict[str, Any]) -> bool:
|
|
153
|
+
def is_final_event(self, event: Dict[str, Any]) -> bool:
|
|
154
|
+
...
|
|
140
155
|
# True if this event marks end-of-task. For Claude: `type=="result"`.
|
|
141
156
|
# For Gemini: `type=="result"`. For Codex: `type=="complete"` or
|
|
142
157
|
# heuristic fallback.
|
|
@@ -146,7 +161,8 @@ class AICliProvider(Protocol):
|
|
|
146
161
|
events: List[Dict[str, Any]],
|
|
147
162
|
stderr: str,
|
|
148
163
|
exit_code: int,
|
|
149
|
-
) -> Dict[str, Any]:
|
|
164
|
+
) -> Dict[str, Any]:
|
|
165
|
+
...
|
|
150
166
|
# Reconstruct a partial dict of `SessionResult` fields from the
|
|
151
167
|
# event stream. Returns:
|
|
152
168
|
# {
|
|
@@ -161,13 +177,15 @@ class AICliProvider(Protocol):
|
|
|
161
177
|
# bloating the shared schema. Pattern from
|
|
162
178
|
# Hermes agent/transports/types.py NormalizedResponse.
|
|
163
179
|
|
|
164
|
-
def canonical_usage(self, events: List[Dict[str, Any]]) -> CanonicalUsage:
|
|
180
|
+
def canonical_usage(self, events: List[Dict[str, Any]]) -> CanonicalUsage:
|
|
181
|
+
...
|
|
165
182
|
# Normalise vendor token-counting into the shared `CanonicalUsage`
|
|
166
183
|
# shape. Pattern from Hermes agent/usage_pricing.py.
|
|
167
184
|
|
|
168
185
|
# ---- feature gating --------------------------------------------------
|
|
169
186
|
|
|
170
|
-
def supports(self, feature: str) -> bool:
|
|
187
|
+
def supports(self, feature: str) -> bool:
|
|
188
|
+
...
|
|
171
189
|
# Feature flags consulted by the session/service layer.
|
|
172
190
|
# Recognised: "max_budget", "max_turns", "session_id", "resume",
|
|
173
191
|
# "mcp_runtime", "json_cost", "ide_lockfile", "sandbox".
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
"""Concrete `AICliProvider` implementations
|
|
1
|
+
"""Concrete `AICliProvider` implementations that still live under the
|
|
2
|
+
generic framework (i.e. haven't been migrated to the canonical
|
|
3
|
+
plugin-folder layout yet):
|
|
2
4
|
|
|
3
|
-
- `anthropic_claude.AnthropicClaudeProvider` — full v1 surface
|
|
4
5
|
- `openai_codex.OpenAICodexProvider` — sandbox-first, no session
|
|
5
6
|
- `google_gemini.GoogleGeminiProvider` — v2 stub raising NotImplementedError
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
The claude provider has moved to its plugin folder
|
|
9
|
+
(``server/nodes/agent/claude_code_agent/_provider.py``) and is
|
|
10
|
+
discovered via the ``register_provider`` registry. The codex
|
|
11
|
+
provider will follow once `codex_agent` adopts the per-plugin
|
|
12
|
+
folder structure.
|
|
9
13
|
"""
|
|
@@ -30,10 +30,7 @@ class GoogleGeminiProvider:
|
|
|
30
30
|
name = "gemini"
|
|
31
31
|
|
|
32
32
|
def __init__(self) -> None:
|
|
33
|
-
raise NotImplementedError(
|
|
34
|
-
"GoogleGeminiProvider is a v2 stub. The factory raises "
|
|
35
|
-
"NotImplementedError for 'gemini' in v1."
|
|
36
|
-
)
|
|
33
|
+
raise NotImplementedError("GoogleGeminiProvider is a v2 stub. The factory raises " "NotImplementedError for 'gemini' in v1.")
|
|
37
34
|
|
|
38
35
|
# The Protocol surface below is declared so static type-checkers see
|
|
39
36
|
# the class as a complete `AICliProvider`. None of these are reachable
|
|
@@ -47,7 +44,16 @@ class GoogleGeminiProvider:
|
|
|
47
44
|
def binary_path(self) -> Path: # pragma: no cover
|
|
48
45
|
raise NotImplementedError
|
|
49
46
|
|
|
50
|
-
def
|
|
47
|
+
def interactive_argv(
|
|
48
|
+
self,
|
|
49
|
+
task: Any,
|
|
50
|
+
*,
|
|
51
|
+
defaults: Dict[str, Any],
|
|
52
|
+
mcp_endpoint_url: Optional[str] = None,
|
|
53
|
+
mcp_bearer_token: Optional[str] = None,
|
|
54
|
+
connected_tool_names: Optional[List[str]] = None,
|
|
55
|
+
include_prompt: bool = True,
|
|
56
|
+
) -> List[str]: # pragma: no cover
|
|
51
57
|
raise NotImplementedError
|
|
52
58
|
|
|
53
59
|
def login_argv(self) -> List[str]: # pragma: no cover
|
|
@@ -46,9 +46,15 @@ NAME = "codex"
|
|
|
46
46
|
|
|
47
47
|
# Best-effort markers for Codex's "stream-end" / "task complete" event.
|
|
48
48
|
# Update if/when OpenAI publishes a stable schema.
|
|
49
|
-
_FINAL_EVENT_TYPES = frozenset(
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
_FINAL_EVENT_TYPES = frozenset(
|
|
50
|
+
{
|
|
51
|
+
"complete",
|
|
52
|
+
"task_complete",
|
|
53
|
+
"done",
|
|
54
|
+
"finished",
|
|
55
|
+
"result",
|
|
56
|
+
}
|
|
57
|
+
)
|
|
52
58
|
|
|
53
59
|
_AUTH_ERROR_MARKERS = (
|
|
54
60
|
"OPENAI_API_KEY not set",
|
|
@@ -68,9 +74,7 @@ class OpenAICodexProvider:
|
|
|
68
74
|
def __init__(self) -> None:
|
|
69
75
|
cfg = get_provider_config(NAME)
|
|
70
76
|
if cfg is None:
|
|
71
|
-
raise RuntimeError(
|
|
72
|
-
f"Provider config missing for {NAME!r}. Check ai_cli_providers.json."
|
|
73
|
-
)
|
|
77
|
+
raise RuntimeError(f"Provider config missing for {NAME!r}. Check ai_cli_providers.json.")
|
|
74
78
|
self.name = NAME
|
|
75
79
|
self.package_name = cfg.package_name
|
|
76
80
|
self.binary_name = cfg.binary_name
|
|
@@ -93,21 +97,29 @@ class OpenAICodexProvider:
|
|
|
93
97
|
return Path(npx)
|
|
94
98
|
|
|
95
99
|
raise FileNotFoundError(
|
|
96
|
-
f"Neither {self.binary_name!r} nor 'npx' found in PATH. "
|
|
97
|
-
f"Install with: npm install -g {self.package_name}"
|
|
100
|
+
f"Neither {self.binary_name!r} nor 'npx' found in PATH. " f"Install with: npm install -g {self.package_name}"
|
|
98
101
|
)
|
|
99
102
|
|
|
100
|
-
def
|
|
103
|
+
def interactive_argv(
|
|
101
104
|
self,
|
|
102
105
|
task: Any, # CodexTaskSpec
|
|
103
106
|
*,
|
|
104
107
|
defaults: Dict[str, Any],
|
|
108
|
+
mcp_endpoint_url: Optional[str] = None,
|
|
109
|
+
mcp_bearer_token: Optional[str] = None,
|
|
110
|
+
connected_tool_names: Optional[List[str]] = None,
|
|
111
|
+
include_prompt: bool = True,
|
|
105
112
|
) -> List[str]:
|
|
113
|
+
"""Build the codex spawn argv. Codex's automation surface is
|
|
114
|
+
``codex exec --json`` (not a TUI mode like claude); this method
|
|
115
|
+
keeps the name aligned with the Protocol while emitting Codex's
|
|
116
|
+
documented non-interactive form. MCP bridging params are accepted
|
|
117
|
+
for Protocol uniformity but unused (codex's MCP config lives in
|
|
118
|
+
``~/.codex/config.toml``). ``include_prompt`` is honoured so the
|
|
119
|
+
session pool can spawn without an initial prompt."""
|
|
120
|
+
_ = (mcp_endpoint_url, mcp_bearer_token, connected_tool_names)
|
|
106
121
|
if not isinstance(task, CodexTaskSpec):
|
|
107
|
-
raise TypeError(
|
|
108
|
-
"OpenAICodexProvider.headless_argv requires CodexTaskSpec, "
|
|
109
|
-
f"got {type(task).__name__}"
|
|
110
|
-
)
|
|
122
|
+
raise TypeError("OpenAICodexProvider.interactive_argv requires CodexTaskSpec, " f"got {type(task).__name__}")
|
|
111
123
|
|
|
112
124
|
which_codex = shutil.which(self.binary_name)
|
|
113
125
|
if which_codex:
|
|
@@ -115,18 +127,12 @@ class OpenAICodexProvider:
|
|
|
115
127
|
else:
|
|
116
128
|
npx = shutil.which("npx")
|
|
117
129
|
if not npx:
|
|
118
|
-
raise FileNotFoundError(
|
|
119
|
-
f"Neither {self.binary_name!r} nor 'npx' found in PATH"
|
|
120
|
-
)
|
|
130
|
+
raise FileNotFoundError(f"Neither {self.binary_name!r} nor 'npx' found in PATH")
|
|
121
131
|
argv = [npx, "--yes", self.package_name]
|
|
122
132
|
|
|
123
133
|
argv += ["exec", "--json"]
|
|
124
134
|
|
|
125
|
-
model = (
|
|
126
|
-
task.model
|
|
127
|
-
or defaults.get("default_model")
|
|
128
|
-
or self._defaults.get("default_model", "gpt-5.2-codex")
|
|
129
|
-
)
|
|
135
|
+
model = task.model or defaults.get("default_model") or self._defaults.get("default_model", "gpt-5.2-codex")
|
|
130
136
|
argv += ["--model", model]
|
|
131
137
|
|
|
132
138
|
sandbox = task.sandbox or defaults.get(
|
|
@@ -144,11 +150,11 @@ class OpenAICodexProvider:
|
|
|
144
150
|
# System prompt — Codex doesn't have a dedicated --system-prompt
|
|
145
151
|
# flag in `exec`. Prepend it to the user prompt with a clear
|
|
146
152
|
# divider when present.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
if include_prompt and task.prompt:
|
|
154
|
+
prompt = task.prompt
|
|
155
|
+
if task.system_prompt:
|
|
156
|
+
prompt = f"<system>\n{task.system_prompt}\n</system>\n\n{task.prompt}"
|
|
157
|
+
argv += [prompt]
|
|
152
158
|
return argv
|
|
153
159
|
|
|
154
160
|
# ---- native auth -----------------------------------------------------
|
|
@@ -195,10 +201,7 @@ class OpenAICodexProvider:
|
|
|
195
201
|
response = self._extract_response(events)
|
|
196
202
|
provider_data = self._extract_provider_data(events)
|
|
197
203
|
|
|
198
|
-
tool_calls = sum(
|
|
199
|
-
1 for e in events
|
|
200
|
-
if e.get("type") in ("tool_call", "tool_use", "function_call")
|
|
201
|
-
)
|
|
204
|
+
tool_calls = sum(1 for e in events if e.get("type") in ("tool_call", "tool_use", "function_call"))
|
|
202
205
|
|
|
203
206
|
success = exit_code == 0
|
|
204
207
|
error: Optional[str] = None
|
|
@@ -240,10 +243,7 @@ class OpenAICodexProvider:
|
|
|
240
243
|
def canonical_usage(self, events: List[Dict[str, Any]]) -> CanonicalUsage:
|
|
241
244
|
# Codex doesn't expose token counts in `--json` output. Return zeros.
|
|
242
245
|
# If a future Codex schema adds usage, extract here.
|
|
243
|
-
request_count = sum(
|
|
244
|
-
1 for e in events
|
|
245
|
-
if e.get("type") in ("assistant", "message", "response")
|
|
246
|
-
)
|
|
246
|
+
request_count = sum(1 for e in events if e.get("type") in ("assistant", "message", "response"))
|
|
247
247
|
return CanonicalUsage(request_count=request_count)
|
|
248
248
|
|
|
249
249
|
# ---- feature gating --------------------------------------------------
|