neoagent 2.3.1-beta.0 → 2.3.1-beta.100
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.example +63 -5
- package/README.md +16 -5
- package/com.neoagent.plist +1 -1
- package/docs/automation.md +82 -41
- package/docs/capabilities.md +85 -89
- package/docs/configuration.md +89 -87
- package/docs/getting-started.md +46 -27
- package/docs/hardware.md +1 -1
- package/docs/index.md +24 -30
- package/docs/integrations.md +46 -60
- package/docs/migration.md +41 -146
- package/docs/operations.md +23 -20
- package/docs/skills.md +20 -20
- package/docs/why-neoagent.md +15 -13
- package/extensions/chrome-browser/background.mjs +10 -2
- package/flutter_app/.metadata +42 -0
- package/flutter_app/DESIGN_SYSTEM.md +166 -0
- package/flutter_app/README.md +21 -0
- package/flutter_app/analysis_options.yaml +32 -0
- package/flutter_app/android/app/build.gradle.kts +111 -0
- package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
- package/flutter_app/android/app/src/main/AndroidManifest.xml +185 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +888 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/auto/NeoAgentCarAppService.kt +114 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnection.kt +118 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnectionService.kt +86 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
- package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
- package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
- package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
- package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
- package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
- package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
- package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
- package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/flutter_app/android/app/src/main/res/values/arrays.xml +8 -0
- package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
- package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
- package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
- package/flutter_app/android/app/src/main/res/xml/automotive_app_desc.xml +4 -0
- package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
- package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
- package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
- package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
- package/flutter_app/android/build.gradle.kts +24 -0
- package/flutter_app/android/ci-release.keystore +0 -0
- package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/flutter_app/android/gradle.properties +3 -0
- package/flutter_app/android/key.properties +4 -0
- package/flutter_app/android/settings.gradle.kts +26 -0
- package/flutter_app/assets/branding/app_icon_1024.png +0 -0
- package/flutter_app/assets/branding/app_icon_128.png +0 -0
- package/flutter_app/assets/branding/app_icon_192.png +0 -0
- package/flutter_app/assets/branding/app_icon_256.png +0 -0
- package/flutter_app/assets/branding/app_icon_32.png +0 -0
- package/flutter_app/assets/branding/app_icon_512.png +0 -0
- package/flutter_app/assets/branding/app_icon_64.png +0 -0
- package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
- package/flutter_app/assets/branding/tray_icon_template.png +0 -0
- package/flutter_app/lib/features/location/location_service.dart +117 -0
- package/flutter_app/lib/features/notifications/notification_interceptor.dart +73 -0
- package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +571 -0
- package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +275 -0
- package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +366 -0
- package/flutter_app/lib/features/onboarding/onboarding_shell.dart +57 -0
- package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +218 -0
- package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +46 -0
- package/flutter_app/lib/main.dart +107 -0
- package/flutter_app/lib/main_account_settings.dart +1340 -0
- package/flutter_app/lib/main_admin.dart +900 -0
- package/flutter_app/lib/main_app_shell.dart +2162 -0
- package/flutter_app/lib/main_chat.dart +3902 -0
- package/flutter_app/lib/main_controller.dart +7229 -0
- package/flutter_app/lib/main_devices.dart +1738 -0
- package/flutter_app/lib/main_integrations.dart +917 -0
- package/flutter_app/lib/main_launcher.dart +959 -0
- package/flutter_app/lib/main_launcher_entry.dart +5 -0
- package/flutter_app/lib/main_models.dart +3807 -0
- package/flutter_app/lib/main_navigation.dart +206 -0
- package/flutter_app/lib/main_operations.dart +5249 -0
- package/flutter_app/lib/main_recordings.dart +920 -0
- package/flutter_app/lib/main_runtime.dart +869 -0
- package/flutter_app/lib/main_settings.dart +2288 -0
- package/flutter_app/lib/main_shared.dart +3393 -0
- package/flutter_app/lib/main_spacing.dart +33 -0
- package/flutter_app/lib/main_theme.dart +276 -0
- package/flutter_app/lib/main_unified.dart +388 -0
- package/flutter_app/lib/main_voice_assistant.dart +957 -0
- package/flutter_app/lib/src/analytics_service.dart +294 -0
- package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
- package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
- package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
- package/flutter_app/lib/src/android_app_installer.dart +22 -0
- package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
- package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
- package/flutter_app/lib/src/android_auto_bridge.dart +59 -0
- package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
- package/flutter_app/lib/src/app_launch_bridge.dart +58 -0
- package/flutter_app/lib/src/app_release_updater.dart +511 -0
- package/flutter_app/lib/src/backend_client.dart +1870 -0
- package/flutter_app/lib/src/desktop_companion.dart +2 -0
- package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
- package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
- package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
- package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
- package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
- package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
- package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
- package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
- package/flutter_app/lib/src/health_bridge.dart +136 -0
- package/flutter_app/lib/src/live_voice_capture.dart +85 -0
- package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
- package/flutter_app/lib/src/network/app_http_client.dart +53 -0
- package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
- package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
- package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
- package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
- package/flutter_app/lib/src/oauth_launcher.dart +33 -0
- package/flutter_app/lib/src/oauth_launcher_io.dart +95 -0
- package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
- package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
- package/flutter_app/lib/src/recording_bridge.dart +232 -0
- package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
- package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
- package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
- package/flutter_app/lib/src/recording_payloads.dart +86 -0
- package/flutter_app/lib/src/theme/palette.dart +81 -0
- package/flutter_app/lib/src/web_app_update_monitor.dart +17 -0
- package/flutter_app/lib/src/web_app_update_monitor_stub.dart +24 -0
- package/flutter_app/lib/src/web_app_update_monitor_web.dart +123 -0
- package/flutter_app/lib/src/widget_bridge.dart +49 -0
- package/flutter_app/linux/CMakeLists.txt +128 -0
- package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
- package/flutter_app/linux/flutter/generated_plugin_registrant.cc +47 -0
- package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
- package/flutter_app/linux/flutter/generated_plugins.cmake +32 -0
- package/flutter_app/linux/runner/CMakeLists.txt +26 -0
- package/flutter_app/linux/runner/main.cc +6 -0
- package/flutter_app/linux/runner/my_application.cc +144 -0
- package/flutter_app/linux/runner/my_application.h +18 -0
- package/flutter_app/linux/runner/resources/app_icon.png +0 -0
- package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
- package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
- package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +48 -0
- package/flutter_app/macos/Podfile +42 -0
- package/flutter_app/macos/Podfile.lock +87 -0
- package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
- package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
- package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
- package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
- package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
- package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
- package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
- package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
- package/flutter_app/macos/Runner/Info.plist +36 -0
- package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
- package/flutter_app/macos/Runner/Release.entitlements +12 -0
- package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
- package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
- package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
- package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
- package/flutter_app/patch_strings.py +12 -0
- package/flutter_app/pubspec.lock +1256 -0
- package/flutter_app/pubspec.yaml +59 -0
- package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
- package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
- package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
- package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
- package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
- package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
- package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
- package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
- package/flutter_app/tool/generate_desktop_branding.py +219 -0
- package/flutter_app/web/favicon.png +0 -0
- package/flutter_app/web/favicon.svg +12 -0
- package/flutter_app/web/icons/Icon-192.png +0 -0
- package/flutter_app/web/icons/Icon-512.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
- package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
- package/flutter_app/web/index.html +39 -0
- package/flutter_app/web/manifest.json +35 -0
- package/flutter_app/windows/CMakeLists.txt +108 -0
- package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
- package/flutter_app/windows/flutter/generated_plugin_registrant.cc +50 -0
- package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
- package/flutter_app/windows/flutter/generated_plugins.cmake +36 -0
- package/flutter_app/windows/runner/CMakeLists.txt +41 -0
- package/flutter_app/windows/runner/Runner.rc +121 -0
- package/flutter_app/windows/runner/flutter_window.cpp +533 -0
- package/flutter_app/windows/runner/flutter_window.h +37 -0
- package/flutter_app/windows/runner/main.cpp +53 -0
- package/flutter_app/windows/runner/resource.h +16 -0
- package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
- package/flutter_app/windows/runner/runner.exe.manifest +14 -0
- package/flutter_app/windows/runner/utils.cpp +65 -0
- package/flutter_app/windows/runner/utils.h +19 -0
- package/flutter_app/windows/runner/win32_window.cpp +299 -0
- package/flutter_app/windows/runner/win32_window.h +102 -0
- package/lib/install_helpers.js +31 -0
- package/lib/manager.js +465 -43
- package/package.json +11 -3
- package/runtime/paths.js +137 -0
- package/server/config/analytics.js +30 -0
- package/server/db/database.js +363 -21
- package/server/guest-agent.android.package.json +13 -0
- package/server/guest-agent.browser.package.json +14 -0
- package/server/guest_agent.js +98 -52
- package/server/http/middleware.js +55 -2
- package/server/http/routes.js +6 -1
- package/server/http/static.js +41 -1
- package/server/index.js +16 -16
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/AssetManifest.bin +1 -1
- package/server/public/assets/AssetManifest.bin.json +1 -1
- package/server/public/assets/AssetManifest.json +1 -1
- package/server/public/assets/NOTICES +679 -129
- package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/assets/packages/mixpanel_flutter/assets/mixpanel.js +3 -0
- package/server/public/canvaskit/wimp.wasm +0 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +95866 -87333
- package/server/routes/account.js +26 -1
- package/server/routes/agents.js +6 -2
- package/server/routes/android.js +22 -6
- package/server/routes/auth.js +25 -5
- package/server/routes/browser.js +47 -13
- package/server/routes/integrations.js +119 -9
- package/server/routes/memory.js +179 -8
- package/server/routes/runtime.js +14 -0
- package/server/routes/screenHistory.js +46 -0
- package/server/routes/settings.js +102 -24
- package/server/routes/skills.js +12 -0
- package/server/routes/social_video.js +66 -0
- package/server/routes/tasks.js +22 -2
- package/server/routes/triggers.js +90 -0
- package/server/routes/wearable.js +67 -0
- package/server/routes/widgets.js +4 -4
- package/server/services/ai/capabilityHealth.js +23 -51
- package/server/services/ai/compaction.js +1 -1
- package/server/services/ai/deliverables/artifact_helpers.js +190 -0
- package/server/services/ai/deliverables/contracts.js +113 -0
- package/server/services/ai/deliverables/index.js +20 -0
- package/server/services/ai/deliverables/selector.js +94 -0
- package/server/services/ai/deliverables/validator.js +63 -0
- package/server/services/ai/deliverables/workflows.js +207 -0
- package/server/services/ai/engine.js +372 -27
- package/server/services/ai/hooks.js +127 -0
- package/server/services/ai/integrated_tools/index.js +98 -0
- package/server/services/ai/integrated_tools/remotion.js +373 -0
- package/server/services/ai/integrated_tools/shared.js +204 -0
- package/server/services/ai/integrated_tools/slidev.js +207 -0
- package/server/services/ai/loopPolicy.js +146 -0
- package/server/services/ai/models.js +36 -0
- package/server/services/ai/providers/githubCopilot.js +97 -0
- package/server/services/ai/providers/openai.js +2 -1
- package/server/services/ai/providers/openaiCodex.js +384 -0
- package/server/services/ai/recordingInsights.js +11 -13
- package/server/services/ai/runEvents.js +100 -0
- package/server/services/ai/settings.js +20 -0
- package/server/services/ai/systemPrompt.js +16 -2
- package/server/services/ai/taskAnalysis.js +2 -0
- package/server/services/ai/toolResult.js +20 -0
- package/server/services/ai/toolRunner.js +46 -6
- package/server/services/ai/toolSelector.js +54 -1
- package/server/services/ai/tools.js +360 -127
- package/server/services/android/android_bootstrap_worker.js +63 -0
- package/server/services/android/controller.js +442 -1760
- package/server/services/bootstrap_helpers.js +0 -34
- package/server/services/browser/controller.js +326 -52
- package/server/services/cli/executor.js +40 -1
- package/server/services/desktop/screenRecorder.js +182 -0
- package/server/services/integrations/env.js +10 -0
- package/server/services/integrations/figma/provider.js +1 -0
- package/server/services/integrations/github/common.js +106 -0
- package/server/services/integrations/github/provider.js +499 -0
- package/server/services/integrations/github/repos.js +1124 -0
- package/server/services/integrations/google/provider.js +1 -0
- package/server/services/integrations/manager.js +88 -12
- package/server/services/integrations/microsoft/provider.js +1 -0
- package/server/services/integrations/oauth_provider.js +25 -8
- package/server/services/integrations/provider_config_store.js +85 -0
- package/server/services/integrations/registry.js +8 -2
- package/server/services/integrations/spotify/provider.js +488 -0
- package/server/services/integrations/trello/provider.js +842 -0
- package/server/services/integrations/weather/provider.js +559 -0
- package/server/services/integrations/whatsapp/provider.js +6 -2
- package/server/services/manager.js +109 -154
- package/server/services/mcp/client.js +120 -23
- package/server/services/memory/llm_transfer.js +218 -0
- package/server/services/memory/manager.js +299 -35
- package/server/services/messaging/access_policy.js +10 -0
- package/server/services/messaging/automation.js +1 -1
- package/server/services/messaging/manager.js +93 -8
- package/server/services/messaging/meshtastic.js +277 -0
- package/server/services/messaging/meshtastic_env.js +40 -0
- package/server/services/messaging/meshtastic_protocol.js +530 -0
- package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
- package/server/services/runtime/backends/local-vm.js +221 -158
- package/server/services/runtime/docker-vm-manager.js +392 -0
- package/server/services/runtime/guest_bootstrap.js +654 -0
- package/server/services/runtime/manager.js +85 -29
- package/server/services/runtime/settings.js +22 -31
- package/server/services/runtime/validation.js +16 -31
- package/server/services/skills/base_catalog.js +33 -0
- package/server/services/social_video/adapters/base.js +26 -0
- package/server/services/social_video/adapters/index.js +27 -0
- package/server/services/social_video/adapters/instagram.js +17 -0
- package/server/services/social_video/adapters/tiktok.js +17 -0
- package/server/services/social_video/adapters/x.js +17 -0
- package/server/services/social_video/adapters/youtube.js +17 -0
- package/server/services/social_video/captions.js +187 -0
- package/server/services/social_video/frame.js +42 -0
- package/server/services/social_video/index.js +7 -0
- package/server/services/social_video/metadata.js +63 -0
- package/server/services/social_video/result.js +63 -0
- package/server/services/social_video/service.js +720 -0
- package/server/services/social_video/url.js +83 -0
- package/server/services/tasks/adapters/index.js +2 -0
- package/server/services/tasks/adapters/manual.js +12 -0
- package/server/services/tasks/adapters/schedule.js +33 -5
- package/server/services/tasks/adapters/weather_event.js +84 -0
- package/server/services/tasks/integration_runtime.js +86 -1
- package/server/services/tasks/runtime.js +3 -3
- package/server/services/tasks/task_repository.js +3 -6
- package/server/services/voice/agentBridge.js +20 -4
- package/server/services/voice/message.js +3 -0
- package/server/services/voice/openaiClient.js +4 -1
- package/server/services/voice/openaiSpeech.js +6 -1
- package/server/services/voice/providers.js +144 -15
- package/server/services/voice/runtime.js +8 -8
- package/server/services/voice/runtimeManager.js +292 -20
- package/server/services/voice/turnRunner.js +29 -9
- package/server/services/wearable/firmware_manifest.js +353 -0
- package/server/services/wearable/gateway.js +350 -0
- package/server/services/wearable/protocol.js +45 -0
- package/server/services/wearable/service.js +240 -0
- package/server/services/websocket.js +3 -1
- package/server/services/widgets/focus_widget.js +137 -0
- package/server/services/widgets/service.js +182 -6
- package/server/services/workspace/manager.js +301 -0
- package/server/utils/deployment.js +16 -9
- package/server/utils/local_secrets.js +56 -0
- package/server/utils/logger.js +37 -9
- package/server/services/integrations/home_assistant/provider.js +0 -350
- package/server/services/messaging/access_policy.test.js +0 -228
- package/server/services/runtime/backends/host.js +0 -37
- package/server/services/runtime/qemu.js +0 -391
|
@@ -9,6 +9,10 @@ const {
|
|
|
9
9
|
normalizeOutgoingMessageForPlatform,
|
|
10
10
|
} = require('../messaging/formatting_guides');
|
|
11
11
|
const { INTERIM_KINDS, normalizeInterimKind } = require('./interim');
|
|
12
|
+
const {
|
|
13
|
+
executeIntegratedTool,
|
|
14
|
+
getIntegratedToolDefinitions,
|
|
15
|
+
} = require('./integrated_tools');
|
|
12
16
|
|
|
13
17
|
function compactText(text, maxChars = 120) {
|
|
14
18
|
const str = String(text || '').replace(/\s+/g, ' ').trim();
|
|
@@ -91,10 +95,155 @@ function compactToolDefinition(tool, options = {}) {
|
|
|
91
95
|
return compact;
|
|
92
96
|
}
|
|
93
97
|
|
|
98
|
+
function normalizeScheduleTriggerConfig(inputConfig = {}) {
|
|
99
|
+
if (!inputConfig || typeof inputConfig !== 'object' || Array.isArray(inputConfig)) {
|
|
100
|
+
return inputConfig;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const normalized = { ...inputConfig };
|
|
104
|
+
const schedule = (normalized.schedule && typeof normalized.schedule === 'object' && !Array.isArray(normalized.schedule))
|
|
105
|
+
? normalized.schedule
|
|
106
|
+
: null;
|
|
107
|
+
|
|
108
|
+
const modeCandidate = String(
|
|
109
|
+
normalized.mode
|
|
110
|
+
|| normalized.type
|
|
111
|
+
|| normalized.scheduleType
|
|
112
|
+
|| normalized.schedule_type
|
|
113
|
+
|| (normalized.oneTime || normalized.one_time ? 'one_time' : '')
|
|
114
|
+
|| ''
|
|
115
|
+
).trim().toLowerCase();
|
|
116
|
+
if (modeCandidate === 'once') normalized.mode = 'one_time';
|
|
117
|
+
else if (modeCandidate === 'one_time' || modeCandidate === 'recurring') normalized.mode = modeCandidate;
|
|
118
|
+
|
|
119
|
+
const cronCandidate = normalized.cronExpression
|
|
120
|
+
|| normalized.cron_expression
|
|
121
|
+
|| normalized.cron
|
|
122
|
+
|| schedule?.cronExpression
|
|
123
|
+
|| schedule?.cron_expression
|
|
124
|
+
|| schedule?.cron;
|
|
125
|
+
if (cronCandidate != null) {
|
|
126
|
+
normalized.cronExpression = String(cronCandidate).trim();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const runAtCandidate = normalized.runAt
|
|
130
|
+
|| normalized.run_at
|
|
131
|
+
|| normalized.at
|
|
132
|
+
|| normalized.when
|
|
133
|
+
|| schedule?.runAt
|
|
134
|
+
|| schedule?.run_at
|
|
135
|
+
|| schedule?.at
|
|
136
|
+
|| schedule?.when;
|
|
137
|
+
if (runAtCandidate != null) {
|
|
138
|
+
normalized.runAt = String(runAtCandidate).trim();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!normalized.mode) {
|
|
142
|
+
normalized.mode = normalized.runAt ? 'one_time' : 'recurring';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
delete normalized.schedule;
|
|
146
|
+
return normalized;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function normalizeTaskTriggerInput(triggerType, triggerConfig) {
|
|
150
|
+
if (String(triggerType || '').trim() !== 'schedule') {
|
|
151
|
+
return triggerConfig;
|
|
152
|
+
}
|
|
153
|
+
return normalizeScheduleTriggerConfig(triggerConfig || {});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function resolveTaskTriggerArgs(args = {}, fallbackTriggerType = null) {
|
|
157
|
+
let triggerType = args.trigger_type !== undefined
|
|
158
|
+
? String(args.trigger_type || '').trim()
|
|
159
|
+
: String(fallbackTriggerType || '').trim();
|
|
160
|
+
let triggerConfig = args.trigger_config;
|
|
161
|
+
let hasType = args.trigger_type !== undefined;
|
|
162
|
+
let hasConfig = args.trigger_config !== undefined;
|
|
163
|
+
|
|
164
|
+
if (args.trigger && typeof args.trigger === 'object' && !Array.isArray(args.trigger)) {
|
|
165
|
+
const trigger = args.trigger;
|
|
166
|
+
const unifiedType = trigger.type ?? trigger.triggerType ?? trigger.trigger_type;
|
|
167
|
+
const unifiedHasType = unifiedType !== undefined && unifiedType !== null && String(unifiedType).trim().length > 0;
|
|
168
|
+
if (unifiedHasType) {
|
|
169
|
+
triggerType = String(unifiedType).trim();
|
|
170
|
+
hasType = true;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const hasUnifiedConfig = Object.prototype.hasOwnProperty.call(trigger, 'config')
|
|
174
|
+
|| Object.prototype.hasOwnProperty.call(trigger, 'triggerConfig')
|
|
175
|
+
|| Object.prototype.hasOwnProperty.call(trigger, 'trigger_config');
|
|
176
|
+
if (hasUnifiedConfig) {
|
|
177
|
+
triggerConfig = trigger.config ?? trigger.triggerConfig ?? trigger.trigger_config;
|
|
178
|
+
hasConfig = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const normalizedType = String(triggerType || '').trim() || null;
|
|
183
|
+
const normalizedConfig = hasConfig
|
|
184
|
+
? normalizeTaskTriggerInput(normalizedType || fallbackTriggerType || 'schedule', triggerConfig)
|
|
185
|
+
: undefined;
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
triggerType: normalizedType,
|
|
189
|
+
triggerConfig: normalizedConfig,
|
|
190
|
+
hasType,
|
|
191
|
+
hasConfig,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
94
195
|
function isProactiveTrigger(triggerSource) {
|
|
95
196
|
return triggerSource === 'schedule' || triggerSource === 'tasks';
|
|
96
197
|
}
|
|
97
198
|
|
|
199
|
+
function normalizeSendMessagePurpose(value) {
|
|
200
|
+
const normalized = String(value || '').trim().toLowerCase();
|
|
201
|
+
if (normalized === 'final_result' || normalized === 'blocker' || normalized === 'no_response') {
|
|
202
|
+
return normalized;
|
|
203
|
+
}
|
|
204
|
+
return '';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function validateProactiveSendMessageArgs({ purpose, normalizedMessage }) {
|
|
208
|
+
const normalizedPurpose = normalizeSendMessagePurpose(purpose);
|
|
209
|
+
if (!normalizedPurpose) {
|
|
210
|
+
return {
|
|
211
|
+
ok: false,
|
|
212
|
+
error: 'Background send_message requires purpose=final_result, blocker, or no_response.',
|
|
213
|
+
reason: 'Background send_message requires purpose=final_result, blocker, or no_response.',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (normalizedPurpose === 'no_response') {
|
|
218
|
+
if (normalizedMessage !== '[NO RESPONSE]') {
|
|
219
|
+
return {
|
|
220
|
+
ok: false,
|
|
221
|
+
error: 'purpose=no_response requires content "[NO RESPONSE]".',
|
|
222
|
+
reason: 'purpose=no_response requires content "[NO RESPONSE]".',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
ok: false,
|
|
227
|
+
skipped: true,
|
|
228
|
+
suppressed: true,
|
|
229
|
+
reason: 'no_response',
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (normalizedMessage === '[NO RESPONSE]') {
|
|
234
|
+
return {
|
|
235
|
+
ok: false,
|
|
236
|
+
error: `purpose=${normalizedPurpose} cannot use content "[NO RESPONSE]".`,
|
|
237
|
+
reason: `purpose=${normalizedPurpose} cannot use content "[NO RESPONSE]".`,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
ok: true,
|
|
243
|
+
purpose: normalizedPurpose,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
98
247
|
function getRunState(engine, runId) {
|
|
99
248
|
if (!engine || !runId) return null;
|
|
100
249
|
return engine.activeRuns.get(runId) || null;
|
|
@@ -645,14 +794,15 @@ function getAvailableTools(app, options = {}) {
|
|
|
645
794
|
},
|
|
646
795
|
{
|
|
647
796
|
name: 'send_message',
|
|
648
|
-
description: `Send a message on a connected messaging platform. Supports WhatsApp (text/media), Telnyx Voice (phone calls — TTS), Discord, Telegram, Slack, Google Chat, Microsoft Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, WeChat, WebChat, and configurable webhook bridges. ${buildSendMessageFormattingReference()} For WhatsApp: use media_path to attach files. Use content "[NO RESPONSE]" only when the user explicitly asked for silence or no reply.`,
|
|
797
|
+
description: `Send a message on a connected messaging platform. Supports WhatsApp (text/media), Telnyx Voice (phone calls — TTS), Discord, Telegram, Slack, Google Chat, Microsoft Teams, Matrix, Signal, iMessage/BlueBubbles, IRC, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, WeChat, WebChat, and configurable webhook bridges. ${buildSendMessageFormattingReference()} For WhatsApp: use media_path to attach files. Use content "[NO RESPONSE]" only when the user explicitly asked for silence or no reply. For background task or schedule runs, set purpose to final_result, blocker, or no_response.`,
|
|
649
798
|
parameters: {
|
|
650
799
|
type: 'object',
|
|
651
800
|
properties: {
|
|
652
801
|
platform: { type: 'string', description: 'Platform name, for example whatsapp, telnyx, discord, telegram, slack, google_chat, teams, matrix, signal, imessage, bluebubbles, irc, line, mattermost, or webchat' },
|
|
653
802
|
to: { type: 'string', description: 'Recipient/chat ID for the connected platform, such as a WhatsApp chat ID, Telnyx call_control_id, Slack channel ID, Matrix room ID, Discord channel snowflake / "dm_<userId>", Telegram "dm_<userId>" / raw group chat ID, IRC channel, or webhook target' },
|
|
654
803
|
content: { type: 'string', description: 'Message text. Write one compact natural chat reply; the runtime adapts final formatting for the destination platform.' },
|
|
655
|
-
media_path: { type: 'string', description: 'WhatsApp only: absolute path to a local file to attach. Leave empty for text-only or Telnyx.' }
|
|
804
|
+
media_path: { type: 'string', description: 'WhatsApp only: absolute path to a local file to attach. Leave empty for text-only or Telnyx.' },
|
|
805
|
+
purpose: { type: 'string', enum: ['final_result', 'blocker', 'no_response'], description: 'For background task or schedule runs, required intent for this outbound message. Use final_result for a concrete useful outcome, blocker for a real issue the user should know about, or no_response to intentionally send nothing.' }
|
|
656
806
|
},
|
|
657
807
|
required: ['platform', 'to', 'content']
|
|
658
808
|
}
|
|
@@ -876,15 +1026,16 @@ function getAvailableTools(app, options = {}) {
|
|
|
876
1026
|
type: 'object',
|
|
877
1027
|
properties: {
|
|
878
1028
|
name: { type: 'string', description: 'Short descriptive name for the task.' },
|
|
879
|
-
|
|
880
|
-
|
|
1029
|
+
trigger: { type: 'object', description: 'Unified trigger object. Prefer { type: "manual" | "schedule" | integration_trigger_type, config: {...} }.' },
|
|
1030
|
+
trigger_type: { type: 'string', description: 'Trigger type such as manual, schedule, gmail_message_received, outlook_email_received, slack_message_received, teams_message_received, weather_event, or whatsapp_personal_message_received.' },
|
|
1031
|
+
trigger_config: { type: 'object', description: 'Trigger-specific configuration object. For schedule triggers prefer { mode: "recurring", cronExpression: "m h dom mon dow" } or { mode: "one_time", runAt: ISO datetime }. 5-field cron only (seconds unsupported).' },
|
|
881
1032
|
prompt: { type: 'string', description: 'The instructions the agent will run when the trigger fires.' },
|
|
882
1033
|
enabled: { type: 'boolean', description: 'Whether to activate immediately.' },
|
|
883
1034
|
model: { type: 'string', description: 'Optional model override.' },
|
|
884
1035
|
call_to: { type: 'string', description: 'Optional E.164 phone number to call via Telnyx when this task fires.' },
|
|
885
1036
|
call_greeting: { type: 'string', description: 'Optional spoken greeting hint for make_call.' }
|
|
886
1037
|
},
|
|
887
|
-
required: ['name', '
|
|
1038
|
+
required: ['name', 'prompt']
|
|
888
1039
|
}
|
|
889
1040
|
},
|
|
890
1041
|
{
|
|
@@ -911,8 +1062,9 @@ function getAvailableTools(app, options = {}) {
|
|
|
911
1062
|
properties: {
|
|
912
1063
|
task_id: { type: 'number', description: 'The numeric ID of the task to update.' },
|
|
913
1064
|
name: { type: 'string', description: 'New name for the task.' },
|
|
914
|
-
|
|
915
|
-
|
|
1065
|
+
trigger: { type: 'object', description: 'Unified trigger object. Use { type, config } to update trigger in one section.' },
|
|
1066
|
+
trigger_type: { type: 'string', description: 'Updated trigger type, e.g. manual, schedule, or integration trigger type.' },
|
|
1067
|
+
trigger_config: { type: 'object', description: 'Updated trigger-specific configuration. For schedule triggers use mode+cronExpression (recurring) or mode+runAt (one_time).' },
|
|
916
1068
|
prompt: { type: 'string', description: 'Updated task prompt.' },
|
|
917
1069
|
enabled: { type: 'boolean', description: 'Enable or disable the task.' },
|
|
918
1070
|
model: { type: 'string', description: 'Specific AI model ID for this task. Set to empty string to clear the override.' },
|
|
@@ -1019,6 +1171,7 @@ function getAvailableTools(app, options = {}) {
|
|
|
1019
1171
|
required: ['prompt']
|
|
1020
1172
|
}
|
|
1021
1173
|
},
|
|
1174
|
+
...getIntegratedToolDefinitions(),
|
|
1022
1175
|
{
|
|
1023
1176
|
name: 'generate_table',
|
|
1024
1177
|
description: 'Format data into a markdown table. The resulting markdown will be returned to you. You MUST include it in your next message to the user so they can see it.',
|
|
@@ -1053,6 +1206,17 @@ function getAvailableTools(app, options = {}) {
|
|
|
1053
1206
|
required: ['image_path']
|
|
1054
1207
|
}
|
|
1055
1208
|
},
|
|
1209
|
+
{
|
|
1210
|
+
name: 'ocr_extract',
|
|
1211
|
+
description: 'Extract raw text from an image locally using Tesseract OCR. This is faster and completely offline compared to analyze_image.',
|
|
1212
|
+
parameters: {
|
|
1213
|
+
type: 'object',
|
|
1214
|
+
properties: {
|
|
1215
|
+
image_path: { type: 'string', description: 'Absolute path to the image file' }
|
|
1216
|
+
},
|
|
1217
|
+
required: ['image_path']
|
|
1218
|
+
}
|
|
1219
|
+
},
|
|
1056
1220
|
{
|
|
1057
1221
|
name: 'read_health_data',
|
|
1058
1222
|
description: 'Read the user\'s synced mobile health data. Omit metric_type for a summary of all available metrics. With metric_type, returns an aggregate summary (total, avg, min, max over all stored data) plus the most recent individual records. Always report the summary figures — avoid listing every raw record.',
|
|
@@ -1103,9 +1267,46 @@ function getAvailableTools(app, options = {}) {
|
|
|
1103
1267
|
},
|
|
1104
1268
|
required: ['query']
|
|
1105
1269
|
}
|
|
1270
|
+
},
|
|
1271
|
+
{
|
|
1272
|
+
name: 'social_video_extract',
|
|
1273
|
+
description: 'Extract title, description, transcript, and one representative frame image from a public social video URL (YouTube, TikTok, Instagram, or X) without social API keys.',
|
|
1274
|
+
parameters: {
|
|
1275
|
+
type: 'object',
|
|
1276
|
+
properties: {
|
|
1277
|
+
url: { type: 'string', description: 'Public social video URL.' },
|
|
1278
|
+
include_frame: { type: 'boolean', description: 'Whether to return one representative frame image artifact (default true).' },
|
|
1279
|
+
force_stt: { type: 'boolean', description: 'Force speech-to-text fallback even if captions are present.' }
|
|
1280
|
+
},
|
|
1281
|
+
required: ['url']
|
|
1282
|
+
}
|
|
1106
1283
|
}
|
|
1107
1284
|
];
|
|
1108
1285
|
|
|
1286
|
+
// task_complete — always available. Lets the AI explicitly signal that
|
|
1287
|
+
// the task is fully done and provide the final response. This replaces
|
|
1288
|
+
// the opaque directAnswerEligible heuristic as the primary loop-exit
|
|
1289
|
+
// mechanism and gives the AI real agency over when it's finished.
|
|
1290
|
+
tools.push({
|
|
1291
|
+
name: 'task_complete',
|
|
1292
|
+
description: 'Signal that the task is fully complete and provide the final response. Call this exactly once when all steps are done and you have a complete answer ready. Do NOT call it if you still have work to do.',
|
|
1293
|
+
parameters: {
|
|
1294
|
+
type: 'object',
|
|
1295
|
+
properties: {
|
|
1296
|
+
message: {
|
|
1297
|
+
type: 'string',
|
|
1298
|
+
description: 'Your complete final response to the user. Write it as if it were your reply — do not summarize or reference prior steps.'
|
|
1299
|
+
},
|
|
1300
|
+
confidence: {
|
|
1301
|
+
type: 'string',
|
|
1302
|
+
enum: ['high', 'medium', 'low'],
|
|
1303
|
+
description: 'How confident are you the task is fully and correctly complete? Use "low" if you had to make assumptions.'
|
|
1304
|
+
}
|
|
1305
|
+
},
|
|
1306
|
+
required: ['message']
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1109
1310
|
const allowInterimUpdates = (
|
|
1110
1311
|
(options.triggerSource === 'web' || options.triggerSource === 'messaging' || options.triggerSource === 'voice_live')
|
|
1111
1312
|
&& options.triggerType !== 'subagent'
|
|
@@ -1123,7 +1324,8 @@ function getAvailableTools(app, options = {}) {
|
|
|
1123
1324
|
properties: {
|
|
1124
1325
|
content: { type: 'string', description: 'Natural assistant message derived from the current task state.' },
|
|
1125
1326
|
kind: { type: 'string', enum: Array.from(INTERIM_KINDS), description: 'ack, progress, question, or blocker' },
|
|
1126
|
-
expects_reply: { type: 'boolean', description: 'Set true only when the current run should pause for the user to answer.' }
|
|
1327
|
+
expects_reply: { type: 'boolean', description: 'Set true only when the current run should pause for the user to answer.' },
|
|
1328
|
+
defer_follow_up: { type: 'boolean', description: 'Set true when you choose to deliver the final result later via the user\'s last connected chat target.' }
|
|
1127
1329
|
},
|
|
1128
1330
|
required: ['content', 'kind']
|
|
1129
1331
|
}
|
|
@@ -1204,23 +1406,16 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1204
1406
|
if (manager && typeof manager.getBrowserProviderForUser === 'function') {
|
|
1205
1407
|
return manager.getBrowserProviderForUser(userId);
|
|
1206
1408
|
}
|
|
1207
|
-
|
|
1208
|
-
if (typeof scoped === 'function') {
|
|
1209
|
-
return scoped(userId);
|
|
1210
|
-
}
|
|
1211
|
-
return app?.locals?.browserController || engine.browserController;
|
|
1409
|
+
throw new Error('Browser provider is unavailable. VM runtime is required.');
|
|
1212
1410
|
};
|
|
1213
1411
|
const ac = () => {
|
|
1214
1412
|
const manager = runtime();
|
|
1215
1413
|
if (manager && typeof manager.getAndroidProviderForUser === 'function') {
|
|
1216
1414
|
return manager.getAndroidProviderForUser(userId);
|
|
1217
1415
|
}
|
|
1218
|
-
|
|
1219
|
-
if (typeof scoped === 'function') {
|
|
1220
|
-
return scoped(userId);
|
|
1221
|
-
}
|
|
1222
|
-
return app?.locals?.androidController || engine.androidController;
|
|
1416
|
+
throw new Error('Android provider is unavailable. VM runtime is required.');
|
|
1223
1417
|
};
|
|
1418
|
+
const wc = () => app?.locals?.workspaceManager || engine.workspaceManager || null;
|
|
1224
1419
|
const dc = () => {
|
|
1225
1420
|
const scoped = app?.locals?.getDesktopProviderForUser;
|
|
1226
1421
|
if (typeof scoped === 'function') {
|
|
@@ -1234,7 +1429,9 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1234
1429
|
const sk = () => app?.locals?.skillRunner || engine.skillRunner;
|
|
1235
1430
|
const taskRuntime = () => app?.locals?.taskRuntime || engine.taskRuntime;
|
|
1236
1431
|
const rec = () => app?.locals?.recordingManager || null;
|
|
1432
|
+
const socialVideo = () => app?.locals?.socialVideoService || null;
|
|
1237
1433
|
const widgets = () => app?.locals?.widgetService || null;
|
|
1434
|
+
const artifactStore = app?.locals?.artifactStore || null;
|
|
1238
1435
|
|
|
1239
1436
|
const integrationManager = integrations();
|
|
1240
1437
|
if (integrationManager) {
|
|
@@ -1259,35 +1456,37 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1259
1456
|
}
|
|
1260
1457
|
}
|
|
1261
1458
|
|
|
1459
|
+
const integratedToolResult = await executeIntegratedTool(toolName, args, {
|
|
1460
|
+
userId,
|
|
1461
|
+
agentId,
|
|
1462
|
+
cliExecutor: runtime() && typeof runtime().getCommandExecutorForUser === 'function'
|
|
1463
|
+
? await runtime().getCommandExecutorForUser(userId)
|
|
1464
|
+
: null,
|
|
1465
|
+
workspaceManager: wc(),
|
|
1466
|
+
artifactStore,
|
|
1467
|
+
});
|
|
1468
|
+
if (integratedToolResult !== null) {
|
|
1469
|
+
return integratedToolResult;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1262
1472
|
switch (toolName) {
|
|
1473
|
+
// task_complete is handled at the engine loop level before executeTool
|
|
1474
|
+
// is called. If it somehow reaches here, return a no-op success so the
|
|
1475
|
+
// loop-level handler can still read the args from the tool call object.
|
|
1476
|
+
case 'task_complete':
|
|
1477
|
+
return { success: true, handled_by: 'engine_loop' };
|
|
1478
|
+
|
|
1263
1479
|
case 'execute_command': {
|
|
1264
1480
|
const runtimeManager = runtime();
|
|
1265
|
-
if (runtimeManager
|
|
1266
|
-
|
|
1267
|
-
return await runtimeManager.executeCommand(userId, args.command, {
|
|
1268
|
-
cwd: args.cwd,
|
|
1269
|
-
timeout: args.timeout || (args.pty ? 20 * 60 * 1000 : 15 * 60 * 1000),
|
|
1270
|
-
stdinInput: args.stdin_input,
|
|
1271
|
-
pty: args.pty === true,
|
|
1272
|
-
inputs: args.inputs || [],
|
|
1273
|
-
onSpawn,
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
const { CLIExecutor } = require('../cli/executor');
|
|
1277
|
-
const executor = app?.locals?.cliExecutor || engine.cliExecutor || new CLIExecutor();
|
|
1278
|
-
const onSpawn = (pid) => engine.attachProcessToRun(runId, pid);
|
|
1279
|
-
if (args.pty) {
|
|
1280
|
-
return await executor.executeInteractive(args.command, args.inputs || [], {
|
|
1281
|
-
cwd: args.cwd,
|
|
1282
|
-
timeout: args.timeout || 20 * 60 * 1000,
|
|
1283
|
-
onSpawn
|
|
1284
|
-
});
|
|
1481
|
+
if (!runtimeManager || typeof runtimeManager.executeCommand !== 'function') {
|
|
1482
|
+
return { error: 'Command execution is unavailable. VM runtime is required.' };
|
|
1285
1483
|
}
|
|
1286
|
-
return await
|
|
1484
|
+
return await runtimeManager.executeCommand(userId, args.command, {
|
|
1287
1485
|
cwd: args.cwd,
|
|
1288
|
-
timeout: args.timeout || 15 * 60 * 1000,
|
|
1486
|
+
timeout: args.timeout || (args.pty ? 20 * 60 * 1000 : 15 * 60 * 1000),
|
|
1289
1487
|
stdinInput: args.stdin_input,
|
|
1290
|
-
|
|
1488
|
+
pty: args.pty === true,
|
|
1489
|
+
inputs: args.inputs || [],
|
|
1291
1490
|
});
|
|
1292
1491
|
}
|
|
1293
1492
|
|
|
@@ -1795,6 +1994,22 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1795
1994
|
};
|
|
1796
1995
|
}
|
|
1797
1996
|
|
|
1997
|
+
case 'social_video_extract': {
|
|
1998
|
+
const service = socialVideo();
|
|
1999
|
+
if (!service || typeof service.extractFromUrl !== 'function') {
|
|
2000
|
+
return { error: 'Social video extraction service is unavailable.' };
|
|
2001
|
+
}
|
|
2002
|
+
const sourceUrl = String(args.url || '').trim();
|
|
2003
|
+
if (!sourceUrl) {
|
|
2004
|
+
return { error: 'url is required' };
|
|
2005
|
+
}
|
|
2006
|
+
return await service.extractFromUrl(userId, sourceUrl, {
|
|
2007
|
+
includeFrame: args.include_frame !== false,
|
|
2008
|
+
forceStt: args.force_stt === true,
|
|
2009
|
+
agentId,
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1798
2013
|
case 'memory_write': {
|
|
1799
2014
|
const { MemoryManager } = require('../memory/manager');
|
|
1800
2015
|
const mm = new MemoryManager();
|
|
@@ -1847,6 +2062,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1847
2062
|
}
|
|
1848
2063
|
const interimContent = typeof args.content === 'string' ? args.content : '';
|
|
1849
2064
|
const expectsReply = args.expects_reply === true;
|
|
2065
|
+
const deferFollowUp = args.defer_follow_up === true;
|
|
1850
2066
|
return engine.publishInterimUpdate({
|
|
1851
2067
|
userId,
|
|
1852
2068
|
runId,
|
|
@@ -1858,6 +2074,7 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1858
2074
|
content: interimContent,
|
|
1859
2075
|
kind: normalizeInterimKind(args.kind),
|
|
1860
2076
|
expectsReply,
|
|
2077
|
+
deferFollowUp,
|
|
1861
2078
|
});
|
|
1862
2079
|
}
|
|
1863
2080
|
|
|
@@ -1873,6 +2090,25 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1873
2090
|
stripNoResponseMarker: false
|
|
1874
2091
|
});
|
|
1875
2092
|
const suppressReply = normalizedMessage === '[NO RESPONSE]';
|
|
2093
|
+
if (isProactiveTrigger(triggerSource)) {
|
|
2094
|
+
const proactiveValidation = validateProactiveSendMessageArgs({
|
|
2095
|
+
purpose: args.purpose,
|
|
2096
|
+
normalizedMessage,
|
|
2097
|
+
});
|
|
2098
|
+
if (!proactiveValidation.ok) {
|
|
2099
|
+
if (proactiveValidation.error) {
|
|
2100
|
+
return {
|
|
2101
|
+
error: proactiveValidation.error,
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
return {
|
|
2105
|
+
sent: false,
|
|
2106
|
+
suppressed: proactiveValidation.suppressed === true,
|
|
2107
|
+
skipped: proactiveValidation.skipped === true,
|
|
2108
|
+
reason: proactiveValidation.reason,
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
1876
2112
|
if (!suppressReply && hasAlreadySentProactiveMessage({
|
|
1877
2113
|
triggerSource,
|
|
1878
2114
|
runState,
|
|
@@ -1904,21 +2140,14 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1904
2140
|
|
|
1905
2141
|
case 'read_file': {
|
|
1906
2142
|
try {
|
|
1907
|
-
const
|
|
1908
|
-
if (
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
content: sliced.length > 20000 ? sliced.slice(0, 20000) + '\n...[truncated]' : sliced,
|
|
1916
|
-
totalLines: lines.length,
|
|
1917
|
-
rangeShown: [start + 1, Math.min(end, lines.length)]
|
|
1918
|
-
};
|
|
1919
|
-
}
|
|
1920
|
-
const content = fs.readFileSync(args.path, encoding);
|
|
1921
|
-
return { content: content.length > 20000 ? content.slice(0, 20000) + '\n...[truncated]' : content };
|
|
2143
|
+
const workspace = wc();
|
|
2144
|
+
if (!workspace) return { error: 'Workspace service is unavailable.' };
|
|
2145
|
+
return workspace.readFile(userId, {
|
|
2146
|
+
path: args.path,
|
|
2147
|
+
encoding: args.encoding || 'utf-8',
|
|
2148
|
+
start_line: args.start_line,
|
|
2149
|
+
end_line: args.end_line,
|
|
2150
|
+
});
|
|
1922
2151
|
} catch (err) {
|
|
1923
2152
|
return { error: err.message };
|
|
1924
2153
|
}
|
|
@@ -1926,14 +2155,13 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1926
2155
|
|
|
1927
2156
|
case 'write_file': {
|
|
1928
2157
|
try {
|
|
1929
|
-
const
|
|
1930
|
-
if (!
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
}
|
|
1936
|
-
return { success: true, path: args.path };
|
|
2158
|
+
const workspace = wc();
|
|
2159
|
+
if (!workspace) return { error: 'Workspace service is unavailable.' };
|
|
2160
|
+
return workspace.writeFile(userId, {
|
|
2161
|
+
path: args.path,
|
|
2162
|
+
content: args.content,
|
|
2163
|
+
mode: args.mode,
|
|
2164
|
+
});
|
|
1937
2165
|
} catch (err) {
|
|
1938
2166
|
return { error: err.message };
|
|
1939
2167
|
}
|
|
@@ -1941,23 +2169,12 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1941
2169
|
|
|
1942
2170
|
case 'edit_file': {
|
|
1943
2171
|
try {
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
if (content.includes(edit.oldText)) {
|
|
1951
|
-
content = content.replace(edit.oldText, edit.newText);
|
|
1952
|
-
modified = true;
|
|
1953
|
-
report.push({ success: true, edit: edit.oldText.slice(0, 50) + '...' });
|
|
1954
|
-
} else {
|
|
1955
|
-
report.push({ success: false, error: 'Target text not found', edit: edit.oldText.slice(0, 50) + '...' });
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
if (modified) fs.writeFileSync(args.path, content);
|
|
1960
|
-
return { success: modified, report, path: args.path };
|
|
2172
|
+
const workspace = wc();
|
|
2173
|
+
if (!workspace) return { error: 'Workspace service is unavailable.' };
|
|
2174
|
+
return workspace.editFile(userId, {
|
|
2175
|
+
path: args.path,
|
|
2176
|
+
edits: args.edits,
|
|
2177
|
+
});
|
|
1961
2178
|
} catch (err) {
|
|
1962
2179
|
return { error: err.message };
|
|
1963
2180
|
}
|
|
@@ -1965,28 +2182,13 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1965
2182
|
|
|
1966
2183
|
case 'list_directory': {
|
|
1967
2184
|
try {
|
|
1968
|
-
const
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
const item = {
|
|
1976
|
-
name: e.name,
|
|
1977
|
-
type: e.isDirectory() ? 'directory' : 'file',
|
|
1978
|
-
path: fullPath,
|
|
1979
|
-
size: stats.size,
|
|
1980
|
-
mtime: stats.mtime.toISOString()
|
|
1981
|
-
};
|
|
1982
|
-
result.push(item);
|
|
1983
|
-
if (e.isDirectory() && currentDepth < maxDepth && !e.name.startsWith('.') && e.name !== 'node_modules') {
|
|
1984
|
-
result.push(...recurse(fullPath, currentDepth + 1));
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
return result;
|
|
1988
|
-
};
|
|
1989
|
-
return { entries: recurse(args.path) };
|
|
2185
|
+
const workspace = wc();
|
|
2186
|
+
if (!workspace) return { error: 'Workspace service is unavailable.' };
|
|
2187
|
+
return workspace.listDirectory(userId, {
|
|
2188
|
+
path: args.path,
|
|
2189
|
+
depth: args.depth,
|
|
2190
|
+
recursive: args.recursive,
|
|
2191
|
+
});
|
|
1990
2192
|
} catch (err) {
|
|
1991
2193
|
return { error: err.message };
|
|
1992
2194
|
}
|
|
@@ -1994,23 +2196,13 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
1994
2196
|
|
|
1995
2197
|
case 'search_files': {
|
|
1996
2198
|
try {
|
|
1997
|
-
const
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
const lines = (result.stdout || '').split('\n').filter(Boolean);
|
|
2005
|
-
const matches = lines.map(line => {
|
|
2006
|
-
const parts = line.split(':');
|
|
2007
|
-
return {
|
|
2008
|
-
file: parts[0],
|
|
2009
|
-
line: parseInt(parts[1]),
|
|
2010
|
-
content: parts.slice(2).join(':').trim()
|
|
2011
|
-
};
|
|
2199
|
+
const workspace = wc();
|
|
2200
|
+
if (!workspace) return { error: 'Workspace service is unavailable.' };
|
|
2201
|
+
return workspace.searchFiles(userId, {
|
|
2202
|
+
path: args.path,
|
|
2203
|
+
query: args.query,
|
|
2204
|
+
include: args.include,
|
|
2012
2205
|
});
|
|
2013
|
-
return { matches, count: matches.length };
|
|
2014
2206
|
} catch (err) {
|
|
2015
2207
|
return { error: err.message };
|
|
2016
2208
|
}
|
|
@@ -2205,10 +2397,21 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2205
2397
|
const s = taskRuntime();
|
|
2206
2398
|
if (!s) return { error: 'Task runtime not available' };
|
|
2207
2399
|
try {
|
|
2400
|
+
const resolvedTrigger = resolveTaskTriggerArgs(args, 'schedule');
|
|
2401
|
+
if (!resolvedTrigger.hasType || !resolvedTrigger.triggerType) {
|
|
2402
|
+
return { error: 'Task trigger type is required (use trigger.type or trigger_type).' };
|
|
2403
|
+
}
|
|
2404
|
+
const normalizedTriggerType = String(resolvedTrigger.triggerType || '').trim();
|
|
2405
|
+
const triggerConfig = (!resolvedTrigger.hasConfig || resolvedTrigger.triggerConfig === undefined)
|
|
2406
|
+
? (normalizedTriggerType === 'manual' ? {} : undefined)
|
|
2407
|
+
: resolvedTrigger.triggerConfig;
|
|
2408
|
+
if (triggerConfig === undefined) {
|
|
2409
|
+
return { error: 'Task trigger config is required (use trigger.config or trigger_config).' };
|
|
2410
|
+
}
|
|
2208
2411
|
const task = await s.createTask(userId, {
|
|
2209
2412
|
name: args.name,
|
|
2210
|
-
triggerType:
|
|
2211
|
-
triggerConfig
|
|
2413
|
+
triggerType: normalizedTriggerType,
|
|
2414
|
+
triggerConfig,
|
|
2212
2415
|
prompt: args.prompt,
|
|
2213
2416
|
enabled: args.enabled !== false,
|
|
2214
2417
|
model: args.model || null,
|
|
@@ -2246,12 +2449,13 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2246
2449
|
const s = taskRuntime();
|
|
2247
2450
|
if (!s) return { error: 'Task runtime not available' };
|
|
2248
2451
|
try {
|
|
2249
|
-
const existing = db.prepare('SELECT agent_id FROM scheduled_tasks WHERE id = ? AND user_id = ?').get(args.task_id, userId);
|
|
2452
|
+
const existing = db.prepare('SELECT agent_id, trigger_type FROM scheduled_tasks WHERE id = ? AND user_id = ?').get(args.task_id, userId);
|
|
2250
2453
|
if (!existing || existing.agent_id !== agentId) return { error: 'Task not found for this agent.' };
|
|
2251
2454
|
const updates = {};
|
|
2455
|
+
const resolvedTrigger = resolveTaskTriggerArgs(args, existing.trigger_type || 'schedule');
|
|
2252
2456
|
if (args.name !== undefined) updates.name = args.name;
|
|
2253
|
-
if (
|
|
2254
|
-
if (
|
|
2457
|
+
if (resolvedTrigger.hasType && resolvedTrigger.triggerType) updates.triggerType = resolvedTrigger.triggerType;
|
|
2458
|
+
if (resolvedTrigger.hasConfig && resolvedTrigger.triggerConfig !== undefined) updates.triggerConfig = resolvedTrigger.triggerConfig;
|
|
2255
2459
|
if (args.prompt !== undefined) updates.prompt = args.prompt;
|
|
2256
2460
|
if (args.enabled !== undefined) updates.enabled = args.enabled;
|
|
2257
2461
|
if (args.model !== undefined) updates.model = args.model || null;
|
|
@@ -2363,7 +2567,17 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2363
2567
|
if (!widgetService) return { error: 'Widget service not available' };
|
|
2364
2568
|
if (!widgetId) return { error: 'save_widget_snapshot is only available during widget refresh runs.' };
|
|
2365
2569
|
try {
|
|
2366
|
-
const
|
|
2570
|
+
const snapshotPayload = (
|
|
2571
|
+
args
|
|
2572
|
+
&& typeof args === 'object'
|
|
2573
|
+
&& !Array.isArray(args)
|
|
2574
|
+
&& args.snapshot
|
|
2575
|
+
&& typeof args.snapshot === 'object'
|
|
2576
|
+
&& !Array.isArray(args.snapshot)
|
|
2577
|
+
)
|
|
2578
|
+
? args.snapshot
|
|
2579
|
+
: args;
|
|
2580
|
+
const snapshot = widgetService.saveSnapshot(userId, widgetId, snapshotPayload, {
|
|
2367
2581
|
sourceRunId: runId,
|
|
2368
2582
|
status: 'ready',
|
|
2369
2583
|
});
|
|
@@ -2470,6 +2684,20 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2470
2684
|
}
|
|
2471
2685
|
}
|
|
2472
2686
|
|
|
2687
|
+
case 'ocr_extract': {
|
|
2688
|
+
try {
|
|
2689
|
+
const fs = require('fs');
|
|
2690
|
+
if (!fs.existsSync(args.image_path)) {
|
|
2691
|
+
return { error: 'File not found: ' + args.image_path };
|
|
2692
|
+
}
|
|
2693
|
+
const Tesseract = require('tesseract.js');
|
|
2694
|
+
const result = await Tesseract.recognize(args.image_path, 'eng');
|
|
2695
|
+
return { text: result.data.text, confidence: result.data.confidence };
|
|
2696
|
+
} catch (err) {
|
|
2697
|
+
return { error: err.message };
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2473
2701
|
case 'spawn_subagent': {
|
|
2474
2702
|
try {
|
|
2475
2703
|
const task = args.context ? `${args.task}\n\nContext: ${args.context}` : args.task;
|
|
@@ -2537,7 +2765,12 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2537
2765
|
const { detectPromptInjection } = require('../../utils/security');
|
|
2538
2766
|
const mcpManager = mcp();
|
|
2539
2767
|
if (mcpManager) {
|
|
2540
|
-
|
|
2768
|
+
let mcpResult = null;
|
|
2769
|
+
try {
|
|
2770
|
+
mcpResult = await mcpManager.callToolByName(toolName, args, userId, { agentId });
|
|
2771
|
+
} catch (mcpErr) {
|
|
2772
|
+
return { error: mcpErr.message, tool: toolName, source: 'mcp' };
|
|
2773
|
+
}
|
|
2541
2774
|
if (mcpResult !== null) {
|
|
2542
2775
|
const resultText = typeof mcpResult === 'string' ? mcpResult : JSON.stringify(mcpResult);
|
|
2543
2776
|
if (detectPromptInjection(resultText)) {
|
|
@@ -2562,4 +2795,4 @@ async function executeTool(toolName, args, context, engine) {
|
|
|
2562
2795
|
}
|
|
2563
2796
|
}
|
|
2564
2797
|
|
|
2565
|
-
module.exports = { getAvailableTools, executeTool };
|
|
2798
|
+
module.exports = { getAvailableTools, executeTool, validateProactiveSendMessageArgs };
|