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
|
@@ -37,9 +37,17 @@ const {
|
|
|
37
37
|
buildInterimSignature,
|
|
38
38
|
normalizeInterimKind,
|
|
39
39
|
} = require('./interim');
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
40
|
+
const { recordRunEvent } = require('./runEvents');
|
|
41
|
+
const {
|
|
42
|
+
buildDeliverableWorkflowGuidance,
|
|
43
|
+
DeliverableValidationError,
|
|
44
|
+
extractArtifactsFromResult,
|
|
45
|
+
getDeliverableWorkflow,
|
|
46
|
+
selectDeliverableWorkflow,
|
|
47
|
+
validateDeliverableExecution,
|
|
48
|
+
} = require('./deliverables');
|
|
49
|
+
const { buildLoopPolicy, resolveToolResultLimits } = require('./loopPolicy');
|
|
50
|
+
const { globalHooks } = require('./hooks');
|
|
43
51
|
|
|
44
52
|
function generateTitle(task) {
|
|
45
53
|
if (!task || typeof task !== 'string') return 'Untitled';
|
|
@@ -72,11 +80,12 @@ function buildSkipTaskAnalysisResult(forceMode) {
|
|
|
72
80
|
};
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
function buildAnalyzeTaskFallback(forceMode) {
|
|
83
|
+
function buildAnalyzeTaskFallback(forceMode, userMessage = '') {
|
|
76
84
|
return {
|
|
77
85
|
mode: forceMode || 'execute',
|
|
78
86
|
verification_need: 'light',
|
|
79
87
|
planning_depth: planningDepthForForceMode(forceMode),
|
|
88
|
+
goal: userMessage ? String(userMessage).trim().slice(0, 300) : '',
|
|
80
89
|
};
|
|
81
90
|
}
|
|
82
91
|
|
|
@@ -640,10 +649,10 @@ class AgentEngine {
|
|
|
640
649
|
this.activeRuns = new Map();
|
|
641
650
|
this.subagents = new Map();
|
|
642
651
|
this.app = services.app || null;
|
|
643
|
-
this.cliExecutor = services.cliExecutor || null;
|
|
644
652
|
this.browserController = services.browserController || null;
|
|
645
653
|
this.androidController = services.androidController || null;
|
|
646
654
|
this.runtimeManager = services.runtimeManager || null;
|
|
655
|
+
this.workspaceManager = services.workspaceManager || null;
|
|
647
656
|
this.messagingManager = services.messagingManager || null;
|
|
648
657
|
this.mcpManager = services.mcpManager || services.mcpClient || null;
|
|
649
658
|
this.skillRunner = services.skillRunner || null;
|
|
@@ -675,6 +684,54 @@ class AgentEngine {
|
|
|
675
684
|
.run(JSON.stringify(next), runId);
|
|
676
685
|
}
|
|
677
686
|
|
|
687
|
+
recordRunEvent(userId, runId, eventType, payload = {}, options = {}) {
|
|
688
|
+
try {
|
|
689
|
+
return recordRunEvent({
|
|
690
|
+
runId,
|
|
691
|
+
userId,
|
|
692
|
+
agentId: options.agentId || null,
|
|
693
|
+
eventType,
|
|
694
|
+
requestId: options.requestId || null,
|
|
695
|
+
stepId: options.stepId || null,
|
|
696
|
+
payload,
|
|
697
|
+
});
|
|
698
|
+
} catch {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
async persistDeliverableMemory(userId, runId, agentId, deliverableResult) {
|
|
704
|
+
if (!this.memoryManager?.saveMemory || !deliverableResult?.summary) return;
|
|
705
|
+
try {
|
|
706
|
+
await this.memoryManager.saveMemory(
|
|
707
|
+
userId,
|
|
708
|
+
deliverableResult.summary,
|
|
709
|
+
'tasks',
|
|
710
|
+
deliverableResult.validation?.status === 'passed' ? 7 : 5,
|
|
711
|
+
{
|
|
712
|
+
agentId,
|
|
713
|
+
sourceRef: {
|
|
714
|
+
sourceType: 'deliverable_run',
|
|
715
|
+
sourceId: runId,
|
|
716
|
+
sourceLabel: deliverableResult.type || 'deliverable',
|
|
717
|
+
},
|
|
718
|
+
metadata: {
|
|
719
|
+
deliverableType: deliverableResult.type,
|
|
720
|
+
status: deliverableResult.status,
|
|
721
|
+
artifactCount: Array.isArray(deliverableResult.artifacts)
|
|
722
|
+
? deliverableResult.artifacts.length
|
|
723
|
+
: 0,
|
|
724
|
+
artifacts: Array.isArray(deliverableResult.artifacts)
|
|
725
|
+
? deliverableResult.artifacts.slice(0, 6)
|
|
726
|
+
: [],
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
);
|
|
730
|
+
} catch (error) {
|
|
731
|
+
console.error('[Engine] Failed to persist deliverable memory:', error?.message || error);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
678
735
|
async publishInterimUpdate({
|
|
679
736
|
userId,
|
|
680
737
|
runId,
|
|
@@ -686,6 +743,7 @@ class AgentEngine {
|
|
|
686
743
|
content,
|
|
687
744
|
kind,
|
|
688
745
|
expectsReply = false,
|
|
746
|
+
deferFollowUp = false,
|
|
689
747
|
} = {}) {
|
|
690
748
|
const runMeta = this.getRunMeta(runId);
|
|
691
749
|
if (!runMeta || runMeta.aborted) {
|
|
@@ -715,6 +773,9 @@ class AgentEngine {
|
|
|
715
773
|
kind: normalizedKind,
|
|
716
774
|
expectsReply,
|
|
717
775
|
});
|
|
776
|
+
if (deferFollowUp === true) {
|
|
777
|
+
metadata.defer_follow_up = true;
|
|
778
|
+
}
|
|
718
779
|
const createdAt = new Date().toISOString();
|
|
719
780
|
|
|
720
781
|
if (triggerSource === 'messaging') {
|
|
@@ -739,6 +800,7 @@ class AgentEngine {
|
|
|
739
800
|
content: normalizedContent,
|
|
740
801
|
kind: normalizedKind,
|
|
741
802
|
expectsReply,
|
|
803
|
+
deferFollowUp,
|
|
742
804
|
});
|
|
743
805
|
} else {
|
|
744
806
|
db.prepare(
|
|
@@ -758,6 +820,7 @@ class AgentEngine {
|
|
|
758
820
|
content: normalizedContent,
|
|
759
821
|
kind: normalizedKind,
|
|
760
822
|
expectsReply: expectsReply === true,
|
|
823
|
+
deferFollowUp: deferFollowUp === true,
|
|
761
824
|
createdAt,
|
|
762
825
|
});
|
|
763
826
|
runMeta.lastInterimMessage = normalizedContent;
|
|
@@ -767,6 +830,7 @@ class AgentEngine {
|
|
|
767
830
|
content: normalizedContent,
|
|
768
831
|
kind: normalizedKind,
|
|
769
832
|
expectsReply: expectsReply === true,
|
|
833
|
+
deferFollowUp: deferFollowUp === true,
|
|
770
834
|
triggerSource,
|
|
771
835
|
platform: triggerSource === 'messaging' ? platform : 'web',
|
|
772
836
|
});
|
|
@@ -783,6 +847,7 @@ class AgentEngine {
|
|
|
783
847
|
latestInterim: {
|
|
784
848
|
kind: normalizedKind,
|
|
785
849
|
expectsReply: expectsReply === true,
|
|
850
|
+
deferFollowUp: deferFollowUp === true,
|
|
786
851
|
content: normalizedContent,
|
|
787
852
|
createdAt,
|
|
788
853
|
},
|
|
@@ -795,6 +860,7 @@ class AgentEngine {
|
|
|
795
860
|
sent: true,
|
|
796
861
|
kind: normalizedKind,
|
|
797
862
|
expectsReply: expectsReply === true,
|
|
863
|
+
deferFollowUp: deferFollowUp === true,
|
|
798
864
|
content: normalizedContent,
|
|
799
865
|
terminal: terminalInterim,
|
|
800
866
|
};
|
|
@@ -898,6 +964,7 @@ class AgentEngine {
|
|
|
898
964
|
tools,
|
|
899
965
|
capabilityHealth,
|
|
900
966
|
forceMode,
|
|
967
|
+
userMessage,
|
|
901
968
|
options,
|
|
902
969
|
}) {
|
|
903
970
|
const summary = summarizeCapabilityHealth(capabilityHealth);
|
|
@@ -913,7 +980,7 @@ class AgentEngine {
|
|
|
913
980
|
}),
|
|
914
981
|
maxTokens: 1100,
|
|
915
982
|
normalize: normalizeTaskAnalysis,
|
|
916
|
-
fallback: buildAnalyzeTaskFallback(forceMode),
|
|
983
|
+
fallback: buildAnalyzeTaskFallback(forceMode, userMessage),
|
|
917
984
|
reasoningEffort: this.getReasoningEffort(providerName, options),
|
|
918
985
|
});
|
|
919
986
|
|
|
@@ -966,6 +1033,7 @@ class AgentEngine {
|
|
|
966
1033
|
toolExecutions,
|
|
967
1034
|
lastReply,
|
|
968
1035
|
triggerSource,
|
|
1036
|
+
messagingSent,
|
|
969
1037
|
iteration,
|
|
970
1038
|
maxIterations,
|
|
971
1039
|
options,
|
|
@@ -995,9 +1063,11 @@ class AgentEngine {
|
|
|
995
1063
|
'- A progress update is not complete.',
|
|
996
1064
|
'- A single failed tool attempt is not blocked if another safe retry, verification step, or alternative path remains.',
|
|
997
1065
|
'- A tool-specific API error, timeout, rate limit, or missing result inside this run is usually "continue", not "blocked", if any other available tool could still make progress.',
|
|
998
|
-
triggerSource === 'messaging'
|
|
999
|
-
? '-
|
|
1000
|
-
:
|
|
1066
|
+
triggerSource === 'messaging' && messagingSent
|
|
1067
|
+
? '- A reply was already delivered to the user via send_message. Use "complete" unless there is concrete remaining work (e.g., a tool call you still need to make) before the task is truly done. Do not send follow-up elaborations or re-introductions.'
|
|
1068
|
+
: triggerSource === 'messaging'
|
|
1069
|
+
? '- For messaging, do not stop on a partial status message. Continue unless the task is actually complete or externally blocked. If you already asked for missing user input, choose "blocked" and wait.'
|
|
1070
|
+
: '- Do not stop just because you wrote a status update. Continue unless the task is actually complete or externally blocked.',
|
|
1001
1071
|
analysis?.goal ? `Goal: ${analysis.goal}` : '',
|
|
1002
1072
|
successCriteria.length > 0 ? `Success criteria:\n${successCriteria.map((item, index) => `${index + 1}. ${item}`).join('\n')}` : '',
|
|
1003
1073
|
`Current iteration: ${iteration} of ${maxIterations}.`,
|
|
@@ -1314,8 +1384,10 @@ class AgentEngine {
|
|
|
1314
1384
|
const runMeta = this.getRunMeta(runId);
|
|
1315
1385
|
if (!runMeta || !pid) return;
|
|
1316
1386
|
runMeta.toolPids.add(pid);
|
|
1317
|
-
if (runMeta.aborted
|
|
1318
|
-
this.
|
|
1387
|
+
if (runMeta.aborted) {
|
|
1388
|
+
if (this.runtimeManager && typeof this.runtimeManager.killCommand === 'function') {
|
|
1389
|
+
void this.runtimeManager.killCommand(runMeta.userId, pid, 'aborted');
|
|
1390
|
+
}
|
|
1319
1391
|
}
|
|
1320
1392
|
}
|
|
1321
1393
|
|
|
@@ -1325,11 +1397,8 @@ class AgentEngine {
|
|
|
1325
1397
|
runMeta.toolPids.delete(pid);
|
|
1326
1398
|
}
|
|
1327
1399
|
|
|
1328
|
-
getIterationLimit(
|
|
1329
|
-
|
|
1330
|
-
if (options.widgetId) return Math.min(this.maxIterations, WIDGET_REFRESH_MAX_ITERATIONS);
|
|
1331
|
-
return this.maxIterations;
|
|
1332
|
-
}
|
|
1400
|
+
// getIterationLimit() removed — use buildLoopPolicy() directly.
|
|
1401
|
+
// maxIterations is derived in runWithModel from loopPolicy.maxIterations.
|
|
1333
1402
|
|
|
1334
1403
|
getReasoningEffort(providerName, options = {}) {
|
|
1335
1404
|
if (providerName === 'google') return undefined;
|
|
@@ -1468,8 +1537,11 @@ class AgentEngine {
|
|
|
1468
1537
|
1,
|
|
1469
1538
|
Number(options.historyWindow || aiSettings.chat_history_window) || aiSettings.chat_history_window,
|
|
1470
1539
|
);
|
|
1471
|
-
|
|
1472
|
-
|
|
1540
|
+
// loopPolicy is built after task analysis so analysisMode can be passed in;
|
|
1541
|
+
// we build a provisional policy now (with default mode) and rebuild after
|
|
1542
|
+
// analysis when the mode is known. See the post-analysis policy rebuild below.
|
|
1543
|
+
let loopPolicy = buildLoopPolicy(aiSettings, triggerType, 'execute', options);
|
|
1544
|
+
let maxIterations = loopPolicy.maxIterations;
|
|
1473
1545
|
const providerStatusConfig = {
|
|
1474
1546
|
agentId,
|
|
1475
1547
|
onStatus: (status) => {
|
|
@@ -1524,6 +1596,12 @@ class AgentEngine {
|
|
|
1524
1596
|
toolPids: new Set(),
|
|
1525
1597
|
});
|
|
1526
1598
|
this.emit(userId, 'run:start', { runId, agentId, title: runTitle, model, triggerType, triggerSource });
|
|
1599
|
+
this.recordRunEvent(userId, runId, 'run_started', {
|
|
1600
|
+
title: runTitle,
|
|
1601
|
+
model,
|
|
1602
|
+
triggerType,
|
|
1603
|
+
triggerSource,
|
|
1604
|
+
}, { agentId });
|
|
1527
1605
|
console.info(
|
|
1528
1606
|
`[Run ${shortenRunId(runId)}] started trigger=${triggerSource} type=${triggerType} model=${model} title=${summarizeForLog(runTitle, 120)}`
|
|
1529
1607
|
);
|
|
@@ -1542,6 +1620,7 @@ class AgentEngine {
|
|
|
1542
1620
|
agentId,
|
|
1543
1621
|
triggerType,
|
|
1544
1622
|
triggerSource,
|
|
1623
|
+
widgetId: options.widgetId || null,
|
|
1545
1624
|
});
|
|
1546
1625
|
const mcpManager = app?.locals?.mcpManager || app?.locals?.mcpClient || this.mcpManager;
|
|
1547
1626
|
const integrationManager = app?.locals?.integrationManager || null;
|
|
@@ -1583,6 +1662,11 @@ class AgentEngine {
|
|
|
1583
1662
|
if (threadStateMessage) {
|
|
1584
1663
|
messages.push({ role: 'system', content: threadStateMessage });
|
|
1585
1664
|
}
|
|
1665
|
+
this.recordRunEvent(userId, runId, 'memory_injected', {
|
|
1666
|
+
hasRecallContext: Boolean(recallMsg),
|
|
1667
|
+
hasThreadState: Boolean(threadStateMessage),
|
|
1668
|
+
recallPreview: recallMsg ? String(recallMsg).slice(0, 240) : '',
|
|
1669
|
+
}, { agentId });
|
|
1586
1670
|
messages.push(this.buildUserMessage(userMessage, options));
|
|
1587
1671
|
messages = sanitizeConversationMessages(messages);
|
|
1588
1672
|
|
|
@@ -1602,6 +1686,10 @@ class AgentEngine {
|
|
|
1602
1686
|
let analysis = null;
|
|
1603
1687
|
let plan = null;
|
|
1604
1688
|
let verification = null;
|
|
1689
|
+
let deliverableWorkflow = null;
|
|
1690
|
+
let deliverablePlan = null;
|
|
1691
|
+
let deliverableArtifacts = [];
|
|
1692
|
+
let deliverableValidation = null;
|
|
1605
1693
|
let directAnswerEligible = false;
|
|
1606
1694
|
let analysisUsage = 0;
|
|
1607
1695
|
|
|
@@ -1617,11 +1705,15 @@ class AgentEngine {
|
|
|
1617
1705
|
tools,
|
|
1618
1706
|
capabilityHealth,
|
|
1619
1707
|
forceMode: options.forceMode || null,
|
|
1708
|
+
userMessage,
|
|
1620
1709
|
options: { ...options, triggerSource },
|
|
1621
1710
|
});
|
|
1622
1711
|
analysisUsage = analysisResult.usage || 0;
|
|
1623
1712
|
totalTokens += analysisUsage;
|
|
1624
1713
|
analysis = applyForcedAnalysisMode({ ...analysisResult.analysis }, options.forceMode);
|
|
1714
|
+
if (!analysis.goal && userMessage) {
|
|
1715
|
+
analysis.goal = String(userMessage).trim().slice(0, 300);
|
|
1716
|
+
}
|
|
1625
1717
|
analysis.mode = promoteAnalysisMode(analysis.mode, {
|
|
1626
1718
|
verificationNeed: analysis.verification_need,
|
|
1627
1719
|
freshnessRisk: analysis.freshness_risk,
|
|
@@ -1652,6 +1744,62 @@ class AgentEngine {
|
|
|
1652
1744
|
...analysis,
|
|
1653
1745
|
capabilitySummary,
|
|
1654
1746
|
});
|
|
1747
|
+
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// Rebuild loop policy with the resolved analysis mode. Runs in both the
|
|
1751
|
+
// normal path and the skipTaskAnalysis path so that forceMode='plan_execute'
|
|
1752
|
+
// (or any mode set by buildSkipTaskAnalysisResult) raises the iteration
|
|
1753
|
+
// ceiling correctly.
|
|
1754
|
+
loopPolicy = buildLoopPolicy(aiSettings, triggerType, analysis.mode || 'execute', options);
|
|
1755
|
+
maxIterations = loopPolicy.maxIterations;
|
|
1756
|
+
|
|
1757
|
+
if (options.skipDeliverableWorkflow !== true) {
|
|
1758
|
+
const deliverableSelectionResult = await selectDeliverableWorkflow({
|
|
1759
|
+
engine: this,
|
|
1760
|
+
provider,
|
|
1761
|
+
providerName,
|
|
1762
|
+
model,
|
|
1763
|
+
messages,
|
|
1764
|
+
tools,
|
|
1765
|
+
options,
|
|
1766
|
+
});
|
|
1767
|
+
totalTokens += deliverableSelectionResult.usage || 0;
|
|
1768
|
+
const selectedWorkflow = getDeliverableWorkflow(deliverableSelectionResult.selection.type);
|
|
1769
|
+
if (selectedWorkflow?.canHandle(deliverableSelectionResult.selection)) {
|
|
1770
|
+
deliverableWorkflow = {
|
|
1771
|
+
workflow: selectedWorkflow,
|
|
1772
|
+
selection: deliverableSelectionResult.selection,
|
|
1773
|
+
request: selectedWorkflow.normalizeRequest({
|
|
1774
|
+
...deliverableSelectionResult.selection,
|
|
1775
|
+
userMessage,
|
|
1776
|
+
}),
|
|
1777
|
+
};
|
|
1778
|
+
deliverablePlan = selectedWorkflow.buildExecutionPlan(deliverableWorkflow.request, {
|
|
1779
|
+
analysis,
|
|
1780
|
+
tools,
|
|
1781
|
+
options,
|
|
1782
|
+
});
|
|
1783
|
+
await selectedWorkflow.run(deliverablePlan, {
|
|
1784
|
+
engine: this,
|
|
1785
|
+
userId,
|
|
1786
|
+
runId,
|
|
1787
|
+
agentId,
|
|
1788
|
+
app,
|
|
1789
|
+
});
|
|
1790
|
+
this.persistRunMetadata(runId, {
|
|
1791
|
+
deliverableWorkflow: {
|
|
1792
|
+
...deliverableWorkflow.selection,
|
|
1793
|
+
plan: deliverablePlan,
|
|
1794
|
+
},
|
|
1795
|
+
});
|
|
1796
|
+
this.recordRunEvent(userId, runId, 'deliverable_workflow_selected', {
|
|
1797
|
+
type: deliverableWorkflow.selection.type,
|
|
1798
|
+
confidence: deliverableWorkflow.selection.confidence,
|
|
1799
|
+
goal: deliverableWorkflow.selection.goal,
|
|
1800
|
+
requestedOutputs: deliverableWorkflow.selection.requestedOutputs,
|
|
1801
|
+
}, { agentId });
|
|
1802
|
+
}
|
|
1655
1803
|
}
|
|
1656
1804
|
|
|
1657
1805
|
if (analysis.mode === 'plan_execute') {
|
|
@@ -1697,6 +1845,17 @@ class AgentEngine {
|
|
|
1697
1845
|
capabilityHealth: capabilitySummary,
|
|
1698
1846
|
}),
|
|
1699
1847
|
});
|
|
1848
|
+
if (deliverablePlan) {
|
|
1849
|
+
messages.push({
|
|
1850
|
+
role: 'system',
|
|
1851
|
+
content: buildDeliverableWorkflowGuidance(deliverablePlan),
|
|
1852
|
+
});
|
|
1853
|
+
this.recordRunEvent(userId, runId, 'deliverable_execution_started', {
|
|
1854
|
+
type: deliverableWorkflow?.selection?.type,
|
|
1855
|
+
preferredTools: deliverablePlan.preferredTools || [],
|
|
1856
|
+
expectedOutputs: deliverablePlan.expectedOutputs || [],
|
|
1857
|
+
}, { agentId });
|
|
1858
|
+
}
|
|
1700
1859
|
messages = sanitizeConversationMessages(messages);
|
|
1701
1860
|
|
|
1702
1861
|
directAnswerEligible = isDirectAnswerEligibleAnalysis(analysis)
|
|
@@ -1712,10 +1871,15 @@ class AgentEngine {
|
|
|
1712
1871
|
}
|
|
1713
1872
|
}
|
|
1714
1873
|
|
|
1874
|
+
// BUG FIX: consecutiveToolFailures was previously declared INSIDE the
|
|
1875
|
+
// while loop (resetting each iteration). It is now tracked across the
|
|
1876
|
+
// full run so the failure guard fires correctly after 5 consecutive failures
|
|
1877
|
+
// regardless of which iteration they fall in.
|
|
1878
|
+
let consecutiveToolFailures = 0;
|
|
1879
|
+
|
|
1715
1880
|
while (!directAnswerEligible && iteration < maxIterations) {
|
|
1716
1881
|
if (this.isRunStopped(runId)) break;
|
|
1717
1882
|
iteration++;
|
|
1718
|
-
let consecutiveToolFailures = 0;
|
|
1719
1883
|
|
|
1720
1884
|
const steeringAtLoopStart = this.applyQueuedSteering(runId, messages, {
|
|
1721
1885
|
userId,
|
|
@@ -1726,7 +1890,7 @@ class AgentEngine {
|
|
|
1726
1890
|
|
|
1727
1891
|
let metrics = this.estimatePromptMetrics(messages, tools);
|
|
1728
1892
|
const contextWindow = provider.getContextWindow(model);
|
|
1729
|
-
if (metrics.totalEstimatedTokens > contextWindow *
|
|
1893
|
+
if (metrics.totalEstimatedTokens > contextWindow * loopPolicy.compactionThreshold) {
|
|
1730
1894
|
messages = await compact(messages, provider, model, contextWindow);
|
|
1731
1895
|
messages = sanitizeConversationMessages(messages);
|
|
1732
1896
|
this.emit(userId, 'run:compaction', { runId, iteration });
|
|
@@ -1736,6 +1900,10 @@ class AgentEngine {
|
|
|
1736
1900
|
promptMetrics = this.mergePromptMetrics(promptMetrics, metrics, iteration, tools.length);
|
|
1737
1901
|
this.persistPromptMetrics(runId, promptMetrics).catch(() => { });
|
|
1738
1902
|
this.emit(userId, 'run:thinking', { runId, iteration });
|
|
1903
|
+
this.recordRunEvent(userId, runId, 'model_turn_started', {
|
|
1904
|
+
iteration,
|
|
1905
|
+
toolCount: tools.length,
|
|
1906
|
+
}, { agentId });
|
|
1739
1907
|
|
|
1740
1908
|
let response;
|
|
1741
1909
|
let responseModel = model;
|
|
@@ -1813,7 +1981,7 @@ class AgentEngine {
|
|
|
1813
1981
|
const isFatalModelError = /no ai providers? are currently available|missing an api key|disabled in settings|unauthorized|forbidden|authentication failed/i
|
|
1814
1982
|
.test(modelError);
|
|
1815
1983
|
|
|
1816
|
-
if (!isFatalModelError && modelFailureRecoveries <
|
|
1984
|
+
if (!isFatalModelError && modelFailureRecoveries < loopPolicy.maxModelFailureRecoveries) {
|
|
1817
1985
|
modelFailureRecoveries += 1;
|
|
1818
1986
|
failedStepCount += 1;
|
|
1819
1987
|
const failedModel = model;
|
|
@@ -1869,6 +2037,12 @@ class AgentEngine {
|
|
|
1869
2037
|
}
|
|
1870
2038
|
}
|
|
1871
2039
|
|
|
2040
|
+
this.recordRunEvent(userId, runId, 'model_turn_completed', {
|
|
2041
|
+
iteration,
|
|
2042
|
+
toolCallCount: response.toolCalls?.length || 0,
|
|
2043
|
+
contentPreview: String(lastContent || streamContent || '').slice(0, 240),
|
|
2044
|
+
}, { agentId });
|
|
2045
|
+
|
|
1872
2046
|
const assistantMessage = { role: 'assistant', content: lastContent };
|
|
1873
2047
|
if (response.toolCalls?.length) assistantMessage.tool_calls = response.toolCalls;
|
|
1874
2048
|
if (response.providerContentBlocks?.length) assistantMessage.providerContentBlocks = response.providerContentBlocks;
|
|
@@ -1919,6 +2093,7 @@ class AgentEngine {
|
|
|
1919
2093
|
toolExecutions,
|
|
1920
2094
|
lastReply: lastContent,
|
|
1921
2095
|
triggerSource,
|
|
2096
|
+
messagingSent,
|
|
1922
2097
|
iteration,
|
|
1923
2098
|
maxIterations,
|
|
1924
2099
|
options,
|
|
@@ -1955,6 +2130,44 @@ class AgentEngine {
|
|
|
1955
2130
|
toolArgs = {};
|
|
1956
2131
|
}
|
|
1957
2132
|
|
|
2133
|
+
// ── task_complete: AI explicitly signals the task is fully done ──
|
|
2134
|
+
// Handle before DB insert / before_tool_call hook — this is not a
|
|
2135
|
+
// regular tool execution, it is a loop-exit signal.
|
|
2136
|
+
if (toolName === 'task_complete') {
|
|
2137
|
+
const finalMessage = String(toolArgs.message || '').trim();
|
|
2138
|
+
this.recordRunEvent(userId, runId, 'task_complete_signaled', {
|
|
2139
|
+
confidence: toolArgs.confidence || 'high',
|
|
2140
|
+
iteration,
|
|
2141
|
+
messageLength: finalMessage.length,
|
|
2142
|
+
}, { agentId });
|
|
2143
|
+
console.info(
|
|
2144
|
+
`[Run ${shortenRunId(runId)}] task_complete signaled at iteration=${iteration} confidence=${toolArgs.confidence || 'high'}`
|
|
2145
|
+
);
|
|
2146
|
+
// Always honor task_complete as a stop signal, even with no message.
|
|
2147
|
+
lastContent = finalMessage; // empty string is valid; downstream handles it
|
|
2148
|
+
directAnswerEligible = true;
|
|
2149
|
+
break; // exit the for-loop; the while condition will also exit
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// ── before_tool_call hook ──
|
|
2153
|
+
// Plugins can block a tool call (e.g. security policy) or mutate args.
|
|
2154
|
+
if (globalHooks.has('before_tool_call')) {
|
|
2155
|
+
const hookCtx = { toolName, toolArgs, runId, userId, agentId, iteration };
|
|
2156
|
+
const hookResult = await globalHooks.run('before_tool_call', hookCtx);
|
|
2157
|
+
if (hookResult.block) {
|
|
2158
|
+
console.warn(`[Run ${shortenRunId(runId)}] before_tool_call hook blocked tool=${toolName}`);
|
|
2159
|
+
// Treat as a soft skip — add a skipped tool message so the model knows
|
|
2160
|
+
messages.push({
|
|
2161
|
+
role: 'tool',
|
|
2162
|
+
name: toolName,
|
|
2163
|
+
tool_call_id: toolCall.id,
|
|
2164
|
+
content: JSON.stringify({ tool: toolName, status: 'skipped', reason: 'Blocked by policy.' }),
|
|
2165
|
+
});
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2168
|
+
if (hookResult.toolArgs) toolArgs = hookResult.toolArgs;
|
|
2169
|
+
}
|
|
2170
|
+
|
|
1958
2171
|
db.prepare('INSERT INTO agent_steps (id, run_id, step_index, type, description, status, tool_name, tool_input, started_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime(\'now\'))')
|
|
1959
2172
|
.run(stepId, runId, stepIndex, this.getStepType(toolName), `${toolName}: ${JSON.stringify(toolArgs).slice(0, 200)} `, 'running', toolName, JSON.stringify(toolArgs));
|
|
1960
2173
|
|
|
@@ -1962,6 +2175,12 @@ class AgentEngine {
|
|
|
1962
2175
|
runId, stepId, stepIndex, toolName, toolArgs,
|
|
1963
2176
|
type: this.getStepType(toolName)
|
|
1964
2177
|
});
|
|
2178
|
+
this.recordRunEvent(userId, runId, 'tool_started', {
|
|
2179
|
+
stepIndex,
|
|
2180
|
+
toolName,
|
|
2181
|
+
toolArgs,
|
|
2182
|
+
type: this.getStepType(toolName),
|
|
2183
|
+
}, { agentId, stepId });
|
|
1965
2184
|
console.info(
|
|
1966
2185
|
`[Run ${shortenRunId(runId)}] step=${stepIndex} start tool=${toolName} args=${summarizeForLog(toolArgs)}`
|
|
1967
2186
|
);
|
|
@@ -1996,11 +2215,24 @@ class AgentEngine {
|
|
|
1996
2215
|
.run(stepStatus, JSON.stringify(toolResult).slice(0, 20000), toolErrorMessage || null, screenshotPath, stepId);
|
|
1997
2216
|
if (toolErrorMessage) {
|
|
1998
2217
|
this.emit(userId, 'run:tool_end', { runId, stepId, toolName, error: toolErrorMessage, result: toolResult, screenshotPath, status: stepStatus });
|
|
2218
|
+
this.recordRunEvent(userId, runId, 'tool_failed', {
|
|
2219
|
+
toolName,
|
|
2220
|
+
status: stepStatus,
|
|
2221
|
+
error: toolErrorMessage,
|
|
2222
|
+
durationMs: Date.now() - stepStartedAt,
|
|
2223
|
+
resultPreview: summarizeForLog(toolResult),
|
|
2224
|
+
}, { agentId, stepId });
|
|
1999
2225
|
console.warn(
|
|
2000
2226
|
`[Run ${shortenRunId(runId)}] step=${stepIndex} failed tool=${toolName} durationMs=${Date.now() - stepStartedAt} error=${summarizeForLog(toolErrorMessage, 160)}`
|
|
2001
2227
|
);
|
|
2002
2228
|
} else {
|
|
2003
2229
|
this.emit(userId, 'run:tool_end', { runId, stepId, toolName, result: toolResult, screenshotPath, status: stepStatus });
|
|
2230
|
+
this.recordRunEvent(userId, runId, 'tool_completed', {
|
|
2231
|
+
toolName,
|
|
2232
|
+
status: stepStatus,
|
|
2233
|
+
durationMs: Date.now() - stepStartedAt,
|
|
2234
|
+
resultPreview: summarizeForLog(toolResult),
|
|
2235
|
+
}, { agentId, stepId });
|
|
2004
2236
|
console.info(
|
|
2005
2237
|
`[Run ${shortenRunId(runId)}] step=${stepIndex} done tool=${toolName} status=${stepStatus} durationMs=${Date.now() - stepStartedAt} result=${summarizeForLog(toolResult)}`
|
|
2006
2238
|
);
|
|
@@ -2013,25 +2245,49 @@ class AgentEngine {
|
|
|
2013
2245
|
db.prepare('UPDATE agent_steps SET status = ?, error = ?, completed_at = datetime(\'now\') WHERE id = ?')
|
|
2014
2246
|
.run('failed', err.message, stepId);
|
|
2015
2247
|
this.emit(userId, 'run:tool_end', { runId, stepId, toolName, error: err.message, status: 'failed' });
|
|
2248
|
+
this.recordRunEvent(userId, runId, 'tool_failed', {
|
|
2249
|
+
toolName,
|
|
2250
|
+
status: 'failed',
|
|
2251
|
+
error: err.message,
|
|
2252
|
+
durationMs: Date.now() - stepStartedAt,
|
|
2253
|
+
}, { agentId, stepId });
|
|
2016
2254
|
console.warn(
|
|
2017
2255
|
`[Run ${shortenRunId(runId)}] step=${stepIndex} failed tool=${toolName} durationMs=${Date.now() - stepStartedAt} error=${summarizeForLog(err.message, 160)}`
|
|
2018
2256
|
);
|
|
2019
2257
|
}
|
|
2020
2258
|
|
|
2021
2259
|
const execution = classifyToolExecution(toolName, toolArgs, toolResult, toolErrorMessage);
|
|
2260
|
+
execution.artifacts = await extractArtifactsFromResult(toolName, toolResult);
|
|
2022
2261
|
toolExecutions.push(execution);
|
|
2262
|
+
if (deliverableWorkflow && Array.isArray(execution.artifacts) && execution.artifacts.length > 0) {
|
|
2263
|
+
for (const artifact of execution.artifacts) {
|
|
2264
|
+
if (!deliverableArtifacts.some((existing) => (
|
|
2265
|
+
(existing.path && artifact.path && existing.path === artifact.path)
|
|
2266
|
+
|| (existing.uri && artifact.uri && existing.uri === artifact.uri)
|
|
2267
|
+
))) {
|
|
2268
|
+
deliverableArtifacts.push(artifact);
|
|
2269
|
+
this.recordRunEvent(userId, runId, 'deliverable_artifact_produced', {
|
|
2270
|
+
type: deliverableWorkflow.selection.type,
|
|
2271
|
+
toolName,
|
|
2272
|
+
artifact,
|
|
2273
|
+
}, { agentId, stepId });
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2023
2277
|
this.persistRunMetadata(runId, {
|
|
2024
2278
|
evidenceSources: [...new Set(toolExecutions.map((item) => item.evidenceSource).filter(Boolean))],
|
|
2025
2279
|
subagentState: this.listSubagents(runId),
|
|
2280
|
+
deliverableArtifacts,
|
|
2026
2281
|
});
|
|
2027
2282
|
|
|
2283
|
+
const toolResultLimits = resolveToolResultLimits(toolName, loopPolicy);
|
|
2028
2284
|
const toolMessage = {
|
|
2029
2285
|
role: 'tool',
|
|
2030
2286
|
name: toolName,
|
|
2031
2287
|
tool_call_id: toolCall.id,
|
|
2032
2288
|
content: compactToolResult(toolName, toolArgs, toolResult, {
|
|
2033
|
-
softLimit:
|
|
2034
|
-
hardLimit:
|
|
2289
|
+
softLimit: toolResultLimits.softLimit,
|
|
2290
|
+
hardLimit: toolResultLimits.hardLimit,
|
|
2035
2291
|
})
|
|
2036
2292
|
};
|
|
2037
2293
|
messages.push(toolMessage);
|
|
@@ -2050,7 +2306,7 @@ class AgentEngine {
|
|
|
2050
2306
|
].filter(Boolean).join(' ')
|
|
2051
2307
|
});
|
|
2052
2308
|
|
|
2053
|
-
if (consecutiveToolFailures >=
|
|
2309
|
+
if (consecutiveToolFailures >= loopPolicy.maxConsecutiveToolFailures) {
|
|
2054
2310
|
messages.push({
|
|
2055
2311
|
role: 'system',
|
|
2056
2312
|
content: `There were ${consecutiveToolFailures} consecutive tool failures. Stop calling tools now and return a clear blocker response that summarizes attempted actions and concrete errors.`
|
|
@@ -2124,6 +2380,11 @@ class AgentEngine {
|
|
|
2124
2380
|
);
|
|
2125
2381
|
this.activeRuns.delete(runId);
|
|
2126
2382
|
this.emit(userId, 'run:stopped', { runId, triggerSource });
|
|
2383
|
+
this.recordRunEvent(userId, runId, 'run_stopped', {
|
|
2384
|
+
triggerSource,
|
|
2385
|
+
totalTokens,
|
|
2386
|
+
iterations: iteration,
|
|
2387
|
+
}, { agentId });
|
|
2127
2388
|
return { runId, content: '', totalTokens, iterations: iteration, status: 'stopped' };
|
|
2128
2389
|
}
|
|
2129
2390
|
|
|
@@ -2237,6 +2498,46 @@ class AgentEngine {
|
|
|
2237
2498
|
});
|
|
2238
2499
|
}
|
|
2239
2500
|
|
|
2501
|
+
if (deliverableWorkflow && deliverablePlan) {
|
|
2502
|
+
this.recordRunEvent(userId, runId, 'deliverable_validation_started', {
|
|
2503
|
+
type: deliverableWorkflow.selection.type,
|
|
2504
|
+
artifactCount: deliverableArtifacts.length,
|
|
2505
|
+
}, { agentId });
|
|
2506
|
+
const validationResult = await validateDeliverableExecution({
|
|
2507
|
+
workflow: deliverableWorkflow.workflow,
|
|
2508
|
+
request: deliverableWorkflow.request,
|
|
2509
|
+
plan: deliverablePlan,
|
|
2510
|
+
finalReply: finalResponseText,
|
|
2511
|
+
artifacts: deliverableArtifacts,
|
|
2512
|
+
toolExecutions,
|
|
2513
|
+
runId,
|
|
2514
|
+
});
|
|
2515
|
+
deliverableValidation = validationResult.validation;
|
|
2516
|
+
this.persistRunMetadata(runId, {
|
|
2517
|
+
deliverable: validationResult.result,
|
|
2518
|
+
});
|
|
2519
|
+
if (deliverableValidation.status !== 'passed') {
|
|
2520
|
+
this.recordRunEvent(userId, runId, 'deliverable_validation_failed', {
|
|
2521
|
+
type: deliverableWorkflow.selection.type,
|
|
2522
|
+
errors: deliverableValidation.errors,
|
|
2523
|
+
warnings: deliverableValidation.warnings,
|
|
2524
|
+
}, { agentId });
|
|
2525
|
+
throw new DeliverableValidationError(
|
|
2526
|
+
deliverableValidation.summary || `Deliverable validation failed for ${deliverableWorkflow.selection.type}.`,
|
|
2527
|
+
{
|
|
2528
|
+
validation: deliverableValidation,
|
|
2529
|
+
result: validationResult.result,
|
|
2530
|
+
},
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
await this.persistDeliverableMemory(userId, runId, agentId, validationResult.result);
|
|
2534
|
+
this.recordRunEvent(userId, runId, 'deliverable_completed', {
|
|
2535
|
+
type: deliverableWorkflow.selection.type,
|
|
2536
|
+
artifactCount: validationResult.result.artifacts.length,
|
|
2537
|
+
summary: validationResult.result.summary,
|
|
2538
|
+
}, { agentId });
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2240
2541
|
db.prepare('UPDATE agent_runs SET status = ?, total_tokens = ?, final_response = ?, updated_at = datetime(\'now\'), completed_at = datetime(\'now\') WHERE id = ?')
|
|
2241
2542
|
.run('completed', totalTokens, finalResponseText || null, runId);
|
|
2242
2543
|
|
|
@@ -2327,6 +2628,26 @@ class AgentEngine {
|
|
|
2327
2628
|
executionMode: analysis?.mode || 'execute',
|
|
2328
2629
|
verificationStatus: verification?.status || 'skipped',
|
|
2329
2630
|
});
|
|
2631
|
+
this.recordRunEvent(userId, runId, 'run_completed', {
|
|
2632
|
+
contentPreview: String(finalResponseText || lastContent || '').slice(0, 240),
|
|
2633
|
+
totalTokens,
|
|
2634
|
+
iterations: iteration,
|
|
2635
|
+
triggerSource,
|
|
2636
|
+
executionMode: analysis?.mode || 'execute',
|
|
2637
|
+
verificationStatus: verification?.status || 'skipped',
|
|
2638
|
+
}, { agentId });
|
|
2639
|
+
|
|
2640
|
+
// ── on_loop_end hook ──
|
|
2641
|
+
// Fire-and-forget: plugins can use this for self-improvement, memory
|
|
2642
|
+
// consolidation, analytics, or other post-run housekeeping.
|
|
2643
|
+
if (globalHooks.has('on_loop_end')) {
|
|
2644
|
+
globalHooks.run('on_loop_end', {
|
|
2645
|
+
userId, runId, agentId, status: 'completed',
|
|
2646
|
+
iterations: iteration, totalTokens,
|
|
2647
|
+
taskAnalysis: analysis,
|
|
2648
|
+
finalContent: finalResponseText,
|
|
2649
|
+
}).catch(() => {});
|
|
2650
|
+
}
|
|
2330
2651
|
|
|
2331
2652
|
return { runId, content: lastContent, totalTokens, iterations: iteration, status: 'completed' };
|
|
2332
2653
|
} catch (err) {
|
|
@@ -2339,6 +2660,11 @@ class AgentEngine {
|
|
|
2339
2660
|
this.cleanupSubagentsForRun(runId, { cancelRunning: true });
|
|
2340
2661
|
this.activeRuns.delete(runId);
|
|
2341
2662
|
this.emit(userId, 'run:stopped', { runId, triggerSource });
|
|
2663
|
+
this.recordRunEvent(userId, runId, 'run_stopped', {
|
|
2664
|
+
triggerSource,
|
|
2665
|
+
totalTokens,
|
|
2666
|
+
iterations: iteration,
|
|
2667
|
+
}, { agentId });
|
|
2342
2668
|
return { runId, content: '', totalTokens, iterations: iteration, status: 'stopped' };
|
|
2343
2669
|
}
|
|
2344
2670
|
|
|
@@ -2348,6 +2674,7 @@ class AgentEngine {
|
|
|
2348
2674
|
triggerSource === 'messaging'
|
|
2349
2675
|
&& options.source
|
|
2350
2676
|
&& options.chatId
|
|
2677
|
+
&& err?.disableAutonomousRetry !== true
|
|
2351
2678
|
&& retryCount < this.getMessagingRetryLimit(maxIterations)
|
|
2352
2679
|
);
|
|
2353
2680
|
|
|
@@ -2402,6 +2729,9 @@ class AgentEngine {
|
|
|
2402
2729
|
return this.runWithModel(userId, userMessage, retryOptions, _modelOverride);
|
|
2403
2730
|
}
|
|
2404
2731
|
|
|
2732
|
+
const deliverableFailureResponse = err?.deliverableResult?.summary
|
|
2733
|
+
|| err?.deliverableValidation?.summary
|
|
2734
|
+
|| '';
|
|
2405
2735
|
let messagingFailureContent = '';
|
|
2406
2736
|
let sendSucceeded = false;
|
|
2407
2737
|
if (triggerSource === 'messaging' && options.source && options.chatId) {
|
|
@@ -2460,7 +2790,14 @@ class AgentEngine {
|
|
|
2460
2790
|
}
|
|
2461
2791
|
|
|
2462
2792
|
db.prepare('UPDATE agent_runs SET status = ?, error = ?, final_response = ?, updated_at = datetime(\'now\') WHERE id = ?')
|
|
2463
|
-
.run(
|
|
2793
|
+
.run(
|
|
2794
|
+
'failed',
|
|
2795
|
+
err.message,
|
|
2796
|
+
sendSucceeded
|
|
2797
|
+
? (messagingFailureContent || null)
|
|
2798
|
+
: (deliverableFailureResponse || null),
|
|
2799
|
+
runId,
|
|
2800
|
+
);
|
|
2464
2801
|
console.error(
|
|
2465
2802
|
`[Run ${shortenRunId(runId)}] failed trigger=${triggerSource} steps=${stepIndex} tokens=${totalTokens} error=${summarizeForLog(err.message, 180)}`
|
|
2466
2803
|
);
|
|
@@ -2468,6 +2805,12 @@ class AgentEngine {
|
|
|
2468
2805
|
this.cleanupSubagentsForRun(runId, { cancelRunning: true });
|
|
2469
2806
|
this.activeRuns.delete(runId);
|
|
2470
2807
|
this.emit(userId, 'run:error', { runId, error: err.message });
|
|
2808
|
+
this.recordRunEvent(userId, runId, 'run_failed', {
|
|
2809
|
+
error: err.message,
|
|
2810
|
+
totalTokens,
|
|
2811
|
+
iterations: iteration,
|
|
2812
|
+
deliverableType: deliverableWorkflow?.selection?.type || null,
|
|
2813
|
+
}, { agentId });
|
|
2471
2814
|
|
|
2472
2815
|
if (messagingFailureContent) {
|
|
2473
2816
|
return {
|
|
@@ -2488,10 +2831,10 @@ class AgentEngine {
|
|
|
2488
2831
|
const childRunId = uuidv4();
|
|
2489
2832
|
const subEngine = new AgentEngine(this.io, {
|
|
2490
2833
|
app: options.app || this.app,
|
|
2491
|
-
cliExecutor: this.cliExecutor,
|
|
2492
2834
|
browserController: this.browserController,
|
|
2493
2835
|
androidController: this.androidController,
|
|
2494
2836
|
runtimeManager: this.runtimeManager,
|
|
2837
|
+
workspaceManager: this.workspaceManager,
|
|
2495
2838
|
messagingManager: this.messagingManager,
|
|
2496
2839
|
mcpManager: this.mcpManager,
|
|
2497
2840
|
skillRunner: this.skillRunner,
|
|
@@ -2798,7 +3141,9 @@ class AgentEngine {
|
|
|
2798
3141
|
runMeta.aborted = true;
|
|
2799
3142
|
this.emit(runMeta.userId, 'run:stopping', { runId });
|
|
2800
3143
|
for (const pid of runMeta.toolPids) {
|
|
2801
|
-
this.
|
|
3144
|
+
if (this.runtimeManager && typeof this.runtimeManager.killCommand === 'function') {
|
|
3145
|
+
void this.runtimeManager.killCommand(runMeta.userId, pid, 'aborted');
|
|
3146
|
+
}
|
|
2802
3147
|
}
|
|
2803
3148
|
runMeta.toolPids.clear();
|
|
2804
3149
|
}
|