@sparkleideas/memory 3.0.0-alpha.10 → 3.0.0-alpha.20
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.
|
@@ -360,7 +360,7 @@ export const vectorSearchOptimizations = {
|
|
|
360
360
|
description: 'Use HNSW for O(log n) approximate nearest neighbor search',
|
|
361
361
|
expectedImprovement: '150x-12500x',
|
|
362
362
|
implementation: `
|
|
363
|
-
import { HNSW } from '
|
|
363
|
+
import { HNSW } from 'agentdb';
|
|
364
364
|
|
|
365
365
|
const index = new HNSW({
|
|
366
366
|
dimensions: 384,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AgentDB Backend Example
|
|
3
3
|
*
|
|
4
|
-
* Demonstrates
|
|
4
|
+
* Demonstrates agentdb@2.0.0-alpha.3.4 integration with V3 memory system
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { AgentDBBackend, HybridBackend, createDefaultEntry } from '../src/index.js';
|
|
@@ -119,7 +119,7 @@ async function hybridExample() {
|
|
|
119
119
|
sqlite: {
|
|
120
120
|
dbPath: ':memory:',
|
|
121
121
|
},
|
|
122
|
-
|
|
122
|
+
agentdb: {
|
|
123
123
|
dbPath: ':memory:',
|
|
124
124
|
vectorDimension: 384,
|
|
125
125
|
hnswM: 16,
|
|
@@ -278,7 +278,7 @@ async function vectorSearchExample() {
|
|
|
278
278
|
async function gracefulDegradationExample() {
|
|
279
279
|
console.log('\n=== Graceful Degradation Example ===\n');
|
|
280
280
|
|
|
281
|
-
// Create backend that might not have
|
|
281
|
+
// Create backend that might not have agentdb
|
|
282
282
|
const backend = new AgentDBBackend({
|
|
283
283
|
dbPath: ':memory:',
|
|
284
284
|
});
|
|
@@ -290,7 +290,7 @@ async function gracefulDegradationExample() {
|
|
|
290
290
|
console.log('✓ AgentDB available - using HNSW indexing');
|
|
291
291
|
} else {
|
|
292
292
|
console.log('⚠ AgentDB not available - using fallback in-memory storage');
|
|
293
|
-
console.log(' (Install: npm install
|
|
293
|
+
console.log(' (Install: npm install agentdb@2.0.0-alpha.3.4)');
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
// Store entries (works either way)
|
|
@@ -319,7 +319,7 @@ async function gracefulDegradationExample() {
|
|
|
319
319
|
async function main() {
|
|
320
320
|
console.log('╔═══════════════════════════════════════════════════════════╗');
|
|
321
321
|
console.log('║ AgentDB Integration Examples ║');
|
|
322
|
-
console.log('║ V3 Memory Module with
|
|
322
|
+
console.log('║ V3 Memory Module with agentdb@2.0.0-alpha.3.4 ║');
|
|
323
323
|
console.log('╚═══════════════════════════════════════════════════════════╝');
|
|
324
324
|
|
|
325
325
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sparkleideas/memory",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Memory module - AgentDB unification, HNSW indexing, vector search, hybrid SQLite+AgentDB backend (ADR-009)",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AgentDB Backend Tests
|
|
3
3
|
*
|
|
4
|
-
* Tests for
|
|
4
|
+
* Tests for agentdb@2.0.0-alpha.3.4 integration with V3 memory system
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
@@ -29,7 +29,7 @@ describe('AgentDBBackend', () => {
|
|
|
29
29
|
expect(backend).toBeDefined();
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('should handle missing
|
|
32
|
+
it('should handle missing agentdb gracefully', async () => {
|
|
33
33
|
const fallbackBackend = new AgentDBBackend();
|
|
34
34
|
await fallbackBackend.initialize();
|
|
35
35
|
|
|
@@ -177,7 +177,7 @@ describe('AgentDBBackend', () => {
|
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
describe('Vector Search', () => {
|
|
180
|
-
it('should perform brute-force search when
|
|
180
|
+
it('should perform brute-force search when agentdb unavailable', async () => {
|
|
181
181
|
const entry = createDefaultEntry({
|
|
182
182
|
key: 'vector-test',
|
|
183
183
|
content: 'Vector content',
|
|
@@ -311,7 +311,7 @@ describe('AgentDBBackend', () => {
|
|
|
311
311
|
});
|
|
312
312
|
|
|
313
313
|
describe('Graceful Degradation', () => {
|
|
314
|
-
it('should work without
|
|
314
|
+
it('should work without agentdb package', async () => {
|
|
315
315
|
const fallbackBackend = new AgentDBBackend({
|
|
316
316
|
dbPath: ':memory:',
|
|
317
317
|
});
|
package/src/agentdb-backend.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AgentDB Backend - Integration with
|
|
2
|
+
* AgentDB Backend - Integration with agentdb@2.0.0-alpha.3.4
|
|
3
3
|
*
|
|
4
4
|
* Provides IMemoryBackend implementation using AgentDB with:
|
|
5
5
|
* - HNSW vector search (150x-12,500x faster than brute-force)
|
|
@@ -36,14 +36,14 @@ let AgentDB: any;
|
|
|
36
36
|
let HNSWIndex: any;
|
|
37
37
|
let isHnswlibAvailable: (() => Promise<boolean>) | undefined;
|
|
38
38
|
|
|
39
|
-
// Dynamically import
|
|
39
|
+
// Dynamically import agentdb (handled at runtime)
|
|
40
40
|
let agentdbImportPromise: Promise<void> | undefined;
|
|
41
41
|
|
|
42
42
|
function ensureAgentDBImport(): Promise<void> {
|
|
43
43
|
if (!agentdbImportPromise) {
|
|
44
44
|
agentdbImportPromise = (async () => {
|
|
45
45
|
try {
|
|
46
|
-
const agentdbModule = await import('
|
|
46
|
+
const agentdbModule = await import('agentdb');
|
|
47
47
|
AgentDB = agentdbModule.AgentDB || agentdbModule.default;
|
|
48
48
|
HNSWIndex = agentdbModule.HNSWIndex;
|
|
49
49
|
isHnswlibAvailable = agentdbModule.isHnswlibAvailable;
|
|
@@ -134,7 +134,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
134
134
|
dbPath?: string;
|
|
135
135
|
embeddingGenerator?: EmbeddingGenerator;
|
|
136
136
|
};
|
|
137
|
-
private
|
|
137
|
+
private agentdb: any;
|
|
138
138
|
private initialized: boolean = false;
|
|
139
139
|
private available: boolean = false;
|
|
140
140
|
|
|
@@ -179,7 +179,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
179
179
|
|
|
180
180
|
try {
|
|
181
181
|
// Initialize AgentDB with config
|
|
182
|
-
this
|
|
182
|
+
this.agentdb = new AgentDB({
|
|
183
183
|
dbPath: this.config.dbPath || ':memory:',
|
|
184
184
|
namespace: this.config.namespace,
|
|
185
185
|
forceWasm: this.config.forceWasm,
|
|
@@ -187,15 +187,15 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
187
187
|
vectorDimension: this.config.vectorDimension,
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
-
await this
|
|
190
|
+
await this.agentdb.initialize();
|
|
191
191
|
|
|
192
192
|
// Create memory_entries table if it doesn't exist
|
|
193
193
|
await this.createSchema();
|
|
194
194
|
|
|
195
195
|
this.initialized = true;
|
|
196
196
|
this.emit('initialized', {
|
|
197
|
-
backend: this
|
|
198
|
-
isWasm: this
|
|
197
|
+
backend: this.agentdb.vectorBackendName,
|
|
198
|
+
isWasm: this.agentdb.isWasm,
|
|
199
199
|
});
|
|
200
200
|
} catch (error) {
|
|
201
201
|
console.error('Failed to initialize AgentDB:', error);
|
|
@@ -211,8 +211,8 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
211
211
|
async shutdown(): Promise<void> {
|
|
212
212
|
if (!this.initialized) return;
|
|
213
213
|
|
|
214
|
-
if (this
|
|
215
|
-
await this
|
|
214
|
+
if (this.agentdb) {
|
|
215
|
+
await this.agentdb.close();
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
this.initialized = false;
|
|
@@ -238,7 +238,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
238
238
|
this.updateIndexes(entry);
|
|
239
239
|
|
|
240
240
|
// Store in AgentDB if available
|
|
241
|
-
if (this
|
|
241
|
+
if (this.agentdb) {
|
|
242
242
|
await this.storeInAgentDB(entry);
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -254,7 +254,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
254
254
|
if (cached) return cached;
|
|
255
255
|
|
|
256
256
|
// Query AgentDB if available
|
|
257
|
-
if (this
|
|
257
|
+
if (this.agentdb) {
|
|
258
258
|
return this.getFromAgentDB(id);
|
|
259
259
|
}
|
|
260
260
|
|
|
@@ -311,7 +311,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
311
311
|
entry.version++;
|
|
312
312
|
|
|
313
313
|
// Update in AgentDB
|
|
314
|
-
if (this
|
|
314
|
+
if (this.agentdb) {
|
|
315
315
|
await this.updateInAgentDB(entry);
|
|
316
316
|
}
|
|
317
317
|
|
|
@@ -334,7 +334,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
334
334
|
this.keyIndex.delete(keyIndexKey);
|
|
335
335
|
|
|
336
336
|
// Delete from AgentDB
|
|
337
|
-
if (this
|
|
337
|
+
if (this.agentdb) {
|
|
338
338
|
await this.deleteFromAgentDB(id);
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -374,7 +374,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
374
374
|
): Promise<SearchResult[]> {
|
|
375
375
|
const startTime = performance.now();
|
|
376
376
|
|
|
377
|
-
if (!this
|
|
377
|
+
if (!this.agentdb) {
|
|
378
378
|
// Fallback to brute-force search
|
|
379
379
|
return this.bruteForceSearch(embedding, options);
|
|
380
380
|
}
|
|
@@ -473,9 +473,9 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
473
473
|
|
|
474
474
|
// Get HNSW stats if available
|
|
475
475
|
let hnswStats: HNSWStats | undefined;
|
|
476
|
-
if (this
|
|
476
|
+
if (this.agentdb && HNSWIndex) {
|
|
477
477
|
try {
|
|
478
|
-
const hnsw = this
|
|
478
|
+
const hnsw = this.agentdb.getController('hnsw');
|
|
479
479
|
if (hnsw) {
|
|
480
480
|
const stats = hnsw.getStats();
|
|
481
481
|
hnswStats = {
|
|
@@ -516,7 +516,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
516
516
|
const recommendations: string[] = [];
|
|
517
517
|
|
|
518
518
|
// Check AgentDB availability
|
|
519
|
-
const storageHealth: ComponentHealth = this
|
|
519
|
+
const storageHealth: ComponentHealth = this.agentdb
|
|
520
520
|
? { status: 'healthy', latency: 0 }
|
|
521
521
|
: {
|
|
522
522
|
status: 'degraded',
|
|
@@ -526,10 +526,10 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
526
526
|
|
|
527
527
|
// Check index health
|
|
528
528
|
const indexHealth: ComponentHealth = { status: 'healthy', latency: 0 };
|
|
529
|
-
if (!this
|
|
529
|
+
if (!this.agentdb) {
|
|
530
530
|
indexHealth.status = 'degraded';
|
|
531
531
|
indexHealth.message = 'HNSW index not available';
|
|
532
|
-
recommendations.push('Install
|
|
532
|
+
recommendations.push('Install agentdb for 150x-12,500x faster vector search');
|
|
533
533
|
}
|
|
534
534
|
|
|
535
535
|
// Check cache health
|
|
@@ -561,9 +561,9 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
561
561
|
* Create database schema
|
|
562
562
|
*/
|
|
563
563
|
private async createSchema(): Promise<void> {
|
|
564
|
-
if (!this
|
|
564
|
+
if (!this.agentdb) return;
|
|
565
565
|
|
|
566
|
-
const db = this
|
|
566
|
+
const db = this.agentdb.database;
|
|
567
567
|
if (!db || typeof db.run !== 'function') {
|
|
568
568
|
// AgentDB doesn't expose raw database - using native API
|
|
569
569
|
return;
|
|
@@ -608,12 +608,12 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
608
608
|
* Store entry in AgentDB
|
|
609
609
|
*/
|
|
610
610
|
private async storeInAgentDB(entry: MemoryEntry): Promise<void> {
|
|
611
|
-
if (!this
|
|
611
|
+
if (!this.agentdb) return;
|
|
612
612
|
|
|
613
|
-
// Try to use
|
|
613
|
+
// Try to use agentdb's native store method if available
|
|
614
614
|
try {
|
|
615
|
-
if (typeof this
|
|
616
|
-
await this
|
|
615
|
+
if (typeof this.agentdb.store === 'function') {
|
|
616
|
+
await this.agentdb.store(entry.id, {
|
|
617
617
|
key: entry.key,
|
|
618
618
|
content: entry.content,
|
|
619
619
|
embedding: entry.embedding,
|
|
@@ -626,9 +626,9 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
626
626
|
}
|
|
627
627
|
|
|
628
628
|
// Fallback: use database directly if available
|
|
629
|
-
const db = this
|
|
629
|
+
const db = this.agentdb.database;
|
|
630
630
|
if (!db || typeof db.run !== 'function') {
|
|
631
|
-
// No compatible database interface - skip
|
|
631
|
+
// No compatible database interface - skip agentdb storage
|
|
632
632
|
// Entry is already stored in-memory
|
|
633
633
|
return;
|
|
634
634
|
}
|
|
@@ -668,7 +668,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
668
668
|
// Add to vector index if HNSW is available
|
|
669
669
|
if (entry.embedding && HNSWIndex) {
|
|
670
670
|
try {
|
|
671
|
-
const hnsw = this
|
|
671
|
+
const hnsw = this.agentdb.getController('hnsw');
|
|
672
672
|
if (hnsw) {
|
|
673
673
|
// Convert string ID to number for HNSW (use hash)
|
|
674
674
|
const numericId = this.stringIdToNumeric(entry.id);
|
|
@@ -684,17 +684,17 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
684
684
|
* Get entry from AgentDB
|
|
685
685
|
*/
|
|
686
686
|
private async getFromAgentDB(id: string): Promise<MemoryEntry | null> {
|
|
687
|
-
if (!this
|
|
687
|
+
if (!this.agentdb) return null;
|
|
688
688
|
|
|
689
689
|
try {
|
|
690
690
|
// Try native get method first
|
|
691
|
-
if (typeof this
|
|
692
|
-
const data = await this
|
|
691
|
+
if (typeof this.agentdb.get === 'function') {
|
|
692
|
+
const data = await this.agentdb.get(id);
|
|
693
693
|
if (data) return this.dataToEntry(id, data);
|
|
694
694
|
}
|
|
695
695
|
|
|
696
696
|
// Fallback to database
|
|
697
|
-
const db = this
|
|
697
|
+
const db = this.agentdb.database;
|
|
698
698
|
if (!db || typeof db.get !== 'function') return null;
|
|
699
699
|
|
|
700
700
|
const row = await db.get('SELECT * FROM memory_entries WHERE id = ?', [id]);
|
|
@@ -706,7 +706,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
706
706
|
}
|
|
707
707
|
|
|
708
708
|
/**
|
|
709
|
-
* Convert
|
|
709
|
+
* Convert agentdb data to MemoryEntry
|
|
710
710
|
*/
|
|
711
711
|
private dataToEntry(id: string, data: any): MemoryEntry {
|
|
712
712
|
const now = Date.now();
|
|
@@ -742,17 +742,17 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
742
742
|
* Delete entry from AgentDB
|
|
743
743
|
*/
|
|
744
744
|
private async deleteFromAgentDB(id: string): Promise<void> {
|
|
745
|
-
if (!this
|
|
745
|
+
if (!this.agentdb) return;
|
|
746
746
|
|
|
747
747
|
try {
|
|
748
748
|
// Try native delete method first
|
|
749
|
-
if (typeof this
|
|
750
|
-
await this
|
|
749
|
+
if (typeof this.agentdb.delete === 'function') {
|
|
750
|
+
await this.agentdb.delete(id);
|
|
751
751
|
return;
|
|
752
752
|
}
|
|
753
753
|
|
|
754
754
|
// Fallback to database
|
|
755
|
-
const db = this
|
|
755
|
+
const db = this.agentdb.database;
|
|
756
756
|
if (!db || typeof db.run !== 'function') return;
|
|
757
757
|
|
|
758
758
|
await db.run('DELETE FROM memory_entries WHERE id = ?', [id]);
|
|
@@ -768,12 +768,12 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
768
768
|
embedding: Float32Array,
|
|
769
769
|
options: SearchOptions
|
|
770
770
|
): Promise<SearchResult[]> {
|
|
771
|
-
if (!this
|
|
771
|
+
if (!this.agentdb || !HNSWIndex) {
|
|
772
772
|
return [];
|
|
773
773
|
}
|
|
774
774
|
|
|
775
775
|
try {
|
|
776
|
-
const hnsw = this
|
|
776
|
+
const hnsw = this.agentdb.getController('hnsw');
|
|
777
777
|
if (!hnsw) {
|
|
778
778
|
return this.bruteForceSearch(embedding, options);
|
|
779
779
|
}
|
|
@@ -1009,7 +1009,7 @@ export class AgentDBBackend extends EventEmitter implements IMemoryBackend {
|
|
|
1009
1009
|
* Get underlying AgentDB instance
|
|
1010
1010
|
*/
|
|
1011
1011
|
getAgentDB(): any {
|
|
1012
|
-
return this
|
|
1012
|
+
return this.agentdb;
|
|
1013
1013
|
}
|
|
1014
1014
|
}
|
|
1015
1015
|
|
package/src/hybrid-backend.ts
CHANGED
|
@@ -35,7 +35,7 @@ export interface HybridBackendConfig {
|
|
|
35
35
|
sqlite?: Partial<SQLiteBackendConfig>;
|
|
36
36
|
|
|
37
37
|
/** AgentDB configuration */
|
|
38
|
-
|
|
38
|
+
agentdb?: Partial<AgentDBBackendConfig>;
|
|
39
39
|
|
|
40
40
|
/** Default namespace */
|
|
41
41
|
defaultNamespace?: string;
|
|
@@ -61,7 +61,7 @@ export interface HybridBackendConfig {
|
|
|
61
61
|
*/
|
|
62
62
|
const DEFAULT_CONFIG: Required<HybridBackendConfig> = {
|
|
63
63
|
sqlite: {},
|
|
64
|
-
|
|
64
|
+
agentdb: {},
|
|
65
65
|
defaultNamespace: 'default',
|
|
66
66
|
embeddingGenerator: undefined as any,
|
|
67
67
|
routingStrategy: 'auto',
|
|
@@ -153,7 +153,7 @@ export interface HybridQuery {
|
|
|
153
153
|
*/
|
|
154
154
|
export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
155
155
|
private sqlite: SQLiteBackend;
|
|
156
|
-
private
|
|
156
|
+
private agentdb: AgentDBBackend;
|
|
157
157
|
private config: Required<HybridBackendConfig>;
|
|
158
158
|
private initialized: boolean = false;
|
|
159
159
|
|
|
@@ -177,8 +177,8 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
// Initialize AgentDB backend
|
|
180
|
-
this
|
|
181
|
-
...this.config
|
|
180
|
+
this.agentdb = new AgentDBBackend({
|
|
181
|
+
...this.config.agentdb,
|
|
182
182
|
namespace: this.config.defaultNamespace,
|
|
183
183
|
embeddingGenerator: this.config.embeddingGenerator,
|
|
184
184
|
});
|
|
@@ -188,11 +188,11 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
188
188
|
this.sqlite.on('entry:updated', (data) => this.emit('sqlite:updated', data));
|
|
189
189
|
this.sqlite.on('entry:deleted', (data) => this.emit('sqlite:deleted', data));
|
|
190
190
|
|
|
191
|
-
this
|
|
192
|
-
this
|
|
193
|
-
this
|
|
194
|
-
this
|
|
195
|
-
this
|
|
191
|
+
this.agentdb.on('entry:stored', (data) => this.emit('agentdb:stored', data));
|
|
192
|
+
this.agentdb.on('entry:updated', (data) => this.emit('agentdb:updated', data));
|
|
193
|
+
this.agentdb.on('entry:deleted', (data) => this.emit('agentdb:deleted', data));
|
|
194
|
+
this.agentdb.on('cache:hit', (data) => this.emit('cache:hit', data));
|
|
195
|
+
this.agentdb.on('cache:miss', (data) => this.emit('cache:miss', data));
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/**
|
|
@@ -201,7 +201,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
201
201
|
async initialize(): Promise<void> {
|
|
202
202
|
if (this.initialized) return;
|
|
203
203
|
|
|
204
|
-
await Promise.all([this.sqlite.initialize(), this
|
|
204
|
+
await Promise.all([this.sqlite.initialize(), this.agentdb.initialize()]);
|
|
205
205
|
|
|
206
206
|
this.initialized = true;
|
|
207
207
|
this.emit('initialized');
|
|
@@ -213,7 +213,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
213
213
|
async shutdown(): Promise<void> {
|
|
214
214
|
if (!this.initialized) return;
|
|
215
215
|
|
|
216
|
-
await Promise.all([this.sqlite.shutdown(), this
|
|
216
|
+
await Promise.all([this.sqlite.shutdown(), this.agentdb.shutdown()]);
|
|
217
217
|
|
|
218
218
|
this.initialized = false;
|
|
219
219
|
this.emit('shutdown');
|
|
@@ -225,10 +225,10 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
225
225
|
async store(entry: MemoryEntry): Promise<void> {
|
|
226
226
|
if (this.config.dualWrite) {
|
|
227
227
|
// Write to both backends in parallel
|
|
228
|
-
await Promise.all([this.sqlite.store(entry), this
|
|
228
|
+
await Promise.all([this.sqlite.store(entry), this.agentdb.store(entry)]);
|
|
229
229
|
} else {
|
|
230
230
|
// Write to primary backend only (AgentDB has vector search)
|
|
231
|
-
await this
|
|
231
|
+
await this.agentdb.store(entry);
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
this.emit('entry:stored', { id: entry.id });
|
|
@@ -238,7 +238,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
238
238
|
* Get from AgentDB (has caching enabled)
|
|
239
239
|
*/
|
|
240
240
|
async get(id: string): Promise<MemoryEntry | null> {
|
|
241
|
-
return this
|
|
241
|
+
return this.agentdb.get(id);
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
/**
|
|
@@ -256,11 +256,11 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
256
256
|
// Update both backends
|
|
257
257
|
const [sqliteResult, agentdbResult] = await Promise.all([
|
|
258
258
|
this.sqlite.update(id, update),
|
|
259
|
-
this
|
|
259
|
+
this.agentdb.update(id, update),
|
|
260
260
|
]);
|
|
261
261
|
return agentdbResult || sqliteResult;
|
|
262
262
|
} else {
|
|
263
|
-
return this
|
|
263
|
+
return this.agentdb.update(id, update);
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
@@ -271,11 +271,11 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
271
271
|
if (this.config.dualWrite) {
|
|
272
272
|
const [sqliteResult, agentdbResult] = await Promise.all([
|
|
273
273
|
this.sqlite.delete(id),
|
|
274
|
-
this
|
|
274
|
+
this.agentdb.delete(id),
|
|
275
275
|
]);
|
|
276
276
|
return sqliteResult || agentdbResult;
|
|
277
277
|
} else {
|
|
278
|
-
return this
|
|
278
|
+
return this.agentdb.delete(id);
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
|
|
@@ -310,7 +310,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
310
310
|
case 'semantic':
|
|
311
311
|
// AgentDB optimized for semantic search
|
|
312
312
|
this.stats.agentdbQueries++;
|
|
313
|
-
results = await this
|
|
313
|
+
results = await this.agentdb.query(query);
|
|
314
314
|
break;
|
|
315
315
|
|
|
316
316
|
case 'hybrid':
|
|
@@ -374,7 +374,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
374
374
|
throw new Error('SemanticQuery requires either content or embedding');
|
|
375
375
|
}
|
|
376
376
|
|
|
377
|
-
const searchResults = await this
|
|
377
|
+
const searchResults = await this.agentdb.search(embedding, {
|
|
378
378
|
k: query.k || 10,
|
|
379
379
|
threshold: query.threshold || this.config.semanticThreshold,
|
|
380
380
|
filters: query.filters as MemoryQuery | undefined,
|
|
@@ -423,7 +423,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
423
423
|
*/
|
|
424
424
|
async search(embedding: Float32Array, options: SearchOptions): Promise<SearchResult[]> {
|
|
425
425
|
this.stats.agentdbQueries++;
|
|
426
|
-
return this
|
|
426
|
+
return this.agentdb.search(embedding, options);
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
/**
|
|
@@ -431,9 +431,9 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
431
431
|
*/
|
|
432
432
|
async bulkInsert(entries: MemoryEntry[]): Promise<void> {
|
|
433
433
|
if (this.config.dualWrite) {
|
|
434
|
-
await Promise.all([this.sqlite.bulkInsert(entries), this
|
|
434
|
+
await Promise.all([this.sqlite.bulkInsert(entries), this.agentdb.bulkInsert(entries)]);
|
|
435
435
|
} else {
|
|
436
|
-
await this
|
|
436
|
+
await this.agentdb.bulkInsert(entries);
|
|
437
437
|
}
|
|
438
438
|
}
|
|
439
439
|
|
|
@@ -444,11 +444,11 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
444
444
|
if (this.config.dualWrite) {
|
|
445
445
|
const [sqliteCount, agentdbCount] = await Promise.all([
|
|
446
446
|
this.sqlite.bulkDelete(ids),
|
|
447
|
-
this
|
|
447
|
+
this.agentdb.bulkDelete(ids),
|
|
448
448
|
]);
|
|
449
449
|
return Math.max(sqliteCount, agentdbCount);
|
|
450
450
|
} else {
|
|
451
|
-
return this
|
|
451
|
+
return this.agentdb.bulkDelete(ids);
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
|
|
@@ -473,11 +473,11 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
473
473
|
if (this.config.dualWrite) {
|
|
474
474
|
const [sqliteCount, agentdbCount] = await Promise.all([
|
|
475
475
|
this.sqlite.clearNamespace(namespace),
|
|
476
|
-
this
|
|
476
|
+
this.agentdb.clearNamespace(namespace),
|
|
477
477
|
]);
|
|
478
478
|
return Math.max(sqliteCount, agentdbCount);
|
|
479
479
|
} else {
|
|
480
|
-
return this
|
|
480
|
+
return this.agentdb.clearNamespace(namespace);
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
483
|
|
|
@@ -487,7 +487,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
487
487
|
async getStats(): Promise<BackendStats> {
|
|
488
488
|
const [sqliteStats, agentdbStats] = await Promise.all([
|
|
489
489
|
this.sqlite.getStats(),
|
|
490
|
-
this
|
|
490
|
+
this.agentdb.getStats(),
|
|
491
491
|
]);
|
|
492
492
|
|
|
493
493
|
return {
|
|
@@ -512,7 +512,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
512
512
|
async healthCheck(): Promise<HealthCheckResult> {
|
|
513
513
|
const [sqliteHealth, agentdbHealth] = await Promise.all([
|
|
514
514
|
this.sqlite.healthCheck(),
|
|
515
|
-
this
|
|
515
|
+
this.agentdb.healthCheck(),
|
|
516
516
|
]);
|
|
517
517
|
|
|
518
518
|
const allIssues = [...sqliteHealth.issues, ...agentdbHealth.issues];
|
|
@@ -558,7 +558,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
558
558
|
const hasEmbeddingGenerator = typeof this.config.embeddingGenerator === 'function';
|
|
559
559
|
if (query.embedding || (query.content && hasEmbeddingGenerator)) {
|
|
560
560
|
this.stats.agentdbQueries++;
|
|
561
|
-
return this
|
|
561
|
+
return this.agentdb.query(query);
|
|
562
562
|
}
|
|
563
563
|
|
|
564
564
|
// If has exact key or prefix, use structured search (SQLite)
|
|
@@ -575,13 +575,13 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
575
575
|
|
|
576
576
|
case 'agentdb-first':
|
|
577
577
|
this.stats.agentdbQueries++;
|
|
578
|
-
return this
|
|
578
|
+
return this.agentdb.query(query);
|
|
579
579
|
|
|
580
580
|
case 'auto':
|
|
581
581
|
default:
|
|
582
582
|
// Default to AgentDB (has caching)
|
|
583
583
|
this.stats.agentdbQueries++;
|
|
584
|
-
return this
|
|
584
|
+
return this.agentdb.query(query);
|
|
585
585
|
}
|
|
586
586
|
}
|
|
587
587
|
|
|
@@ -687,7 +687,7 @@ export class HybridBackend extends EventEmitter implements IMemoryBackend {
|
|
|
687
687
|
}
|
|
688
688
|
|
|
689
689
|
getAgentDBBackend(): AgentDBBackend {
|
|
690
|
-
return this
|
|
690
|
+
return this.agentdb;
|
|
691
691
|
}
|
|
692
692
|
}
|
|
693
693
|
|