neoagent 2.4.4-beta.0 → 2.4.4-beta.5
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/README.md +5 -3
- package/docs/capabilities.md +16 -7
- package/docs/index.md +1 -0
- package/docs/security-boundaries.md +122 -0
- package/docs/supermemory-memory-review.md +852 -0
- package/flutter_app/lib/features/memory/views/retrieval_inspector_view.dart +128 -0
- package/flutter_app/lib/main.dart +3 -0
- package/flutter_app/lib/main_app_shell.dart +22 -0
- package/flutter_app/lib/main_controller.dart +36 -1
- package/flutter_app/lib/main_operations.dart +13 -0
- package/flutter_app/lib/main_security.dart +971 -0
- package/flutter_app/lib/main_settings.dart +61 -0
- package/flutter_app/lib/src/backend_client.dart +60 -3
- package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +2 -0
- package/flutter_app/pubspec.lock +32 -0
- package/flutter_app/pubspec.yaml +1 -0
- package/lib/schema_migrations.js +237 -0
- package/package.json +4 -2
- package/server/db/database.js +3 -0
- package/server/http/routes.js +2 -1
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/NOTICES +86 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +80911 -79117
- package/server/routes/memory.js +39 -2
- package/server/routes/security.js +112 -0
- package/server/services/ai/engine.js +267 -10
- package/server/services/ai/systemPrompt.js +13 -2
- package/server/services/cli/shell_worker.js +135 -0
- package/server/services/cli/shell_worker_pool.js +125 -0
- package/server/services/manager.js +20 -1
- package/server/services/memory/consolidation.js +111 -0
- package/server/services/memory/embedding_index.js +175 -0
- package/server/services/memory/embeddings.js +22 -2
- package/server/services/memory/evaluation.js +187 -0
- package/server/services/memory/ingestion_chunking.js +191 -0
- package/server/services/memory/ingestion_documents.js +96 -26
- package/server/services/memory/intelligence.js +3 -1
- package/server/services/memory/manager.js +855 -40
- package/server/services/memory/policy.js +0 -40
- package/server/services/memory/retrieval_reasoning.js +191 -0
- package/server/services/runtime/manager.js +7 -0
- package/server/services/security/approval_gate_service.js +93 -0
- package/server/services/security/tool_categories.js +105 -0
- package/server/services/security/tool_policy_service.js +92 -0
- package/server/services/security/tool_security_hook.js +77 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
import '../../../main.dart'; // To access NeoAgentController
|
|
3
|
+
|
|
4
|
+
class RetrievalInspectorView extends StatefulWidget {
|
|
5
|
+
final NeoAgentController controller;
|
|
6
|
+
|
|
7
|
+
const RetrievalInspectorView({super.key, required this.controller});
|
|
8
|
+
|
|
9
|
+
@override
|
|
10
|
+
State<RetrievalInspectorView> createState() => _RetrievalInspectorViewState();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class _RetrievalInspectorViewState extends State<RetrievalInspectorView> {
|
|
14
|
+
final _queryController = TextEditingController();
|
|
15
|
+
bool _isLoading = false;
|
|
16
|
+
Map<String, dynamic>? _results;
|
|
17
|
+
String? _error;
|
|
18
|
+
|
|
19
|
+
@override
|
|
20
|
+
void dispose() {
|
|
21
|
+
_queryController.dispose();
|
|
22
|
+
super.dispose();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Future<void> _inspect() async {
|
|
26
|
+
final query = _queryController.text.trim();
|
|
27
|
+
if (query.isEmpty) return;
|
|
28
|
+
|
|
29
|
+
setState(() {
|
|
30
|
+
_isLoading = true;
|
|
31
|
+
_error = null;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
final res = await widget.controller.inspectMemory(query);
|
|
36
|
+
if (!mounted) return;
|
|
37
|
+
setState(() {
|
|
38
|
+
_results = res;
|
|
39
|
+
});
|
|
40
|
+
} catch (e) {
|
|
41
|
+
if (!mounted) return;
|
|
42
|
+
setState(() {
|
|
43
|
+
_error = e.toString();
|
|
44
|
+
});
|
|
45
|
+
} finally {
|
|
46
|
+
if (mounted) {
|
|
47
|
+
setState(() {
|
|
48
|
+
_isLoading = false;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@override
|
|
55
|
+
Widget build(BuildContext context) {
|
|
56
|
+
return Scaffold(
|
|
57
|
+
appBar: AppBar(
|
|
58
|
+
title: const Text('Retrieval Inspector'),
|
|
59
|
+
),
|
|
60
|
+
body: Padding(
|
|
61
|
+
padding: const EdgeInsets.all(16.0),
|
|
62
|
+
child: Column(
|
|
63
|
+
children: [
|
|
64
|
+
Row(
|
|
65
|
+
children: [
|
|
66
|
+
Expanded(
|
|
67
|
+
child: TextField(
|
|
68
|
+
controller: _queryController,
|
|
69
|
+
decoration: const InputDecoration(
|
|
70
|
+
labelText: 'Query',
|
|
71
|
+
border: OutlineInputBorder(),
|
|
72
|
+
),
|
|
73
|
+
onSubmitted: (_) => _inspect(),
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
const SizedBox(width: 8),
|
|
77
|
+
ElevatedButton(
|
|
78
|
+
onPressed: _isLoading ? null : _inspect,
|
|
79
|
+
child: const Text('Inspect'),
|
|
80
|
+
),
|
|
81
|
+
],
|
|
82
|
+
),
|
|
83
|
+
const SizedBox(height: 16),
|
|
84
|
+
if (_isLoading)
|
|
85
|
+
const CircularProgressIndicator()
|
|
86
|
+
else if (_error != null)
|
|
87
|
+
Text('Error: $_error', style: const TextStyle(color: Colors.red))
|
|
88
|
+
else if (_results != null)
|
|
89
|
+
Expanded(
|
|
90
|
+
child: ListView.builder(
|
|
91
|
+
itemCount: (_results!['results'] as List?)?.length ?? 0,
|
|
92
|
+
itemBuilder: (context, index) {
|
|
93
|
+
final item = _results!['results'][index];
|
|
94
|
+
final breakdown = item['scoreBreakdown'] ?? {};
|
|
95
|
+
return Card(
|
|
96
|
+
margin: const EdgeInsets.only(bottom: 8),
|
|
97
|
+
child: Padding(
|
|
98
|
+
padding: const EdgeInsets.all(12.0),
|
|
99
|
+
child: Column(
|
|
100
|
+
crossAxisAlignment: CrossAxisAlignment.start,
|
|
101
|
+
children: [
|
|
102
|
+
Text(
|
|
103
|
+
'Score: ${item['score']?.toStringAsFixed(3) ?? '?'}',
|
|
104
|
+
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
105
|
+
),
|
|
106
|
+
Text('Content: ${item['content']}'),
|
|
107
|
+
const SizedBox(height: 8),
|
|
108
|
+
const Text('Breakdown:', style: TextStyle(fontWeight: FontWeight.bold)),
|
|
109
|
+
Text('Semantic: ${breakdown['semantic']?.toStringAsFixed(3)}'),
|
|
110
|
+
Text('Lexical: ${breakdown['lexical']?.toStringAsFixed(3)}'),
|
|
111
|
+
Text('Full Text (FTS): ${breakdown['fullText']?.toStringAsFixed(3)}'),
|
|
112
|
+
Text('Entity: ${breakdown['entity']?.toStringAsFixed(3)}'),
|
|
113
|
+
Text('Relation: ${breakdown['relation']?.toStringAsFixed(3)}'),
|
|
114
|
+
Text('Candidate Count: ${breakdown['candidateCount']}'),
|
|
115
|
+
Text('Vector Rank: ${breakdown['vectorCandidateRank']}'),
|
|
116
|
+
],
|
|
117
|
+
),
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
},
|
|
121
|
+
),
|
|
122
|
+
),
|
|
123
|
+
],
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart';
|
|
|
11
11
|
import 'package:flutter/gestures.dart';
|
|
12
12
|
import 'package:flutter/material.dart';
|
|
13
13
|
import 'package:flutter/services.dart';
|
|
14
|
+
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
14
15
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
|
15
16
|
import 'package:file_picker/file_picker.dart';
|
|
16
17
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|
@@ -48,6 +49,7 @@ import 'src/android_auto_bridge.dart';
|
|
|
48
49
|
import 'features/location/location_service.dart';
|
|
49
50
|
import 'features/notifications/notification_interceptor.dart';
|
|
50
51
|
import 'features/onboarding/onboarding_shell.dart';
|
|
52
|
+
import 'features/memory/views/retrieval_inspector_view.dart';
|
|
51
53
|
|
|
52
54
|
part 'main_spacing.dart';
|
|
53
55
|
part 'main_theme.dart';
|
|
@@ -65,6 +67,7 @@ part 'main_recordings.dart';
|
|
|
65
67
|
part 'main_chat.dart';
|
|
66
68
|
part 'main_account_settings.dart';
|
|
67
69
|
part 'main_settings.dart';
|
|
70
|
+
part 'main_security.dart';
|
|
68
71
|
part 'main_model_picker.dart';
|
|
69
72
|
part 'main_operations.dart';
|
|
70
73
|
part 'main_admin.dart';
|
|
@@ -1086,6 +1086,7 @@ class HomeView extends StatefulWidget {
|
|
|
1086
1086
|
|
|
1087
1087
|
class _HomeViewState extends State<HomeView> {
|
|
1088
1088
|
bool _blockedDialogOpen = false;
|
|
1089
|
+
bool _approvalSheetOpen = false;
|
|
1089
1090
|
SidebarGroup? _expandedSidebarGroup;
|
|
1090
1091
|
AppSection? _lastSelectedSection;
|
|
1091
1092
|
final GlobalKey _devicesPanelKey = GlobalKey();
|
|
@@ -1198,6 +1199,27 @@ class _HomeViewState extends State<HomeView> {
|
|
|
1198
1199
|
_showBlockedSenderDialog(pendingBlockedSender);
|
|
1199
1200
|
});
|
|
1200
1201
|
}
|
|
1202
|
+
final pendingApproval = controller.pendingApproval;
|
|
1203
|
+
if (!_approvalSheetOpen && pendingApproval != null) {
|
|
1204
|
+
_approvalSheetOpen = true;
|
|
1205
|
+
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
1206
|
+
if (!mounted) return;
|
|
1207
|
+
showModalBottomSheet<void>(
|
|
1208
|
+
context: context,
|
|
1209
|
+
isDismissible: false,
|
|
1210
|
+
enableDrag: false,
|
|
1211
|
+
shape: const RoundedRectangleBorder(
|
|
1212
|
+
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
1213
|
+
),
|
|
1214
|
+
builder: (_) => ToolApprovalSheet(
|
|
1215
|
+
request: pendingApproval,
|
|
1216
|
+
controller: controller,
|
|
1217
|
+
),
|
|
1218
|
+
).whenComplete(() {
|
|
1219
|
+
if (mounted) setState(() => _approvalSheetOpen = false);
|
|
1220
|
+
});
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1201
1223
|
|
|
1202
1224
|
final wide = MediaQuery.sizeOf(context).width >= 1080;
|
|
1203
1225
|
|
|
@@ -156,6 +156,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
156
156
|
Map<String, MessagingAccessCatalog> messagingAccessCatalogs =
|
|
157
157
|
const <String, MessagingAccessCatalog>{};
|
|
158
158
|
MessagingQrState? pendingMessagingQr;
|
|
159
|
+
ToolApprovalRequest? pendingApproval;
|
|
159
160
|
final List<BlockedSenderNotice> _blockedSenderQueue = <BlockedSenderNotice>[];
|
|
160
161
|
List<SkillItem> skills = const <SkillItem>[];
|
|
161
162
|
List<StoreSkillItem> storeSkills = const <StoreSkillItem>[];
|
|
@@ -359,6 +360,13 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
359
360
|
|
|
360
361
|
String? get sessionCookie => _backendClient.sessionCookie;
|
|
361
362
|
|
|
363
|
+
BackendClient get backendClient => _backendClient;
|
|
364
|
+
|
|
365
|
+
void clearPendingApproval() {
|
|
366
|
+
pendingApproval = null;
|
|
367
|
+
notifyListeners();
|
|
368
|
+
}
|
|
369
|
+
|
|
362
370
|
bool get desktopFloatingToolbarPopupRequested =>
|
|
363
371
|
_desktopFloatingToolbarPopupRequested;
|
|
364
372
|
|
|
@@ -5618,7 +5626,7 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5618
5626
|
}
|
|
5619
5627
|
|
|
5620
5628
|
Future<void> searchMemories(String query) async {
|
|
5621
|
-
memoryRecallResults = (await _backendClient.
|
|
5629
|
+
memoryRecallResults = (await _backendClient.recallMemory(
|
|
5622
5630
|
backendUrl,
|
|
5623
5631
|
query,
|
|
5624
5632
|
agentId: _scopedAgentId,
|
|
@@ -5631,6 +5639,14 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
5631
5639
|
notifyListeners();
|
|
5632
5640
|
}
|
|
5633
5641
|
|
|
5642
|
+
Future<Map<String, dynamic>> inspectMemory(String query) async {
|
|
5643
|
+
return _backendClient.inspectMemory(
|
|
5644
|
+
backendUrl,
|
|
5645
|
+
query,
|
|
5646
|
+
agentId: _scopedAgentId,
|
|
5647
|
+
);
|
|
5648
|
+
}
|
|
5649
|
+
|
|
5634
5650
|
Future<void> updateAssistantBehaviorNotes(String content) async {
|
|
5635
5651
|
await _backendClient.saveSettings(backendUrl, <String, dynamic>{
|
|
5636
5652
|
'assistant_behavior_notes': content,
|
|
@@ -7146,6 +7162,25 @@ class NeoAgentController extends ChangeNotifier {
|
|
|
7146
7162
|
}
|
|
7147
7163
|
notifyListeners();
|
|
7148
7164
|
});
|
|
7165
|
+
socket.on('tool:approval_required', (dynamic data) {
|
|
7166
|
+
final payload = _jsonMap(data);
|
|
7167
|
+
final req = ToolApprovalRequest.fromJson(payload);
|
|
7168
|
+
pendingApproval = req;
|
|
7169
|
+
notifyListeners();
|
|
7170
|
+
// Show interactive push notification when app is backgrounded
|
|
7171
|
+
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
|
7172
|
+
_SecurityNotificationService.showApprovalNotification(req);
|
|
7173
|
+
}
|
|
7174
|
+
});
|
|
7175
|
+
socket.on('tool:approval_resolved', (dynamic data) {
|
|
7176
|
+
final payload = _jsonMap(data);
|
|
7177
|
+
final resolvedId = payload['approvalId']?.toString() ?? '';
|
|
7178
|
+
if (pendingApproval?.approvalId == resolvedId) {
|
|
7179
|
+
_SecurityNotificationService.cancelApprovalNotification(resolvedId);
|
|
7180
|
+
pendingApproval = null;
|
|
7181
|
+
notifyListeners();
|
|
7182
|
+
}
|
|
7183
|
+
});
|
|
7149
7184
|
socket.on('run:steer_queued', (dynamic data) {
|
|
7150
7185
|
final payload = _jsonMap(data);
|
|
7151
7186
|
final runId = payload['runId']?.toString() ?? '';
|
|
@@ -1463,6 +1463,14 @@ class _MemoryPanelState extends State<MemoryPanel>
|
|
|
1463
1463
|
});
|
|
1464
1464
|
}
|
|
1465
1465
|
|
|
1466
|
+
void _openRetrievalInspector(BuildContext context, NeoAgentController controller) {
|
|
1467
|
+
Navigator.of(context).push(
|
|
1468
|
+
MaterialPageRoute(
|
|
1469
|
+
builder: (context) => RetrievalInspectorView(controller: controller),
|
|
1470
|
+
),
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1466
1474
|
@override
|
|
1467
1475
|
Widget build(BuildContext context) {
|
|
1468
1476
|
final controller = widget.controller;
|
|
@@ -1485,6 +1493,11 @@ class _MemoryPanelState extends State<MemoryPanel>
|
|
|
1485
1493
|
spacing: 10,
|
|
1486
1494
|
runSpacing: 10,
|
|
1487
1495
|
children: <Widget>[
|
|
1496
|
+
OutlinedButton.icon(
|
|
1497
|
+
onPressed: () => _openRetrievalInspector(context, controller),
|
|
1498
|
+
icon: Icon(Icons.bug_report_outlined),
|
|
1499
|
+
label: Text('Inspect'),
|
|
1500
|
+
),
|
|
1488
1501
|
OutlinedButton.icon(
|
|
1489
1502
|
onPressed: () => _openBehaviorNotesEditor(context, controller),
|
|
1490
1503
|
icon: Icon(Icons.edit_outlined),
|