@yamo/memory-mesh 2.3.2 → 3.0.0

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 (102) hide show
  1. package/bin/memory_mesh.js +1 -1
  2. package/lib/llm/client.d.ts +111 -0
  3. package/lib/llm/client.js +299 -357
  4. package/lib/llm/client.ts +413 -0
  5. package/lib/llm/index.d.ts +17 -0
  6. package/lib/llm/index.js +15 -8
  7. package/lib/llm/index.ts +19 -0
  8. package/lib/memory/adapters/client.d.ts +183 -0
  9. package/lib/memory/adapters/client.js +518 -0
  10. package/lib/memory/adapters/client.ts +678 -0
  11. package/lib/memory/adapters/config.d.ts +137 -0
  12. package/lib/memory/adapters/config.js +189 -0
  13. package/lib/memory/adapters/config.ts +259 -0
  14. package/lib/memory/adapters/errors.d.ts +76 -0
  15. package/lib/memory/adapters/errors.js +128 -0
  16. package/lib/memory/adapters/errors.ts +166 -0
  17. package/lib/memory/context-manager.d.ts +44 -0
  18. package/lib/memory/context-manager.js +344 -0
  19. package/lib/memory/context-manager.ts +432 -0
  20. package/lib/memory/embeddings/factory.d.ts +59 -0
  21. package/lib/memory/embeddings/factory.js +148 -0
  22. package/lib/{embeddings/factory.js → memory/embeddings/factory.ts} +69 -28
  23. package/lib/memory/embeddings/index.d.ts +2 -0
  24. package/lib/memory/embeddings/index.js +2 -0
  25. package/lib/memory/embeddings/index.ts +2 -0
  26. package/lib/memory/embeddings/service.d.ts +164 -0
  27. package/lib/memory/embeddings/service.js +515 -0
  28. package/lib/{embeddings/service.js → memory/embeddings/service.ts} +223 -156
  29. package/lib/memory/index.d.ts +9 -0
  30. package/lib/memory/index.js +9 -1
  31. package/lib/memory/index.ts +20 -0
  32. package/lib/memory/memory-mesh.d.ts +274 -0
  33. package/lib/memory/memory-mesh.js +1469 -678
  34. package/lib/memory/memory-mesh.ts +1803 -0
  35. package/lib/memory/memory-translator.d.ts +19 -0
  36. package/lib/memory/memory-translator.js +125 -0
  37. package/lib/memory/memory-translator.ts +158 -0
  38. package/lib/memory/schema.d.ts +111 -0
  39. package/lib/memory/schema.js +183 -0
  40. package/lib/memory/schema.ts +267 -0
  41. package/lib/memory/scorer.d.ts +26 -0
  42. package/lib/memory/scorer.js +77 -0
  43. package/lib/memory/scorer.ts +95 -0
  44. package/lib/memory/search/index.d.ts +1 -0
  45. package/lib/memory/search/index.js +1 -0
  46. package/lib/memory/search/index.ts +1 -0
  47. package/lib/memory/search/keyword-search.d.ts +62 -0
  48. package/lib/memory/search/keyword-search.js +135 -0
  49. package/lib/{search/keyword-search.js → memory/search/keyword-search.ts} +66 -36
  50. package/lib/scrubber/config/defaults.d.ts +53 -0
  51. package/lib/scrubber/config/defaults.js +49 -57
  52. package/lib/scrubber/config/defaults.ts +117 -0
  53. package/lib/scrubber/index.d.ts +6 -0
  54. package/lib/scrubber/index.js +3 -23
  55. package/lib/scrubber/index.ts +7 -0
  56. package/lib/scrubber/scrubber.d.ts +61 -0
  57. package/lib/scrubber/scrubber.js +99 -121
  58. package/lib/scrubber/scrubber.ts +168 -0
  59. package/lib/scrubber/stages/chunker.d.ts +13 -0
  60. package/lib/scrubber/stages/metadata-annotator.d.ts +18 -0
  61. package/lib/scrubber/stages/normalizer.d.ts +13 -0
  62. package/lib/scrubber/stages/semantic-filter.d.ts +13 -0
  63. package/lib/scrubber/stages/structural-cleaner.d.ts +13 -0
  64. package/lib/scrubber/stages/validator.d.ts +18 -0
  65. package/lib/scrubber/telemetry.d.ts +36 -0
  66. package/lib/scrubber/telemetry.js +53 -58
  67. package/lib/scrubber/telemetry.ts +99 -0
  68. package/lib/utils/logger.d.ts +29 -0
  69. package/lib/utils/logger.js +64 -0
  70. package/lib/utils/logger.ts +85 -0
  71. package/lib/utils/skill-metadata.d.ts +32 -0
  72. package/lib/utils/skill-metadata.js +132 -0
  73. package/lib/utils/skill-metadata.ts +147 -0
  74. package/lib/yamo/emitter.d.ts +73 -0
  75. package/lib/yamo/emitter.js +78 -143
  76. package/lib/yamo/emitter.ts +249 -0
  77. package/lib/yamo/schema.d.ts +58 -0
  78. package/lib/yamo/schema.js +81 -108
  79. package/lib/yamo/schema.ts +165 -0
  80. package/package.json +11 -8
  81. package/index.d.ts +0 -111
  82. package/lib/embeddings/index.js +0 -2
  83. package/lib/index.js +0 -6
  84. package/lib/lancedb/client.js +0 -633
  85. package/lib/lancedb/config.js +0 -215
  86. package/lib/lancedb/errors.js +0 -144
  87. package/lib/lancedb/index.js +0 -4
  88. package/lib/lancedb/schema.js +0 -217
  89. package/lib/scrubber/errors/scrubber-error.js +0 -43
  90. package/lib/scrubber/stages/chunker.js +0 -103
  91. package/lib/scrubber/stages/metadata-annotator.js +0 -74
  92. package/lib/scrubber/stages/normalizer.js +0 -59
  93. package/lib/scrubber/stages/semantic-filter.js +0 -61
  94. package/lib/scrubber/stages/structural-cleaner.js +0 -82
  95. package/lib/scrubber/stages/validator.js +0 -66
  96. package/lib/scrubber/utils/hash.js +0 -39
  97. package/lib/scrubber/utils/html-parser.js +0 -45
  98. package/lib/scrubber/utils/pattern-matcher.js +0 -63
  99. package/lib/scrubber/utils/token-counter.js +0 -31
  100. package/lib/search/index.js +0 -1
  101. package/lib/utils/index.js +0 -1
  102. package/lib/yamo/index.js +0 -15
@@ -10,38 +10,93 @@
10
10
  */
11
11
 
12
12
  import crypto from "crypto";
13
- import {
14
- ConfigurationError,
15
- EmbeddingError,
16
- StorageError,
17
- QueryError
18
- } from "../lancedb/errors.js";
13
+ import { ConfigurationError, EmbeddingError } from "../adapters/errors.js";
14
+
15
+ /**
16
+ * Service configuration interface
17
+ */
18
+
19
+ export interface ServiceConfig {
20
+ modelType?: "local" | "ollama" | "openai" | "cohere";
21
+ modelName?: string;
22
+ baseUrl?: string;
23
+ dimension?: number;
24
+ batchSize?: number;
25
+ normalize?: boolean;
26
+ cacheMaxSize?: number;
27
+ apiKey?: string;
28
+ priority?: number; // Used by factory
29
+ }
30
+
31
+ export interface ServiceStats {
32
+ modelType: string;
33
+ modelName: string;
34
+ dimension: number;
35
+ initialized: boolean;
36
+ totalEmbeddings: number;
37
+ cacheHits: number;
38
+ cacheMisses: number;
39
+ cacheSize: number;
40
+ cacheMaxSize: number;
41
+ cacheHitRate: number;
42
+ batchCount: number;
43
+ batchSize: number;
44
+ normalize: boolean;
45
+ }
19
46
 
20
47
  /**
21
48
  * EmbeddingService provides a unified interface for generating text embeddings
22
49
  * using multiple backend providers (local ONNX models or cloud APIs).
23
50
  */
24
- class EmbeddingService {
51
+ export class EmbeddingService {
52
+ modelType: string;
53
+ modelName: string;
54
+ baseUrl: string;
55
+ dimension: number;
56
+ batchSize: number;
57
+ normalize: boolean;
58
+ apiKey?: string;
59
+ model: any;
60
+ cache: Map<string, number[]>;
61
+ cacheMaxSize: number;
62
+ initialized: boolean;
63
+ stats: {
64
+ totalEmbeddings: number;
65
+ cacheHits: number;
66
+ cacheMisses: number;
67
+ batchCount: number;
68
+ };
69
+
25
70
  /**
26
71
  * Create a new EmbeddingService instance
27
72
  * @param {Object} [config={}] - Configuration options
28
- * @param {string} [config.modelType] - Type of model ('local', 'ollama', 'openai', 'cohere')
29
- * @param {string} [config.modelName] - Name of the model to use
30
- * @param {string} [config.baseUrl] - Base URL for Ollama (default: http://localhost:11434)
31
- * @param {number} [config.dimension] - Embedding dimension
32
- * @param {number} [config.batchSize] - Maximum batch size for processing
33
- * @param {boolean} [config.normalize] - Whether to normalize embeddings to unit length
34
- * @param {number} [config.cacheMaxSize] - Maximum size of LRU cache
35
- * @param {string} [config.apiKey] - API key for cloud providers
36
73
  */
37
- // @ts-ignore
38
- constructor(config = {}) {
39
- this.modelType = (config && config.modelType) || process.env.EMBEDDING_MODEL_TYPE || 'local';
40
- this.modelName = (config && config.modelName) || process.env.EMBEDDING_MODEL_NAME || 'Xenova/all-MiniLM-L6-v2';
41
- this.baseUrl = (config && config.baseUrl) || process.env.OLLAMA_BASE_URL || process.env.EMBEDDING_BASE_URL || 'http://localhost:11434';
42
- this.dimension = (config && config.dimension) || parseInt(process.env.EMBEDDING_DIMENSION || '384') || 384;
43
- this.batchSize = (config && config.batchSize) || parseInt(process.env.EMBEDDING_BATCH_SIZE || '32') || 32;
44
- this.normalize = (config && config.normalize !== undefined) ? config.normalize : (process.env.EMBEDDING_NORMALIZE !== 'false');
74
+ constructor(config: ServiceConfig = {}) {
75
+ this.modelType =
76
+ (config && config.modelType) ||
77
+ process.env.EMBEDDING_MODEL_TYPE ||
78
+ "local";
79
+ this.modelName =
80
+ (config && config.modelName) ||
81
+ process.env.EMBEDDING_MODEL_NAME ||
82
+ "Xenova/all-MiniLM-L6-v2";
83
+ this.baseUrl =
84
+ (config && config.baseUrl) ||
85
+ process.env.OLLAMA_BASE_URL ||
86
+ process.env.EMBEDDING_BASE_URL ||
87
+ "http://localhost:11434";
88
+ this.dimension =
89
+ (config && config.dimension) ||
90
+ parseInt(process.env.EMBEDDING_DIMENSION || "384") ||
91
+ 384;
92
+ this.batchSize =
93
+ (config && config.batchSize) ||
94
+ parseInt(process.env.EMBEDDING_BATCH_SIZE || "32") ||
95
+ 32;
96
+ this.normalize =
97
+ config && config.normalize !== undefined
98
+ ? config.normalize
99
+ : process.env.EMBEDDING_NORMALIZE !== "false";
45
100
 
46
101
  this.apiKey = (config && config.apiKey) || process.env.EMBEDDING_API_KEY;
47
102
 
@@ -55,7 +110,7 @@ class EmbeddingService {
55
110
  totalEmbeddings: 0,
56
111
  cacheHits: 0,
57
112
  cacheMisses: 0,
58
- batchCount: 0
113
+ batchCount: 0,
59
114
  };
60
115
  }
61
116
 
@@ -63,25 +118,25 @@ class EmbeddingService {
63
118
  * Initialize the embedding model
64
119
  * Loads the model based on modelType (local, ollama, openai, cohere)
65
120
  */
66
- async init() {
121
+ async init(): Promise<void> {
67
122
  try {
68
123
  switch (this.modelType) {
69
- case 'local':
124
+ case "local":
70
125
  await this._initLocalModel();
71
126
  break;
72
- case 'ollama':
73
- await this._initOllama();
127
+ case "ollama":
128
+ this._initOllama();
74
129
  break;
75
- case 'openai':
130
+ case "openai":
76
131
  await this._initOpenAI();
77
132
  break;
78
- case 'cohere':
133
+ case "cohere":
79
134
  await this._initCohere();
80
135
  break;
81
136
  default:
82
137
  throw new ConfigurationError(
83
138
  `Unknown model type: ${this.modelType}. Must be 'local', 'ollama', 'openai', or 'cohere'`,
84
- { modelType: this.modelType }
139
+ { modelType: this.modelType },
85
140
  );
86
141
  }
87
142
 
@@ -93,7 +148,11 @@ class EmbeddingService {
93
148
  const message = error instanceof Error ? error.message : String(error);
94
149
  throw new EmbeddingError(
95
150
  `Failed to initialize embedding service: ${message}`,
96
- { modelType: this.modelType, modelName: this.modelName, originalError: message }
151
+ {
152
+ modelType: this.modelType,
153
+ modelName: this.modelName,
154
+ originalError: message,
155
+ },
97
156
  );
98
157
  }
99
158
  }
@@ -104,19 +163,21 @@ class EmbeddingService {
104
163
  * @param {Object} options - Options for embedding generation
105
164
  * @returns {Promise<number[]>} Embedding vector
106
165
  */
107
- async embed(text, options = {}) {
166
+ async embed(text: string, _options: any = {}): Promise<number[]> {
108
167
  if (!this.initialized) {
109
168
  throw new EmbeddingError(
110
- 'Embedding service not initialized. Call init() first.',
111
- { modelType: this.modelType }
169
+ "Embedding service not initialized. Call init() first.",
170
+ {
171
+ modelType: this.modelType,
172
+ },
112
173
  );
113
174
  }
114
175
 
115
- if (!text || typeof text !== 'string') {
116
- throw new EmbeddingError(
117
- 'Text must be a non-empty string',
118
- { text, textType: typeof text }
119
- );
176
+ if (!text || typeof text !== "string") {
177
+ throw new EmbeddingError("Text must be a non-empty string", {
178
+ text,
179
+ textType: typeof text,
180
+ });
120
181
  }
121
182
 
122
183
  // Check cache
@@ -128,26 +189,25 @@ class EmbeddingService {
128
189
  }
129
190
 
130
191
  // Generate embedding
131
- let embedding;
192
+ let embedding: number[];
132
193
  try {
133
194
  switch (this.modelType) {
134
- case 'local':
195
+ case "local":
135
196
  embedding = await this._embedLocal(text);
136
197
  break;
137
- case 'ollama':
198
+ case "ollama":
138
199
  embedding = await this._embedOllama(text);
139
200
  break;
140
- case 'openai':
201
+ case "openai":
141
202
  embedding = await this._embedOpenAI(text);
142
203
  break;
143
- case 'cohere':
204
+ case "cohere":
144
205
  embedding = await this._embedCohere(text);
145
206
  break;
146
207
  default:
147
- throw new EmbeddingError(
148
- `Unknown model type: ${this.modelType}`,
149
- { modelType: this.modelType }
150
- );
208
+ throw new EmbeddingError(`Unknown model type: ${this.modelType}`, {
209
+ modelType: this.modelType,
210
+ });
151
211
  }
152
212
 
153
213
  // Normalize if enabled
@@ -167,10 +227,10 @@ class EmbeddingService {
167
227
  throw error;
168
228
  }
169
229
  const message = error instanceof Error ? error.message : String(error);
170
- throw new EmbeddingError(
171
- `Failed to generate embedding: ${message}`,
172
- { modelType: this.modelType, text: text.substring(0, 100) }
173
- );
230
+ throw new EmbeddingError(`Failed to generate embedding: ${message}`, {
231
+ modelType: this.modelType,
232
+ text: text.substring(0, 100),
233
+ });
174
234
  }
175
235
  }
176
236
 
@@ -180,19 +240,20 @@ class EmbeddingService {
180
240
  * @param {Object} options - Options for embedding generation
181
241
  * @returns {Promise<number[][]>} Array of embedding vectors
182
242
  */
183
- async embedBatch(texts, options = {}) {
243
+ async embedBatch(texts: string[], _options: any = {}): Promise<number[][]> {
184
244
  if (!this.initialized) {
185
245
  throw new EmbeddingError(
186
- 'Embedding service not initialized. Call init() first.',
187
- { modelType: this.modelType }
246
+ "Embedding service not initialized. Call init() first.",
247
+ {
248
+ modelType: this.modelType,
249
+ },
188
250
  );
189
251
  }
190
252
 
191
253
  if (!Array.isArray(texts)) {
192
- throw new EmbeddingError(
193
- 'Texts must be an array',
194
- { textsType: typeof texts }
195
- );
254
+ throw new EmbeddingError("Texts must be an array", {
255
+ textsType: typeof texts,
256
+ });
196
257
  }
197
258
 
198
259
  if (texts.length === 0) {
@@ -200,15 +261,18 @@ class EmbeddingService {
200
261
  }
201
262
 
202
263
  try {
203
- const embeddings = [];
264
+ const embeddings: number[][] = [];
204
265
 
205
266
  // Process in batches
206
267
  for (let i = 0; i < texts.length; i += this.batchSize) {
207
- const batch = texts.slice(i, Math.min(i + this.batchSize, texts.length));
268
+ const batch = texts.slice(
269
+ i,
270
+ Math.min(i + this.batchSize, texts.length),
271
+ );
208
272
 
209
273
  // Generate embeddings for batch
210
274
  const batchEmbeddings = await Promise.all(
211
- batch.map(text => this.embed(text, options))
275
+ batch.map((text) => this.embed(text)),
212
276
  );
213
277
 
214
278
  embeddings.push(...batchEmbeddings);
@@ -223,7 +287,10 @@ class EmbeddingService {
223
287
  const message = error instanceof Error ? error.message : String(error);
224
288
  throw new EmbeddingError(
225
289
  `Failed to generate batch embeddings: ${message}`,
226
- { modelType: this.modelType, batchSize: texts.length }
290
+ {
291
+ modelType: this.modelType,
292
+ batchSize: texts.length,
293
+ },
227
294
  );
228
295
  }
229
296
  }
@@ -232,36 +299,31 @@ class EmbeddingService {
232
299
  * Initialize local ONNX model using Xenova/Transformers.js
233
300
  * @private
234
301
  */
235
- async _initLocalModel() {
302
+ async _initLocalModel(): Promise<void> {
236
303
  try {
237
304
  // Dynamic import to allow optional dependency
238
- const { pipeline } = await import("@xenova/transformers");
305
+ const { pipeline } = (await import("@xenova/transformers")) as any;
239
306
 
240
307
  // Load feature extraction pipeline
241
- // @ts-ignore
242
- this.model = await pipeline(
243
- 'feature-extraction',
244
- this.modelName,
245
- {
246
- quantized: true,
247
- progress_callback: (progress) => {
248
- // Optional: Log model download progress
249
- if (progress.status === 'downloading') {
250
- // Silently handle progress
251
- }
308
+ this.model = await pipeline("feature-extraction", this.modelName, {
309
+ quantized: true,
310
+ progress_callback: (progress: any) => {
311
+ // Optional: Log model download progress
312
+ if (progress.status === "downloading") {
313
+ // Silently handle progress
252
314
  }
253
- }
254
- );
315
+ },
316
+ });
255
317
 
256
318
  // Update dimension based on model (384 for all-MiniLM-L6-v2)
257
- if (this.modelName.includes('all-MiniLM-L6-v2')) {
319
+ if (this.modelName.includes("all-MiniLM-L6-v2")) {
258
320
  this.dimension = 384;
259
321
  }
260
322
  } catch (error) {
261
323
  const message = error instanceof Error ? error.message : String(error);
262
324
  throw new ConfigurationError(
263
325
  `Failed to load local model: ${message}. Make sure @xenova/transformers is installed.`,
264
- { modelName: this.modelName, error: message }
326
+ { modelName: this.modelName, error: message },
265
327
  );
266
328
  }
267
329
  }
@@ -271,20 +333,20 @@ class EmbeddingService {
271
333
  * Ollama runs locally and doesn't require authentication
272
334
  * @private
273
335
  */
274
- async _initOllama() {
336
+ _initOllama(): void {
275
337
  // Ollama doesn't require initialization - it's a local HTTP API
276
338
  // Store the base URL for use in _embedOllama
277
339
  this.model = {
278
340
  baseUrl: this.baseUrl,
279
- modelName: this.modelName || 'nomic-embed-text'
341
+ modelName: this.modelName || "nomic-embed-text",
280
342
  };
281
343
 
282
344
  // Set default dimension for common Ollama embedding models
283
- if (this.modelName.includes('nomic-embed-text')) {
345
+ if (this.modelName.includes("nomic-embed-text")) {
284
346
  this.dimension = 768;
285
- } else if (this.modelName.includes('mxbai-embed')) {
347
+ } else if (this.modelName.includes("mxbai-embed")) {
286
348
  this.dimension = 1024;
287
- } else if (this.modelName.includes('all-MiniLM')) {
349
+ } else if (this.modelName.includes("all-MiniLM")) {
288
350
  this.dimension = 384;
289
351
  }
290
352
  }
@@ -293,29 +355,28 @@ class EmbeddingService {
293
355
  * Initialize OpenAI client
294
356
  * @private
295
357
  */
296
- async _initOpenAI() {
358
+ async _initOpenAI(): Promise<void> {
297
359
  if (!this.apiKey) {
298
360
  throw new ConfigurationError(
299
- 'OpenAI API key is required. Set EMBEDDING_API_KEY environment variable or pass apiKey in config.',
300
- { modelType: 'openai' }
361
+ "OpenAI API key is required. Set EMBEDDING_API_KEY environment variable or pass apiKey in config.",
362
+ { modelType: "openai" },
301
363
  );
302
364
  }
303
365
 
304
366
  try {
305
- // Dynamic import to allow optional dependency
306
- const { OpenAI } = await import("openai");
307
- // @ts-ignore - OpenAI constructor
367
+ // Dynamic import to allow optional dependency (openai may not be installed)
368
+ const { OpenAI } = await import("openai" as any);
308
369
  this.model = new OpenAI({ apiKey: this.apiKey });
309
370
 
310
371
  // Update dimension for OpenAI models
311
- if (this.modelName.includes('text-embedding-ada-002')) {
372
+ if (this.modelName.includes("text-embedding-ada-002")) {
312
373
  this.dimension = 1536;
313
374
  }
314
375
  } catch (error) {
315
376
  const message = error instanceof Error ? error.message : String(error);
316
377
  throw new ConfigurationError(
317
378
  `Failed to initialize OpenAI client: ${message}. Make sure openai package is installed.`,
318
- { error: message }
379
+ { error: message },
319
380
  );
320
381
  }
321
382
  }
@@ -324,29 +385,28 @@ class EmbeddingService {
324
385
  * Initialize Cohere client
325
386
  * @private
326
387
  */
327
- async _initCohere() {
388
+ async _initCohere(): Promise<void> {
328
389
  if (!this.apiKey) {
329
390
  throw new ConfigurationError(
330
- 'Cohere API key is required. Set EMBEDDING_API_KEY environment variable or pass apiKey in config.',
331
- { modelType: 'cohere' }
391
+ "Cohere API key is required. Set EMBEDDING_API_KEY environment variable or pass apiKey in config.",
392
+ { modelType: "cohere" },
332
393
  );
333
394
  }
334
395
 
335
396
  try {
336
- // Dynamic import to allow optional dependency
337
- const cohere = await import("cohere-ai");
338
- // @ts-ignore - Cohere constructor
397
+ // Dynamic import to allow optional dependency (cohere-ai may not be installed)
398
+ const cohere = await import("cohere-ai" as any);
339
399
  this.model = new cohere.CohereClient({ token: this.apiKey });
340
400
 
341
401
  // Update dimension for Cohere models
342
- if (this.modelName.includes('embed-english-v3.0')) {
402
+ if (this.modelName.includes("embed-english-v3.0")) {
343
403
  this.dimension = 1024;
344
404
  }
345
405
  } catch (error) {
346
406
  const message = error instanceof Error ? error.message : String(error);
347
407
  throw new ConfigurationError(
348
408
  `Failed to initialize Cohere client: ${message}. Make sure cohere-ai package is installed.`,
349
- { error: message }
409
+ { error: message },
350
410
  );
351
411
  }
352
412
  }
@@ -357,24 +417,28 @@ class EmbeddingService {
357
417
  * @returns {Promise<number[]>} Embedding vector
358
418
  * @private
359
419
  */
360
- async _embedLocal(text) {
361
- if (!this.model) throw new EmbeddingError('Model not initialized');
420
+ async _embedLocal(text: string): Promise<number[]> {
421
+ if (!this.model) {
422
+ throw new EmbeddingError("Model not initialized");
423
+ }
362
424
  try {
363
- // @ts-ignore - Local model call
425
+ // Local model call
364
426
  const output = await this.model(text, {
365
- pooling: 'mean',
366
- normalize: false
427
+ pooling: "mean",
428
+ normalize: false,
367
429
  });
368
430
 
369
431
  // Convert from tensor to array
370
432
  const embedding = Array.from(output.data);
371
- // @ts-ignore
372
- return embedding;
433
+ return embedding as number[];
373
434
  } catch (error) {
374
435
  const message = error instanceof Error ? error.message : String(error);
375
436
  throw new EmbeddingError(
376
437
  `Failed to generate local embedding: ${message}`,
377
- { modelName: this.modelName, text: text.substring(0, 100) }
438
+ {
439
+ modelName: this.modelName,
440
+ text: text.substring(0, 100),
441
+ },
378
442
  );
379
443
  }
380
444
  }
@@ -385,30 +449,30 @@ class EmbeddingService {
385
449
  * @returns {Promise<number[]>} Embedding vector
386
450
  * @private
387
451
  */
388
- async _embedOllama(text) {
389
- if (!this.model) throw new EmbeddingError('Model not initialized');
452
+ async _embedOllama(text: string): Promise<number[]> {
453
+ if (!this.model) {
454
+ throw new EmbeddingError("Model not initialized");
455
+ }
390
456
  try {
391
- // @ts-ignore - Ollama model object
392
457
  const baseUrl = this.model.baseUrl;
393
- // @ts-ignore
394
458
  const modelName = this.model.modelName;
395
459
 
396
460
  const response = await fetch(`${baseUrl}/api/embeddings`, {
397
- method: 'POST',
461
+ method: "POST",
398
462
  headers: {
399
- 'Content-Type': 'application/json'
463
+ "Content-Type": "application/json",
400
464
  },
401
465
  body: JSON.stringify({
402
466
  model: modelName,
403
- prompt: text
404
- })
467
+ prompt: text,
468
+ }),
405
469
  });
406
470
 
407
471
  if (!response.ok) {
408
472
  const errorText = await response.text();
409
473
  throw new EmbeddingError(
410
474
  `Ollama API error: ${response.status} ${response.statusText} - ${errorText}`,
411
- { baseUrl: baseUrl, modelName: modelName }
475
+ { baseUrl: baseUrl, modelName: modelName },
412
476
  );
413
477
  }
414
478
 
@@ -416,8 +480,10 @@ class EmbeddingService {
416
480
 
417
481
  if (!data.embedding) {
418
482
  throw new EmbeddingError(
419
- 'Invalid response from Ollama API: missing embedding field',
420
- { response: data }
483
+ "Invalid response from Ollama API: missing embedding field",
484
+ {
485
+ response: data,
486
+ },
421
487
  );
422
488
  }
423
489
 
@@ -427,13 +493,11 @@ class EmbeddingService {
427
493
  throw error;
428
494
  }
429
495
  const message = error instanceof Error ? error.message : String(error);
430
- // @ts-ignore
431
496
  const baseUrl = this.model?.baseUrl;
432
- // @ts-ignore
433
497
  const modelName = this.model?.modelName;
434
498
  throw new EmbeddingError(
435
499
  `Failed to generate Ollama embedding: ${message}. Make sure Ollama is running and the model is available.`,
436
- { baseUrl, modelName, error: message }
500
+ { baseUrl, modelName, error: message },
437
501
  );
438
502
  }
439
503
  }
@@ -444,13 +508,14 @@ class EmbeddingService {
444
508
  * @returns {Promise<number[]>} Embedding vector
445
509
  * @private
446
510
  */
447
- async _embedOpenAI(text) {
448
- if (!this.model) throw new EmbeddingError('Model not initialized');
511
+ async _embedOpenAI(text: string): Promise<number[]> {
512
+ if (!this.model) {
513
+ throw new EmbeddingError("Model not initialized");
514
+ }
449
515
  try {
450
- // @ts-ignore - OpenAI client
451
516
  const response = await this.model.embeddings.create({
452
517
  model: this.modelName,
453
- input: text
518
+ input: text,
454
519
  });
455
520
 
456
521
  const embedding = response.data[0].embedding;
@@ -459,7 +524,10 @@ class EmbeddingService {
459
524
  const message = error instanceof Error ? error.message : String(error);
460
525
  throw new EmbeddingError(
461
526
  `Failed to generate OpenAI embedding: ${message}`,
462
- { modelName: this.modelName, error: message }
527
+ {
528
+ modelName: this.modelName,
529
+ error: message,
530
+ },
463
531
  );
464
532
  }
465
533
  }
@@ -470,14 +538,15 @@ class EmbeddingService {
470
538
  * @returns {Promise<number[]>} Embedding vector
471
539
  * @private
472
540
  */
473
- async _embedCohere(text) {
474
- if (!this.model) throw new EmbeddingError('Model not initialized');
541
+ async _embedCohere(text: string): Promise<number[]> {
542
+ if (!this.model) {
543
+ throw new EmbeddingError("Model not initialized");
544
+ }
475
545
  try {
476
- // @ts-ignore - Cohere client
477
546
  const response = await this.model.embed({
478
547
  model: this.modelName,
479
548
  texts: [text],
480
- inputType: 'search_document'
549
+ inputType: "search_document",
481
550
  });
482
551
 
483
552
  const embedding = response.embeddings[0];
@@ -486,7 +555,10 @@ class EmbeddingService {
486
555
  const message = error instanceof Error ? error.message : String(error);
487
556
  throw new EmbeddingError(
488
557
  `Failed to generate Cohere embedding: ${message}`,
489
- { modelName: this.modelName, error: message }
558
+ {
559
+ modelName: this.modelName,
560
+ error: message,
561
+ },
490
562
  );
491
563
  }
492
564
  }
@@ -497,10 +569,10 @@ class EmbeddingService {
497
569
  * @returns {number[]} Normalized vector
498
570
  * @private
499
571
  */
500
- _normalize(vector) {
572
+ _normalize(vector: number[]): number[] {
501
573
  // Calculate magnitude
502
574
  const magnitude = Math.sqrt(
503
- vector.reduce((sum, val) => sum + val * val, 0)
575
+ vector.reduce((sum, val) => sum + val * val, 0),
504
576
  );
505
577
 
506
578
  // Avoid division by zero
@@ -509,7 +581,7 @@ class EmbeddingService {
509
581
  }
510
582
 
511
583
  // Normalize
512
- return vector.map(val => val / magnitude);
584
+ return vector.map((val) => val / magnitude);
513
585
  }
514
586
 
515
587
  /**
@@ -518,24 +590,17 @@ class EmbeddingService {
518
590
  * @returns {string} Cache key
519
591
  * @private
520
592
  */
521
- _getCacheKey(text) {
522
- return crypto
523
- .createHash('md5')
524
- .update(text)
525
- .digest('hex');
593
+ _getCacheKey(text: string): string {
594
+ return crypto.createHash("md5").update(text).digest("hex");
526
595
  }
527
596
 
528
- /**
529
- * Set cache value with LRU eviction
530
- * @param {string} key - Cache key
531
- * @param {number[]} value - Embedding vector
532
- * @private
533
- */
534
- _setCache(key, value) {
597
+ _setCache(key: string, value: number[]): void {
535
598
  // Evict oldest if at capacity
536
599
  if (this.cache.size >= this.cacheMaxSize) {
537
600
  const firstKey = this.cache.keys().next().value;
538
- this.cache.delete(firstKey);
601
+ if (firstKey !== undefined) {
602
+ this.cache.delete(firstKey);
603
+ }
539
604
  }
540
605
 
541
606
  this.cache.set(key, value);
@@ -545,7 +610,7 @@ class EmbeddingService {
545
610
  * Get service statistics
546
611
  * @returns {Object} Statistics object
547
612
  */
548
- getStats() {
613
+ getStats(): ServiceStats {
549
614
  return {
550
615
  modelType: this.modelType,
551
616
  modelName: this.modelName,
@@ -556,29 +621,31 @@ class EmbeddingService {
556
621
  cacheMisses: this.stats.cacheMisses,
557
622
  cacheSize: this.cache.size,
558
623
  cacheMaxSize: this.cacheMaxSize,
559
- cacheHitRate: this.stats.cacheHits / (this.stats.cacheHits + this.stats.cacheMisses) || 0,
624
+ cacheHitRate:
625
+ this.stats.cacheHits /
626
+ (this.stats.cacheHits + this.stats.cacheMisses) || 0,
560
627
  batchCount: this.stats.batchCount,
561
628
  batchSize: this.batchSize,
562
- normalize: this.normalize
629
+ normalize: this.normalize,
563
630
  };
564
631
  }
565
632
 
566
633
  /**
567
634
  * Clear the embedding cache
568
635
  */
569
- clearCache() {
636
+ clearCache(): void {
570
637
  this.cache.clear();
571
638
  }
572
639
 
573
640
  /**
574
641
  * Reset statistics
575
642
  */
576
- resetStats() {
643
+ resetStats(): void {
577
644
  this.stats = {
578
645
  totalEmbeddings: 0,
579
646
  cacheHits: 0,
580
647
  cacheMisses: 0,
581
- batchCount: 0
648
+ batchCount: 0,
582
649
  };
583
650
  }
584
651
  }