@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,69 @@
1
+ /**
2
+ * Version: 1.1.1
3
+ * Description: Dynamic plugin loader with direct _type:name registry mapping
4
+ * Author: Ali Kahwaji
5
+ */
6
+
7
+ const fs = require("fs");
8
+ // eslint-disable-line global-require
9
+ const path = require("path");
10
+ // eslint-disable-line global-require
11
+ const { pathToFileURL } = require("url");
12
+ // eslint-disable-line global-require
13
+ const registry = require("../core/plugin-registry.js");
14
+ // eslint-disable-line global-require
15
+ const { validatePluginSchema } = require("./validate-schema.js");
16
+ // eslint-disable-line global-require
17
+ const { logger } = require("../utils/logger.js");
18
+ // eslint-disable-line global-require
19
+
20
+ /**
21
+ * Loads plugins from validated _config path and registers them.
22
+ * @param {string} configPath
23
+ */
24
+ async function loadPluginsFromJson(configPath) {
25
+ if (!fs.existsSync(configPath)) {
26
+ throw new Error(`Plugin _config missing: ${configPath}`);
27
+ }
28
+
29
+ const raw = fs.readFileSync(configPath, "utf-8");
30
+ const _config = JSON.parse(raw);
31
+
32
+ const validation = validatePluginSchema(_config);
33
+ if (!validation.valid) {
34
+ logger.error({ errors: validation.errors }, "Invalid plugin _config");
35
+ throw new Error("Plugin _config validation failed");
36
+ }
37
+
38
+ for (const [_type, namedPlugins] of Object.entries(_config)) {
39
+ if (!["loader", "embedder", "retriever", "llm"].includes(_type)) continue;
40
+
41
+ for (const [name, relPath] of Object.entries(namedPlugins)) {
42
+ const absPath = path.resolve(path.dirname(configPath), relPath);
43
+ const fileUrl = pathToFileURL(absPath).href;
44
+
45
+ try {
46
+ const mod = await import(fileUrl);
47
+ const PluginClass = mod?.default;
48
+ if (typeof PluginClass !== "function") {
49
+ throw new Error(
50
+ `Invalid export in plugin [${_type}:${name}] at ${absPath}`,
51
+ );
52
+ }
53
+
54
+ const _instance = new PluginClass();
55
+ registry.register(_type, name, _instance);
56
+
57
+ logger.info({ _type, name }, `Registered plugin: ${_type}:${name}`);
58
+ } catch (err) {
59
+ logger.error(
60
+ { _type, name, err },
61
+ `Failed to register plugin [${_type}:${name}]`,
62
+ );
63
+ throw err;
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ module.exports = { loadPluginsFromJson };
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Configuration Normalization - Unifies config shape and validation
3
+ * Handles pipeline object/array conversion and default namespace assignment
4
+ */
5
+
6
+ function normalizeConfig(cfg) {
7
+ if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) {
8
+ throw new TypeError("Configuration must be a non-null object");
9
+ }
10
+
11
+ // Track validation warnings for invalid entries that get filtered out
12
+ const warnings = [];
13
+
14
+ // Default namespace
15
+ const namespace = cfg.namespace || "default";
16
+
17
+ // Canonical pipeline: array of { stage, name, ...opts }
18
+ // Accept legacy object form like:
19
+ // { pipeline: { loader:{name:'x'}, embedder:{name:'y'} } }
20
+ // { plugins: { loader:'file-loader', embedder:'openai-embedder' } }
21
+ // and modern array form:
22
+ // { pipeline: [{stage:'loader', name:'x'}] }
23
+ const legacy =
24
+ (cfg.pipeline &&
25
+ !Array.isArray(cfg.pipeline) &&
26
+ typeof cfg.pipeline === "object") ||
27
+ (cfg.plugins && typeof cfg.plugins === "object");
28
+ const modern = Array.isArray(cfg.pipeline);
29
+
30
+ let pipeline = [];
31
+ if (modern) {
32
+ pipeline = cfg.pipeline
33
+ .filter(Boolean)
34
+ .map((p) => {
35
+ const entry = { stage: p.stage, name: p.name };
36
+ if (p.version) entry.version = p.version;
37
+ if (p.config) entry.config = p.config;
38
+ if (p.options) Object.assign(entry, p.options);
39
+ return entry;
40
+ })
41
+ .filter((p) => typeof p.stage === "string" && typeof p.name === "string");
42
+ } else if (legacy) {
43
+ const order = ["loader", "embedder", "retriever", "reranker", "llm"];
44
+ const source = cfg.pipeline || cfg.plugins;
45
+
46
+ for (const stage of order) {
47
+ const entry = source[stage];
48
+ if (entry) {
49
+ if (typeof entry === "string") {
50
+ // Simple format: { plugins: { loader: 'file-loader' } }
51
+ pipeline.push({ stage, name: entry });
52
+ } else if (
53
+ entry &&
54
+ typeof entry === "object" &&
55
+ typeof entry.name === "string"
56
+ ) {
57
+ // Complex format: { pipeline: { loader: { name: 'file-loader', version: '1.0.0', config: {}, options: {} } } }
58
+ const pipelineEntry = { stage, name: entry.name };
59
+ if (entry.version) pipelineEntry.version = entry.version;
60
+ if (entry.config) pipelineEntry.config = entry.config;
61
+ if (entry.options) Object.assign(pipelineEntry, entry.options);
62
+ pipeline.push(pipelineEntry);
63
+ } else if (entry && typeof entry === "object") {
64
+ // Invalid entry - has object but invalid name
65
+ if (typeof entry.name !== "string") {
66
+ warnings.push(
67
+ `Invalid ${stage} plugin name: expected string, got ${typeof entry.name}`,
68
+ );
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ // Ensure at least handles loader/embedder for legacy tests
76
+ // (empty array is allowed but tests expect 2 when legacy provided)
77
+ const metadata =
78
+ cfg.metadata && typeof cfg.metadata === "object" ? cfg.metadata : {};
79
+
80
+ const out = {
81
+ namespace,
82
+ metadata,
83
+ pipeline,
84
+ };
85
+
86
+ // Preserve known top-level fields (non-breaking)
87
+ const known = [
88
+ "cache",
89
+ "limits",
90
+ "plugins",
91
+ "observability",
92
+ "storage",
93
+ "performance",
94
+ ];
95
+ for (const k of known) if (k in cfg) out[k] = cfg[k];
96
+
97
+ // Add warnings if any invalid entries were encountered
98
+ if (warnings.length > 0) {
99
+ out._warnings = warnings;
100
+ }
101
+
102
+ return out;
103
+ }
104
+
105
+ module.exports = { normalizeConfig };
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Configuration Schema Validator - Enterprise-grade config validation
3
+ * Provides JSON Schema validation for all configuration files
4
+ */
5
+
6
+ const Ajv = require("ajv");
7
+ const addFormats = require("ajv-formats");
8
+ const { logger } = require("../utils/logger");
9
+
10
+ class ConfigSchemaValidator {
11
+ constructor() {
12
+ this.ajv = new Ajv({
13
+ allErrors: true,
14
+ verbose: true,
15
+ strict: false,
16
+ });
17
+ addFormats(this.ajv);
18
+
19
+ // Register custom formats
20
+ this.ajv.addFormat("semver", /^\d+\.\d+\.\d+(-[\w.-]+)?(\+[\w.-]+)?$/);
21
+ this.ajv.addFormat("log-level", /^(trace|debug|info|warn|error|fatal)$/);
22
+
23
+ this.schemas = new Map();
24
+ this._loadSchemas();
25
+ }
26
+
27
+ _loadSchemas() {
28
+ // Core pipeline configuration schema
29
+ const pipelineSchema = {
30
+ type: "object",
31
+ properties: {
32
+ version: { type: "string", format: "semver" },
33
+ name: { type: "string", minLength: 1 },
34
+ description: { type: "string" },
35
+ pipeline: {
36
+ type: "object",
37
+ properties: {
38
+ steps: {
39
+ type: "array",
40
+ items: {
41
+ type: "object",
42
+ properties: {
43
+ name: { type: "string", minLength: 1 },
44
+ type: {
45
+ type: "string",
46
+ enum: [
47
+ "ingest",
48
+ "chunk",
49
+ "embed",
50
+ "store",
51
+ "query",
52
+ "evaluate",
53
+ ],
54
+ },
55
+ config: { type: "object" },
56
+ enabled: { type: "boolean", default: true },
57
+ },
58
+ required: ["name", "type"],
59
+ additionalProperties: false,
60
+ },
61
+ minItems: 1,
62
+ },
63
+ concurrency: {
64
+ type: "integer",
65
+ minimum: 1,
66
+ maximum: 100,
67
+ default: 5,
68
+ },
69
+ timeout: { type: "integer", minimum: 1000, default: 30000 },
70
+ retries: { type: "integer", minimum: 0, maximum: 10, default: 3 },
71
+ },
72
+ required: ["steps"],
73
+ additionalProperties: false,
74
+ },
75
+ logging: {
76
+ type: "object",
77
+ properties: {
78
+ level: { type: "string", format: "log-level", default: "info" },
79
+ structured: { type: "boolean", default: true },
80
+ correlationId: { type: "boolean", default: true },
81
+ },
82
+ additionalProperties: false,
83
+ },
84
+ },
85
+ required: ["version", "name", "pipeline"],
86
+ additionalProperties: false,
87
+ };
88
+
89
+ // AI/ML configuration schema
90
+ const aiConfigSchema = {
91
+ type: "object",
92
+ properties: {
93
+ embeddings: {
94
+ type: "object",
95
+ properties: {
96
+ provider: {
97
+ type: "string",
98
+ enum: ["openai", "azure", "huggingface", "local"],
99
+ },
100
+ model: { type: "string", minLength: 1 },
101
+ dimensions: { type: "integer", minimum: 1, maximum: 4096 },
102
+ batchSize: {
103
+ type: "integer",
104
+ minimum: 1,
105
+ maximum: 1000,
106
+ default: 100,
107
+ },
108
+ timeout: { type: "integer", minimum: 1000, default: 30000 },
109
+ },
110
+ required: ["provider", "model"],
111
+ additionalProperties: false,
112
+ },
113
+ training: {
114
+ type: "object",
115
+ properties: {
116
+ batchSize: {
117
+ type: "integer",
118
+ minimum: 1,
119
+ maximum: 1024,
120
+ default: 32,
121
+ },
122
+ learningRate: {
123
+ type: "number",
124
+ minimum: 0.0001,
125
+ maximum: 1,
126
+ default: 0.001,
127
+ },
128
+ epochs: { type: "integer", minimum: 1, maximum: 1000, default: 10 },
129
+ validationSplit: {
130
+ type: "number",
131
+ minimum: 0,
132
+ maximum: 0.5,
133
+ default: 0.2,
134
+ },
135
+ },
136
+ additionalProperties: false,
137
+ },
138
+ federation: {
139
+ type: "object",
140
+ properties: {
141
+ minParticipants: {
142
+ type: "integer",
143
+ minimum: 2,
144
+ maximum: 1000,
145
+ default: 2,
146
+ },
147
+ maxParticipants: {
148
+ type: "integer",
149
+ minimum: 2,
150
+ maximum: 10000,
151
+ default: 100,
152
+ },
153
+ roundDuration: { type: "integer", minimum: 60000, default: 300000 },
154
+ convergenceThreshold: {
155
+ type: "number",
156
+ minimum: 0.0001,
157
+ maximum: 1,
158
+ default: 0.001,
159
+ },
160
+ },
161
+ additionalProperties: false,
162
+ },
163
+ },
164
+ additionalProperties: false,
165
+ };
166
+
167
+ // Security configuration schema
168
+ const securitySchema = {
169
+ type: "object",
170
+ properties: {
171
+ authentication: {
172
+ type: "object",
173
+ properties: {
174
+ enabled: { type: "boolean", default: true },
175
+ provider: {
176
+ type: "string",
177
+ enum: ["jwt", "oauth2", "api-key", "none"],
178
+ },
179
+ tokenExpiry: { type: "integer", minimum: 300, default: 3600 },
180
+ },
181
+ required: ["enabled", "provider"],
182
+ additionalProperties: false,
183
+ },
184
+ encryption: {
185
+ type: "object",
186
+ properties: {
187
+ algorithm: {
188
+ type: "string",
189
+ enum: ["aes-256-gcm", "aes-256-cbc", "chacha20-poly1305"],
190
+ },
191
+ keyRotation: { type: "boolean", default: true },
192
+ keyRotationInterval: {
193
+ type: "integer",
194
+ minimum: 86400,
195
+ default: 2592000,
196
+ },
197
+ },
198
+ additionalProperties: false,
199
+ },
200
+ audit: {
201
+ type: "object",
202
+ properties: {
203
+ enabled: { type: "boolean", default: true },
204
+ retention: { type: "integer", minimum: 86400, default: 7776000 },
205
+ sensitiveFields: {
206
+ type: "array",
207
+ items: { type: "string" },
208
+ default: ["password", "token", "key", "secret"],
209
+ },
210
+ },
211
+ additionalProperties: false,
212
+ },
213
+ },
214
+ additionalProperties: false,
215
+ };
216
+
217
+ this.schemas.set("pipeline", pipelineSchema);
218
+ this.schemas.set("ai", aiConfigSchema);
219
+ this.schemas.set("security", securitySchema);
220
+ }
221
+
222
+ validate(config, schemaName) {
223
+ const schema = this.schemas.get(schemaName);
224
+ if (!schema) {
225
+ throw new Error(`Unknown schema: ${schemaName}`);
226
+ }
227
+
228
+ const validate = this.ajv.compile(schema);
229
+ const valid = validate(config);
230
+
231
+ if (!valid) {
232
+ const errors = validate.errors.map((error) => ({
233
+ path: error.instancePath || error.schemaPath,
234
+ message: error.message,
235
+ value: error.data,
236
+ allowedValues: error.schema?.enum,
237
+ }));
238
+
239
+ logger.error("Configuration validation failed", {
240
+ schema: schemaName,
241
+ errors,
242
+ config: this._sanitizeConfig(config),
243
+ });
244
+
245
+ return {
246
+ valid: false,
247
+ errors,
248
+ };
249
+ }
250
+
251
+ logger.info("Configuration validation passed", {
252
+ schema: schemaName,
253
+ configKeys: Object.keys(config),
254
+ });
255
+
256
+ return {
257
+ valid: true,
258
+ errors: [],
259
+ };
260
+ }
261
+
262
+ validatePipeline(config) {
263
+ return this.validate(config, "pipeline");
264
+ }
265
+
266
+ validateAI(config) {
267
+ return this.validate(config, "ai");
268
+ }
269
+
270
+ validateSecurity(config) {
271
+ return this.validate(config, "security");
272
+ }
273
+
274
+ addSchema(name, schema) {
275
+ this.schemas.set(name, schema);
276
+ logger.info("Custom schema registered", { schemaName: name });
277
+ }
278
+
279
+ getSchema(name) {
280
+ return this.schemas.get(name);
281
+ }
282
+
283
+ listSchemas() {
284
+ return Array.from(this.schemas.keys());
285
+ }
286
+
287
+ _sanitizeConfig(config) {
288
+ // Remove sensitive fields from logs
289
+ const sensitiveFields = ["password", "token", "key", "secret", "apiKey"];
290
+ const sanitized = JSON.parse(JSON.stringify(config));
291
+
292
+ const sanitizeObject = (obj) => {
293
+ for (const [key, value] of Object.entries(obj)) {
294
+ if (
295
+ sensitiveFields.some((field) => key.toLowerCase().includes(field))
296
+ ) {
297
+ obj[key] = "[REDACTED]";
298
+ } else if (typeof value === "object" && value !== null) {
299
+ sanitizeObject(value);
300
+ }
301
+ }
302
+ };
303
+
304
+ sanitizeObject(sanitized);
305
+ return sanitized;
306
+ }
307
+ }
308
+
309
+ // Create singleton instance
310
+ const validator = new ConfigSchemaValidator();
311
+
312
+ module.exports = {
313
+ ConfigSchemaValidator,
314
+ validator,
315
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Version: 0.1.0
3
+ * Description: Schema validator for plugin._config.json
4
+ * Author: Ali Kahwaji
5
+ */
6
+
7
+ function validatePluginSchema(config) {
8
+ const validTypes = ["loader", "embedder", "retriever", "llm"];
9
+ const errors = [];
10
+
11
+ for (const _type of Object.keys(config)) {
12
+ if (!validTypes.includes(_type)) {
13
+ errors.push(`Unknown plugin _type: ${_type}`);
14
+ continue;
15
+ }
16
+ for (const [name, modulePath] of Object.entries(config[_type])) {
17
+ if (typeof name !== "string" || typeof modulePath !== "string") {
18
+ errors.push(
19
+ `Invalid plugin definition for _type "${_type}" and name "${name}"`,
20
+ );
21
+ }
22
+ }
23
+ }
24
+
25
+ return {
26
+ valid: errors.length === 0,
27
+ errors,
28
+ };
29
+ }
30
+
31
+ // Default export
32
+
33
+ module.exports = {
34
+ validatePluginSchema,
35
+ };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Version: 1.3.0
3
+ * Description: AJV-powered validators for .ragrc.json full _config and plugin-only structure
4
+ * Author: Ali Kahwaji
5
+ * File: /src/_config/validate-schema.js
6
+ */
7
+
8
+ const Ajv = require("ajv");
9
+ // eslint-disable-line global-require
10
+
11
+ /**
12
+ * Full .ragrc.json schema (used in load-_config.js)
13
+ */
14
+ const ragrcSchema = {
15
+ type: "object",
16
+ required: ["loader", "embedder", "retriever", "llm", "namespace", "pipeline"],
17
+ properties: {
18
+ loader: {
19
+ type: "object",
20
+ minProperties: 1,
21
+ additionalProperties: { type: "string" },
22
+ },
23
+ embedder: {
24
+ type: "object",
25
+ minProperties: 1,
26
+ additionalProperties: { type: "string" },
27
+ },
28
+ retriever: {
29
+ type: "object",
30
+ minProperties: 1,
31
+ additionalProperties: { type: "string" },
32
+ },
33
+ llm: {
34
+ type: "object",
35
+ minProperties: 1,
36
+ additionalProperties: { type: "string" },
37
+ },
38
+ namespace: {
39
+ type: "string",
40
+ minLength: 1,
41
+ },
42
+ pipeline: {
43
+ type: "array",
44
+ items: {
45
+ type: "string",
46
+ enum: ["loader", "embedder", "retriever"],
47
+ },
48
+ minItems: 1,
49
+ uniqueItems: true,
50
+ },
51
+ },
52
+ additionalProperties: false,
53
+ };
54
+
55
+ /**
56
+ * Minimal plugin-only schema (used in load-plugin-_config.js)
57
+ */
58
+ const pluginSchema = {
59
+ type: "object",
60
+ required: ["loader", "embedder", "retriever", "llm"],
61
+ properties: {
62
+ loader: {
63
+ type: "object",
64
+ minProperties: 1,
65
+ additionalProperties: { type: "string" },
66
+ },
67
+ embedder: {
68
+ type: "object",
69
+ minProperties: 1,
70
+ additionalProperties: { type: "string" },
71
+ },
72
+ retriever: {
73
+ type: "object",
74
+ minProperties: 1,
75
+ additionalProperties: { type: "string" },
76
+ },
77
+ llm: {
78
+ type: "object",
79
+ minProperties: 1,
80
+ additionalProperties: { type: "string" },
81
+ },
82
+ },
83
+ additionalProperties: true, // allow namespace, pipeline, etc.
84
+ };
85
+
86
+ /**
87
+ * Validates the full .ragrc.json _config structure
88
+ * @param {object} config
89
+ * @returns {{ valid: boolean, errors?: any[] }}
90
+ */
91
+ function validateRagrcSchema(config) {
92
+ const ajv = new Ajv({ allErrors: true, strict: false });
93
+ const validate = ajv.compile(ragrcSchema);
94
+ const valid = validate(config);
95
+ return valid ? { valid: true } : { valid: false, errors: validate.errors };
96
+ }
97
+
98
+ /**
99
+ * Validates a plugin-only structure (for runtime plugin loading)
100
+ * @param {object} config
101
+ * @returns {{ valid: boolean, errors?: any[] }}
102
+ */
103
+ function validatePluginSchema(config) {
104
+ const ajv = new Ajv({ allErrors: true, strict: false });
105
+ const validate = ajv.compile(pluginSchema);
106
+ const valid = validate(config);
107
+ return valid ? { valid: true } : { valid: false, errors: validate.errors };
108
+ }
109
+
110
+ module.exports = {
111
+ validateRagrcSchema,
112
+ validatePluginSchema,
113
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Plugin Contract Definitions
3
+ * Minimal fixture for test compatibility
4
+ */
5
+
6
+ const pluginContracts = {
7
+ loader: {
8
+ name: 'loader',
9
+ version: '1.0.0',
10
+ methods: ['load'],
11
+ description: 'Document loader contract',
12
+ },
13
+ embedder: {
14
+ name: 'embedder',
15
+ version: '1.0.0',
16
+ methods: ['embed', 'embedQuery'],
17
+ description: 'Text embedder contract',
18
+ },
19
+ retriever: {
20
+ name: 'retriever',
21
+ version: '1.0.0',
22
+ methods: ['store', 'retrieve'],
23
+ description: 'Vector retriever contract',
24
+ },
25
+ llm: {
26
+ name: 'llm',
27
+ version: '1.0.0',
28
+ methods: ['generate'],
29
+ description: 'Language model contract',
30
+ },
31
+ };
32
+
33
+ module.exports = { pluginContracts };