agentic-flow 2.0.1-alpha.19 → 2.0.1-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.
@@ -1,14 +1,17 @@
1
1
  /**
2
- * EmbeddingCache - Persistent SQLite cache for embeddings
2
+ * EmbeddingCache - Persistent cache for embeddings
3
3
  *
4
4
  * Makes ONNX embeddings practical by caching across sessions:
5
5
  * - First embed: ~400ms (ONNX inference)
6
- * - Cached embed: ~0.1ms (SQLite lookup)
6
+ * - Cached embed: ~0.1ms (SQLite lookup) or ~0.01ms (in-memory fallback)
7
7
  *
8
- * Storage: ~/.agentic-flow/embedding-cache.db
8
+ * Storage: ~/.agentic-flow/embedding-cache.db (if SQLite available)
9
+ *
10
+ * Windows Compatibility:
11
+ * - Falls back to in-memory cache if better-sqlite3 compilation fails
12
+ * - No native module compilation required for basic functionality
9
13
  */
10
- import Database from 'better-sqlite3';
11
- import { existsSync, mkdirSync } from 'fs';
14
+ import { existsSync, mkdirSync, statSync, readFileSync, writeFileSync } from 'fs';
12
15
  import { join } from 'path';
13
16
  import { homedir } from 'os';
14
17
  import { createHash } from 'crypto';
@@ -18,8 +21,303 @@ const DEFAULT_CONFIG = {
18
21
  maxAgeDays: 30,
19
22
  dbPath: join(homedir(), '.agentic-flow', 'embedding-cache.db'),
20
23
  dimension: 384,
24
+ forceMemory: false,
21
25
  };
22
- export class EmbeddingCache {
26
+ // Check if better-sqlite3 is available (native, fastest)
27
+ let BetterSqlite3 = null;
28
+ let nativeSqliteAvailable = false;
29
+ // Check if sql.js is available (WASM, cross-platform)
30
+ let SqlJs = null;
31
+ let wasmSqliteAvailable = false;
32
+ try {
33
+ // Try native SQLite first (fastest)
34
+ BetterSqlite3 = require('better-sqlite3');
35
+ nativeSqliteAvailable = true;
36
+ }
37
+ catch {
38
+ // Native not available, try WASM fallback
39
+ try {
40
+ SqlJs = require('sql.js');
41
+ wasmSqliteAvailable = true;
42
+ }
43
+ catch {
44
+ // Neither available, will use memory cache
45
+ }
46
+ }
47
+ const sqliteAvailable = nativeSqliteAvailable || wasmSqliteAvailable;
48
+ /**
49
+ * In-memory cache fallback for Windows compatibility
50
+ */
51
+ class MemoryCache {
52
+ cache = new Map();
53
+ maxEntries;
54
+ hits = 0;
55
+ misses = 0;
56
+ constructor(maxEntries = 10000) {
57
+ this.maxEntries = maxEntries;
58
+ }
59
+ get(hash) {
60
+ const entry = this.cache.get(hash);
61
+ if (entry) {
62
+ entry.hits++;
63
+ entry.accessed = Date.now();
64
+ this.hits++;
65
+ return { embedding: entry.embedding, dimension: entry.embedding.length };
66
+ }
67
+ this.misses++;
68
+ return null;
69
+ }
70
+ set(hash, text, embedding, model) {
71
+ const now = Date.now();
72
+ this.cache.set(hash, {
73
+ embedding,
74
+ model,
75
+ hits: 1,
76
+ created: now,
77
+ accessed: now,
78
+ });
79
+ // Evict if over limit
80
+ if (this.cache.size > this.maxEntries) {
81
+ this.evictLRU(Math.ceil(this.maxEntries * 0.1));
82
+ }
83
+ }
84
+ has(hash) {
85
+ return this.cache.has(hash);
86
+ }
87
+ evictLRU(count) {
88
+ const entries = Array.from(this.cache.entries())
89
+ .sort((a, b) => a[1].accessed - b[1].accessed)
90
+ .slice(0, count);
91
+ for (const [key] of entries) {
92
+ this.cache.delete(key);
93
+ }
94
+ }
95
+ clear() {
96
+ this.cache.clear();
97
+ this.hits = 0;
98
+ this.misses = 0;
99
+ }
100
+ getStats() {
101
+ const entries = Array.from(this.cache.values());
102
+ const oldest = entries.length > 0 ? Math.min(...entries.map(e => e.created)) : 0;
103
+ const newest = entries.length > 0 ? Math.max(...entries.map(e => e.created)) : 0;
104
+ return {
105
+ totalEntries: this.cache.size,
106
+ hits: this.hits,
107
+ misses: this.misses,
108
+ hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
109
+ dbSizeBytes: this.cache.size * 384 * 4, // Approximate
110
+ oldestEntry: oldest,
111
+ newestEntry: newest,
112
+ backend: 'memory',
113
+ };
114
+ }
115
+ }
116
+ /**
117
+ * WASM SQLite cache (sql.js) - Cross-platform with persistence
118
+ * Works on Windows without native compilation
119
+ */
120
+ class WasmSqliteCache {
121
+ db = null;
122
+ config;
123
+ hits = 0;
124
+ misses = 0;
125
+ dirty = false;
126
+ saveTimeout = null;
127
+ constructor(config) {
128
+ this.config = config;
129
+ }
130
+ async init() {
131
+ if (this.db)
132
+ return;
133
+ // Ensure directory exists
134
+ const dir = join(homedir(), '.agentic-flow');
135
+ if (!existsSync(dir)) {
136
+ mkdirSync(dir, { recursive: true });
137
+ }
138
+ // Initialize sql.js
139
+ const SQL = await SqlJs();
140
+ // Load existing database or create new
141
+ const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
142
+ try {
143
+ if (existsSync(dbPath)) {
144
+ const buffer = readFileSync(dbPath);
145
+ this.db = new SQL.Database(buffer);
146
+ }
147
+ else {
148
+ this.db = new SQL.Database();
149
+ }
150
+ }
151
+ catch {
152
+ this.db = new SQL.Database();
153
+ }
154
+ this.initSchema();
155
+ this.cleanupOldEntries();
156
+ }
157
+ initSchema() {
158
+ this.db.run(`
159
+ CREATE TABLE IF NOT EXISTS embeddings (
160
+ hash TEXT PRIMARY KEY,
161
+ text TEXT NOT NULL,
162
+ embedding BLOB NOT NULL,
163
+ dimension INTEGER NOT NULL,
164
+ model TEXT NOT NULL,
165
+ hits INTEGER DEFAULT 1,
166
+ created_at INTEGER NOT NULL,
167
+ last_accessed INTEGER NOT NULL
168
+ )
169
+ `);
170
+ this.db.run(`CREATE INDEX IF NOT EXISTS idx_last_accessed ON embeddings(last_accessed)`);
171
+ this.db.run(`CREATE INDEX IF NOT EXISTS idx_created_at ON embeddings(created_at)`);
172
+ }
173
+ save() {
174
+ // Debounce saves
175
+ if (this.saveTimeout)
176
+ return;
177
+ this.saveTimeout = setTimeout(() => {
178
+ try {
179
+ const data = this.db.export();
180
+ const buffer = Buffer.from(data);
181
+ const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
182
+ writeFileSync(dbPath, buffer);
183
+ this.dirty = false;
184
+ }
185
+ catch (err) {
186
+ console.warn('[WasmSqliteCache] Save failed:', err);
187
+ }
188
+ this.saveTimeout = null;
189
+ }, 1000);
190
+ }
191
+ get(hash) {
192
+ if (!this.db)
193
+ return null;
194
+ const stmt = this.db.prepare(`SELECT embedding, dimension FROM embeddings WHERE hash = ?`);
195
+ stmt.bind([hash]);
196
+ if (stmt.step()) {
197
+ const row = stmt.getAsObject();
198
+ stmt.free();
199
+ this.hits++;
200
+ this.db.run(`UPDATE embeddings SET hits = hits + 1, last_accessed = ? WHERE hash = ?`, [Date.now(), hash]);
201
+ this.dirty = true;
202
+ this.save();
203
+ // Convert Uint8Array to Float32Array
204
+ const uint8 = row.embedding;
205
+ const float32 = new Float32Array(uint8.buffer, uint8.byteOffset, row.dimension);
206
+ return { embedding: float32, dimension: row.dimension };
207
+ }
208
+ stmt.free();
209
+ this.misses++;
210
+ return null;
211
+ }
212
+ set(hash, text, embedding, model) {
213
+ if (!this.db)
214
+ return;
215
+ const now = Date.now();
216
+ const buffer = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
217
+ this.db.run(`INSERT OR REPLACE INTO embeddings (hash, text, embedding, dimension, model, hits, created_at, last_accessed)
218
+ VALUES (?, ?, ?, ?, ?, 1, ?, ?)`, [hash, text, buffer, embedding.length, model, now, now]);
219
+ this.dirty = true;
220
+ this.maybeEvict();
221
+ this.save();
222
+ }
223
+ has(hash) {
224
+ if (!this.db)
225
+ return false;
226
+ const stmt = this.db.prepare(`SELECT 1 FROM embeddings WHERE hash = ? LIMIT 1`);
227
+ stmt.bind([hash]);
228
+ const found = stmt.step();
229
+ stmt.free();
230
+ return found;
231
+ }
232
+ maybeEvict() {
233
+ const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM embeddings`);
234
+ countStmt.step();
235
+ const count = countStmt.getAsObject().count;
236
+ countStmt.free();
237
+ if (count > this.config.maxEntries) {
238
+ const toEvict = Math.ceil(this.config.maxEntries * 0.1);
239
+ this.db.run(`DELETE FROM embeddings WHERE hash IN (
240
+ SELECT hash FROM embeddings ORDER BY last_accessed ASC LIMIT ?
241
+ )`, [toEvict]);
242
+ }
243
+ }
244
+ cleanupOldEntries() {
245
+ const cutoff = Date.now() - (this.config.maxAgeDays * 24 * 60 * 60 * 1000);
246
+ this.db.run(`DELETE FROM embeddings WHERE created_at < ?`, [cutoff]);
247
+ }
248
+ clear() {
249
+ if (this.db) {
250
+ this.db.run('DELETE FROM embeddings');
251
+ this.hits = 0;
252
+ this.misses = 0;
253
+ this.save();
254
+ }
255
+ }
256
+ close() {
257
+ if (this.saveTimeout) {
258
+ clearTimeout(this.saveTimeout);
259
+ // Force save
260
+ try {
261
+ const data = this.db.export();
262
+ const buffer = Buffer.from(data);
263
+ const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
264
+ writeFileSync(dbPath, buffer);
265
+ }
266
+ catch { }
267
+ }
268
+ if (this.db) {
269
+ this.db.close();
270
+ this.db = null;
271
+ }
272
+ }
273
+ getStats() {
274
+ if (!this.db) {
275
+ return {
276
+ totalEntries: 0,
277
+ hits: this.hits,
278
+ misses: this.misses,
279
+ hitRate: 0,
280
+ dbSizeBytes: 0,
281
+ oldestEntry: 0,
282
+ newestEntry: 0,
283
+ backend: 'memory',
284
+ };
285
+ }
286
+ const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM embeddings`);
287
+ countStmt.step();
288
+ const count = countStmt.getAsObject().count;
289
+ countStmt.free();
290
+ const oldestStmt = this.db.prepare(`SELECT MIN(created_at) as oldest FROM embeddings`);
291
+ oldestStmt.step();
292
+ const oldest = oldestStmt.getAsObject().oldest || 0;
293
+ oldestStmt.free();
294
+ const newestStmt = this.db.prepare(`SELECT MAX(created_at) as newest FROM embeddings`);
295
+ newestStmt.step();
296
+ const newest = newestStmt.getAsObject().newest || 0;
297
+ newestStmt.free();
298
+ let dbSizeBytes = 0;
299
+ try {
300
+ const dbPath = this.config.dbPath.replace('.db', '-wasm.db');
301
+ const stats = statSync(dbPath);
302
+ dbSizeBytes = stats.size;
303
+ }
304
+ catch { }
305
+ return {
306
+ totalEntries: count,
307
+ hits: this.hits,
308
+ misses: this.misses,
309
+ hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
310
+ dbSizeBytes,
311
+ oldestEntry: oldest,
312
+ newestEntry: newest,
313
+ backend: 'file',
314
+ };
315
+ }
316
+ }
317
+ /**
318
+ * Native SQLite cache (better-sqlite3) - Fastest option
319
+ */
320
+ class SqliteCache {
23
321
  db;
24
322
  config;
25
323
  hits = 0;
@@ -31,15 +329,16 @@ export class EmbeddingCache {
31
329
  stmtCount;
32
330
  stmtEvictOld;
33
331
  stmtEvictLRU;
34
- constructor(config = {}) {
35
- this.config = { ...DEFAULT_CONFIG, ...config };
332
+ stmtHas;
333
+ constructor(config) {
334
+ this.config = config;
36
335
  // Ensure directory exists
37
336
  const dir = join(homedir(), '.agentic-flow');
38
337
  if (!existsSync(dir)) {
39
338
  mkdirSync(dir, { recursive: true });
40
339
  }
41
340
  // Open database with WAL mode for better concurrency
42
- this.db = new Database(this.config.dbPath);
341
+ this.db = new BetterSqlite3(this.config.dbPath);
43
342
  this.db.pragma('journal_mode = WAL');
44
343
  this.db.pragma('synchronous = NORMAL');
45
344
  this.db.pragma('cache_size = 10000');
@@ -85,6 +384,117 @@ export class EmbeddingCache {
85
384
  SELECT hash FROM embeddings ORDER BY last_accessed ASC LIMIT ?
86
385
  )
87
386
  `);
387
+ this.stmtHas = this.db.prepare(`SELECT 1 FROM embeddings WHERE hash = ? LIMIT 1`);
388
+ }
389
+ get(hash) {
390
+ const row = this.stmtGet.get(hash);
391
+ if (row) {
392
+ this.hits++;
393
+ this.stmtUpdateHits.run(Date.now(), hash);
394
+ return {
395
+ embedding: new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.dimension),
396
+ dimension: row.dimension,
397
+ };
398
+ }
399
+ this.misses++;
400
+ return null;
401
+ }
402
+ set(hash, text, embedding, model) {
403
+ const now = Date.now();
404
+ const buffer = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
405
+ this.stmtInsert.run(hash, text, buffer, embedding.length, model, now, now);
406
+ this.maybeEvict();
407
+ }
408
+ has(hash) {
409
+ return this.stmtHas.get(hash) !== undefined;
410
+ }
411
+ maybeEvict() {
412
+ const count = this.stmtCount.get().count;
413
+ if (count > this.config.maxEntries) {
414
+ const toEvict = Math.ceil(this.config.maxEntries * 0.1);
415
+ this.stmtEvictLRU.run(toEvict);
416
+ }
417
+ }
418
+ cleanupOldEntries() {
419
+ const cutoff = Date.now() - (this.config.maxAgeDays * 24 * 60 * 60 * 1000);
420
+ this.stmtEvictOld.run(cutoff);
421
+ }
422
+ clear() {
423
+ this.db.exec('DELETE FROM embeddings');
424
+ this.hits = 0;
425
+ this.misses = 0;
426
+ }
427
+ vacuum() {
428
+ this.db.exec('VACUUM');
429
+ }
430
+ close() {
431
+ this.db.close();
432
+ }
433
+ getStats() {
434
+ const count = this.stmtCount.get().count;
435
+ const oldest = this.db.prepare(`SELECT MIN(created_at) as oldest FROM embeddings`).get();
436
+ const newest = this.db.prepare(`SELECT MAX(created_at) as newest FROM embeddings`).get();
437
+ let dbSizeBytes = 0;
438
+ try {
439
+ const stats = statSync(this.config.dbPath);
440
+ dbSizeBytes = stats.size;
441
+ }
442
+ catch { }
443
+ return {
444
+ totalEntries: count,
445
+ hits: this.hits,
446
+ misses: this.misses,
447
+ hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
448
+ dbSizeBytes,
449
+ oldestEntry: oldest.oldest || 0,
450
+ newestEntry: newest.newest || 0,
451
+ backend: 'sqlite',
452
+ };
453
+ }
454
+ }
455
+ /**
456
+ * EmbeddingCache - Auto-selects best available backend
457
+ *
458
+ * Backend priority:
459
+ * 1. Native SQLite (better-sqlite3) - Fastest, 9000x speedup
460
+ * 2. WASM SQLite (sql.js) - Cross-platform with persistence
461
+ * 3. Memory cache - Fallback, no persistence
462
+ */
463
+ export class EmbeddingCache {
464
+ backend;
465
+ config;
466
+ wasmInitPromise = null;
467
+ constructor(config = {}) {
468
+ this.config = { ...DEFAULT_CONFIG, ...config };
469
+ // Try native SQLite first (fastest)
470
+ if (nativeSqliteAvailable && !this.config.forceMemory) {
471
+ try {
472
+ this.backend = new SqliteCache(this.config);
473
+ return;
474
+ }
475
+ catch (err) {
476
+ console.warn('[EmbeddingCache] Native SQLite failed, trying WASM fallback');
477
+ }
478
+ }
479
+ // Try WASM SQLite second (cross-platform with persistence)
480
+ if (wasmSqliteAvailable && !this.config.forceMemory) {
481
+ this.backend = new WasmSqliteCache(this.config);
482
+ this.wasmInitPromise = this.backend.init().catch(err => {
483
+ console.warn('[EmbeddingCache] WASM SQLite init failed, using memory cache');
484
+ this.backend = new MemoryCache(this.config.maxEntries);
485
+ });
486
+ return;
487
+ }
488
+ // Fallback to memory cache
489
+ this.backend = new MemoryCache(this.config.maxEntries);
490
+ }
491
+ /**
492
+ * Ensure WASM backend is initialized (if using)
493
+ */
494
+ async ensureInit() {
495
+ if (this.wasmInitPromise) {
496
+ await this.wasmInitPromise;
497
+ }
88
498
  }
89
499
  /**
90
500
  * Generate hash key for text + model combination
@@ -94,44 +504,33 @@ export class EmbeddingCache {
94
504
  }
95
505
  /**
96
506
  * Get embedding from cache
97
- * Returns null if not found
98
507
  */
99
508
  get(text, model = 'default') {
100
509
  const hash = this.hashKey(text, model);
101
- const row = this.stmtGet.get(hash);
102
- if (row) {
103
- this.hits++;
104
- // Update access time and hit count
105
- this.stmtUpdateHits.run(Date.now(), hash);
106
- // Convert Buffer back to Float32Array
107
- return new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.dimension);
108
- }
109
- this.misses++;
110
- return null;
510
+ const result = this.backend.get(hash);
511
+ return result ? result.embedding : null;
111
512
  }
112
513
  /**
113
514
  * Store embedding in cache
114
515
  */
115
516
  set(text, embedding, model = 'default') {
116
517
  const hash = this.hashKey(text, model);
117
- const now = Date.now();
118
- // Convert Float32Array to Buffer
119
- const buffer = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
120
- this.stmtInsert.run(hash, text, buffer, embedding.length, model, now, now);
121
- // Check if we need to evict
122
- this.maybeEvict();
518
+ if (this.backend instanceof SqliteCache) {
519
+ this.backend.set(hash, text, embedding, model);
520
+ }
521
+ else {
522
+ this.backend.set(hash, text, embedding, model);
523
+ }
123
524
  }
124
525
  /**
125
526
  * Check if text is cached
126
527
  */
127
528
  has(text, model = 'default') {
128
529
  const hash = this.hashKey(text, model);
129
- const row = this.stmtGet.get(hash);
130
- return row !== undefined;
530
+ return this.backend.has(hash);
131
531
  }
132
532
  /**
133
533
  * Get multiple embeddings at once
134
- * Returns map of text -> embedding (only cached ones)
135
534
  */
136
535
  getMany(texts, model = 'default') {
137
536
  const result = new Map();
@@ -147,87 +546,53 @@ export class EmbeddingCache {
147
546
  * Store multiple embeddings at once
148
547
  */
149
548
  setMany(entries, model = 'default') {
150
- const insertMany = this.db.transaction((items) => {
151
- const now = Date.now();
152
- for (const { text, embedding } of items) {
153
- const hash = this.hashKey(text, model);
154
- const buffer = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
155
- this.stmtInsert.run(hash, text, buffer, embedding.length, model, now, now);
156
- }
157
- });
158
- insertMany(entries);
159
- this.maybeEvict();
160
- }
161
- /**
162
- * Evict old or LRU entries if over limit
163
- */
164
- maybeEvict() {
165
- const count = this.stmtCount.get().count;
166
- if (count > this.config.maxEntries) {
167
- // Evict 10% of entries (LRU)
168
- const toEvict = Math.ceil(this.config.maxEntries * 0.1);
169
- this.stmtEvictLRU.run(toEvict);
549
+ for (const { text, embedding } of entries) {
550
+ this.set(text, embedding, model);
170
551
  }
171
552
  }
172
- /**
173
- * Cleanup entries older than maxAgeDays
174
- */
175
- cleanupOldEntries() {
176
- const cutoff = Date.now() - (this.config.maxAgeDays * 24 * 60 * 60 * 1000);
177
- this.stmtEvictOld.run(cutoff);
178
- }
179
553
  /**
180
554
  * Get cache statistics
181
555
  */
182
556
  getStats() {
183
- const count = this.stmtCount.get().count;
184
- const oldest = this.db.prepare(`SELECT MIN(created_at) as oldest FROM embeddings`).get();
185
- const newest = this.db.prepare(`SELECT MAX(created_at) as newest FROM embeddings`).get();
186
- // Get database file size
187
- let dbSizeBytes = 0;
188
- try {
189
- const fs = require('fs');
190
- const stats = fs.statSync(this.config.dbPath);
191
- dbSizeBytes = stats.size;
192
- }
193
- catch {
194
- // Ignore
195
- }
196
- return {
197
- totalEntries: count,
198
- hits: this.hits,
199
- misses: this.misses,
200
- hitRate: this.hits + this.misses > 0 ? this.hits / (this.hits + this.misses) : 0,
201
- dbSizeBytes,
202
- oldestEntry: oldest.oldest || 0,
203
- newestEntry: newest.newest || 0,
204
- };
557
+ return this.backend.getStats();
205
558
  }
206
559
  /**
207
560
  * Clear all cached embeddings
208
561
  */
209
562
  clear() {
210
- this.db.exec('DELETE FROM embeddings');
211
- this.hits = 0;
212
- this.misses = 0;
563
+ this.backend.clear();
213
564
  }
214
565
  /**
215
- * Clear embeddings for a specific model
216
- */
217
- clearModel(model) {
218
- this.db.prepare('DELETE FROM embeddings WHERE model = ?').run(model);
219
- }
220
- /**
221
- * Vacuum database to reclaim space
566
+ * Vacuum database (SQLite only)
222
567
  */
223
568
  vacuum() {
224
- this.db.exec('VACUUM');
569
+ if (this.backend instanceof SqliteCache) {
570
+ this.backend.vacuum();
571
+ }
225
572
  }
226
573
  /**
227
574
  * Close database connection
228
575
  */
229
576
  close() {
230
- this.db.close();
577
+ if (this.backend instanceof SqliteCache || this.backend instanceof WasmSqliteCache) {
578
+ this.backend.close();
579
+ }
580
+ }
581
+ /**
582
+ * Check if using SQLite backend (native or WASM)
583
+ */
584
+ isSqliteBackend() {
585
+ return this.backend instanceof SqliteCache || this.backend instanceof WasmSqliteCache;
586
+ }
587
+ /**
588
+ * Get backend type
589
+ */
590
+ getBackendType() {
591
+ if (this.backend instanceof SqliteCache)
592
+ return 'native';
593
+ if (this.backend instanceof WasmSqliteCache)
594
+ return 'wasm';
595
+ return 'memory';
231
596
  }
232
597
  }
233
598
  // Singleton instance
@@ -250,4 +615,10 @@ export function resetEmbeddingCache() {
250
615
  cacheInstance = null;
251
616
  }
252
617
  }
618
+ /**
619
+ * Check if SQLite is available
620
+ */
621
+ export function isSqliteAvailable() {
622
+ return sqliteAvailable;
623
+ }
253
624
  //# sourceMappingURL=EmbeddingCache.js.map