@retrivora-ai/rag-engine 0.1.6 → 0.1.8
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.
- package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-2JZSBOQX.mjs} +1 -1
- package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-CJDBCBVI.mjs} +1 -1
- package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-E6L5Z2FO.mjs} +1 -1
- package/dist/{QdrantProvider-NYGHAA7C.mjs → QdrantProvider-JITRNJQN.mjs} +1 -1
- package/dist/{RagConfig-hBGXJmSx.d.mts → RagConfig-D_rSf8ep.d.mts} +1 -1
- package/dist/{RagConfig-hBGXJmSx.d.ts → RagConfig-D_rSf8ep.d.ts} +1 -1
- package/dist/{RedisProvider-ASONNYBI.mjs → RedisProvider-3VKFQXXD.mjs} +1 -1
- package/dist/UniversalVectorProvider-E6L4U4OX.mjs +9 -0
- package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-MXIPP44J.mjs} +1 -1
- package/dist/{chunk-5K23H7JL.mjs → chunk-26EMHLIN.mjs} +40 -2
- package/dist/{chunk-VPNRDXIA.mjs → chunk-7BQI4A5J.mjs} +17 -11
- package/dist/{chunk-ZM6TYIDH.mjs → chunk-MFWJZVF3.mjs} +3 -1
- package/dist/{chunk-V75V7BT2.mjs → chunk-TSX6DQXX.mjs} +2 -2
- package/dist/{chunk-HUGLYKD6.mjs → chunk-XZPVJS2B.mjs} +27 -9
- package/dist/chunk-Y6HQZDCJ.mjs +156 -0
- package/dist/{chunk-HSBXE2WV.mjs → chunk-YIYDJQJM.mjs} +745 -192
- package/dist/{chunk-7NXI6ZWX.mjs → chunk-YST6KYBJ.mjs} +8 -5
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +924 -626
- package/dist/handlers/index.mjs +1 -2
- package/dist/index-BJ8CUArE.d.mts +114 -0
- package/dist/index-DtNprGGj.d.ts +114 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/server.d.mts +575 -17
- package/dist/server.d.ts +575 -17
- package/dist/server.js +1280 -643
- package/dist/server.mjs +314 -16
- package/package.json +11 -2
- package/src/config/ConfigBuilder.ts +373 -0
- package/src/config/EmbeddingStrategy.ts +147 -0
- package/src/config/serverConfig.ts +51 -17
- package/src/core/ConfigValidator.ts +77 -52
- package/src/core/Pipeline.ts +28 -26
- package/src/core/PluginManager.ts +277 -0
- package/src/core/ProviderHealthCheck.ts +79 -140
- package/src/core/ProviderRegistry.ts +38 -15
- package/src/providers/vectordb/ChromaDBProvider.ts +37 -12
- package/src/providers/vectordb/MilvusProvider.ts +25 -10
- package/src/providers/vectordb/PineconeProvider.ts +17 -2
- package/src/providers/vectordb/QdrantProvider.ts +46 -2
- package/src/providers/vectordb/RedisProvider.ts +34 -11
- package/src/providers/vectordb/UniversalVectorProvider.ts +220 -0
- package/src/providers/vectordb/WeaviateProvider.ts +17 -10
- package/src/server.ts +28 -10
- package/dist/LLMFactory-JFOY2V4X.mjs +0 -8
- package/dist/chunk-JI6VD5TJ.mjs +0 -387
- package/dist/index-Bx182KKn.d.ts +0 -64
- package/dist/index-Ck2pt7-8.d.mts +0 -64
- package/src/test-refactor.ts +0 -59
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Performs connectivity tests, credential validation, and capability checks
|
|
5
5
|
* before initializing providers.
|
|
6
|
+
*
|
|
7
|
+
* Note: Option keys used here mirror each Provider constructor's expected keys.
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import { VectorDBConfig, LLMConfig, EmbeddingConfig } from '../config/RagConfig';
|
|
@@ -20,16 +22,15 @@ export interface HealthCheckResult {
|
|
|
20
22
|
export class ProviderHealthCheck {
|
|
21
23
|
/**
|
|
22
24
|
* Validates vector database configuration before initialization.
|
|
23
|
-
* Performs connectivity checks and verifies required resources exist.
|
|
24
25
|
*/
|
|
25
26
|
static async checkVectorProvider(config: VectorDBConfig): Promise<HealthCheckResult> {
|
|
26
27
|
const timestamp = Date.now();
|
|
27
28
|
|
|
28
|
-
//
|
|
29
|
+
// Validate configuration first
|
|
29
30
|
const configErrors = ConfigValidator.validate({
|
|
30
31
|
projectId: 'health-check',
|
|
31
32
|
vectorDb: config,
|
|
32
|
-
llm: { provider: 'openai', model: 'gpt-4o' },
|
|
33
|
+
llm: { provider: 'openai', model: 'gpt-4o' },
|
|
33
34
|
embedding: { provider: 'openai', model: 'text-embedding-3-small' },
|
|
34
35
|
});
|
|
35
36
|
|
|
@@ -85,15 +86,12 @@ export class ProviderHealthCheck {
|
|
|
85
86
|
|
|
86
87
|
private static async checkPinecone(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
87
88
|
const opts = config.options as Record<string, string>;
|
|
88
|
-
|
|
89
89
|
try {
|
|
90
|
-
// Dynamic import to avoid requiring all dependencies
|
|
91
90
|
const { Pinecone } = await import('@pinecone-database/pinecone');
|
|
92
91
|
const client = new Pinecone({ apiKey: opts.apiKey });
|
|
93
|
-
|
|
94
92
|
const indexes = await client.listIndexes();
|
|
95
93
|
const indexNames = indexes.indexes?.map((i) => i.name) ?? [];
|
|
96
|
-
|
|
94
|
+
|
|
97
95
|
if (!indexNames.includes(config.indexName)) {
|
|
98
96
|
return {
|
|
99
97
|
healthy: false,
|
|
@@ -102,14 +100,10 @@ export class ProviderHealthCheck {
|
|
|
102
100
|
timestamp,
|
|
103
101
|
};
|
|
104
102
|
}
|
|
105
|
-
|
|
106
103
|
return {
|
|
107
104
|
healthy: true,
|
|
108
105
|
provider: 'pinecone',
|
|
109
|
-
capabilities: {
|
|
110
|
-
indexes: indexNames.length,
|
|
111
|
-
targetIndex: config.indexName,
|
|
112
|
-
},
|
|
106
|
+
capabilities: { indexes: indexNames.length, targetIndex: config.indexName },
|
|
113
107
|
timestamp,
|
|
114
108
|
};
|
|
115
109
|
} catch (error) {
|
|
@@ -124,24 +118,15 @@ export class ProviderHealthCheck {
|
|
|
124
118
|
|
|
125
119
|
private static async checkPostgres(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
126
120
|
const opts = config.options as Record<string, string>;
|
|
127
|
-
|
|
128
121
|
try {
|
|
129
122
|
const { Client } = await import('pg');
|
|
130
123
|
const client = new Client({ connectionString: opts.connectionString });
|
|
131
|
-
|
|
132
124
|
await client.connect();
|
|
133
|
-
|
|
134
|
-
// Check if pgvector extension is installed
|
|
135
125
|
const result = await client.query(`
|
|
136
|
-
SELECT EXISTS(
|
|
137
|
-
SELECT 1 FROM pg_extension WHERE extname = 'vector'
|
|
138
|
-
);
|
|
126
|
+
SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
|
|
139
127
|
`);
|
|
140
|
-
|
|
141
128
|
const hasVector = result.rows[0].exists;
|
|
142
|
-
|
|
143
129
|
await client.end();
|
|
144
|
-
|
|
145
130
|
return {
|
|
146
131
|
healthy: true,
|
|
147
132
|
provider: 'postgresql',
|
|
@@ -160,27 +145,21 @@ export class ProviderHealthCheck {
|
|
|
160
145
|
|
|
161
146
|
private static async checkMongoDB(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
162
147
|
const opts = config.options as Record<string, string>;
|
|
163
|
-
|
|
164
148
|
try {
|
|
165
149
|
const { MongoClient } = await import('mongodb');
|
|
166
150
|
const client = new MongoClient(opts.uri);
|
|
167
|
-
|
|
168
151
|
await client.connect();
|
|
169
|
-
|
|
170
152
|
const db = client.db(opts.database);
|
|
171
153
|
const collections = await db.listCollections().toArray();
|
|
172
154
|
const collectionNames = collections.map((c) => c.name);
|
|
173
|
-
|
|
174
155
|
const hasCollection = collectionNames.includes(opts.collection);
|
|
175
|
-
|
|
176
156
|
await client.close();
|
|
177
|
-
|
|
178
157
|
return {
|
|
179
158
|
healthy: true,
|
|
180
159
|
provider: 'mongodb',
|
|
181
160
|
capabilities: {
|
|
182
161
|
collections: collectionNames.length,
|
|
183
|
-
targetCollection: hasCollection ? opts.collection : 'NOT FOUND',
|
|
162
|
+
targetCollection: hasCollection ? opts.collection : 'NOT FOUND (will be created on first insert)',
|
|
184
163
|
},
|
|
185
164
|
timestamp,
|
|
186
165
|
};
|
|
@@ -194,30 +173,31 @@ export class ProviderHealthCheck {
|
|
|
194
173
|
}
|
|
195
174
|
}
|
|
196
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Milvus health check — uses baseUrl/uri (matching MilvusProvider constructor).
|
|
178
|
+
*/
|
|
197
179
|
private static async checkMilvus(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
198
180
|
const opts = config.options as Record<string, unknown>;
|
|
199
|
-
|
|
200
|
-
|
|
181
|
+
|
|
182
|
+
// Resolve endpoint — mirrors MilvusProvider constructor logic
|
|
183
|
+
const baseUrl =
|
|
184
|
+
(opts.baseUrl as string) ||
|
|
185
|
+
(opts.uri as string) ||
|
|
186
|
+
(opts.host ? `http://${opts.host}:${(opts.port as number) || 19530}` : 'http://localhost:19530');
|
|
201
187
|
|
|
202
188
|
try {
|
|
203
|
-
// Try HTTP health check endpoint
|
|
204
189
|
const controller = new AbortController();
|
|
205
190
|
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
206
|
-
|
|
207
|
-
const response = await fetch(`http://${host}:${port}/healthz`, {
|
|
208
|
-
signal: controller.signal,
|
|
209
|
-
});
|
|
210
|
-
|
|
191
|
+
const response = await fetch(`${baseUrl}/v1/health`, { signal: controller.signal });
|
|
211
192
|
clearTimeout(timeoutId);
|
|
212
193
|
|
|
213
194
|
if (!response.ok) {
|
|
214
195
|
throw new Error(`Health check returned ${response.status}`);
|
|
215
196
|
}
|
|
216
|
-
|
|
217
197
|
return {
|
|
218
198
|
healthy: true,
|
|
219
199
|
provider: 'milvus',
|
|
220
|
-
capabilities: { endpoint:
|
|
200
|
+
capabilities: { endpoint: baseUrl },
|
|
221
201
|
timestamp,
|
|
222
202
|
};
|
|
223
203
|
} catch (error) {
|
|
@@ -230,19 +210,19 @@ export class ProviderHealthCheck {
|
|
|
230
210
|
}
|
|
231
211
|
}
|
|
232
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Qdrant health check — uses baseUrl (matching QdrantProvider constructor).
|
|
215
|
+
*/
|
|
233
216
|
private static async checkQdrant(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
234
217
|
const opts = config.options as Record<string, unknown>;
|
|
235
|
-
const baseUrl = (opts.baseUrl as string) || (opts.url as string) || 'http://localhost:6333';
|
|
236
|
-
|
|
218
|
+
const baseUrl = ((opts.baseUrl as string) || (opts.url as string) || 'http://localhost:6333').replace(/\/$/, '');
|
|
237
219
|
try {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
220
|
+
const apiKey = opts.apiKey as string | undefined;
|
|
221
|
+
const response = await fetch(`${baseUrl}/`, {
|
|
222
|
+
headers: apiKey ? { 'api-key': apiKey } : {},
|
|
223
|
+
});
|
|
224
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
244
225
|
const health = await response.json();
|
|
245
|
-
|
|
246
226
|
return {
|
|
247
227
|
healthy: true,
|
|
248
228
|
provider: 'qdrant',
|
|
@@ -259,22 +239,24 @@ export class ProviderHealthCheck {
|
|
|
259
239
|
}
|
|
260
240
|
}
|
|
261
241
|
|
|
242
|
+
/**
|
|
243
|
+
* ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
|
|
244
|
+
*/
|
|
262
245
|
private static async checkChromaDB(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
263
246
|
const opts = config.options as Record<string, unknown>;
|
|
264
|
-
const host = (opts.host as string) || 'localhost';
|
|
265
|
-
const port = (opts.port as number) || 8000;
|
|
266
247
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
272
|
-
}
|
|
248
|
+
// Mirrors ChromaDBProvider constructor
|
|
249
|
+
const baseUrl =
|
|
250
|
+
(opts.baseUrl as string) ||
|
|
251
|
+
(opts.host ? `http://${opts.host}:${(opts.port as number) || 8000}` : 'http://localhost:8000');
|
|
273
252
|
|
|
253
|
+
try {
|
|
254
|
+
const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
|
|
255
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
274
256
|
return {
|
|
275
257
|
healthy: true,
|
|
276
258
|
provider: 'chromadb',
|
|
277
|
-
capabilities: { endpoint:
|
|
259
|
+
capabilities: { endpoint: baseUrl },
|
|
278
260
|
timestamp,
|
|
279
261
|
};
|
|
280
262
|
} catch (error) {
|
|
@@ -287,47 +269,49 @@ export class ProviderHealthCheck {
|
|
|
287
269
|
}
|
|
288
270
|
}
|
|
289
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Redis health check — Redis is TCP-only (no HTTP endpoint).
|
|
274
|
+
* We report healthy=true with a note; actual connectivity is validated at first operation.
|
|
275
|
+
*/
|
|
290
276
|
private static async checkRedis(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
291
277
|
const opts = config.options as Record<string, string>;
|
|
292
|
-
const url =
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
timestamp,
|
|
304
|
-
};
|
|
305
|
-
} catch (error) {
|
|
306
|
-
// If fetch fails, try to gracefully handle (redis may not have HTTP interface)
|
|
307
|
-
return {
|
|
308
|
-
healthy: false,
|
|
309
|
-
provider: 'redis',
|
|
310
|
-
error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
|
|
311
|
-
timestamp,
|
|
312
|
-
};
|
|
278
|
+
const url =
|
|
279
|
+
opts.baseUrl || opts.url || (opts.host && opts.port ? `redis://${opts.host}:${opts.port}` : 'redis://localhost:6379');
|
|
280
|
+
|
|
281
|
+
// For Upstash REST endpoints, try an HTTP ping
|
|
282
|
+
if (url.startsWith('http')) {
|
|
283
|
+
try {
|
|
284
|
+
await fetch(url);
|
|
285
|
+
return { healthy: true, provider: 'redis', capabilities: { endpoint: url }, timestamp };
|
|
286
|
+
} catch {
|
|
287
|
+
// Ignore — Upstash may reject GET but accept POST
|
|
288
|
+
}
|
|
313
289
|
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
healthy: true,
|
|
293
|
+
provider: 'redis',
|
|
294
|
+
capabilities: {
|
|
295
|
+
endpoint: url,
|
|
296
|
+
note: 'Redis uses TCP; connectivity is validated on first operation.',
|
|
297
|
+
},
|
|
298
|
+
timestamp,
|
|
299
|
+
};
|
|
314
300
|
}
|
|
315
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
|
|
304
|
+
*/
|
|
316
305
|
private static async checkWeaviate(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
317
306
|
const opts = config.options as Record<string, string>;
|
|
318
|
-
const
|
|
319
|
-
|
|
307
|
+
const baseUrl = ((opts.baseUrl || opts.url) || 'http://localhost:8080').replace(/\/$/, '');
|
|
320
308
|
try {
|
|
321
|
-
const response = await fetch(`${
|
|
322
|
-
|
|
323
|
-
if (!response.ok) {
|
|
324
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
325
|
-
}
|
|
326
|
-
|
|
309
|
+
const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
|
|
310
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
327
311
|
return {
|
|
328
312
|
healthy: true,
|
|
329
313
|
provider: 'weaviate',
|
|
330
|
-
capabilities: { endpoint:
|
|
314
|
+
capabilities: { endpoint: baseUrl },
|
|
331
315
|
timestamp,
|
|
332
316
|
};
|
|
333
317
|
} catch (error) {
|
|
@@ -343,21 +327,13 @@ export class ProviderHealthCheck {
|
|
|
343
327
|
private static async checkRestAPI(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
344
328
|
const opts = config.options as Record<string, string>;
|
|
345
329
|
const baseUrl = (opts.baseUrl || '').replace(/\/$/, '');
|
|
346
|
-
|
|
347
330
|
if (!baseUrl) {
|
|
348
|
-
return {
|
|
349
|
-
healthy: false,
|
|
350
|
-
provider: 'rest',
|
|
351
|
-
error: 'baseUrl is required',
|
|
352
|
-
timestamp,
|
|
353
|
-
};
|
|
331
|
+
return { healthy: false, provider: 'rest', error: 'baseUrl is required', timestamp };
|
|
354
332
|
}
|
|
355
|
-
|
|
356
333
|
try {
|
|
357
334
|
const response = await fetch(`${baseUrl}/health`, {
|
|
358
335
|
headers: opts.headers ? JSON.parse(opts.headers) : {},
|
|
359
336
|
});
|
|
360
|
-
|
|
361
337
|
return {
|
|
362
338
|
healthy: response.ok,
|
|
363
339
|
provider: 'rest',
|
|
@@ -379,7 +355,6 @@ export class ProviderHealthCheck {
|
|
|
379
355
|
*/
|
|
380
356
|
static async checkLLMProvider(config: LLMConfig): Promise<HealthCheckResult> {
|
|
381
357
|
const timestamp = Date.now();
|
|
382
|
-
|
|
383
358
|
try {
|
|
384
359
|
switch (config.provider) {
|
|
385
360
|
case 'openai':
|
|
@@ -413,20 +388,12 @@ export class ProviderHealthCheck {
|
|
|
413
388
|
try {
|
|
414
389
|
const OpenAI = await import('openai');
|
|
415
390
|
const client = new OpenAI.default({ apiKey: config.apiKey });
|
|
416
|
-
|
|
417
|
-
// Test models endpoint
|
|
418
391
|
const models = await client.models.list();
|
|
419
|
-
|
|
420
392
|
const hasModel = models.data.some((m) => m.id === config.model);
|
|
421
|
-
|
|
422
393
|
return {
|
|
423
394
|
healthy: true,
|
|
424
395
|
provider: 'openai',
|
|
425
|
-
capabilities: {
|
|
426
|
-
model: config.model,
|
|
427
|
-
available: hasModel,
|
|
428
|
-
totalModels: models.data.length,
|
|
429
|
-
},
|
|
396
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
|
|
430
397
|
timestamp,
|
|
431
398
|
};
|
|
432
399
|
} catch (error) {
|
|
@@ -443,20 +410,12 @@ export class ProviderHealthCheck {
|
|
|
443
410
|
try {
|
|
444
411
|
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
445
412
|
const client = new Anthropic({ apiKey: config.apiKey });
|
|
446
|
-
|
|
447
|
-
// Try a minimal API call to verify credentials
|
|
448
413
|
await client.messages.create({
|
|
449
414
|
model: config.model,
|
|
450
415
|
max_tokens: 10,
|
|
451
416
|
messages: [{ role: 'user', content: 'ping' }],
|
|
452
417
|
});
|
|
453
|
-
|
|
454
|
-
return {
|
|
455
|
-
healthy: true,
|
|
456
|
-
provider: 'anthropic',
|
|
457
|
-
capabilities: { model: config.model },
|
|
458
|
-
timestamp,
|
|
459
|
-
};
|
|
418
|
+
return { healthy: true, provider: 'anthropic', capabilities: { model: config.model }, timestamp };
|
|
460
419
|
} catch (error) {
|
|
461
420
|
return {
|
|
462
421
|
healthy: false,
|
|
@@ -469,26 +428,16 @@ export class ProviderHealthCheck {
|
|
|
469
428
|
|
|
470
429
|
private static async checkOllama(config: LLMConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
471
430
|
const baseUrl = (config.baseUrl || 'http://localhost:11434').replace(/\/$/, '');
|
|
472
|
-
|
|
473
431
|
try {
|
|
474
432
|
const response = await fetch(`${baseUrl}/api/tags`);
|
|
475
|
-
|
|
476
|
-
if (!response.ok) {
|
|
477
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
478
|
-
}
|
|
479
|
-
|
|
433
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
480
434
|
const data = await response.json() as Record<string, unknown>;
|
|
481
435
|
const models = (data.models as Array<{ name: string }>) || [];
|
|
482
436
|
const hasModel = models.some((m) => m.name === config.model);
|
|
483
|
-
|
|
484
437
|
return {
|
|
485
438
|
healthy: true,
|
|
486
439
|
provider: 'ollama',
|
|
487
|
-
capabilities: {
|
|
488
|
-
model: config.model,
|
|
489
|
-
available: hasModel,
|
|
490
|
-
totalModels: models.length,
|
|
491
|
-
},
|
|
440
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.length },
|
|
492
441
|
timestamp,
|
|
493
442
|
};
|
|
494
443
|
} catch (error) {
|
|
@@ -504,22 +453,12 @@ export class ProviderHealthCheck {
|
|
|
504
453
|
private static async checkLLMRestAPI(config: LLMConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
505
454
|
const baseUrlRaw = config.baseUrl || (config.options as Record<string, unknown>)?.baseUrl;
|
|
506
455
|
const baseUrl = (typeof baseUrlRaw === 'string' ? baseUrlRaw : '').replace(/\/$/, '');
|
|
507
|
-
|
|
508
456
|
if (!baseUrl) {
|
|
509
|
-
return {
|
|
510
|
-
healthy: false,
|
|
511
|
-
provider: config.provider,
|
|
512
|
-
error: 'baseUrl is required',
|
|
513
|
-
timestamp,
|
|
514
|
-
};
|
|
457
|
+
return { healthy: false, provider: config.provider, error: 'baseUrl is required', timestamp };
|
|
515
458
|
}
|
|
516
|
-
|
|
517
459
|
try {
|
|
518
460
|
const headers = (config.options as Record<string, unknown>)?.headers as Record<string, string> | undefined;
|
|
519
|
-
const response = await fetch(`${baseUrl}/health`, {
|
|
520
|
-
headers: headers || undefined,
|
|
521
|
-
});
|
|
522
|
-
|
|
461
|
+
const response = await fetch(`${baseUrl}/health`, { headers: headers || undefined });
|
|
523
462
|
return {
|
|
524
463
|
healthy: response.ok,
|
|
525
464
|
provider: config.provider,
|
|
@@ -537,7 +476,7 @@ export class ProviderHealthCheck {
|
|
|
537
476
|
}
|
|
538
477
|
|
|
539
478
|
/**
|
|
540
|
-
* Runs comprehensive health checks on all configured providers.
|
|
479
|
+
* Runs comprehensive health checks on all configured providers in parallel.
|
|
541
480
|
*/
|
|
542
481
|
static async checkAll(
|
|
543
482
|
vectorDbConfig: VectorDBConfig,
|
|
@@ -3,17 +3,22 @@ import { VectorDBConfig, LLMConfig, EmbeddingConfig } from '../config/RagConfig'
|
|
|
3
3
|
import { LLMFactory } from '../llm/LLMFactory';
|
|
4
4
|
import { ILLMProvider } from '../llm/ILLMProvider';
|
|
5
5
|
|
|
6
|
-
// We will import these as we create them
|
|
7
|
-
// import { PineconeProvider } from '../providers/vectordb/PineconeProvider';
|
|
8
|
-
|
|
9
6
|
/**
|
|
10
7
|
* ProviderRegistry — dynamic provider loader for Vector DBs and LLMs.
|
|
8
|
+
*
|
|
9
|
+
* Supports:
|
|
10
|
+
* - Built-in providers loaded on-demand via dynamic imports (tree-shaking friendly)
|
|
11
|
+
* - Custom provider registration via registerVectorProvider()
|
|
11
12
|
*/
|
|
12
13
|
export class ProviderRegistry {
|
|
13
14
|
private static vectorProviders: Record<string, new (config: VectorDBConfig) => BaseVectorProvider> = {};
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
|
-
* Register a custom vector provider.
|
|
17
|
+
* Register a custom vector provider class by name.
|
|
18
|
+
* The name must match the provider value used in VectorDBConfig.provider.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ProviderRegistry.registerVectorProvider('my-db', MyCustomProvider);
|
|
17
22
|
*/
|
|
18
23
|
static registerVectorProvider(name: string, providerClass: new (config: VectorDBConfig) => BaseVectorProvider) {
|
|
19
24
|
this.vectorProviders[name] = providerClass;
|
|
@@ -21,44 +26,62 @@ export class ProviderRegistry {
|
|
|
21
26
|
|
|
22
27
|
/**
|
|
23
28
|
* Creates a vector database provider based on the configuration.
|
|
29
|
+
* Built-in providers are dynamically imported to avoid bundling all SDKs.
|
|
24
30
|
*/
|
|
25
31
|
static async createVectorProvider(config: VectorDBConfig): Promise<BaseVectorProvider> {
|
|
26
32
|
const { provider } = config;
|
|
27
33
|
|
|
28
|
-
//
|
|
34
|
+
// Custom registered provider takes priority
|
|
29
35
|
if (this.vectorProviders[provider]) {
|
|
30
36
|
return new this.vectorProviders[provider](config);
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
//
|
|
39
|
+
// Built-in providers — lazy-loaded
|
|
34
40
|
switch (provider) {
|
|
35
|
-
case 'pinecone':
|
|
41
|
+
case 'pinecone': {
|
|
36
42
|
const { PineconeProvider } = await import('../providers/vectordb/PineconeProvider');
|
|
37
43
|
return new PineconeProvider(config);
|
|
44
|
+
}
|
|
38
45
|
case 'pgvector':
|
|
39
|
-
case 'postgresql':
|
|
46
|
+
case 'postgresql': {
|
|
40
47
|
const { PostgreSQLProvider } = await import('../providers/vectordb/PostgreSQLProvider');
|
|
41
48
|
return new PostgreSQLProvider(config);
|
|
42
|
-
|
|
49
|
+
}
|
|
50
|
+
case 'mongodb': {
|
|
43
51
|
const { MongoDBProvider } = await import('../providers/vectordb/MongoDBProvider');
|
|
44
52
|
return new MongoDBProvider(config);
|
|
45
|
-
|
|
53
|
+
}
|
|
54
|
+
case 'milvus': {
|
|
46
55
|
const { MilvusProvider } = await import('../providers/vectordb/MilvusProvider');
|
|
47
56
|
return new MilvusProvider(config);
|
|
48
|
-
|
|
57
|
+
}
|
|
58
|
+
case 'qdrant': {
|
|
49
59
|
const { QdrantProvider } = await import('../providers/vectordb/QdrantProvider');
|
|
50
60
|
return new QdrantProvider(config);
|
|
51
|
-
|
|
61
|
+
}
|
|
62
|
+
case 'chromadb': {
|
|
52
63
|
const { ChromaDBProvider } = await import('../providers/vectordb/ChromaDBProvider');
|
|
53
64
|
return new ChromaDBProvider(config);
|
|
54
|
-
|
|
65
|
+
}
|
|
66
|
+
case 'redis': {
|
|
55
67
|
const { RedisProvider } = await import('../providers/vectordb/RedisProvider');
|
|
56
68
|
return new RedisProvider(config);
|
|
57
|
-
|
|
69
|
+
}
|
|
70
|
+
case 'weaviate': {
|
|
58
71
|
const { WeaviateProvider } = await import('../providers/vectordb/WeaviateProvider');
|
|
59
72
|
return new WeaviateProvider(config);
|
|
73
|
+
}
|
|
74
|
+
case 'universal_rest':
|
|
75
|
+
case 'rest': {
|
|
76
|
+
const { UniversalVectorProvider } = await import('../providers/vectordb/UniversalVectorProvider');
|
|
77
|
+
return new UniversalVectorProvider(config);
|
|
78
|
+
}
|
|
60
79
|
default:
|
|
61
|
-
throw new Error(
|
|
80
|
+
throw new Error(
|
|
81
|
+
`[ProviderRegistry] Unsupported vector provider: "${provider}". ` +
|
|
82
|
+
`Built-in providers: pinecone | pgvector | postgresql | mongodb | milvus | qdrant | chromadb | redis | weaviate | universal_rest. ` +
|
|
83
|
+
`For custom providers, call ProviderRegistry.registerVectorProvider("${provider}", YourClass).`
|
|
84
|
+
);
|
|
62
85
|
}
|
|
63
86
|
}
|
|
64
87
|
|
|
@@ -4,7 +4,10 @@ import { BaseVectorProvider } from './BaseVectorProvider';
|
|
|
4
4
|
import { VectorMatch, UpsertDocument } from '../../types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* ChromaDBProvider — implementation
|
|
7
|
+
* ChromaDBProvider — ChromaDB implementation using its REST API.
|
|
8
|
+
*
|
|
9
|
+
* Required options: { baseUrl: string } — e.g. "http://localhost:8000"
|
|
10
|
+
* Optional: { host?: string, port?: number } — used to construct baseUrl when baseUrl not set
|
|
8
11
|
*/
|
|
9
12
|
export class ChromaDBProvider extends BaseVectorProvider {
|
|
10
13
|
private http: AxiosInstance;
|
|
@@ -13,8 +16,13 @@ export class ChromaDBProvider extends BaseVectorProvider {
|
|
|
13
16
|
constructor(config: VectorDBConfig) {
|
|
14
17
|
super(config);
|
|
15
18
|
const opts = config.options as Record<string, unknown>;
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
|
|
20
|
+
// Accept either explicit baseUrl or host+port
|
|
21
|
+
const baseUrl =
|
|
22
|
+
(opts.baseUrl as string) ||
|
|
23
|
+
(opts.host ? `http://${opts.host}:${(opts.port as number) || 8000}` : undefined);
|
|
24
|
+
|
|
25
|
+
if (!baseUrl) throw new Error('[ChromaDBProvider] options.baseUrl is required');
|
|
18
26
|
|
|
19
27
|
this.http = axios.create({
|
|
20
28
|
baseURL: baseUrl,
|
|
@@ -22,10 +30,27 @@ export class ChromaDBProvider extends BaseVectorProvider {
|
|
|
22
30
|
});
|
|
23
31
|
}
|
|
24
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Get or create the ChromaDB collection.
|
|
35
|
+
*/
|
|
25
36
|
async initialize(): Promise<void> {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
try {
|
|
38
|
+
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
39
|
+
this.collectionId = data.id;
|
|
40
|
+
console.log(`[ChromaDBProvider] ✅ Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (axios.isAxiosError(err) && err.response?.status === 404) {
|
|
43
|
+
// Create the collection if it doesn't exist
|
|
44
|
+
console.log(`[ChromaDBProvider] ⏳ Collection "${this.indexName}" not found. Creating...`);
|
|
45
|
+
const { data } = await this.http.post('/api/v1/collections', {
|
|
46
|
+
name: this.indexName,
|
|
47
|
+
});
|
|
48
|
+
this.collectionId = data.id;
|
|
49
|
+
console.log(`[ChromaDBProvider] ✅ Created collection "${this.indexName}" (id: ${this.collectionId})`);
|
|
50
|
+
} else {
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
29
54
|
}
|
|
30
55
|
|
|
31
56
|
async upsert(doc: UpsertDocument, namespace?: string): Promise<void> {
|
|
@@ -34,7 +59,7 @@ export class ChromaDBProvider extends BaseVectorProvider {
|
|
|
34
59
|
|
|
35
60
|
async batchUpsert(docs: UpsertDocument[], namespace?: string): Promise<void> {
|
|
36
61
|
const payload = {
|
|
37
|
-
ids: docs.map(d => d.id),
|
|
62
|
+
ids: docs.map(d => String(d.id)),
|
|
38
63
|
embeddings: docs.map(d => d.vector),
|
|
39
64
|
documents: docs.map(d => d.content),
|
|
40
65
|
metadatas: docs.map(d => ({
|
|
@@ -53,7 +78,7 @@ export class ChromaDBProvider extends BaseVectorProvider {
|
|
|
53
78
|
where: namespace ? { namespace: { $eq: namespace } } : undefined,
|
|
54
79
|
};
|
|
55
80
|
const { data } = await this.http.post(`/api/v1/collections/${this.collectionId}/query`, payload);
|
|
56
|
-
|
|
81
|
+
|
|
57
82
|
const matches: VectorMatch[] = [];
|
|
58
83
|
if (data.ids && data.ids[0]) {
|
|
59
84
|
for (let i = 0; i < data.ids[0].length; i++) {
|
|
@@ -68,16 +93,16 @@ export class ChromaDBProvider extends BaseVectorProvider {
|
|
|
68
93
|
return matches;
|
|
69
94
|
}
|
|
70
95
|
|
|
71
|
-
async delete(id: string,
|
|
96
|
+
async delete(id: string, namespace?: string): Promise<void> {
|
|
72
97
|
await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
|
|
73
98
|
ids: [id],
|
|
74
|
-
where:
|
|
99
|
+
where: namespace ? { namespace: { $eq: namespace } } : undefined,
|
|
75
100
|
});
|
|
76
101
|
}
|
|
77
102
|
|
|
78
|
-
async deleteNamespace(
|
|
103
|
+
async deleteNamespace(namespace: string): Promise<void> {
|
|
79
104
|
await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
|
|
80
|
-
where: { namespace: { $eq:
|
|
105
|
+
where: { namespace: { $eq: namespace } },
|
|
81
106
|
});
|
|
82
107
|
}
|
|
83
108
|
|