@retrivora-ai/rag-engine 0.1.5 → 0.1.6

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 (40) hide show
  1. package/dist/{DocumentChunker-cfaMidtA.d.mts → DocumentChunker-BEyzadsv.d.mts} +2 -2
  2. package/dist/{DocumentChunker-cfaMidtA.d.ts → DocumentChunker-BEyzadsv.d.ts} +2 -2
  3. package/dist/{PineconeProvider-NJ675H7U.mjs → PineconeProvider-ZRAFNFEC.mjs} +1 -1
  4. package/dist/{PostgreSQLProvider-ISNMD3BE.mjs → PostgreSQLProvider-ZNXA67IM.mjs} +1 -1
  5. package/dist/{QdrantProvider-LJWOIGES.mjs → QdrantProvider-NYGHAA7C.mjs} +1 -1
  6. package/dist/{RagConfig-DG_0f8ka.d.mts → RagConfig-hBGXJmSx.d.mts} +3 -3
  7. package/dist/{RagConfig-DG_0f8ka.d.ts → RagConfig-hBGXJmSx.d.ts} +3 -3
  8. package/dist/{chunk-6FODXNUF.mjs → chunk-5K23H7JL.mjs} +27 -1
  9. package/dist/chunk-HSBXE2WV.mjs +1758 -0
  10. package/dist/{chunk-S5DRHETN.mjs → chunk-IUTAZ7QR.mjs} +31 -2
  11. package/dist/{chunk-AALIF3AL.mjs → chunk-ZM6TYIDH.mjs} +3 -3
  12. package/dist/handlers/index.d.mts +3 -44
  13. package/dist/handlers/index.d.ts +3 -44
  14. package/dist/handlers/index.js +1322 -57
  15. package/dist/handlers/index.mjs +1 -1
  16. package/dist/index-Bx182KKn.d.ts +64 -0
  17. package/dist/index-Ck2pt7-8.d.mts +64 -0
  18. package/dist/index.d.mts +4 -4
  19. package/dist/index.d.ts +4 -4
  20. package/dist/server.d.mts +65 -18
  21. package/dist/server.d.ts +65 -18
  22. package/dist/server.js +1322 -57
  23. package/dist/server.mjs +4 -4
  24. package/package.json +2 -1
  25. package/src/config/serverConfig.ts +3 -0
  26. package/src/core/BatchProcessor.ts +347 -0
  27. package/src/core/ConfigValidator.ts +560 -0
  28. package/src/core/Pipeline.ts +89 -39
  29. package/src/core/ProviderHealthCheck.ts +565 -0
  30. package/src/core/VectorPlugin.ts +49 -8
  31. package/src/handlers/index.ts +2 -2
  32. package/src/providers/vectordb/BaseVectorProvider.ts +1 -1
  33. package/src/providers/vectordb/MilvusProvider.ts +1 -1
  34. package/src/providers/vectordb/MongoDBProvider.ts +1 -1
  35. package/src/providers/vectordb/PineconeProvider.ts +4 -4
  36. package/src/providers/vectordb/PostgreSQLProvider.ts +35 -3
  37. package/src/providers/vectordb/QdrantProvider.ts +32 -2
  38. package/src/rag/DocumentChunker.ts +2 -2
  39. package/src/types/index.ts +3 -3
  40. package/dist/chunk-BP4U4TT5.mjs +0 -548
package/dist/server.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  QdrantProvider
3
- } from "./chunk-6FODXNUF.mjs";
3
+ } from "./chunk-5K23H7JL.mjs";
4
4
  import {
5
5
  ChromaDBProvider
6
6
  } from "./chunk-HUGLYKD6.mjs";
@@ -21,7 +21,7 @@ import {
21
21
  createIngestHandler,
22
22
  createUploadHandler,
23
23
  getRagConfig
24
- } from "./chunk-BP4U4TT5.mjs";
24
+ } from "./chunk-HSBXE2WV.mjs";
25
25
  import {
26
26
  AnthropicProvider,
27
27
  LLMFactory,
@@ -31,10 +31,10 @@ import {
31
31
  import "./chunk-UKDXCXW7.mjs";
32
32
  import {
33
33
  PineconeProvider
34
- } from "./chunk-AALIF3AL.mjs";
34
+ } from "./chunk-ZM6TYIDH.mjs";
35
35
  import {
36
36
  PostgreSQLProvider
37
- } from "./chunk-S5DRHETN.mjs";
37
+ } from "./chunk-IUTAZ7QR.mjs";
38
38
  import {
39
39
  MongoDBProvider
40
40
  } from "./chunk-QEYVWVT5.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "MIT",
@@ -98,6 +98,7 @@
98
98
  "@types/pg": "^8.20.0",
99
99
  "@types/react": "^19.2.14",
100
100
  "@types/react-dom": "^19.2.3",
101
+ "dotenv": "^17.4.2",
101
102
  "eslint": "^9",
102
103
  "eslint-config-next": "16.2.4",
103
104
  "tailwindcss": "^4",
@@ -73,6 +73,9 @@ export function getRagConfig(env: Record<string, string | undefined> = process.e
73
73
  vectorDbOptions.database = readString(env, 'MONGODB_DB') ?? '';
74
74
  vectorDbOptions.collection = readString(env, 'MONGODB_COLLECTION') ?? '';
75
75
  vectorDbOptions.indexName = readString(env, 'MONGODB_INDEX_NAME') ?? 'vector_index';
76
+ } else if (vectorProvider === 'qdrant') {
77
+ vectorDbOptions.baseUrl = readString(env, 'QDRANT_URL') ?? 'http://localhost:6333';
78
+ vectorDbOptions.apiKey = readString(env, 'QDRANT_API_KEY');
76
79
  }
77
80
 
78
81
  const llmApiKeyByProvider: Record<string, string | undefined> = {
@@ -0,0 +1,347 @@
1
+ /**
2
+ * BatchProcessor.ts — Handles batch operations with retry logic.
3
+ *
4
+ * Provides exponential backoff, partial failure tracking, and
5
+ * configurable batch sizing for efficient bulk operations.
6
+ */
7
+
8
+ export interface BatchOptions {
9
+ /** Maximum number of items per batch */
10
+ batchSize?: number;
11
+ /** Maximum number of retries for transient failures */
12
+ maxRetries?: number;
13
+ /** Initial delay before retry in milliseconds */
14
+ initialDelayMs?: number;
15
+ /** Maximum delay between retries in milliseconds */
16
+ maxDelayMs?: number;
17
+ /** Multiplier for exponential backoff */
18
+ backoffMultiplier?: number;
19
+ /** Whether to throw on any partial failure */
20
+ throwOnPartialFailure?: boolean;
21
+ }
22
+
23
+ export interface BatchResult<T> {
24
+ results: T[];
25
+ errors: Array<{ index: number; error: Error; itemCount?: number }>;
26
+ totalProcessed: number;
27
+ totalFailed: number;
28
+ }
29
+
30
+ /**
31
+ * Determines if an error is transient (should retry)
32
+ */
33
+ function isTransientError(error: unknown): boolean {
34
+ if (!(error instanceof Error)) return false;
35
+
36
+ const message = error.message.toLowerCase();
37
+
38
+ // Network errors
39
+ if (
40
+ message.includes('econnrefused') ||
41
+ message.includes('econnreset') ||
42
+ message.includes('timeout') ||
43
+ message.includes('network') ||
44
+ message.includes('socket')
45
+ ) {
46
+ return true;
47
+ }
48
+
49
+ // HTTP errors (rate limit, service unavailable)
50
+ if (
51
+ message.includes('429') ||
52
+ message.includes('503') ||
53
+ message.includes('502') ||
54
+ message.includes('rate limit') ||
55
+ message.includes('too many requests')
56
+ ) {
57
+ return true;
58
+ }
59
+
60
+ return false;
61
+ }
62
+
63
+ /**
64
+ * Calculates delay using exponential backoff with jitter
65
+ */
66
+ function calculateBackoffDelay(
67
+ attempt: number,
68
+ initialDelayMs: number,
69
+ maxDelayMs: number,
70
+ multiplier: number
71
+ ): number {
72
+ const exponentialDelay = Math.min(
73
+ initialDelayMs * Math.pow(multiplier, attempt),
74
+ maxDelayMs
75
+ );
76
+ // Add jitter: ±10% of the delay
77
+ const jitter = exponentialDelay * 0.1 * (Math.random() * 2 - 1);
78
+ return Math.max(0, exponentialDelay + jitter);
79
+ }
80
+
81
+ /**
82
+ * Sleeps for the given duration
83
+ */
84
+ function sleep(ms: number): Promise<void> {
85
+ return new Promise((resolve) => setTimeout(resolve, ms));
86
+ }
87
+
88
+ export class BatchProcessor {
89
+ /**
90
+ * Processes an array of items in configurable batches with retry logic.
91
+ *
92
+ * @param items - Items to process
93
+ * @param processor - Async function that processes a batch of items
94
+ * @param options - Configuration for batch size, retries, etc.
95
+ * @returns Object with results, errors, and statistics
96
+ *
97
+ * @example
98
+ * const docs = [...];
99
+ * const result = await BatchProcessor.processBatch(
100
+ * docs,
101
+ * (batch) => vectorDB.batchUpsert(batch),
102
+ * { batchSize: 100, maxRetries: 3 }
103
+ * );
104
+ */
105
+ static async processBatch<T, R>(
106
+ items: T[],
107
+ processor: (batch: T[]) => Promise<R>,
108
+ options?: BatchOptions
109
+ ): Promise<BatchResult<R>> {
110
+ const {
111
+ batchSize = 100,
112
+ maxRetries = 3,
113
+ initialDelayMs = 100,
114
+ maxDelayMs = 10000,
115
+ backoffMultiplier = 2,
116
+ throwOnPartialFailure = false,
117
+ } = options ?? {};
118
+
119
+ const results: R[] = [];
120
+ const errors: Array<{ index: number; error: Error; itemCount?: number }> = [];
121
+
122
+ // Split items into batches
123
+ const batches: T[][] = [];
124
+ for (let i = 0; i < items.length; i += batchSize) {
125
+ batches.push(items.slice(i, i + batchSize));
126
+ }
127
+
128
+ if (batches.length === 0) {
129
+ return { results: [], errors: [], totalProcessed: 0, totalFailed: 0 };
130
+ }
131
+
132
+ // Process each batch with retry logic
133
+ for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) {
134
+ const batch = batches[batchIndex];
135
+ let success = false;
136
+ let lastError: Error | undefined;
137
+
138
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
139
+ try {
140
+ const result = await processor(batch);
141
+ results.push(result);
142
+ success = true;
143
+ break;
144
+ } catch (err) {
145
+ lastError = err instanceof Error ? err : new Error(String(err));
146
+
147
+ // If not transient or last attempt, fail immediately
148
+ if (!isTransientError(err) || attempt === maxRetries) {
149
+ break;
150
+ }
151
+
152
+ // Wait before retry with exponential backoff
153
+ const delay = calculateBackoffDelay(
154
+ attempt,
155
+ initialDelayMs,
156
+ maxDelayMs,
157
+ backoffMultiplier
158
+ );
159
+ await sleep(delay);
160
+ }
161
+ }
162
+
163
+ if (!success && lastError) {
164
+ errors.push({
165
+ index: batchIndex,
166
+ error: lastError,
167
+ itemCount: batch.length,
168
+ });
169
+ }
170
+ }
171
+
172
+ const totalProcessed = items.length - (errors.length > 0 ? errors.reduce((sum, e) => sum + (e.itemCount || 0), 0) : 0);
173
+ const totalFailed = errors.reduce((sum, e) => sum + (e.itemCount || 0), 0);
174
+
175
+ if (throwOnPartialFailure && errors.length > 0) {
176
+ const errorMessages = errors
177
+ .map((e) => `Batch ${e.index} (${e.itemCount} items): ${e.error.message}`)
178
+ .join('\n');
179
+ throw new Error(
180
+ `[BatchProcessor] Batch processing failed:\n${errorMessages}`
181
+ );
182
+ }
183
+
184
+ return { results, errors, totalProcessed, totalFailed };
185
+ }
186
+
187
+ /**
188
+ * Processes items sequentially (one at a time) with retry logic.
189
+ * Useful for operations that don't support batching or when granular
190
+ * error tracking is needed.
191
+ */
192
+ static async processSequential<T, R>(
193
+ items: T[],
194
+ processor: (item: T) => Promise<R>,
195
+ options?: BatchOptions
196
+ ): Promise<BatchResult<R>> {
197
+ const {
198
+ maxRetries = 3,
199
+ initialDelayMs = 100,
200
+ maxDelayMs = 10000,
201
+ backoffMultiplier = 2,
202
+ throwOnPartialFailure = false,
203
+ } = options ?? {};
204
+
205
+ const results: R[] = [];
206
+ const errors: Array<{ index: number; error: Error; itemCount?: number }> = [];
207
+
208
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
209
+ const item = items[itemIndex];
210
+ let success = false;
211
+ let lastError: Error | undefined;
212
+
213
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
214
+ try {
215
+ const result = await processor(item);
216
+ results.push(result);
217
+ success = true;
218
+ break;
219
+ } catch (err) {
220
+ lastError = err instanceof Error ? err : new Error(String(err));
221
+
222
+ if (!isTransientError(err) || attempt === maxRetries) {
223
+ break;
224
+ }
225
+
226
+ const delay = calculateBackoffDelay(
227
+ attempt,
228
+ initialDelayMs,
229
+ maxDelayMs,
230
+ backoffMultiplier
231
+ );
232
+ await sleep(delay);
233
+ }
234
+ }
235
+
236
+ if (!success && lastError) {
237
+ errors.push({ index: itemIndex, error: lastError, itemCount: 1 });
238
+ }
239
+ }
240
+
241
+ const totalProcessed = items.length - errors.length;
242
+ const totalFailed = errors.length;
243
+
244
+ if (throwOnPartialFailure && errors.length > 0) {
245
+ const errorMessages = errors
246
+ .map((e) => `Item ${e.index}: ${e.error.message}`)
247
+ .join('\n');
248
+ throw new Error(
249
+ `[BatchProcessor] Sequential processing failed:\n${errorMessages}`
250
+ );
251
+ }
252
+
253
+ return { results, errors, totalProcessed, totalFailed };
254
+ }
255
+
256
+ /**
257
+ * Maps over items with retry logic, returning results in order.
258
+ * Like Array.map() but with async processing and automatic retries.
259
+ */
260
+ static async mapWithRetry<T, R>(
261
+ items: T[],
262
+ mapper: (item: T) => Promise<R>,
263
+ options?: BatchOptions
264
+ ): Promise<R[]> {
265
+ const result = await this.processSequential(items, mapper, options);
266
+
267
+ if (result.errors.length > 0) {
268
+ console.warn(
269
+ `[BatchProcessor] mapWithRetry: ${result.errors.length} items failed`
270
+ );
271
+ }
272
+
273
+ // Return results in original order (fill gaps with undefined or error value)
274
+ const orderedResults: (R | undefined)[] = new Array(items.length);
275
+ let resultIndex = 0;
276
+ let errorIndex = 0;
277
+
278
+ for (let i = 0; i < items.length; i++) {
279
+ if (errorIndex < result.errors.length && result.errors[errorIndex].index === i) {
280
+ orderedResults[i] = undefined;
281
+ errorIndex++;
282
+ } else {
283
+ orderedResults[i] = result.results[resultIndex];
284
+ resultIndex++;
285
+ }
286
+ }
287
+
288
+ return orderedResults.filter((r) => r !== undefined) as R[];
289
+ }
290
+
291
+ /**
292
+ * Parallel processor with concurrency limit.
293
+ * Processes up to `concurrency` items at the same time.
294
+ */
295
+ static async processConcurrent<T, R>(
296
+ items: T[],
297
+ processor: (item: T) => Promise<R>,
298
+ concurrency: number = 5,
299
+ options?: BatchOptions
300
+ ): Promise<BatchResult<R>> {
301
+ const { throwOnPartialFailure = false } = options ?? {};
302
+ const results: R[] = [];
303
+ const errors: Array<{ index: number; error: Error; itemCount?: number }> = [];
304
+
305
+ // Process in chunks of `concurrency` size
306
+ for (let i = 0; i < items.length; i += concurrency) {
307
+ const chunk = items.slice(i, i + concurrency).map((item, idx) => ({
308
+ item,
309
+ originalIndex: i + idx,
310
+ }));
311
+
312
+ const chunkPromises = chunk.map(async ({ item, originalIndex }) => {
313
+ try {
314
+ const result = await processor(item);
315
+ return { success: true, result, index: originalIndex };
316
+ } catch (err) {
317
+ const error = err instanceof Error ? err : new Error(String(err));
318
+ return { success: false, error, index: originalIndex };
319
+ }
320
+ });
321
+
322
+ const chunkResults = await Promise.all(chunkPromises);
323
+
324
+ for (const { success, result, error, index } of chunkResults) {
325
+ if (success) {
326
+ results.push(result as R);
327
+ } else {
328
+ errors.push({ index, error: error as Error, itemCount: 1 });
329
+ }
330
+ }
331
+ }
332
+
333
+ const totalProcessed = items.length - errors.length;
334
+ const totalFailed = errors.length;
335
+
336
+ if (throwOnPartialFailure && errors.length > 0) {
337
+ const errorMessages = errors
338
+ .map((e) => `Item ${e.index}: ${e.error.message}`)
339
+ .join('\n');
340
+ throw new Error(
341
+ `[BatchProcessor] Concurrent processing failed:\n${errorMessages}`
342
+ );
343
+ }
344
+
345
+ return { results, errors, totalProcessed, totalFailed };
346
+ }
347
+ }