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
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const express = require('express');
|
|
4
|
+
const db = require('../db/database');
|
|
5
|
+
const { getErrorMessage } = require('../services/bootstrap_helpers');
|
|
6
|
+
const { requireAuth } = require('../middleware/auth');
|
|
7
|
+
|
|
8
|
+
const router = express.Router();
|
|
9
|
+
|
|
10
|
+
router.use(requireAuth);
|
|
11
|
+
|
|
12
|
+
router.post('/geofence', async (req, res) => {
|
|
13
|
+
const { label, latitude, longitude, radius_meters, action } = req.body;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const userRow = db.prepare('SELECT id FROM users WHERE id = ?').get(req.user.id);
|
|
17
|
+
if (!userRow) return res.status(401).json({ error: 'Unauthorized' });
|
|
18
|
+
|
|
19
|
+
console.log(`[Triggers] Geofence entered: ${label} by user ${req.user.id}`);
|
|
20
|
+
|
|
21
|
+
res.json({ success: true, message: 'Geofence trigger processed' });
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error('[Triggers] Geofence error:', getErrorMessage(err));
|
|
24
|
+
res.status(500).json({ error: 'Failed to process geofence trigger' });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Fire-and-forget after response is sent — errors here must never touch res.
|
|
29
|
+
Promise.resolve().then(() => {
|
|
30
|
+
const agentEngine = req.app.locals.agentEngine;
|
|
31
|
+
if (!agentEngine) return;
|
|
32
|
+
const defaultAgentId = db.prepare('SELECT id FROM agents WHERE user_id = ? ORDER BY is_default DESC LIMIT 1').get(req.user.id)?.id;
|
|
33
|
+
if (!defaultAgentId) return;
|
|
34
|
+
const prompt = [
|
|
35
|
+
`A geofence event was triggered.`,
|
|
36
|
+
`Location label: ${label || 'unknown'}`,
|
|
37
|
+
action ? `Suggested action: ${action}` : 'Check if there are any active reminders or tasks related to this location.',
|
|
38
|
+
].join('\n');
|
|
39
|
+
return agentEngine.run(req.user.id, prompt, {
|
|
40
|
+
agentId: defaultAgentId,
|
|
41
|
+
triggerSource: 'tasks',
|
|
42
|
+
context: { source: 'geofence', label, latitude, longitude, radius_meters },
|
|
43
|
+
});
|
|
44
|
+
}).catch(err => console.error('[Triggers] Geofence agent run failed:', err.message));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
router.post('/notification', async (req, res) => {
|
|
48
|
+
const { app_package, title, body, action_taken } = req.body;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const userRow = db.prepare('SELECT id FROM users WHERE id = ?').get(req.session.userId);
|
|
52
|
+
if (!userRow) return res.status(401).json({ error: 'Unauthorized' });
|
|
53
|
+
|
|
54
|
+
console.log(`[Triggers] Notification received: ${app_package} - ${title} for user ${req.session.userId}`);
|
|
55
|
+
|
|
56
|
+
db.prepare(`
|
|
57
|
+
INSERT INTO notification_history (user_id, app_package, title, body, action_taken)
|
|
58
|
+
VALUES (?, ?, ?, ?, ?)
|
|
59
|
+
`).run(req.session.userId, app_package || 'unknown', title || '', body || '', action_taken || 'none');
|
|
60
|
+
|
|
61
|
+
// Respond immediately so the mobile client doesn't retry
|
|
62
|
+
res.json({ success: true, message: 'Notification trigger processed and stored' });
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error('[Triggers] Notification error:', getErrorMessage(err));
|
|
65
|
+
res.status(500).json({ error: 'Failed to process notification trigger' });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Fire-and-forget after response is sent — errors here must never touch res.
|
|
70
|
+
Promise.resolve().then(() => {
|
|
71
|
+
const agentEngine = req.app.locals.agentEngine;
|
|
72
|
+
if (!agentEngine) return;
|
|
73
|
+
const defaultAgentId = db.prepare('SELECT id FROM agents WHERE user_id = ? ORDER BY is_default DESC LIMIT 1').get(req.session.userId)?.id;
|
|
74
|
+
if (!defaultAgentId) return;
|
|
75
|
+
const prompt = [
|
|
76
|
+
`A notification arrived on your device.`,
|
|
77
|
+
`App: ${app_package || 'unknown'}`,
|
|
78
|
+
title ? `Title: ${title}` : '',
|
|
79
|
+
body ? `Body: ${body}` : '',
|
|
80
|
+
`Evaluate whether this notification requires action or a reply. If it is routine or low-priority, do nothing.`,
|
|
81
|
+
].filter(Boolean).join('\n');
|
|
82
|
+
return agentEngine.run(req.session.userId, prompt, {
|
|
83
|
+
agentId: defaultAgentId,
|
|
84
|
+
triggerSource: 'tasks',
|
|
85
|
+
context: { source: 'notification', app_package, title, body, action_taken },
|
|
86
|
+
});
|
|
87
|
+
}).catch(err => console.error('[Triggers] Notification agent run failed:', err.message));
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
module.exports = router;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const express = require('express');
|
|
4
|
+
const { requireAuth } = require('../middleware/auth');
|
|
5
|
+
const { sanitizeError } = require('../utils/security');
|
|
6
|
+
|
|
7
|
+
const router = express.Router();
|
|
8
|
+
|
|
9
|
+
function wearableService(req) {
|
|
10
|
+
return req.app?.locals?.wearableService || null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Intentionally public so an already-provisioned wearable can sync local time
|
|
14
|
+
// before the user finishes session-based pairing on the device.
|
|
15
|
+
router.get('/timezone', (req, res) => {
|
|
16
|
+
try {
|
|
17
|
+
const service = wearableService(req);
|
|
18
|
+
if (!service) {
|
|
19
|
+
return res.status(500).json({ error: 'Wearable service unavailable.' });
|
|
20
|
+
}
|
|
21
|
+
res.json(service.buildTimeConfig(req));
|
|
22
|
+
} catch (err) {
|
|
23
|
+
res.status(400).json({ error: sanitizeError(err) });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
router.use(requireAuth);
|
|
28
|
+
|
|
29
|
+
router.get('/bootstrap', async (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
const service = wearableService(req);
|
|
32
|
+
if (!service) {
|
|
33
|
+
return res.status(500).json({ error: 'Wearable service unavailable.' });
|
|
34
|
+
}
|
|
35
|
+
res.json(await service.buildBootstrap(req));
|
|
36
|
+
} catch (err) {
|
|
37
|
+
res.status(400).json({ error: sanitizeError(err) });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
router.get('/firmware/manifest', async (req, res) => {
|
|
42
|
+
try {
|
|
43
|
+
const service = wearableService(req);
|
|
44
|
+
if (!service) {
|
|
45
|
+
return res.status(500).json({ error: 'Wearable service unavailable.' });
|
|
46
|
+
}
|
|
47
|
+
res.json(await service.buildFirmwareManifest(req));
|
|
48
|
+
} catch (err) {
|
|
49
|
+
res.status(400).json({ error: sanitizeError(err) });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
router.get('/connections', (req, res) => {
|
|
54
|
+
try {
|
|
55
|
+
const service = wearableService(req);
|
|
56
|
+
if (!service) {
|
|
57
|
+
return res.status(500).json({ error: 'Wearable service unavailable.' });
|
|
58
|
+
}
|
|
59
|
+
res.json({
|
|
60
|
+
connections: service.listConnections(req.session.userId),
|
|
61
|
+
});
|
|
62
|
+
} catch (err) {
|
|
63
|
+
res.status(400).json({ error: sanitizeError(err) });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
module.exports = router;
|
package/server/routes/widgets.js
CHANGED
|
@@ -78,7 +78,7 @@ router.delete('/:id', (req, res) => {
|
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
router.post('/:id/refresh', (req, res) => {
|
|
81
|
+
router.post('/:id/refresh', async (req, res) => {
|
|
82
82
|
try {
|
|
83
83
|
const service = widgetService(req);
|
|
84
84
|
const taskRuntime = req.app?.locals?.taskRuntime;
|
|
@@ -89,10 +89,10 @@ router.post('/:id/refresh', (req, res) => {
|
|
|
89
89
|
if (!widget) {
|
|
90
90
|
return res.status(404).json({ error: 'Widget not found.' });
|
|
91
91
|
}
|
|
92
|
-
if (!widget.scheduledTaskId) {
|
|
93
|
-
return res.
|
|
92
|
+
if (widget.isSystem || !widget.scheduledTaskId) {
|
|
93
|
+
return res.json(await service.refreshWidget(req.session.userId, req.params.id));
|
|
94
94
|
}
|
|
95
|
-
res.json(taskRuntime.runTaskNow(widget.scheduledTaskId, req.session.userId));
|
|
95
|
+
res.json(await taskRuntime.runTaskNow(widget.scheduledTaskId, req.session.userId));
|
|
96
96
|
} catch (err) {
|
|
97
97
|
res.status(400).json({ error: sanitizeError(err) });
|
|
98
98
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const db = require('../../db/database');
|
|
2
2
|
const { getProviderHealthCatalog } = require('./models');
|
|
3
|
-
const { resolveBrowserExecutablePath } = require('../browser/controller');
|
|
4
|
-
const { deriveCloudBrowserBackend } = require('../runtime/settings');
|
|
5
3
|
|
|
6
4
|
function capabilityEntry(overrides = {}) {
|
|
7
5
|
return {
|
|
@@ -38,7 +36,6 @@ function summarizeCapabilityHealth(health) {
|
|
|
38
36
|
|
|
39
37
|
async function getBrowserHealth(userId, app, engine) {
|
|
40
38
|
const runtimeManager = app?.locals?.runtimeManager || engine?.runtimeManager || null;
|
|
41
|
-
const executablePath = resolveBrowserExecutablePath();
|
|
42
39
|
const runtimeSettings = typeof runtimeManager?.getSettings === 'function'
|
|
43
40
|
? runtimeManager.getSettings(userId)
|
|
44
41
|
: null;
|
|
@@ -78,26 +75,16 @@ async function getBrowserHealth(userId, app, engine) {
|
|
|
78
75
|
}
|
|
79
76
|
|
|
80
77
|
if (!controller) {
|
|
81
|
-
|
|
82
|
-
const resolver = app?.locals?.getBrowserControllerForUser;
|
|
83
|
-
controller = await Promise.resolve(
|
|
84
|
-
typeof resolver === 'function'
|
|
85
|
-
? resolver(userId)
|
|
86
|
-
: (app?.locals?.browserController || engine?.browserController || null)
|
|
87
|
-
);
|
|
88
|
-
} catch (err) {
|
|
89
|
-
resolutionError = resolutionError || err;
|
|
90
|
-
}
|
|
78
|
+
resolutionError = resolutionError || new Error('Browser provider is unavailable. VM runtime is required.');
|
|
91
79
|
}
|
|
92
80
|
|
|
93
81
|
if (!controller && resolutionError) {
|
|
94
82
|
return capabilityEntry({
|
|
95
|
-
configured:
|
|
83
|
+
configured: true,
|
|
96
84
|
healthy: false,
|
|
97
85
|
degraded: true,
|
|
98
86
|
summary: `Browser controller resolution failed: ${resolutionError.message}`,
|
|
99
87
|
details: {
|
|
100
|
-
executablePath: executablePath || null,
|
|
101
88
|
error: resolutionError.message,
|
|
102
89
|
},
|
|
103
90
|
});
|
|
@@ -117,23 +104,18 @@ async function getBrowserHealth(userId, app, engine) {
|
|
|
117
104
|
|
|
118
105
|
return capabilityEntry({
|
|
119
106
|
connected: launched,
|
|
120
|
-
configured:
|
|
121
|
-
healthy:
|
|
107
|
+
configured: true,
|
|
108
|
+
healthy: !error,
|
|
122
109
|
degraded: Boolean(error) || runtimeSettings?.browser_backend === 'extension',
|
|
123
110
|
summary: error
|
|
124
111
|
? `Browser runtime error: ${error}`
|
|
125
112
|
: runtimeSettings?.browser_backend === 'extension'
|
|
126
|
-
?
|
|
127
|
-
|
|
128
|
-
: 'No extension device is active and no browser executable was found for Puppeteer.'
|
|
129
|
-
: executablePath
|
|
130
|
-
? (launched ? 'Browser runtime is ready.' : 'Browser executable is available but not launched.')
|
|
131
|
-
: 'No browser executable was found for Puppeteer.',
|
|
113
|
+
? `No extension device is active. Falling back to the vm browser runtime.`
|
|
114
|
+
: (launched ? 'Browser runtime is ready.' : 'Browser runtime is available but not launched.'),
|
|
132
115
|
details: {
|
|
133
|
-
executablePath: executablePath || null,
|
|
134
116
|
preferredBackend: runtimeSettings?.browser_backend || null,
|
|
135
117
|
backend: runtimeSettings?.browser_backend === 'extension'
|
|
136
|
-
?
|
|
118
|
+
? 'vm'
|
|
137
119
|
: runtimeSettings?.browser_backend || null,
|
|
138
120
|
extensionConnected: extensionStatus?.connected === true,
|
|
139
121
|
activeTokenCount: Array.isArray(extensionStatus?.tokens)
|
|
@@ -159,17 +141,7 @@ async function getAndroidHealth(userId, app, engine) {
|
|
|
159
141
|
}
|
|
160
142
|
|
|
161
143
|
if (!controller) {
|
|
162
|
-
|
|
163
|
-
const resolver = app?.locals?.getAndroidControllerForUser;
|
|
164
|
-
controller = await Promise.resolve(
|
|
165
|
-
typeof resolver === 'function'
|
|
166
|
-
? resolver(userId)
|
|
167
|
-
: (app?.locals?.androidController || engine?.androidController || null)
|
|
168
|
-
);
|
|
169
|
-
} catch (err) {
|
|
170
|
-
resolutionError = resolutionError || err;
|
|
171
|
-
controller = null;
|
|
172
|
-
}
|
|
144
|
+
resolutionError = resolutionError || new Error('Android provider is unavailable. VM runtime is required.');
|
|
173
145
|
}
|
|
174
146
|
|
|
175
147
|
if (!controller || typeof controller.getStatus !== 'function') {
|
|
@@ -194,7 +166,7 @@ async function getAndroidHealth(userId, app, engine) {
|
|
|
194
166
|
summary: status.lastStartError
|
|
195
167
|
? `Android tooling reported: ${status.lastStartError}`
|
|
196
168
|
: bootstrapped
|
|
197
|
-
? 'Android environment is
|
|
169
|
+
? 'Android environment is ready on this host.'
|
|
198
170
|
: (canBootstrap ? 'Android environment can be bootstrapped on this host.' : 'Android tooling cannot bootstrap on this host.'),
|
|
199
171
|
details: status,
|
|
200
172
|
});
|
|
@@ -319,27 +291,27 @@ function getSkillHealth(app, engine) {
|
|
|
319
291
|
});
|
|
320
292
|
}
|
|
321
293
|
|
|
322
|
-
function getFileHealth() {
|
|
294
|
+
function getFileHealth(app, engine) {
|
|
295
|
+
const workspaceManager = app?.locals?.workspaceManager || engine?.workspaceManager || null;
|
|
323
296
|
return capabilityEntry({
|
|
324
|
-
connected:
|
|
325
|
-
configured:
|
|
326
|
-
healthy:
|
|
327
|
-
summary:
|
|
297
|
+
connected: Boolean(workspaceManager),
|
|
298
|
+
configured: Boolean(workspaceManager),
|
|
299
|
+
healthy: Boolean(workspaceManager),
|
|
300
|
+
summary: workspaceManager
|
|
301
|
+
? 'Per-user workspace access is available.'
|
|
302
|
+
: 'Per-user workspace service is not available.',
|
|
328
303
|
});
|
|
329
304
|
}
|
|
330
305
|
|
|
331
306
|
function getCommandHealth(userId, app, engine) {
|
|
332
307
|
const runtimeManager = app?.locals?.runtimeManager || engine?.runtimeManager || null;
|
|
333
|
-
const backend = runtimeManager?.getSettings?.(userId)?.runtime_backend || 'host';
|
|
334
308
|
return capabilityEntry({
|
|
335
|
-
connected: Boolean(runtimeManager
|
|
336
|
-
configured:
|
|
337
|
-
healthy: Boolean(runtimeManager
|
|
309
|
+
connected: Boolean(runtimeManager),
|
|
310
|
+
configured: Boolean(runtimeManager),
|
|
311
|
+
healthy: Boolean(runtimeManager),
|
|
338
312
|
summary: runtimeManager
|
|
339
|
-
?
|
|
340
|
-
:
|
|
341
|
-
? 'Shell command execution is available.'
|
|
342
|
-
: 'Shell executor is not available.',
|
|
313
|
+
? 'Shell command execution is available.'
|
|
314
|
+
: 'Shell command execution is not available in this environment.',
|
|
343
315
|
});
|
|
344
316
|
}
|
|
345
317
|
|
|
@@ -376,7 +348,7 @@ async function getCapabilityHealth({ userId, agentId = null, app, engine }) {
|
|
|
376
348
|
providers,
|
|
377
349
|
capabilities: {
|
|
378
350
|
command: getCommandHealth(userId, app, engine),
|
|
379
|
-
files: getFileHealth(),
|
|
351
|
+
files: getFileHealth(app, engine),
|
|
380
352
|
memory: getMemoryHealth(engine),
|
|
381
353
|
search: getSearchHealth(),
|
|
382
354
|
browser: await getBrowserHealth(userId, app, engine),
|
|
@@ -21,7 +21,7 @@ async function compact(messages, provider, model, contextWindow = null) {
|
|
|
21
21
|
}).join('\n');
|
|
22
22
|
|
|
23
23
|
const summaryPrompt = [
|
|
24
|
-
{ role: 'system', content: 'Compress conversation context. Preserve goals
|
|
24
|
+
{ role: 'system', content: 'Compress this conversation into a dense context block. Preserve: active goals and constraints, decisions made, promised actions (sent/created/changed/deleted), tool outcomes and errors, unresolved blockers, task configs, and concrete facts (names, IDs, dates, statuses, file paths). Omit greetings, filler, and tool-call narration. Write in past tense. Be specific — "email sent to alice@example.com at 3pm" beats "a message was sent".' },
|
|
25
25
|
{ role: 'user', content: `Summarize this conversation:\n\n${compactionText}` }
|
|
26
26
|
];
|
|
27
27
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { normalizeArtifactContract } = require('./contracts');
|
|
6
|
+
|
|
7
|
+
const FILE_EXTENSION_TO_KIND = {
|
|
8
|
+
'.ppt': 'slides',
|
|
9
|
+
'.pptx': 'slides',
|
|
10
|
+
'.key': 'slides',
|
|
11
|
+
'.pdf': 'document',
|
|
12
|
+
'.doc': 'document',
|
|
13
|
+
'.docx': 'document',
|
|
14
|
+
'.md': 'document',
|
|
15
|
+
'.txt': 'document',
|
|
16
|
+
'.html': 'document',
|
|
17
|
+
'.htm': 'document',
|
|
18
|
+
'.csv': 'data',
|
|
19
|
+
'.tsv': 'data',
|
|
20
|
+
'.xlsx': 'data',
|
|
21
|
+
'.xls': 'data',
|
|
22
|
+
'.json': 'data',
|
|
23
|
+
'.png': 'image',
|
|
24
|
+
'.jpg': 'image',
|
|
25
|
+
'.jpeg': 'image',
|
|
26
|
+
'.gif': 'image',
|
|
27
|
+
'.webp': 'image',
|
|
28
|
+
'.svg': 'image',
|
|
29
|
+
'.mp4': 'video',
|
|
30
|
+
'.mov': 'video',
|
|
31
|
+
'.m4v': 'video',
|
|
32
|
+
'.webm': 'video',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const FILE_EXTENSION_TO_MIME = {
|
|
36
|
+
'.ppt': 'application/vnd.ms-powerpoint',
|
|
37
|
+
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
38
|
+
'.pdf': 'application/pdf',
|
|
39
|
+
'.doc': 'application/msword',
|
|
40
|
+
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
41
|
+
'.md': 'text/markdown',
|
|
42
|
+
'.txt': 'text/plain',
|
|
43
|
+
'.html': 'text/html',
|
|
44
|
+
'.htm': 'text/html',
|
|
45
|
+
'.csv': 'text/csv',
|
|
46
|
+
'.tsv': 'text/tab-separated-values',
|
|
47
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
48
|
+
'.xls': 'application/vnd.ms-excel',
|
|
49
|
+
'.json': 'application/json',
|
|
50
|
+
'.png': 'image/png',
|
|
51
|
+
'.jpg': 'image/jpeg',
|
|
52
|
+
'.jpeg': 'image/jpeg',
|
|
53
|
+
'.gif': 'image/gif',
|
|
54
|
+
'.webp': 'image/webp',
|
|
55
|
+
'.svg': 'image/svg+xml',
|
|
56
|
+
'.mp4': 'video/mp4',
|
|
57
|
+
'.mov': 'video/quicktime',
|
|
58
|
+
'.m4v': 'video/x-m4v',
|
|
59
|
+
'.webm': 'video/webm',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const CANDIDATE_KEYS = [
|
|
63
|
+
'path',
|
|
64
|
+
'paths',
|
|
65
|
+
'file',
|
|
66
|
+
'files',
|
|
67
|
+
'filePath',
|
|
68
|
+
'filePaths',
|
|
69
|
+
'fullPath',
|
|
70
|
+
'fullPaths',
|
|
71
|
+
'mediaPath',
|
|
72
|
+
'mediaPaths',
|
|
73
|
+
'screenshotPath',
|
|
74
|
+
'uiDumpPath',
|
|
75
|
+
'url',
|
|
76
|
+
'urls',
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
function inferExtension(candidate = '') {
|
|
80
|
+
return path.extname(String(candidate || '').split('?')[0]).toLowerCase();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function inferArtifactKind(candidate = '', fallback = 'artifact') {
|
|
84
|
+
const extension = inferExtension(candidate);
|
|
85
|
+
if (FILE_EXTENSION_TO_KIND[extension]) return FILE_EXTENSION_TO_KIND[extension];
|
|
86
|
+
const normalized = String(candidate || '').toLowerCase();
|
|
87
|
+
if (normalized.includes('image')) return 'image';
|
|
88
|
+
if (normalized.includes('video')) return 'video';
|
|
89
|
+
if (normalized.includes('slide') || normalized.includes('ppt')) return 'slides';
|
|
90
|
+
if (normalized.includes('doc') || normalized.includes('pdf')) return 'document';
|
|
91
|
+
if (normalized.includes('data') || normalized.includes('chart') || normalized.includes('csv')) return 'data';
|
|
92
|
+
return fallback;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function inferMimeType(candidate = '') {
|
|
96
|
+
const extension = inferExtension(candidate);
|
|
97
|
+
return FILE_EXTENSION_TO_MIME[extension] || null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function normalizePathOrUri(value) {
|
|
101
|
+
const text = String(value || '').trim();
|
|
102
|
+
if (!text) return null;
|
|
103
|
+
if (text.startsWith('/api/artifacts/')) return { uri: text, path: null };
|
|
104
|
+
if (/^https?:\/\//i.test(text)) return { uri: text, path: null };
|
|
105
|
+
if (/^[A-Za-z]:\\/.test(text)) return { path: text, uri: null };
|
|
106
|
+
if (path.isAbsolute(text)) return { path: text, uri: null };
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function buildArtifactFromCandidate(candidate, fallbackKind = 'artifact') {
|
|
111
|
+
const normalized = normalizePathOrUri(candidate);
|
|
112
|
+
if (!normalized) return null;
|
|
113
|
+
const source = normalized.path || normalized.uri || '';
|
|
114
|
+
const artifact = normalizeArtifactContract({
|
|
115
|
+
kind: inferArtifactKind(source, fallbackKind),
|
|
116
|
+
path: normalized.path,
|
|
117
|
+
uri: normalized.uri,
|
|
118
|
+
label: path.basename(String(source).split('?')[0]) || null,
|
|
119
|
+
mimeType: inferMimeType(source),
|
|
120
|
+
});
|
|
121
|
+
if (artifact.path) {
|
|
122
|
+
try {
|
|
123
|
+
artifact.size = (await fs.promises.stat(artifact.path)).size;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.warn('[deliverables] Failed to stat artifact candidate:', artifact.path, error?.message || error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return artifact.path || artifact.uri ? artifact : null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function scanStringForCandidates(text) {
|
|
132
|
+
const input = String(text || '');
|
|
133
|
+
const matches = [];
|
|
134
|
+
const regexes = [
|
|
135
|
+
/\/api\/artifacts\/[A-Za-z0-9%_-]+\/content/g,
|
|
136
|
+
/\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
|
|
137
|
+
/[A-Za-z]:\\[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
|
|
138
|
+
/https?:\/\/[^\s"'`]+?\.(?:pptx?|pdf|docx?|md|txt|html?|csv|tsv|xlsx?|json|png|jpe?g|gif|webp|svg|mp4|mov|m4v|webm)\b/g,
|
|
139
|
+
];
|
|
140
|
+
for (const regex of regexes) {
|
|
141
|
+
const found = input.match(regex);
|
|
142
|
+
if (found) matches.push(...found);
|
|
143
|
+
}
|
|
144
|
+
return matches;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function extractArtifactsFromResult(toolName, result) {
|
|
148
|
+
const artifacts = [];
|
|
149
|
+
const seen = new Set();
|
|
150
|
+
const fallbackKind = inferArtifactKind(toolName, 'artifact');
|
|
151
|
+
|
|
152
|
+
async function pushCandidate(candidate) {
|
|
153
|
+
const artifact = await buildArtifactFromCandidate(candidate, fallbackKind);
|
|
154
|
+
if (!artifact) return;
|
|
155
|
+
const key = `${artifact.kind}:${artifact.path || artifact.uri}`;
|
|
156
|
+
if (seen.has(key)) return;
|
|
157
|
+
seen.add(key);
|
|
158
|
+
artifacts.push(artifact);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function visit(value, keyHint = '') {
|
|
162
|
+
if (value == null) return;
|
|
163
|
+
if (typeof value === 'string') {
|
|
164
|
+
if (CANDIDATE_KEYS.includes(keyHint)) await pushCandidate(value);
|
|
165
|
+
for (const candidate of scanStringForCandidates(value)) {
|
|
166
|
+
await pushCandidate(candidate);
|
|
167
|
+
}
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (Array.isArray(value)) {
|
|
171
|
+
for (const item of value) await visit(item, keyHint);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (typeof value === 'object') {
|
|
175
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
176
|
+
await visit(nested, key);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
await visit(result);
|
|
182
|
+
return artifacts;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = {
|
|
186
|
+
extractArtifactsFromResult,
|
|
187
|
+
inferArtifactKind,
|
|
188
|
+
inferMimeType,
|
|
189
|
+
normalizePathOrUri,
|
|
190
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DELIVERABLE_TYPES = [
|
|
4
|
+
'slides',
|
|
5
|
+
'document',
|
|
6
|
+
'research_report',
|
|
7
|
+
'data_analysis',
|
|
8
|
+
'image',
|
|
9
|
+
'video',
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const DELIVERABLE_SELECTION_STATUSES = ['selected', 'standard'];
|
|
13
|
+
const DELIVERABLE_VALIDATION_STATUSES = ['passed', 'failed'];
|
|
14
|
+
|
|
15
|
+
function clampText(value, maxLength = 240) {
|
|
16
|
+
return String(value || '').trim().slice(0, maxLength);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeDeliverableType(value) {
|
|
20
|
+
const normalized = clampText(value, 48).toLowerCase();
|
|
21
|
+
return DELIVERABLE_TYPES.includes(normalized) ? normalized : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizeStringList(value, limit = 8, maxLength = 120) {
|
|
25
|
+
if (!Array.isArray(value)) return [];
|
|
26
|
+
return value
|
|
27
|
+
.map((item) => clampText(item, maxLength))
|
|
28
|
+
.filter(Boolean)
|
|
29
|
+
.slice(0, limit);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function normalizeArtifactContract(raw = {}) {
|
|
33
|
+
const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
34
|
+
return {
|
|
35
|
+
kind: clampText(source.kind, 48) || 'artifact',
|
|
36
|
+
path: clampText(source.path || source.fullPath, 500) || null,
|
|
37
|
+
uri: clampText(source.uri || source.url, 500) || null,
|
|
38
|
+
label: clampText(source.label, 120) || null,
|
|
39
|
+
mimeType: clampText(source.mimeType || source.contentType, 120) || null,
|
|
40
|
+
size: Number.isFinite(Number(source.size ?? source.byteSize))
|
|
41
|
+
? Number(source.size ?? source.byteSize)
|
|
42
|
+
: null,
|
|
43
|
+
preview: source.preview && typeof source.preview === 'object' && !Array.isArray(source.preview)
|
|
44
|
+
? { ...source.preview }
|
|
45
|
+
: {},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function normalizeDeliverableSelection(raw = {}) {
|
|
50
|
+
const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
51
|
+
const type = normalizeDeliverableType(source.type);
|
|
52
|
+
const confidence = Math.max(0, Math.min(1, Number(source.confidence) || 0));
|
|
53
|
+
const status = DELIVERABLE_SELECTION_STATUSES.includes(String(source.status || '').trim().toLowerCase())
|
|
54
|
+
? String(source.status).trim().toLowerCase()
|
|
55
|
+
: (type ? 'selected' : 'standard');
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
status,
|
|
59
|
+
type,
|
|
60
|
+
confidence,
|
|
61
|
+
goal: clampText(source.goal, 240),
|
|
62
|
+
requestedOutputs: normalizeStringList(source.requested_outputs || source.requestedOutputs, 8, 120),
|
|
63
|
+
supportingCapabilities: normalizeStringList(source.supporting_capabilities || source.supportingCapabilities, 8, 64),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeDeliverableValidationResult(raw = {}) {
|
|
68
|
+
const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
69
|
+
const status = DELIVERABLE_VALIDATION_STATUSES.includes(String(source.status || '').trim().toLowerCase())
|
|
70
|
+
? String(source.status).trim().toLowerCase()
|
|
71
|
+
: 'failed';
|
|
72
|
+
const artifacts = Array.isArray(source.artifacts)
|
|
73
|
+
? source.artifacts.map(normalizeArtifactContract).filter((artifact) => artifact.path || artifact.uri)
|
|
74
|
+
: [];
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
status,
|
|
78
|
+
summary: clampText(source.summary, 320),
|
|
79
|
+
errors: normalizeStringList(source.errors, 8, 220),
|
|
80
|
+
warnings: normalizeStringList(source.warnings, 8, 220),
|
|
81
|
+
artifacts,
|
|
82
|
+
metrics: source.metrics && typeof source.metrics === 'object' && !Array.isArray(source.metrics)
|
|
83
|
+
? { ...source.metrics }
|
|
84
|
+
: {},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function normalizeDeliverableResult(raw = {}) {
|
|
89
|
+
const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
90
|
+
return {
|
|
91
|
+
type: normalizeDeliverableType(source.type),
|
|
92
|
+
status: clampText(source.status, 32) || 'unknown',
|
|
93
|
+
summary: clampText(source.summary, 320),
|
|
94
|
+
artifacts: Array.isArray(source.artifacts)
|
|
95
|
+
? source.artifacts.map(normalizeArtifactContract).filter((artifact) => artifact.path || artifact.uri)
|
|
96
|
+
: [],
|
|
97
|
+
validation: normalizeDeliverableValidationResult(source.validation),
|
|
98
|
+
metadata: source.metadata && typeof source.metadata === 'object' && !Array.isArray(source.metadata)
|
|
99
|
+
? { ...source.metadata }
|
|
100
|
+
: {},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
DELIVERABLE_TYPES,
|
|
106
|
+
clampText,
|
|
107
|
+
normalizeArtifactContract,
|
|
108
|
+
normalizeDeliverableResult,
|
|
109
|
+
normalizeDeliverableSelection,
|
|
110
|
+
normalizeDeliverableType,
|
|
111
|
+
normalizeDeliverableValidationResult,
|
|
112
|
+
normalizeStringList,
|
|
113
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { selectDeliverableWorkflow } = require('./selector');
|
|
4
|
+
const {
|
|
5
|
+
buildDeliverableWorkflowGuidance,
|
|
6
|
+
getDeliverableWorkflow,
|
|
7
|
+
listDeliverableWorkflows,
|
|
8
|
+
} = require('./workflows');
|
|
9
|
+
const { extractArtifactsFromResult } = require('./artifact_helpers');
|
|
10
|
+
const { DeliverableValidationError, validateDeliverableExecution } = require('./validator');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
buildDeliverableWorkflowGuidance,
|
|
14
|
+
DeliverableValidationError,
|
|
15
|
+
extractArtifactsFromResult,
|
|
16
|
+
getDeliverableWorkflow,
|
|
17
|
+
listDeliverableWorkflows,
|
|
18
|
+
selectDeliverableWorkflow,
|
|
19
|
+
validateDeliverableExecution,
|
|
20
|
+
};
|