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.
Files changed (406) hide show
  1. package/.env.example +63 -5
  2. package/README.md +16 -5
  3. package/com.neoagent.plist +1 -1
  4. package/docs/automation.md +82 -41
  5. package/docs/capabilities.md +85 -89
  6. package/docs/configuration.md +89 -87
  7. package/docs/getting-started.md +46 -27
  8. package/docs/hardware.md +1 -1
  9. package/docs/index.md +24 -30
  10. package/docs/integrations.md +46 -60
  11. package/docs/migration.md +41 -146
  12. package/docs/operations.md +23 -20
  13. package/docs/skills.md +20 -20
  14. package/docs/why-neoagent.md +15 -13
  15. package/extensions/chrome-browser/background.mjs +10 -2
  16. package/flutter_app/.metadata +42 -0
  17. package/flutter_app/DESIGN_SYSTEM.md +166 -0
  18. package/flutter_app/README.md +21 -0
  19. package/flutter_app/analysis_options.yaml +32 -0
  20. package/flutter_app/android/app/build.gradle.kts +111 -0
  21. package/flutter_app/android/app/src/debug/AndroidManifest.xml +7 -0
  22. package/flutter_app/android/app/src/main/AndroidManifest.xml +185 -0
  23. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +888 -0
  24. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/auto/NeoAgentCarAppService.kt +114 -0
  25. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthConnectGateway.kt +280 -0
  26. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncNotifications.kt +113 -0
  27. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncPayload.kt +57 -0
  28. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncScheduler.kt +78 -0
  29. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/HealthSyncWorker.kt +253 -0
  30. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/health/PermissionsRationaleActivity.kt +46 -0
  31. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +21 -0
  32. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +586 -0
  33. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +78 -0
  34. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +104 -0
  35. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnection.kt +118 -0
  36. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/telecom/NeoAgentConnectionService.kt +86 -0
  37. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiHomeWidgetProvider.kt +457 -0
  38. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/AiWidgetStore.kt +194 -0
  39. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/VoiceLaunchWidgetProvider.kt +67 -0
  40. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetConfigActivity.kt +228 -0
  41. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncScheduler.kt +72 -0
  42. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetSyncWorker.kt +186 -0
  43. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/widgets/WidgetTaskRunWorker.kt +210 -0
  44. package/flutter_app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  45. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_bg.xml +11 -0
  46. package/flutter_app/android/app/src/main/res/drawable/neoagent_ai_widget_task_bg.xml +8 -0
  47. package/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  48. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget.xml +138 -0
  49. package/flutter_app/android/app/src/main/res/layout/neoagent_ai_widget_task_row.xml +52 -0
  50. package/flutter_app/android/app/src/main/res/layout/neoagent_voice_widget.xml +49 -0
  51. package/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  52. package/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  53. package/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  54. package/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  55. package/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  56. package/flutter_app/android/app/src/main/res/values/arrays.xml +8 -0
  57. package/flutter_app/android/app/src/main/res/values/strings.xml +12 -0
  58. package/flutter_app/android/app/src/main/res/values/styles.xml +18 -0
  59. package/flutter_app/android/app/src/main/res/values-night/styles.xml +18 -0
  60. package/flutter_app/android/app/src/main/res/xml/automotive_app_desc.xml +4 -0
  61. package/flutter_app/android/app/src/main/res/xml/file_paths.xml +6 -0
  62. package/flutter_app/android/app/src/main/res/xml/neoagent_ai_widget_info.xml +12 -0
  63. package/flutter_app/android/app/src/main/res/xml/neoagent_voice_widget_info.xml +12 -0
  64. package/flutter_app/android/app/src/profile/AndroidManifest.xml +7 -0
  65. package/flutter_app/android/build.gradle.kts +24 -0
  66. package/flutter_app/android/ci-release.keystore +0 -0
  67. package/flutter_app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  68. package/flutter_app/android/gradle.properties +3 -0
  69. package/flutter_app/android/key.properties +4 -0
  70. package/flutter_app/android/settings.gradle.kts +26 -0
  71. package/flutter_app/assets/branding/app_icon_1024.png +0 -0
  72. package/flutter_app/assets/branding/app_icon_128.png +0 -0
  73. package/flutter_app/assets/branding/app_icon_192.png +0 -0
  74. package/flutter_app/assets/branding/app_icon_256.png +0 -0
  75. package/flutter_app/assets/branding/app_icon_32.png +0 -0
  76. package/flutter_app/assets/branding/app_icon_512.png +0 -0
  77. package/flutter_app/assets/branding/app_icon_64.png +0 -0
  78. package/flutter_app/assets/branding/onboarding_intro.mp4 +0 -0
  79. package/flutter_app/assets/branding/tray_icon_template.png +0 -0
  80. package/flutter_app/lib/features/location/location_service.dart +117 -0
  81. package/flutter_app/lib/features/notifications/notification_interceptor.dart +73 -0
  82. package/flutter_app/lib/features/onboarding/onboarding_chrome.dart +571 -0
  83. package/flutter_app/lib/features/onboarding/onboarding_messaging_step.dart +275 -0
  84. package/flutter_app/lib/features/onboarding/onboarding_model_step.dart +366 -0
  85. package/flutter_app/lib/features/onboarding/onboarding_shell.dart +57 -0
  86. package/flutter_app/lib/features/onboarding/onboarding_video_step.dart +218 -0
  87. package/flutter_app/lib/features/onboarding/onboarding_welcome_step.dart +46 -0
  88. package/flutter_app/lib/main.dart +107 -0
  89. package/flutter_app/lib/main_account_settings.dart +1340 -0
  90. package/flutter_app/lib/main_admin.dart +900 -0
  91. package/flutter_app/lib/main_app_shell.dart +2162 -0
  92. package/flutter_app/lib/main_chat.dart +3902 -0
  93. package/flutter_app/lib/main_controller.dart +7229 -0
  94. package/flutter_app/lib/main_devices.dart +1738 -0
  95. package/flutter_app/lib/main_integrations.dart +917 -0
  96. package/flutter_app/lib/main_launcher.dart +959 -0
  97. package/flutter_app/lib/main_launcher_entry.dart +5 -0
  98. package/flutter_app/lib/main_models.dart +3807 -0
  99. package/flutter_app/lib/main_navigation.dart +206 -0
  100. package/flutter_app/lib/main_operations.dart +5249 -0
  101. package/flutter_app/lib/main_recordings.dart +920 -0
  102. package/flutter_app/lib/main_runtime.dart +869 -0
  103. package/flutter_app/lib/main_settings.dart +2288 -0
  104. package/flutter_app/lib/main_shared.dart +3393 -0
  105. package/flutter_app/lib/main_spacing.dart +33 -0
  106. package/flutter_app/lib/main_theme.dart +276 -0
  107. package/flutter_app/lib/main_unified.dart +388 -0
  108. package/flutter_app/lib/main_voice_assistant.dart +957 -0
  109. package/flutter_app/lib/src/analytics_service.dart +294 -0
  110. package/flutter_app/lib/src/android_apk_drop_zone.dart +32 -0
  111. package/flutter_app/lib/src/android_apk_drop_zone_stub.dart +16 -0
  112. package/flutter_app/lib/src/android_apk_drop_zone_web.dart +348 -0
  113. package/flutter_app/lib/src/android_app_installer.dart +22 -0
  114. package/flutter_app/lib/src/android_app_installer_io.dart +122 -0
  115. package/flutter_app/lib/src/android_app_installer_stub.dart +21 -0
  116. package/flutter_app/lib/src/android_auto_bridge.dart +59 -0
  117. package/flutter_app/lib/src/android_launcher_bridge.dart +239 -0
  118. package/flutter_app/lib/src/app_launch_bridge.dart +58 -0
  119. package/flutter_app/lib/src/app_release_updater.dart +511 -0
  120. package/flutter_app/lib/src/backend_client.dart +1870 -0
  121. package/flutter_app/lib/src/desktop_companion.dart +2 -0
  122. package/flutter_app/lib/src/desktop_companion_actions.dart +586 -0
  123. package/flutter_app/lib/src/desktop_companion_io.dart +538 -0
  124. package/flutter_app/lib/src/desktop_companion_stub.dart +59 -0
  125. package/flutter_app/lib/src/desktop_native_bridge.dart +91 -0
  126. package/flutter_app/lib/src/desktop_screen_capture.dart +21 -0
  127. package/flutter_app/lib/src/desktop_screen_capture_io.dart +142 -0
  128. package/flutter_app/lib/src/desktop_screen_capture_stub.dart +12 -0
  129. package/flutter_app/lib/src/diagnostics_logger.dart +119 -0
  130. package/flutter_app/lib/src/health_bridge.dart +136 -0
  131. package/flutter_app/lib/src/live_voice_capture.dart +85 -0
  132. package/flutter_app/lib/src/messaging_access_summary.dart +46 -0
  133. package/flutter_app/lib/src/network/app_http_client.dart +53 -0
  134. package/flutter_app/lib/src/network/app_http_client_factory.dart +6 -0
  135. package/flutter_app/lib/src/network/app_http_client_io.dart +138 -0
  136. package/flutter_app/lib/src/network/app_http_client_stub.dart +3 -0
  137. package/flutter_app/lib/src/network/app_http_client_web.dart +94 -0
  138. package/flutter_app/lib/src/oauth_launcher.dart +33 -0
  139. package/flutter_app/lib/src/oauth_launcher_io.dart +95 -0
  140. package/flutter_app/lib/src/oauth_launcher_stub.dart +33 -0
  141. package/flutter_app/lib/src/oauth_launcher_web.dart +107 -0
  142. package/flutter_app/lib/src/recording_bridge.dart +232 -0
  143. package/flutter_app/lib/src/recording_bridge_io.dart +1019 -0
  144. package/flutter_app/lib/src/recording_bridge_stub.dart +120 -0
  145. package/flutter_app/lib/src/recording_bridge_web.dart +689 -0
  146. package/flutter_app/lib/src/recording_payloads.dart +86 -0
  147. package/flutter_app/lib/src/theme/palette.dart +81 -0
  148. package/flutter_app/lib/src/web_app_update_monitor.dart +17 -0
  149. package/flutter_app/lib/src/web_app_update_monitor_stub.dart +24 -0
  150. package/flutter_app/lib/src/web_app_update_monitor_web.dart +123 -0
  151. package/flutter_app/lib/src/widget_bridge.dart +49 -0
  152. package/flutter_app/linux/CMakeLists.txt +128 -0
  153. package/flutter_app/linux/flutter/CMakeLists.txt +88 -0
  154. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +47 -0
  155. package/flutter_app/linux/flutter/generated_plugin_registrant.h +15 -0
  156. package/flutter_app/linux/flutter/generated_plugins.cmake +32 -0
  157. package/flutter_app/linux/runner/CMakeLists.txt +26 -0
  158. package/flutter_app/linux/runner/main.cc +6 -0
  159. package/flutter_app/linux/runner/my_application.cc +144 -0
  160. package/flutter_app/linux/runner/my_application.h +18 -0
  161. package/flutter_app/linux/runner/resources/app_icon.png +0 -0
  162. package/flutter_app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  163. package/flutter_app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  164. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +48 -0
  165. package/flutter_app/macos/Podfile +42 -0
  166. package/flutter_app/macos/Podfile.lock +87 -0
  167. package/flutter_app/macos/Runner/AppDelegate.swift +576 -0
  168. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  169. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  170. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  171. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  172. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  173. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  174. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  175. package/flutter_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  176. package/flutter_app/macos/Runner/Base.lproj/MainMenu.xib +342 -0
  177. package/flutter_app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  178. package/flutter_app/macos/Runner/Configs/Debug.xcconfig +2 -0
  179. package/flutter_app/macos/Runner/Configs/Release.xcconfig +2 -0
  180. package/flutter_app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  181. package/flutter_app/macos/Runner/DebugProfile.entitlements +16 -0
  182. package/flutter_app/macos/Runner/Info.plist +36 -0
  183. package/flutter_app/macos/Runner/MainFlutterWindow.swift +19 -0
  184. package/flutter_app/macos/Runner/Release.entitlements +12 -0
  185. package/flutter_app/macos/Runner.xcodeproj/project.pbxproj +801 -0
  186. package/flutter_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  187. package/flutter_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +99 -0
  188. package/flutter_app/macos/Runner.xcworkspace/contents.xcworkspacedata +10 -0
  189. package/flutter_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  190. package/flutter_app/macos/RunnerTests/RunnerTests.swift +12 -0
  191. package/flutter_app/patch_strings.py +12 -0
  192. package/flutter_app/pubspec.lock +1256 -0
  193. package/flutter_app/pubspec.yaml +59 -0
  194. package/flutter_app/third_party/desktop_audio_capture/LICENSE +21 -0
  195. package/flutter_app/third_party/desktop_audio_capture/README.md +262 -0
  196. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +65 -0
  197. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +153 -0
  198. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +110 -0
  199. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +461 -0
  200. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +91 -0
  201. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +106 -0
  202. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +219 -0
  203. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +336 -0
  204. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +101 -0
  205. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +692 -0
  206. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +35 -0
  207. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +36 -0
  208. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +32 -0
  209. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +32 -0
  210. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +878 -0
  211. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +27 -0
  212. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +1172 -0
  213. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +655 -0
  214. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +12 -0
  215. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +30 -0
  216. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +87 -0
  217. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +105 -0
  218. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +80 -0
  219. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +31 -0
  220. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +12 -0
  221. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +23 -0
  222. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +25 -0
  223. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +1117 -0
  224. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +115 -0
  225. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +777 -0
  226. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +87 -0
  227. package/flutter_app/third_party/flutter_secure_storage_linux/linux/CMakeLists.txt +30 -0
  228. package/flutter_app/third_party/flutter_secure_storage_linux/linux/flutter_secure_storage_linux_plugin.cc +215 -0
  229. package/flutter_app/third_party/flutter_secure_storage_linux/linux/include/flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h +27 -0
  230. package/flutter_app/third_party/flutter_secure_storage_linux/pubspec.yaml +20 -0
  231. package/flutter_app/tool/generate_desktop_branding.py +219 -0
  232. package/flutter_app/web/favicon.png +0 -0
  233. package/flutter_app/web/favicon.svg +12 -0
  234. package/flutter_app/web/icons/Icon-192.png +0 -0
  235. package/flutter_app/web/icons/Icon-512.png +0 -0
  236. package/flutter_app/web/icons/Icon-maskable-192.png +0 -0
  237. package/flutter_app/web/icons/Icon-maskable-512.png +0 -0
  238. package/flutter_app/web/index.html +39 -0
  239. package/flutter_app/web/manifest.json +35 -0
  240. package/flutter_app/windows/CMakeLists.txt +108 -0
  241. package/flutter_app/windows/flutter/CMakeLists.txt +109 -0
  242. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +50 -0
  243. package/flutter_app/windows/flutter/generated_plugin_registrant.h +15 -0
  244. package/flutter_app/windows/flutter/generated_plugins.cmake +36 -0
  245. package/flutter_app/windows/runner/CMakeLists.txt +41 -0
  246. package/flutter_app/windows/runner/Runner.rc +121 -0
  247. package/flutter_app/windows/runner/flutter_window.cpp +533 -0
  248. package/flutter_app/windows/runner/flutter_window.h +37 -0
  249. package/flutter_app/windows/runner/main.cpp +53 -0
  250. package/flutter_app/windows/runner/resource.h +16 -0
  251. package/flutter_app/windows/runner/resources/app_icon.ico +0 -0
  252. package/flutter_app/windows/runner/runner.exe.manifest +14 -0
  253. package/flutter_app/windows/runner/utils.cpp +65 -0
  254. package/flutter_app/windows/runner/utils.h +19 -0
  255. package/flutter_app/windows/runner/win32_window.cpp +299 -0
  256. package/flutter_app/windows/runner/win32_window.h +102 -0
  257. package/lib/install_helpers.js +31 -0
  258. package/lib/manager.js +465 -43
  259. package/package.json +11 -3
  260. package/runtime/paths.js +137 -0
  261. package/server/config/analytics.js +30 -0
  262. package/server/db/database.js +363 -21
  263. package/server/guest-agent.android.package.json +13 -0
  264. package/server/guest-agent.browser.package.json +14 -0
  265. package/server/guest_agent.js +98 -52
  266. package/server/http/middleware.js +55 -2
  267. package/server/http/routes.js +6 -1
  268. package/server/http/static.js +41 -1
  269. package/server/index.js +16 -16
  270. package/server/public/.last_build_id +1 -1
  271. package/server/public/assets/AssetManifest.bin +1 -1
  272. package/server/public/assets/AssetManifest.bin.json +1 -1
  273. package/server/public/assets/AssetManifest.json +1 -1
  274. package/server/public/assets/NOTICES +679 -129
  275. package/server/public/assets/assets/branding/onboarding_intro.mp4 +0 -0
  276. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  277. package/server/public/assets/packages/mixpanel_flutter/assets/mixpanel.js +3 -0
  278. package/server/public/canvaskit/wimp.wasm +0 -0
  279. package/server/public/flutter_bootstrap.js +2 -2
  280. package/server/public/main.dart.js +95866 -87333
  281. package/server/routes/account.js +26 -1
  282. package/server/routes/agents.js +6 -2
  283. package/server/routes/android.js +22 -6
  284. package/server/routes/auth.js +25 -5
  285. package/server/routes/browser.js +47 -13
  286. package/server/routes/integrations.js +119 -9
  287. package/server/routes/memory.js +179 -8
  288. package/server/routes/runtime.js +14 -0
  289. package/server/routes/screenHistory.js +46 -0
  290. package/server/routes/settings.js +102 -24
  291. package/server/routes/skills.js +12 -0
  292. package/server/routes/social_video.js +66 -0
  293. package/server/routes/tasks.js +22 -2
  294. package/server/routes/triggers.js +90 -0
  295. package/server/routes/wearable.js +67 -0
  296. package/server/routes/widgets.js +4 -4
  297. package/server/services/ai/capabilityHealth.js +23 -51
  298. package/server/services/ai/compaction.js +1 -1
  299. package/server/services/ai/deliverables/artifact_helpers.js +190 -0
  300. package/server/services/ai/deliverables/contracts.js +113 -0
  301. package/server/services/ai/deliverables/index.js +20 -0
  302. package/server/services/ai/deliverables/selector.js +94 -0
  303. package/server/services/ai/deliverables/validator.js +63 -0
  304. package/server/services/ai/deliverables/workflows.js +207 -0
  305. package/server/services/ai/engine.js +372 -27
  306. package/server/services/ai/hooks.js +127 -0
  307. package/server/services/ai/integrated_tools/index.js +98 -0
  308. package/server/services/ai/integrated_tools/remotion.js +373 -0
  309. package/server/services/ai/integrated_tools/shared.js +204 -0
  310. package/server/services/ai/integrated_tools/slidev.js +207 -0
  311. package/server/services/ai/loopPolicy.js +146 -0
  312. package/server/services/ai/models.js +36 -0
  313. package/server/services/ai/providers/githubCopilot.js +97 -0
  314. package/server/services/ai/providers/openai.js +2 -1
  315. package/server/services/ai/providers/openaiCodex.js +384 -0
  316. package/server/services/ai/recordingInsights.js +11 -13
  317. package/server/services/ai/runEvents.js +100 -0
  318. package/server/services/ai/settings.js +20 -0
  319. package/server/services/ai/systemPrompt.js +16 -2
  320. package/server/services/ai/taskAnalysis.js +2 -0
  321. package/server/services/ai/toolResult.js +20 -0
  322. package/server/services/ai/toolRunner.js +46 -6
  323. package/server/services/ai/toolSelector.js +54 -1
  324. package/server/services/ai/tools.js +360 -127
  325. package/server/services/android/android_bootstrap_worker.js +63 -0
  326. package/server/services/android/controller.js +442 -1760
  327. package/server/services/bootstrap_helpers.js +0 -34
  328. package/server/services/browser/controller.js +326 -52
  329. package/server/services/cli/executor.js +40 -1
  330. package/server/services/desktop/screenRecorder.js +182 -0
  331. package/server/services/integrations/env.js +10 -0
  332. package/server/services/integrations/figma/provider.js +1 -0
  333. package/server/services/integrations/github/common.js +106 -0
  334. package/server/services/integrations/github/provider.js +499 -0
  335. package/server/services/integrations/github/repos.js +1124 -0
  336. package/server/services/integrations/google/provider.js +1 -0
  337. package/server/services/integrations/manager.js +88 -12
  338. package/server/services/integrations/microsoft/provider.js +1 -0
  339. package/server/services/integrations/oauth_provider.js +25 -8
  340. package/server/services/integrations/provider_config_store.js +85 -0
  341. package/server/services/integrations/registry.js +8 -2
  342. package/server/services/integrations/spotify/provider.js +488 -0
  343. package/server/services/integrations/trello/provider.js +842 -0
  344. package/server/services/integrations/weather/provider.js +559 -0
  345. package/server/services/integrations/whatsapp/provider.js +6 -2
  346. package/server/services/manager.js +109 -154
  347. package/server/services/mcp/client.js +120 -23
  348. package/server/services/memory/llm_transfer.js +218 -0
  349. package/server/services/memory/manager.js +299 -35
  350. package/server/services/messaging/access_policy.js +10 -0
  351. package/server/services/messaging/automation.js +1 -1
  352. package/server/services/messaging/manager.js +93 -8
  353. package/server/services/messaging/meshtastic.js +277 -0
  354. package/server/services/messaging/meshtastic_env.js +40 -0
  355. package/server/services/messaging/meshtastic_protocol.js +530 -0
  356. package/server/services/messaging/meshtastic_tcp_transport.js +25 -0
  357. package/server/services/runtime/backends/local-vm.js +221 -158
  358. package/server/services/runtime/docker-vm-manager.js +392 -0
  359. package/server/services/runtime/guest_bootstrap.js +654 -0
  360. package/server/services/runtime/manager.js +85 -29
  361. package/server/services/runtime/settings.js +22 -31
  362. package/server/services/runtime/validation.js +16 -31
  363. package/server/services/skills/base_catalog.js +33 -0
  364. package/server/services/social_video/adapters/base.js +26 -0
  365. package/server/services/social_video/adapters/index.js +27 -0
  366. package/server/services/social_video/adapters/instagram.js +17 -0
  367. package/server/services/social_video/adapters/tiktok.js +17 -0
  368. package/server/services/social_video/adapters/x.js +17 -0
  369. package/server/services/social_video/adapters/youtube.js +17 -0
  370. package/server/services/social_video/captions.js +187 -0
  371. package/server/services/social_video/frame.js +42 -0
  372. package/server/services/social_video/index.js +7 -0
  373. package/server/services/social_video/metadata.js +63 -0
  374. package/server/services/social_video/result.js +63 -0
  375. package/server/services/social_video/service.js +720 -0
  376. package/server/services/social_video/url.js +83 -0
  377. package/server/services/tasks/adapters/index.js +2 -0
  378. package/server/services/tasks/adapters/manual.js +12 -0
  379. package/server/services/tasks/adapters/schedule.js +33 -5
  380. package/server/services/tasks/adapters/weather_event.js +84 -0
  381. package/server/services/tasks/integration_runtime.js +86 -1
  382. package/server/services/tasks/runtime.js +3 -3
  383. package/server/services/tasks/task_repository.js +3 -6
  384. package/server/services/voice/agentBridge.js +20 -4
  385. package/server/services/voice/message.js +3 -0
  386. package/server/services/voice/openaiClient.js +4 -1
  387. package/server/services/voice/openaiSpeech.js +6 -1
  388. package/server/services/voice/providers.js +144 -15
  389. package/server/services/voice/runtime.js +8 -8
  390. package/server/services/voice/runtimeManager.js +292 -20
  391. package/server/services/voice/turnRunner.js +29 -9
  392. package/server/services/wearable/firmware_manifest.js +353 -0
  393. package/server/services/wearable/gateway.js +350 -0
  394. package/server/services/wearable/protocol.js +45 -0
  395. package/server/services/wearable/service.js +240 -0
  396. package/server/services/websocket.js +3 -1
  397. package/server/services/widgets/focus_widget.js +137 -0
  398. package/server/services/widgets/service.js +182 -6
  399. package/server/services/workspace/manager.js +301 -0
  400. package/server/utils/deployment.js +16 -9
  401. package/server/utils/local_secrets.js +56 -0
  402. package/server/utils/logger.js +37 -9
  403. package/server/services/integrations/home_assistant/provider.js +0 -350
  404. package/server/services/messaging/access_policy.test.js +0 -228
  405. package/server/services/runtime/backends/host.js +0 -37
  406. package/server/services/runtime/qemu.js +0 -391
@@ -0,0 +1,204 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const crypto = require('crypto');
6
+ const { APP_DIR } = require('../../../../runtime/paths');
7
+
8
+ function ensureDir(dirPath) {
9
+ fs.mkdirSync(dirPath, { recursive: true });
10
+ return dirPath;
11
+ }
12
+
13
+ function ensureRepoNodeModulesLink(targetDir) {
14
+ ensureDir(targetDir);
15
+ const sourceNodeModules = path.join(APP_DIR, 'node_modules');
16
+ const targetNodeModules = path.join(targetDir, 'node_modules');
17
+ if (fs.existsSync(targetNodeModules)) {
18
+ return targetNodeModules;
19
+ }
20
+ fs.symlinkSync(sourceNodeModules, targetNodeModules, 'junction');
21
+ return targetNodeModules;
22
+ }
23
+
24
+ function shellEscape(value) {
25
+ const text = String(value ?? '');
26
+ if (!text.length) return "''";
27
+ return `'${text.replace(/'/g, `'\\''`)}'`;
28
+ }
29
+
30
+ function normalizeFilenameBase(value, fallback = 'artifact') {
31
+ const normalized = String(value || '')
32
+ .trim()
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9_-]+/g, '-')
35
+ .replace(/^-+|-+$/g, '');
36
+ return normalized || fallback;
37
+ }
38
+
39
+ function resolveRepoBinary(...segments) {
40
+ const parts = [...segments];
41
+ if (process.platform === 'win32' && parts.length > 0 && !parts[parts.length - 1].endsWith('.cmd')) {
42
+ parts[parts.length - 1] = `${parts[parts.length - 1]}.cmd`;
43
+ }
44
+ return path.join(APP_DIR, 'node_modules', '.bin', ...parts);
45
+ }
46
+
47
+ function assertExistingFile(filePath, label = 'file') {
48
+ const absolutePath = path.resolve(String(filePath || ''));
49
+ if (!fs.existsSync(absolutePath)) {
50
+ throw new Error(`${label} does not exist: ${absolutePath}`);
51
+ }
52
+ const stat = fs.statSync(absolutePath);
53
+ if (!stat.isFile()) {
54
+ throw new Error(`${label} is not a file: ${absolutePath}`);
55
+ }
56
+ return absolutePath;
57
+ }
58
+
59
+ function writeTextFile(filePath, content) {
60
+ ensureDir(path.dirname(filePath));
61
+ fs.writeFileSync(filePath, String(content || ''), 'utf8');
62
+ return filePath;
63
+ }
64
+
65
+ function writeJsonFile(filePath, payload) {
66
+ writeTextFile(filePath, `${JSON.stringify(payload, null, 2)}\n`);
67
+ return filePath;
68
+ }
69
+
70
+ function copyAssetIntoJob(sourcePath, targetDir, preferredName = 'asset', workspaceManager = null, userId = null) {
71
+ if (!workspaceManager || userId == null) {
72
+ throw new Error('Workspace manager is required for integrated tool assets.');
73
+ }
74
+ const absolutePath = workspaceManager.resolvePath(userId, sourcePath, 'asset');
75
+ ensureDir(targetDir);
76
+ const extension = path.extname(absolutePath).toLowerCase();
77
+ const basename = normalizeFilenameBase(path.basename(absolutePath, extension), preferredName);
78
+ const filename = `${basename}-${crypto.randomBytes(3).toString('hex')}${extension}`;
79
+ const targetPath = path.join(targetDir, filename);
80
+ fs.copyFileSync(absolutePath, targetPath);
81
+ return {
82
+ sourcePath: absolutePath,
83
+ targetPath,
84
+ relativePath: filename,
85
+ };
86
+ }
87
+
88
+ async function runCheckedCommand(executor, command, options = {}) {
89
+ if (!executor || typeof executor.execute !== 'function') {
90
+ throw new Error('CLI executor is unavailable for integrated tools.');
91
+ }
92
+ const result = await executor.execute(command, {
93
+ cwd: options.cwd,
94
+ timeout: options.timeout,
95
+ env: options.env,
96
+ });
97
+ if (result.exitCode !== 0) {
98
+ const stderr = String(result.stderr || '').trim();
99
+ const stdout = String(result.stdout || '').trim();
100
+ const details = stderr || stdout || `Command failed: ${command}`;
101
+ throw new Error(
102
+ options.errorPrefix
103
+ ? `${options.errorPrefix} ${details}`.trim()
104
+ : details
105
+ );
106
+ }
107
+ return result;
108
+ }
109
+
110
+ async function createJobDir(toolName, filenameBase, workspaceManager = null, userId = null) {
111
+ const prefix = normalizeFilenameBase(toolName, 'tool');
112
+ const suffix = normalizeFilenameBase(filenameBase, 'output');
113
+ const jobId = `${Date.now()}-${crypto.randomBytes(4).toString('hex')}-${suffix}`;
114
+ if (workspaceManager && userId != null) {
115
+ const toolingRoot = await workspaceManager.getToolingRoot(userId, prefix);
116
+ return ensureDir(path.join(toolingRoot, jobId));
117
+ }
118
+ throw new Error('Workspace manager is required for integrated tool jobs.');
119
+ }
120
+
121
+ function inferArtifactExtension(filePath) {
122
+ return path.extname(String(filePath || '')).toLowerCase().replace(/^\./, '') || 'bin';
123
+ }
124
+
125
+ function inferContentType(filePath) {
126
+ const extension = path.extname(String(filePath || '')).toLowerCase();
127
+ switch (extension) {
128
+ case '.pdf': return 'application/pdf';
129
+ case '.ppt': return 'application/vnd.ms-powerpoint';
130
+ case '.pptx': return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
131
+ case '.md': return 'text/markdown';
132
+ case '.png': return 'image/png';
133
+ case '.jpg':
134
+ case '.jpeg': return 'image/jpeg';
135
+ case '.svg': return 'image/svg+xml';
136
+ case '.mp4': return 'video/mp4';
137
+ case '.mov': return 'video/quicktime';
138
+ case '.webm': return 'video/webm';
139
+ default: return 'application/octet-stream';
140
+ }
141
+ }
142
+
143
+ function inferArtifactKind(filePath) {
144
+ const extension = path.extname(String(filePath || '')).toLowerCase();
145
+ if (['.ppt', '.pptx'].includes(extension)) return 'slides';
146
+ if (['.pdf', '.md'].includes(extension)) return 'document';
147
+ if (['.png', '.jpg', '.jpeg', '.svg'].includes(extension)) return 'image';
148
+ if (['.mp4', '.mov', '.webm'].includes(extension)) return 'video';
149
+ return 'artifact';
150
+ }
151
+
152
+ function createArtifactDescriptor(filePath, options = {}) {
153
+ const absolutePath = assertExistingFile(filePath, 'output');
154
+ const stat = fs.statSync(absolutePath);
155
+ return {
156
+ kind: options.kind || inferArtifactKind(absolutePath),
157
+ label: options.label || path.basename(absolutePath),
158
+ path: absolutePath,
159
+ mimeType: options.mimeType || inferContentType(absolutePath),
160
+ size: stat.size,
161
+ };
162
+ }
163
+
164
+ function promoteArtifactDescriptor(descriptor, artifactStore, userId) {
165
+ if (!artifactStore || userId == null || !descriptor?.path) {
166
+ return descriptor;
167
+ }
168
+ const extension = inferArtifactExtension(descriptor.path);
169
+ const allocation = artifactStore.allocateFile(userId, {
170
+ kind: descriptor.kind || inferArtifactKind(descriptor.path),
171
+ extension,
172
+ contentType: descriptor.mimeType || inferContentType(descriptor.path),
173
+ filenameBase: normalizeFilenameBase(descriptor.label || descriptor.kind || 'artifact', 'artifact'),
174
+ originalFilename: path.basename(descriptor.path),
175
+ metadata: {
176
+ sourceTool: 'integrated-media',
177
+ originalPath: descriptor.path,
178
+ },
179
+ });
180
+ fs.copyFileSync(descriptor.path, allocation.storagePath);
181
+ const finalized = artifactStore.finalizeFile(allocation.artifactId, allocation.storagePath);
182
+ return {
183
+ kind: descriptor.kind || inferArtifactKind(descriptor.path),
184
+ label: descriptor.label || path.basename(descriptor.path),
185
+ url: finalized.url,
186
+ mimeType: descriptor.mimeType || inferContentType(descriptor.path),
187
+ size: finalized.byteSize,
188
+ };
189
+ }
190
+
191
+ module.exports = {
192
+ copyAssetIntoJob,
193
+ createArtifactDescriptor,
194
+ createJobDir,
195
+ ensureDir,
196
+ ensureRepoNodeModulesLink,
197
+ normalizeFilenameBase,
198
+ promoteArtifactDescriptor,
199
+ resolveRepoBinary,
200
+ runCheckedCommand,
201
+ shellEscape,
202
+ writeJsonFile,
203
+ writeTextFile,
204
+ };
@@ -0,0 +1,207 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const {
6
+ copyAssetIntoJob,
7
+ createArtifactDescriptor,
8
+ createJobDir,
9
+ ensureDir,
10
+ ensureRepoNodeModulesLink,
11
+ normalizeFilenameBase,
12
+ promoteArtifactDescriptor,
13
+ resolveRepoBinary,
14
+ runCheckedCommand,
15
+ shellEscape,
16
+ writeTextFile,
17
+ } = require('./shared');
18
+
19
+ const SLIDEV_BIN = resolveRepoBinary('slidev');
20
+ const DEFAULT_EXPORT_FORMATS = ['pdf'];
21
+ const ALLOWED_EXPORT_FORMATS = new Set(['pdf', 'pptx', 'png']);
22
+ const ALLOWED_LAYOUTS = new Set(['cover', 'intro', 'statement', 'quote', 'section', 'two-cols', 'default']);
23
+
24
+ function normalizeArray(value) {
25
+ return Array.isArray(value) ? value : [];
26
+ }
27
+
28
+ function normalizeExportFormats(value) {
29
+ const formats = normalizeArray(value)
30
+ .map((item) => String(item || '').trim().toLowerCase())
31
+ .filter((item) => ALLOWED_EXPORT_FORMATS.has(item));
32
+ return formats.length > 0 ? [...new Set(formats)] : [...DEFAULT_EXPORT_FORMATS];
33
+ }
34
+
35
+ function buildFrontmatter(args = {}) {
36
+ const lines = [
37
+ '---',
38
+ `theme: ${String(args.theme || 'default').trim() || 'default'}`,
39
+ ];
40
+ if (args.title) lines.push(`title: ${JSON.stringify(String(args.title).trim())}`);
41
+ if (args.subtitle) lines.push(`info: ${JSON.stringify(String(args.subtitle).trim())}`);
42
+ lines.push('layout: cover');
43
+ lines.push('transition: fade-out');
44
+ lines.push('mdc: true');
45
+ lines.push('---');
46
+ return lines.join('\n');
47
+ }
48
+
49
+ function materializeSlideAsset(value, assetsDir, workspaceManager, userId) {
50
+ if (!value) return '';
51
+ const text = String(value).trim();
52
+ if (!text) return '';
53
+ if (/^https?:\/\//i.test(text)) {
54
+ return text;
55
+ }
56
+ const asset = copyAssetIntoJob(text, assetsDir, 'slide-asset', workspaceManager, userId);
57
+ return `./assets/${asset.relativePath}`;
58
+ }
59
+
60
+ function buildStructuredDeckMarkdown(args, jobDir, workspaceManager, userId) {
61
+ const slides = normalizeArray(args.slides);
62
+ if (slides.length === 0) {
63
+ throw new Error('generate_slide_deck requires a non-empty slides array or deck_markdown.');
64
+ }
65
+ const assetsDir = ensureDir(path.join(jobDir, 'assets'));
66
+ const sections = [buildFrontmatter(args)];
67
+ const coverTitle = String(args.title || 'Presentation').trim();
68
+ const coverSubtitle = String(args.subtitle || '').trim();
69
+ sections.push(`# ${coverTitle}${coverSubtitle ? `\n\n${coverSubtitle}` : ''}`);
70
+
71
+ for (const slide of slides) {
72
+ const title = String(slide?.title || '').trim();
73
+ const layout = ALLOWED_LAYOUTS.has(String(slide?.layout || '').trim()) ? String(slide.layout).trim() : 'default';
74
+ const body = String(slide?.body || '').trim();
75
+ const notes = String(slide?.notes || '').trim();
76
+ const bullets = normalizeArray(slide?.bullets)
77
+ .map((item) => String(item || '').trim())
78
+ .filter(Boolean);
79
+ const imageRef = materializeSlideAsset(slide?.image_path || slide?.image_url, assetsDir, workspaceManager, userId);
80
+ const slideLines = ['---'];
81
+ if (layout !== 'default') slideLines.push(`layout: ${layout}`);
82
+ if (slide?.className) slideLines.push(`class: ${JSON.stringify(String(slide.className).trim())}`);
83
+ slideLines.push('---');
84
+ if (title) slideLines.push(`# ${title}`);
85
+ if (body) slideLines.push('', body);
86
+ if (bullets.length > 0) {
87
+ if (!body) slideLines.push('');
88
+ slideLines.push(...bullets.map((item) => `- ${item}`));
89
+ }
90
+ if (imageRef) {
91
+ slideLines.push('', `![](${imageRef})`);
92
+ }
93
+ if (notes) {
94
+ slideLines.push('', `<!--\n${notes}\n-->`);
95
+ }
96
+ sections.push(slideLines.join('\n'));
97
+ }
98
+
99
+ return `${sections.join('\n\n')}\n`;
100
+ }
101
+
102
+ function buildDeckMarkdown(args, jobDir, workspaceManager, userId) {
103
+ const rawMarkdown = String(args.deck_markdown || '').trim();
104
+ if (rawMarkdown) {
105
+ if (rawMarkdown.startsWith('---')) {
106
+ return `${rawMarkdown}\n`;
107
+ }
108
+ return `${buildFrontmatter(args)}\n\n${rawMarkdown}\n`;
109
+ }
110
+ return buildStructuredDeckMarkdown(args, jobDir, workspaceManager, userId);
111
+ }
112
+
113
+ function resolveExportPath(jobDir, filenameBase, format) {
114
+ if (format === 'png') {
115
+ return path.join(jobDir, `${filenameBase}-png`);
116
+ }
117
+ return path.join(jobDir, `${filenameBase}.${format}`);
118
+ }
119
+
120
+ function collectPngArtifacts(outputDir) {
121
+ if (!fs.existsSync(outputDir)) return [];
122
+ return fs.readdirSync(outputDir)
123
+ .filter((entry) => entry.toLowerCase().endsWith('.png'))
124
+ .sort()
125
+ .map((entry) => createArtifactDescriptor(path.join(outputDir, entry), {
126
+ kind: 'image',
127
+ label: entry,
128
+ mimeType: 'image/png',
129
+ }));
130
+ }
131
+
132
+ async function generateSlideDeck(args, context = {}) {
133
+ if (!fs.existsSync(SLIDEV_BIN)) {
134
+ throw new Error('Slidev CLI is not installed.');
135
+ }
136
+ const filenameBase = normalizeFilenameBase(args.filename_base || args.title || 'slide-deck', 'slide-deck');
137
+ const workspaceManager = context.workspaceManager;
138
+ const userId = context.userId;
139
+ const jobDir = await createJobDir('slidev', filenameBase, workspaceManager, userId);
140
+ ensureRepoNodeModulesLink(jobDir);
141
+ const markdownPath = path.join(jobDir, `${filenameBase}.md`);
142
+ const exportFormats = normalizeExportFormats(args.export_formats);
143
+ const deckMarkdown = buildDeckMarkdown(args, jobDir, workspaceManager, userId);
144
+ writeTextFile(markdownPath, deckMarkdown);
145
+
146
+ const executor = context.cliExecutor;
147
+ const commandOutputs = [];
148
+ for (const format of exportFormats) {
149
+ const outputPath = resolveExportPath(jobDir, filenameBase, format);
150
+ const command = [
151
+ shellEscape(SLIDEV_BIN),
152
+ 'export',
153
+ shellEscape(markdownPath),
154
+ '--format',
155
+ shellEscape(format),
156
+ '--output',
157
+ shellEscape(outputPath),
158
+ ].join(' ');
159
+ const result = await runCheckedCommand(executor, command, {
160
+ cwd: jobDir,
161
+ timeout: 15 * 60 * 1000,
162
+ errorPrefix: `Slidev export failed for ${format}.`,
163
+ });
164
+ commandOutputs.push({ format, result });
165
+ }
166
+
167
+ const descriptors = [
168
+ createArtifactDescriptor(markdownPath, {
169
+ kind: 'document',
170
+ label: path.basename(markdownPath),
171
+ mimeType: 'text/markdown',
172
+ }),
173
+ ];
174
+
175
+ for (const format of exportFormats) {
176
+ const outputPath = resolveExportPath(jobDir, filenameBase, format);
177
+ if (format === 'png') {
178
+ descriptors.push(...collectPngArtifacts(outputPath));
179
+ continue;
180
+ }
181
+ descriptors.push(createArtifactDescriptor(outputPath, {
182
+ kind: format === 'pptx' ? 'slides' : 'document',
183
+ label: path.basename(outputPath),
184
+ }));
185
+ }
186
+
187
+ const promotedArtifacts = descriptors.map((descriptor) => (
188
+ promoteArtifactDescriptor(descriptor, context.artifactStore, context.userId)
189
+ ));
190
+
191
+ return {
192
+ success: true,
193
+ tool: 'generate_slide_deck',
194
+ title: String(args.title || '').trim() || null,
195
+ exportFormats,
196
+ artifacts: promotedArtifacts,
197
+ message: `Generated slide deck with ${exportFormats.join(', ')} output.`,
198
+ logs: commandOutputs.map((item) => ({
199
+ format: item.format,
200
+ durationMs: item.result.durationMs,
201
+ })),
202
+ };
203
+ }
204
+
205
+ module.exports = {
206
+ generateSlideDeck,
207
+ };
@@ -0,0 +1,146 @@
1
+ /**
2
+ * loopPolicy.js
3
+ *
4
+ * Single source of truth for every tunable limit in the agent loop.
5
+ * No magic numbers live in engine.js — everything flows from here.
6
+ *
7
+ * Values resolve in priority order:
8
+ * 1. Per-run option override (options.*)
9
+ * 2. Agent AI settings (aiSettings.*)
10
+ * 3. Hardcoded sane default
11
+ *
12
+ * "Open but stable": limits exist as safety nets, not as the primary
13
+ * exit signal. The AI signals completion via task_complete; these
14
+ * numbers only fire when something goes wrong.
15
+ */
16
+
17
+ const DEFAULT_MAX_ITERATIONS = 20;
18
+ const DEFAULT_WIDGET_MAX_ITERATIONS = 30;
19
+ const DEFAULT_PLAN_EXECUTE_MAX_ITERATIONS = 40;
20
+ const DEFAULT_COMPACTION_THRESHOLD = 0.82;
21
+ const DEFAULT_MAX_CONSECUTIVE_TOOL_FAILURES = 5;
22
+ const DEFAULT_MAX_MODEL_FAILURE_RECOVERIES = 3;
23
+
24
+ // Hard ceilings — protect against runaway config values
25
+ const MAX_ALLOWED_ITERATIONS = 200;
26
+ const MAX_ALLOWED_TOOL_FAILURES = 50;
27
+ const MAX_ALLOWED_MODEL_RECOVERIES = 10;
28
+ const MAX_ALLOWED_BUDGET_CHARS = 500_000;
29
+
30
+ /** Return n if finite and positive, otherwise fallback. */
31
+ function finitePositive(n, fallback) {
32
+ return Number.isFinite(n) && n > 0 ? n : fallback;
33
+ }
34
+
35
+ /** Clamp n to [lo, hi]; return fallback if not finite. */
36
+ function clampFinite(n, lo, hi, fallback) {
37
+ if (!Number.isFinite(n)) return fallback;
38
+ return Math.min(Math.max(n, lo), hi);
39
+ }
40
+
41
+ /**
42
+ * @param {object} aiSettings - from getAiSettings()
43
+ * @param {string} triggerType - 'chat' | 'schedule' | 'subagent' | etc.
44
+ * @param {string} analysisMode - 'direct_answer' | 'execute' | 'plan_execute'
45
+ * @param {object} options - per-run options (may override anything)
46
+ * @returns {LoopPolicy}
47
+ */
48
+ function buildLoopPolicy(aiSettings = {}, triggerType = 'chat', analysisMode = 'execute', options = {}) {
49
+ // ── maxIterations ────────────────────────────────────────────────────────
50
+ // Resolve raw value from options → aiSettings → mode/context defaults,
51
+ // then clamp to [1, MAX_ALLOWED_ITERATIONS] and floor to integer.
52
+ let rawIterations;
53
+ if (options.maxIterations != null) {
54
+ rawIterations = Number(options.maxIterations);
55
+ } else if (aiSettings.max_iterations != null) {
56
+ rawIterations = Number(aiSettings.max_iterations);
57
+ } else if (options.widgetId) {
58
+ rawIterations = DEFAULT_WIDGET_MAX_ITERATIONS;
59
+ } else if (analysisMode === 'plan_execute') {
60
+ rawIterations = DEFAULT_PLAN_EXECUTE_MAX_ITERATIONS;
61
+ } else {
62
+ rawIterations = DEFAULT_MAX_ITERATIONS;
63
+ }
64
+ const maxIterations = clampFinite(
65
+ Math.floor(rawIterations),
66
+ 1,
67
+ MAX_ALLOWED_ITERATIONS,
68
+ DEFAULT_MAX_ITERATIONS,
69
+ );
70
+
71
+ // ── Tool result size budget ───────────────────────────────────────────────
72
+ // Must be a finite positive integer; bad values fall back to 2400.
73
+ const defaultBudget = clampFinite(
74
+ Math.floor(Number(aiSettings.tool_replay_budget_chars) || 0),
75
+ 500,
76
+ MAX_ALLOWED_BUDGET_CHARS,
77
+ 2400,
78
+ );
79
+
80
+ // ── Scalar policy fields ─────────────────────────────────────────────────
81
+ const maxConsecutiveToolFailures = clampFinite(
82
+ Math.floor(Number(aiSettings.max_consecutive_tool_failures)),
83
+ 1,
84
+ MAX_ALLOWED_TOOL_FAILURES,
85
+ DEFAULT_MAX_CONSECUTIVE_TOOL_FAILURES,
86
+ );
87
+
88
+ const maxModelFailureRecoveries = clampFinite(
89
+ Math.floor(Number(aiSettings.max_model_failure_recoveries)),
90
+ 0,
91
+ MAX_ALLOWED_MODEL_RECOVERIES,
92
+ DEFAULT_MAX_MODEL_FAILURE_RECOVERIES,
93
+ );
94
+
95
+ // compactionThreshold must be in (0, 1]; clamp to [0.1, 1].
96
+ const compactionThreshold = clampFinite(
97
+ Number(aiSettings.compaction_threshold),
98
+ 0.1,
99
+ 1,
100
+ DEFAULT_COMPACTION_THRESHOLD,
101
+ );
102
+
103
+ return {
104
+ maxIterations,
105
+ maxConsecutiveToolFailures,
106
+ maxModelFailureRecoveries,
107
+
108
+ // Fill ratio at which context compaction triggers (0–1)
109
+ compactionThreshold,
110
+
111
+ // Per-category tool result size budgets (chars)
112
+ toolResultBudget: {
113
+ default: defaultBudget,
114
+ file: clampFinite(Math.floor(Number(aiSettings.tool_replay_budget_file_chars)), 500, MAX_ALLOWED_BUDGET_CHARS, Math.max(defaultBudget, 6000)),
115
+ browser: clampFinite(Math.floor(Number(aiSettings.tool_replay_budget_browser_chars)), 500, MAX_ALLOWED_BUDGET_CHARS, Math.max(defaultBudget, 4000)),
116
+ command: clampFinite(Math.floor(Number(aiSettings.tool_replay_budget_command_chars)), 500, MAX_ALLOWED_BUDGET_CHARS, Math.max(defaultBudget, 4000)),
117
+ },
118
+
119
+ // Hard ceiling is always 2× soft, capped at a reasonable absolute max
120
+ hardLimitMultiplier: 2,
121
+ absoluteHardLimit: 12000,
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Map a tool name to its result-size category.
127
+ */
128
+ function getToolCategory(toolName) {
129
+ if (!toolName) return 'default';
130
+ if (/^(read_file|write_file|search_files|list_directory|file_)/.test(toolName)) return 'file';
131
+ if (/^browser_/.test(toolName)) return 'browser';
132
+ if (/^(execute_command|android_shell|android_)/.test(toolName)) return 'command';
133
+ return 'default';
134
+ }
135
+
136
+ /**
137
+ * Resolve soft + hard limits for a specific tool from the policy.
138
+ */
139
+ function resolveToolResultLimits(toolName, policy) {
140
+ const category = getToolCategory(toolName);
141
+ const soft = policy.toolResultBudget[category] ?? policy.toolResultBudget.default;
142
+ const hard = Math.min(soft * policy.hardLimitMultiplier, policy.absoluteHardLimit);
143
+ return { softLimit: soft, hardLimit: hard };
144
+ }
145
+
146
+ module.exports = { buildLoopPolicy, getToolCategory, resolveToolResultLimits };
@@ -3,6 +3,8 @@ const { GoogleProvider } = require('./providers/google');
3
3
  const { GrokProvider } = require('./providers/grok');
4
4
  const { OllamaProvider } = require('./providers/ollama');
5
5
  const { OpenAIProvider } = require('./providers/openai');
6
+ const { GithubCopilotProvider } = require('./providers/githubCopilot');
7
+ const { OpenAICodexProvider } = require('./providers/openaiCodex');
6
8
  const {
7
9
  AI_PROVIDER_DEFINITIONS,
8
10
  getProviderConfigs,
@@ -16,6 +18,36 @@ const STATIC_MODELS = [
16
18
  provider: 'grok',
17
19
  purpose: 'general'
18
20
  },
21
+ {
22
+ id: 'gpt-5.3',
23
+ label: 'GPT-5.3 (Copilot Default)',
24
+ provider: 'github-copilot',
25
+ purpose: 'general'
26
+ },
27
+ {
28
+ id: 'gpt-4.1',
29
+ label: 'GPT-4.1 (Copilot Fast)',
30
+ provider: 'github-copilot',
31
+ purpose: 'coding'
32
+ },
33
+ {
34
+ id: 'gpt-5.5',
35
+ label: 'GPT-5.5 (Codex Default)',
36
+ provider: 'openai-codex',
37
+ purpose: 'general'
38
+ },
39
+ {
40
+ id: 'gpt-5.4-mini',
41
+ label: 'GPT-5.4 mini (Codex Fast)',
42
+ provider: 'openai-codex',
43
+ purpose: 'coding'
44
+ },
45
+ {
46
+ id: 'gpt-5.4',
47
+ label: 'GPT-5.4 (Codex Fallback)',
48
+ provider: 'openai-codex',
49
+ purpose: 'general'
50
+ },
19
51
  {
20
52
  id: 'gpt-5-nano',
21
53
  label: 'GPT-5 Nano (Fast / Subagents)',
@@ -302,6 +334,10 @@ function createProviderInstance(providerStr, userId = null, configOverrides = {}
302
334
  return new AnthropicProvider({ apiKey: runtime.apiKey, baseUrl: runtime.baseUrl, ...providerOverrides });
303
335
  } else if (providerStr === 'ollama') {
304
336
  return new OllamaProvider({ baseUrl: runtime.baseUrl, ...providerOverrides });
337
+ } else if (providerStr === 'github-copilot') {
338
+ return new GithubCopilotProvider({ apiKey: runtime.apiKey, ...providerOverrides });
339
+ } else if (providerStr === 'openai-codex') {
340
+ return new OpenAICodexProvider({ apiKey: runtime.apiKey, ...providerOverrides });
305
341
  }
306
342
  throw new Error(`Unknown provider: ${providerStr}`);
307
343
  }