neoagent 3.0.1-beta.9 → 3.1.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 -10
- package/README.md +12 -3
- package/docs/automation.md +37 -0
- package/docs/benchmarking.md +102 -0
- package/docs/billing.md +34 -8
- package/docs/configuration.md +11 -2
- package/docs/getting-started.md +10 -8
- package/docs/operations.md +1 -1
- package/flutter_app/lib/main.dart +3 -0
- package/flutter_app/lib/main_account_settings.dart +138 -0
- package/flutter_app/lib/main_app_shell.dart +38 -13
- package/flutter_app/lib/main_billing.dart +1465 -0
- package/flutter_app/lib/main_chat.dart +1612 -214
- package/flutter_app/lib/main_controller.dart +398 -26
- package/flutter_app/lib/main_devices.dart +293 -207
- package/flutter_app/lib/main_models.dart +142 -0
- package/flutter_app/lib/main_navigation.dart +19 -1
- package/flutter_app/lib/main_operations.dart +288 -9
- package/flutter_app/lib/main_settings.dart +510 -300
- package/flutter_app/lib/main_shared.dart +2 -0
- package/flutter_app/lib/main_timeline.dart +1378 -0
- package/flutter_app/lib/src/backend_client.dart +149 -19
- package/flutter_app/lib/src/desktop_companion_actions.dart +132 -21
- package/flutter_app/lib/src/desktop_companion_io.dart +65 -1
- package/flutter_app/lib/src/desktop_companion_stub.dart +12 -0
- package/flutter_app/lib/src/desktop_ocr_bridge.dart +2 -0
- package/flutter_app/lib/src/desktop_ocr_bridge_io.dart +125 -0
- package/flutter_app/lib/src/desktop_ocr_bridge_stub.dart +30 -0
- package/flutter_app/lib/src/desktop_passive_history.dart +332 -0
- package/flutter_app/lib/src/recording_bridge_io.dart +80 -72
- package/flutter_app/lib/src/recording_bridge_web.dart +127 -114
- package/flutter_app/lib/src/recording_chunk_queue.dart +149 -0
- package/flutter_app/lib/src/recording_chunk_queue_io.dart +182 -0
- package/flutter_app/lib/src/recording_payloads.dart +9 -0
- package/flutter_app/macos/Runner/AppDelegate.swift +25 -0
- package/flutter_app/windows/runner/flutter_window.cpp +75 -0
- package/landing/index.html +3 -3
- package/lib/manager.js +184 -66
- package/package.json +4 -1
- package/server/admin/access.js +12 -7
- package/server/admin/admin.js +436 -10
- package/server/admin/billing.js +158 -35
- package/server/admin/index.html +72 -2
- package/server/admin/users.js +15 -15
- package/server/db/database.js +125 -20
- package/server/http/routes.js +1 -0
- package/server/http/static.js +4 -2
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/canvaskit/wimp.js.symbols +8475 -8467
- package/server/public/canvaskit/wimp.wasm +0 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +91077 -87037
- package/server/routes/account.js +53 -0
- package/server/routes/admin.js +345 -64
- package/server/routes/agents.js +203 -21
- package/server/routes/billing.js +5 -0
- package/server/routes/browser.js +8 -1
- package/server/routes/recordings.js +96 -6
- package/server/routes/screenHistory.js +140 -2
- package/server/routes/timeline.js +43 -0
- package/server/services/account/erasure.js +263 -0
- package/server/services/ai/hooks.js +4 -1
- package/server/services/ai/loop/agent_engine_core.js +8 -1
- package/server/services/ai/loop/blank_recovery.js +36 -0
- package/server/services/ai/loop/conversation_loop.js +166 -33
- package/server/services/ai/messagingFallback.js +22 -0
- package/server/services/ai/rate_limits.js +28 -5
- package/server/services/ai/systemPrompt.js +6 -5
- package/server/services/ai/taskAnalysis.js +2 -0
- package/server/services/ai/toolEvidence.js +15 -0
- package/server/services/ai/toolResult.js +40 -0
- package/server/services/ai/tools.js +163 -4
- package/server/services/android/controller.js +6 -2
- package/server/services/billing/plans.js +2 -1
- package/server/services/browser/anti_detection.js +192 -0
- package/server/services/browser/controller.js +180 -54
- package/server/services/desktop/auth.js +3 -0
- package/server/services/desktop/registry.js +50 -2
- package/server/services/integrations/google/calendar.js +22 -14
- package/server/services/manager.js +12 -42
- package/server/services/memory/ingestion_chunking.js +268 -0
- package/server/services/messaging/telnyx.js +9 -8
- package/server/services/recordings/manager.js +60 -27
- package/server/services/runtime/docker-vm-manager.js +157 -266
- package/server/services/runtime/guest_bootstrap.js +17 -5
- package/server/services/runtime/guest_image.js +188 -0
- package/server/services/runtime/manager.js +0 -1
- package/server/services/runtime/validation.js +3 -8
- package/server/services/social_video/service.js +60 -10
- package/server/services/tasks/runtime.js +234 -9
- package/server/services/tasks/task_repository.js +13 -0
- package/server/services/timeline/service.js +558 -0
- package/server/services/wearable/gateway.js +1 -1
- package/server/services/websocket.js +21 -3
- package/server/services/desktop/screenRecorder.js +0 -292
- package/server/services/desktop/screen_recorder_support.js +0 -46
|
@@ -47,6 +47,8 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
47
47
|
StreamSubscription<List<ConnectivityResult>>? _connectivitySubscription;
|
|
48
48
|
bool _connectivityPluginAvailable = true;
|
|
49
49
|
static const int _maxVisibleLogs = 400;
|
|
50
|
+
static const int _maxToolEvents =
|
|
51
|
+
500; // separate list from _maxVisibleLogs (chat diagnostics)
|
|
50
52
|
|
|
51
53
|
static const String _configuredBackendUrl = String.fromEnvironment(
|
|
52
54
|
'NEOAGENT_BACKEND_URL',
|
|
@@ -66,6 +68,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
66
68
|
final Map<String, DateTime> _manualRunCooldowns = <String, DateTime>{};
|
|
67
69
|
static const Duration _manualRunCooldownDuration = Duration(seconds: 10);
|
|
68
70
|
static const Duration _homeWidgetSyncCooldown = Duration(seconds: 5);
|
|
71
|
+
static const int _chatHistoryPageSize = 20;
|
|
69
72
|
DateTime? _lastHomeWidgetSyncAt;
|
|
70
73
|
int _authCycle = 0;
|
|
71
74
|
bool _isPollingQrLogin = false;
|
|
@@ -98,6 +101,8 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
98
101
|
bool isApprovingQrLogin = false;
|
|
99
102
|
bool isCheckingAppUpdate = false;
|
|
100
103
|
bool isOpeningAppUpdate = false;
|
|
104
|
+
bool isLoadingBilling = false;
|
|
105
|
+
bool showBillingSection = false;
|
|
101
106
|
bool socketConnected = false;
|
|
102
107
|
bool hasNetworkConnection = true;
|
|
103
108
|
bool networkStatusKnown = false;
|
|
@@ -142,12 +147,18 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
142
147
|
List<RecordingSessionItem> recordingSessions = const <RecordingSessionItem>[];
|
|
143
148
|
|
|
144
149
|
List<ChatEntry> chatMessages = const <ChatEntry>[];
|
|
150
|
+
bool chatHistoryHasMore = false;
|
|
151
|
+
bool isLoadingOlderChatHistory = false;
|
|
145
152
|
List<AgentProfile> agentProfiles = const <AgentProfile>[];
|
|
146
153
|
String? selectedAgentId;
|
|
147
154
|
List<ModelMeta> supportedModels = const <ModelMeta>[];
|
|
148
155
|
List<AiProviderMeta> aiProviders = const <AiProviderMeta>[];
|
|
149
156
|
List<RunSummary> recentRuns = const <RunSummary>[];
|
|
157
|
+
List<TimelineEventItem> timelineItems = const <TimelineEventItem>[];
|
|
150
158
|
TokenUsageSnapshot? tokenUsage;
|
|
159
|
+
Map<String, dynamic>? billingSubscription;
|
|
160
|
+
List<Map<String, dynamic>> billingPlans = const <Map<String, dynamic>>[];
|
|
161
|
+
List<Map<String, dynamic>> billingInvoices = const <Map<String, dynamic>>[];
|
|
151
162
|
UpdateStatusSnapshot updateStatus = const UpdateStatusSnapshot();
|
|
152
163
|
List<LogEntry> logs = const <LogEntry>[];
|
|
153
164
|
Map<String, MessagingPlatformStatus> messagingStatuses =
|
|
@@ -158,6 +169,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
158
169
|
MessagingQrState? pendingMessagingQr;
|
|
159
170
|
ToolApprovalRequest? pendingApproval;
|
|
160
171
|
final List<BlockedSenderNotice> _blockedSenderQueue = <BlockedSenderNotice>[];
|
|
172
|
+
final Set<String> _ignoredChats = <String>{};
|
|
161
173
|
List<SkillItem> skills = const <SkillItem>[];
|
|
162
174
|
List<StoreSkillItem> storeSkills = const <StoreSkillItem>[];
|
|
163
175
|
List<OfficialIntegrationItem> officialIntegrations =
|
|
@@ -199,6 +211,10 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
199
211
|
String? _pendingChatDraft;
|
|
200
212
|
List<SharedChatAttachment> _pendingSharedChatAttachments =
|
|
201
213
|
const <SharedChatAttachment>[];
|
|
214
|
+
String? _chatHistoryBeforeCreatedAt;
|
|
215
|
+
String? _chatHistoryBeforeSource;
|
|
216
|
+
String? _chatHistoryBeforeId;
|
|
217
|
+
String? _requestedRunFocusId;
|
|
202
218
|
|
|
203
219
|
ActiveRunState? activeRun;
|
|
204
220
|
List<ToolEventItem> toolEvents = const <ToolEventItem>[];
|
|
@@ -227,14 +243,23 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
227
243
|
bool _desktopKeepRunningOnClose = true;
|
|
228
244
|
bool _desktopAutoShowFloatingToolbar = true;
|
|
229
245
|
bool _desktopAssistantHotkeyEnabled = true;
|
|
246
|
+
bool isRefreshingTimeline = false;
|
|
247
|
+
Set<String> selectedTimelineSources = <String>{'screen', 'tasks', 'runs'};
|
|
230
248
|
|
|
231
249
|
bool get desktopCompanionEnabled => _desktopCompanion.enabled;
|
|
250
|
+
bool get desktopPassiveHistoryEnabled =>
|
|
251
|
+
_desktopCompanion.passiveHistoryEnabled;
|
|
232
252
|
bool get isLauncherMode => appMode == NeoAgentAppMode.launcher;
|
|
233
253
|
bool get desktopCompanionConnected => _desktopCompanion.connected;
|
|
234
254
|
bool get desktopCompanionConnecting => _desktopCompanion.connecting;
|
|
235
255
|
bool get desktopCompanionPaused => _desktopCompanion.paused;
|
|
236
256
|
String get desktopCompanionLabel => _desktopCompanion.label;
|
|
237
257
|
String? get desktopCompanionErrorMessage => _desktopCompanion.errorMessage;
|
|
258
|
+
String? get desktopPassiveHistoryLastUploadedAt =>
|
|
259
|
+
_desktopCompanion.passiveHistoryLastUploadedAt;
|
|
260
|
+
String? get desktopPassiveHistoryLastError =>
|
|
261
|
+
_desktopCompanion.passiveHistoryLastError;
|
|
262
|
+
String? get requestedRunFocusId => _requestedRunFocusId;
|
|
238
263
|
Map<String, Object?> get desktopCompanionStatus => _desktopCompanion.status;
|
|
239
264
|
|
|
240
265
|
bool get hasLiveRun => isSendingMessage && activeRun != null;
|
|
@@ -494,6 +519,103 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
494
519
|
];
|
|
495
520
|
}
|
|
496
521
|
|
|
522
|
+
void _resetChatHistoryPagination() {
|
|
523
|
+
chatHistoryHasMore = false;
|
|
524
|
+
isLoadingOlderChatHistory = false;
|
|
525
|
+
_chatHistoryBeforeCreatedAt = null;
|
|
526
|
+
_chatHistoryBeforeSource = null;
|
|
527
|
+
_chatHistoryBeforeId = null;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
void _applyChatHistoryCursor(Map<String, dynamic> history) {
|
|
531
|
+
chatHistoryHasMore = history['hasMore'] == true;
|
|
532
|
+
_chatHistoryBeforeCreatedAt = _optionalIdFrom(
|
|
533
|
+
history['nextBeforeCreatedAt'],
|
|
534
|
+
);
|
|
535
|
+
_chatHistoryBeforeSource = _optionalIdFrom(history['nextBeforeSource']);
|
|
536
|
+
_chatHistoryBeforeId = _optionalIdFrom(history['nextBeforeId']);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
String _chatEntryKey(ChatEntry entry) {
|
|
540
|
+
final stableId = entry.id.trim();
|
|
541
|
+
if (stableId.isNotEmpty) {
|
|
542
|
+
return [
|
|
543
|
+
stableId,
|
|
544
|
+
entry.platform,
|
|
545
|
+
entry.role,
|
|
546
|
+
entry.createdAt.toIso8601String(),
|
|
547
|
+
].join('|');
|
|
548
|
+
}
|
|
549
|
+
return [
|
|
550
|
+
entry.role,
|
|
551
|
+
entry.platform,
|
|
552
|
+
entry.createdAt.toIso8601String(),
|
|
553
|
+
entry.content,
|
|
554
|
+
].join('|');
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
List<ChatEntry> _chatHistoryEntriesFromResponse(
|
|
558
|
+
Map<String, dynamic> history,
|
|
559
|
+
) {
|
|
560
|
+
return _decodeModelList(
|
|
561
|
+
'chat_history',
|
|
562
|
+
history['messages'],
|
|
563
|
+
ChatEntry.fromJson,
|
|
564
|
+
fallbackToMapValues: true,
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
Future<bool> loadOlderChatHistory() async {
|
|
569
|
+
if (!isAuthenticated ||
|
|
570
|
+
isLoadingOlderChatHistory ||
|
|
571
|
+
!chatHistoryHasMore ||
|
|
572
|
+
_chatHistoryBeforeCreatedAt == null ||
|
|
573
|
+
_chatHistoryBeforeSource == null ||
|
|
574
|
+
_chatHistoryBeforeId == null) {
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
final agentId = _scopedAgentId;
|
|
579
|
+
final beforeCreatedAt = _chatHistoryBeforeCreatedAt;
|
|
580
|
+
final beforeSource = _chatHistoryBeforeSource;
|
|
581
|
+
final beforeId = _chatHistoryBeforeId;
|
|
582
|
+
isLoadingOlderChatHistory = true;
|
|
583
|
+
notifyListeners();
|
|
584
|
+
try {
|
|
585
|
+
final history = await _backendClient.fetchChatHistory(
|
|
586
|
+
backendUrl,
|
|
587
|
+
agentId: agentId,
|
|
588
|
+
limit: _chatHistoryPageSize,
|
|
589
|
+
beforeCreatedAt: beforeCreatedAt,
|
|
590
|
+
beforeSource: beforeSource,
|
|
591
|
+
beforeId: beforeId,
|
|
592
|
+
);
|
|
593
|
+
if (agentId != _scopedAgentId) {
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
final olderMessages = _chatHistoryEntriesFromResponse(history);
|
|
597
|
+
_applyChatHistoryCursor(history);
|
|
598
|
+
if (olderMessages.isEmpty) {
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
final existingKeys = chatMessages.map(_chatEntryKey).toSet();
|
|
602
|
+
final prepended = olderMessages
|
|
603
|
+
.where((entry) => existingKeys.add(_chatEntryKey(entry)))
|
|
604
|
+
.toList(growable: false);
|
|
605
|
+
if (prepended.isEmpty) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
chatMessages = <ChatEntry>[...prepended, ...chatMessages];
|
|
609
|
+
return true;
|
|
610
|
+
} catch (error) {
|
|
611
|
+
errorMessage = _friendlyErrorMessage(error);
|
|
612
|
+
return false;
|
|
613
|
+
} finally {
|
|
614
|
+
isLoadingOlderChatHistory = false;
|
|
615
|
+
notifyListeners();
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
497
619
|
String _settingString(String key, String fallback, {bool lowercase = false}) {
|
|
498
620
|
final value = settings[key]?.toString().trim() ?? '';
|
|
499
621
|
if (value.isEmpty) {
|
|
@@ -631,6 +753,8 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
631
753
|
BlockedSenderNotice? get pendingBlockedSenderNotice =>
|
|
632
754
|
_blockedSenderQueue.isEmpty ? null : _blockedSenderQueue.first;
|
|
633
755
|
|
|
756
|
+
List<String> get ignoredChats => _ignoredChats.toList();
|
|
757
|
+
|
|
634
758
|
void _handleRecordingBridgeChanged() {
|
|
635
759
|
_logRecording('bridge.changed');
|
|
636
760
|
notifyListeners();
|
|
@@ -716,6 +840,9 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
716
840
|
|
|
717
841
|
Future<void> bootstrap() async {
|
|
718
842
|
_prefs = await SharedPreferences.getInstance();
|
|
843
|
+
_ignoredChats.addAll(
|
|
844
|
+
_prefs?.getStringList('messaging.ignored_chats') ?? <String>[],
|
|
845
|
+
);
|
|
719
846
|
await _desktopCompanion.bootstrap(_prefs!);
|
|
720
847
|
final configured = _configuredBackendUrl.trim();
|
|
721
848
|
final savedBackendUrl = _prefs?.getString('backend_url')?.trim() ?? '';
|
|
@@ -1552,11 +1679,14 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1552
1679
|
linkedAuthProviders = const <LinkedAuthProviderItem>[];
|
|
1553
1680
|
settings = const <String, dynamic>{};
|
|
1554
1681
|
chatMessages = const <ChatEntry>[];
|
|
1682
|
+
_resetChatHistoryPagination();
|
|
1555
1683
|
agentProfiles = const <AgentProfile>[];
|
|
1556
1684
|
selectedAgentId = null;
|
|
1557
1685
|
supportedModels = const <ModelMeta>[];
|
|
1558
1686
|
aiProviders = const <AiProviderMeta>[];
|
|
1559
1687
|
recentRuns = const <RunSummary>[];
|
|
1688
|
+
timelineItems = const <TimelineEventItem>[];
|
|
1689
|
+
isRefreshingTimeline = false;
|
|
1560
1690
|
tokenUsage = null;
|
|
1561
1691
|
updateStatus = const UpdateStatusSnapshot();
|
|
1562
1692
|
_serverLogs = const <LogEntry>[];
|
|
@@ -1680,12 +1810,34 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1680
1810
|
if (section == AppSection.devices) {
|
|
1681
1811
|
unawaited(refreshDevices());
|
|
1682
1812
|
}
|
|
1813
|
+
if (section == AppSection.timeline) {
|
|
1814
|
+
unawaited(refreshTimeline());
|
|
1815
|
+
}
|
|
1683
1816
|
if (section == AppSection.accountSettings) {
|
|
1684
1817
|
unawaited(refreshAccountSettings());
|
|
1685
1818
|
}
|
|
1819
|
+
if (section == AppSection.billing) {
|
|
1820
|
+
unawaited(refreshBilling());
|
|
1821
|
+
}
|
|
1686
1822
|
notifyListeners();
|
|
1687
1823
|
}
|
|
1688
1824
|
|
|
1825
|
+
Future<void> openRunDetails(String runId) async {
|
|
1826
|
+
final normalized = runId.trim();
|
|
1827
|
+
if (normalized.isEmpty) {
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
_requestedRunFocusId = normalized;
|
|
1831
|
+
setSelectedSection(AppSection.runs);
|
|
1832
|
+
await refreshRunsOnly();
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
void clearRequestedRunFocus(String runId) {
|
|
1836
|
+
if (_requestedRunFocusId == runId) {
|
|
1837
|
+
_requestedRunFocusId = null;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1689
1841
|
void _ensureSelectedAgent() {
|
|
1690
1842
|
if (agentProfiles.isEmpty) {
|
|
1691
1843
|
selectedAgentId = null;
|
|
@@ -1711,6 +1863,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1711
1863
|
}
|
|
1712
1864
|
selectedAgentId = id;
|
|
1713
1865
|
chatMessages = const <ChatEntry>[];
|
|
1866
|
+
_resetChatHistoryPagination();
|
|
1714
1867
|
recentRuns = const <RunSummary>[];
|
|
1715
1868
|
messagingStatuses = const <String, MessagingPlatformStatus>{};
|
|
1716
1869
|
messagingMessages = const <MessagingMessage>[];
|
|
@@ -1914,14 +2067,20 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1914
2067
|
|
|
1915
2068
|
Future<void> allowMessagingSuggestion(
|
|
1916
2069
|
String platform,
|
|
1917
|
-
QuickAllowSuggestion suggestion,
|
|
1918
|
-
|
|
2070
|
+
QuickAllowSuggestion suggestion, {
|
|
2071
|
+
String? chatId,
|
|
2072
|
+
}) async {
|
|
1919
2073
|
try {
|
|
1920
2074
|
final nextPolicy = _policyWithAddedRule(
|
|
1921
2075
|
currentMessagingAccessPolicy(platform),
|
|
1922
2076
|
suggestion,
|
|
1923
2077
|
);
|
|
1924
2078
|
await saveMessagingAccessPolicy(platform, nextPolicy);
|
|
2079
|
+
if (chatId != null) {
|
|
2080
|
+
_blockedSenderQueue.removeWhere(
|
|
2081
|
+
(notice) => notice.platform == platform && notice.chatId == chatId,
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
1925
2084
|
errorMessage = null;
|
|
1926
2085
|
notifyListeners();
|
|
1927
2086
|
} catch (error) {
|
|
@@ -1930,6 +2089,30 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1930
2089
|
}
|
|
1931
2090
|
}
|
|
1932
2091
|
|
|
2092
|
+
Future<void> ignoreBlockedSender(BlockedSenderNotice notice) async {
|
|
2093
|
+
final key = '${notice.platform}:${notice.chatId ?? notice.sender ?? ''}';
|
|
2094
|
+
_ignoredChats.add(key);
|
|
2095
|
+
_blockedSenderQueue.removeWhere(
|
|
2096
|
+
(n) =>
|
|
2097
|
+
n.platform == notice.platform &&
|
|
2098
|
+
(n.chatId == notice.chatId || n.sender == notice.sender),
|
|
2099
|
+
);
|
|
2100
|
+
await _prefs?.setStringList(
|
|
2101
|
+
'messaging.ignored_chats',
|
|
2102
|
+
_ignoredChats.toList(),
|
|
2103
|
+
);
|
|
2104
|
+
notifyListeners();
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
Future<void> removeIgnoredChat(String key) async {
|
|
2108
|
+
_ignoredChats.remove(key);
|
|
2109
|
+
await _prefs?.setStringList(
|
|
2110
|
+
'messaging.ignored_chats',
|
|
2111
|
+
_ignoredChats.toList(),
|
|
2112
|
+
);
|
|
2113
|
+
notifyListeners();
|
|
2114
|
+
}
|
|
2115
|
+
|
|
1933
2116
|
void consumeBlockedSenderNotice(String id) {
|
|
1934
2117
|
if (_blockedSenderQueue.isNotEmpty && _blockedSenderQueue.first.id == id) {
|
|
1935
2118
|
_blockedSenderQueue.removeAt(0);
|
|
@@ -1940,6 +2123,9 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
1940
2123
|
}
|
|
1941
2124
|
|
|
1942
2125
|
void _enqueueBlockedSenderNotice(BlockedSenderNotice notice) {
|
|
2126
|
+
final ignoreKey =
|
|
2127
|
+
'${notice.platform}:${notice.chatId ?? notice.sender ?? ''}';
|
|
2128
|
+
if (_ignoredChats.contains(ignoreKey)) return;
|
|
1943
2129
|
final exists = _blockedSenderQueue.any((item) => item.id == notice.id);
|
|
1944
2130
|
if (!exists) {
|
|
1945
2131
|
_blockedSenderQueue.add(notice);
|
|
@@ -2009,8 +2195,12 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2009
2195
|
|
|
2010
2196
|
final historyFuture = _softRefreshLoad<Map<String, dynamic>>(
|
|
2011
2197
|
'chat_history',
|
|
2012
|
-
_backendClient.fetchChatHistory(
|
|
2013
|
-
|
|
2198
|
+
_backendClient.fetchChatHistory(
|
|
2199
|
+
backendUrl,
|
|
2200
|
+
agentId: agentId,
|
|
2201
|
+
limit: _chatHistoryPageSize,
|
|
2202
|
+
),
|
|
2203
|
+
const <String, dynamic>{'messages': <dynamic>[], 'hasMore': false},
|
|
2014
2204
|
);
|
|
2015
2205
|
final modelsFuture = _softRefreshLoad<Map<String, dynamic>>(
|
|
2016
2206
|
'supported_models',
|
|
@@ -2032,6 +2222,15 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2032
2222
|
_backendClient.fetchRuns(backendUrl, agentId: agentId),
|
|
2033
2223
|
const <String, dynamic>{'runs': <dynamic>[]},
|
|
2034
2224
|
);
|
|
2225
|
+
final timelineFuture = _softRefreshLoad<Map<String, dynamic>>(
|
|
2226
|
+
'timeline',
|
|
2227
|
+
_backendClient.fetchTimeline(
|
|
2228
|
+
backendUrl,
|
|
2229
|
+
sources: selectedTimelineSources,
|
|
2230
|
+
limit: 50,
|
|
2231
|
+
),
|
|
2232
|
+
const <String, dynamic>{'items': <dynamic>[]},
|
|
2233
|
+
);
|
|
2035
2234
|
final versionFuture = _softRefreshLoad<Map<String, dynamic>>(
|
|
2036
2235
|
'version',
|
|
2037
2236
|
_backendClient.fetchVersion(backendUrl),
|
|
@@ -2113,6 +2312,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2113
2312
|
final recordingsFuture = _backendClient
|
|
2114
2313
|
.fetchRecordingSessions(backendUrl)
|
|
2115
2314
|
.catchError((_) => const <Map<String, dynamic>>[]);
|
|
2315
|
+
unawaited(checkBillingEnabled());
|
|
2116
2316
|
final browserFuture = _backendClient
|
|
2117
2317
|
.fetchBrowserStatus(backendUrl)
|
|
2118
2318
|
.catchError((_) => const <String, dynamic>{});
|
|
@@ -2154,6 +2354,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2154
2354
|
final providersResponse = await providersFuture;
|
|
2155
2355
|
final settingsResponse = await settingsFuture;
|
|
2156
2356
|
final runsResponse = await runsFuture;
|
|
2357
|
+
final timelineResponse = await timelineFuture;
|
|
2157
2358
|
final versionResponse = await versionFuture;
|
|
2158
2359
|
final tokenResponse = await tokenFuture;
|
|
2159
2360
|
final rateLimitResponse = await rateLimitFuture;
|
|
@@ -2177,12 +2378,8 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2177
2378
|
return;
|
|
2178
2379
|
}
|
|
2179
2380
|
|
|
2180
|
-
chatMessages =
|
|
2181
|
-
|
|
2182
|
-
history['messages'],
|
|
2183
|
-
ChatEntry.fromJson,
|
|
2184
|
-
fallbackToMapValues: true,
|
|
2185
|
-
);
|
|
2381
|
+
chatMessages = _chatHistoryEntriesFromResponse(history);
|
|
2382
|
+
_applyChatHistoryCursor(history);
|
|
2186
2383
|
|
|
2187
2384
|
supportedModels = _decodeModelList(
|
|
2188
2385
|
'supported_models',
|
|
@@ -2205,6 +2402,12 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2205
2402
|
RunSummary.fromJson,
|
|
2206
2403
|
fallbackToMapValues: true,
|
|
2207
2404
|
);
|
|
2405
|
+
timelineItems = _decodeModelList(
|
|
2406
|
+
'timeline',
|
|
2407
|
+
timelineResponse['items'],
|
|
2408
|
+
TimelineEventItem.fromJson,
|
|
2409
|
+
fallbackToMapValues: true,
|
|
2410
|
+
);
|
|
2208
2411
|
versionInfo = versionResponse;
|
|
2209
2412
|
backendHealthStatus = healthResponse;
|
|
2210
2413
|
tokenUsage = TokenUsageSnapshot.fromJson(tokenResponse);
|
|
@@ -2398,6 +2601,62 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
2398
2601
|
} catch (_) {}
|
|
2399
2602
|
}
|
|
2400
2603
|
|
|
2604
|
+
Future<void> refreshTimeline({
|
|
2605
|
+
Set<String>? sources,
|
|
2606
|
+
bool notify = true,
|
|
2607
|
+
}) async {
|
|
2608
|
+
if (!isAuthenticated) {
|
|
2609
|
+
return;
|
|
2610
|
+
}
|
|
2611
|
+
if (sources != null) {
|
|
2612
|
+
selectedTimelineSources = sources
|
|
2613
|
+
.map((value) => value.trim().toLowerCase())
|
|
2614
|
+
.where((value) => value.isNotEmpty)
|
|
2615
|
+
.toSet();
|
|
2616
|
+
}
|
|
2617
|
+
isRefreshingTimeline = true;
|
|
2618
|
+
if (notify) {
|
|
2619
|
+
notifyListeners();
|
|
2620
|
+
}
|
|
2621
|
+
try {
|
|
2622
|
+
final response = await _backendClient.fetchTimeline(
|
|
2623
|
+
backendUrl,
|
|
2624
|
+
sources: selectedTimelineSources,
|
|
2625
|
+
limit: 50,
|
|
2626
|
+
);
|
|
2627
|
+
timelineItems = _decodeModelList(
|
|
2628
|
+
'timeline',
|
|
2629
|
+
response['items'],
|
|
2630
|
+
TimelineEventItem.fromJson,
|
|
2631
|
+
fallbackToMapValues: true,
|
|
2632
|
+
);
|
|
2633
|
+
} catch (error) {
|
|
2634
|
+
errorMessage = _friendlyErrorMessage(error);
|
|
2635
|
+
} finally {
|
|
2636
|
+
isRefreshingTimeline = false;
|
|
2637
|
+
if (notify) {
|
|
2638
|
+
notifyListeners();
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
Future<void> toggleTimelineSource(String sourceKind) async {
|
|
2644
|
+
final normalized = sourceKind.trim().toLowerCase();
|
|
2645
|
+
if (normalized.isEmpty) {
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
final next = <String>{...selectedTimelineSources};
|
|
2649
|
+
if (next.contains(normalized)) {
|
|
2650
|
+
if (next.length == 1) {
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
next.remove(normalized);
|
|
2654
|
+
} else {
|
|
2655
|
+
next.add(normalized);
|
|
2656
|
+
}
|
|
2657
|
+
await refreshTimeline(sources: next);
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2401
2660
|
Future<void> refreshMessaging() async {
|
|
2402
2661
|
try {
|
|
2403
2662
|
final statuses = await _backendClient.fetchMessagingStatus(
|
|
@@ -3732,6 +3991,19 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
3732
3991
|
}
|
|
3733
3992
|
}
|
|
3734
3993
|
|
|
3994
|
+
Future<void> setDesktopPassiveHistoryEnabled(bool value) async {
|
|
3995
|
+
final prefs = _prefs;
|
|
3996
|
+
if (prefs == null) {
|
|
3997
|
+
return;
|
|
3998
|
+
}
|
|
3999
|
+
try {
|
|
4000
|
+
await _desktopCompanion.setPassiveHistoryEnabled(value, prefs);
|
|
4001
|
+
} catch (error) {
|
|
4002
|
+
errorMessage = _friendlyErrorMessage(error);
|
|
4003
|
+
notifyListeners();
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
|
|
3735
4007
|
Future<void> rotateDesktopCompanionIdentity() async {
|
|
3736
4008
|
final prefs = _prefs;
|
|
3737
4009
|
if (prefs == null) {
|
|
@@ -4525,12 +4797,17 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4525
4797
|
_appendChatMessage(content, role: 'user', platform: platform);
|
|
4526
4798
|
}
|
|
4527
4799
|
|
|
4800
|
+
List<ToolEventItem> _capToolEvents(List<ToolEventItem> events) {
|
|
4801
|
+
if (events.length <= _maxToolEvents) return events;
|
|
4802
|
+
return events.sublist(events.length - _maxToolEvents);
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4528
4805
|
void _appendToolNote(String summary, {String toolName = 'note'}) {
|
|
4529
4806
|
final trimmed = summary.trim();
|
|
4530
4807
|
if (trimmed.isEmpty) {
|
|
4531
4808
|
return;
|
|
4532
4809
|
}
|
|
4533
|
-
toolEvents = <ToolEventItem>[
|
|
4810
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
4534
4811
|
...toolEvents,
|
|
4535
4812
|
ToolEventItem(
|
|
4536
4813
|
id: 'note-${DateTime.now().microsecondsSinceEpoch}',
|
|
@@ -4539,7 +4816,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4539
4816
|
status: 'completed',
|
|
4540
4817
|
summary: trimmed,
|
|
4541
4818
|
),
|
|
4542
|
-
];
|
|
4819
|
+
]);
|
|
4543
4820
|
}
|
|
4544
4821
|
|
|
4545
4822
|
Future<void> refreshUpdateStatus() async {
|
|
@@ -4816,6 +5093,96 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
4816
5093
|
} catch (_) {}
|
|
4817
5094
|
}
|
|
4818
5095
|
|
|
5096
|
+
// ── Billing ──────────────────────────────────────────────────────────────
|
|
5097
|
+
|
|
5098
|
+
Future<void> checkBillingEnabled() async {
|
|
5099
|
+
try {
|
|
5100
|
+
final r = await _backendClient.getBillingPlans(backendUrl);
|
|
5101
|
+
final enabled = r['plans'] != null;
|
|
5102
|
+
if (showBillingSection != enabled) {
|
|
5103
|
+
showBillingSection = enabled;
|
|
5104
|
+
notifyListeners();
|
|
5105
|
+
}
|
|
5106
|
+
} catch (_) {
|
|
5107
|
+
if (showBillingSection) {
|
|
5108
|
+
showBillingSection = false;
|
|
5109
|
+
notifyListeners();
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
|
|
5114
|
+
Future<void> refreshBilling() async {
|
|
5115
|
+
if (!isAuthenticated || !showBillingSection) return;
|
|
5116
|
+
isLoadingBilling = true;
|
|
5117
|
+
notifyListeners();
|
|
5118
|
+
try {
|
|
5119
|
+
final results = await Future.wait(<Future<Map<String, dynamic>>>[
|
|
5120
|
+
_backendClient.getBillingInfo(backendUrl),
|
|
5121
|
+
_backendClient.getBillingPlans(backendUrl),
|
|
5122
|
+
_backendClient.getBillingInvoices(backendUrl),
|
|
5123
|
+
]);
|
|
5124
|
+
billingSubscription = results[0]['subscription'] as Map<String, dynamic>?;
|
|
5125
|
+
billingPlans = _asDynList(
|
|
5126
|
+
results[1]['plans'],
|
|
5127
|
+
).cast<Map<String, dynamic>>();
|
|
5128
|
+
billingInvoices = _asDynList(
|
|
5129
|
+
results[2]['invoices'],
|
|
5130
|
+
).cast<Map<String, dynamic>>();
|
|
5131
|
+
} catch (_) {
|
|
5132
|
+
// retain previous data on error
|
|
5133
|
+
} finally {
|
|
5134
|
+
isLoadingBilling = false;
|
|
5135
|
+
notifyListeners();
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
|
|
5139
|
+
Future<String?> createCheckoutSession(String planId) async {
|
|
5140
|
+
try {
|
|
5141
|
+
final serverUrl = backendUrl;
|
|
5142
|
+
final result = await _backendClient.createCheckoutSession(
|
|
5143
|
+
baseUrl: serverUrl,
|
|
5144
|
+
planId: planId,
|
|
5145
|
+
successUrl: '$serverUrl/',
|
|
5146
|
+
cancelUrl: '$serverUrl/',
|
|
5147
|
+
);
|
|
5148
|
+
return result['url'] as String?;
|
|
5149
|
+
} catch (e) {
|
|
5150
|
+
errorMessage = _friendlyErrorMessage(e);
|
|
5151
|
+
notifyListeners();
|
|
5152
|
+
return null;
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
Future<String?> createPortalSession() async {
|
|
5157
|
+
try {
|
|
5158
|
+
final serverUrl = backendUrl;
|
|
5159
|
+
final result = await _backendClient.createPortalSession(
|
|
5160
|
+
baseUrl: serverUrl,
|
|
5161
|
+
returnUrl: '$serverUrl/',
|
|
5162
|
+
);
|
|
5163
|
+
return result['url'] as String?;
|
|
5164
|
+
} catch (e) {
|
|
5165
|
+
errorMessage = _friendlyErrorMessage(e);
|
|
5166
|
+
notifyListeners();
|
|
5167
|
+
return null;
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5170
|
+
|
|
5171
|
+
Future<bool> cancelBillingSubscription() async {
|
|
5172
|
+
try {
|
|
5173
|
+
await _backendClient.cancelBillingSubscription(backendUrl);
|
|
5174
|
+
await refreshBilling();
|
|
5175
|
+
return true;
|
|
5176
|
+
} catch (e) {
|
|
5177
|
+
errorMessage = _friendlyErrorMessage(e);
|
|
5178
|
+
notifyListeners();
|
|
5179
|
+
return false;
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
|
|
5183
|
+
List<dynamic> _asDynList(dynamic val) =>
|
|
5184
|
+
val is List ? val : const <dynamic>[];
|
|
5185
|
+
|
|
4819
5186
|
Future<bool> updateAccountEmail({
|
|
4820
5187
|
required String email,
|
|
4821
5188
|
required String currentPassword,
|
|
@@ -5709,6 +6076,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5709
6076
|
required String triggerType,
|
|
5710
6077
|
required Map<String, dynamic> triggerConfig,
|
|
5711
6078
|
required String prompt,
|
|
6079
|
+
Map<String, dynamic>? taskConfig,
|
|
5712
6080
|
String? model,
|
|
5713
6081
|
bool enabled = true,
|
|
5714
6082
|
String? agentId,
|
|
@@ -5720,6 +6088,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5720
6088
|
triggerType: triggerType,
|
|
5721
6089
|
triggerConfig: triggerConfig,
|
|
5722
6090
|
prompt: prompt,
|
|
6091
|
+
taskConfig: taskConfig,
|
|
5723
6092
|
model: model,
|
|
5724
6093
|
enabled: enabled,
|
|
5725
6094
|
agentId: agentId ?? _scopedAgentId,
|
|
@@ -6764,6 +7133,9 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
6764
7133
|
}
|
|
6765
7134
|
unawaited(_refreshRecordingSessionById(sessionId));
|
|
6766
7135
|
});
|
|
7136
|
+
socket.on('timeline:updated', (dynamic _) {
|
|
7137
|
+
unawaited(refreshTimeline());
|
|
7138
|
+
});
|
|
6767
7139
|
socket.on('voice:session_ready', (dynamic data) {
|
|
6768
7140
|
final payload = _jsonMap(data);
|
|
6769
7141
|
voiceAssistantLiveState = voiceAssistantLiveState.copyWith(
|
|
@@ -6982,7 +7354,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
6982
7354
|
'verification: ${payload['verification_need']?.toString() ?? 'none'}',
|
|
6983
7355
|
'freshness: ${payload['freshness_risk']?.toString() ?? 'none'}',
|
|
6984
7356
|
].join(' | ');
|
|
6985
|
-
toolEvents = <ToolEventItem>[
|
|
7357
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
6986
7358
|
...toolEvents,
|
|
6987
7359
|
ToolEventItem(
|
|
6988
7360
|
id: 'analysis-${DateTime.now().microsecondsSinceEpoch}',
|
|
@@ -6991,7 +7363,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
6991
7363
|
status: 'completed',
|
|
6992
7364
|
summary: summary,
|
|
6993
7365
|
),
|
|
6994
|
-
];
|
|
7366
|
+
]);
|
|
6995
7367
|
if (activeRun?.runId == runId) {
|
|
6996
7368
|
activeRun = activeRun!.copyWith(phase: 'Analyzing');
|
|
6997
7369
|
}
|
|
@@ -7016,7 +7388,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7016
7388
|
.where((item) => item.trim().isNotEmpty)
|
|
7017
7389
|
.take(4)
|
|
7018
7390
|
.join(' | ');
|
|
7019
|
-
toolEvents = <ToolEventItem>[
|
|
7391
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
7020
7392
|
...toolEvents,
|
|
7021
7393
|
ToolEventItem(
|
|
7022
7394
|
id: 'plan-${DateTime.now().microsecondsSinceEpoch}',
|
|
@@ -7025,7 +7397,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7025
7397
|
status: 'completed',
|
|
7026
7398
|
summary: steps.ifEmpty('Execution plan created.'),
|
|
7027
7399
|
),
|
|
7028
|
-
];
|
|
7400
|
+
]);
|
|
7029
7401
|
if (activeRun?.runId == runId) {
|
|
7030
7402
|
activeRun = activeRun!.copyWith(phase: 'Planning');
|
|
7031
7403
|
}
|
|
@@ -7065,10 +7437,10 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7065
7437
|
status: 'running',
|
|
7066
7438
|
summary: _summarizeToolArgs(payload['toolArgs']),
|
|
7067
7439
|
);
|
|
7068
|
-
toolEvents = <ToolEventItem>[
|
|
7440
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
7069
7441
|
...toolEvents.where((event) => event.id != item.id),
|
|
7070
7442
|
item,
|
|
7071
|
-
];
|
|
7443
|
+
]);
|
|
7072
7444
|
if (activeRun?.runId == runId) {
|
|
7073
7445
|
activeRun = activeRun!.copyWith(phase: 'Running tool');
|
|
7074
7446
|
}
|
|
@@ -7083,7 +7455,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7083
7455
|
if (_backgroundRunIds.contains(runId)) {
|
|
7084
7456
|
return;
|
|
7085
7457
|
}
|
|
7086
|
-
toolEvents = <ToolEventItem>[
|
|
7458
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
7087
7459
|
...toolEvents,
|
|
7088
7460
|
ToolEventItem(
|
|
7089
7461
|
id: 'verification-${DateTime.now().microsecondsSinceEpoch}',
|
|
@@ -7098,7 +7470,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7098
7470
|
) ??
|
|
7099
7471
|
'Verification completed.',
|
|
7100
7472
|
),
|
|
7101
|
-
];
|
|
7473
|
+
]);
|
|
7102
7474
|
if (activeRun?.runId == runId) {
|
|
7103
7475
|
activeRun = activeRun!.copyWith(phase: 'Verifying');
|
|
7104
7476
|
}
|
|
@@ -7138,7 +7510,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7138
7510
|
'Subagent update.',
|
|
7139
7511
|
),
|
|
7140
7512
|
);
|
|
7141
|
-
toolEvents = nextEvents;
|
|
7513
|
+
toolEvents = _capToolEvents(nextEvents);
|
|
7142
7514
|
notifyListeners();
|
|
7143
7515
|
});
|
|
7144
7516
|
socket.on('run:tool_end', (dynamic data) {
|
|
@@ -7171,7 +7543,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7171
7543
|
if (!replaced) {
|
|
7172
7544
|
next.add(updated);
|
|
7173
7545
|
}
|
|
7174
|
-
toolEvents = next;
|
|
7546
|
+
toolEvents = _capToolEvents(next);
|
|
7175
7547
|
final toolName = payload['toolName']?.toString() ?? '';
|
|
7176
7548
|
final screenshotPath =
|
|
7177
7549
|
payload['screenshotPath']?.toString() ??
|
|
@@ -7220,7 +7592,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7220
7592
|
if (_backgroundRunIds.contains(runId)) {
|
|
7221
7593
|
return;
|
|
7222
7594
|
}
|
|
7223
|
-
toolEvents = <ToolEventItem>[
|
|
7595
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
7224
7596
|
...toolEvents,
|
|
7225
7597
|
ToolEventItem(
|
|
7226
7598
|
id: 'steer-queued-${DateTime.now().microsecondsSinceEpoch}',
|
|
@@ -7230,7 +7602,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7230
7602
|
summary:
|
|
7231
7603
|
'Queued as steering for the current run: ${payload['content']?.toString() ?? ''}',
|
|
7232
7604
|
),
|
|
7233
|
-
];
|
|
7605
|
+
]);
|
|
7234
7606
|
if (activeRun?.runId == runId || activeRun?.runId == 'pending') {
|
|
7235
7607
|
activeRun = activeRun!.copyWith(
|
|
7236
7608
|
pendingSteeringCount: _asInt(payload['pendingCount']),
|
|
@@ -7247,7 +7619,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7247
7619
|
if (_backgroundRunIds.contains(runId)) {
|
|
7248
7620
|
return;
|
|
7249
7621
|
}
|
|
7250
|
-
toolEvents = <ToolEventItem>[
|
|
7622
|
+
toolEvents = _capToolEvents(<ToolEventItem>[
|
|
7251
7623
|
...toolEvents,
|
|
7252
7624
|
ToolEventItem(
|
|
7253
7625
|
id: 'steer-applied-${DateTime.now().microsecondsSinceEpoch}',
|
|
@@ -7258,7 +7630,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7258
7630
|
? 'Applied the latest steering update to the current run.'
|
|
7259
7631
|
: 'Applied ${_asInt(payload['count'])} queued steering updates to the current run.',
|
|
7260
7632
|
),
|
|
7261
|
-
];
|
|
7633
|
+
]);
|
|
7262
7634
|
if (activeRun?.runId == runId || activeRun?.runId == 'pending') {
|
|
7263
7635
|
activeRun = activeRun!.copyWith(
|
|
7264
7636
|
pendingSteeringCount: _asInt(payload['pendingCount']),
|