@mcampa/ai-context-core 0.0.1-beta.05e8984

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +354 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/context.d.ts +276 -0
  5. package/dist/context.d.ts.map +1 -0
  6. package/dist/context.js +1177 -0
  7. package/dist/context.js.map +1 -0
  8. package/dist/embedding/base-embedding.d.ts +51 -0
  9. package/dist/embedding/base-embedding.d.ts.map +1 -0
  10. package/dist/embedding/base-embedding.js +36 -0
  11. package/dist/embedding/base-embedding.js.map +1 -0
  12. package/dist/embedding/gemini-embedding.d.ts +53 -0
  13. package/dist/embedding/gemini-embedding.d.ts.map +1 -0
  14. package/dist/embedding/gemini-embedding.js +154 -0
  15. package/dist/embedding/gemini-embedding.js.map +1 -0
  16. package/dist/embedding/index.d.ts +6 -0
  17. package/dist/embedding/index.d.ts.map +1 -0
  18. package/dist/embedding/index.js +24 -0
  19. package/dist/embedding/index.js.map +1 -0
  20. package/dist/embedding/ollama-embedding.d.ts +55 -0
  21. package/dist/embedding/ollama-embedding.d.ts.map +1 -0
  22. package/dist/embedding/ollama-embedding.js +193 -0
  23. package/dist/embedding/ollama-embedding.js.map +1 -0
  24. package/dist/embedding/openai-embedding.d.ts +36 -0
  25. package/dist/embedding/openai-embedding.d.ts.map +1 -0
  26. package/dist/embedding/openai-embedding.js +161 -0
  27. package/dist/embedding/openai-embedding.js.map +1 -0
  28. package/dist/embedding/voyageai-embedding.d.ts +44 -0
  29. package/dist/embedding/voyageai-embedding.d.ts.map +1 -0
  30. package/dist/embedding/voyageai-embedding.js +227 -0
  31. package/dist/embedding/voyageai-embedding.js.map +1 -0
  32. package/dist/index.d.ts +8 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +24 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/splitter/ast-splitter.d.ts +22 -0
  37. package/dist/splitter/ast-splitter.d.ts.map +1 -0
  38. package/dist/splitter/ast-splitter.js +308 -0
  39. package/dist/splitter/ast-splitter.js.map +1 -0
  40. package/dist/splitter/index.d.ts +41 -0
  41. package/dist/splitter/index.d.ts.map +1 -0
  42. package/dist/splitter/index.js +27 -0
  43. package/dist/splitter/index.js.map +1 -0
  44. package/dist/splitter/langchain-splitter.d.ts +13 -0
  45. package/dist/splitter/langchain-splitter.d.ts.map +1 -0
  46. package/dist/splitter/langchain-splitter.js +118 -0
  47. package/dist/splitter/langchain-splitter.js.map +1 -0
  48. package/dist/sync/merkle.d.ts +30 -0
  49. package/dist/sync/merkle.d.ts.map +1 -0
  50. package/dist/sync/merkle.js +112 -0
  51. package/dist/sync/merkle.js.map +1 -0
  52. package/dist/sync/synchronizer.d.ts +30 -0
  53. package/dist/sync/synchronizer.d.ts.map +1 -0
  54. package/dist/sync/synchronizer.js +347 -0
  55. package/dist/sync/synchronizer.js.map +1 -0
  56. package/dist/types.d.ts +14 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +3 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/utils/env-manager.d.ts +19 -0
  61. package/dist/utils/env-manager.d.ts.map +1 -0
  62. package/dist/utils/env-manager.js +125 -0
  63. package/dist/utils/env-manager.js.map +1 -0
  64. package/dist/utils/index.d.ts +2 -0
  65. package/dist/utils/index.d.ts.map +1 -0
  66. package/dist/utils/index.js +7 -0
  67. package/dist/utils/index.js.map +1 -0
  68. package/dist/vectordb/index.d.ts +5 -0
  69. package/dist/vectordb/index.d.ts.map +1 -0
  70. package/dist/vectordb/index.js +14 -0
  71. package/dist/vectordb/index.js.map +1 -0
  72. package/dist/vectordb/milvus-restful-vectordb.d.ts +75 -0
  73. package/dist/vectordb/milvus-restful-vectordb.d.ts.map +1 -0
  74. package/dist/vectordb/milvus-restful-vectordb.js +728 -0
  75. package/dist/vectordb/milvus-restful-vectordb.js.map +1 -0
  76. package/dist/vectordb/milvus-vectordb.d.ts +60 -0
  77. package/dist/vectordb/milvus-vectordb.d.ts.map +1 -0
  78. package/dist/vectordb/milvus-vectordb.js +662 -0
  79. package/dist/vectordb/milvus-vectordb.js.map +1 -0
  80. package/dist/vectordb/types.d.ts +120 -0
  81. package/dist/vectordb/types.d.ts.map +1 -0
  82. package/dist/vectordb/types.js +9 -0
  83. package/dist/vectordb/types.js.map +1 -0
  84. package/dist/vectordb/zilliz-utils.d.ts +135 -0
  85. package/dist/vectordb/zilliz-utils.d.ts.map +1 -0
  86. package/dist/vectordb/zilliz-utils.js +197 -0
  87. package/dist/vectordb/zilliz-utils.js.map +1 -0
  88. package/package.json +58 -0
@@ -0,0 +1,662 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MilvusVectorDatabase = void 0;
4
+ const milvus2_sdk_node_1 = require("@zilliz/milvus2-sdk-node");
5
+ const zilliz_utils_1 = require("./zilliz-utils");
6
+ class MilvusVectorDatabase {
7
+ constructor(config) {
8
+ this.client = null;
9
+ this.config = config;
10
+ // Start initialization asynchronously without waiting
11
+ this.initializationPromise = this.initialize();
12
+ }
13
+ async initialize() {
14
+ const resolvedAddress = await this.resolveAddress();
15
+ await this.initializeClient(resolvedAddress);
16
+ }
17
+ async initializeClient(address) {
18
+ const milvusConfig = this.config;
19
+ console.log("🔌 Connecting to vector database at: ", address);
20
+ this.client = new milvus2_sdk_node_1.MilvusClient({
21
+ address: address,
22
+ username: milvusConfig.username,
23
+ password: milvusConfig.password,
24
+ token: milvusConfig.token,
25
+ ssl: milvusConfig.ssl || false,
26
+ });
27
+ }
28
+ /**
29
+ * Resolve address from config or token
30
+ * Common logic for both gRPC and REST implementations
31
+ */
32
+ async resolveAddress() {
33
+ const finalConfig = { ...this.config };
34
+ // If address is not provided, get it using token
35
+ if (!finalConfig.address && finalConfig.token) {
36
+ finalConfig.address = await zilliz_utils_1.ClusterManager.getAddressFromToken(finalConfig.token);
37
+ }
38
+ if (!finalConfig.address) {
39
+ throw new Error("Address is required and could not be resolved from token");
40
+ }
41
+ return finalConfig.address;
42
+ }
43
+ /**
44
+ * Ensure initialization is complete before method execution
45
+ */
46
+ async ensureInitialized() {
47
+ await this.initializationPromise;
48
+ if (!this.client) {
49
+ throw new Error("Client not initialized");
50
+ }
51
+ }
52
+ /**
53
+ * Ensure collection is loaded before search/query operations
54
+ */
55
+ async ensureLoaded(collectionName) {
56
+ if (!this.client) {
57
+ throw new Error("MilvusClient is not initialized. Call ensureInitialized() first.");
58
+ }
59
+ try {
60
+ // Check if collection is loaded
61
+ const result = await this.client.getLoadState({
62
+ collection_name: collectionName,
63
+ });
64
+ if (result.state !== milvus2_sdk_node_1.LoadState.LoadStateLoaded) {
65
+ console.log(`[MilvusDB] 🔄 Loading collection '${collectionName}' to memory...`);
66
+ await this.client.loadCollection({
67
+ collection_name: collectionName,
68
+ });
69
+ }
70
+ }
71
+ catch (error) {
72
+ console.error(`[MilvusDB] ❌ Failed to ensure collection '${collectionName}' is loaded:`, error);
73
+ throw error;
74
+ }
75
+ }
76
+ /**
77
+ * Wait for an index to be ready before proceeding
78
+ * Polls index build progress with exponential backoff up to 60 seconds
79
+ */
80
+ async waitForIndexReady(collectionName, fieldName, maxWaitTime = 60000, // 60 seconds
81
+ initialInterval = 500, // 500ms
82
+ maxInterval = 5000, // 5 seconds
83
+ backoffMultiplier = 1.5) {
84
+ if (!this.client) {
85
+ throw new Error("MilvusClient is not initialized. Call ensureInitialized() first.");
86
+ }
87
+ let interval = initialInterval;
88
+ const startTime = Date.now();
89
+ console.log(`[MilvusDB] ⏳ Waiting for index on field '${fieldName}' in collection '${collectionName}' to be ready...`);
90
+ while (Date.now() - startTime < maxWaitTime) {
91
+ try {
92
+ const indexBuildProgress = await this.client.getIndexBuildProgress({
93
+ collection_name: collectionName,
94
+ field_name: fieldName,
95
+ });
96
+ // Debug logging to understand the progress
97
+ console.log(`[MilvusDB] 📊 Index build progress for '${fieldName}': indexed_rows=${indexBuildProgress.indexed_rows}, total_rows=${indexBuildProgress.total_rows}`);
98
+ console.log(`[MilvusDB] 📊 Full response:`, JSON.stringify(indexBuildProgress));
99
+ // Check if index building is complete
100
+ if (indexBuildProgress.indexed_rows === indexBuildProgress.total_rows) {
101
+ console.log(`[MilvusDB] ✅ Index on field '${fieldName}' is ready! (${indexBuildProgress.indexed_rows}/${indexBuildProgress.total_rows} rows indexed)`);
102
+ return;
103
+ }
104
+ // Check for error status
105
+ if (indexBuildProgress.status &&
106
+ indexBuildProgress.status.error_code !== "Success") {
107
+ // Handle known issue with older Milvus versions where sparse vector index progress returns incorrect error
108
+ if (indexBuildProgress.status.reason &&
109
+ indexBuildProgress.status.reason.includes("index duplicates[indexName=]")) {
110
+ console.log(`[MilvusDB] ⚠️ Index progress check returned known older Milvus issue: ${indexBuildProgress.status.reason}`);
111
+ console.log(`[MilvusDB] ⚠️ This is a known issue with older Milvus versions - treating as index ready`);
112
+ return; // Treat as ready since this is a false error
113
+ }
114
+ throw new Error(`Index creation failed for field '${fieldName}' in collection '${collectionName}': ${indexBuildProgress.status.reason}`);
115
+ }
116
+ console.log(`[MilvusDB] 📊 Index building in progress: ${indexBuildProgress.indexed_rows}/${indexBuildProgress.total_rows} rows indexed`);
117
+ // Wait with exponential backoff
118
+ await new Promise((resolve) => setTimeout(resolve, interval));
119
+ interval = Math.min(interval * backoffMultiplier, maxInterval);
120
+ }
121
+ catch (error) {
122
+ console.error(`[MilvusDB] ❌ Error checking index build progress for field '${fieldName}':`, error);
123
+ throw error;
124
+ }
125
+ }
126
+ throw new Error(`Timeout waiting for index on field '${fieldName}' in collection '${collectionName}' to be ready after ${maxWaitTime}ms`);
127
+ }
128
+ /**
129
+ * Load collection with retry logic and exponential backoff
130
+ * Retries up to 5 times with exponential backoff
131
+ */
132
+ async loadCollectionWithRetry(collectionName, maxRetries = 5, initialInterval = 1000, // 1 second
133
+ backoffMultiplier = 2) {
134
+ if (!this.client) {
135
+ throw new Error("MilvusClient is not initialized. Call ensureInitialized() first.");
136
+ }
137
+ let attempt = 1;
138
+ let interval = initialInterval;
139
+ while (attempt <= maxRetries) {
140
+ try {
141
+ console.log(`[MilvusDB] 🔄 Loading collection '${collectionName}' to memory (attempt ${attempt}/${maxRetries})...`);
142
+ await this.client.loadCollection({
143
+ collection_name: collectionName,
144
+ });
145
+ console.log(`[MilvusDB] ✅ Collection '${collectionName}' loaded successfully!`);
146
+ return;
147
+ }
148
+ catch (error) {
149
+ console.error(`[MilvusDB] ❌ Failed to load collection '${collectionName}' on attempt ${attempt}:`, error);
150
+ if (attempt === maxRetries) {
151
+ throw new Error(`Failed to load collection '${collectionName}' after ${maxRetries} attempts: ${error}`);
152
+ }
153
+ // Wait with exponential backoff before retry
154
+ console.log(`[MilvusDB] ⏳ Retrying collection load in ${interval}ms...`);
155
+ await new Promise((resolve) => setTimeout(resolve, interval));
156
+ interval *= backoffMultiplier;
157
+ attempt++;
158
+ }
159
+ }
160
+ }
161
+ async createCollection(collectionName, dimension, description) {
162
+ await this.ensureInitialized();
163
+ console.log("Beginning collection creation:", collectionName);
164
+ console.log("Collection dimension:", dimension);
165
+ const schema = [
166
+ {
167
+ name: "id",
168
+ description: "Document ID",
169
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
170
+ max_length: 512,
171
+ is_primary_key: true,
172
+ },
173
+ {
174
+ name: "vector",
175
+ description: "Embedding vector",
176
+ data_type: milvus2_sdk_node_1.DataType.FloatVector,
177
+ dim: dimension,
178
+ },
179
+ {
180
+ name: "content",
181
+ description: "Document content",
182
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
183
+ max_length: 65535,
184
+ },
185
+ {
186
+ name: "relativePath",
187
+ description: "Relative path to the codebase",
188
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
189
+ max_length: 1024,
190
+ },
191
+ {
192
+ name: "startLine",
193
+ description: "Start line number of the chunk",
194
+ data_type: milvus2_sdk_node_1.DataType.Int64,
195
+ },
196
+ {
197
+ name: "endLine",
198
+ description: "End line number of the chunk",
199
+ data_type: milvus2_sdk_node_1.DataType.Int64,
200
+ },
201
+ {
202
+ name: "fileExtension",
203
+ description: "File extension",
204
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
205
+ max_length: 32,
206
+ },
207
+ {
208
+ name: "metadata",
209
+ description: "Additional document metadata as JSON string",
210
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
211
+ max_length: 65535,
212
+ },
213
+ ];
214
+ const createCollectionParams = {
215
+ collection_name: collectionName,
216
+ description: description || `Claude Context collection: ${collectionName}`,
217
+ fields: schema,
218
+ };
219
+ if (!this.client) {
220
+ throw new Error("MilvusClient is not initialized. Call ensureInitialized() first.");
221
+ }
222
+ await this.client.createCollection(createCollectionParams);
223
+ // Create index
224
+ const indexParams = {
225
+ collection_name: collectionName,
226
+ field_name: "vector",
227
+ index_name: "vector_index",
228
+ index_type: "AUTOINDEX",
229
+ metric_type: milvus2_sdk_node_1.MetricType.COSINE,
230
+ };
231
+ console.log(`[MilvusDB] 🔧 Creating index for field 'vector' in collection '${collectionName}'...`);
232
+ await this.client.createIndex(indexParams);
233
+ // Wait for index to be ready before loading collection
234
+ await this.waitForIndexReady(collectionName, "vector");
235
+ // Load collection to memory with retry logic
236
+ await this.loadCollectionWithRetry(collectionName);
237
+ // Verify collection is created correctly
238
+ await this.client.describeCollection({
239
+ collection_name: collectionName,
240
+ });
241
+ }
242
+ async dropCollection(collectionName) {
243
+ await this.ensureInitialized();
244
+ if (!this.client) {
245
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
246
+ }
247
+ await this.client.dropCollection({
248
+ collection_name: collectionName,
249
+ });
250
+ }
251
+ async hasCollection(collectionName) {
252
+ await this.ensureInitialized();
253
+ if (!this.client) {
254
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
255
+ }
256
+ const result = await this.client.hasCollection({
257
+ collection_name: collectionName,
258
+ });
259
+ return Boolean(result.value);
260
+ }
261
+ async listCollections() {
262
+ await this.ensureInitialized();
263
+ if (!this.client) {
264
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
265
+ }
266
+ const result = await this.client.showCollections();
267
+ // Handle the response format - the Milvus SDK returns different formats
268
+ const resultData = result;
269
+ const collections = resultData.collection_names || resultData.collections || [];
270
+ return Array.isArray(collections) ? collections : [];
271
+ }
272
+ async insert(collectionName, documents) {
273
+ await this.ensureInitialized();
274
+ await this.ensureLoaded(collectionName);
275
+ if (!this.client) {
276
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
277
+ }
278
+ console.log("Inserting documents into collection:", collectionName);
279
+ const data = documents.map((doc) => ({
280
+ id: doc.id,
281
+ vector: doc.vector,
282
+ content: doc.content,
283
+ relativePath: doc.relativePath,
284
+ startLine: doc.startLine,
285
+ endLine: doc.endLine,
286
+ fileExtension: doc.fileExtension,
287
+ metadata: JSON.stringify(doc.metadata),
288
+ }));
289
+ await this.client.insert({
290
+ collection_name: collectionName,
291
+ data: data,
292
+ });
293
+ }
294
+ async search(collectionName, queryVector, options) {
295
+ await this.ensureInitialized();
296
+ await this.ensureLoaded(collectionName);
297
+ if (!this.client) {
298
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
299
+ }
300
+ const searchParams = {
301
+ collection_name: collectionName,
302
+ data: [queryVector],
303
+ limit: options?.topK || 10,
304
+ output_fields: [
305
+ "id",
306
+ "content",
307
+ "relativePath",
308
+ "startLine",
309
+ "endLine",
310
+ "fileExtension",
311
+ "metadata",
312
+ ],
313
+ };
314
+ // Apply boolean expression filter if provided (e.g., fileExtension in [".ts",".py"])
315
+ if (options?.filterExpr && options.filterExpr.trim().length > 0) {
316
+ searchParams.expr = options.filterExpr;
317
+ }
318
+ const searchResult = await this.client.search(searchParams);
319
+ if (!searchResult.results || searchResult.results.length === 0) {
320
+ return [];
321
+ }
322
+ return searchResult.results.map((result) => ({
323
+ document: {
324
+ id: result.id,
325
+ vector: queryVector,
326
+ content: String(result.content || ""),
327
+ relativePath: String(result.relativePath || ""),
328
+ startLine: Number(result.startLine || 0),
329
+ endLine: Number(result.endLine || 0),
330
+ fileExtension: String(result.fileExtension || ""),
331
+ metadata: JSON.parse(String(result.metadata || "{}")),
332
+ },
333
+ score: result.score,
334
+ }));
335
+ }
336
+ async delete(collectionName, ids) {
337
+ await this.ensureInitialized();
338
+ await this.ensureLoaded(collectionName);
339
+ if (!this.client) {
340
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
341
+ }
342
+ await this.client.delete({
343
+ collection_name: collectionName,
344
+ filter: `id in [${ids.map((id) => `"${id}"`).join(", ")}]`,
345
+ });
346
+ }
347
+ async query(collectionName, filter, outputFields, limit) {
348
+ await this.ensureInitialized();
349
+ await this.ensureLoaded(collectionName);
350
+ if (!this.client) {
351
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
352
+ }
353
+ try {
354
+ const queryParams = {
355
+ collection_name: collectionName,
356
+ filter: filter,
357
+ output_fields: outputFields,
358
+ };
359
+ // Add limit if provided, or default for empty filter expressions
360
+ if (limit !== undefined) {
361
+ queryParams.limit = limit;
362
+ }
363
+ else if (filter === "" || filter.trim() === "") {
364
+ // Milvus requires limit when using empty expressions
365
+ queryParams.limit = 16384; // Default limit for empty filters
366
+ }
367
+ const result = await this.client.query(queryParams);
368
+ if (result.status.error_code !== "Success") {
369
+ throw new Error(`Failed to query Milvus: ${result.status.reason}`);
370
+ }
371
+ return result.data || [];
372
+ }
373
+ catch (error) {
374
+ console.error(`[MilvusDB] ❌ Failed to query collection '${collectionName}':`, error);
375
+ throw error;
376
+ }
377
+ }
378
+ async createHybridCollection(collectionName, dimension, description) {
379
+ await this.ensureInitialized();
380
+ console.log("Beginning hybrid collection creation:", collectionName);
381
+ console.log("Collection dimension:", dimension);
382
+ const schema = [
383
+ {
384
+ name: "id",
385
+ description: "Document ID",
386
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
387
+ max_length: 512,
388
+ is_primary_key: true,
389
+ },
390
+ {
391
+ name: "content",
392
+ description: "Full text content for BM25 and storage",
393
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
394
+ max_length: 65535,
395
+ enable_analyzer: true,
396
+ },
397
+ {
398
+ name: "vector",
399
+ description: "Dense vector embedding",
400
+ data_type: milvus2_sdk_node_1.DataType.FloatVector,
401
+ dim: dimension,
402
+ },
403
+ {
404
+ name: "sparse_vector",
405
+ description: "Sparse vector embedding from BM25",
406
+ data_type: milvus2_sdk_node_1.DataType.SparseFloatVector,
407
+ },
408
+ {
409
+ name: "relativePath",
410
+ description: "Relative path to the codebase",
411
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
412
+ max_length: 1024,
413
+ },
414
+ {
415
+ name: "startLine",
416
+ description: "Start line number of the chunk",
417
+ data_type: milvus2_sdk_node_1.DataType.Int64,
418
+ },
419
+ {
420
+ name: "endLine",
421
+ description: "End line number of the chunk",
422
+ data_type: milvus2_sdk_node_1.DataType.Int64,
423
+ },
424
+ {
425
+ name: "fileExtension",
426
+ description: "File extension",
427
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
428
+ max_length: 32,
429
+ },
430
+ {
431
+ name: "metadata",
432
+ description: "Additional document metadata as JSON string",
433
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
434
+ max_length: 65535,
435
+ },
436
+ ];
437
+ // Add BM25 function
438
+ const functions = [
439
+ {
440
+ name: "content_bm25_emb",
441
+ description: "content bm25 function",
442
+ type: milvus2_sdk_node_1.FunctionType.BM25,
443
+ input_field_names: ["content"],
444
+ output_field_names: ["sparse_vector"],
445
+ params: {},
446
+ },
447
+ ];
448
+ const createCollectionParams = {
449
+ collection_name: collectionName,
450
+ description: description || `Hybrid code context collection: ${collectionName}`,
451
+ fields: schema,
452
+ functions: functions,
453
+ };
454
+ if (!this.client) {
455
+ throw new Error("MilvusClient is not initialized. Call ensureInitialized() first.");
456
+ }
457
+ await this.client.createCollection(createCollectionParams);
458
+ // Create indexes for both vector fields
459
+ // Index for dense vector
460
+ const denseIndexParams = {
461
+ collection_name: collectionName,
462
+ field_name: "vector",
463
+ index_name: "vector_index",
464
+ index_type: "AUTOINDEX",
465
+ metric_type: milvus2_sdk_node_1.MetricType.COSINE,
466
+ };
467
+ console.log(`[MilvusDB] 🔧 Creating dense vector index for field 'vector' in collection '${collectionName}'...`);
468
+ await this.client.createIndex(denseIndexParams);
469
+ // Wait for dense vector index to be ready
470
+ await this.waitForIndexReady(collectionName, "vector");
471
+ // Index for sparse vector
472
+ const sparseIndexParams = {
473
+ collection_name: collectionName,
474
+ field_name: "sparse_vector",
475
+ index_name: "sparse_vector_index",
476
+ index_type: "SPARSE_INVERTED_INDEX",
477
+ metric_type: milvus2_sdk_node_1.MetricType.BM25,
478
+ };
479
+ console.log(`[MilvusDB] 🔧 Creating sparse vector index for field 'sparse_vector' in collection '${collectionName}'...`);
480
+ await this.client.createIndex(sparseIndexParams);
481
+ // Wait for sparse vector index to be ready
482
+ await this.waitForIndexReady(collectionName, "sparse_vector");
483
+ // Load collection to memory with retry logic
484
+ await this.loadCollectionWithRetry(collectionName);
485
+ // Verify collection is created correctly
486
+ await this.client.describeCollection({
487
+ collection_name: collectionName,
488
+ });
489
+ }
490
+ async insertHybrid(collectionName, documents) {
491
+ await this.ensureInitialized();
492
+ await this.ensureLoaded(collectionName);
493
+ if (!this.client) {
494
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
495
+ }
496
+ const data = documents.map((doc) => ({
497
+ id: doc.id,
498
+ content: doc.content,
499
+ vector: doc.vector,
500
+ relativePath: doc.relativePath,
501
+ startLine: doc.startLine,
502
+ endLine: doc.endLine,
503
+ fileExtension: doc.fileExtension,
504
+ metadata: JSON.stringify(doc.metadata),
505
+ }));
506
+ await this.client.insert({
507
+ collection_name: collectionName,
508
+ data: data,
509
+ });
510
+ }
511
+ async hybridSearch(collectionName, searchRequests, options) {
512
+ await this.ensureInitialized();
513
+ await this.ensureLoaded(collectionName);
514
+ if (!this.client) {
515
+ throw new Error("MilvusClient is not initialized after ensureInitialized().");
516
+ }
517
+ try {
518
+ // Generate OpenAI embedding for the first search request (dense)
519
+ console.log(`[MilvusDB] 🔍 Preparing hybrid search for collection: ${collectionName}`);
520
+ // Prepare search requests in the correct Milvus format
521
+ const search_param_1 = {
522
+ data: Array.isArray(searchRequests[0].data)
523
+ ? searchRequests[0].data
524
+ : [searchRequests[0].data],
525
+ anns_field: searchRequests[0].anns_field, // "vector"
526
+ param: searchRequests[0].param, // {"nprobe": 10}
527
+ limit: searchRequests[0].limit,
528
+ };
529
+ const search_param_2 = {
530
+ data: searchRequests[1].data, // query text for sparse search
531
+ anns_field: searchRequests[1].anns_field, // "sparse_vector"
532
+ param: searchRequests[1].param, // {"drop_ratio_search": 0.2}
533
+ limit: searchRequests[1].limit,
534
+ };
535
+ // Set rerank strategy to RRF (100) by default
536
+ const rerank_strategy = {
537
+ strategy: "rrf",
538
+ params: {
539
+ k: 100,
540
+ },
541
+ };
542
+ console.log(`[MilvusDB] 🔍 Dense search params:`, JSON.stringify({
543
+ anns_field: search_param_1.anns_field,
544
+ param: search_param_1.param,
545
+ limit: search_param_1.limit,
546
+ data_length: Array.isArray(search_param_1.data[0])
547
+ ? search_param_1.data[0].length
548
+ : "N/A",
549
+ }, null, 2));
550
+ console.log(`[MilvusDB] 🔍 Sparse search params:`, JSON.stringify({
551
+ anns_field: search_param_2.anns_field,
552
+ param: search_param_2.param,
553
+ limit: search_param_2.limit,
554
+ query_text: typeof search_param_2.data === "string"
555
+ ? search_param_2.data.substring(0, 50) + "..."
556
+ : "N/A",
557
+ }, null, 2));
558
+ console.log(`[MilvusDB] 🔍 Rerank strategy:`, JSON.stringify(rerank_strategy, null, 2));
559
+ // Execute hybrid search using the correct client.search format
560
+ const searchParams = {
561
+ collection_name: collectionName,
562
+ data: [search_param_1, search_param_2],
563
+ limit: options?.limit || searchRequests[0]?.limit || 10,
564
+ rerank: rerank_strategy,
565
+ output_fields: [
566
+ "id",
567
+ "content",
568
+ "relativePath",
569
+ "startLine",
570
+ "endLine",
571
+ "fileExtension",
572
+ "metadata",
573
+ ],
574
+ };
575
+ if (options?.filterExpr && options.filterExpr.trim().length > 0) {
576
+ searchParams.expr = options.filterExpr;
577
+ }
578
+ console.log(`[MilvusDB] 🔍 Complete search request:`, JSON.stringify({
579
+ collection_name: searchParams.collection_name,
580
+ data_count: searchParams.data.length,
581
+ limit: searchParams.limit,
582
+ rerank: searchParams.rerank,
583
+ output_fields: searchParams.output_fields,
584
+ expr: searchParams.expr,
585
+ }, null, 2));
586
+ const searchResult = await this.client.search(searchParams);
587
+ console.log(`[MilvusDB] 🔍 Search executed, processing results...`);
588
+ if (!searchResult.results || searchResult.results.length === 0) {
589
+ console.log(`[MilvusDB] ⚠️ No results returned from Milvus search`);
590
+ return [];
591
+ }
592
+ console.log(`[MilvusDB] ✅ Found ${searchResult.results.length} results from hybrid search`);
593
+ // Transform results to HybridSearchResult format
594
+ return searchResult.results.map((result) => ({
595
+ document: {
596
+ id: result.id,
597
+ content: String(result.content || ""),
598
+ vector: [],
599
+ relativePath: String(result.relativePath || ""),
600
+ startLine: Number(result.startLine || 0),
601
+ endLine: Number(result.endLine || 0),
602
+ fileExtension: String(result.fileExtension || ""),
603
+ metadata: JSON.parse(String(result.metadata || "{}")),
604
+ },
605
+ score: result.score,
606
+ }));
607
+ }
608
+ catch (error) {
609
+ console.error(`[MilvusDB] ❌ Failed to perform hybrid search on collection '${collectionName}':`, error);
610
+ throw error;
611
+ }
612
+ }
613
+ /**
614
+ * Wrapper method to handle collection creation with limit detection for gRPC client
615
+ * Returns true if collection can be created, false if limit exceeded
616
+ */
617
+ async checkCollectionLimit() {
618
+ if (!this.client) {
619
+ throw new Error("MilvusClient is not initialized. Call ensureInitialized() first.");
620
+ }
621
+ const collectionName = `dummy_collection_${Date.now()}`;
622
+ const createCollectionParams = {
623
+ collection_name: collectionName,
624
+ description: "Test collection for limit check",
625
+ fields: [
626
+ {
627
+ name: "id",
628
+ data_type: milvus2_sdk_node_1.DataType.VarChar,
629
+ max_length: 512,
630
+ is_primary_key: true,
631
+ },
632
+ {
633
+ name: "vector",
634
+ data_type: milvus2_sdk_node_1.DataType.FloatVector,
635
+ dim: 128,
636
+ },
637
+ ],
638
+ };
639
+ try {
640
+ await this.client.createCollection(createCollectionParams);
641
+ // Immediately drop the collection after successful creation
642
+ if (await this.client.hasCollection({ collection_name: collectionName })) {
643
+ await this.client.dropCollection({
644
+ collection_name: collectionName,
645
+ });
646
+ }
647
+ return true;
648
+ }
649
+ catch (error) {
650
+ // Check if the error message contains the collection limit exceeded pattern
651
+ const errorMessage = String(error);
652
+ if (/exceeded the limit number of collections/i.test(errorMessage)) {
653
+ // Return false for collection limit exceeded
654
+ return false;
655
+ }
656
+ // Re-throw other errors as-is
657
+ throw error;
658
+ }
659
+ }
660
+ }
661
+ exports.MilvusVectorDatabase = MilvusVectorDatabase;
662
+ //# sourceMappingURL=milvus-vectordb.js.map