@retrivora-ai/rag-engine 0.1.7 → 0.1.9
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-T7TK3ONZ.mjs} +2 -2
- package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-Y5FV5EAE.mjs} +2 -2
- package/dist/{MongoDBProvider-WWVJG3WT.mjs → MongoDBProvider-QHMGD2LZ.mjs} +2 -2
- package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-A47MRRYJ.mjs} +2 -2
- package/dist/{PostgreSQLProvider-ZNXA67IM.mjs → PostgreSQLProvider-PJ5ER5Z4.mjs} +1 -1
- package/dist/{QdrantProvider-VAED5VA7.mjs → QdrantProvider-OLPJK7CY.mjs} +2 -2
- 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-ANEJ3BHR.mjs} +2 -2
- package/dist/UniversalVectorProvider-QJIV2AJJ.mjs +9 -0
- package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-WIK2QN23.mjs} +2 -2
- package/dist/{chunk-7YQWGERZ.mjs → chunk-2VR5ZMXV.mjs} +740 -193
- package/dist/{chunk-QEYVWVT5.mjs → chunk-5HXNKSCR.mjs} +1 -1
- package/dist/{chunk-ZM6TYIDH.mjs → chunk-BMHJTWSU.mjs} +4 -2
- package/dist/{chunk-UKDXCXW7.mjs → chunk-EDLTMSNY.mjs} +1 -1
- package/dist/{chunk-I4E63NIC.mjs → chunk-FWCSY2DS.mjs} +14 -1
- package/dist/{chunk-VPNRDXIA.mjs → chunk-HOMXEE3M.mjs} +17 -11
- package/dist/{chunk-V75V7BT2.mjs → chunk-RUKZC3ON.mjs} +3 -3
- package/dist/{chunk-7NXI6ZWX.mjs → chunk-VEJNRS4B.mjs} +9 -6
- package/dist/{chunk-HUGLYKD6.mjs → chunk-VKE5ZW7Y.mjs} +28 -10
- package/dist/chunk-VV2ML6TM.mjs +156 -0
- package/dist/{chunk-CWQQHAF6.mjs → chunk-W2PQR3UK.mjs} +4 -6
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +877 -625
- package/dist/handlers/index.mjs +3 -4
- 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/index.js +67 -58
- package/dist/index.mjs +74 -47
- package/dist/server.d.mts +601 -17
- package/dist/server.d.ts +601 -17
- package/dist/server.js +1426 -708
- package/dist/server.mjs +429 -18
- package/package.json +11 -2
- package/src/app/constants.tsx +220 -0
- package/src/app/page.tsx +193 -363
- package/src/app/types.ts +30 -0
- package/src/components/ChatWindow.tsx +3 -11
- package/src/config/ConfigBuilder.ts +373 -0
- package/src/config/EmbeddingStrategy.ts +147 -0
- package/src/config/serverConfig.ts +51 -18
- package/src/core/ConfigValidator.ts +67 -50
- package/src/core/Pipeline.ts +28 -26
- package/src/core/PluginManager.ts +277 -0
- package/src/core/ProviderHealthCheck.ts +75 -139
- 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/MultiTablePostgresProvider.ts +164 -0
- package/src/providers/vectordb/PineconeProvider.ts +17 -2
- package/src/providers/vectordb/QdrantProvider.ts +3 -6
- 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 +29 -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,22 +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
220
|
const apiKey = opts.apiKey as string | undefined;
|
|
239
221
|
const response = await fetch(`${baseUrl}/`, {
|
|
240
222
|
headers: apiKey ? { 'api-key': apiKey } : {},
|
|
241
223
|
});
|
|
242
|
-
|
|
243
|
-
if (!response.ok) {
|
|
244
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
245
|
-
}
|
|
246
|
-
|
|
224
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
247
225
|
const health = await response.json();
|
|
248
|
-
|
|
249
226
|
return {
|
|
250
227
|
healthy: true,
|
|
251
228
|
provider: 'qdrant',
|
|
@@ -262,22 +239,24 @@ export class ProviderHealthCheck {
|
|
|
262
239
|
}
|
|
263
240
|
}
|
|
264
241
|
|
|
242
|
+
/**
|
|
243
|
+
* ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
|
|
244
|
+
*/
|
|
265
245
|
private static async checkChromaDB(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
266
246
|
const opts = config.options as Record<string, unknown>;
|
|
267
|
-
const host = (opts.host as string) || 'localhost';
|
|
268
|
-
const port = (opts.port as number) || 8000;
|
|
269
247
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
275
|
-
}
|
|
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');
|
|
276
252
|
|
|
253
|
+
try {
|
|
254
|
+
const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
|
|
255
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
277
256
|
return {
|
|
278
257
|
healthy: true,
|
|
279
258
|
provider: 'chromadb',
|
|
280
|
-
capabilities: { endpoint:
|
|
259
|
+
capabilities: { endpoint: baseUrl },
|
|
281
260
|
timestamp,
|
|
282
261
|
};
|
|
283
262
|
} catch (error) {
|
|
@@ -290,47 +269,49 @@ export class ProviderHealthCheck {
|
|
|
290
269
|
}
|
|
291
270
|
}
|
|
292
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
|
+
*/
|
|
293
276
|
private static async checkRedis(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
294
277
|
const opts = config.options as Record<string, string>;
|
|
295
|
-
const url =
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
timestamp,
|
|
307
|
-
};
|
|
308
|
-
} catch (error) {
|
|
309
|
-
// If fetch fails, try to gracefully handle (redis may not have HTTP interface)
|
|
310
|
-
return {
|
|
311
|
-
healthy: false,
|
|
312
|
-
provider: 'redis',
|
|
313
|
-
error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
|
|
314
|
-
timestamp,
|
|
315
|
-
};
|
|
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
|
+
}
|
|
316
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
|
+
};
|
|
317
300
|
}
|
|
318
301
|
|
|
302
|
+
/**
|
|
303
|
+
* Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
|
|
304
|
+
*/
|
|
319
305
|
private static async checkWeaviate(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
320
306
|
const opts = config.options as Record<string, string>;
|
|
321
|
-
const
|
|
322
|
-
|
|
307
|
+
const baseUrl = ((opts.baseUrl || opts.url) || 'http://localhost:8080').replace(/\/$/, '');
|
|
323
308
|
try {
|
|
324
|
-
const response = await fetch(`${
|
|
325
|
-
|
|
326
|
-
if (!response.ok) {
|
|
327
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
328
|
-
}
|
|
329
|
-
|
|
309
|
+
const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
|
|
310
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
330
311
|
return {
|
|
331
312
|
healthy: true,
|
|
332
313
|
provider: 'weaviate',
|
|
333
|
-
capabilities: { endpoint:
|
|
314
|
+
capabilities: { endpoint: baseUrl },
|
|
334
315
|
timestamp,
|
|
335
316
|
};
|
|
336
317
|
} catch (error) {
|
|
@@ -346,21 +327,13 @@ export class ProviderHealthCheck {
|
|
|
346
327
|
private static async checkRestAPI(config: VectorDBConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
347
328
|
const opts = config.options as Record<string, string>;
|
|
348
329
|
const baseUrl = (opts.baseUrl || '').replace(/\/$/, '');
|
|
349
|
-
|
|
350
330
|
if (!baseUrl) {
|
|
351
|
-
return {
|
|
352
|
-
healthy: false,
|
|
353
|
-
provider: 'rest',
|
|
354
|
-
error: 'baseUrl is required',
|
|
355
|
-
timestamp,
|
|
356
|
-
};
|
|
331
|
+
return { healthy: false, provider: 'rest', error: 'baseUrl is required', timestamp };
|
|
357
332
|
}
|
|
358
|
-
|
|
359
333
|
try {
|
|
360
334
|
const response = await fetch(`${baseUrl}/health`, {
|
|
361
335
|
headers: opts.headers ? JSON.parse(opts.headers) : {},
|
|
362
336
|
});
|
|
363
|
-
|
|
364
337
|
return {
|
|
365
338
|
healthy: response.ok,
|
|
366
339
|
provider: 'rest',
|
|
@@ -382,7 +355,6 @@ export class ProviderHealthCheck {
|
|
|
382
355
|
*/
|
|
383
356
|
static async checkLLMProvider(config: LLMConfig): Promise<HealthCheckResult> {
|
|
384
357
|
const timestamp = Date.now();
|
|
385
|
-
|
|
386
358
|
try {
|
|
387
359
|
switch (config.provider) {
|
|
388
360
|
case 'openai':
|
|
@@ -416,20 +388,12 @@ export class ProviderHealthCheck {
|
|
|
416
388
|
try {
|
|
417
389
|
const OpenAI = await import('openai');
|
|
418
390
|
const client = new OpenAI.default({ apiKey: config.apiKey });
|
|
419
|
-
|
|
420
|
-
// Test models endpoint
|
|
421
391
|
const models = await client.models.list();
|
|
422
|
-
|
|
423
392
|
const hasModel = models.data.some((m) => m.id === config.model);
|
|
424
|
-
|
|
425
393
|
return {
|
|
426
394
|
healthy: true,
|
|
427
395
|
provider: 'openai',
|
|
428
|
-
capabilities: {
|
|
429
|
-
model: config.model,
|
|
430
|
-
available: hasModel,
|
|
431
|
-
totalModels: models.data.length,
|
|
432
|
-
},
|
|
396
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
|
|
433
397
|
timestamp,
|
|
434
398
|
};
|
|
435
399
|
} catch (error) {
|
|
@@ -446,20 +410,12 @@ export class ProviderHealthCheck {
|
|
|
446
410
|
try {
|
|
447
411
|
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
448
412
|
const client = new Anthropic({ apiKey: config.apiKey });
|
|
449
|
-
|
|
450
|
-
// Try a minimal API call to verify credentials
|
|
451
413
|
await client.messages.create({
|
|
452
414
|
model: config.model,
|
|
453
415
|
max_tokens: 10,
|
|
454
416
|
messages: [{ role: 'user', content: 'ping' }],
|
|
455
417
|
});
|
|
456
|
-
|
|
457
|
-
return {
|
|
458
|
-
healthy: true,
|
|
459
|
-
provider: 'anthropic',
|
|
460
|
-
capabilities: { model: config.model },
|
|
461
|
-
timestamp,
|
|
462
|
-
};
|
|
418
|
+
return { healthy: true, provider: 'anthropic', capabilities: { model: config.model }, timestamp };
|
|
463
419
|
} catch (error) {
|
|
464
420
|
return {
|
|
465
421
|
healthy: false,
|
|
@@ -472,26 +428,16 @@ export class ProviderHealthCheck {
|
|
|
472
428
|
|
|
473
429
|
private static async checkOllama(config: LLMConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
474
430
|
const baseUrl = (config.baseUrl || 'http://localhost:11434').replace(/\/$/, '');
|
|
475
|
-
|
|
476
431
|
try {
|
|
477
432
|
const response = await fetch(`${baseUrl}/api/tags`);
|
|
478
|
-
|
|
479
|
-
if (!response.ok) {
|
|
480
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
481
|
-
}
|
|
482
|
-
|
|
433
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
483
434
|
const data = await response.json() as Record<string, unknown>;
|
|
484
435
|
const models = (data.models as Array<{ name: string }>) || [];
|
|
485
436
|
const hasModel = models.some((m) => m.name === config.model);
|
|
486
|
-
|
|
487
437
|
return {
|
|
488
438
|
healthy: true,
|
|
489
439
|
provider: 'ollama',
|
|
490
|
-
capabilities: {
|
|
491
|
-
model: config.model,
|
|
492
|
-
available: hasModel,
|
|
493
|
-
totalModels: models.length,
|
|
494
|
-
},
|
|
440
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.length },
|
|
495
441
|
timestamp,
|
|
496
442
|
};
|
|
497
443
|
} catch (error) {
|
|
@@ -507,22 +453,12 @@ export class ProviderHealthCheck {
|
|
|
507
453
|
private static async checkLLMRestAPI(config: LLMConfig, timestamp: number): Promise<HealthCheckResult> {
|
|
508
454
|
const baseUrlRaw = config.baseUrl || (config.options as Record<string, unknown>)?.baseUrl;
|
|
509
455
|
const baseUrl = (typeof baseUrlRaw === 'string' ? baseUrlRaw : '').replace(/\/$/, '');
|
|
510
|
-
|
|
511
456
|
if (!baseUrl) {
|
|
512
|
-
return {
|
|
513
|
-
healthy: false,
|
|
514
|
-
provider: config.provider,
|
|
515
|
-
error: 'baseUrl is required',
|
|
516
|
-
timestamp,
|
|
517
|
-
};
|
|
457
|
+
return { healthy: false, provider: config.provider, error: 'baseUrl is required', timestamp };
|
|
518
458
|
}
|
|
519
|
-
|
|
520
459
|
try {
|
|
521
460
|
const headers = (config.options as Record<string, unknown>)?.headers as Record<string, string> | undefined;
|
|
522
|
-
const response = await fetch(`${baseUrl}/health`, {
|
|
523
|
-
headers: headers || undefined,
|
|
524
|
-
});
|
|
525
|
-
|
|
461
|
+
const response = await fetch(`${baseUrl}/health`, { headers: headers || undefined });
|
|
526
462
|
return {
|
|
527
463
|
healthy: response.ok,
|
|
528
464
|
provider: config.provider,
|
|
@@ -540,7 +476,7 @@ export class ProviderHealthCheck {
|
|
|
540
476
|
}
|
|
541
477
|
|
|
542
478
|
/**
|
|
543
|
-
* Runs comprehensive health checks on all configured providers.
|
|
479
|
+
* Runs comprehensive health checks on all configured providers in parallel.
|
|
544
480
|
*/
|
|
545
481
|
static async checkAll(
|
|
546
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
|
|