@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.
Files changed (63) hide show
  1. package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-T7TK3ONZ.mjs} +2 -2
  2. package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-Y5FV5EAE.mjs} +2 -2
  3. package/dist/{MongoDBProvider-WWVJG3WT.mjs → MongoDBProvider-QHMGD2LZ.mjs} +2 -2
  4. package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-A47MRRYJ.mjs} +2 -2
  5. package/dist/{PostgreSQLProvider-ZNXA67IM.mjs → PostgreSQLProvider-PJ5ER5Z4.mjs} +1 -1
  6. package/dist/{QdrantProvider-VAED5VA7.mjs → QdrantProvider-OLPJK7CY.mjs} +2 -2
  7. package/dist/{RagConfig-hBGXJmSx.d.mts → RagConfig-D_rSf8ep.d.mts} +1 -1
  8. package/dist/{RagConfig-hBGXJmSx.d.ts → RagConfig-D_rSf8ep.d.ts} +1 -1
  9. package/dist/{RedisProvider-ASONNYBI.mjs → RedisProvider-ANEJ3BHR.mjs} +2 -2
  10. package/dist/UniversalVectorProvider-QJIV2AJJ.mjs +9 -0
  11. package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-WIK2QN23.mjs} +2 -2
  12. package/dist/{chunk-7YQWGERZ.mjs → chunk-2VR5ZMXV.mjs} +740 -193
  13. package/dist/{chunk-QEYVWVT5.mjs → chunk-5HXNKSCR.mjs} +1 -1
  14. package/dist/{chunk-ZM6TYIDH.mjs → chunk-BMHJTWSU.mjs} +4 -2
  15. package/dist/{chunk-UKDXCXW7.mjs → chunk-EDLTMSNY.mjs} +1 -1
  16. package/dist/{chunk-I4E63NIC.mjs → chunk-FWCSY2DS.mjs} +14 -1
  17. package/dist/{chunk-VPNRDXIA.mjs → chunk-HOMXEE3M.mjs} +17 -11
  18. package/dist/{chunk-V75V7BT2.mjs → chunk-RUKZC3ON.mjs} +3 -3
  19. package/dist/{chunk-7NXI6ZWX.mjs → chunk-VEJNRS4B.mjs} +9 -6
  20. package/dist/{chunk-HUGLYKD6.mjs → chunk-VKE5ZW7Y.mjs} +28 -10
  21. package/dist/chunk-VV2ML6TM.mjs +156 -0
  22. package/dist/{chunk-CWQQHAF6.mjs → chunk-W2PQR3UK.mjs} +4 -6
  23. package/dist/handlers/index.d.mts +2 -2
  24. package/dist/handlers/index.d.ts +2 -2
  25. package/dist/handlers/index.js +877 -625
  26. package/dist/handlers/index.mjs +3 -4
  27. package/dist/index-BJ8CUArE.d.mts +114 -0
  28. package/dist/index-DtNprGGj.d.ts +114 -0
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +67 -58
  32. package/dist/index.mjs +74 -47
  33. package/dist/server.d.mts +601 -17
  34. package/dist/server.d.ts +601 -17
  35. package/dist/server.js +1426 -708
  36. package/dist/server.mjs +429 -18
  37. package/package.json +11 -2
  38. package/src/app/constants.tsx +220 -0
  39. package/src/app/page.tsx +193 -363
  40. package/src/app/types.ts +30 -0
  41. package/src/components/ChatWindow.tsx +3 -11
  42. package/src/config/ConfigBuilder.ts +373 -0
  43. package/src/config/EmbeddingStrategy.ts +147 -0
  44. package/src/config/serverConfig.ts +51 -18
  45. package/src/core/ConfigValidator.ts +67 -50
  46. package/src/core/Pipeline.ts +28 -26
  47. package/src/core/PluginManager.ts +277 -0
  48. package/src/core/ProviderHealthCheck.ts +75 -139
  49. package/src/core/ProviderRegistry.ts +38 -15
  50. package/src/providers/vectordb/ChromaDBProvider.ts +37 -12
  51. package/src/providers/vectordb/MilvusProvider.ts +25 -10
  52. package/src/providers/vectordb/MultiTablePostgresProvider.ts +164 -0
  53. package/src/providers/vectordb/PineconeProvider.ts +17 -2
  54. package/src/providers/vectordb/QdrantProvider.ts +3 -6
  55. package/src/providers/vectordb/RedisProvider.ts +34 -11
  56. package/src/providers/vectordb/UniversalVectorProvider.ts +220 -0
  57. package/src/providers/vectordb/WeaviateProvider.ts +17 -10
  58. package/src/server.ts +29 -10
  59. package/dist/LLMFactory-JFOY2V4X.mjs +0 -8
  60. package/dist/chunk-JI6VD5TJ.mjs +0 -387
  61. package/dist/index-Bx182KKn.d.ts +0 -64
  62. package/dist/index-Ck2pt7-8.d.mts +0 -64
  63. 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
- // First validate configuration
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' }, // dummy
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
- const host = (opts.host as string) || 'localhost';
200
- const port = (opts.port as number) || 19530;
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: `${host}:${port}` },
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
- try {
271
- const response = await fetch(`http://${host}:${port}/api/v1/heartbeat`);
272
-
273
- if (!response.ok) {
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: `${host}:${port}` },
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 = opts.url || `redis://${opts.host}:${opts.port}`;
296
-
297
- try {
298
- // Try to connect via simple TCP check using fetch
299
- // Note: Full Redis connection would require redis package as optional dependency
300
- await fetch(url);
301
-
302
- return {
303
- healthy: true,
304
- provider: 'redis',
305
- capabilities: { endpoint: url },
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 url = (opts.url || 'http://localhost:8080').replace(/\/$/, '');
322
-
307
+ const baseUrl = ((opts.baseUrl || opts.url) || 'http://localhost:8080').replace(/\/$/, '');
323
308
  try {
324
- const response = await fetch(`${url}/.well-known/ready`);
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: url },
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
- // Check if we have a registered provider (dynamic loading)
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
- // Fallback to internal switch for built-in providers
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
- case 'mongodb':
49
+ }
50
+ case 'mongodb': {
43
51
  const { MongoDBProvider } = await import('../providers/vectordb/MongoDBProvider');
44
52
  return new MongoDBProvider(config);
45
- case 'milvus':
53
+ }
54
+ case 'milvus': {
46
55
  const { MilvusProvider } = await import('../providers/vectordb/MilvusProvider');
47
56
  return new MilvusProvider(config);
48
- case 'qdrant':
57
+ }
58
+ case 'qdrant': {
49
59
  const { QdrantProvider } = await import('../providers/vectordb/QdrantProvider');
50
60
  return new QdrantProvider(config);
51
- case 'chromadb':
61
+ }
62
+ case 'chromadb': {
52
63
  const { ChromaDBProvider } = await import('../providers/vectordb/ChromaDBProvider');
53
64
  return new ChromaDBProvider(config);
54
- case 'redis':
65
+ }
66
+ case 'redis': {
55
67
  const { RedisProvider } = await import('../providers/vectordb/RedisProvider');
56
68
  return new RedisProvider(config);
57
- case 'weaviate':
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(`[ProviderRegistry] Unsupported vector provider: ${provider}`);
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 for ChromaDB using its REST API.
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
- const baseUrl = opts.baseUrl as string;
17
- if (!baseUrl) throw new Error('[ChromaDBProvider] baseUrl is required');
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
- // Get or create collection
27
- const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
28
- this.collectionId = data.id;
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, _namespace?: string): Promise<void> {
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: _namespace ? { namespace: { $eq: _namespace } } : undefined,
99
+ where: namespace ? { namespace: { $eq: namespace } } : undefined,
75
100
  });
76
101
  }
77
102
 
78
- async deleteNamespace(_namespace: string): Promise<void> {
103
+ async deleteNamespace(namespace: string): Promise<void> {
79
104
  await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
80
- where: { namespace: { $eq: _namespace } },
105
+ where: { namespace: { $eq: namespace } },
81
106
  });
82
107
  }
83
108