@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.
- package/.ragrc.schema.json +218 -0
- package/README.md +178 -550
- package/bin/cli.js +8 -14
- package/contracts/reranker-contract.json +69 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.mjs +22 -7
- package/package.json +18 -13
- package/src/ai/adaptive-retrieval.js +191 -0
- package/src/ai/federated-learning.js +214 -0
- package/src/ai/federation/federated-learning-coordinator.js +345 -0
- package/src/ai/federation.js +76 -0
- package/src/ai/index-fixed.js +509 -0
- package/src/ai/index.js +33 -0
- package/src/ai/model-trainer.js +217 -0
- package/src/ai/model-training.js +205 -0
- package/src/ai/module-template.js +37 -0
- package/src/ai/multimodal/multi-modal-processor.js +345 -0
- package/src/ai/multimodal-processing.js +268 -0
- package/src/ai/multimodal.js +71 -0
- package/src/ai/orchestrator.js +70 -0
- package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
- package/src/ai/retrieval-engine.js +69 -0
- package/src/ai/training/model-training-orchestrator.js +228 -0
- package/src/ci/workflow-analyzer.js +71 -0
- package/src/cli/commands/ai-ml.js +967 -0
- package/src/cli/commands/docs.js +228 -0
- package/src/cli/commands/dx.js +538 -0
- package/src/cli/commands/plugin-hub.js +875 -0
- package/src/cli/doctor-command.js +639 -0
- package/src/cli/enhanced-cli-commands.js +945 -0
- package/src/cli/interactive-wizard.js +997 -0
- package/src/cli/plugin-marketplace-commands.js +869 -0
- package/src/cli.js +17 -0
- package/src/config/enhanced-ragrc-schema.js +632 -0
- package/src/config/load-config.js +54 -0
- package/src/config/load-plugin-config.js +69 -0
- package/src/config/normalize-config.js +105 -0
- package/src/config/schema-validator.js +315 -0
- package/src/config/validate-plugin-schema.js +35 -0
- package/src/config/validate-schema.js +113 -0
- package/src/contracts/plugin-contracts.js +33 -0
- package/src/core/create-pipeline.js +99 -0
- package/src/core/dependency-injection.js +242 -0
- package/src/core/observability/event-logger.js +241 -0
- package/src/core/observability/instrumented-pipeline.js +609 -0
- package/src/core/observability/metrics.js +497 -0
- package/src/core/observability/tracing.js +781 -0
- package/src/core/performance/benchmark.js +516 -0
- package/src/core/performance/parallel-processor.js +240 -0
- package/src/core/performance/streaming-safeguards.js +620 -0
- package/src/core/pipeline-factory.js +60 -0
- package/src/core/plugin-contracts.js +89 -0
- package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
- package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
- package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
- package/src/core/plugin-marketplace/version-resolver.js +61 -0
- package/src/core/plugin-registry.js +294 -0
- package/src/dag/dag-engine.js +954 -0
- package/src/dag/dag-node.js +76 -0
- package/src/dag/enhanced-dag-engine.js +822 -0
- package/src/dx/index.js +40 -0
- package/src/dx/integration-templates.js +665 -0
- package/src/dx/performance-profiler.js +968 -0
- package/src/dx/realtime-debugger.js +755 -0
- package/src/dx/visual-pipeline-builder.js +578 -0
- package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
- package/src/ecosystem/plugin-certification.js +580 -0
- package/src/ecosystem/plugin-hub.js +821 -0
- package/src/enterprise/audit-logging.js +967 -0
- package/src/enterprise/data-governance.js +408 -0
- package/src/enterprise/multi-tenancy.js +496 -0
- package/src/enterprise/sso-integration.js +1030 -0
- package/src/evaluate/evaluator.js +52 -0
- package/src/evaluate/scoring.js +91 -0
- package/src/index.js +67 -0
- package/src/ingest.js +59 -0
- package/src/loader/csv-loader.js +38 -0
- package/src/loader/directory-loader.js +48 -0
- package/src/loader/html-loader.js +62 -0
- package/src/loader/markdown-loader.js +67 -0
- package/src/mocks/openai-embedder.js +119 -0
- package/src/mocks/openai-llm.js +77 -0
- package/src/mocks/pdf-loader.js +21 -0
- package/src/mocks/pinecone-retriever.js +106 -0
- package/src/observability/audit-logger.js +758 -0
- package/src/observability/dashboard-config.json +675 -0
- package/src/observability/event-logger.js +310 -0
- package/src/observability/metrics.js +691 -0
- package/src/observability/security-monitor.js +830 -0
- package/src/observability/slo-monitor.js +319 -0
- package/src/observability/telemetry.js +686 -0
- package/src/pipeline/pipeline.js +18 -0
- package/src/plugins/sample-embedder.js +53 -0
- package/src/plugins/sample-llm.js +30 -0
- package/src/plugins/sample-loader.js +24 -0
- package/src/plugins/sample-retriever.js +84 -0
- package/src/query.js +117 -0
- package/src/reranker/llm-reranker.js +111 -0
- package/src/scripts/script-utilities.js +36 -0
- package/src/security/plugin-sandbox.js +586 -0
- package/src/security/plugin-signature-verifier.js +414 -0
- package/src/security/validator.js +36 -0
- package/src/utils/ci/diagnostic-reporter.js +57 -0
- package/src/utils/logger.js +211 -0
- package/src/utils/performance-monitor.js +561 -0
- package/src/utils/plugin-scaffolder.js +447 -0
- package/src/utils/rate-limiter.js +244 -0
- package/src/utils/retry-policy.js +443 -0
- package/src/utils/retry.js +107 -0
- package/src/utils/safe-expression-evaluator.js +579 -0
- package/src/utils/secure-logging.js +338 -0
- package/src/utils/structured-logger.js +388 -0
- package/src/utils/validate-plugin-contract.js +42 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI/ML Module Index - Fixed CommonJS Exports
|
|
3
|
+
* Standardized exports for Jest/Node.js compatibility
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { EventEmitter } = require("events");
|
|
7
|
+
// eslint-disable-line global-require
|
|
8
|
+
const crypto = require("crypto");
|
|
9
|
+
// eslint-disable-line global-require
|
|
10
|
+
|
|
11
|
+
// Model Training Orchestrator
|
|
12
|
+
class ModelTrainingOrchestrator extends EventEmitter {
|
|
13
|
+
constructor(_options = {}) {
|
|
14
|
+
super();
|
|
15
|
+
this._config = {
|
|
16
|
+
batchSize: _options.batchSize || 32,
|
|
17
|
+
learningRate: _options.learningRate || 1e-4,
|
|
18
|
+
epochs: _options.epochs || 10,
|
|
19
|
+
};
|
|
20
|
+
this.trainingJobs = new Map();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async createTrainingJob(tenantId, _config = {}) {
|
|
24
|
+
const jobId = crypto.randomUUID();
|
|
25
|
+
const job = {
|
|
26
|
+
id: jobId,
|
|
27
|
+
tenantId,
|
|
28
|
+
status: "created",
|
|
29
|
+
_config,
|
|
30
|
+
createdAt: Date.now(),
|
|
31
|
+
progress: 0,
|
|
32
|
+
};
|
|
33
|
+
this.trainingJobs.set(jobId, job);
|
|
34
|
+
this.emit("jobCreated", { jobId, tenantId });
|
|
35
|
+
return jobId;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async startTraining(jobId, data = null, _config = {}) {
|
|
39
|
+
const job = this.trainingJobs.get(jobId);
|
|
40
|
+
if (!job) {
|
|
41
|
+
throw new Error(`Training job ${jobId} not found`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
job.status = "training";
|
|
45
|
+
job.startedAt = Date.now();
|
|
46
|
+
this.emit("trainingStarted", { jobId });
|
|
47
|
+
|
|
48
|
+
// Simulate training progress
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
job.progress = 0.5;
|
|
51
|
+
this.emit("progressUpdated", { jobId, progress: 0.5 });
|
|
52
|
+
}, 100);
|
|
53
|
+
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
job.status = "completed";
|
|
56
|
+
job.progress = 1.0;
|
|
57
|
+
job.completedAt = Date.now();
|
|
58
|
+
this.emit("trainingCompleted", { jobId });
|
|
59
|
+
}, 200);
|
|
60
|
+
|
|
61
|
+
return { jobId, status: "started" };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getTrainingStatus(jobId) {
|
|
65
|
+
return this.trainingJobs.get(jobId);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async stopTraining(jobId) {
|
|
69
|
+
const job = this.trainingJobs.get(jobId);
|
|
70
|
+
if (job && job.status === "training") {
|
|
71
|
+
job.status = "stopped";
|
|
72
|
+
this.emit("trainingStopped", { jobId });
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async deployModel(jobId, deploymentConfig = {}) {
|
|
79
|
+
const job = this.trainingJobs.get(jobId);
|
|
80
|
+
if (!job) {
|
|
81
|
+
throw new Error(`Training job ${jobId} not found`);
|
|
82
|
+
}
|
|
83
|
+
if (job.status !== "completed") {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Cannot deploy model: job ${jobId} is not completed (status: ${job.status})`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const deploymentId = crypto.randomUUID();
|
|
90
|
+
const deployment = {
|
|
91
|
+
id: deploymentId,
|
|
92
|
+
jobId,
|
|
93
|
+
modelId: `model_${jobId}`,
|
|
94
|
+
environment: deploymentConfig.environment || "production",
|
|
95
|
+
status: "deploying",
|
|
96
|
+
deployedAt: Date.now(),
|
|
97
|
+
_config: deploymentConfig,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Simulate deployment process
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
deployment.status = "deployed";
|
|
103
|
+
this.emit("modelDeployed", {
|
|
104
|
+
deploymentId,
|
|
105
|
+
jobId,
|
|
106
|
+
environment: deployment.environment,
|
|
107
|
+
});
|
|
108
|
+
}, 500);
|
|
109
|
+
|
|
110
|
+
this.emit("deploymentStarted", { deploymentId, jobId });
|
|
111
|
+
return deploymentId;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Adaptive Retrieval Engine
|
|
116
|
+
class AdaptiveRetrievalEngine extends EventEmitter {
|
|
117
|
+
constructor(_options = {}) {
|
|
118
|
+
super();
|
|
119
|
+
this._config = {
|
|
120
|
+
learning: {
|
|
121
|
+
algorithm: _options.algorithm || "contextual_bandit",
|
|
122
|
+
explorationRate: _options.explorationRate || 0.1,
|
|
123
|
+
learningRate: _options.learningRate || 0.01,
|
|
124
|
+
},
|
|
125
|
+
..._options,
|
|
126
|
+
};
|
|
127
|
+
this.userProfiles = new Map();
|
|
128
|
+
this.queryHistory = new Map();
|
|
129
|
+
this.feedbackHistory = [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async initializeUserProfile(userId, preferences = {}) {
|
|
133
|
+
const profile = {
|
|
134
|
+
userId,
|
|
135
|
+
interests: preferences.interests || [],
|
|
136
|
+
preferences: preferences,
|
|
137
|
+
createdAt: Date.now(),
|
|
138
|
+
interactions: 0,
|
|
139
|
+
personalizedRankings: new Map(),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
this.userProfiles.set(userId, profile);
|
|
143
|
+
this.emit("userProfileInitialized", { userId, profile });
|
|
144
|
+
return profile;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async generatePersonalizedRankings(userId, results, context = {}) {
|
|
148
|
+
const profile = this.userProfiles.get(userId);
|
|
149
|
+
if (!profile) {
|
|
150
|
+
throw new Error(`User profile not found for ${userId}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Simulate personalized ranking based on user interests
|
|
154
|
+
const rankedResults = results
|
|
155
|
+
.map((result, ___index) => ({
|
|
156
|
+
...result,
|
|
157
|
+
personalizedScore: Math.random() * 0.5 + 0.5,
|
|
158
|
+
relevanceFactors: profile.interests.slice(0, 2),
|
|
159
|
+
}))
|
|
160
|
+
.sort((a, b) => b.personalizedScore - a.personalizedScore);
|
|
161
|
+
|
|
162
|
+
this.emit("personalizedRankingsGenerated", {
|
|
163
|
+
userId,
|
|
164
|
+
resultsCount: rankedResults.length,
|
|
165
|
+
});
|
|
166
|
+
return rankedResults;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async optimizeRetrieval(query, context = {}) {
|
|
170
|
+
const optimizedQuery = `optimized: ${query}`;
|
|
171
|
+
const retrievalStrategy = "adaptive";
|
|
172
|
+
|
|
173
|
+
this.emit("retrievalOptimized", {
|
|
174
|
+
originalQuery: query,
|
|
175
|
+
optimizedQuery,
|
|
176
|
+
strategy: retrievalStrategy,
|
|
177
|
+
context,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
query: optimizedQuery,
|
|
182
|
+
strategy: retrievalStrategy,
|
|
183
|
+
confidence: Math.random() * 0.3 + 0.7,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Multi-Modal Processor
|
|
189
|
+
class MultiModalProcessor extends EventEmitter {
|
|
190
|
+
constructor(_options = {}) {
|
|
191
|
+
super();
|
|
192
|
+
this._config = {
|
|
193
|
+
supportedModalities: ["text", "image", "audio", "video"],
|
|
194
|
+
embeddingDimension: _options.embeddingDimension || 768,
|
|
195
|
+
..._options,
|
|
196
|
+
};
|
|
197
|
+
this.processors = new Map();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async processContent(content, modality, _options = {}) {
|
|
201
|
+
const processingId = crypto.randomUUID();
|
|
202
|
+
|
|
203
|
+
// Handle case where modality might be passed as an object
|
|
204
|
+
let modalityType = modality;
|
|
205
|
+
if (typeof modality === "object" && modality._type) {
|
|
206
|
+
modalityType = modality._type;
|
|
207
|
+
} else if (typeof modality === "object") {
|
|
208
|
+
modalityType = "text"; // Default fallback
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.emit("processingStarted", { processingId, modality: modalityType });
|
|
212
|
+
|
|
213
|
+
// Simulate processing based on modality
|
|
214
|
+
let result;
|
|
215
|
+
switch (modalityType) {
|
|
216
|
+
case "text":
|
|
217
|
+
result = await this._processText(content, _options);
|
|
218
|
+
break;
|
|
219
|
+
case "image":
|
|
220
|
+
result = await this._processImage(content, _options);
|
|
221
|
+
break;
|
|
222
|
+
case "audio":
|
|
223
|
+
result = await this._processAudio(content, _options);
|
|
224
|
+
break;
|
|
225
|
+
case "video":
|
|
226
|
+
result = await this._processVideo(content, _options);
|
|
227
|
+
break;
|
|
228
|
+
default:
|
|
229
|
+
throw new Error(
|
|
230
|
+
`Unsupported modality: ${modalityType} (original: ${JSON.stringify(modality)})`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.emit("processingCompleted", {
|
|
235
|
+
processingId,
|
|
236
|
+
modality: modalityType,
|
|
237
|
+
result,
|
|
238
|
+
});
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async _processText(content, ___options) {
|
|
243
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
244
|
+
return {
|
|
245
|
+
modality: "text",
|
|
246
|
+
embedding: Array.from({ length: this._config.embeddingDimension }, () =>
|
|
247
|
+
Math.random(),
|
|
248
|
+
),
|
|
249
|
+
features: {
|
|
250
|
+
length: content.length,
|
|
251
|
+
wordCount: content.split(" ").length,
|
|
252
|
+
},
|
|
253
|
+
processed: true,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async _processImage(___content, ___options) {
|
|
258
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
259
|
+
return {
|
|
260
|
+
modality: "image",
|
|
261
|
+
embedding: Array.from({ length: this._config.embeddingDimension }, () =>
|
|
262
|
+
Math.random(),
|
|
263
|
+
),
|
|
264
|
+
features: { width: 1024, height: 768, channels: 3 },
|
|
265
|
+
processed: true,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async _processAudio(___content, ___options) {
|
|
270
|
+
await new Promise((resolve) => setTimeout(resolve, 75));
|
|
271
|
+
return {
|
|
272
|
+
modality: "audio",
|
|
273
|
+
embedding: Array.from({ length: this._config.embeddingDimension }, () =>
|
|
274
|
+
Math.random(),
|
|
275
|
+
),
|
|
276
|
+
features: { duration: 30, sampleRate: 44100, channels: 2 },
|
|
277
|
+
processed: true,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async _processVideo(___content, ___options) {
|
|
282
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
283
|
+
return {
|
|
284
|
+
modality: "video",
|
|
285
|
+
embedding: Array.from({ length: this._config.embeddingDimension }, () =>
|
|
286
|
+
Math.random(),
|
|
287
|
+
),
|
|
288
|
+
features: { duration: 60, fps: 30, resolution: "1920x1080" },
|
|
289
|
+
processed: true,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Federated Learning Coordinator
|
|
295
|
+
class FederatedLearningCoordinator extends EventEmitter {
|
|
296
|
+
constructor(_options = {}) {
|
|
297
|
+
super();
|
|
298
|
+
this._config = {
|
|
299
|
+
minParticipants: _options.minParticipants || 2,
|
|
300
|
+
maxParticipants: _options.maxParticipants || 100,
|
|
301
|
+
roundDuration: _options.roundDuration || 300000,
|
|
302
|
+
convergenceThreshold: _options.convergenceThreshold || 0.001,
|
|
303
|
+
maxRounds: _options.maxRounds || 100,
|
|
304
|
+
..._options,
|
|
305
|
+
};
|
|
306
|
+
this.federations = new Map();
|
|
307
|
+
this.participants = new Map();
|
|
308
|
+
this.globalModels = new Map();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async createFederation(tenantId, modelConfig, federationConfig = {}) {
|
|
312
|
+
const federationId = crypto.randomUUID();
|
|
313
|
+
const federation = {
|
|
314
|
+
id: federationId,
|
|
315
|
+
tenantId,
|
|
316
|
+
modelConfig,
|
|
317
|
+
status: "created",
|
|
318
|
+
currentRound: 0,
|
|
319
|
+
minParticipants:
|
|
320
|
+
federationConfig.minParticipants || this._config.minParticipants,
|
|
321
|
+
maxParticipants:
|
|
322
|
+
federationConfig.maxParticipants || this._config.maxParticipants,
|
|
323
|
+
convergenceThreshold:
|
|
324
|
+
federationConfig.convergenceThreshold ||
|
|
325
|
+
this._config.convergenceThreshold,
|
|
326
|
+
maxRounds: federationConfig.maxRounds || this._config.maxRounds,
|
|
327
|
+
createdAt: Date.now(),
|
|
328
|
+
participants: [],
|
|
329
|
+
convergenceHistory: [],
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
this.federations.set(federationId, federation);
|
|
333
|
+
this.emit("federationCreated", { federationId, tenantId });
|
|
334
|
+
return federationId;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async registerParticipant(federationId, participantInfo) {
|
|
338
|
+
const federation = this.federations.get(federationId);
|
|
339
|
+
if (!federation) {
|
|
340
|
+
throw new Error(`Federation ${federationId} not found`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Validate participant eligibility
|
|
344
|
+
if (participantInfo.dataSize < 100) {
|
|
345
|
+
throw new Error("Participant not eligible: Insufficient data size");
|
|
346
|
+
}
|
|
347
|
+
if (participantInfo.computeCapacity < 0.1) {
|
|
348
|
+
throw new Error(
|
|
349
|
+
"Participant not eligible: Insufficient compute capacity",
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const participantId = crypto.randomUUID();
|
|
354
|
+
const participant = {
|
|
355
|
+
id: participantId,
|
|
356
|
+
federationId,
|
|
357
|
+
tenantId: participantInfo.tenantId,
|
|
358
|
+
status: "active",
|
|
359
|
+
dataSize: participantInfo.dataSize || 1000,
|
|
360
|
+
computeCapacity: participantInfo.computeCapacity || 0.5,
|
|
361
|
+
privacyLevel: participantInfo.privacyLevel || "standard",
|
|
362
|
+
performance: {
|
|
363
|
+
rounds: 0,
|
|
364
|
+
accuracy: 0.5,
|
|
365
|
+
loss: 1.0,
|
|
366
|
+
avgTrainingTime: 45000,
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
this.participants.set(participantId, participant);
|
|
371
|
+
this.emit("participantRegistered", { federationId, participantId });
|
|
372
|
+
return participantId;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async startFederatedRound(federationId) {
|
|
376
|
+
const federation = this.federations.get(federationId);
|
|
377
|
+
if (!federation) {
|
|
378
|
+
throw new Error(`Federation ${federationId} not found`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const roundId = crypto.randomUUID();
|
|
382
|
+
|
|
383
|
+
// Get or create participants
|
|
384
|
+
let selectedParticipants = Array.from(this.participants.values()).filter(
|
|
385
|
+
(p) => p.federationId === federationId && p.status === "active",
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
if (selectedParticipants.length === 0) {
|
|
389
|
+
// Create mock participants for testing
|
|
390
|
+
for (let i = 0; i < federation.minParticipants; i++) {
|
|
391
|
+
const mockParticipant = {
|
|
392
|
+
id: `mock_participant_${i}`,
|
|
393
|
+
tenantId: `tenant_${i}`,
|
|
394
|
+
federationId: federationId,
|
|
395
|
+
status: "active",
|
|
396
|
+
dataSize: 1000 + Math.random() * 5000,
|
|
397
|
+
computeCapacity: 0.5 + Math.random() * 0.5,
|
|
398
|
+
privacyLevel: "standard",
|
|
399
|
+
performance: {
|
|
400
|
+
rounds: 0,
|
|
401
|
+
accuracy: 0.5,
|
|
402
|
+
loss: 1.0,
|
|
403
|
+
avgTrainingTime: 45000,
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
this.participants.set(mockParticipant.id, mockParticipant);
|
|
407
|
+
selectedParticipants.push(mockParticipant);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Simulate federated round
|
|
412
|
+
const modelUpdates = selectedParticipants.map((participant) => ({
|
|
413
|
+
participantId: participant.id,
|
|
414
|
+
modelDelta: Array.from({ length: 100 }, () => Math.random() * 0.01),
|
|
415
|
+
metadata: {
|
|
416
|
+
localAccuracy: 0.6 + Math.random() * 0.3,
|
|
417
|
+
localLoss: 0.1 + Math.random() * 0.4,
|
|
418
|
+
trainingTime: 30000 + Math.random() * 60000,
|
|
419
|
+
},
|
|
420
|
+
}));
|
|
421
|
+
|
|
422
|
+
// Simulate aggregation
|
|
423
|
+
const aggregatedModel = {
|
|
424
|
+
id: crypto.randomUUID(),
|
|
425
|
+
parameters: Array.from({ length: 100 }, () => Math.random()),
|
|
426
|
+
accuracy: 0.7 + Math.random() * 0.2,
|
|
427
|
+
loss: 0.2 + Math.random() * 0.3,
|
|
428
|
+
round: federation.currentRound + 1,
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
federation.currentRound++;
|
|
432
|
+
federation.lastRoundAt = Date.now();
|
|
433
|
+
|
|
434
|
+
this.emit("federatedRoundCompleted", {
|
|
435
|
+
federationId,
|
|
436
|
+
roundId,
|
|
437
|
+
round: federation.currentRound,
|
|
438
|
+
participants: selectedParticipants.length,
|
|
439
|
+
globalAccuracy: aggregatedModel.accuracy,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
roundId,
|
|
444
|
+
round: federation.currentRound,
|
|
445
|
+
participants: selectedParticipants.length,
|
|
446
|
+
convergence: {
|
|
447
|
+
converged: false,
|
|
448
|
+
globalAccuracy: aggregatedModel.accuracy,
|
|
449
|
+
},
|
|
450
|
+
nextRoundScheduled: federation.currentRound < federation.maxRounds,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async getFederationStats(federationId) {
|
|
455
|
+
const federation = this.federations.get(federationId);
|
|
456
|
+
if (!federation) {
|
|
457
|
+
throw new Error(`Federation ${federationId} not found`);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const participants = Array.from(this.participants.values()).filter(
|
|
461
|
+
(p) => p.federationId === federationId,
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
federation: {
|
|
466
|
+
id: federationId,
|
|
467
|
+
status: federation.status,
|
|
468
|
+
currentRound: federation.currentRound,
|
|
469
|
+
totalParticipants: participants.length,
|
|
470
|
+
activeParticipants: participants.filter((p) => p.status === "active")
|
|
471
|
+
.length,
|
|
472
|
+
createdAt: federation.createdAt,
|
|
473
|
+
},
|
|
474
|
+
performance: {
|
|
475
|
+
averageAccuracy:
|
|
476
|
+
participants.length > 0
|
|
477
|
+
? participants.reduce((sum, p) => sum + p.performance.accuracy, 0) /
|
|
478
|
+
participants.length
|
|
479
|
+
: 0,
|
|
480
|
+
totalDataSize: participants.reduce((sum, p) => sum + p.dataSize, 0),
|
|
481
|
+
averageTrainingTime:
|
|
482
|
+
participants.length > 0
|
|
483
|
+
? participants.reduce(
|
|
484
|
+
(sum, p) => sum + p.performance.avgTrainingTime,
|
|
485
|
+
0,
|
|
486
|
+
) / participants.length
|
|
487
|
+
: 0,
|
|
488
|
+
},
|
|
489
|
+
participants: participants.map((p) => ({
|
|
490
|
+
id: p.id,
|
|
491
|
+
tenantId: p.tenantId,
|
|
492
|
+
dataSize: p.dataSize,
|
|
493
|
+
performance: p.performance,
|
|
494
|
+
privacyLevel: p.privacyLevel,
|
|
495
|
+
status: p.status,
|
|
496
|
+
})),
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// CRITICAL: Use standardized CommonJS export pattern
|
|
502
|
+
module.exports = {
|
|
503
|
+
ModelTrainingOrchestrator,
|
|
504
|
+
AdaptiveRetrievalEngine,
|
|
505
|
+
MultiModalProcessor,
|
|
506
|
+
FederatedLearningCoordinator,
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// Ensure module.exports is properly defined
|
package/src/ai/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI/ML Module Index - Decomposed Architecture
|
|
3
|
+
* Provides unified interface to 4 separate AI modules as required by CLAUDE.md
|
|
4
|
+
*
|
|
5
|
+
* Decomposed modules:
|
|
6
|
+
* - orchestrator.js - ModelTrainingOrchestrator
|
|
7
|
+
* - retrieval-engine.js - AdaptiveRetrievalEngine
|
|
8
|
+
* - multimodal.js - MultiModalProcessor
|
|
9
|
+
* - federation.js - FederatedLearningCoordinator
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const orchestrator = require("./orchestrator");
|
|
13
|
+
const retrievalEngine = require("./retrieval-engine");
|
|
14
|
+
const multimodal = require("./multimodal");
|
|
15
|
+
const federation = require("./federation");
|
|
16
|
+
|
|
17
|
+
// Export the decomposed modules
|
|
18
|
+
module.exports = {
|
|
19
|
+
// Primary exports with new decomposed architecture
|
|
20
|
+
ModelTrainingOrchestrator: orchestrator,
|
|
21
|
+
AdaptiveRetrievalEngine: retrievalEngine,
|
|
22
|
+
MultiModalProcessor: multimodal,
|
|
23
|
+
FederatedLearningCoordinator: federation,
|
|
24
|
+
|
|
25
|
+
// Legacy names for backward compatibility
|
|
26
|
+
modelTrainer: orchestrator,
|
|
27
|
+
adaptiveRetrieval: retrievalEngine,
|
|
28
|
+
multiModalProcessor: multimodal,
|
|
29
|
+
federatedLearning: federation,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// CJS+ESM interop pattern
|
|
33
|
+
module.exports.default = module.exports;
|