neoagent 3.1.1-beta.9 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +2 -2
- package/README.md +5 -1
- package/docs/architecture.md +1 -1
- package/docs/benchmarking.md +68 -87
- package/docs/capabilities.md +1 -1
- package/docs/clients-and-devices.md +3 -4
- package/docs/configuration.md +1 -1
- package/docs/devices.md +1 -2
- package/docs/health.md +24 -0
- package/docs/index.md +2 -2
- package/docs/integrations-architecture.md +6 -0
- package/docs/integrations.md +15 -1
- package/docs/models.md +1 -1
- package/docs/persistence.md +1 -1
- package/docs/why-neoagent.md +1 -1
- package/flutter_app/README.md +0 -5
- package/flutter_app/android/app/src/main/AndroidManifest.xml +0 -14
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +0 -98
- package/flutter_app/lib/main.dart +0 -6
- package/flutter_app/lib/main_app_shell.dart +0 -2
- package/flutter_app/lib/main_controller.dart +2 -867
- package/flutter_app/lib/main_devices.dart +0 -73
- package/flutter_app/lib/main_integrations.dart +339 -187
- package/flutter_app/lib/main_launcher.dart +2 -212
- package/flutter_app/lib/main_models.dart +0 -259
- package/flutter_app/lib/main_navigation.dart +2 -14
- package/flutter_app/lib/main_operations.dart +322 -364
- package/flutter_app/lib/main_runtime.dart +9 -208
- package/flutter_app/lib/main_settings.dart +17 -199
- package/flutter_app/lib/main_shared.dart +20 -591
- package/flutter_app/lib/main_timeline.dart +26 -122
- package/flutter_app/lib/main_voice_assistant.dart +0 -5
- package/flutter_app/lib/src/backend_client.dart +0 -102
- package/flutter_app/lib/src/desktop_companion_io.dart +1 -65
- package/flutter_app/lib/src/desktop_companion_stub.dart +0 -12
- package/flutter_app/linux/flutter/generated_plugin_registrant.cc +0 -4
- package/flutter_app/linux/flutter/generated_plugins.cmake +0 -1
- package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +0 -2
- package/flutter_app/macos/Podfile.lock +56 -5
- package/flutter_app/pubspec.lock +0 -7
- package/flutter_app/pubspec.yaml +0 -2
- package/flutter_app/web/index.html +174 -0
- package/flutter_app/windows/flutter/generated_plugin_registrant.cc +0 -3
- package/flutter_app/windows/flutter/generated_plugins.cmake +0 -1
- package/landing/index.html +0 -2
- package/lib/manager.js +1 -1
- package/lib/schema_migrations.js +75 -0
- package/package.json +1 -4
- package/server/db/database.js +1 -133
- package/server/http/middleware.js +2 -16
- package/server/http/routes.js +0 -2
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/NOTICES +0 -25
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/index.html +174 -0
- package/server/public/main.dart.js +88081 -90036
- package/server/routes/auth.js +11 -2
- package/server/routes/settings.js +0 -5
- package/server/routes/voice_assistant.js +1 -128
- package/server/services/account/erasure.js +0 -3
- package/server/services/ai/deliverables/artifact_helpers.js +1 -1
- package/server/services/ai/loop/conversation_loop.js +6 -2
- package/server/services/ai/loop/tool_dispatch.js +0 -3
- package/server/services/ai/messagingFallback.js +1 -1
- package/server/services/ai/settings.js +0 -6
- package/server/services/ai/toolEvidence.js +1 -4
- package/server/services/ai/tools.js +0 -234
- package/server/services/desktop/auth.js +0 -3
- package/server/services/desktop/registry.js +2 -50
- package/server/services/integrations/neoarchive/provider.js +616 -0
- package/server/services/integrations/neorecall/client.js +140 -0
- package/server/services/integrations/neorecall/constants.js +87 -0
- package/server/services/integrations/neorecall/provider.js +163 -0
- package/server/services/integrations/registry.js +4 -2
- package/server/services/manager.js +0 -22
- package/server/services/memory/manager.js +44 -19
- package/server/services/memory/retrieval_reasoning.js +36 -14
- package/server/services/messaging/whatsapp.js +18 -0
- package/server/services/security/tool_categories.js +0 -5
- package/server/services/social_video/service.js +2 -20
- package/server/services/tasks/adapters/index.js +1 -1
- package/server/services/tasks/integration_runtime.js +3 -67
- package/server/services/tasks/runtime.js +1 -6
- package/server/services/tasks/task_repository.js +6 -13
- package/server/services/timeline/service.js +0 -224
- package/server/services/voice/message.js +0 -24
- package/server/services/voice/providers.js +42 -1
- package/server/services/voice/runtimeManager.js +9 -5
- package/server/services/voice/turnRunner.js +0 -22
- package/server/services/wearable/service.js +0 -5
- package/docs/recordings-and-health.md +0 -41
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +0 -21
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +0 -586
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +0 -78
- package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +0 -104
- package/flutter_app/lib/main_recordings.dart +0 -920
- package/flutter_app/lib/src/desktop_ocr_bridge.dart +0 -2
- package/flutter_app/lib/src/desktop_ocr_bridge_io.dart +0 -125
- package/flutter_app/lib/src/desktop_ocr_bridge_stub.dart +0 -30
- package/flutter_app/lib/src/desktop_passive_history.dart +0 -332
- package/flutter_app/lib/src/recording_bridge.dart +0 -232
- package/flutter_app/lib/src/recording_bridge_io.dart +0 -1027
- package/flutter_app/lib/src/recording_bridge_stub.dart +0 -120
- package/flutter_app/lib/src/recording_bridge_web.dart +0 -702
- package/flutter_app/lib/src/recording_chunk_queue.dart +0 -149
- package/flutter_app/lib/src/recording_chunk_queue_io.dart +0 -182
- package/flutter_app/lib/src/recording_payloads.dart +0 -95
- package/flutter_app/third_party/desktop_audio_capture/LICENSE +0 -21
- package/flutter_app/third_party/desktop_audio_capture/README.md +0 -262
- package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +0 -65
- package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +0 -153
- package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +0 -110
- package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +0 -461
- package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +0 -91
- package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +0 -106
- package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +0 -219
- package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +0 -336
- package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +0 -101
- package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +0 -692
- package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +0 -35
- package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +0 -36
- package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +0 -32
- package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +0 -32
- package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +0 -878
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +0 -27
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +0 -1172
- package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +0 -655
- package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +0 -12
- package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +0 -30
- package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +0 -87
- package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +0 -105
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +0 -80
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +0 -31
- package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +0 -12
- package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +0 -23
- package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +0 -25
- package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +0 -1117
- package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +0 -115
- package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +0 -777
- package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +0 -87
- package/server/routes/recordings.js +0 -335
- package/server/routes/screenHistory.js +0 -190
- package/server/services/ai/recordingInsights.js +0 -105
- package/server/services/integrations/neomail/provider.js +0 -993
- package/server/services/recordings/deepgram.js +0 -58
- package/server/services/recordings/manager.js +0 -1273
- package/server/services/tasks/adapters/neomail_email_received.js +0 -46
- package/server/services/voice/screenshotContext.js +0 -73
- package/server/services/voice/turnCoordinator.js +0 -51
|
@@ -6,15 +6,11 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
6
6
|
required BackendClient backendClient,
|
|
7
7
|
required HealthBridge healthBridge,
|
|
8
8
|
required WidgetBridge widgetBridge,
|
|
9
|
-
required RecordingBridge recordingBridge,
|
|
10
9
|
OAuthLauncher? oauthLauncher,
|
|
11
10
|
}) : _backendClient = backendClient,
|
|
12
11
|
_healthBridge = healthBridge,
|
|
13
12
|
_widgetBridge = widgetBridge,
|
|
14
|
-
_recordingBridge = recordingBridge,
|
|
15
13
|
_oauthLauncher = oauthLauncher ?? createOAuthLauncher() {
|
|
16
|
-
_recordingBridge.onRecordingStopped = _handleRecordingStopped;
|
|
17
|
-
_recordingBridge.addListener(_handleRecordingBridgeChanged);
|
|
18
14
|
_desktopCompanion.addListener(notifyListeners);
|
|
19
15
|
|
|
20
16
|
AndroidAutoBridge.instance.onStartVoiceMode = startLiveVoiceCapture;
|
|
@@ -33,13 +29,10 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
33
29
|
final BackendClient _backendClient;
|
|
34
30
|
final HealthBridge _healthBridge;
|
|
35
31
|
final WidgetBridge _widgetBridge;
|
|
36
|
-
final RecordingBridge _recordingBridge;
|
|
37
32
|
final OAuthLauncher _oauthLauncher;
|
|
38
33
|
final app_release_updater.AppReleaseUpdater _appReleaseUpdater =
|
|
39
34
|
app_release_updater.AppReleaseUpdater();
|
|
40
35
|
final LiveVoiceCapture _liveVoiceCapture = LiveVoiceCapture();
|
|
41
|
-
final DesktopScreenCapture _desktopScreenCapture =
|
|
42
|
-
createDesktopScreenCapture();
|
|
43
36
|
final DesktopCompanionManager _desktopCompanion = DesktopCompanionManager(
|
|
44
37
|
screenCapture: createDesktopScreenCapture(),
|
|
45
38
|
);
|
|
@@ -106,8 +99,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
106
99
|
bool socketConnected = false;
|
|
107
100
|
bool hasNetworkConnection = true;
|
|
108
101
|
bool networkStatusKnown = false;
|
|
109
|
-
bool _desktopFloatingToolbarPopupRequested = false;
|
|
110
|
-
bool _voiceAssistantIncludeScreenContext = false;
|
|
111
102
|
|
|
112
103
|
io.Socket? get streamSocket => socketConnected ? _socket : null;
|
|
113
104
|
|
|
@@ -144,7 +135,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
144
135
|
Map<String, dynamic>? versionInfo;
|
|
145
136
|
Map<String, dynamic>? backendHealthStatus;
|
|
146
137
|
HealthBridgeStatus? deviceHealthStatus;
|
|
147
|
-
List<RecordingSessionItem> recordingSessions = const <RecordingSessionItem>[];
|
|
148
138
|
|
|
149
139
|
List<ChatEntry> chatMessages = const <ChatEntry>[];
|
|
150
140
|
bool chatHistoryHasMore = false;
|
|
@@ -220,8 +210,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
220
210
|
ActiveRunState? activeRun;
|
|
221
211
|
List<ToolEventItem> toolEvents = const <ToolEventItem>[];
|
|
222
212
|
String streamingAssistant = '';
|
|
223
|
-
bool isStartingRecording = false;
|
|
224
|
-
bool isStoppingRecording = false;
|
|
225
213
|
bool _isStartingLiveVoice = false;
|
|
226
214
|
bool _isStoppingLiveVoice = false;
|
|
227
215
|
bool _liveVoiceCaptureActive = false;
|
|
@@ -242,24 +230,17 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
242
230
|
VoiceAssistantLiveState voiceAssistantLiveState = VoiceAssistantLiveState();
|
|
243
231
|
bool _desktopAskOnClose = true;
|
|
244
232
|
bool _desktopKeepRunningOnClose = true;
|
|
245
|
-
bool _desktopAutoShowFloatingToolbar = true;
|
|
246
233
|
bool _desktopAssistantHotkeyEnabled = true;
|
|
247
234
|
bool isRefreshingTimeline = false;
|
|
248
|
-
Set<String> selectedTimelineSources = <String>{'
|
|
235
|
+
Set<String> selectedTimelineSources = <String>{'tasks', 'runs'};
|
|
249
236
|
|
|
250
237
|
bool get desktopCompanionEnabled => _desktopCompanion.enabled;
|
|
251
|
-
bool get desktopPassiveHistoryEnabled =>
|
|
252
|
-
_desktopCompanion.passiveHistoryEnabled;
|
|
253
238
|
bool get isLauncherMode => appMode == NeoAgentAppMode.launcher;
|
|
254
239
|
bool get desktopCompanionConnected => _desktopCompanion.connected;
|
|
255
240
|
bool get desktopCompanionConnecting => _desktopCompanion.connecting;
|
|
256
241
|
bool get desktopCompanionPaused => _desktopCompanion.paused;
|
|
257
242
|
String get desktopCompanionLabel => _desktopCompanion.label;
|
|
258
243
|
String? get desktopCompanionErrorMessage => _desktopCompanion.errorMessage;
|
|
259
|
-
String? get desktopPassiveHistoryLastUploadedAt =>
|
|
260
|
-
_desktopCompanion.passiveHistoryLastUploadedAt;
|
|
261
|
-
String? get desktopPassiveHistoryLastError =>
|
|
262
|
-
_desktopCompanion.passiveHistoryLastError;
|
|
263
244
|
String? get requestedRunFocusId => _requestedRunFocusId;
|
|
264
245
|
Map<String, Object?> get desktopCompanionStatus => _desktopCompanion.status;
|
|
265
246
|
|
|
@@ -367,21 +348,15 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
367
348
|
_appReleaseUpdater.dispose();
|
|
368
349
|
_desktopCompanion.removeListener(notifyListeners);
|
|
369
350
|
unawaited(_desktopCompanion.disconnect());
|
|
370
|
-
_recordingBridge.removeListener(_handleRecordingBridgeChanged);
|
|
371
|
-
_recordingBridge.dispose();
|
|
372
351
|
unawaited(_liveVoiceCapture.dispose());
|
|
373
352
|
_oauthLauncher.dispose();
|
|
374
353
|
super.dispose();
|
|
375
354
|
}
|
|
376
355
|
|
|
377
|
-
RecordingRuntimeStatus get recordingRuntime => _recordingBridge.status;
|
|
378
|
-
|
|
379
356
|
bool get desktopAskOnClose => _desktopAskOnClose;
|
|
380
357
|
|
|
381
358
|
bool get desktopKeepRunningOnClose => _desktopKeepRunningOnClose;
|
|
382
359
|
|
|
383
|
-
bool get desktopAutoShowFloatingToolbar => _desktopAutoShowFloatingToolbar;
|
|
384
|
-
|
|
385
360
|
bool get desktopAssistantHotkeyEnabled => _desktopAssistantHotkeyEnabled;
|
|
386
361
|
|
|
387
362
|
String? get sessionCookie => _backendClient.sessionCookie;
|
|
@@ -402,15 +377,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
402
377
|
notifyListeners();
|
|
403
378
|
}
|
|
404
379
|
|
|
405
|
-
bool get desktopFloatingToolbarPopupRequested =>
|
|
406
|
-
_desktopFloatingToolbarPopupRequested;
|
|
407
|
-
|
|
408
|
-
bool get voiceAssistantIncludeScreenContext =>
|
|
409
|
-
_voiceAssistantIncludeScreenContext;
|
|
410
|
-
|
|
411
|
-
bool get canCaptureVoiceAssistantScreenContext =>
|
|
412
|
-
_desktopScreenCapture.isSupported;
|
|
413
|
-
|
|
414
380
|
bool get isLiveVoiceCaptureEngaged =>
|
|
415
381
|
_isStartingLiveVoice || _liveVoiceCaptureActive;
|
|
416
382
|
|
|
@@ -438,53 +404,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
438
404
|
return '${local.year}-${local.month.toString().padLeft(2, '0')}-${local.day.toString().padLeft(2, '0')} ${local.hour.toString().padLeft(2, '0')}:$minute';
|
|
439
405
|
}
|
|
440
406
|
|
|
441
|
-
bool get canStartDesktopRecording =>
|
|
442
|
-
_supportsDesktopShell &&
|
|
443
|
-
isAuthenticated &&
|
|
444
|
-
!isBooting &&
|
|
445
|
-
!requiresBackendUrlSetup &&
|
|
446
|
-
backendUrl.trim().isNotEmpty &&
|
|
447
|
-
!isStartingRecording &&
|
|
448
|
-
!isLiveVoiceCaptureActive &&
|
|
449
|
-
!isLiveVoiceCaptureStarting &&
|
|
450
|
-
!recordingRuntime.active &&
|
|
451
|
-
recordingRuntime.supportsSystemAudio;
|
|
452
|
-
|
|
453
|
-
Map<String, Object?> _recordingRuntimeSnapshot() {
|
|
454
|
-
final runtime = recordingRuntime;
|
|
455
|
-
return <String, Object?>{
|
|
456
|
-
'runtimeActive': runtime.active,
|
|
457
|
-
'runtimePaused': runtime.paused,
|
|
458
|
-
'runtimeSessionId': runtime.sessionId,
|
|
459
|
-
'runtimeStartedAt': runtime.startedAt?.toIso8601String(),
|
|
460
|
-
'runtimeError': runtime.errorMessage,
|
|
461
|
-
'runtimeSupportsSystemAudio': runtime.supportsSystemAudio,
|
|
462
|
-
'runtimeFloatingToolbarVisible': runtime.floatingToolbarVisible,
|
|
463
|
-
'sessionsLoaded': recordingSessions.length,
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
void _upsertRecordingSession(RecordingSessionItem session) {
|
|
468
|
-
final existingIndex = recordingSessions.indexWhere(
|
|
469
|
-
(item) => item.id == session.id,
|
|
470
|
-
);
|
|
471
|
-
if (existingIndex >= 0) {
|
|
472
|
-
recordingSessions = <RecordingSessionItem>[
|
|
473
|
-
...recordingSessions.sublist(0, existingIndex),
|
|
474
|
-
session,
|
|
475
|
-
...recordingSessions.sublist(existingIndex + 1),
|
|
476
|
-
];
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
recordingSessions = <RecordingSessionItem>[session, ...recordingSessions];
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
void _removeRecordingSession(String sessionId) {
|
|
483
|
-
recordingSessions = recordingSessions
|
|
484
|
-
.where((item) => item.id != sessionId)
|
|
485
|
-
.toList();
|
|
486
|
-
}
|
|
487
|
-
|
|
488
407
|
void _appendChatMessage(
|
|
489
408
|
String content, {
|
|
490
409
|
required String role,
|
|
@@ -625,142 +544,11 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
625
544
|
return lowercase ? value.toLowerCase() : value;
|
|
626
545
|
}
|
|
627
546
|
|
|
628
|
-
Future<void> _finalizeRecordingSessionQuietly(String? sessionId) async {
|
|
629
|
-
final trimmed = sessionId?.trim() ?? '';
|
|
630
|
-
if (trimmed.isEmpty) {
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
633
|
-
try {
|
|
634
|
-
await _backendClient.finalizeRecordingSession(
|
|
635
|
-
backendUrl,
|
|
636
|
-
trimmed,
|
|
637
|
-
stopReason: 'cancelled',
|
|
638
|
-
);
|
|
639
|
-
} catch (_) {}
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
Future<void> _startRecordingCapture({
|
|
643
|
-
required String logKey,
|
|
644
|
-
required Map<String, dynamic> payload,
|
|
645
|
-
required Future<void> Function(String sessionId) startCapture,
|
|
646
|
-
}) async {
|
|
647
|
-
if (isStartingRecording || recordingRuntime.active) {
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
isStartingRecording = true;
|
|
651
|
-
errorMessage = null;
|
|
652
|
-
notifyListeners();
|
|
653
|
-
|
|
654
|
-
String? sessionId;
|
|
655
|
-
try {
|
|
656
|
-
_logRecording('$logKey.request');
|
|
657
|
-
final response = await _backendClient.createRecordingSession(
|
|
658
|
-
backendUrl,
|
|
659
|
-
payload,
|
|
660
|
-
);
|
|
661
|
-
final session = RecordingSessionItem.fromJson(
|
|
662
|
-
_jsonMap(response['session']),
|
|
663
|
-
);
|
|
664
|
-
sessionId = session.id;
|
|
665
|
-
_upsertRecordingSession(session);
|
|
666
|
-
await startCapture(session.id);
|
|
667
|
-
_logRecording(
|
|
668
|
-
'$logKey.done',
|
|
669
|
-
data: <String, Object?>{'sessionId': session.id},
|
|
670
|
-
);
|
|
671
|
-
notifyListeners();
|
|
672
|
-
} catch (error) {
|
|
673
|
-
_logRecording(
|
|
674
|
-
'$logKey.failed',
|
|
675
|
-
data: <String, Object?>{'sessionId': sessionId},
|
|
676
|
-
error: error,
|
|
677
|
-
);
|
|
678
|
-
await _finalizeRecordingSessionQuietly(sessionId);
|
|
679
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
680
|
-
await refreshRecordings();
|
|
681
|
-
} finally {
|
|
682
|
-
isStartingRecording = false;
|
|
683
|
-
notifyListeners();
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
void _logRecording(
|
|
688
|
-
String event, {
|
|
689
|
-
Map<String, Object?> data = const <String, Object?>{},
|
|
690
|
-
Object? error,
|
|
691
|
-
StackTrace? stackTrace,
|
|
692
|
-
}) {
|
|
693
|
-
AppDiagnostics.log(
|
|
694
|
-
'recording.controller',
|
|
695
|
-
event,
|
|
696
|
-
data: <String, Object?>{..._recordingRuntimeSnapshot(), ...data},
|
|
697
|
-
error: error,
|
|
698
|
-
stackTrace: stackTrace,
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
void _logRecordingConsistency(String reason) {
|
|
703
|
-
final activeSessionId = recordingRuntime.sessionId;
|
|
704
|
-
RecordingSessionItem? activeSession;
|
|
705
|
-
if (activeSessionId != null) {
|
|
706
|
-
for (final session in recordingSessions) {
|
|
707
|
-
if (session.id == activeSessionId) {
|
|
708
|
-
activeSession = session;
|
|
709
|
-
break;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
final serverRecordingCount = recordingSessions
|
|
715
|
-
.where((session) => session.status == 'recording')
|
|
716
|
-
.length;
|
|
717
|
-
|
|
718
|
-
_logRecording(
|
|
719
|
-
'consistency.snapshot',
|
|
720
|
-
data: <String, Object?>{
|
|
721
|
-
'reason': reason,
|
|
722
|
-
'activeSessionId': activeSessionId,
|
|
723
|
-
'activeSessionStatus': activeSession?.status,
|
|
724
|
-
'serverRecordingCount': serverRecordingCount,
|
|
725
|
-
},
|
|
726
|
-
);
|
|
727
|
-
|
|
728
|
-
if (!recordingRuntime.active &&
|
|
729
|
-
activeSession != null &&
|
|
730
|
-
activeSession.status == 'recording') {
|
|
731
|
-
_logRecording(
|
|
732
|
-
'consistency.mismatch_runtime_inactive_server_recording',
|
|
733
|
-
data: <String, Object?>{
|
|
734
|
-
'reason': reason,
|
|
735
|
-
'sessionId': activeSession.id,
|
|
736
|
-
},
|
|
737
|
-
);
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
if (recordingRuntime.active &&
|
|
741
|
-
activeSession != null &&
|
|
742
|
-
activeSession.status != 'recording') {
|
|
743
|
-
_logRecording(
|
|
744
|
-
'consistency.mismatch_runtime_active_server_not_recording',
|
|
745
|
-
data: <String, Object?>{
|
|
746
|
-
'reason': reason,
|
|
747
|
-
'sessionId': activeSession.id,
|
|
748
|
-
'serverStatus': activeSession.status,
|
|
749
|
-
},
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
547
|
BlockedSenderNotice? get pendingBlockedSenderNotice =>
|
|
755
548
|
_blockedSenderQueue.isEmpty ? null : _blockedSenderQueue.first;
|
|
756
549
|
|
|
757
550
|
List<String> get ignoredChats => _ignoredChats.toList();
|
|
758
551
|
|
|
759
|
-
void _handleRecordingBridgeChanged() {
|
|
760
|
-
_logRecording('bridge.changed');
|
|
761
|
-
notifyListeners();
|
|
762
|
-
}
|
|
763
|
-
|
|
764
552
|
static LogEntry _logEntryFromDiagnostic(AppDiagnosticEntry entry) {
|
|
765
553
|
final buffer = StringBuffer('[${entry.area}] ${entry.event}');
|
|
766
554
|
if (entry.data.isNotEmpty) {
|
|
@@ -812,33 +600,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
812
600
|
: merged;
|
|
813
601
|
}
|
|
814
602
|
|
|
815
|
-
Future<void> _handleRecordingStopped(String sessionId) async {
|
|
816
|
-
_logRecording(
|
|
817
|
-
'bridge.on_recording_stopped',
|
|
818
|
-
data: <String, Object?>{'sessionId': sessionId},
|
|
819
|
-
);
|
|
820
|
-
try {
|
|
821
|
-
await _backendClient.finalizeRecordingSession(
|
|
822
|
-
backendUrl,
|
|
823
|
-
sessionId,
|
|
824
|
-
stopReason: 'ended',
|
|
825
|
-
);
|
|
826
|
-
_logRecording(
|
|
827
|
-
'finalize.ok',
|
|
828
|
-
data: <String, Object?>{'sessionId': sessionId, 'stopReason': 'ended'},
|
|
829
|
-
);
|
|
830
|
-
await refreshRecordings();
|
|
831
|
-
} catch (error) {
|
|
832
|
-
_logRecording(
|
|
833
|
-
'finalize.failed',
|
|
834
|
-
data: <String, Object?>{'sessionId': sessionId, 'stopReason': 'ended'},
|
|
835
|
-
error: error,
|
|
836
|
-
);
|
|
837
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
838
|
-
notifyListeners();
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
|
|
842
603
|
Future<void> bootstrap() async {
|
|
843
604
|
_prefs = await SharedPreferences.getInstance();
|
|
844
605
|
_ignoredChats.addAll(
|
|
@@ -853,14 +614,9 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
853
614
|
_desktopAskOnClose = _prefs?.getBool('desktop.askOnClose') ?? true;
|
|
854
615
|
_desktopKeepRunningOnClose =
|
|
855
616
|
_prefs?.getBool('desktop.keepRunningOnClose') ?? true;
|
|
856
|
-
_desktopAutoShowFloatingToolbar =
|
|
857
|
-
_prefs?.getBool('desktop.autoShowFloatingToolbar') ?? true;
|
|
858
617
|
_desktopAssistantHotkeyEnabled =
|
|
859
618
|
_prefs?.getBool('desktop.assistantHotkeyEnabled') ?? true;
|
|
860
619
|
_restoreSelectedSectionFromPrefs();
|
|
861
|
-
_voiceAssistantIncludeScreenContext =
|
|
862
|
-
(_prefs?.getBool('voiceAssistant.includeScreenContext') ?? false) &&
|
|
863
|
-
canCaptureVoiceAssistantScreenContext;
|
|
864
620
|
appUpdateChannel =
|
|
865
621
|
_prefs?.getString('app.update.channel')?.trim().toLowerCase() == 'beta'
|
|
866
622
|
? 'beta'
|
|
@@ -917,7 +673,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
917
673
|
_backendClient.clearSessionCookie();
|
|
918
674
|
}
|
|
919
675
|
|
|
920
|
-
await _recordingBridge.refreshStatus();
|
|
921
676
|
notifyListeners();
|
|
922
677
|
|
|
923
678
|
if (appUpdaterConfigured &&
|
|
@@ -1598,20 +1353,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1598
1353
|
}
|
|
1599
1354
|
|
|
1600
1355
|
Future<void> logout() async {
|
|
1601
|
-
final recordingSessionId = recordingRuntime.sessionId;
|
|
1602
|
-
if (recordingRuntime.active && recordingSessionId != null) {
|
|
1603
|
-
try {
|
|
1604
|
-
await _recordingBridge.stopActiveRecording();
|
|
1605
|
-
if (!recordingRuntime.supportsBackgroundMic) {
|
|
1606
|
-
await _backendClient.finalizeRecordingSession(
|
|
1607
|
-
backendUrl,
|
|
1608
|
-
recordingSessionId,
|
|
1609
|
-
stopReason: 'ended',
|
|
1610
|
-
);
|
|
1611
|
-
}
|
|
1612
|
-
} catch (_) {}
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
1356
|
final logoutFuture = _backendClient.logout(backendUrl);
|
|
1616
1357
|
_authCycle += 1;
|
|
1617
1358
|
_clearAuthenticatedState();
|
|
@@ -1728,7 +1469,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1728
1469
|
androidUiDumpPath = null;
|
|
1729
1470
|
versionInfo = null;
|
|
1730
1471
|
backendHealthStatus = null;
|
|
1731
|
-
recordingSessions = const <RecordingSessionItem>[];
|
|
1732
1472
|
activeRun = null;
|
|
1733
1473
|
toolEvents = const <ToolEventItem>[];
|
|
1734
1474
|
streamingAssistant = '';
|
|
@@ -2310,9 +2050,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2310
2050
|
_backendClient.fetchMcpServers(backendUrl, agentId: agentId),
|
|
2311
2051
|
const <Map<String, dynamic>>[],
|
|
2312
2052
|
);
|
|
2313
|
-
final recordingsFuture = _backendClient
|
|
2314
|
-
.fetchRecordingSessions(backendUrl)
|
|
2315
|
-
.catchError((_) => const <Map<String, dynamic>>[]);
|
|
2316
2053
|
unawaited(checkBillingEnabled());
|
|
2317
2054
|
final browserFuture = _backendClient
|
|
2318
2055
|
.fetchBrowserStatus(backendUrl)
|
|
@@ -2373,7 +2110,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2373
2110
|
final tasksResponse = await tasksFuture;
|
|
2374
2111
|
final widgetsResponse = await widgetsFuture;
|
|
2375
2112
|
final mcpResponse = await mcpFuture;
|
|
2376
|
-
final recordingsResponse = await recordingsFuture;
|
|
2377
2113
|
final browserResponse = await browserFuture;
|
|
2378
2114
|
final socialReachResponse = await socialReachFuture;
|
|
2379
2115
|
final browserExtensionResponse = await browserExtensionFuture;
|
|
@@ -2467,11 +2203,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2467
2203
|
mcpResponse,
|
|
2468
2204
|
McpServerItem.fromJson,
|
|
2469
2205
|
);
|
|
2470
|
-
recordingSessions = _decodeModelList(
|
|
2471
|
-
'recordings',
|
|
2472
|
-
recordingsResponse,
|
|
2473
|
-
RecordingSessionItem.fromJson,
|
|
2474
|
-
);
|
|
2475
2206
|
browserRuntime = Map<String, dynamic>.from(browserResponse);
|
|
2476
2207
|
socialReachStatus = Map<String, dynamic>.from(socialReachResponse);
|
|
2477
2208
|
browserExtensionStatus = Map<String, dynamic>.from(
|
|
@@ -2494,10 +2225,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2494
2225
|
desktopRuntime['devices'],
|
|
2495
2226
|
fallbackToMapValues: true,
|
|
2496
2227
|
);
|
|
2497
|
-
await _recordingBridge.refreshStatus();
|
|
2498
|
-
if (!_isCurrentAuthCycle(authCycle)) {
|
|
2499
|
-
return;
|
|
2500
|
-
}
|
|
2501
2228
|
deviceHealthStatus = await _healthBridge.getStatus();
|
|
2502
2229
|
if (!_isCurrentAuthCycle(authCycle)) {
|
|
2503
2230
|
return;
|
|
@@ -2847,69 +2574,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2847
2574
|
notifyListeners();
|
|
2848
2575
|
}
|
|
2849
2576
|
|
|
2850
|
-
Future<void> refreshRecordings() async {
|
|
2851
|
-
_logRecording('refresh.request');
|
|
2852
|
-
recordingSessions = _decodeModelList(
|
|
2853
|
-
'recordings',
|
|
2854
|
-
await _backendClient.fetchRecordingSessions(backendUrl),
|
|
2855
|
-
RecordingSessionItem.fromJson,
|
|
2856
|
-
);
|
|
2857
|
-
await _recordingBridge.refreshStatus();
|
|
2858
|
-
_logRecording(
|
|
2859
|
-
'refresh.done',
|
|
2860
|
-
data: <String, Object?>{
|
|
2861
|
-
'sessionStatuses': recordingSessions
|
|
2862
|
-
.take(5)
|
|
2863
|
-
.map((item) => '${item.id}:${item.status}')
|
|
2864
|
-
.join(','),
|
|
2865
|
-
},
|
|
2866
|
-
);
|
|
2867
|
-
_logRecordingConsistency('refreshRecordings');
|
|
2868
|
-
notifyListeners();
|
|
2869
|
-
}
|
|
2870
|
-
|
|
2871
|
-
Future<void> _refreshRecordingSessionById(String sessionId) async {
|
|
2872
|
-
final trimmed = sessionId.trim();
|
|
2873
|
-
if (trimmed.isEmpty || !isAuthenticated) {
|
|
2874
|
-
return;
|
|
2875
|
-
}
|
|
2876
|
-
|
|
2877
|
-
try {
|
|
2878
|
-
_logRecording(
|
|
2879
|
-
'refresh_by_id.request',
|
|
2880
|
-
data: <String, Object?>{'sessionId': trimmed},
|
|
2881
|
-
);
|
|
2882
|
-
final response = await _backendClient.fetchRecordingSession(
|
|
2883
|
-
backendUrl,
|
|
2884
|
-
trimmed,
|
|
2885
|
-
);
|
|
2886
|
-
final session = RecordingSessionItem.fromJson(
|
|
2887
|
-
_jsonMap(response['session']),
|
|
2888
|
-
);
|
|
2889
|
-
_upsertRecordingSession(session);
|
|
2890
|
-
|
|
2891
|
-
await _recordingBridge.refreshStatus();
|
|
2892
|
-
_logRecording(
|
|
2893
|
-
'refresh_by_id.done',
|
|
2894
|
-
data: <String, Object?>{
|
|
2895
|
-
'sessionId': trimmed,
|
|
2896
|
-
'status': session.status,
|
|
2897
|
-
'endedAt': session.endedAt?.toIso8601String(),
|
|
2898
|
-
},
|
|
2899
|
-
);
|
|
2900
|
-
_logRecordingConsistency('refreshRecordingSessionById');
|
|
2901
|
-
notifyListeners();
|
|
2902
|
-
} catch (error) {
|
|
2903
|
-
_logRecording(
|
|
2904
|
-
'refresh_by_id.fallback_full_refresh',
|
|
2905
|
-
data: <String, Object?>{'sessionId': trimmed},
|
|
2906
|
-
error: error,
|
|
2907
|
-
);
|
|
2908
|
-
// Session may have been pruned or unavailable; fall back to full refresh.
|
|
2909
|
-
await refreshRecordings();
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
|
|
2913
2577
|
Future<void> refreshDevices() async {
|
|
2914
2578
|
if (!isAuthenticated || isRefreshingDevices) {
|
|
2915
2579
|
return;
|
|
@@ -3769,25 +3433,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
3769
3433
|
);
|
|
3770
3434
|
}
|
|
3771
3435
|
|
|
3772
|
-
Uri resolveRecordingSourceAudioUri(String sessionId, String sourceKey) {
|
|
3773
|
-
final encodedSessionId = Uri.encodeComponent(sessionId);
|
|
3774
|
-
final encodedSourceKey = Uri.encodeComponent(sourceKey);
|
|
3775
|
-
return resolveRuntimeAsset(
|
|
3776
|
-
'/api/recordings/$encodedSessionId/audio/$encodedSourceKey',
|
|
3777
|
-
);
|
|
3778
|
-
}
|
|
3779
|
-
|
|
3780
|
-
Future<Uint8List> fetchRecordingSourceAudioBytes(
|
|
3781
|
-
String sessionId,
|
|
3782
|
-
String sourceKey,
|
|
3783
|
-
) {
|
|
3784
|
-
final encodedSessionId = Uri.encodeComponent(sessionId);
|
|
3785
|
-
final encodedSourceKey = Uri.encodeComponent(sourceKey);
|
|
3786
|
-
return fetchRuntimeAssetBytes(
|
|
3787
|
-
'/api/recordings/$encodedSessionId/audio/$encodedSourceKey',
|
|
3788
|
-
);
|
|
3789
|
-
}
|
|
3790
|
-
|
|
3791
3436
|
Future<Uint8List> fetchRuntimeAssetBytes(String path) {
|
|
3792
3437
|
final separator = path.contains('?') ? '&' : '?';
|
|
3793
3438
|
return _backendClient.fetchBinary(
|
|
@@ -3804,153 +3449,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
3804
3449
|
return <String, String>{'Cookie': cookie};
|
|
3805
3450
|
}
|
|
3806
3451
|
|
|
3807
|
-
Future<void> startWebRecording() async {
|
|
3808
|
-
await _startRecordingCapture(
|
|
3809
|
-
logKey: 'start_web',
|
|
3810
|
-
payload: buildWebScreenAndMicRecordingPayload(),
|
|
3811
|
-
startCapture: (sessionId) => _recordingBridge.startWebRecording(
|
|
3812
|
-
baseUrl: backendUrl,
|
|
3813
|
-
sessionId: sessionId,
|
|
3814
|
-
),
|
|
3815
|
-
);
|
|
3816
|
-
}
|
|
3817
|
-
|
|
3818
|
-
Future<void> startWebMicrophoneRecording() async {
|
|
3819
|
-
await _startRecordingCapture(
|
|
3820
|
-
logKey: 'start_web_mic_only',
|
|
3821
|
-
payload: buildWebMicrophoneRecordingPayload(),
|
|
3822
|
-
startCapture: (sessionId) => _recordingBridge.startWebMicrophoneRecording(
|
|
3823
|
-
baseUrl: backendUrl,
|
|
3824
|
-
sessionId: sessionId,
|
|
3825
|
-
),
|
|
3826
|
-
);
|
|
3827
|
-
}
|
|
3828
|
-
|
|
3829
|
-
Future<void> startBackgroundRecording() async {
|
|
3830
|
-
await _startRecordingCapture(
|
|
3831
|
-
logKey: 'start_background',
|
|
3832
|
-
payload: buildAndroidBackgroundRecordingPayload(),
|
|
3833
|
-
startCapture: (sessionId) => _recordingBridge.startBackgroundRecording(
|
|
3834
|
-
baseUrl: backendUrl,
|
|
3835
|
-
sessionCookie: _backendClient.sessionCookie ?? '',
|
|
3836
|
-
sessionId: sessionId,
|
|
3837
|
-
),
|
|
3838
|
-
);
|
|
3839
|
-
}
|
|
3840
|
-
|
|
3841
|
-
Future<void> startDesktopRecording() async {
|
|
3842
|
-
if (isLiveVoiceCaptureActive || isLiveVoiceCaptureStarting) {
|
|
3843
|
-
errorMessage =
|
|
3844
|
-
'Finish assistant push-to-talk before starting desktop recording.';
|
|
3845
|
-
notifyListeners();
|
|
3846
|
-
return;
|
|
3847
|
-
}
|
|
3848
|
-
if (!canStartDesktopRecording) {
|
|
3849
|
-
if (!isAuthenticated || requiresBackendUrlSetup) {
|
|
3850
|
-
errorMessage =
|
|
3851
|
-
'Sign in and finish backend setup before starting desktop recording.';
|
|
3852
|
-
notifyListeners();
|
|
3853
|
-
}
|
|
3854
|
-
return;
|
|
3855
|
-
}
|
|
3856
|
-
await _startRecordingCapture(
|
|
3857
|
-
logKey: 'start_desktop',
|
|
3858
|
-
payload: buildDesktopRecordingPayload(),
|
|
3859
|
-
startCapture: (sessionId) => _recordingBridge.startDesktopAudioRecording(
|
|
3860
|
-
baseUrl: backendUrl,
|
|
3861
|
-
sessionCookie: _backendClient.sessionCookie ?? '',
|
|
3862
|
-
sessionId: sessionId,
|
|
3863
|
-
autoShowToolbar: _desktopAutoShowFloatingToolbar,
|
|
3864
|
-
),
|
|
3865
|
-
);
|
|
3866
|
-
}
|
|
3867
|
-
|
|
3868
|
-
Future<void> pauseBackgroundRecording() async {
|
|
3869
|
-
try {
|
|
3870
|
-
_logRecording('pause_background.request');
|
|
3871
|
-
await _recordingBridge.pauseBackgroundRecording();
|
|
3872
|
-
_logRecording('pause_background.done');
|
|
3873
|
-
} catch (error) {
|
|
3874
|
-
_logRecording('pause_background.failed', error: error);
|
|
3875
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3876
|
-
notifyListeners();
|
|
3877
|
-
}
|
|
3878
|
-
}
|
|
3879
|
-
|
|
3880
|
-
Future<void> resumeBackgroundRecording() async {
|
|
3881
|
-
try {
|
|
3882
|
-
_logRecording('resume_background.request');
|
|
3883
|
-
await _recordingBridge.resumeBackgroundRecording();
|
|
3884
|
-
_logRecording('resume_background.done');
|
|
3885
|
-
} catch (error) {
|
|
3886
|
-
_logRecording('resume_background.failed', error: error);
|
|
3887
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3888
|
-
notifyListeners();
|
|
3889
|
-
}
|
|
3890
|
-
}
|
|
3891
|
-
|
|
3892
|
-
Future<void> pauseDesktopRecording() async {
|
|
3893
|
-
try {
|
|
3894
|
-
_logRecording('pause_desktop.request');
|
|
3895
|
-
await _recordingBridge.pauseDesktopRecording();
|
|
3896
|
-
_logRecording('pause_desktop.done');
|
|
3897
|
-
} catch (error) {
|
|
3898
|
-
_logRecording('pause_desktop.failed', error: error);
|
|
3899
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3900
|
-
notifyListeners();
|
|
3901
|
-
}
|
|
3902
|
-
}
|
|
3903
|
-
|
|
3904
|
-
Future<void> resumeDesktopRecording() async {
|
|
3905
|
-
try {
|
|
3906
|
-
_logRecording('resume_desktop.request');
|
|
3907
|
-
await _recordingBridge.resumeDesktopRecording();
|
|
3908
|
-
_logRecording('resume_desktop.done');
|
|
3909
|
-
} catch (error) {
|
|
3910
|
-
_logRecording('resume_desktop.failed', error: error);
|
|
3911
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3912
|
-
notifyListeners();
|
|
3913
|
-
}
|
|
3914
|
-
}
|
|
3915
|
-
|
|
3916
|
-
Future<void> showDesktopFloatingToolbar() async {
|
|
3917
|
-
try {
|
|
3918
|
-
_desktopFloatingToolbarPopupRequested = true;
|
|
3919
|
-
await _recordingBridge.showFloatingToolbar();
|
|
3920
|
-
} catch (error) {
|
|
3921
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3922
|
-
notifyListeners();
|
|
3923
|
-
}
|
|
3924
|
-
}
|
|
3925
|
-
|
|
3926
|
-
Future<void> hideDesktopFloatingToolbar() async {
|
|
3927
|
-
try {
|
|
3928
|
-
_desktopFloatingToolbarPopupRequested = false;
|
|
3929
|
-
await _recordingBridge.hideFloatingToolbar();
|
|
3930
|
-
} catch (error) {
|
|
3931
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3932
|
-
notifyListeners();
|
|
3933
|
-
}
|
|
3934
|
-
}
|
|
3935
|
-
|
|
3936
|
-
Future<void> openDesktopMicrophoneSettings() async {
|
|
3937
|
-
try {
|
|
3938
|
-
await _recordingBridge.openMicrophoneSettings();
|
|
3939
|
-
} catch (error) {
|
|
3940
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3941
|
-
notifyListeners();
|
|
3942
|
-
}
|
|
3943
|
-
}
|
|
3944
|
-
|
|
3945
|
-
Future<void> openDesktopSystemAudioSettings() async {
|
|
3946
|
-
try {
|
|
3947
|
-
await _recordingBridge.openSystemAudioSettings();
|
|
3948
|
-
} catch (error) {
|
|
3949
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
3950
|
-
notifyListeners();
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
|
|
3954
3452
|
Future<void> setDesktopClosePreference({
|
|
3955
3453
|
required bool askOnClose,
|
|
3956
3454
|
required bool keepRunningOnClose,
|
|
@@ -3962,12 +3460,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
3962
3460
|
notifyListeners();
|
|
3963
3461
|
}
|
|
3964
3462
|
|
|
3965
|
-
Future<void> setDesktopAutoShowFloatingToolbar(bool value) async {
|
|
3966
|
-
_desktopAutoShowFloatingToolbar = value;
|
|
3967
|
-
await _prefs?.setBool('desktop.autoShowFloatingToolbar', value);
|
|
3968
|
-
notifyListeners();
|
|
3969
|
-
}
|
|
3970
|
-
|
|
3971
3463
|
Future<void> setDesktopAssistantHotkeyEnabled(bool value) async {
|
|
3972
3464
|
_desktopAssistantHotkeyEnabled = value;
|
|
3973
3465
|
await _prefs?.setBool('desktop.assistantHotkeyEnabled', value);
|
|
@@ -4014,19 +3506,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4014
3506
|
}
|
|
4015
3507
|
}
|
|
4016
3508
|
|
|
4017
|
-
Future<void> setDesktopPassiveHistoryEnabled(bool value) async {
|
|
4018
|
-
final prefs = _prefs;
|
|
4019
|
-
if (prefs == null) {
|
|
4020
|
-
return;
|
|
4021
|
-
}
|
|
4022
|
-
try {
|
|
4023
|
-
await _desktopCompanion.setPassiveHistoryEnabled(value, prefs);
|
|
4024
|
-
} catch (error) {
|
|
4025
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
4026
|
-
notifyListeners();
|
|
4027
|
-
}
|
|
4028
|
-
}
|
|
4029
|
-
|
|
4030
3509
|
Future<void> rotateDesktopCompanionIdentity() async {
|
|
4031
3510
|
final prefs = _prefs;
|
|
4032
3511
|
if (prefs == null) {
|
|
@@ -4061,302 +3540,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4061
3540
|
}
|
|
4062
3541
|
}
|
|
4063
3542
|
|
|
4064
|
-
Future<void> setVoiceAssistantIncludeScreenContext(bool value) async {
|
|
4065
|
-
_voiceAssistantIncludeScreenContext =
|
|
4066
|
-
value && canCaptureVoiceAssistantScreenContext;
|
|
4067
|
-
await _prefs?.setBool(
|
|
4068
|
-
'voiceAssistant.includeScreenContext',
|
|
4069
|
-
_voiceAssistantIncludeScreenContext,
|
|
4070
|
-
);
|
|
4071
|
-
notifyListeners();
|
|
4072
|
-
}
|
|
4073
|
-
|
|
4074
|
-
Future<void> toggleVoiceAssistantScreenContext() {
|
|
4075
|
-
return setVoiceAssistantIncludeScreenContext(
|
|
4076
|
-
!voiceAssistantIncludeScreenContext,
|
|
4077
|
-
);
|
|
4078
|
-
}
|
|
4079
|
-
|
|
4080
|
-
void acknowledgeDesktopFloatingToolbarPopupRequest() {
|
|
4081
|
-
_desktopFloatingToolbarPopupRequested = false;
|
|
4082
|
-
}
|
|
4083
|
-
|
|
4084
|
-
Future<Map<String, String>> _captureVoiceAssistantScreenshotPayload() async {
|
|
4085
|
-
if (!_voiceAssistantIncludeScreenContext ||
|
|
4086
|
-
!canCaptureVoiceAssistantScreenContext) {
|
|
4087
|
-
return const <String, String>{};
|
|
4088
|
-
}
|
|
4089
|
-
|
|
4090
|
-
try {
|
|
4091
|
-
final capture = await _desktopScreenCapture.captureCurrentScreen();
|
|
4092
|
-
if (capture == null || capture.bytes.isEmpty) {
|
|
4093
|
-
return const <String, String>{};
|
|
4094
|
-
}
|
|
4095
|
-
final optimized = _optimizeVoiceAssistantScreenshotPayload(capture);
|
|
4096
|
-
if (optimized == null) {
|
|
4097
|
-
AppDiagnostics.log(
|
|
4098
|
-
'desktop.assistant',
|
|
4099
|
-
'screen_capture.optimize_failed',
|
|
4100
|
-
data: <String, Object?>{
|
|
4101
|
-
'mimeType': capture.mimeType,
|
|
4102
|
-
'originalByteLength': capture.bytes.length,
|
|
4103
|
-
},
|
|
4104
|
-
);
|
|
4105
|
-
return const <String, String>{};
|
|
4106
|
-
}
|
|
4107
|
-
AppDiagnostics.log(
|
|
4108
|
-
'desktop.assistant',
|
|
4109
|
-
'screen_capture.success',
|
|
4110
|
-
data: <String, Object?>{
|
|
4111
|
-
'mimeType': optimized.mimeType,
|
|
4112
|
-
'byteLength': optimized.bytes.length,
|
|
4113
|
-
'originalByteLength': capture.bytes.length,
|
|
4114
|
-
'resizedOrReencoded': optimized.resizedOrReencoded,
|
|
4115
|
-
},
|
|
4116
|
-
);
|
|
4117
|
-
return <String, String>{
|
|
4118
|
-
'screenshotMimeType': optimized.mimeType,
|
|
4119
|
-
'screenshotBase64': base64Encode(optimized.bytes),
|
|
4120
|
-
};
|
|
4121
|
-
} catch (error, stackTrace) {
|
|
4122
|
-
AppDiagnostics.log(
|
|
4123
|
-
'desktop.assistant',
|
|
4124
|
-
'screen_capture.failed',
|
|
4125
|
-
error: error,
|
|
4126
|
-
stackTrace: stackTrace,
|
|
4127
|
-
);
|
|
4128
|
-
return const <String, String>{};
|
|
4129
|
-
}
|
|
4130
|
-
}
|
|
4131
|
-
|
|
4132
|
-
Future<Map<String, String>> buildVoiceAssistantContextPayload() async {
|
|
4133
|
-
return _captureVoiceAssistantScreenshotPayload();
|
|
4134
|
-
}
|
|
4135
|
-
|
|
4136
|
-
_OptimizedScreenshotPayload? _optimizeVoiceAssistantScreenshotPayload(
|
|
4137
|
-
DesktopScreenCaptureResult capture,
|
|
4138
|
-
) {
|
|
4139
|
-
final sourceBytes = Uint8List.fromList(capture.bytes);
|
|
4140
|
-
final sourceMime = _normalizeScreenshotMimeType(capture.mimeType);
|
|
4141
|
-
final decoded = img.decodeImage(sourceBytes);
|
|
4142
|
-
if (decoded == null) {
|
|
4143
|
-
if (sourceBytes.length <= _voiceAssistantScreenshotMaxBytes) {
|
|
4144
|
-
return _OptimizedScreenshotPayload(
|
|
4145
|
-
bytes: sourceBytes,
|
|
4146
|
-
mimeType: sourceMime,
|
|
4147
|
-
resizedOrReencoded: false,
|
|
4148
|
-
);
|
|
4149
|
-
}
|
|
4150
|
-
return null;
|
|
4151
|
-
}
|
|
4152
|
-
|
|
4153
|
-
var workingImage = decoded;
|
|
4154
|
-
var transformed = false;
|
|
4155
|
-
if (workingImage.width > _voiceAssistantScreenshotMaxDimension ||
|
|
4156
|
-
workingImage.height > _voiceAssistantScreenshotMaxDimension) {
|
|
4157
|
-
final scale = math.min(
|
|
4158
|
-
_voiceAssistantScreenshotMaxDimension / workingImage.width,
|
|
4159
|
-
_voiceAssistantScreenshotMaxDimension / workingImage.height,
|
|
4160
|
-
);
|
|
4161
|
-
final nextWidth = math.max(1, (workingImage.width * scale).round());
|
|
4162
|
-
final nextHeight = math.max(1, (workingImage.height * scale).round());
|
|
4163
|
-
workingImage = img.copyResize(
|
|
4164
|
-
workingImage,
|
|
4165
|
-
width: nextWidth,
|
|
4166
|
-
height: nextHeight,
|
|
4167
|
-
interpolation: img.Interpolation.average,
|
|
4168
|
-
);
|
|
4169
|
-
transformed = true;
|
|
4170
|
-
}
|
|
4171
|
-
|
|
4172
|
-
if (!transformed &&
|
|
4173
|
-
sourceBytes.length <= _voiceAssistantScreenshotMaxBytes) {
|
|
4174
|
-
return _OptimizedScreenshotPayload(
|
|
4175
|
-
bytes: sourceBytes,
|
|
4176
|
-
mimeType: sourceMime,
|
|
4177
|
-
resizedOrReencoded: false,
|
|
4178
|
-
);
|
|
4179
|
-
}
|
|
4180
|
-
|
|
4181
|
-
final qualitySteps = <int>[84, 74, 64, 54, 46, 40];
|
|
4182
|
-
var bestBytes = Uint8List(0);
|
|
4183
|
-
for (var pass = 0; pass < qualitySteps.length; pass += 1) {
|
|
4184
|
-
final encoded = Uint8List.fromList(
|
|
4185
|
-
img.encodeJpg(workingImage, quality: qualitySteps[pass]),
|
|
4186
|
-
);
|
|
4187
|
-
if (bestBytes.isEmpty || encoded.length < bestBytes.length) {
|
|
4188
|
-
bestBytes = encoded;
|
|
4189
|
-
}
|
|
4190
|
-
if (encoded.length <= _voiceAssistantScreenshotMaxBytes) {
|
|
4191
|
-
return _OptimizedScreenshotPayload(
|
|
4192
|
-
bytes: encoded,
|
|
4193
|
-
mimeType: 'image/jpeg',
|
|
4194
|
-
resizedOrReencoded: true,
|
|
4195
|
-
);
|
|
4196
|
-
}
|
|
4197
|
-
if (pass % 2 == 1) {
|
|
4198
|
-
final nextWidth = math.max(1, (workingImage.width * 0.85).round());
|
|
4199
|
-
final nextHeight = math.max(1, (workingImage.height * 0.85).round());
|
|
4200
|
-
if (nextWidth == workingImage.width &&
|
|
4201
|
-
nextHeight == workingImage.height) {
|
|
4202
|
-
continue;
|
|
4203
|
-
}
|
|
4204
|
-
workingImage = img.copyResize(
|
|
4205
|
-
workingImage,
|
|
4206
|
-
width: nextWidth,
|
|
4207
|
-
height: nextHeight,
|
|
4208
|
-
interpolation: img.Interpolation.average,
|
|
4209
|
-
);
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
|
|
4213
|
-
if (bestBytes.isNotEmpty &&
|
|
4214
|
-
bestBytes.length <= _voiceAssistantScreenshotMaxBytes) {
|
|
4215
|
-
return _OptimizedScreenshotPayload(
|
|
4216
|
-
bytes: bestBytes,
|
|
4217
|
-
mimeType: 'image/jpeg',
|
|
4218
|
-
resizedOrReencoded: true,
|
|
4219
|
-
);
|
|
4220
|
-
}
|
|
4221
|
-
return null;
|
|
4222
|
-
}
|
|
4223
|
-
|
|
4224
|
-
String _normalizeScreenshotMimeType(String mimeType) {
|
|
4225
|
-
final normalized = mimeType.trim().toLowerCase();
|
|
4226
|
-
if (normalized.startsWith('image/')) {
|
|
4227
|
-
return normalized;
|
|
4228
|
-
}
|
|
4229
|
-
return 'image/png';
|
|
4230
|
-
}
|
|
4231
|
-
|
|
4232
|
-
Future<void> stopRecording({String stopReason = 'stopped'}) async {
|
|
4233
|
-
final sessionId = recordingRuntime.sessionId;
|
|
4234
|
-
if (sessionId == null || isStoppingRecording) {
|
|
4235
|
-
return;
|
|
4236
|
-
}
|
|
4237
|
-
final isAndroidBackgroundStop =
|
|
4238
|
-
recordingRuntime.supportsBackgroundMic &&
|
|
4239
|
-
!recordingRuntime.supportsScreenAndMic;
|
|
4240
|
-
isStoppingRecording = true;
|
|
4241
|
-
errorMessage = null;
|
|
4242
|
-
_logRecording(
|
|
4243
|
-
'stop.request',
|
|
4244
|
-
data: <String, Object?>{
|
|
4245
|
-
'sessionId': sessionId,
|
|
4246
|
-
'isAndroidBackgroundStop': isAndroidBackgroundStop,
|
|
4247
|
-
},
|
|
4248
|
-
);
|
|
4249
|
-
notifyListeners();
|
|
4250
|
-
try {
|
|
4251
|
-
_desktopFloatingToolbarPopupRequested = false;
|
|
4252
|
-
await _recordingBridge.stopActiveRecording();
|
|
4253
|
-
if (isAndroidBackgroundStop) {
|
|
4254
|
-
await Future<void>.delayed(const Duration(milliseconds: 600));
|
|
4255
|
-
} else {
|
|
4256
|
-
await _backendClient.finalizeRecordingSession(
|
|
4257
|
-
backendUrl,
|
|
4258
|
-
sessionId,
|
|
4259
|
-
stopReason: stopReason,
|
|
4260
|
-
);
|
|
4261
|
-
}
|
|
4262
|
-
await refreshRecordings();
|
|
4263
|
-
_logRecording(
|
|
4264
|
-
'stop.done',
|
|
4265
|
-
data: <String, Object?>{'sessionId': sessionId},
|
|
4266
|
-
);
|
|
4267
|
-
} catch (error) {
|
|
4268
|
-
_logRecording(
|
|
4269
|
-
'stop.failed',
|
|
4270
|
-
data: <String, Object?>{
|
|
4271
|
-
'sessionId': sessionId,
|
|
4272
|
-
'isAndroidBackgroundStop': isAndroidBackgroundStop,
|
|
4273
|
-
},
|
|
4274
|
-
error: error,
|
|
4275
|
-
);
|
|
4276
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
4277
|
-
notifyListeners();
|
|
4278
|
-
} finally {
|
|
4279
|
-
isStoppingRecording = false;
|
|
4280
|
-
notifyListeners();
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
|
|
4284
|
-
Future<void> retryRecording(String sessionId) async {
|
|
4285
|
-
try {
|
|
4286
|
-
await _backendClient.retryRecordingSession(backendUrl, sessionId);
|
|
4287
|
-
await refreshRecordings();
|
|
4288
|
-
} catch (error) {
|
|
4289
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
4290
|
-
notifyListeners();
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
|
|
4294
|
-
Future<void> deleteRecordingSegment(String sessionId, int segmentId) async {
|
|
4295
|
-
try {
|
|
4296
|
-
errorMessage = null;
|
|
4297
|
-
final response = await _backendClient.deleteRecordingTranscriptSegment(
|
|
4298
|
-
backendUrl,
|
|
4299
|
-
sessionId,
|
|
4300
|
-
segmentId,
|
|
4301
|
-
);
|
|
4302
|
-
final session = RecordingSessionItem.fromJson(
|
|
4303
|
-
_jsonMap(response['session']),
|
|
4304
|
-
);
|
|
4305
|
-
_upsertRecordingSession(session);
|
|
4306
|
-
notifyListeners();
|
|
4307
|
-
} catch (error) {
|
|
4308
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
4309
|
-
notifyListeners();
|
|
4310
|
-
}
|
|
4311
|
-
}
|
|
4312
|
-
|
|
4313
|
-
Future<void> deleteRecordingSession(String sessionId) async {
|
|
4314
|
-
try {
|
|
4315
|
-
errorMessage = null;
|
|
4316
|
-
await _backendClient.deleteRecordingSession(backendUrl, sessionId);
|
|
4317
|
-
_removeRecordingSession(sessionId);
|
|
4318
|
-
notifyListeners();
|
|
4319
|
-
} catch (error) {
|
|
4320
|
-
errorMessage = _friendlyErrorMessage(error);
|
|
4321
|
-
notifyListeners();
|
|
4322
|
-
}
|
|
4323
|
-
}
|
|
4324
|
-
|
|
4325
|
-
Future<VoiceAssistantTurnResult> runVoiceAssistantTurn({
|
|
4326
|
-
required String sessionId,
|
|
4327
|
-
String? ttsProvider,
|
|
4328
|
-
String? ttsVoice,
|
|
4329
|
-
String? ttsModel,
|
|
4330
|
-
}) async {
|
|
4331
|
-
final screenshotPayload = await buildVoiceAssistantContextPayload();
|
|
4332
|
-
final response = await _backendClient.runVoiceAssistantTurn(
|
|
4333
|
-
backendUrl,
|
|
4334
|
-
sessionId: sessionId,
|
|
4335
|
-
ttsProvider:
|
|
4336
|
-
ttsProvider?.trim().ifEmpty(voiceTtsProvider) ?? voiceTtsProvider,
|
|
4337
|
-
ttsVoice: ttsVoice?.trim().ifEmpty(voiceTtsVoice) ?? voiceTtsVoice,
|
|
4338
|
-
ttsModel: ttsModel?.trim().ifEmpty(voiceTtsModel) ?? voiceTtsModel,
|
|
4339
|
-
agentId: _scopedAgentId,
|
|
4340
|
-
screenshotBase64: screenshotPayload['screenshotBase64'],
|
|
4341
|
-
screenshotMimeType: screenshotPayload['screenshotMimeType'],
|
|
4342
|
-
);
|
|
4343
|
-
|
|
4344
|
-
final result = VoiceAssistantTurnResult.fromJson(response);
|
|
4345
|
-
_upsertRecordingSession(result.session);
|
|
4346
|
-
|
|
4347
|
-
if (result.transcript.trim().isNotEmpty) {
|
|
4348
|
-
_appendUserChatMessage(result.transcript, platform: 'voice_assistant');
|
|
4349
|
-
}
|
|
4350
|
-
if (result.replyText.trim().isNotEmpty) {
|
|
4351
|
-
_appendAssistantChatMessage(
|
|
4352
|
-
result.replyText,
|
|
4353
|
-
platform: 'voice_assistant',
|
|
4354
|
-
);
|
|
4355
|
-
}
|
|
4356
|
-
notifyListeners();
|
|
4357
|
-
return result;
|
|
4358
|
-
}
|
|
4359
|
-
|
|
4360
3543
|
Future<bool> _ensureSocketReady({
|
|
4361
3544
|
Duration timeout = const Duration(seconds: 5),
|
|
4362
3545
|
}) async {
|
|
@@ -4556,11 +3739,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4556
3739
|
}
|
|
4557
3740
|
|
|
4558
3741
|
Future<void> startLiveVoiceCapture() async {
|
|
4559
|
-
if (recordingRuntime.active || isStartingRecording || isStoppingRecording) {
|
|
4560
|
-
throw StateError(
|
|
4561
|
-
'Stop recording before starting the assistant push-to-talk flow.',
|
|
4562
|
-
);
|
|
4563
|
-
}
|
|
4564
3742
|
if (_isStartingLiveVoice || _isStoppingLiveVoice) {
|
|
4565
3743
|
return;
|
|
4566
3744
|
}
|
|
@@ -4726,7 +3904,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4726
3904
|
);
|
|
4727
3905
|
return;
|
|
4728
3906
|
}
|
|
4729
|
-
final screenshotPayload = await buildVoiceAssistantContextPayload();
|
|
4730
3907
|
AppDiagnostics.log(
|
|
4731
3908
|
'desktop.assistant',
|
|
4732
3909
|
'ptt.capture_committing',
|
|
@@ -4737,12 +3914,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4737
3914
|
);
|
|
4738
3915
|
_liveVoiceFinalSequence = _liveVoiceBufferedChunks.length - 1;
|
|
4739
3916
|
_liveVoiceCommitPending = true;
|
|
4740
|
-
_liveVoicePendingCommitPayload = <String, dynamic>{
|
|
4741
|
-
if ((screenshotPayload['screenshotBase64'] ?? '').isNotEmpty)
|
|
4742
|
-
'screenshotBase64': screenshotPayload['screenshotBase64'],
|
|
4743
|
-
if ((screenshotPayload['screenshotMimeType'] ?? '').isNotEmpty)
|
|
4744
|
-
'screenshotMimeType': screenshotPayload['screenshotMimeType'],
|
|
4745
|
-
};
|
|
3917
|
+
_liveVoicePendingCommitPayload = <String, dynamic>{};
|
|
4746
3918
|
_setLiveVoiceRecoveryWindow();
|
|
4747
3919
|
voiceAssistantLiveState = voiceAssistantLiveState.copyWith(
|
|
4748
3920
|
state: 'transcribing',
|
|
@@ -4992,10 +4164,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4992
4164
|
required String defaultChatModel,
|
|
4993
4165
|
required String defaultSubagentModel,
|
|
4994
4166
|
required String defaultSpeechModel,
|
|
4995
|
-
required String defaultRecordingTranscriptionProvider,
|
|
4996
|
-
required String defaultRecordingTranscriptionModel,
|
|
4997
|
-
required String defaultRecordingSummaryProvider,
|
|
4998
|
-
required String defaultRecordingSummaryModel,
|
|
4999
4167
|
required String fallbackModel,
|
|
5000
4168
|
required String voiceSttProvider,
|
|
5001
4169
|
required String voiceSttModel,
|
|
@@ -5025,12 +4193,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5025
4193
|
'default_chat_model': defaultChatModel,
|
|
5026
4194
|
'default_subagent_model': defaultSubagentModel,
|
|
5027
4195
|
'default_speech_model': defaultSpeechModel,
|
|
5028
|
-
'default_recording_transcription_provider':
|
|
5029
|
-
defaultRecordingTranscriptionProvider,
|
|
5030
|
-
'default_recording_transcription_model':
|
|
5031
|
-
defaultRecordingTranscriptionModel,
|
|
5032
|
-
'default_recording_summary_provider': defaultRecordingSummaryProvider,
|
|
5033
|
-
'default_recording_summary_model': defaultRecordingSummaryModel,
|
|
5034
4196
|
'fallback_model_id': fallbackModel,
|
|
5035
4197
|
'voice_stt_provider': voiceSttProvider,
|
|
5036
4198
|
'voice_stt_model': voiceSttModel,
|
|
@@ -6812,24 +5974,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
6812
5974
|
String get defaultSpeechModel =>
|
|
6813
5975
|
settings['default_speech_model']?.toString() ?? 'auto';
|
|
6814
5976
|
|
|
6815
|
-
String get defaultRecordingTranscriptionModel =>
|
|
6816
|
-
settings['default_recording_transcription_model']?.toString() ?? 'nova-3';
|
|
6817
|
-
|
|
6818
|
-
String get defaultRecordingTranscriptionProvider => _settingString(
|
|
6819
|
-
'default_recording_transcription_provider',
|
|
6820
|
-
'deepgram',
|
|
6821
|
-
lowercase: true,
|
|
6822
|
-
);
|
|
6823
|
-
|
|
6824
|
-
String get defaultRecordingSummaryModel =>
|
|
6825
|
-
settings['default_recording_summary_model']?.toString() ?? 'auto';
|
|
6826
|
-
|
|
6827
|
-
String get defaultRecordingSummaryProvider => _settingString(
|
|
6828
|
-
'default_recording_summary_provider',
|
|
6829
|
-
'auto',
|
|
6830
|
-
lowercase: true,
|
|
6831
|
-
);
|
|
6832
|
-
|
|
6833
5977
|
String get fallbackModel =>
|
|
6834
5978
|
settings['fallback_model_id']?.toString() ??
|
|
6835
5979
|
_firstAvailableModelId(supportedModels);
|
|
@@ -7173,15 +6317,6 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7173
6317
|
payload['error']?.toString() ?? 'Messaging error. Please try again.';
|
|
7174
6318
|
notifyListeners();
|
|
7175
6319
|
});
|
|
7176
|
-
socket.on('recordings:updated', (dynamic data) {
|
|
7177
|
-
final payload = _jsonMap(data);
|
|
7178
|
-
final sessionId = payload['sessionId']?.toString() ?? '';
|
|
7179
|
-
if (sessionId.isEmpty) {
|
|
7180
|
-
unawaited(refreshRecordings());
|
|
7181
|
-
return;
|
|
7182
|
-
}
|
|
7183
|
-
unawaited(_refreshRecordingSessionById(sessionId));
|
|
7184
|
-
});
|
|
7185
6320
|
socket.on('timeline:updated', (dynamic _) {
|
|
7186
6321
|
unawaited(refreshTimeline());
|
|
7187
6322
|
});
|