@devilsdev/rag-pipeline-utils 2.1.12 → 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 +292 -32
  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,516 @@
1
+ /**
2
+ * Benchmark tooling for measuring RAG pipeline performance
3
+ * Provides detailed timing and performance metrics for each stage
4
+ */
5
+
6
+ const path = require('path');
7
+ const { logger } = require('../../utils/structured-logger.js');
8
+
9
+ /**
10
+ * Performance timer utility
11
+ */
12
+ class PerformanceTimer {
13
+ constructor() {
14
+ this.timers = new Map();
15
+ this.results = new Map();
16
+ }
17
+
18
+ /**
19
+ * Start timing an operation
20
+ * @param {string} name - Timer name
21
+ * @param {object} metadata - Additional metadata
22
+ */
23
+ start(name, metadata = {}) {
24
+ this.timers.set(name, {
25
+ startTime: performance.now(),
26
+ startMemory: process.memoryUsage(),
27
+ metadata,
28
+ });
29
+ }
30
+
31
+ /**
32
+ * End timing an operation
33
+ * @param {string} name - Timer name
34
+ * @param {object} result - Operation result metadata
35
+ */
36
+ end(name, result = {}) {
37
+ const timer = this.timers.get(name);
38
+ if (!timer) {
39
+ throw new Error(`Timer '${name}' not found. Did you call start() first?`);
40
+ }
41
+
42
+ const endTime = performance.now();
43
+ const endMemory = process.memoryUsage();
44
+
45
+ const timing = {
46
+ duration: endTime - timer.startTime,
47
+ startTime: timer.startTime,
48
+ endTime,
49
+ memoryDelta: {
50
+ heapUsed: endMemory.heapUsed - timer.startMemory.heapUsed,
51
+ heapTotal: endMemory.heapTotal - timer.startMemory.heapTotal,
52
+ external: endMemory.external - timer.startMemory.external,
53
+ },
54
+ metadata: timer.metadata,
55
+ result,
56
+ };
57
+
58
+ this.results.set(name, timing);
59
+ this.timers.delete(name);
60
+
61
+ return timing;
62
+ }
63
+
64
+ /**
65
+ * Get timing result
66
+ * @param {string} name - Timer name
67
+ * @returns {object} Timing result
68
+ */
69
+ getResult(name) {
70
+ return this.results.get(name);
71
+ }
72
+
73
+ /**
74
+ * Get all results
75
+ * @returns {Map} All timing results
76
+ */
77
+ getAllResults() {
78
+ return new Map(this.results);
79
+ }
80
+
81
+ /**
82
+ * Clear all results
83
+ */
84
+ clear() {
85
+ this.timers.clear();
86
+ this.results.clear();
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Pipeline benchmark runner
92
+ */
93
+ class PipelineBenchmark {
94
+ constructor(pipeline, options = {}) {
95
+ this.pipeline = pipeline;
96
+ this.timer = new PerformanceTimer();
97
+ this.options = {
98
+ includeMemory: options.includeMemory !== false,
99
+ includeGC: options.includeGC !== false,
100
+ warmupRuns: options.warmupRuns || 0,
101
+ iterations: options.iterations || 1,
102
+ concurrency: options.concurrency || 1,
103
+ timeout: options.timeout || 30000,
104
+ ...options,
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Benchmark the ingest operation
110
+ * @param {string} docPath - Document path
111
+ * @returns {Promise<object>} Benchmark results
112
+ */
113
+ async benchmarkIngest(docPath) {
114
+ logger.info('Benchmarking ingest operation', { docPath });
115
+
116
+ // Warmup runs
117
+ for (let i = 0; i < this.options.warmupRuns; i++) {
118
+ logger.info('Warmup run', { run: i + 1, total: this.options.warmupRuns });
119
+ await this.runIngestBenchmark(docPath, true);
120
+ }
121
+
122
+ // Actual benchmark runs
123
+ const results = [];
124
+ for (let i = 0; i < this.options.iterations; i++) {
125
+ logger.info('Benchmark run', {
126
+ run: i + 1,
127
+ total: this.options.iterations,
128
+ });
129
+ const result = await this.runIngestBenchmark(docPath, false);
130
+ results.push(result);
131
+ }
132
+
133
+ return this.aggregateResults('ingest', results);
134
+ }
135
+
136
+ /**
137
+ * Run a single ingest benchmark
138
+ * @param {string} docPath - Document path
139
+ * @param {boolean} isWarmup - Whether this is a warmup run
140
+ * @returns {Promise<object>} Single run results
141
+ */
142
+ async runIngestBenchmark(docPath, isWarmup = false) {
143
+ this.timer.clear();
144
+
145
+ try {
146
+ // Overall ingest timing
147
+ this.timer.start('ingest_total', { docPath, isWarmup });
148
+
149
+ // Stage 1: Document loading
150
+ this.timer.start('loader', { stage: 'load', docPath });
151
+ const documents = await this.pipeline.loaderInstance.load(docPath);
152
+ const loadResult = this.timer.end('loader', {
153
+ documentCount: documents.length,
154
+ totalSize: documents.reduce(
155
+ (sum, doc) => sum + (doc.content?.length || 0),
156
+ 0,
157
+ ),
158
+ });
159
+
160
+ // Stage 2: Chunking
161
+ this.timer.start('chunker', {
162
+ stage: 'chunk',
163
+ documentCount: documents.length,
164
+ });
165
+ const chunks = documents.flatMap((doc) => doc.chunk());
166
+ const chunkResult = this.timer.end('chunker', {
167
+ chunkCount: chunks.length,
168
+ avgChunkSize:
169
+ chunks.reduce((sum, chunk) => sum + chunk.length, 0) / chunks.length,
170
+ });
171
+
172
+ // Stage 3: Embedding
173
+ this.timer.start('embedder', {
174
+ stage: 'embed',
175
+ chunkCount: chunks.length,
176
+ });
177
+ const vectors = await this.pipeline.embedderInstance.embed(chunks);
178
+ const embedResult = this.timer.end('embedder', {
179
+ vectorCount: vectors.length,
180
+ vectorDimension: vectors[0]?.length || 0,
181
+ throughput: chunks.length / (loadResult.duration / 1000), // chunks per second
182
+ });
183
+
184
+ // Stage 4: Storage
185
+ this.timer.start('retriever_store', {
186
+ stage: 'store',
187
+ vectorCount: vectors.length,
188
+ });
189
+ await this.pipeline.retrieverInstance.store(vectors);
190
+ const storeResult = this.timer.end('retriever_store', {
191
+ vectorCount: vectors.length,
192
+ });
193
+
194
+ // End overall timing
195
+ const totalResult = this.timer.end('ingest_total', {
196
+ success: true,
197
+ documentCount: documents.length,
198
+ chunkCount: chunks.length,
199
+ vectorCount: vectors.length,
200
+ });
201
+
202
+ return {
203
+ success: true,
204
+ stages: {
205
+ load: loadResult,
206
+ chunk: chunkResult,
207
+ embed: embedResult,
208
+ store: storeResult,
209
+ },
210
+ total: totalResult,
211
+ metadata: {
212
+ docPath,
213
+ isWarmup,
214
+ timestamp: new Date().toISOString(),
215
+ },
216
+ };
217
+ } catch (error) {
218
+ const totalResult = this.timer.end('ingest_total', {
219
+ success: false,
220
+ error: error.message,
221
+ });
222
+
223
+ return {
224
+ success: false,
225
+ error: error.message,
226
+ total: totalResult,
227
+ stages: Object.fromEntries(this.timer.getAllResults()),
228
+ metadata: {
229
+ docPath,
230
+ isWarmup,
231
+ timestamp: new Date().toISOString(),
232
+ },
233
+ };
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Benchmark the query operation
239
+ * @param {string} prompt - Query prompt
240
+ * @returns {Promise<object>} Benchmark results
241
+ */
242
+ async benchmarkQuery(prompt) {
243
+ logger.info('Benchmarking query operation', {
244
+ promptPreview: prompt.substring(0, 50),
245
+ });
246
+
247
+ // Warmup runs
248
+ for (let i = 0; i < this.options.warmupRuns; i++) {
249
+ logger.info('Warmup run', { run: i + 1, total: this.options.warmupRuns });
250
+ await this.runQueryBenchmark(prompt, true);
251
+ }
252
+
253
+ // Actual benchmark runs
254
+ const results = [];
255
+ for (let i = 0; i < this.options.iterations; i++) {
256
+ logger.info('Benchmark run', {
257
+ run: i + 1,
258
+ total: this.options.iterations,
259
+ });
260
+ const result = await this.runQueryBenchmark(prompt, false);
261
+ results.push(result);
262
+ }
263
+
264
+ return this.aggregateResults('query', results);
265
+ }
266
+
267
+ /**
268
+ * Run a single query benchmark
269
+ * @param {string} prompt - Query prompt
270
+ * @param {boolean} isWarmup - Whether this is a warmup run
271
+ * @returns {Promise<object>} Single run results
272
+ */
273
+ async runQueryBenchmark(prompt, isWarmup = false) {
274
+ this.timer.clear();
275
+
276
+ try {
277
+ // Overall query timing
278
+ this.timer.start('query_total', {
279
+ prompt: prompt.substring(0, 100),
280
+ isWarmup,
281
+ });
282
+
283
+ // Stage 1: Query embedding
284
+ this.timer.start('embedder_query', {
285
+ stage: 'embed_query',
286
+ promptLength: prompt.length,
287
+ });
288
+ const queryVector =
289
+ await this.pipeline.embedderInstance.embedQuery(prompt);
290
+ const embedResult = this.timer.end('embedder_query', {
291
+ vectorDimension: queryVector.length,
292
+ });
293
+
294
+ // Stage 2: Retrieval
295
+ this.timer.start('retriever_search', {
296
+ stage: 'retrieve',
297
+ vectorDimension: queryVector.length,
298
+ });
299
+ let retrieved =
300
+ await this.pipeline.retrieverInstance.retrieve(queryVector);
301
+ const retrieveResult = this.timer.end('retriever_search', {
302
+ retrievedCount: retrieved.length,
303
+ });
304
+
305
+ // Stage 3: Reranking (if enabled)
306
+ let rerankResult = null;
307
+ if (this.pipeline.rerankerInstance) {
308
+ this.timer.start('reranker', {
309
+ stage: 'rerank',
310
+ documentCount: retrieved.length,
311
+ });
312
+ retrieved = await this.pipeline.rerankerInstance.rerank(
313
+ prompt,
314
+ retrieved,
315
+ );
316
+ rerankResult = this.timer.end('reranker', {
317
+ rerankedCount: retrieved.length,
318
+ });
319
+ }
320
+
321
+ // Stage 4: LLM Generation
322
+ this.timer.start('llm_generate', {
323
+ stage: 'generate',
324
+ promptLength: prompt.length,
325
+ contextCount: retrieved.length,
326
+ });
327
+ const result = await this.pipeline.llmInstance.generate(
328
+ prompt,
329
+ retrieved,
330
+ );
331
+ const generateResult = this.timer.end('llm_generate', {
332
+ responseLength: result.length,
333
+ estimatedTokens: Math.ceil(result.length / 4), // Rough token estimate
334
+ });
335
+
336
+ // End overall timing
337
+ const totalResult = this.timer.end('query_total', {
338
+ success: true,
339
+ promptLength: prompt.length,
340
+ responseLength: result.length,
341
+ retrievedCount: retrieved.length,
342
+ });
343
+
344
+ const stages = {
345
+ embed: embedResult,
346
+ retrieve: retrieveResult,
347
+ generate: generateResult,
348
+ };
349
+
350
+ if (rerankResult) {
351
+ stages.rerank = rerankResult;
352
+ }
353
+
354
+ return {
355
+ success: true,
356
+ stages,
357
+ total: totalResult,
358
+ result,
359
+ metadata: {
360
+ prompt: prompt.substring(0, 100),
361
+ isWarmup,
362
+ timestamp: new Date().toISOString(),
363
+ },
364
+ };
365
+ } catch (error) {
366
+ const totalResult = this.timer.end('query_total', {
367
+ success: false,
368
+ error: error.message,
369
+ });
370
+
371
+ return {
372
+ success: false,
373
+ error: error.message,
374
+ total: totalResult,
375
+ stages: Object.fromEntries(this.timer.getAllResults()),
376
+ metadata: {
377
+ prompt: prompt.substring(0, 100),
378
+ isWarmup,
379
+ timestamp: new Date().toISOString(),
380
+ },
381
+ };
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Aggregate results from multiple runs
387
+ * @param {string} operation - Operation name
388
+ * @param {object[]} results - Array of run results
389
+ * @returns {object} Aggregated results
390
+ */
391
+ aggregateResults(operation, results) {
392
+ const successful = results.filter((r) => r.success);
393
+ const failed = results.filter((r) => !r.success);
394
+
395
+ if (successful.length === 0) {
396
+ return {
397
+ operation,
398
+ success: false,
399
+ error: 'All benchmark runs failed',
400
+ runs: {
401
+ failed: failed.length,
402
+ total: results.length,
403
+ },
404
+ };
405
+ }
406
+
407
+ // Aggregate stage timings
408
+ const stageStats = {};
409
+ const stageNames = Object.keys(successful[0].stages);
410
+
411
+ for (const stageName of stageNames) {
412
+ const stageDurations = successful
413
+ .map((r) => r.stages[stageName]?.duration)
414
+ .filter((d) => d !== undefined);
415
+
416
+ if (stageDurations.length > 0) {
417
+ stageStats[stageName] = this.calculateStats(stageDurations);
418
+ }
419
+ }
420
+
421
+ // Aggregate total timings
422
+ const totalDurations = successful.map((r) => r.total.duration);
423
+ const totalStats = this.calculateStats(totalDurations);
424
+
425
+ return {
426
+ operation,
427
+ success: true,
428
+ runs: {
429
+ total: results.length,
430
+ successful: successful.length,
431
+ failed: failed.length,
432
+ },
433
+ timing: {
434
+ stages: stageStats,
435
+ total: totalStats,
436
+ },
437
+ metadata: {
438
+ iterations: this.options.iterations,
439
+ warmupRuns: this.options.warmupRuns,
440
+ timestamp: new Date().toISOString(),
441
+ },
442
+ rawResults: successful,
443
+ };
444
+ }
445
+
446
+ /**
447
+ * Calculate statistical measures for an array of values
448
+ * @param {number[]} values - Array of numeric values
449
+ * @returns {object} Statistical measures
450
+ */
451
+ calculateStats(values) {
452
+ if (values.length === 0) return null;
453
+
454
+ const sorted = [...values].sort((a, b) => a - b);
455
+ const sum = values.reduce((a, b) => a + b, 0);
456
+ const mean = sum / values.length;
457
+
458
+ return {
459
+ min: Math.min(...values),
460
+ max: Math.max(...values),
461
+ mean: mean,
462
+ median: sorted[Math.floor(sorted.length / 2)],
463
+ p95: sorted[Math.floor(sorted.length * 0.95)],
464
+ p99: sorted[Math.floor(sorted.length * 0.99)],
465
+ stdDev: Math.sqrt(
466
+ values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) /
467
+ values.length,
468
+ ),
469
+ count: values.length,
470
+ };
471
+ }
472
+
473
+ /**
474
+ * Format benchmark results for display
475
+ * @param {object} results - Benchmark results
476
+ * @returns {string} Formatted output
477
+ */
478
+ formatResults(results) {
479
+ if (!results.success) {
480
+ return `āŒ Benchmark failed: ${results.error}`;
481
+ }
482
+
483
+ let output = `\nšŸ“Š ${results.operation.toUpperCase()} BENCHMARK RESULTS\n`;
484
+ output += `${'='.repeat(50)}\n`;
485
+ output += `Runs: ${results.runs.successful}/${results.runs.total} successful\n`;
486
+
487
+ if (results.runs.failed > 0) {
488
+ output += `āš ļø ${results.runs.failed} runs failed\n`;
489
+ }
490
+
491
+ output += '\nā±ļø STAGE TIMINGS (ms)\n';
492
+ output += `${'-'.repeat(30)}\n`;
493
+
494
+ for (const [stage, stats] of Object.entries(results.timing.stages)) {
495
+ output += `${stage.padEnd(15)} | `;
496
+ output += `avg: ${stats.mean.toFixed(1).padStart(6)} | `;
497
+ output += `min: ${stats.min.toFixed(1).padStart(6)} | `;
498
+ output += `max: ${stats.max.toFixed(1).padStart(6)} | `;
499
+ output += `p95: ${stats.p95.toFixed(1).padStart(6)}\n`;
500
+ }
501
+
502
+ output += `${'-'.repeat(30)}\n`;
503
+ output += 'TOTAL | ';
504
+ output += `avg: ${results.timing.total.mean.toFixed(1).padStart(6)} | `;
505
+ output += `min: ${results.timing.total.min.toFixed(1).padStart(6)} | `;
506
+ output += `max: ${results.timing.total.max.toFixed(1).padStart(6)} | `;
507
+ output += `p95: ${results.timing.total.p95.toFixed(1).padStart(6)}\n`;
508
+
509
+ return output;
510
+ }
511
+ }
512
+
513
+ module.exports = {
514
+ PipelineBenchmark,
515
+ PerformanceTimer,
516
+ };