@devilsdev/rag-pipeline-utils 2.1.11 → 2.2.0

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 (110) hide show
  1. package/.ragrc.schema.json +218 -0
  2. package/README.md +651 -393
  3. package/bin/cli.js +8 -14
  4. package/dist/index.d.ts +237 -0
  5. package/dist/index.mjs +22 -7
  6. package/package.json +17 -13
  7. package/src/ai/adaptive-retrieval.js +191 -0
  8. package/src/ai/federated-learning.js +214 -0
  9. package/src/ai/federation/federated-learning-coordinator.js +345 -0
  10. package/src/ai/federation.js +76 -0
  11. package/src/ai/index-fixed.js +509 -0
  12. package/src/ai/index.js +33 -0
  13. package/src/ai/model-trainer.js +217 -0
  14. package/src/ai/model-training.js +205 -0
  15. package/src/ai/module-template.js +37 -0
  16. package/src/ai/multimodal/multi-modal-processor.js +345 -0
  17. package/src/ai/multimodal-processing.js +268 -0
  18. package/src/ai/multimodal.js +71 -0
  19. package/src/ai/orchestrator.js +70 -0
  20. package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
  21. package/src/ai/retrieval-engine.js +69 -0
  22. package/src/ai/training/model-training-orchestrator.js +228 -0
  23. package/src/ci/workflow-analyzer.js +71 -0
  24. package/src/cli/commands/ai-ml.js +967 -0
  25. package/src/cli/commands/docs.js +228 -0
  26. package/src/cli/commands/dx.js +538 -0
  27. package/src/cli/commands/plugin-hub.js +875 -0
  28. package/src/cli/doctor-command.js +639 -0
  29. package/src/cli/enhanced-cli-commands.js +945 -0
  30. package/src/cli/interactive-wizard.js +997 -0
  31. package/src/cli/plugin-marketplace-commands.js +869 -0
  32. package/src/cli.js +17 -0
  33. package/src/config/enhanced-ragrc-schema.js +632 -0
  34. package/src/config/load-config.js +54 -0
  35. package/src/config/load-plugin-config.js +69 -0
  36. package/src/config/normalize-config.js +105 -0
  37. package/src/config/schema-validator.js +315 -0
  38. package/src/config/validate-plugin-schema.js +35 -0
  39. package/src/config/validate-schema.js +113 -0
  40. package/src/contracts/plugin-contracts.js +33 -0
  41. package/src/core/create-pipeline.js +99 -0
  42. package/src/core/dependency-injection.js +242 -0
  43. package/src/core/observability/event-logger.js +241 -0
  44. package/src/core/observability/instrumented-pipeline.js +609 -0
  45. package/src/core/observability/metrics.js +497 -0
  46. package/src/core/observability/tracing.js +781 -0
  47. package/src/core/performance/benchmark.js +516 -0
  48. package/src/core/performance/parallel-processor.js +240 -0
  49. package/src/core/performance/streaming-safeguards.js +611 -0
  50. package/src/core/pipeline-factory.js +60 -0
  51. package/src/core/plugin-contracts.js +89 -0
  52. package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
  53. package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
  54. package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
  55. package/src/core/plugin-marketplace/version-resolver.js +61 -0
  56. package/src/core/plugin-registry.js +265 -0
  57. package/src/dag/dag-engine.js +954 -0
  58. package/src/dag/dag-node.js +76 -0
  59. package/src/dag/enhanced-dag-engine.js +822 -0
  60. package/src/dx/index.js +40 -0
  61. package/src/dx/integration-templates.js +665 -0
  62. package/src/dx/performance-profiler.js +968 -0
  63. package/src/dx/realtime-debugger.js +755 -0
  64. package/src/dx/visual-pipeline-builder.js +578 -0
  65. package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
  66. package/src/ecosystem/plugin-certification.js +580 -0
  67. package/src/ecosystem/plugin-hub.js +821 -0
  68. package/src/enterprise/audit-logging.js +967 -0
  69. package/src/enterprise/data-governance.js +408 -0
  70. package/src/enterprise/multi-tenancy.js +496 -0
  71. package/src/enterprise/sso-integration.js +903 -0
  72. package/src/evaluate/evaluator.js +52 -0
  73. package/src/evaluate/scoring.js +91 -0
  74. package/src/index.js +67 -0
  75. package/src/ingest.js +59 -0
  76. package/src/loader/csv-loader.js +38 -0
  77. package/src/loader/directory-loader.js +48 -0
  78. package/src/loader/html-loader.js +62 -0
  79. package/src/loader/markdown-loader.js +67 -0
  80. package/src/mocks/openai-embedder.js +119 -0
  81. package/src/mocks/openai-llm.js +77 -0
  82. package/src/mocks/pdf-loader.js +21 -0
  83. package/src/mocks/pinecone-retriever.js +106 -0
  84. package/src/observability/audit-logger.js +758 -0
  85. package/src/observability/dashboard-config.json +675 -0
  86. package/src/observability/event-logger.js +310 -0
  87. package/src/observability/metrics.js +691 -0
  88. package/src/observability/security-monitor.js +830 -0
  89. package/src/observability/slo-monitor.js +319 -0
  90. package/src/observability/telemetry.js +686 -0
  91. package/src/pipeline/pipeline.js +18 -0
  92. package/src/plugins/sample-embedder.js +53 -0
  93. package/src/plugins/sample-llm.js +30 -0
  94. package/src/plugins/sample-loader.js +24 -0
  95. package/src/plugins/sample-retriever.js +84 -0
  96. package/src/query.js +117 -0
  97. package/src/reranker/llm-reranker.js +85 -0
  98. package/src/scripts/script-utilities.js +36 -0
  99. package/src/security/plugin-sandbox.js +586 -0
  100. package/src/security/plugin-signature-verifier.js +414 -0
  101. package/src/security/validator.js +36 -0
  102. package/src/utils/ci/diagnostic-reporter.js +57 -0
  103. package/src/utils/logger.js +211 -0
  104. package/src/utils/performance-monitor.js +561 -0
  105. package/src/utils/plugin-scaffolder.js +447 -0
  106. package/src/utils/retry-policy.js +443 -0
  107. package/src/utils/retry.js +107 -0
  108. package/src/utils/safe-expression-evaluator.js +579 -0
  109. package/src/utils/structured-logger.js +361 -0
  110. package/src/utils/validate-plugin-contract.js +42 -0
@@ -0,0 +1,611 @@
1
+ /**
2
+ * Streaming memory safeguards and backpressure management
3
+ * Prevents memory overload during large document processing
4
+ */
5
+
6
+ const { logger } = require('../../utils/logger.js');
7
+
8
+ // Use performance.now() for monotonic timing, fallback to perf_hooks for older Node
9
+ const { performance } = globalThis.performance
10
+ ? globalThis
11
+ : require('node:perf_hooks');
12
+
13
+ /**
14
+ * Memory monitor for tracking heap usage
15
+ */
16
+ class MemoryMonitor {
17
+ constructor(maxMemoryMB = 512) {
18
+ this.maxMemoryBytes = maxMemoryMB * 1024 * 1024;
19
+ this.warningThreshold = 0.8; // 80% of max memory
20
+ this.criticalThreshold = 0.9; // 90% of max memory
21
+ }
22
+
23
+ getCurrentUsage() {
24
+ const usage =
25
+ typeof process.memoryUsage === 'function' ? process.memoryUsage() : null;
26
+ const heapUsed = usage?.heapUsed ?? 0;
27
+ const heapTotal = usage?.heapTotal ?? Math.max(1, heapUsed);
28
+ return {
29
+ heapUsed,
30
+ heapTotal,
31
+ external: usage?.external ?? 0,
32
+ rss: usage?.rss ?? 0,
33
+ heapUsedMB: Math.round(heapUsed / 1024 / 1024),
34
+ heapTotalMB: Math.round(heapTotal / 1024 / 1024),
35
+ };
36
+ }
37
+
38
+ getUsageRatio() {
39
+ const usage = this.getCurrentUsage();
40
+ return usage.heapUsed / this.maxMemoryBytes;
41
+ }
42
+
43
+ isWarningLevel() {
44
+ return this.getUsageRatio() > this.warningThreshold;
45
+ }
46
+
47
+ isCriticalLevel() {
48
+ return this.getUsageRatio() > this.criticalThreshold;
49
+ }
50
+
51
+ getMemoryReport() {
52
+ const usage = this.getCurrentUsage();
53
+ const ratio = this.getUsageRatio();
54
+
55
+ return {
56
+ heapUsedMB: usage.heapUsedMB,
57
+ heapTotalMB: usage.heapTotalMB,
58
+ maxMemoryMB: Math.round(this.maxMemoryBytes / 1024 / 1024),
59
+ usagePercentage: Math.round(ratio * 100),
60
+ status:
61
+ ratio > this.criticalThreshold
62
+ ? 'critical'
63
+ : ratio > this.warningThreshold
64
+ ? 'warning'
65
+ : 'normal',
66
+ };
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Backpressure controller for streaming operations
72
+ */
73
+ class BackpressureController {
74
+ constructor(_options = {}) {
75
+ this.maxBufferSize = _options.maxBufferSize || 100;
76
+ this.memoryMonitor = new MemoryMonitor(_options.maxMemoryMB);
77
+ this.pauseThreshold = _options.pauseThreshold || 0.85;
78
+ this.resumeThreshold = _options.resumeThreshold || 0.7;
79
+ this.checkInterval = _options.checkInterval || 1000; // ms
80
+
81
+ this.isPaused = false;
82
+ this.buffer = [];
83
+ this.waitingResolvers = [];
84
+ }
85
+
86
+ /**
87
+ * Check if backpressure should be applied
88
+ * @returns {boolean} True if processing should be paused
89
+ */
90
+ shouldApplyBackpressure() {
91
+ const memoryRatio = this.memoryMonitor.getUsageRatio();
92
+ const bufferFull = this.buffer.length >= this.maxBufferSize;
93
+
94
+ return memoryRatio > this.pauseThreshold || bufferFull;
95
+ }
96
+
97
+ /**
98
+ * Wait for backpressure to be relieved
99
+ * @returns {Promise<void>}
100
+ */
101
+ async waitForRelief() {
102
+ if (!this.shouldApplyBackpressure()) {
103
+ return;
104
+ }
105
+
106
+ this.isPaused = true;
107
+ const memoryReport = this.memoryMonitor.getMemoryReport();
108
+ logger.warn('Applying backpressure', {
109
+ memoryPercentage: memoryReport.usagePercentage,
110
+ bufferSize: this.buffer.length,
111
+ maxBufferSize: this.maxBufferSize,
112
+ });
113
+
114
+ return new Promise((resolve) => {
115
+ this.waitingResolvers.push(resolve);
116
+ this.startReliefCheck();
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Start checking for relief conditions
122
+ */
123
+ startReliefCheck() {
124
+ if (this.reliefCheckInterval) return;
125
+
126
+ this.reliefCheckInterval = setInterval(() => {
127
+ const memoryRatio = this.memoryMonitor.getUsageRatio();
128
+ const bufferOk = this.buffer.length < this.maxBufferSize * 0.5;
129
+
130
+ if (memoryRatio < this.resumeThreshold && bufferOk) {
131
+ this.relieveBackpressure();
132
+ }
133
+ }, this.checkInterval);
134
+
135
+ // Don't keep process alive for relief checks
136
+ if (typeof this.reliefCheckInterval.unref === 'function') {
137
+ this.reliefCheckInterval.unref();
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Relieve backpressure and resume processing
143
+ */
144
+ relieveBackpressure() {
145
+ if (!this.isPaused) return;
146
+
147
+ this.isPaused = false;
148
+ logger.info('Backpressure relieved - resuming processing');
149
+
150
+ // Clear interval
151
+ if (this.reliefCheckInterval) {
152
+ clearInterval(this.reliefCheckInterval);
153
+ this.reliefCheckInterval = null;
154
+ }
155
+
156
+ // Resolve all waiting promises
157
+ const resolvers = this.waitingResolvers.splice(0);
158
+ resolvers.forEach((resolve) => resolve());
159
+ }
160
+
161
+ /**
162
+ * Add item to buffer with backpressure check
163
+ * @param {any} item - Item to buffer
164
+ */
165
+ async addToBuffer(item) {
166
+ await this.waitForRelief();
167
+ this.buffer.push(item);
168
+ }
169
+
170
+ /**
171
+ * Remove items from buffer
172
+ * @param {number} count - Number of items to remove
173
+ * @returns {any[]} Removed items
174
+ */
175
+ removeFromBuffer(count = 1) {
176
+ return this.buffer.splice(0, count);
177
+ }
178
+
179
+ /**
180
+ * Get current status
181
+ * @returns {object} Status information
182
+ */
183
+ getStatus() {
184
+ const memoryReport = this.memoryMonitor.getMemoryReport();
185
+
186
+ return {
187
+ isPaused: this.isPaused,
188
+ bufferSize: this.buffer.length,
189
+ maxBufferSize: this.maxBufferSize,
190
+ memory: memoryReport,
191
+ shouldApplyBackpressure: this.shouldApplyBackpressure(),
192
+ };
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Streaming processor with memory safeguards
198
+ */
199
+ class StreamingProcessor {
200
+ constructor(_options = {}) {
201
+ this.chunkSize = _options.chunkSize || 1000;
202
+ this.backpressureController = new BackpressureController(_options);
203
+ this.tokenLimit = _options.tokenLimit || 100000; // Token limit per stream
204
+ this.tokenWarningThreshold = _options.tokenWarningThreshold || 0.8;
205
+ }
206
+
207
+ /**
208
+ * Process document stream with memory safeguards
209
+ * @param {string} docPath - Path to document
210
+ * @param {object} pipeline - Pipeline _instance
211
+ * @returns {AsyncGenerator} Stream of processed chunks
212
+ */
213
+ async *processDocumentStream(docPath, pipeline) {
214
+ let totalTokens = 0;
215
+ let chunkCount = 0;
216
+ let processedCount = 0;
217
+ let failedCount = 0;
218
+ let totalChunks = 0;
219
+
220
+ try {
221
+ // First, count total chunks for progress tracking
222
+ const allChunks = [];
223
+ for await (const documentChunk of this.loadInChunks(
224
+ docPath,
225
+ pipeline.loaderInstance,
226
+ )) {
227
+ allChunks.push(documentChunk);
228
+ }
229
+ totalChunks = allChunks.length;
230
+
231
+ for (const documentChunk of allChunks) {
232
+ // Check memory and apply backpressure if needed
233
+ await this.backpressureController.waitForRelief();
234
+
235
+ // Estimate tokens (rough approximation: 1 token ≈ 4 characters)
236
+ const estimatedTokens = documentChunk.length / 4;
237
+ totalTokens += estimatedTokens;
238
+
239
+ // Check token limits
240
+ if (totalTokens > this.tokenLimit) {
241
+ const error = new Error(
242
+ `Token limit exceeded: ${totalTokens} > ${this.tokenLimit}`,
243
+ );
244
+ error.code = 'TOKEN_LIMIT_EXCEEDED';
245
+ throw error;
246
+ }
247
+
248
+ // Process chunk
249
+ const processed = await this.processChunk(documentChunk, pipeline);
250
+ chunkCount++;
251
+
252
+ // Warn if approaching token limit (check after incrementing chunkCount)
253
+ if (
254
+ totalTokens > this.tokenLimit * this.tokenWarningThreshold &&
255
+ chunkCount % 10 === 0
256
+ ) {
257
+ logger.warn('Approaching token limit', {
258
+ currentTokens: Math.round(totalTokens),
259
+ tokenLimit: this.tokenLimit,
260
+ });
261
+ }
262
+
263
+ if (processed.processed) {
264
+ processedCount++;
265
+ } else {
266
+ failedCount++;
267
+ }
268
+
269
+ // Add to buffer and yield
270
+ await this.backpressureController.addToBuffer(processed);
271
+
272
+ // Yield processed chunks from buffer with progress information
273
+ const bufferedItems = this.backpressureController.removeFromBuffer(1);
274
+ for (const item of bufferedItems) {
275
+ yield {
276
+ ...item,
277
+ progress: {
278
+ processed: processedCount,
279
+ failed: failedCount,
280
+ total: totalChunks,
281
+ },
282
+ };
283
+ }
284
+
285
+ // Periodic garbage collection hint
286
+ if (chunkCount % 50 === 0 && global.gc) {
287
+ global.gc();
288
+ }
289
+ }
290
+
291
+ // Yield any remaining buffered items
292
+ const remainingItems = this.backpressureController.removeFromBuffer(
293
+ this.backpressureController.buffer.length,
294
+ );
295
+ for (const item of remainingItems) {
296
+ yield item;
297
+ }
298
+
299
+ logger.info('Streaming processing complete', {
300
+ chunkCount,
301
+ totalTokens: Math.round(totalTokens),
302
+ });
303
+ } catch (error) {
304
+ const status = this.backpressureController.getStatus();
305
+ logger.error('Streaming processing failed', {
306
+ error: error.message,
307
+ totalTokens: Math.round(totalTokens),
308
+ chunkCount,
309
+ memoryStatus: status.memory,
310
+ bufferSize: status.bufferSize,
311
+ });
312
+ throw error;
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Load document in chunks
318
+ * @param {string} docPath - Document path
319
+ * @param {object} loader - Loader _instance
320
+ * @returns {AsyncGenerator} Stream of document chunks
321
+ */
322
+ async *loadInChunks(docPath, loader) {
323
+ const documents = await loader.load(docPath);
324
+
325
+ for (const doc of documents) {
326
+ const chunks = doc.chunk();
327
+
328
+ // Yield chunks in batches to control memory
329
+ for (let i = 0; i < chunks.length; i += this.chunkSize) {
330
+ const batch = chunks.slice(i, i + this.chunkSize);
331
+ for (const chunk of batch) {
332
+ yield chunk;
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Process a single chunk
340
+ * @param {string} chunk - Text chunk
341
+ * @param {object} pipeline - Pipeline _instance
342
+ * @returns {Promise<object>} Processed chunk
343
+ */
344
+ async processChunk(chunk, pipeline) {
345
+ const start = performance.now();
346
+
347
+ try {
348
+ // Embed the chunk
349
+ const vector = await pipeline.embedderInstance.embed([chunk]);
350
+
351
+ // Store in retriever
352
+ await pipeline.retrieverInstance.store(vector);
353
+
354
+ const end = performance.now();
355
+ const duration = Math.max(1, Math.round(end - start)); // clamp to minimum 1ms
356
+
357
+ return {
358
+ chunk,
359
+ vector: vector[0],
360
+ processed: true,
361
+ duration,
362
+ timestamp: new Date().toISOString(),
363
+ };
364
+ } catch (error) {
365
+ const end = performance.now();
366
+ const duration = Math.max(1, Math.round(end - start)); // clamp to minimum 1ms
367
+
368
+ return {
369
+ chunk,
370
+ processed: false,
371
+ error: error.message,
372
+ duration,
373
+ timestamp: new Date().toISOString(),
374
+ };
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Get streaming statistics
380
+ * @returns {object} Statistics
381
+ */
382
+ getStats() {
383
+ const status = this.backpressureController.getStatus();
384
+
385
+ return {
386
+ backpressure: status,
387
+ tokenLimit: this.tokenLimit,
388
+ chunkSize: this.chunkSize,
389
+ };
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Helper utilities for streaming operations
395
+ */
396
+ class StreamingHelpers {
397
+ /**
398
+ * Create a streaming processor with default configuration
399
+ * @param {object} options - Configuration options
400
+ * @returns {StreamingProcessor} Configured streaming processor
401
+ */
402
+ static createProcessor(options = {}) {
403
+ return new StreamingProcessor({
404
+ chunkSize: options.chunkSize || 1000,
405
+ maxMemoryMB: options.maxMemoryMB || 512,
406
+ tokenLimit: options.tokenLimit || 100000,
407
+ tokenWarningThreshold: options.tokenWarningThreshold || 0.8,
408
+ pauseThreshold: options.pauseThreshold || 0.85,
409
+ resumeThreshold: options.resumeThreshold || 0.7,
410
+ checkInterval: options.checkInterval || 1000,
411
+ ...options,
412
+ });
413
+ }
414
+
415
+ /**
416
+ * Create a memory monitor with default configuration
417
+ * @param {number} maxMemoryMB - Maximum memory in MB
418
+ * @returns {MemoryMonitor} Configured memory monitor
419
+ */
420
+ static createMemoryMonitor(maxMemoryMB = 512) {
421
+ return new MemoryMonitor(maxMemoryMB);
422
+ }
423
+
424
+ /**
425
+ * Create a backpressure controller with default configuration
426
+ * @param {object} options - Configuration options
427
+ * @returns {BackpressureController} Configured backpressure controller
428
+ */
429
+ static createBackpressureController(options = {}) {
430
+ return new BackpressureController({
431
+ maxBufferSize: options.maxBufferSize || 100,
432
+ maxMemoryMB: options.maxMemoryMB || 512,
433
+ pauseThreshold: options.pauseThreshold || 0.85,
434
+ resumeThreshold: options.resumeThreshold || 0.7,
435
+ checkInterval: options.checkInterval || 1000,
436
+ ...options,
437
+ });
438
+ }
439
+
440
+ /**
441
+ * Estimate token count from text
442
+ * @param {string} text - Input text
443
+ * @returns {number} Estimated token count
444
+ */
445
+ static estimateTokens(text) {
446
+ if (typeof text !== 'string') return 0;
447
+ // Rough approximation: 1 token ≈ 4 characters
448
+ return Math.ceil(text.length / 4);
449
+ }
450
+
451
+ /**
452
+ * Check if memory usage is within safe limits
453
+ * @param {number} maxMemoryMB - Maximum allowed memory in MB
454
+ * @returns {object} Memory status report
455
+ */
456
+ static checkMemoryStatus(maxMemoryMB = 512) {
457
+ const monitor = new MemoryMonitor(maxMemoryMB);
458
+ const usage = monitor.getCurrentUsage();
459
+ const ratio = monitor.getUsageRatio();
460
+
461
+ return {
462
+ ...usage,
463
+ ratio,
464
+ isWarning: monitor.isWarningLevel(),
465
+ isCritical: monitor.isCriticalLevel(),
466
+ status: ratio > 0.9 ? 'critical' : ratio > 0.8 ? 'warning' : 'normal',
467
+ };
468
+ }
469
+
470
+ /**
471
+ * Create a streaming configuration for different use cases
472
+ * @param {string} profile - Configuration profile ('light', 'standard', 'heavy')
473
+ * @returns {object} Configuration object
474
+ */
475
+ static getStreamingProfile(profile = 'standard') {
476
+ const profiles = {
477
+ light: {
478
+ chunkSize: 500,
479
+ maxMemoryMB: 256,
480
+ tokenLimit: 50000,
481
+ maxBufferSize: 50,
482
+ pauseThreshold: 0.8,
483
+ resumeThreshold: 0.6,
484
+ },
485
+ standard: {
486
+ chunkSize: 1000,
487
+ maxMemoryMB: 512,
488
+ tokenLimit: 100000,
489
+ maxBufferSize: 100,
490
+ pauseThreshold: 0.85,
491
+ resumeThreshold: 0.7,
492
+ },
493
+ heavy: {
494
+ chunkSize: 2000,
495
+ maxMemoryMB: 1024,
496
+ tokenLimit: 200000,
497
+ maxBufferSize: 200,
498
+ pauseThreshold: 0.9,
499
+ resumeThreshold: 0.75,
500
+ },
501
+ };
502
+
503
+ return profiles[profile] || profiles.standard;
504
+ }
505
+
506
+ /**
507
+ * Wrap an async iterator with memory monitoring
508
+ * @param {AsyncIterator} iterator - Source async iterator
509
+ * @param {object} options - Monitoring options
510
+ * @returns {AsyncGenerator} Monitored async generator
511
+ */
512
+ static async *withMemoryMonitoring(iterator, options = {}) {
513
+ const monitor = new MemoryMonitor(options.maxMemoryMB || 512);
514
+ let itemCount = 0;
515
+
516
+ try {
517
+ for await (const item of iterator) {
518
+ itemCount++;
519
+
520
+ // Check memory every N items
521
+ if (itemCount % (options.checkInterval || 10) === 0) {
522
+ const report = monitor.getMemoryReport();
523
+
524
+ if (monitor.isCriticalLevel()) {
525
+ throw new Error(
526
+ `Critical memory usage: ${report.usagePercentage}% (${report.heapUsedMB}MB)`,
527
+ );
528
+ }
529
+
530
+ if (monitor.isWarningLevel() && options.onWarning) {
531
+ options.onWarning(report);
532
+ }
533
+ }
534
+
535
+ yield {
536
+ ...item,
537
+ memoryStatus:
538
+ itemCount % (options.reportInterval || 100) === 0
539
+ ? monitor.getMemoryReport()
540
+ : undefined,
541
+ };
542
+ }
543
+ } catch (error) {
544
+ const finalReport = monitor.getMemoryReport();
545
+ logger.error('Memory monitoring error:', {
546
+ error: error.message,
547
+ itemsProcessed: itemCount,
548
+ finalMemoryStatus: finalReport,
549
+ });
550
+ throw error;
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Create a throttled async iterator
556
+ * @param {AsyncIterator} iterator - Source async iterator
557
+ * @param {number} delayMs - Delay between items in milliseconds
558
+ * @returns {AsyncGenerator} Throttled async generator
559
+ */
560
+ static async *throttle(iterator, delayMs = 100) {
561
+ for await (const item of iterator) {
562
+ yield item;
563
+
564
+ // Add delay between items
565
+ if (delayMs > 0) {
566
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
567
+ }
568
+ }
569
+ }
570
+
571
+ /**
572
+ * Batch items from an async iterator
573
+ * @param {AsyncIterator} iterator - Source async iterator
574
+ * @param {number} batchSize - Number of items per batch
575
+ * @returns {AsyncGenerator} Batched async generator
576
+ */
577
+ static async *batch(iterator, batchSize = 10) {
578
+ let batch = [];
579
+
580
+ for await (const item of iterator) {
581
+ batch.push(item);
582
+
583
+ if (batch.length >= batchSize) {
584
+ yield batch;
585
+ batch = [];
586
+ }
587
+ }
588
+
589
+ // Yield remaining items
590
+ if (batch.length > 0) {
591
+ yield batch;
592
+ }
593
+ }
594
+ }
595
+
596
+ module.exports = {
597
+ BackpressureController,
598
+ StreamingProcessor,
599
+ MemoryMonitor,
600
+ StreamingHelpers,
601
+ // Convenience exports
602
+ createProcessor: StreamingHelpers.createProcessor,
603
+ createMemoryMonitor: StreamingHelpers.createMemoryMonitor,
604
+ createBackpressureController: StreamingHelpers.createBackpressureController,
605
+ estimateTokens: StreamingHelpers.estimateTokens,
606
+ checkMemoryStatus: StreamingHelpers.checkMemoryStatus,
607
+ getStreamingProfile: StreamingHelpers.getStreamingProfile,
608
+ withMemoryMonitoring: StreamingHelpers.withMemoryMonitoring,
609
+ throttle: StreamingHelpers.throttle,
610
+ batch: StreamingHelpers.batch,
611
+ };
@@ -0,0 +1,60 @@
1
+ 'use strict';
2
+
3
+ async function createPipeline({
4
+ loader,
5
+ embedder,
6
+ retriever,
7
+ reranker,
8
+ llm,
9
+ evaluator,
10
+ } = {}) {
11
+ // Required components check
12
+ const required = ['loader', 'embedder', 'retriever', 'llm'];
13
+ const missing = required.filter(
14
+ (name) => !arguments[0] || !arguments[0][name],
15
+ );
16
+ if (missing.length > 0) {
17
+ throw new Error(`Required components missing: ${missing.join(', ')}`);
18
+ }
19
+
20
+ return {
21
+ async run(input, { signal } = {}) {
22
+ // Check if signal is already aborted
23
+ if (signal && signal.aborted) {
24
+ throw new Error('Aborted');
25
+ }
26
+
27
+ // Execute pipeline in order
28
+ const docs = await loader.load(input, { signal });
29
+ const embeddings = await embedder.embed(docs, { signal });
30
+ const candidates = await retriever.retrieve(embeddings, { signal });
31
+
32
+ let ranked = candidates;
33
+ if (reranker && typeof reranker.rerank === 'function') {
34
+ ranked = await reranker.rerank(input, candidates, { signal });
35
+ }
36
+
37
+ const answer = await llm.generate(input, ranked, { signal });
38
+
39
+ let evaluation = null;
40
+ if (evaluator && typeof evaluator.evaluate === 'function') {
41
+ evaluation = await evaluator.evaluate(input, answer, ranked);
42
+ }
43
+
44
+ return {
45
+ docs,
46
+ embeddings,
47
+ candidates,
48
+ ranked,
49
+ answer,
50
+ evaluation,
51
+ };
52
+ },
53
+ };
54
+ }
55
+
56
+ // CJS+ESM interop pattern
57
+ module.exports = createPipeline;
58
+ module.exports.createPipeline = createPipeline;
59
+ module.exports.createRagPipeline = createPipeline; // Alias for backward compatibility
60
+ module.exports.default = module.exports;