neoagent 2.3.1-beta.115 → 2.3.1-beta.118
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/flutter_app/lib/main.dart +1 -0
- package/flutter_app/lib/main_integrations.dart +21 -2
- package/flutter_app/lib/main_models.dart +60 -0
- package/flutter_app/lib/main_theme.dart +31 -2
- package/flutter_app/macos/Runner/AppDelegate.swift +11 -1
- package/flutter_app/macos/Runner/DebugProfile.entitlements +4 -0
- package/flutter_app/macos/Runner/Release.entitlements +4 -0
- package/flutter_app/pubspec.lock +5 -5
- package/package.json +1 -1
- package/server/db/database.js +85 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/NOTICES +971 -1066
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/assets/shaders/ink_sparkle.frag +1 -1
- package/server/public/assets/shaders/stretch_effect.frag +1 -1
- package/server/public/canvaskit/canvaskit.js +2 -2
- package/server/public/canvaskit/canvaskit.js.symbols +11796 -11733
- package/server/public/canvaskit/canvaskit.wasm +0 -0
- package/server/public/canvaskit/chromium/canvaskit.js +2 -2
- package/server/public/canvaskit/chromium/canvaskit.js.symbols +10706 -10643
- package/server/public/canvaskit/chromium/canvaskit.wasm +0 -0
- package/server/public/canvaskit/experimental_webparagraph/canvaskit.js +171 -0
- package/server/public/canvaskit/experimental_webparagraph/canvaskit.js.symbols +9134 -0
- package/server/public/canvaskit/experimental_webparagraph/canvaskit.wasm +0 -0
- package/server/public/canvaskit/skwasm.js +14 -14
- package/server/public/canvaskit/skwasm.js.symbols +12787 -12676
- package/server/public/canvaskit/skwasm.wasm +0 -0
- package/server/public/canvaskit/skwasm_heavy.js +14 -14
- package/server/public/canvaskit/skwasm_heavy.js.symbols +14400 -14286
- package/server/public/canvaskit/skwasm_heavy.wasm +0 -0
- package/server/public/canvaskit/wimp.js +94 -95
- package/server/public/canvaskit/wimp.js.symbols +11325 -11177
- package/server/public/canvaskit/wimp.wasm +0 -0
- package/server/public/flutter_bootstrap.js +2 -2
- package/server/public/main.dart.js +83866 -82074
- package/server/routes/integrations.js +2 -2
- package/server/routes/memory.js +73 -0
- package/server/services/ai/engine.js +65 -26
- package/server/services/ai/preModelCompaction.js +191 -0
- package/server/services/ai/providers/claudeCode.js +0 -1
- package/server/services/integrations/google/provider.js +78 -0
- package/server/services/integrations/manager.js +29 -13
- package/server/services/manager.js +25 -0
- package/server/services/memory/ingestion.js +486 -0
- package/server/services/memory/manager.js +422 -0
- package/server/services/memory/openhuman_uplift.test.js +98 -0
- package/server/services/widgets/focus_widget.js +45 -4
|
@@ -6,6 +6,7 @@ import 'dart:ui' show ImageFilter;
|
|
|
6
6
|
|
|
7
7
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
|
8
8
|
import 'package:hotkey_manager/hotkey_manager.dart';
|
|
9
|
+
import 'package:flutter/cupertino.dart' as cupertino;
|
|
9
10
|
import 'package:flutter/foundation.dart';
|
|
10
11
|
import 'package:flutter/gestures.dart';
|
|
11
12
|
import 'package:flutter/material.dart';
|
|
@@ -175,6 +175,12 @@ class OfficialIntegrationsTab extends StatelessWidget {
|
|
|
175
175
|
label: '${item.availableToolCount} tools',
|
|
176
176
|
icon: Icons.build_outlined,
|
|
177
177
|
),
|
|
178
|
+
_MetaPill(
|
|
179
|
+
label: item.memoryCoverage.supported
|
|
180
|
+
? 'Memory ${item.memoryCoverage.statusLabel}'
|
|
181
|
+
: 'No memory sync',
|
|
182
|
+
icon: Icons.psychology_alt_outlined,
|
|
183
|
+
),
|
|
178
184
|
],
|
|
179
185
|
),
|
|
180
186
|
const SizedBox(height: 10),
|
|
@@ -255,6 +261,7 @@ Future<void> _showTrelloSetupDialog(
|
|
|
255
261
|
final apiKeyController = TextEditingController(text: savedApiKey);
|
|
256
262
|
final tokenInputController = TextEditingController();
|
|
257
263
|
|
|
264
|
+
if (!context.mounted) return;
|
|
258
265
|
await showDialog<void>(
|
|
259
266
|
context: context,
|
|
260
267
|
barrierDismissible: false,
|
|
@@ -426,8 +433,7 @@ Future<void> _showTrelloSetupDialog(
|
|
|
426
433
|
}
|
|
427
434
|
final url = authorizeUrl.isNotEmpty
|
|
428
435
|
? authorizeUrl
|
|
429
|
-
: 'https://trello.com/1/authorize?expiration=never&scope=read,write,account&response_type=token&key
|
|
430
|
-
Uri.encodeComponent(effectiveApiKey);
|
|
436
|
+
: 'https://trello.com/1/authorize?expiration=never&scope=read,write,account&response_type=token&key=${Uri.encodeComponent(effectiveApiKey)}';
|
|
431
437
|
final result = await controller._oauthLauncher
|
|
432
438
|
.openExternal(url: url, label: 'Trello');
|
|
433
439
|
if (!result.launched) {
|
|
@@ -659,6 +665,12 @@ class _OfficialIntegrationAppCard extends StatelessWidget {
|
|
|
659
665
|
label: '${app.availableToolCount} tools',
|
|
660
666
|
icon: Icons.build_circle_outlined,
|
|
661
667
|
),
|
|
668
|
+
_MetaPill(
|
|
669
|
+
label: app.memoryCoverage.supported
|
|
670
|
+
? 'Memory ${app.memoryCoverage.statusLabel}'
|
|
671
|
+
: 'No memory sync',
|
|
672
|
+
icon: Icons.psychology_alt_outlined,
|
|
673
|
+
),
|
|
662
674
|
],
|
|
663
675
|
),
|
|
664
676
|
],
|
|
@@ -715,6 +727,13 @@ class _OfficialIntegrationAppCard extends StatelessWidget {
|
|
|
715
727
|
'Access: ${account.accessModeLabel}',
|
|
716
728
|
style: TextStyle(color: _textSecondary),
|
|
717
729
|
),
|
|
730
|
+
if (account.memoryCoverage.supported) ...<Widget>[
|
|
731
|
+
const SizedBox(height: 4),
|
|
732
|
+
Text(
|
|
733
|
+
'Memory: ${account.memoryCoverage.statusLabel}',
|
|
734
|
+
style: TextStyle(color: _textSecondary),
|
|
735
|
+
),
|
|
736
|
+
],
|
|
718
737
|
const SizedBox(height: 12),
|
|
719
738
|
Wrap(
|
|
720
739
|
spacing: 8,
|
|
@@ -2565,6 +2565,7 @@ class OfficialIntegrationAppItem {
|
|
|
2565
2565
|
),
|
|
2566
2566
|
this.accounts = const <OfficialIntegrationAccountItem>[],
|
|
2567
2567
|
this.availableToolCount = 0,
|
|
2568
|
+
this.memoryCoverage = const OfficialIntegrationMemoryCoverage(),
|
|
2568
2569
|
});
|
|
2569
2570
|
|
|
2570
2571
|
factory OfficialIntegrationAppItem.fromJson(Map<dynamic, dynamic> json) {
|
|
@@ -2583,6 +2584,9 @@ class OfficialIntegrationAppItem {
|
|
|
2583
2584
|
.toList()
|
|
2584
2585
|
: const <OfficialIntegrationAccountItem>[],
|
|
2585
2586
|
availableToolCount: _asInt(json['availableToolCount']),
|
|
2587
|
+
memoryCoverage: OfficialIntegrationMemoryCoverage.fromJson(
|
|
2588
|
+
_jsonMap(json['memoryCoverage']),
|
|
2589
|
+
),
|
|
2586
2590
|
);
|
|
2587
2591
|
}
|
|
2588
2592
|
|
|
@@ -2592,6 +2596,7 @@ class OfficialIntegrationAppItem {
|
|
|
2592
2596
|
final OfficialIntegrationConnectionStatus connection;
|
|
2593
2597
|
final List<OfficialIntegrationAccountItem> accounts;
|
|
2594
2598
|
final int availableToolCount;
|
|
2599
|
+
final OfficialIntegrationMemoryCoverage memoryCoverage;
|
|
2595
2600
|
|
|
2596
2601
|
bool get isConnected => connection.connected;
|
|
2597
2602
|
|
|
@@ -2676,6 +2681,51 @@ class OfficialIntegrationConnectionStatus {
|
|
|
2676
2681
|
}
|
|
2677
2682
|
}
|
|
2678
2683
|
|
|
2684
|
+
class OfficialIntegrationMemoryCoverage {
|
|
2685
|
+
const OfficialIntegrationMemoryCoverage({
|
|
2686
|
+
this.supported = false,
|
|
2687
|
+
this.contributesToMemory = false,
|
|
2688
|
+
this.contributesToTaskExecution = false,
|
|
2689
|
+
this.status = 'not_supported',
|
|
2690
|
+
this.dataDomains = const <String>[],
|
|
2691
|
+
this.documentCount = 0,
|
|
2692
|
+
this.lastRefreshAt,
|
|
2693
|
+
this.nextRefreshAt,
|
|
2694
|
+
this.error,
|
|
2695
|
+
});
|
|
2696
|
+
|
|
2697
|
+
factory OfficialIntegrationMemoryCoverage.fromJson(
|
|
2698
|
+
Map<dynamic, dynamic> json,
|
|
2699
|
+
) {
|
|
2700
|
+
final domainsRaw = json['dataDomains'];
|
|
2701
|
+
return OfficialIntegrationMemoryCoverage(
|
|
2702
|
+
supported: json['supported'] == true,
|
|
2703
|
+
contributesToMemory: json['contributesToMemory'] == true,
|
|
2704
|
+
contributesToTaskExecution: json['contributesToTaskExecution'] == true,
|
|
2705
|
+
status: json['status']?.toString() ?? 'not_supported',
|
|
2706
|
+
dataDomains: domainsRaw is List
|
|
2707
|
+
? domainsRaw.map((item) => item.toString()).toList()
|
|
2708
|
+
: const <String>[],
|
|
2709
|
+
documentCount: _asInt(json['documentCount']),
|
|
2710
|
+
lastRefreshAt: _parseOptionalTimestamp(json['lastRefreshAt']?.toString()),
|
|
2711
|
+
nextRefreshAt: _parseOptionalTimestamp(json['nextRefreshAt']?.toString()),
|
|
2712
|
+
error: json['error']?.toString(),
|
|
2713
|
+
);
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
final bool supported;
|
|
2717
|
+
final bool contributesToMemory;
|
|
2718
|
+
final bool contributesToTaskExecution;
|
|
2719
|
+
final String status;
|
|
2720
|
+
final List<String> dataDomains;
|
|
2721
|
+
final int documentCount;
|
|
2722
|
+
final DateTime? lastRefreshAt;
|
|
2723
|
+
final DateTime? nextRefreshAt;
|
|
2724
|
+
final String? error;
|
|
2725
|
+
|
|
2726
|
+
String get statusLabel => _titleCase(status.replaceAll('_', ' '));
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2679
2729
|
class OfficialIntegrationAccountItem {
|
|
2680
2730
|
const OfficialIntegrationAccountItem({
|
|
2681
2731
|
required this.id,
|
|
@@ -2684,6 +2734,7 @@ class OfficialIntegrationAccountItem {
|
|
|
2684
2734
|
this.accountEmail,
|
|
2685
2735
|
this.lastConnectedAt,
|
|
2686
2736
|
this.accessMode = 'read_write',
|
|
2737
|
+
this.memoryCoverage = const OfficialIntegrationMemoryCoverage(),
|
|
2687
2738
|
});
|
|
2688
2739
|
|
|
2689
2740
|
factory OfficialIntegrationAccountItem.fromJson(Map<dynamic, dynamic> json) {
|
|
@@ -2696,6 +2747,9 @@ class OfficialIntegrationAccountItem {
|
|
|
2696
2747
|
json['lastConnectedAt']?.toString(),
|
|
2697
2748
|
),
|
|
2698
2749
|
accessMode: json['accessMode']?.toString() ?? 'read_write',
|
|
2750
|
+
memoryCoverage: OfficialIntegrationMemoryCoverage.fromJson(
|
|
2751
|
+
_jsonMap(json['memoryCoverage']),
|
|
2752
|
+
),
|
|
2699
2753
|
);
|
|
2700
2754
|
}
|
|
2701
2755
|
|
|
@@ -2705,6 +2759,7 @@ class OfficialIntegrationAccountItem {
|
|
|
2705
2759
|
final String? accountEmail;
|
|
2706
2760
|
final DateTime? lastConnectedAt;
|
|
2707
2761
|
final String accessMode;
|
|
2762
|
+
final OfficialIntegrationMemoryCoverage memoryCoverage;
|
|
2708
2763
|
|
|
2709
2764
|
bool get isExpired => status == 'expired';
|
|
2710
2765
|
|
|
@@ -2733,6 +2788,7 @@ class OfficialIntegrationItem {
|
|
|
2733
2788
|
this.connectPrompt,
|
|
2734
2789
|
this.supportsMultipleAccounts = true,
|
|
2735
2790
|
this.connectionMethod = 'oauth',
|
|
2791
|
+
this.memoryCoverage = const OfficialIntegrationMemoryCoverage(),
|
|
2736
2792
|
});
|
|
2737
2793
|
|
|
2738
2794
|
factory OfficialIntegrationItem.fromJson(Map<dynamic, dynamic> json) {
|
|
@@ -2756,6 +2812,9 @@ class OfficialIntegrationItem {
|
|
|
2756
2812
|
connectPrompt: json['connectPrompt']?.toString(),
|
|
2757
2813
|
supportsMultipleAccounts: json['supportsMultipleAccounts'] != false,
|
|
2758
2814
|
connectionMethod: json['connectionMethod']?.toString() ?? 'oauth',
|
|
2815
|
+
memoryCoverage: OfficialIntegrationMemoryCoverage.fromJson(
|
|
2816
|
+
_jsonMap(json['memoryCoverage']),
|
|
2817
|
+
),
|
|
2759
2818
|
);
|
|
2760
2819
|
}
|
|
2761
2820
|
|
|
@@ -2770,6 +2829,7 @@ class OfficialIntegrationItem {
|
|
|
2770
2829
|
final String? connectPrompt;
|
|
2771
2830
|
final bool supportsMultipleAccounts;
|
|
2772
2831
|
final String connectionMethod;
|
|
2832
|
+
final OfficialIntegrationMemoryCoverage memoryCoverage;
|
|
2773
2833
|
|
|
2774
2834
|
bool get isConnected => connection.connected;
|
|
2775
2835
|
|
|
@@ -224,8 +224,8 @@ ThemeData _buildNeoAgentTheme(NeoAgentPalette palette, Brightness brightness) {
|
|
|
224
224
|
pageTransitionsTheme: const PageTransitionsTheme(
|
|
225
225
|
builders: <TargetPlatform, PageTransitionsBuilder>{
|
|
226
226
|
TargetPlatform.android: FadeForwardsPageTransitionsBuilder(),
|
|
227
|
-
TargetPlatform.iOS:
|
|
228
|
-
TargetPlatform.macOS:
|
|
227
|
+
TargetPlatform.iOS: _NeoAgentCupertinoPageTransitionsBuilder(),
|
|
228
|
+
TargetPlatform.macOS: _NeoAgentCupertinoPageTransitionsBuilder(),
|
|
229
229
|
TargetPlatform.windows: FadeForwardsPageTransitionsBuilder(),
|
|
230
230
|
TargetPlatform.linux: FadeForwardsPageTransitionsBuilder(),
|
|
231
231
|
},
|
|
@@ -274,3 +274,32 @@ ThemeData _buildNeoAgentTheme(NeoAgentPalette palette, Brightness brightness) {
|
|
|
274
274
|
),
|
|
275
275
|
);
|
|
276
276
|
}
|
|
277
|
+
|
|
278
|
+
class _NeoAgentCupertinoPageTransitionsBuilder extends PageTransitionsBuilder {
|
|
279
|
+
const _NeoAgentCupertinoPageTransitionsBuilder();
|
|
280
|
+
|
|
281
|
+
@override
|
|
282
|
+
Duration get transitionDuration =>
|
|
283
|
+
cupertino.CupertinoRouteTransitionMixin.kTransitionDuration;
|
|
284
|
+
|
|
285
|
+
@override
|
|
286
|
+
DelegatedTransitionBuilder? get delegatedTransition =>
|
|
287
|
+
cupertino.CupertinoPageTransition.delegatedTransition;
|
|
288
|
+
|
|
289
|
+
@override
|
|
290
|
+
Widget buildTransitions<T>(
|
|
291
|
+
PageRoute<T> route,
|
|
292
|
+
BuildContext context,
|
|
293
|
+
Animation<double> animation,
|
|
294
|
+
Animation<double> secondaryAnimation,
|
|
295
|
+
Widget child,
|
|
296
|
+
) {
|
|
297
|
+
return cupertino.CupertinoRouteTransitionMixin.buildPageTransitions<T>(
|
|
298
|
+
route,
|
|
299
|
+
context,
|
|
300
|
+
animation,
|
|
301
|
+
secondaryAnimation,
|
|
302
|
+
child,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
@@ -302,7 +302,17 @@ final class DesktopCompanionNativePlugin: NSObject {
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
private func preflightScreenCapturePermission() -> Bool {
|
|
305
|
-
CGPreflightScreenCaptureAccess()
|
|
305
|
+
if CGPreflightScreenCaptureAccess() { return true }
|
|
306
|
+
// CGPreflightScreenCaptureAccess() caches the result per-process on macOS 14+
|
|
307
|
+
// and won't reflect a System Settings grant until the app restarts. Fall back to
|
|
308
|
+
// a live 1×1 capture probe which returns nil when recording is actually blocked.
|
|
309
|
+
let probe = CGWindowListCreateImage(
|
|
310
|
+
CGRect(x: 0, y: 0, width: 1, height: 1),
|
|
311
|
+
.optionOnScreenOnly,
|
|
312
|
+
kCGNullWindowID,
|
|
313
|
+
.bestResolution
|
|
314
|
+
)
|
|
315
|
+
return probe != nil
|
|
306
316
|
}
|
|
307
317
|
|
|
308
318
|
private func isAccessibilityTrusted() -> Bool {
|
package/flutter_app/pubspec.lock
CHANGED
|
@@ -594,10 +594,10 @@ packages:
|
|
|
594
594
|
dependency: transitive
|
|
595
595
|
description:
|
|
596
596
|
name: meta
|
|
597
|
-
sha256: "
|
|
597
|
+
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
|
598
598
|
url: "https://pub.dev"
|
|
599
599
|
source: hosted
|
|
600
|
-
version: "1.
|
|
600
|
+
version: "1.18.0"
|
|
601
601
|
mixpanel_flutter:
|
|
602
602
|
dependency: "direct main"
|
|
603
603
|
description:
|
|
@@ -1039,10 +1039,10 @@ packages:
|
|
|
1039
1039
|
dependency: transitive
|
|
1040
1040
|
description:
|
|
1041
1041
|
name: test_api
|
|
1042
|
-
sha256: "
|
|
1042
|
+
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
|
1043
1043
|
url: "https://pub.dev"
|
|
1044
1044
|
source: hosted
|
|
1045
|
-
version: "0.7.
|
|
1045
|
+
version: "0.7.11"
|
|
1046
1046
|
tray_manager:
|
|
1047
1047
|
dependency: "direct main"
|
|
1048
1048
|
description:
|
|
@@ -1252,5 +1252,5 @@ packages:
|
|
|
1252
1252
|
source: hosted
|
|
1253
1253
|
version: "6.6.1"
|
|
1254
1254
|
sdks:
|
|
1255
|
-
dart: ">=3.
|
|
1255
|
+
dart: ">=3.10.0-0 <4.0.0"
|
|
1256
1256
|
flutter: ">=3.35.0"
|
package/package.json
CHANGED
package/server/db/database.js
CHANGED
|
@@ -614,6 +614,78 @@ db.exec(`
|
|
|
614
614
|
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE CASCADE
|
|
615
615
|
);
|
|
616
616
|
|
|
617
|
+
CREATE TABLE IF NOT EXISTS memory_ingestion_jobs (
|
|
618
|
+
id TEXT PRIMARY KEY,
|
|
619
|
+
user_id INTEGER NOT NULL,
|
|
620
|
+
agent_id TEXT,
|
|
621
|
+
source_type TEXT NOT NULL,
|
|
622
|
+
provider_key TEXT DEFAULT '',
|
|
623
|
+
connection_id INTEGER,
|
|
624
|
+
status TEXT DEFAULT 'pending',
|
|
625
|
+
freshness_policy_json TEXT DEFAULT '{}',
|
|
626
|
+
cursor_json TEXT DEFAULT '{}',
|
|
627
|
+
summary_json TEXT DEFAULT '{}',
|
|
628
|
+
metadata_json TEXT DEFAULT '{}',
|
|
629
|
+
document_count INTEGER DEFAULT 0,
|
|
630
|
+
error_text TEXT,
|
|
631
|
+
started_at TEXT DEFAULT (datetime('now')),
|
|
632
|
+
completed_at TEXT,
|
|
633
|
+
next_sync_at TEXT,
|
|
634
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
635
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
636
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
637
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL,
|
|
638
|
+
FOREIGN KEY (connection_id) REFERENCES integration_connections(id) ON DELETE SET NULL
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
CREATE TABLE IF NOT EXISTS memory_ingestion_documents (
|
|
642
|
+
id TEXT PRIMARY KEY,
|
|
643
|
+
user_id INTEGER NOT NULL,
|
|
644
|
+
agent_id TEXT,
|
|
645
|
+
source_type TEXT NOT NULL,
|
|
646
|
+
normalized_type TEXT NOT NULL,
|
|
647
|
+
provider_key TEXT DEFAULT '',
|
|
648
|
+
connection_id INTEGER NOT NULL DEFAULT 0,
|
|
649
|
+
external_object_id TEXT NOT NULL,
|
|
650
|
+
source_account TEXT,
|
|
651
|
+
title TEXT,
|
|
652
|
+
content TEXT NOT NULL,
|
|
653
|
+
summary TEXT,
|
|
654
|
+
salience INTEGER DEFAULT 5,
|
|
655
|
+
source_timestamp TEXT,
|
|
656
|
+
metadata_json TEXT DEFAULT '{}',
|
|
657
|
+
payload_json TEXT DEFAULT '{}',
|
|
658
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
659
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
660
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
661
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL,
|
|
662
|
+
UNIQUE(user_id, agent_id, source_type, provider_key, connection_id, external_object_id)
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
CREATE TABLE IF NOT EXISTS materialized_knowledge_views (
|
|
666
|
+
id TEXT PRIMARY KEY,
|
|
667
|
+
user_id INTEGER NOT NULL,
|
|
668
|
+
agent_id TEXT,
|
|
669
|
+
view_type TEXT NOT NULL,
|
|
670
|
+
subject_key TEXT NOT NULL,
|
|
671
|
+
title TEXT NOT NULL,
|
|
672
|
+
summary TEXT,
|
|
673
|
+
markdown_text TEXT,
|
|
674
|
+
source_memory_ids_json TEXT DEFAULT '[]',
|
|
675
|
+
source_document_ids_json TEXT DEFAULT '[]',
|
|
676
|
+
metadata_json TEXT DEFAULT '{}',
|
|
677
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
678
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
679
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
680
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE SET NULL,
|
|
681
|
+
UNIQUE(user_id, agent_id, view_type, subject_key)
|
|
682
|
+
);
|
|
683
|
+
|
|
684
|
+
CREATE INDEX IF NOT EXISTS idx_memory_ingestion_jobs_user ON memory_ingestion_jobs(user_id, agent_id, source_type, updated_at DESC);
|
|
685
|
+
CREATE INDEX IF NOT EXISTS idx_memory_ingestion_documents_user ON memory_ingestion_documents(user_id, agent_id, source_type, updated_at DESC);
|
|
686
|
+
CREATE INDEX IF NOT EXISTS idx_memory_ingestion_documents_provider ON memory_ingestion_documents(user_id, agent_id, provider_key, connection_id, updated_at DESC);
|
|
687
|
+
CREATE INDEX IF NOT EXISTS idx_materialized_knowledge_views_user ON materialized_knowledge_views(user_id, agent_id, view_type, updated_at DESC);
|
|
688
|
+
|
|
617
689
|
CREATE TABLE IF NOT EXISTS agent_run_events (
|
|
618
690
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
619
691
|
run_id TEXT NOT NULL,
|
|
@@ -1698,6 +1770,19 @@ function migrateUsersDisplayName() {
|
|
|
1698
1770
|
}
|
|
1699
1771
|
migrateUsersDisplayName();
|
|
1700
1772
|
|
|
1773
|
+
function migrateIngestionDocumentsConnectionId() {
|
|
1774
|
+
// connection_id was initially nullable; NULL breaks the UNIQUE dedup constraint.
|
|
1775
|
+
// Coerce any existing NULLs to 0 so the unique index works as intended.
|
|
1776
|
+
try {
|
|
1777
|
+
db.prepare(
|
|
1778
|
+
`UPDATE memory_ingestion_documents SET connection_id = 0 WHERE connection_id IS NULL`
|
|
1779
|
+
).run();
|
|
1780
|
+
} catch {
|
|
1781
|
+
// Table may not exist yet on first boot; the schema DDL handles that case.
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
migrateIngestionDocumentsConnectionId();
|
|
1785
|
+
|
|
1701
1786
|
try {
|
|
1702
1787
|
db.exec(`
|
|
1703
1788
|
INSERT OR REPLACE INTO conversation_history_fts(rowid, content, role, user_id, agent_id, agent_run_id)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
e4ece615a6927257edff0063d82f2aa6
|