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,97 @@
1
+ const { OpenAIProvider } = require('./openai');
2
+
3
+ class GithubCopilotProvider extends OpenAIProvider {
4
+ constructor(config = {}) {
5
+ // GitHub Copilot base URL defaults to the individual endpoint
6
+ const defaultBaseUrl = 'https://api.individual.githubcopilot.com';
7
+ const baseUrl = config.baseUrl || process.env.GITHUB_COPILOT_BASE_URL || defaultBaseUrl;
8
+
9
+ super({
10
+ ...config,
11
+ apiKey: config.apiKey || process.env.GITHUB_COPILOT_ACCESS_TOKEN,
12
+ baseUrl,
13
+ // Pass special headers required by GitHub Copilot
14
+ defaultHeaders: {
15
+ 'Editor-Version': 'vscode/1.90.0',
16
+ 'Editor-Plugin-Version': 'copilot-chat/0.15.0',
17
+ 'User-Agent': 'GithubCopilot/1.155.0',
18
+ 'X-Github-Api-Version': '2023-07-07',
19
+ 'Copilot-Integration-Id': 'vscode-chat'
20
+ }
21
+ });
22
+ this.name = 'github-copilot';
23
+ this.githubToken = config.apiKey || process.env.GITHUB_COPILOT_ACCESS_TOKEN;
24
+ this.copilotToken = null;
25
+ this.tokenExpiresAt = 0;
26
+ this._refreshPromise = null;
27
+ }
28
+
29
+ async _refreshCopilotToken() {
30
+ if (this._refreshPromise) return this._refreshPromise;
31
+
32
+ const now = Math.floor(Date.now() / 1000);
33
+ // Refresh token if missing or expiring in less than 5 minutes
34
+ if (this.copilotToken && this.tokenExpiresAt >= now + 300) {
35
+ return;
36
+ }
37
+
38
+ this._refreshPromise = (async () => {
39
+ try {
40
+ if (!this.githubToken) {
41
+ throw new Error('GitHub Copilot access token is missing. Please run `neoagent login github-copilot`.');
42
+ }
43
+
44
+ const res = await fetch('https://api.github.com/copilot_internal/v2/token', {
45
+ headers: {
46
+ 'Authorization': `token ${this.githubToken}`,
47
+ 'Accept': 'application/json',
48
+ 'User-Agent': 'NeoAgent/1.0.0'
49
+ }
50
+ });
51
+
52
+ if (!res.ok) {
53
+ const errorText = await res.text().catch(() => 'Unknown error');
54
+ throw new Error(`Failed to refresh GitHub Copilot token: HTTP ${res.status} - ${errorText}`);
55
+ }
56
+
57
+ const data = await res.json();
58
+ if (!data || typeof data.token !== 'string' || !data.token) {
59
+ throw new Error('Invalid token response from GitHub Copilot.');
60
+ }
61
+
62
+ this.copilotToken = data.token;
63
+ this.tokenExpiresAt = typeof data.expires_at === 'number'
64
+ ? data.expires_at
65
+ : Math.floor(new Date(data.expires_at).getTime() / 1000);
66
+
67
+ if (isNaN(this.tokenExpiresAt)) {
68
+ this.tokenExpiresAt = Math.floor(Date.now() / 1000) + 1800;
69
+ }
70
+
71
+ // Update the client's API key
72
+ this.client.apiKey = this.copilotToken;
73
+ } finally {
74
+ this._refreshPromise = null;
75
+ }
76
+ })();
77
+
78
+ return this._refreshPromise;
79
+ }
80
+
81
+ async chat(messages, tools = [], options = {}) {
82
+ await this._refreshCopilotToken();
83
+ return super.chat(messages, tools, options);
84
+ }
85
+
86
+ async *stream(messages, tools = [], options = {}) {
87
+ await this._refreshCopilotToken();
88
+ yield* super.stream(messages, tools, options);
89
+ }
90
+
91
+ async analyzeImage(options = {}) {
92
+ await this._refreshCopilotToken();
93
+ return super.analyzeImage(options);
94
+ }
95
+ }
96
+
97
+ module.exports = { GithubCopilotProvider };
@@ -29,7 +29,8 @@ class OpenAIProvider extends BaseProvider {
29
29
  };
30
30
  this.client = new OpenAI({
31
31
  apiKey: config.apiKey || process.env.OPENAI_API_KEY,
32
- baseURL: config.baseUrl || process.env.OPENAI_BASE_URL || undefined
32
+ baseURL: config.baseUrl || process.env.OPENAI_BASE_URL || undefined,
33
+ defaultHeaders: config.defaultHeaders || undefined
33
34
  });
34
35
  }
35
36
 
@@ -0,0 +1,384 @@
1
+ const OpenAI = require('openai');
2
+ const { BaseProvider } = require('./base');
3
+
4
+ const DEFAULT_BASE_URL = 'https://chatgpt.com/backend-api/codex';
5
+
6
+ function isCodexBackendBaseUrl(baseURL) {
7
+ const trimmed = String(baseURL || '').trim();
8
+ if (!trimmed) return false;
9
+
10
+ try {
11
+ const url = new URL(trimmed);
12
+ const path = url.pathname.replace(/\/+$/, '');
13
+ return url.hostname === 'chatgpt.com'
14
+ && (path === '/backend-api' || path === '/backend-api/codex' || path === '/backend-api/codex/v1');
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ function isOpenAIApiBaseUrl(baseURL) {
21
+ const trimmed = String(baseURL || '').trim();
22
+ if (!trimmed) return false;
23
+
24
+ try {
25
+ const url = new URL(trimmed);
26
+ const path = url.pathname.replace(/\/+$/, '');
27
+ return url.hostname === 'api.openai.com' && (path === '' || path === '/v1');
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ function normalizeCodexBaseUrl(baseURL) {
34
+ if (!baseURL || isOpenAIApiBaseUrl(baseURL) || isCodexBackendBaseUrl(baseURL)) {
35
+ return DEFAULT_BASE_URL;
36
+ }
37
+ return baseURL;
38
+ }
39
+
40
+ function normalizeContent(content) {
41
+ if (content == null) return '';
42
+ if (typeof content === 'string') return content;
43
+ if (Array.isArray(content)) {
44
+ return content.map((part) => {
45
+ if (!part) return '';
46
+ if (typeof part === 'string') return part;
47
+ if (part.type === 'text' && typeof part.text === 'string') return part.text;
48
+ if (part.type === 'input_text' && typeof part.text === 'string') return part.text;
49
+ return '';
50
+ }).join('');
51
+ }
52
+ return String(content);
53
+ }
54
+
55
+ function normalizeInputContent(content) {
56
+ if (content == null) return [];
57
+
58
+ if (typeof content === 'string') {
59
+ return [{ type: 'input_text', text: content }];
60
+ }
61
+
62
+ if (!Array.isArray(content)) {
63
+ const text = String(content);
64
+ return text ? [{ type: 'input_text', text }] : [];
65
+ }
66
+
67
+ const parts = [];
68
+ for (const part of content) {
69
+ if (!part) continue;
70
+ if (typeof part === 'string') {
71
+ if (part.trim()) parts.push({ type: 'input_text', text: part });
72
+ continue;
73
+ }
74
+ if (part.type === 'text' && typeof part.text === 'string') {
75
+ parts.push({ type: 'input_text', text: part.text });
76
+ continue;
77
+ }
78
+ if (part.type === 'input_text' && typeof part.text === 'string') {
79
+ parts.push({ type: 'input_text', text: part.text });
80
+ continue;
81
+ }
82
+ if (part.type === 'image_url') {
83
+ const imageUrl = typeof part.image_url === 'string' ? part.image_url : part.image_url?.url;
84
+ if (imageUrl) {
85
+ parts.push({
86
+ type: 'input_image',
87
+ image_url: imageUrl,
88
+ detail: part.detail || 'auto',
89
+ });
90
+ }
91
+ continue;
92
+ }
93
+ if (part.type === 'input_image') {
94
+ parts.push({
95
+ type: 'input_image',
96
+ image_url: part.image_url || null,
97
+ file_id: part.file_id || null,
98
+ detail: part.detail || 'auto',
99
+ });
100
+ }
101
+ }
102
+
103
+ return parts;
104
+ }
105
+
106
+ function toFunctionCallOutput(toolCallId, content) {
107
+ return {
108
+ type: 'function_call_output',
109
+ call_id: toolCallId,
110
+ output: normalizeContent(content),
111
+ };
112
+ }
113
+
114
+ function extractResponseText(response) {
115
+ if (typeof response?.output_text === 'string' && response.output_text.length > 0) {
116
+ return response.output_text;
117
+ }
118
+
119
+ const parts = [];
120
+ for (const item of response?.output || []) {
121
+ if (item?.type !== 'message') continue;
122
+ for (const content of item.content || []) {
123
+ if (content?.type === 'output_text' && typeof content.text === 'string') {
124
+ parts.push(content.text);
125
+ }
126
+ }
127
+ }
128
+ return parts.join('');
129
+ }
130
+
131
+ function extractToolCalls(response) {
132
+ const toolCalls = [];
133
+ for (const item of response?.output || []) {
134
+ if (item?.type !== 'function_call') continue;
135
+ toolCalls.push({
136
+ id: item.call_id || item.id || '',
137
+ type: 'function',
138
+ function: {
139
+ name: item.name || '',
140
+ arguments: item.arguments || '',
141
+ },
142
+ });
143
+ }
144
+ return toolCalls.filter((toolCall) => toolCall.id && toolCall.function.name);
145
+ }
146
+
147
+ function formatOpenAIError(err) {
148
+ if (!err || typeof err !== 'object') return 'Unknown OpenAI error';
149
+ const parts = [];
150
+ if (typeof err.status === 'number') parts.push(`HTTP ${err.status}`);
151
+ if (err.type) parts.push(`type=${err.type}`);
152
+ if (err.code) parts.push(`code=${err.code}`);
153
+ if (err.param) parts.push(`param=${err.param}`);
154
+ if (err.request_id) parts.push(`request_id=${err.request_id}`);
155
+ const message = err.message || 'Unknown OpenAI error';
156
+ return parts.length > 0 ? `${message} (${parts.join(', ')})` : message;
157
+ }
158
+
159
+ class OpenAICodexProvider extends BaseProvider {
160
+ constructor(config = {}) {
161
+ super(config);
162
+
163
+ const configuredBaseURL = config.baseUrl || process.env.OPENAI_CODEX_BASE_URL || DEFAULT_BASE_URL;
164
+ const baseURL = normalizeCodexBaseUrl(configuredBaseURL);
165
+
166
+ this.baseURL = baseURL;
167
+ this.usesCodexBackend = isCodexBackendBaseUrl(baseURL);
168
+
169
+ if (!this.usesCodexBackend && !baseURL.includes('api.openai.com')) {
170
+ console.warn(`[OpenAICodex] Using non-official base URL: ${baseURL}`);
171
+ } else if (this.usesCodexBackend) {
172
+ console.info(`[OpenAICodex] Using ChatGPT Codex endpoint: ${baseURL}`);
173
+ }
174
+
175
+ this.name = 'openai-codex';
176
+ this.models = [
177
+ 'gpt-5.5',
178
+ 'gpt-5.4',
179
+ 'gpt-5.4-mini',
180
+ ];
181
+ this.reasoningModels = new Set([
182
+ 'gpt-5.5',
183
+ 'gpt-5.4',
184
+ 'gpt-5.4-mini',
185
+ ]);
186
+ const defaultHeaders = this.usesCodexBackend
187
+ ? {
188
+ 'Editor-Version': process.env.OPENAI_CODEX_EDITOR_VERSION || 'vscode/1.99.0',
189
+ 'Editor-Plugin-Version': process.env.OPENAI_CODEX_EDITOR_PLUGIN_VERSION || 'neoagent/1.0.0',
190
+ 'User-Agent': process.env.OPENAI_CODEX_USER_AGENT || 'NeoAgent/1.0.0',
191
+ }
192
+ : undefined;
193
+
194
+ this.client = new OpenAI({
195
+ apiKey: config.apiKey || process.env.OPENAI_CODEX_ACCESS_TOKEN,
196
+ baseURL,
197
+ defaultHeaders,
198
+ });
199
+ }
200
+
201
+ formatTools(tools) {
202
+ return tools.map((tool) => ({
203
+ type: 'function',
204
+ name: tool.name,
205
+ description: tool.description || '',
206
+ parameters: tool.parameters || { type: 'object', properties: {} },
207
+ strict: false,
208
+ }));
209
+ }
210
+
211
+ _isReasoningModel(model) {
212
+ if (!model) return false;
213
+ for (const id of this.reasoningModels) {
214
+ if (model === id || model.startsWith(`${id}-`)) return true;
215
+ }
216
+ return false;
217
+ }
218
+
219
+ _buildRequest(messages = [], tools = [], options = {}, model = '') {
220
+ const instructions = [];
221
+ const input = [];
222
+
223
+ for (const msg of messages || []) {
224
+ if (!msg || !msg.role) continue;
225
+
226
+ if ((msg.role === 'system' || msg.role === 'developer') && msg.content != null) {
227
+ const text = normalizeContent(msg.content).trim();
228
+ if (text) instructions.push(text);
229
+ continue;
230
+ }
231
+
232
+ if (msg.role === 'tool') {
233
+ const toolCallId = String(msg.tool_call_id || '').trim();
234
+ if (!toolCallId) continue;
235
+ input.push(toFunctionCallOutput(toolCallId, msg.content));
236
+ continue;
237
+ }
238
+
239
+ const content = normalizeInputContent(msg.content);
240
+ if (content.length > 0) {
241
+ input.push({
242
+ type: 'message',
243
+ role: msg.role === 'assistant' ? 'assistant' : 'user',
244
+ content,
245
+ });
246
+ }
247
+
248
+ if (msg.role === 'assistant' && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) {
249
+ for (const toolCall of msg.tool_calls) {
250
+ const name = String(toolCall?.function?.name || '').trim();
251
+ const argumentsText = String(toolCall?.function?.arguments || '');
252
+ const callId = String(toolCall?.id || toolCall?.call_id || '').trim();
253
+ if (!name || !callId) continue;
254
+ input.push({
255
+ type: 'function_call',
256
+ call_id: callId,
257
+ name,
258
+ arguments: argumentsText,
259
+ });
260
+ }
261
+ }
262
+ }
263
+
264
+ const request = {
265
+ input,
266
+ };
267
+
268
+ if (instructions.length > 0) {
269
+ request.instructions = instructions.join('\n\n');
270
+ }
271
+
272
+ if (tools && tools.length > 0) {
273
+ request.tools = this.formatTools(tools);
274
+ request.tool_choice = options.toolChoice || 'auto';
275
+ }
276
+
277
+ if (!this.usesCodexBackend) {
278
+ request.max_output_tokens = options.maxTokens || 16384;
279
+
280
+ if (options.temperature !== undefined && options.temperature !== null) {
281
+ request.temperature = options.temperature;
282
+ }
283
+ }
284
+
285
+ const reasoningEffort = options.reasoningEffort || options.reasoning_effort;
286
+ if (reasoningEffort || this._isReasoningModel(model)) {
287
+ request.reasoning = {
288
+ effort: reasoningEffort || 'medium',
289
+ };
290
+ }
291
+
292
+ return request;
293
+ }
294
+
295
+ async chat(messages, tools = [], options = {}) {
296
+ const model = options.model || this.config.model || this.getDefaultModel();
297
+ const request = this._buildRequest(messages, tools, options, model);
298
+ let response;
299
+ try {
300
+ response = await this.client.responses.create({
301
+ model,
302
+ ...request,
303
+ });
304
+ } catch (err) {
305
+ throw new Error(`OpenAI Codex request failed: ${formatOpenAIError(err)}`);
306
+ }
307
+
308
+ const toolCalls = extractToolCalls(response);
309
+
310
+ return {
311
+ content: extractResponseText(response),
312
+ toolCalls,
313
+ finishReason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
314
+ usage: response.usage ? {
315
+ promptTokens: response.usage.input_tokens,
316
+ completionTokens: response.usage.output_tokens,
317
+ totalTokens: response.usage.total_tokens,
318
+ } : null,
319
+ model: response.model,
320
+ };
321
+ }
322
+
323
+ async *stream(messages, tools = [], options = {}) {
324
+ const model = options.model || this.config.model || this.getDefaultModel();
325
+ const request = this._buildRequest(messages, tools, options, model);
326
+ let stream;
327
+ try {
328
+ stream = await this.client.responses.create({
329
+ model,
330
+ ...request,
331
+ stream: true,
332
+ });
333
+ } catch (err) {
334
+ throw new Error(`OpenAI Codex request failed: ${formatOpenAIError(err)}`);
335
+ }
336
+
337
+ let content = '';
338
+ let finalResponse = null;
339
+
340
+ for await (const event of stream) {
341
+ if (event.type === 'response.output_text.delta' && typeof event.delta === 'string') {
342
+ content += event.delta;
343
+ yield { type: 'content', content: event.delta };
344
+ continue;
345
+ }
346
+
347
+ if (event.type === 'response.completed') {
348
+ finalResponse = event.response;
349
+ }
350
+ }
351
+
352
+ const response = finalResponse || {};
353
+ const toolCalls = extractToolCalls(response);
354
+ const finalContent = extractResponseText(response) || content;
355
+
356
+ if (toolCalls.length > 0) {
357
+ yield {
358
+ type: 'tool_calls',
359
+ content: finalContent,
360
+ toolCalls,
361
+ usage: response.usage ? {
362
+ promptTokens: response.usage.input_tokens,
363
+ completionTokens: response.usage.output_tokens,
364
+ totalTokens: response.usage.total_tokens,
365
+ } : null,
366
+ };
367
+ return;
368
+ }
369
+
370
+ yield {
371
+ type: 'done',
372
+ content: finalContent,
373
+ toolCalls: [],
374
+ finishReason: 'stop',
375
+ usage: response.usage ? {
376
+ promptTokens: response.usage.input_tokens,
377
+ completionTokens: response.usage.output_tokens,
378
+ totalTokens: response.usage.total_tokens,
379
+ } : null,
380
+ };
381
+ }
382
+ }
383
+
384
+ module.exports = { OpenAICodexProvider };
@@ -6,23 +6,21 @@ const { getSupportedModels } = require('./models');
6
6
  const { getAiSettings } = require('./settings');
7
7
  const { parseJsonObject } = require('./taskAnalysis');
8
8
 
9
- const INSIGHTS_SYSTEM_PROMPT = `You are an expert audio transcript analyzer. Your job is to read the provided transcript and extract structured insights.
9
+ const INSIGHTS_SYSTEM_PROMPT = `Return JSON only. No markdown, no prose, no code fences.
10
10
 
11
- You must output valid JSON ONLY, with the following exact structure:
11
+ You are a precise conversation analyst. Read the transcript and extract exactly what happened: who said what, what was decided, what needs to happen next, and when.
12
+
13
+ Schema:
12
14
  {
13
- "summary": "A concise, 1-2 paragraph summary of the entire conversation.",
14
- "action_items": [
15
- "List of any action items, tasks, or follow-ups mentioned.",
16
- "Be specific and include who is responsible if mentioned."
17
- ],
18
- "events": [
19
- "List of any events, meetings, or dates mentioned in the transcript."
20
- ]
15
+ "summary": "1-2 paragraph factual summary. Name speakers if identifiable. Cover the main topic, key decisions, outcome, and any unresolved items.",
16
+ "action_items": ["Each item as: '[Owner if named] — specific action'. One item per string. Empty array if none."],
17
+ "events": ["Each as: '[date/time if stated] event description'. One event per string. Empty array if none."]
21
18
  }
22
19
 
23
- If no action items or events are found, return empty arrays for those fields.
24
- Do NOT wrap the output in markdown \`\`\`json blocks. ONLY return the raw JSON object.
25
- `;
20
+ Rules:
21
+ - Report only what the transcript explicitly contains. Do not infer or add context not present in the recording.
22
+ - Be specific: "Alice will send the contract by Friday" beats "follow-up needed".
23
+ - If a field has no data, use an empty array.`;
26
24
 
27
25
  async function extractRecordingInsights(userId, transcriptText, options = {}) {
28
26
  if (!transcriptText || !transcriptText.trim()) {
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ const db = require('../../db/database');
4
+
5
+ function parseJsonObject(value, fallback = {}) {
6
+ if (!value) return { ...fallback };
7
+ if (typeof value === 'object' && !Array.isArray(value)) return { ...value };
8
+ try {
9
+ const parsed = JSON.parse(String(value));
10
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
11
+ ? parsed
12
+ : { ...fallback };
13
+ } catch {
14
+ return { ...fallback };
15
+ }
16
+ }
17
+
18
+ function recordRunEvent({
19
+ runId,
20
+ userId,
21
+ agentId = null,
22
+ eventType,
23
+ requestId = null,
24
+ stepId = null,
25
+ sequenceIndex = null,
26
+ payload = {},
27
+ }) {
28
+ if (!runId || !userId || !eventType) return null;
29
+ const payloadJson = JSON.stringify(
30
+ payload && typeof payload === 'object' && !Array.isArray(payload) ? payload : {},
31
+ );
32
+ const row = db.transaction(() => {
33
+ const resolvedSequence = Number.isInteger(sequenceIndex) && sequenceIndex > 0
34
+ ? sequenceIndex
35
+ : Number(
36
+ db.prepare(
37
+ 'SELECT COALESCE(MAX(sequence_index), 0) AS max_sequence FROM agent_run_events WHERE run_id = ?'
38
+ ).get(runId)?.max_sequence || 0,
39
+ ) + 1;
40
+ const result = db.prepare(
41
+ `INSERT INTO agent_run_events (
42
+ run_id, user_id, agent_id, event_type, request_id, step_id, sequence_index, payload_json
43
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
44
+ ).run(
45
+ runId,
46
+ userId,
47
+ agentId || null,
48
+ eventType,
49
+ requestId || null,
50
+ stepId || null,
51
+ resolvedSequence,
52
+ payloadJson,
53
+ );
54
+ return db.prepare(
55
+ `SELECT id, run_id, user_id, agent_id, event_type, request_id, step_id, sequence_index, payload_json, created_at
56
+ FROM agent_run_events
57
+ WHERE id = ?`
58
+ ).get(result.lastInsertRowid);
59
+ })();
60
+
61
+ return row ? {
62
+ id: Number(row.id),
63
+ runId: row.run_id,
64
+ userId: row.user_id,
65
+ agentId: row.agent_id || null,
66
+ eventType: row.event_type,
67
+ requestId: row.request_id || null,
68
+ stepId: row.step_id || null,
69
+ sequenceIndex: Number(row.sequence_index || 0),
70
+ payload: parseJsonObject(row.payload_json, {}),
71
+ createdAt: row.created_at,
72
+ } : null;
73
+ }
74
+
75
+ function listRunEvents(runId) {
76
+ if (!runId) return [];
77
+ const rows = db.prepare(
78
+ `SELECT id, run_id, user_id, agent_id, event_type, request_id, step_id, sequence_index, payload_json, created_at
79
+ FROM agent_run_events
80
+ WHERE run_id = ?
81
+ ORDER BY sequence_index ASC, id ASC`
82
+ ).all(runId);
83
+ return rows.map((row) => ({
84
+ id: Number(row.id),
85
+ runId: row.run_id,
86
+ userId: row.user_id,
87
+ agentId: row.agent_id || null,
88
+ eventType: row.event_type,
89
+ requestId: row.request_id || null,
90
+ stepId: row.step_id || null,
91
+ sequenceIndex: Number(row.sequence_index || 0),
92
+ payload: parseJsonObject(row.payload_json, {}),
93
+ createdAt: row.created_at,
94
+ }));
95
+ }
96
+
97
+ module.exports = {
98
+ recordRunEvent,
99
+ listRunEvents,
100
+ };
@@ -59,6 +59,26 @@ const AI_PROVIDER_DEFINITIONS = Object.freeze({
59
59
  defaultEnabled: false,
60
60
  defaultBaseUrl: 'https://api.minimax.io/anthropic'
61
61
  },
62
+ 'github-copilot': {
63
+ id: 'github-copilot',
64
+ label: 'GitHub Copilot',
65
+ description: 'Use your GitHub Copilot subscription as an AI provider.',
66
+ envKey: 'GITHUB_COPILOT_ACCESS_TOKEN',
67
+ supportsApiKey: true,
68
+ supportsBaseUrl: true,
69
+ defaultEnabled: false,
70
+ defaultBaseUrl: 'https://api.githubcopilot.com'
71
+ },
72
+ 'openai-codex': {
73
+ id: 'openai-codex',
74
+ label: 'OpenAI Codex',
75
+ description: 'Use Codex models through ChatGPT Codex authentication.',
76
+ envKey: 'OPENAI_CODEX_ACCESS_TOKEN',
77
+ supportsApiKey: true,
78
+ supportsBaseUrl: true,
79
+ defaultEnabled: false,
80
+ defaultBaseUrl: 'https://chatgpt.com/backend-api/codex'
81
+ },
62
82
  ollama: {
63
83
  id: 'ollama',
64
84
  label: 'Ollama',