@soulcraft/brainy 4.1.4 → 4.2.1

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/import/FormatDetector.d.ts +6 -1
  3. package/dist/import/FormatDetector.js +40 -1
  4. package/dist/import/ImportCoordinator.d.ts +102 -4
  5. package/dist/import/ImportCoordinator.js +248 -6
  6. package/dist/import/InstancePool.d.ts +136 -0
  7. package/dist/import/InstancePool.js +231 -0
  8. package/dist/importers/SmartCSVImporter.d.ts +2 -1
  9. package/dist/importers/SmartCSVImporter.js +11 -22
  10. package/dist/importers/SmartDOCXImporter.d.ts +125 -0
  11. package/dist/importers/SmartDOCXImporter.js +227 -0
  12. package/dist/importers/SmartExcelImporter.d.ts +12 -1
  13. package/dist/importers/SmartExcelImporter.js +40 -25
  14. package/dist/importers/SmartJSONImporter.d.ts +1 -0
  15. package/dist/importers/SmartJSONImporter.js +25 -6
  16. package/dist/importers/SmartMarkdownImporter.d.ts +2 -1
  17. package/dist/importers/SmartMarkdownImporter.js +11 -16
  18. package/dist/importers/SmartPDFImporter.d.ts +2 -1
  19. package/dist/importers/SmartPDFImporter.js +11 -22
  20. package/dist/importers/SmartYAMLImporter.d.ts +121 -0
  21. package/dist/importers/SmartYAMLImporter.js +275 -0
  22. package/dist/importers/VFSStructureGenerator.js +12 -0
  23. package/dist/neural/SmartExtractor.d.ts +279 -0
  24. package/dist/neural/SmartExtractor.js +592 -0
  25. package/dist/neural/SmartRelationshipExtractor.d.ts +217 -0
  26. package/dist/neural/SmartRelationshipExtractor.js +396 -0
  27. package/dist/neural/embeddedTypeEmbeddings.d.ts +1 -1
  28. package/dist/neural/embeddedTypeEmbeddings.js +2 -2
  29. package/dist/neural/entityExtractor.d.ts +3 -0
  30. package/dist/neural/entityExtractor.js +34 -36
  31. package/dist/neural/presets.d.ts +189 -0
  32. package/dist/neural/presets.js +365 -0
  33. package/dist/neural/signals/ContextSignal.d.ts +166 -0
  34. package/dist/neural/signals/ContextSignal.js +646 -0
  35. package/dist/neural/signals/EmbeddingSignal.d.ts +175 -0
  36. package/dist/neural/signals/EmbeddingSignal.js +435 -0
  37. package/dist/neural/signals/ExactMatchSignal.d.ts +220 -0
  38. package/dist/neural/signals/ExactMatchSignal.js +542 -0
  39. package/dist/neural/signals/PatternSignal.d.ts +159 -0
  40. package/dist/neural/signals/PatternSignal.js +478 -0
  41. package/dist/neural/signals/VerbContextSignal.d.ts +102 -0
  42. package/dist/neural/signals/VerbContextSignal.js +390 -0
  43. package/dist/neural/signals/VerbEmbeddingSignal.d.ts +131 -0
  44. package/dist/neural/signals/VerbEmbeddingSignal.js +304 -0
  45. package/dist/neural/signals/VerbExactMatchSignal.d.ts +115 -0
  46. package/dist/neural/signals/VerbExactMatchSignal.js +335 -0
  47. package/dist/neural/signals/VerbPatternSignal.d.ts +104 -0
  48. package/dist/neural/signals/VerbPatternSignal.js +457 -0
  49. package/dist/types/graphTypes.d.ts +2 -0
  50. package/dist/utils/metadataIndex.d.ts +22 -0
  51. package/dist/utils/metadataIndex.js +76 -0
  52. package/package.json +4 -1
@@ -0,0 +1,175 @@
1
+ /**
2
+ * EmbeddingSignal - Neural entity type classification using embeddings
3
+ *
4
+ * PRODUCTION-READY: Merges neural + graph + temporal signals into one
5
+ * 3x faster than separate signals (single embedding lookup)
6
+ *
7
+ * Weight: 35% (20% neural + 10% graph + 5% temporal boost)
8
+ * Speed: Fast (~10ms) - single embedding lookup with parallel checking
9
+ *
10
+ * Features:
11
+ * - Single embedding computation (efficient)
12
+ * - Parallel checking against 3 sources
13
+ * - Confidence boosting when multiple sources agree
14
+ * - LRU cache for hot entities
15
+ * - Uses pre-computed type embeddings (zero initialization cost)
16
+ */
17
+ import type { Brainy } from '../../brainy.js';
18
+ import type { NounType } from '../../types/graphTypes.js';
19
+ import type { Vector } from '../../coreTypes.js';
20
+ /**
21
+ * Signal result with classification details
22
+ */
23
+ export interface TypeSignal {
24
+ source: 'embedding-type' | 'embedding-graph' | 'embedding-history' | 'embedding-combined';
25
+ type: NounType;
26
+ confidence: number;
27
+ evidence: string;
28
+ metadata?: {
29
+ typeScore?: number;
30
+ graphScore?: number;
31
+ historyScore?: number;
32
+ agreementBoost?: number;
33
+ };
34
+ }
35
+ /**
36
+ * Options for embedding signal
37
+ */
38
+ export interface EmbeddingSignalOptions {
39
+ minConfidence?: number;
40
+ checkGraph?: boolean;
41
+ checkHistory?: boolean;
42
+ timeout?: number;
43
+ cacheSize?: number;
44
+ }
45
+ /**
46
+ * EmbeddingSignal - Neural type classification with parallel source checking
47
+ *
48
+ * Production features:
49
+ * - Pre-computed type embeddings (instant initialization)
50
+ * - Parallel source checking (type + graph + history)
51
+ * - LRU cache for performance
52
+ * - Confidence boosting when sources agree
53
+ * - Graceful degradation on errors
54
+ */
55
+ export declare class EmbeddingSignal {
56
+ private brain;
57
+ private options;
58
+ private typeEmbeddings;
59
+ private initialized;
60
+ private cache;
61
+ private cacheOrder;
62
+ private historicalEntities;
63
+ private readonly MAX_HISTORY;
64
+ private stats;
65
+ constructor(brain: Brainy, options?: EmbeddingSignalOptions);
66
+ /**
67
+ * Initialize type embeddings (lazy, happens once)
68
+ *
69
+ * PRODUCTION OPTIMIZATION: Uses pre-computed embeddings
70
+ * Zero runtime cost - embeddings loaded instantly
71
+ */
72
+ private init;
73
+ /**
74
+ * Classify entity type using embedding-based signals
75
+ *
76
+ * Main entry point - embeds candidate once, checks all sources in parallel
77
+ *
78
+ * @param candidate Entity text to classify
79
+ * @param context Optional context for better matching
80
+ * @returns TypeSignal with classification result
81
+ */
82
+ classify(candidate: string, context?: {
83
+ definition?: string;
84
+ allTerms?: string[];
85
+ metadata?: any;
86
+ }): Promise<TypeSignal | null>;
87
+ /**
88
+ * Match against NounType embeddings (31 types)
89
+ *
90
+ * Returns best matching type with confidence
91
+ */
92
+ private matchTypeEmbeddings;
93
+ /**
94
+ * Match against existing graph entities
95
+ *
96
+ * Finds similar entities already in the graph
97
+ * Boosts confidence for entities similar to existing ones
98
+ */
99
+ private matchGraphEntities;
100
+ /**
101
+ * Match against historical import data
102
+ *
103
+ * Temporal boosting: entities imported recently are more relevant
104
+ * Helps with batch imports of similar entities
105
+ */
106
+ private matchHistoricalData;
107
+ /**
108
+ * Combine results from all sources with confidence boosting
109
+ *
110
+ * Key insight: When multiple sources agree, boost confidence
111
+ * This is the "ensemble" effect that makes this signal powerful
112
+ */
113
+ private combineResults;
114
+ /**
115
+ * Add entity to historical data (for temporal boosting)
116
+ *
117
+ * Call this after successful imports to improve future matching
118
+ */
119
+ addToHistory(text: string, type: NounType, vector: Vector): void;
120
+ /**
121
+ * Clear historical data (useful between import sessions)
122
+ */
123
+ clearHistory(): void;
124
+ /**
125
+ * Get statistics about signal performance
126
+ */
127
+ getStats(): {
128
+ cacheSize: number;
129
+ historySize: number;
130
+ cacheHitRate: number;
131
+ typeMatchRate: number;
132
+ graphMatchRate: number;
133
+ historyMatchRate: number;
134
+ calls: number;
135
+ cacheHits: number;
136
+ typeMatches: number;
137
+ graphMatches: number;
138
+ historyMatches: number;
139
+ combinedBoosts: number;
140
+ };
141
+ /**
142
+ * Reset statistics (useful for testing)
143
+ */
144
+ resetStats(): void;
145
+ /**
146
+ * Clear cache
147
+ */
148
+ clearCache(): void;
149
+ /**
150
+ * Generate cache key from candidate and context
151
+ */
152
+ private getCacheKey;
153
+ /**
154
+ * Get from LRU cache
155
+ */
156
+ private getFromCache;
157
+ /**
158
+ * Add to LRU cache with eviction
159
+ */
160
+ private addToCache;
161
+ /**
162
+ * Embed text with timeout protection
163
+ */
164
+ private embedWithTimeout;
165
+ /**
166
+ * Calculate cosine similarity between two vectors
167
+ */
168
+ private cosineSimilarity;
169
+ }
170
+ /**
171
+ * Create a new EmbeddingSignal instance
172
+ *
173
+ * Convenience factory function
174
+ */
175
+ export declare function createEmbeddingSignal(brain: Brainy, options?: EmbeddingSignalOptions): EmbeddingSignal;
@@ -0,0 +1,435 @@
1
+ /**
2
+ * EmbeddingSignal - Neural entity type classification using embeddings
3
+ *
4
+ * PRODUCTION-READY: Merges neural + graph + temporal signals into one
5
+ * 3x faster than separate signals (single embedding lookup)
6
+ *
7
+ * Weight: 35% (20% neural + 10% graph + 5% temporal boost)
8
+ * Speed: Fast (~10ms) - single embedding lookup with parallel checking
9
+ *
10
+ * Features:
11
+ * - Single embedding computation (efficient)
12
+ * - Parallel checking against 3 sources
13
+ * - Confidence boosting when multiple sources agree
14
+ * - LRU cache for hot entities
15
+ * - Uses pre-computed type embeddings (zero initialization cost)
16
+ */
17
+ import { getNounTypeEmbeddings } from '../embeddedTypeEmbeddings.js';
18
+ /**
19
+ * EmbeddingSignal - Neural type classification with parallel source checking
20
+ *
21
+ * Production features:
22
+ * - Pre-computed type embeddings (instant initialization)
23
+ * - Parallel source checking (type + graph + history)
24
+ * - LRU cache for performance
25
+ * - Confidence boosting when sources agree
26
+ * - Graceful degradation on errors
27
+ */
28
+ export class EmbeddingSignal {
29
+ constructor(brain, options) {
30
+ // Pre-computed type embeddings (loaded once)
31
+ this.typeEmbeddings = new Map();
32
+ this.initialized = false;
33
+ // LRU cache for hot entities (includes null results to avoid recomputation)
34
+ this.cache = new Map();
35
+ this.cacheOrder = [];
36
+ // Historical data for temporal boosting
37
+ this.historicalEntities = [];
38
+ this.MAX_HISTORY = 1000; // Keep last 1000 imports
39
+ // Statistics
40
+ this.stats = {
41
+ calls: 0,
42
+ cacheHits: 0,
43
+ typeMatches: 0,
44
+ graphMatches: 0,
45
+ historyMatches: 0,
46
+ combinedBoosts: 0
47
+ };
48
+ this.brain = brain;
49
+ this.options = {
50
+ minConfidence: options?.minConfidence ?? 0.60,
51
+ checkGraph: options?.checkGraph ?? true,
52
+ checkHistory: options?.checkHistory ?? true,
53
+ timeout: options?.timeout ?? 100,
54
+ cacheSize: options?.cacheSize ?? 1000
55
+ };
56
+ }
57
+ /**
58
+ * Initialize type embeddings (lazy, happens once)
59
+ *
60
+ * PRODUCTION OPTIMIZATION: Uses pre-computed embeddings
61
+ * Zero runtime cost - embeddings loaded instantly
62
+ */
63
+ async init() {
64
+ if (this.initialized)
65
+ return;
66
+ // Load pre-computed type embeddings (instant, no computation)
67
+ const embeddings = getNounTypeEmbeddings();
68
+ for (const [type, vector] of embeddings.entries()) {
69
+ this.typeEmbeddings.set(type, vector);
70
+ }
71
+ this.initialized = true;
72
+ }
73
+ /**
74
+ * Classify entity type using embedding-based signals
75
+ *
76
+ * Main entry point - embeds candidate once, checks all sources in parallel
77
+ *
78
+ * @param candidate Entity text to classify
79
+ * @param context Optional context for better matching
80
+ * @returns TypeSignal with classification result
81
+ */
82
+ async classify(candidate, context) {
83
+ this.stats.calls++;
84
+ // Ensure initialized
85
+ await this.init();
86
+ // Check cache first
87
+ const cacheKey = this.getCacheKey(candidate, context);
88
+ const cached = this.getFromCache(cacheKey);
89
+ if (cached) {
90
+ this.stats.cacheHits++;
91
+ return cached;
92
+ }
93
+ try {
94
+ // Embed candidate once (efficiency!)
95
+ const vector = await this.embedWithTimeout(candidate);
96
+ // Check all three sources in parallel
97
+ const [typeMatch, graphMatch, historyMatch] = await Promise.all([
98
+ this.matchTypeEmbeddings(vector, candidate),
99
+ this.options.checkGraph ? this.matchGraphEntities(vector, candidate) : null,
100
+ this.options.checkHistory ? this.matchHistoricalData(vector, candidate) : null
101
+ ]);
102
+ // Combine results with confidence boosting
103
+ const result = this.combineResults([typeMatch, graphMatch, historyMatch]);
104
+ // Cache result (including nulls to avoid recomputation)
105
+ if (!result || result.confidence >= this.options.minConfidence) {
106
+ this.addToCache(cacheKey, result);
107
+ }
108
+ return result;
109
+ }
110
+ catch (error) {
111
+ // Graceful degradation - return null instead of throwing
112
+ console.warn(`EmbeddingSignal error for "${candidate}":`, error);
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * Match against NounType embeddings (31 types)
118
+ *
119
+ * Returns best matching type with confidence
120
+ */
121
+ async matchTypeEmbeddings(vector, candidate) {
122
+ let bestType = null;
123
+ let bestScore = 0;
124
+ // Check similarity against all type embeddings
125
+ for (const [type, typeVector] of this.typeEmbeddings.entries()) {
126
+ const similarity = this.cosineSimilarity(vector, typeVector);
127
+ if (similarity > bestScore) {
128
+ bestScore = similarity;
129
+ bestType = type;
130
+ }
131
+ }
132
+ // Use lower threshold for type matching (0.40) to catch more matches
133
+ // Production systems can adjust minConfidence on the signal itself
134
+ if (bestType && bestScore >= 0.40) {
135
+ this.stats.typeMatches++;
136
+ return {
137
+ type: bestType,
138
+ confidence: bestScore,
139
+ source: 'embedding-type',
140
+ metadata: { typeScore: bestScore }
141
+ };
142
+ }
143
+ return null;
144
+ }
145
+ /**
146
+ * Match against existing graph entities
147
+ *
148
+ * Finds similar entities already in the graph
149
+ * Boosts confidence for entities similar to existing ones
150
+ */
151
+ async matchGraphEntities(vector, candidate) {
152
+ try {
153
+ // Query HNSW index for similar entities
154
+ const similar = await this.brain.similar({
155
+ to: vector,
156
+ limit: 5,
157
+ threshold: 0.70 // Higher threshold for graph matching
158
+ });
159
+ if (similar.length === 0)
160
+ return null;
161
+ // Use the most similar entity's type
162
+ const best = similar[0];
163
+ const entity = await this.brain.get(best.id);
164
+ if (entity && entity.type) {
165
+ this.stats.graphMatches++;
166
+ return {
167
+ type: entity.type,
168
+ confidence: best.score * 0.95, // Slight discount for graph match
169
+ source: 'embedding-graph',
170
+ metadata: {
171
+ graphScore: best.score,
172
+ matchedEntity: best.id,
173
+ totalMatches: similar.length
174
+ }
175
+ };
176
+ }
177
+ }
178
+ catch (error) {
179
+ // Graceful degradation if HNSW not available
180
+ return null;
181
+ }
182
+ return null;
183
+ }
184
+ /**
185
+ * Match against historical import data
186
+ *
187
+ * Temporal boosting: entities imported recently are more relevant
188
+ * Helps with batch imports of similar entities
189
+ */
190
+ async matchHistoricalData(vector, candidate) {
191
+ if (this.historicalEntities.length === 0)
192
+ return null;
193
+ let bestMatch = null;
194
+ let bestScore = 0;
195
+ // Check against recent history
196
+ const recentThreshold = Date.now() - 3600000; // Last hour
197
+ for (const historical of this.historicalEntities) {
198
+ const similarity = this.cosineSimilarity(vector, historical.vector);
199
+ // Boost recent entities
200
+ const recencyBoost = historical.timestamp > recentThreshold ? 1.05 : 1.0;
201
+ const usageBoost = 1 + (Math.log(historical.usageCount + 1) * 0.02);
202
+ const adjustedScore = similarity * recencyBoost * usageBoost;
203
+ if (adjustedScore > bestScore && similarity >= 0.75) {
204
+ bestScore = adjustedScore;
205
+ bestMatch = historical;
206
+ }
207
+ }
208
+ if (bestMatch) {
209
+ this.stats.historyMatches++;
210
+ return {
211
+ type: bestMatch.type,
212
+ confidence: Math.min(bestScore, 0.95), // Cap at 0.95
213
+ source: 'embedding-history',
214
+ metadata: {
215
+ historyScore: bestScore,
216
+ matchedText: bestMatch.text,
217
+ recency: bestMatch.timestamp,
218
+ usageCount: bestMatch.usageCount
219
+ }
220
+ };
221
+ }
222
+ return null;
223
+ }
224
+ /**
225
+ * Combine results from all sources with confidence boosting
226
+ *
227
+ * Key insight: When multiple sources agree, boost confidence
228
+ * This is the "ensemble" effect that makes this signal powerful
229
+ */
230
+ combineResults(matches) {
231
+ // Filter out null matches
232
+ const validMatches = matches.filter((m) => m !== null);
233
+ if (validMatches.length === 0)
234
+ return null;
235
+ // Count votes by type
236
+ const typeVotes = new Map();
237
+ for (const match of validMatches) {
238
+ const existing = typeVotes.get(match.type) || [];
239
+ typeVotes.set(match.type, [...existing, match]);
240
+ }
241
+ // Find type with most votes and highest combined confidence
242
+ let bestType = null;
243
+ let bestCombinedScore = 0;
244
+ let bestMatches = [];
245
+ for (const [type, matches] of typeVotes.entries()) {
246
+ // Calculate combined score with agreement boosting
247
+ const avgConfidence = matches.reduce((sum, m) => sum + m.confidence, 0) / matches.length;
248
+ const agreementBoost = matches.length > 1 ? 0.05 * (matches.length - 1) : 0;
249
+ const combinedScore = avgConfidence + agreementBoost;
250
+ if (combinedScore > bestCombinedScore) {
251
+ bestCombinedScore = combinedScore;
252
+ bestType = type;
253
+ bestMatches = matches;
254
+ }
255
+ }
256
+ if (!bestType || bestCombinedScore < this.options.minConfidence) {
257
+ return null;
258
+ }
259
+ // Track combined boosts
260
+ if (bestMatches.length > 1) {
261
+ this.stats.combinedBoosts++;
262
+ }
263
+ // Build evidence string
264
+ const sources = bestMatches.map(m => m.source.replace('embedding-', '')).join('+');
265
+ const evidence = `Matched via ${sources} (${bestMatches.length} source${bestMatches.length > 1 ? 's' : ''} agree)`;
266
+ // Combine metadata
267
+ const metadata = {
268
+ agreementBoost: bestMatches.length > 1 ? 0.05 * (bestMatches.length - 1) : 0
269
+ };
270
+ for (const match of bestMatches) {
271
+ if (match.source === 'embedding-type')
272
+ metadata.typeScore = match.metadata?.typeScore;
273
+ if (match.source === 'embedding-graph')
274
+ metadata.graphScore = match.metadata?.graphScore;
275
+ if (match.source === 'embedding-history')
276
+ metadata.historyScore = match.metadata?.historyScore;
277
+ }
278
+ return {
279
+ source: bestMatches.length > 1 ? 'embedding-combined' : bestMatches[0].source,
280
+ type: bestType,
281
+ confidence: Math.min(bestCombinedScore, 1.0), // Cap at 1.0
282
+ evidence,
283
+ metadata
284
+ };
285
+ }
286
+ /**
287
+ * Add entity to historical data (for temporal boosting)
288
+ *
289
+ * Call this after successful imports to improve future matching
290
+ */
291
+ addToHistory(text, type, vector) {
292
+ // Check if already exists
293
+ const existing = this.historicalEntities.find(h => h.text.toLowerCase() === text.toLowerCase());
294
+ if (existing) {
295
+ existing.usageCount++;
296
+ existing.timestamp = Date.now();
297
+ return;
298
+ }
299
+ // Add new historical entity
300
+ this.historicalEntities.push({
301
+ text,
302
+ type,
303
+ vector,
304
+ timestamp: Date.now(),
305
+ usageCount: 1
306
+ });
307
+ // Trim to max size (keep most recent and most used)
308
+ if (this.historicalEntities.length > this.MAX_HISTORY) {
309
+ // Sort by recency and usage
310
+ this.historicalEntities.sort((a, b) => {
311
+ const aScore = a.timestamp + (a.usageCount * 60000); // 1 minute per usage
312
+ const bScore = b.timestamp + (b.usageCount * 60000);
313
+ return bScore - aScore;
314
+ });
315
+ // Keep top MAX_HISTORY
316
+ this.historicalEntities = this.historicalEntities.slice(0, this.MAX_HISTORY);
317
+ }
318
+ }
319
+ /**
320
+ * Clear historical data (useful between import sessions)
321
+ */
322
+ clearHistory() {
323
+ this.historicalEntities = [];
324
+ }
325
+ /**
326
+ * Get statistics about signal performance
327
+ */
328
+ getStats() {
329
+ return {
330
+ ...this.stats,
331
+ cacheSize: this.cache.size,
332
+ historySize: this.historicalEntities.length,
333
+ cacheHitRate: this.stats.calls > 0 ? this.stats.cacheHits / this.stats.calls : 0,
334
+ typeMatchRate: this.stats.calls > 0 ? this.stats.typeMatches / this.stats.calls : 0,
335
+ graphMatchRate: this.stats.calls > 0 ? this.stats.graphMatches / this.stats.calls : 0,
336
+ historyMatchRate: this.stats.calls > 0 ? this.stats.historyMatches / this.stats.calls : 0
337
+ };
338
+ }
339
+ /**
340
+ * Reset statistics (useful for testing)
341
+ */
342
+ resetStats() {
343
+ this.stats = {
344
+ calls: 0,
345
+ cacheHits: 0,
346
+ typeMatches: 0,
347
+ graphMatches: 0,
348
+ historyMatches: 0,
349
+ combinedBoosts: 0
350
+ };
351
+ }
352
+ /**
353
+ * Clear cache
354
+ */
355
+ clearCache() {
356
+ this.cache.clear();
357
+ this.cacheOrder = [];
358
+ }
359
+ // ========== Private Helper Methods ==========
360
+ /**
361
+ * Generate cache key from candidate and context
362
+ */
363
+ getCacheKey(candidate, context) {
364
+ const normalized = candidate.toLowerCase().trim();
365
+ if (!context?.definition)
366
+ return normalized;
367
+ return `${normalized}:${context.definition.substring(0, 50)}`;
368
+ }
369
+ /**
370
+ * Get from LRU cache
371
+ */
372
+ getFromCache(key) {
373
+ // Check if key exists in cache (including null values)
374
+ if (!this.cache.has(key))
375
+ return null;
376
+ const cached = this.cache.get(key);
377
+ // Move to end (most recently used)
378
+ this.cacheOrder = this.cacheOrder.filter(k => k !== key);
379
+ this.cacheOrder.push(key);
380
+ return cached ?? null;
381
+ }
382
+ /**
383
+ * Add to LRU cache with eviction
384
+ */
385
+ addToCache(key, value) {
386
+ // Add to cache
387
+ this.cache.set(key, value);
388
+ this.cacheOrder.push(key);
389
+ // Evict oldest if over limit
390
+ if (this.cache.size > this.options.cacheSize) {
391
+ const oldest = this.cacheOrder.shift();
392
+ if (oldest) {
393
+ this.cache.delete(oldest);
394
+ }
395
+ }
396
+ }
397
+ /**
398
+ * Embed text with timeout protection
399
+ */
400
+ async embedWithTimeout(text) {
401
+ return Promise.race([
402
+ this.brain.embed(text),
403
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Embedding timeout')), this.options.timeout))
404
+ ]);
405
+ }
406
+ /**
407
+ * Calculate cosine similarity between two vectors
408
+ */
409
+ cosineSimilarity(a, b) {
410
+ if (a.length !== b.length) {
411
+ throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
412
+ }
413
+ let dotProduct = 0;
414
+ let normA = 0;
415
+ let normB = 0;
416
+ for (let i = 0; i < a.length; i++) {
417
+ dotProduct += a[i] * b[i];
418
+ normA += a[i] * a[i];
419
+ normB += b[i] * b[i];
420
+ }
421
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
422
+ if (denominator === 0)
423
+ return 0;
424
+ return dotProduct / denominator;
425
+ }
426
+ }
427
+ /**
428
+ * Create a new EmbeddingSignal instance
429
+ *
430
+ * Convenience factory function
431
+ */
432
+ export function createEmbeddingSignal(brain, options) {
433
+ return new EmbeddingSignal(brain, options);
434
+ }
435
+ //# sourceMappingURL=EmbeddingSignal.js.map