@devilsdev/rag-pipeline-utils 2.1.12 → 2.2.1

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