@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
package/src/cli.js ADDED
@@ -0,0 +1,17 @@
1
+ const { Command } = require('commander');
2
+ const { EnhancedCLI } = require('./cli/enhanced-cli-commands');
3
+ const pkg = require('../package.json');
4
+
5
+ function buildProgram() {
6
+ const enhancedCLI = new EnhancedCLI();
7
+ // Keep the program name consistent with package.json bin command
8
+ enhancedCLI.program.name('rag-pipeline');
9
+ return enhancedCLI.program;
10
+ }
11
+
12
+ async function run(argv = process.argv) {
13
+ const program = buildProgram();
14
+ await program.parseAsync(argv);
15
+ }
16
+
17
+ module.exports = { buildProgram, run };
@@ -0,0 +1,632 @@
1
+ /**
2
+ * Enhanced .ragrc.json Schema with Plugin Versioning Support
3
+ * Single source of truth for configuration validation
4
+ */
5
+
6
+ const Ajv = require("ajv"); // eslint-disable-line global-require
7
+ const addFormats = require("ajv-formats"); // eslint-disable-line global-require
8
+ const { normalizeConfig } = require("./normalize-config");
9
+
10
+ /**
11
+ * Plugin specification schema - supports both simple and versioned formats
12
+ */
13
+ const pluginSpecSchema = {
14
+ oneOf: [
15
+ // Simple format: "plugin-name" (resolves to latest)
16
+ { type: "string" },
17
+ // Versioned format: { "name": "plugin-name", "version": "1.0.0" }
18
+ {
19
+ type: "object",
20
+ required: ["name"],
21
+ properties: {
22
+ name: {
23
+ type: "string",
24
+ pattern: "^[a-z0-9-]+$",
25
+ description: "Plugin name",
26
+ },
27
+ version: {
28
+ type: "string",
29
+ description: "Version specification (exact, range, or tag)",
30
+ },
31
+ source: {
32
+ type: "string",
33
+ enum: ["registry", "local", "git", "npm"],
34
+ default: "registry",
35
+ description: "Plugin source type",
36
+ },
37
+ url: {
38
+ type: "string",
39
+ format: "uri",
40
+ description: "Custom plugin URL (for git/npm sources)",
41
+ },
42
+ path: {
43
+ type: "string",
44
+ description: "Local plugin path (for local source)",
45
+ },
46
+ config: {
47
+ type: "object",
48
+ description: "Plugin-specific configuration",
49
+ },
50
+ enabled: {
51
+ type: "boolean",
52
+ default: true,
53
+ description: "Whether plugin is enabled",
54
+ },
55
+ fallback: {
56
+ type: "string",
57
+ description: "Fallback plugin if this one fails to load",
58
+ },
59
+ },
60
+ additionalProperties: false,
61
+ },
62
+ ],
63
+ };
64
+
65
+ /**
66
+ * Plugin group schema - collection of plugins for a specific _type
67
+ */
68
+ const pluginGroupSchema = {
69
+ type: "object",
70
+ minProperties: 1,
71
+ additionalProperties: pluginSpecSchema,
72
+ description: "Plugin group with name-to-spec mappings",
73
+ };
74
+
75
+ /**
76
+ * Registry configuration schema
77
+ */
78
+ const registryConfigSchema = {
79
+ type: "object",
80
+ properties: {
81
+ urls: {
82
+ type: "array",
83
+ items: { type: "string", format: "uri" },
84
+ description: "Plugin registry URLs",
85
+ },
86
+ cache: {
87
+ type: "object",
88
+ properties: {
89
+ enabled: { type: "boolean", default: true },
90
+ ttl: {
91
+ type: "number",
92
+ default: 3600,
93
+ description: "Cache TTL in seconds",
94
+ },
95
+ directory: { type: "string", description: "Custom cache directory" },
96
+ },
97
+ additionalProperties: false,
98
+ },
99
+ auth: {
100
+ type: "object",
101
+ properties: {
102
+ token: { type: "string", description: "Authentication token" },
103
+ username: { type: "string", description: "Username for basic auth" },
104
+ password: { type: "string", description: "Password for basic auth" },
105
+ },
106
+ additionalProperties: false,
107
+ },
108
+ timeout: {
109
+ type: "number",
110
+ default: 30000,
111
+ description: "Request timeout in milliseconds",
112
+ },
113
+ retries: {
114
+ type: "number",
115
+ default: 3,
116
+ description: "Number of retry attempts",
117
+ },
118
+ },
119
+ additionalProperties: false,
120
+ };
121
+
122
+ /**
123
+ * Enhanced .ragrc.json schema with versioning support
124
+ */
125
+ const enhancedRagrcSchema = {
126
+ type: "object",
127
+ required: ["plugins"],
128
+ properties: {
129
+ // Plugin specifications
130
+ plugins: {
131
+ type: "object",
132
+ required: ["loader", "embedder", "retriever", "llm"],
133
+ properties: {
134
+ loader: pluginGroupSchema,
135
+ embedder: pluginGroupSchema,
136
+ retriever: pluginGroupSchema,
137
+ llm: pluginGroupSchema,
138
+ reranker: pluginGroupSchema,
139
+ },
140
+ additionalProperties: false,
141
+ },
142
+
143
+ // Registry configuration
144
+ registry: registryConfigSchema,
145
+
146
+ // Pipeline configuration
147
+ pipeline: {
148
+ type: "object",
149
+ properties: {
150
+ stages: {
151
+ type: "array",
152
+ items: {
153
+ type: "string",
154
+ enum: ["loader", "embedder", "retriever", "llm", "reranker"],
155
+ },
156
+ default: ["loader", "embedder", "retriever", "llm"],
157
+ description: "Pipeline execution stages",
158
+ },
159
+ middleware: {
160
+ type: "array",
161
+ items: {
162
+ type: "object",
163
+ required: ["name"],
164
+ properties: {
165
+ name: { type: "string" },
166
+ _config: { type: "object" },
167
+ enabled: { type: "boolean", default: true },
168
+ },
169
+ },
170
+ description: "Pipeline middleware configuration",
171
+ },
172
+ retries: {
173
+ type: "object",
174
+ properties: {
175
+ enabled: { type: "boolean", default: true },
176
+ maxAttempts: { type: "number", default: 3 },
177
+ backoff: {
178
+ type: "string",
179
+ enum: ["linear", "exponential"],
180
+ default: "exponential",
181
+ },
182
+ },
183
+ },
184
+ timeout: {
185
+ type: "number",
186
+ description: "Pipeline timeout in milliseconds",
187
+ },
188
+ },
189
+ additionalProperties: false,
190
+ },
191
+
192
+ // Performance configuration
193
+ performance: {
194
+ type: "object",
195
+ properties: {
196
+ parallel: {
197
+ type: "object",
198
+ properties: {
199
+ enabled: { type: "boolean", default: false },
200
+ maxConcurrency: { type: "number", default: 3 },
201
+ batchSize: { type: "number", default: 10 },
202
+ },
203
+ },
204
+ streaming: {
205
+ type: "object",
206
+ properties: {
207
+ enabled: { type: "boolean", default: false },
208
+ maxMemoryMB: { type: "number", default: 512 },
209
+ bufferSize: { type: "number", default: 100 },
210
+ },
211
+ },
212
+ caching: {
213
+ type: "object",
214
+ properties: {
215
+ enabled: { type: "boolean", default: false },
216
+ ttl: { type: "number", default: 3600 },
217
+ maxSize: { type: "number", default: 1000 },
218
+ },
219
+ },
220
+ },
221
+ additionalProperties: false,
222
+ },
223
+
224
+ // Observability configuration
225
+ observability: {
226
+ type: "object",
227
+ properties: {
228
+ logging: {
229
+ type: "object",
230
+ properties: {
231
+ level: {
232
+ type: "string",
233
+ enum: ["debug", "info", "warn", "error"],
234
+ default: "info",
235
+ },
236
+ structured: { type: "boolean", default: true },
237
+ events: { type: "boolean", default: false },
238
+ },
239
+ },
240
+ tracing: {
241
+ type: "object",
242
+ properties: {
243
+ enabled: { type: "boolean", default: false },
244
+ exportUrl: { type: "string", format: "uri" },
245
+ sampleRate: { type: "number", minimum: 0, maximum: 1, default: 1 },
246
+ },
247
+ },
248
+ metrics: {
249
+ type: "object",
250
+ properties: {
251
+ enabled: { type: "boolean", default: false },
252
+ exportUrl: { type: "string", format: "uri" },
253
+ interval: { type: "number", default: 60000 },
254
+ },
255
+ },
256
+ },
257
+ additionalProperties: false,
258
+ },
259
+
260
+ // Environment-specific overrides
261
+ environments: {
262
+ type: "object",
263
+ additionalProperties: {
264
+ type: "object",
265
+ description: "Environment-specific configuration overrides",
266
+ },
267
+ },
268
+
269
+ // Metadata
270
+ metadata: {
271
+ type: "object",
272
+ properties: {
273
+ name: { type: "string", description: "Project name" },
274
+ version: { type: "string", description: "Project version" },
275
+ description: { type: "string", description: "Project description" },
276
+ author: { type: "string", description: "Project author" },
277
+ tags: {
278
+ type: "array",
279
+ items: { type: "string" },
280
+ description: "Project tags",
281
+ },
282
+ },
283
+ additionalProperties: false,
284
+ },
285
+
286
+ // Legacy support
287
+ namespace: {
288
+ type: "string",
289
+ description: "Legacy namespace field (deprecated)",
290
+ },
291
+ },
292
+ additionalProperties: false,
293
+ };
294
+
295
+ /**
296
+ * Backward compatibility schema (original format)
297
+ */
298
+ const legacyRagrcSchema = {
299
+ type: "object",
300
+ required: ["loader", "embedder", "retriever", "llm", "namespace", "pipeline"],
301
+ properties: {
302
+ loader: {
303
+ type: "object",
304
+ minProperties: 1,
305
+ additionalProperties: { type: "string" },
306
+ },
307
+ embedder: {
308
+ type: "object",
309
+ minProperties: 1,
310
+ additionalProperties: { type: "string" },
311
+ },
312
+ retriever: {
313
+ type: "object",
314
+ minProperties: 1,
315
+ additionalProperties: { type: "string" },
316
+ },
317
+ llm: {
318
+ type: "object",
319
+ minProperties: 1,
320
+ additionalProperties: { type: "string" },
321
+ },
322
+ reranker: {
323
+ type: "object",
324
+ additionalProperties: { type: "string" },
325
+ },
326
+ namespace: { type: "string", minLength: 1 },
327
+ pipeline: {
328
+ type: "array",
329
+ items: {
330
+ type: "string",
331
+ enum: ["loader", "embedder", "retriever"],
332
+ },
333
+ minItems: 1,
334
+ uniqueItems: true,
335
+ },
336
+ },
337
+ additionalProperties: false,
338
+ };
339
+
340
+ /**
341
+ * Build the canonical .ragrc.json schema
342
+ * @returns {object} JSON Schema object
343
+ */
344
+ function buildRagrcJsonSchema() {
345
+ return enhancedRagrcSchema;
346
+ }
347
+
348
+ /**
349
+ * Validate .ragrc.json configuration (single source of truth)
350
+ * @param {object} config - Configuration to validate
351
+ * @returns {{ valid: boolean, errors?: any[], normalized?: object }}
352
+ */
353
+ function validateRagrc(config) {
354
+ let errors = [];
355
+
356
+ // Input validation before normalization
357
+ if (!config || typeof config !== "object") {
358
+ return {
359
+ valid: false,
360
+ errors: [{ message: "Configuration must be a non-null object" }],
361
+ normalized: undefined,
362
+ };
363
+ }
364
+
365
+ // Check for obviously invalid plugin configurations
366
+ const pluginTypes = ["loader", "embedder", "retriever", "llm", "reranker"];
367
+ for (const type of pluginTypes) {
368
+ if (config.hasOwnProperty(type)) {
369
+ const value = config[type];
370
+ // Plugin configs should be objects or strings, not primitives like true, 123, null
371
+ if (
372
+ value !== null &&
373
+ typeof value !== "string" &&
374
+ typeof value !== "object"
375
+ ) {
376
+ errors.push({
377
+ message: `${type} must be an object or string, got ${typeof value}`,
378
+ });
379
+ }
380
+ }
381
+ }
382
+
383
+ // Pipeline should be array or object if specified (object format will be normalized)
384
+ if (
385
+ config.hasOwnProperty("pipeline") &&
386
+ !Array.isArray(config.pipeline) &&
387
+ (typeof config.pipeline !== "object" || config.pipeline === null)
388
+ ) {
389
+ errors.push({ message: "pipeline must be an array or object" });
390
+ }
391
+
392
+ // Only return early for critical errors that prevent normalization
393
+ const criticalErrors = errors.filter(
394
+ (e) =>
395
+ e.message.includes("Configuration must be a non-null object") ||
396
+ e.message.includes("pipeline must be an array or object"),
397
+ );
398
+
399
+ if (criticalErrors.length > 0) {
400
+ return {
401
+ valid: false,
402
+ errors: criticalErrors,
403
+ normalized: undefined,
404
+ };
405
+ }
406
+
407
+ // Try normalization
408
+ let normalized;
409
+ try {
410
+ normalized = normalizeConfig(config);
411
+ } catch (e) {
412
+ return {
413
+ valid: false,
414
+ errors: [{ message: e.message }],
415
+ normalized: undefined,
416
+ };
417
+ }
418
+
419
+ // Post-normalization validation
420
+ if (!normalized || typeof normalized !== "object") {
421
+ errors.push({ message: "Normalized config invalid" });
422
+ }
423
+ if (typeof normalized.namespace !== "string") {
424
+ errors.push({ message: "namespace must be string" });
425
+ }
426
+ if (!Array.isArray(normalized.pipeline)) {
427
+ errors.push({ message: "pipeline must be array" });
428
+ }
429
+
430
+ // Validate pipeline entries have valid names
431
+ if (Array.isArray(normalized.pipeline)) {
432
+ for (const entry of normalized.pipeline) {
433
+ if (!entry || typeof entry !== "object") {
434
+ errors.push({ message: "Pipeline entry must be object" });
435
+ } else if (typeof entry.name !== "string") {
436
+ errors.push({
437
+ message: `Pipeline entry name must be string, got ${typeof entry.name}`,
438
+ });
439
+ } else if (typeof entry.stage !== "string") {
440
+ errors.push({
441
+ message: `Pipeline entry stage must be string, got ${typeof entry.stage}`,
442
+ });
443
+ }
444
+ }
445
+ }
446
+
447
+ // Check for normalization warnings (invalid entries that were filtered out)
448
+ if (normalized._warnings && Array.isArray(normalized._warnings)) {
449
+ for (const warning of normalized._warnings) {
450
+ errors.push({ message: warning });
451
+ }
452
+ }
453
+
454
+ return {
455
+ valid: errors.length === 0,
456
+ errors: errors.length ? errors : undefined,
457
+ normalized,
458
+ };
459
+ }
460
+
461
+ /**
462
+ * Legacy function for backward compatibility
463
+ * @deprecated Use validateRagrc instead
464
+ */
465
+ function validateEnhancedRagrcSchema(config) {
466
+ const result = validateRagrc(config);
467
+ return {
468
+ valid: result.valid,
469
+ errors: result.errors,
470
+ legacy: false,
471
+ };
472
+ }
473
+
474
+ /**
475
+ * Convert legacy _config to enhanced format
476
+ * @param {object} legacyConfig - Legacy configuration
477
+ * @returns {object} Enhanced configuration
478
+ */
479
+ function convertLegacyConfig(legacyConfig) {
480
+ const enhanced = {
481
+ plugins: {
482
+ loader: {},
483
+ embedder: {},
484
+ retriever: {},
485
+ llm: {},
486
+ },
487
+ };
488
+
489
+ // Convert plugin specifications
490
+ for (const [_type, plugins] of Object.entries(legacyConfig)) {
491
+ if (
492
+ ["loader", "embedder", "retriever", "llm", "reranker"].includes(_type)
493
+ ) {
494
+ enhanced.plugins[_type] = {};
495
+ for (const [name, spec] of Object.entries(plugins)) {
496
+ enhanced.plugins[_type][name] = typeof spec === "string" ? spec : spec;
497
+ }
498
+ }
499
+ }
500
+
501
+ // Convert pipeline configuration
502
+ if (legacyConfig.pipeline) {
503
+ enhanced.pipeline = {
504
+ stages: legacyConfig.pipeline,
505
+ };
506
+ }
507
+
508
+ // Add namespace as metadata
509
+ if (legacyConfig.namespace) {
510
+ enhanced.metadata = {
511
+ name: legacyConfig.namespace,
512
+ };
513
+ }
514
+
515
+ return enhanced;
516
+ }
517
+
518
+ /**
519
+ * Normalize plugin specification to object format
520
+ * @param {string|object} spec - Plugin specification
521
+ * @returns {object} Normalized specification
522
+ */
523
+ function normalizePluginSpec(spec) {
524
+ if (typeof spec === "string") {
525
+ return {
526
+ name: spec,
527
+ version: "latest",
528
+ source: "registry",
529
+ enabled: true,
530
+ };
531
+ }
532
+
533
+ return {
534
+ name: spec.name,
535
+ version: spec.version || "latest",
536
+ source: spec.source || "registry",
537
+ url: spec.url,
538
+ path: spec.path,
539
+ _config: spec._config || {},
540
+ enabled: spec.enabled !== false,
541
+ fallback: spec.fallback,
542
+ };
543
+ }
544
+
545
+ /**
546
+ * Extract plugin dependencies from configuration
547
+ * @param {object} _config - Enhanced configuration
548
+ * @returns {Array<{type: string, name: string, spec: object}>}
549
+ */
550
+ function extractPluginDependencies(config) {
551
+ const dependencies = [];
552
+
553
+ if (!config.plugins) {
554
+ return dependencies;
555
+ }
556
+
557
+ for (const [_type, plugins] of Object.entries(config.plugins)) {
558
+ for (const [name, spec] of Object.entries(plugins)) {
559
+ const normalizedSpec = normalizePluginSpec(spec);
560
+ dependencies.push({
561
+ _type,
562
+ name,
563
+ spec: normalizedSpec,
564
+ });
565
+ }
566
+ }
567
+
568
+ return dependencies;
569
+ }
570
+
571
+ /**
572
+ * Validate plugin configuration consistency
573
+ * @param {object} config - Configuration to validate
574
+ * @returns {{ valid: boolean, issues: Array<string> }}
575
+ */
576
+ function validateConfigConsistency(config) {
577
+ const issues = [];
578
+ // Check for required plugin types
579
+ const requiredTypes = ["loader", "embedder", "retriever", "llm"];
580
+ for (const _type of requiredTypes) {
581
+ if (
582
+ !config.plugins?.[_type] ||
583
+ Object.keys(config.plugins[_type]).length === 0
584
+ ) {
585
+ issues.push(`Missing required plugin type: ${_type}`);
586
+ }
587
+ }
588
+
589
+ // Check pipeline stages reference valid plugin types
590
+ if (config.pipeline?.stages) {
591
+ for (const stage of config.pipeline.stages) {
592
+ if (!config.plugins?.[stage]) {
593
+ issues.push(`Pipeline stage '${stage}' has no configured plugins`);
594
+ }
595
+ }
596
+ }
597
+
598
+ // Check fallback plugins exist
599
+ const dependencies = extractPluginDependencies(config);
600
+ for (const dep of dependencies) {
601
+ if (dep.spec.fallback) {
602
+ const fallbackExists = dependencies.some(
603
+ (d) => d._type === dep._type && d.name === dep.spec.fallback,
604
+ );
605
+ if (!fallbackExists) {
606
+ issues.push(
607
+ `Fallback plugin '${dep.spec.fallback}' not found for ${dep._type}:${dep.name}`,
608
+ );
609
+ }
610
+ }
611
+ }
612
+
613
+ return {
614
+ valid: issues.length === 0,
615
+ issues,
616
+ };
617
+ }
618
+
619
+ // Default export
620
+
621
+ module.exports = {
622
+ validateRagrc,
623
+ normalizeConfig,
624
+ buildRagrcJsonSchema,
625
+ validateEnhancedRagrcSchema, // Legacy compatibility
626
+ convertLegacyConfig,
627
+ normalizePluginSpec,
628
+ extractPluginDependencies,
629
+ validateConfigConsistency,
630
+ enhancedRagrcSchema,
631
+ legacyRagrcSchema,
632
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Version: 1.3.0
3
+ * Description: Loads and validates RAG pipeline configuration with proper error handling
4
+ * Author: Ali Kahwaji
5
+ */
6
+
7
+ const fs = require("fs"); // eslint-disable-line global-require
8
+ const path = require("path"); // eslint-disable-line global-require
9
+ const { validateRagrc } = require("./enhanced-ragrc-schema.js"); // eslint-disable-line global-require
10
+ const { logger } = require("../utils/logger.js"); // eslint-disable-line global-require
11
+
12
+ // Use CommonJS __dirname (already available in Node.js CommonJS modules)
13
+
14
+ const CONFIG_FILENAME = ".ragrc.json";
15
+
16
+ /**
17
+ * Load and validate a RAG configuration file.
18
+ * @param {string} [cwd=process.cwd()] - Directory to resolve the config from
19
+ * @returns {object} Validated configuration object
20
+ */
21
+ function loadRagConfig(cwd = process.cwd()) {
22
+ const configPath = path.resolve(cwd, CONFIG_FILENAME);
23
+
24
+ if (!fs.existsSync(configPath)) {
25
+ logger.error(`❌ Config file not found: ${configPath}`);
26
+ throw new Error(`Config file not found: ${configPath}`);
27
+ }
28
+
29
+ const raw = fs.readFileSync(configPath, "utf-8");
30
+ let config;
31
+
32
+ try {
33
+ config = JSON.parse(raw);
34
+ } catch (err) {
35
+ logger.error("❌ Failed to parse JSON configuration.");
36
+ throw new Error("Invalid JSON in config file.");
37
+ }
38
+
39
+ const { valid, errors, normalized } = validateRagrc(config);
40
+
41
+ if (!valid) {
42
+ logger.error(
43
+ `❌ Config validation failed:\n${JSON.stringify(errors, null, 2)}`,
44
+ );
45
+ throw new Error("Config validation failed");
46
+ }
47
+
48
+ logger.info("✅ Configuration loaded and normalized successfully");
49
+ return normalized;
50
+ }
51
+
52
+ module.exports = {
53
+ loadRagConfig,
54
+ };