@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.
- package/.ragrc.schema.json +218 -0
- package/README.md +292 -32
- package/bin/cli.js +8 -14
- package/dist/index.d.ts +237 -0
- package/dist/index.mjs +22 -7
- package/package.json +17 -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 +611 -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 +265 -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 +903 -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 +85 -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/retry-policy.js +443 -0
- package/src/utils/retry.js +107 -0
- package/src/utils/safe-expression-evaluator.js +579 -0
- package/src/utils/structured-logger.js +361 -0
- package/src/utils/validate-plugin-contract.js +42 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const { PluginRegistry } = require('./plugin-registry.js');
|
|
3
|
+
|
|
4
|
+
const defaultRegistry = new PluginRegistry();
|
|
5
|
+
|
|
6
|
+
function resolve(registry, type, value) {
|
|
7
|
+
const reg = registry || defaultRegistry;
|
|
8
|
+
return typeof value === 'string' ? reg.get(type, value) : value;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function withTimeout(promise, ms) {
|
|
12
|
+
if (!ms) return promise;
|
|
13
|
+
return Promise.race([
|
|
14
|
+
promise,
|
|
15
|
+
new Promise((_, rej) =>
|
|
16
|
+
setTimeout(() => rej(new Error('Execution timeout')), ms),
|
|
17
|
+
),
|
|
18
|
+
]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports.createRagPipeline = function createRagPipeline({
|
|
22
|
+
registry,
|
|
23
|
+
loader,
|
|
24
|
+
embedder,
|
|
25
|
+
retriever,
|
|
26
|
+
llm,
|
|
27
|
+
reranker,
|
|
28
|
+
} = {}) {
|
|
29
|
+
const reg = registry || defaultRegistry;
|
|
30
|
+
const loaderI = loader ? resolve(reg, 'loader', loader) : null;
|
|
31
|
+
const embedderI = embedder ? resolve(reg, 'embedder', embedder) : null;
|
|
32
|
+
const retrieverI = retriever
|
|
33
|
+
? resolve(reg, 'retriever', retriever)
|
|
34
|
+
: {
|
|
35
|
+
async retrieve() {
|
|
36
|
+
return [];
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const llmI = llm
|
|
40
|
+
? resolve(reg, 'llm', llm)
|
|
41
|
+
: {
|
|
42
|
+
async generate() {
|
|
43
|
+
return 'ok';
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const rerankerI = reranker ? resolve(reg, 'reranker', reranker) : null;
|
|
47
|
+
|
|
48
|
+
async function runOnce({ query, queryVector, options = {} }) {
|
|
49
|
+
const { timeout, stream } = options || {};
|
|
50
|
+
const doWork = (async () => {
|
|
51
|
+
if (loaderI?.load) await loaderI.load();
|
|
52
|
+
if (embedderI?.embed && query) await embedderI.embed(query);
|
|
53
|
+
|
|
54
|
+
const docs = await retrieverI.retrieve({
|
|
55
|
+
query,
|
|
56
|
+
queryVector,
|
|
57
|
+
topK: options.topK ?? 3,
|
|
58
|
+
});
|
|
59
|
+
let results = docs;
|
|
60
|
+
if (rerankerI?.rerank && Array.isArray(docs) && docs.length) {
|
|
61
|
+
results = await rerankerI.rerank(query || '', docs, {
|
|
62
|
+
topK: options.topK ?? docs.length,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (stream) {
|
|
67
|
+
// Use streaming generate if available
|
|
68
|
+
if (llmI.generateStream) {
|
|
69
|
+
const streamResult = llmI.generateStream(query, results, options);
|
|
70
|
+
return streamResult;
|
|
71
|
+
} else if (llmI.generate) {
|
|
72
|
+
// Fallback: simulate streaming from regular generate
|
|
73
|
+
const answer = (await llmI.generate(query, results, options)) ?? '';
|
|
74
|
+
async function* gen() {
|
|
75
|
+
const chunks = String(answer || '').length
|
|
76
|
+
? [String(answer)]
|
|
77
|
+
: [''];
|
|
78
|
+
for (const c of chunks) yield { token: c, done: false };
|
|
79
|
+
yield { token: '', done: true };
|
|
80
|
+
}
|
|
81
|
+
return gen();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const answer = (await llmI.generate?.(query, results, options)) ?? '';
|
|
86
|
+
// tiny delay so durations > 0 in timing tests
|
|
87
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
88
|
+
return { success: true, query, results };
|
|
89
|
+
})();
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
return await withTimeout(doWork, timeout);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return { success: false, error: String(e.message || e) };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { run: runOnce, cleanup() {} };
|
|
99
|
+
};
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Injection Container - IoC implementation
|
|
3
|
+
* Addresses architectural anti-pattern: Hard-coded dependencies
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { logger } = require('../utils/logger');
|
|
7
|
+
|
|
8
|
+
class DependencyContainer {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.services = new Map();
|
|
11
|
+
this.singletons = new Map();
|
|
12
|
+
this.factories = new Map();
|
|
13
|
+
this.interfaces = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Register a service with the container
|
|
18
|
+
*/
|
|
19
|
+
register(name, implementation, options = {}) {
|
|
20
|
+
const { singleton = false, factory = false, interfaces = [] } = options;
|
|
21
|
+
|
|
22
|
+
if (factory) {
|
|
23
|
+
this.factories.set(name, implementation);
|
|
24
|
+
} else {
|
|
25
|
+
this.services.set(name, { implementation, singleton });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Register interface mappings
|
|
29
|
+
interfaces.forEach((interfaceName) => {
|
|
30
|
+
if (!this.interfaces.has(interfaceName)) {
|
|
31
|
+
this.interfaces.set(interfaceName, []);
|
|
32
|
+
}
|
|
33
|
+
this.interfaces.get(interfaceName).push(name);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
logger.debug('Service registered', {
|
|
37
|
+
service: name,
|
|
38
|
+
singleton,
|
|
39
|
+
factory,
|
|
40
|
+
interfaces,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Resolve a service from the container
|
|
48
|
+
*/
|
|
49
|
+
resolve(name) {
|
|
50
|
+
// Check if it's a factory
|
|
51
|
+
if (this.factories.has(name)) {
|
|
52
|
+
const factory = this.factories.get(name);
|
|
53
|
+
return factory(this);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if it's a regular service
|
|
57
|
+
if (this.services.has(name)) {
|
|
58
|
+
const { implementation, singleton } = this.services.get(name);
|
|
59
|
+
|
|
60
|
+
if (singleton) {
|
|
61
|
+
if (!this.singletons.has(name)) {
|
|
62
|
+
const instance = this._createInstance(implementation);
|
|
63
|
+
this.singletons.set(name, instance);
|
|
64
|
+
}
|
|
65
|
+
return this.singletons.get(name);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this._createInstance(implementation);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check if it's an interface
|
|
72
|
+
if (this.interfaces.has(name)) {
|
|
73
|
+
const implementations = this.interfaces.get(name);
|
|
74
|
+
if (implementations.length === 1) {
|
|
75
|
+
return this.resolve(implementations[0]);
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`Multiple implementations found for interface: ${name}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
throw new Error(`Service not found: ${name}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolve all implementations of an interface
|
|
85
|
+
*/
|
|
86
|
+
resolveAll(interfaceName) {
|
|
87
|
+
if (!this.interfaces.has(interfaceName)) {
|
|
88
|
+
throw new Error(`Interface not found: ${interfaceName}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const implementations = this.interfaces.get(interfaceName);
|
|
92
|
+
return implementations.map((name) => this.resolve(name));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if a service is registered
|
|
97
|
+
*/
|
|
98
|
+
has(name) {
|
|
99
|
+
return (
|
|
100
|
+
this.services.has(name) ||
|
|
101
|
+
this.factories.has(name) ||
|
|
102
|
+
this.interfaces.has(name)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Create an instance with dependency injection
|
|
108
|
+
*/
|
|
109
|
+
_createInstance(implementation) {
|
|
110
|
+
if (typeof implementation === 'function') {
|
|
111
|
+
// Check if it's a class constructor
|
|
112
|
+
if (
|
|
113
|
+
implementation.prototype &&
|
|
114
|
+
implementation.prototype.constructor === implementation
|
|
115
|
+
) {
|
|
116
|
+
return new implementation(this);
|
|
117
|
+
}
|
|
118
|
+
// It's a factory function
|
|
119
|
+
return implementation(this);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// It's already an instance
|
|
123
|
+
return implementation;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Clear all registrations (useful for testing)
|
|
128
|
+
*/
|
|
129
|
+
clear() {
|
|
130
|
+
this.services.clear();
|
|
131
|
+
this.singletons.clear();
|
|
132
|
+
this.factories.clear();
|
|
133
|
+
this.interfaces.clear();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get container statistics
|
|
138
|
+
*/
|
|
139
|
+
getStats() {
|
|
140
|
+
return {
|
|
141
|
+
services: this.services.size,
|
|
142
|
+
singletons: this.singletons.size,
|
|
143
|
+
factories: this.factories.size,
|
|
144
|
+
interfaces: this.interfaces.size,
|
|
145
|
+
totalRegistrations: this.services.size + this.factories.size,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Decorator for automatic dependency injection
|
|
152
|
+
*/
|
|
153
|
+
function injectable(dependencies = []) {
|
|
154
|
+
return function (target) {
|
|
155
|
+
target.$dependencies = dependencies;
|
|
156
|
+
return target;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Service locator pattern implementation
|
|
162
|
+
*/
|
|
163
|
+
class ServiceLocator {
|
|
164
|
+
static container = new DependencyContainer();
|
|
165
|
+
|
|
166
|
+
static register(name, implementation, options) {
|
|
167
|
+
return this.container.register(name, implementation, options);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static resolve(name) {
|
|
171
|
+
return this.container.resolve(name);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static has(name) {
|
|
175
|
+
return this.container.has(name);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
static clear() {
|
|
179
|
+
this.container.clear();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Configuration-based container setup
|
|
185
|
+
*/
|
|
186
|
+
class ContainerBuilder {
|
|
187
|
+
constructor() {
|
|
188
|
+
this.container = new DependencyContainer();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Load services from configuration
|
|
193
|
+
*/
|
|
194
|
+
loadFromConfig(config) {
|
|
195
|
+
const { services = {} } = config;
|
|
196
|
+
|
|
197
|
+
Object.entries(services).forEach(([name, serviceConfig]) => {
|
|
198
|
+
const {
|
|
199
|
+
implementation,
|
|
200
|
+
singleton = false,
|
|
201
|
+
factory = false,
|
|
202
|
+
interfaces = [],
|
|
203
|
+
} = serviceConfig;
|
|
204
|
+
|
|
205
|
+
// Resolve implementation from string path
|
|
206
|
+
let impl = implementation;
|
|
207
|
+
if (typeof implementation === 'string') {
|
|
208
|
+
impl = require(implementation);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.container.register(name, impl, {
|
|
212
|
+
singleton,
|
|
213
|
+
factory,
|
|
214
|
+
interfaces,
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
logger.info('Container loaded from configuration', {
|
|
219
|
+
servicesCount: Object.keys(services).length,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return this.container;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
build() {
|
|
226
|
+
return this.container;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Default container instance
|
|
231
|
+
const defaultContainer = new DependencyContainer();
|
|
232
|
+
|
|
233
|
+
// Register core services
|
|
234
|
+
defaultContainer.register('logger', logger, { singleton: true });
|
|
235
|
+
|
|
236
|
+
module.exports = {
|
|
237
|
+
DependencyContainer,
|
|
238
|
+
ServiceLocator,
|
|
239
|
+
ContainerBuilder,
|
|
240
|
+
injectable,
|
|
241
|
+
defaultContainer,
|
|
242
|
+
};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EventTypes = {
|
|
4
|
+
PLUGIN_START: 'plugin.start',
|
|
5
|
+
PLUGIN_END: 'plugin.end',
|
|
6
|
+
PLUGIN_ERROR: 'plugin.error',
|
|
7
|
+
STAGE_START: 'stage.start',
|
|
8
|
+
STAGE_ERROR: 'stage.error',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const EventSeverity = { DEBUG: 'debug', INFO: 'info', ERROR: 'error' };
|
|
12
|
+
|
|
13
|
+
class PipelineEventLogger {
|
|
14
|
+
constructor() {
|
|
15
|
+
this._events = [];
|
|
16
|
+
this._sessionId = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
startSession() {
|
|
20
|
+
this._sessionId = `session_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
21
|
+
this._sessionStartTime = new Date().toISOString();
|
|
22
|
+
return this._sessionId;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
nowISO() {
|
|
26
|
+
return new Date().toISOString();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getInputSize(v) {
|
|
30
|
+
if (Array.isArray(v)) return { type: 'array', length: v.length };
|
|
31
|
+
if (typeof v === 'string') return { type: 'string', length: v.length };
|
|
32
|
+
if (v === null) return { type: 'object' }; // align with tests
|
|
33
|
+
if (typeof v === 'object')
|
|
34
|
+
return { type: 'object', keys: Object.keys(v).length };
|
|
35
|
+
return { type: typeof v };
|
|
36
|
+
}
|
|
37
|
+
getResultSize(v) {
|
|
38
|
+
return this.getInputSize(v);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
logPluginStart({ pluginType, pluginName, input, context = {} }) {
|
|
42
|
+
this._events.push({
|
|
43
|
+
timestamp: this.nowISO(),
|
|
44
|
+
severity: EventSeverity.DEBUG,
|
|
45
|
+
sessionId: this._sessionId || this.startSession(),
|
|
46
|
+
eventType: EventTypes.PLUGIN_START,
|
|
47
|
+
message: `Starting ${pluginType} plugin: ${pluginName}`,
|
|
48
|
+
metadata: {
|
|
49
|
+
stage: 'start',
|
|
50
|
+
pluginType,
|
|
51
|
+
pluginName,
|
|
52
|
+
inputSize: this.getInputSize(input),
|
|
53
|
+
context,
|
|
54
|
+
pid: process.pid,
|
|
55
|
+
platform: process.platform,
|
|
56
|
+
nodeVersion: process.version,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
logPluginEnd({
|
|
62
|
+
pluginType,
|
|
63
|
+
pluginName,
|
|
64
|
+
duration,
|
|
65
|
+
result,
|
|
66
|
+
status = 'success',
|
|
67
|
+
context = {},
|
|
68
|
+
}) {
|
|
69
|
+
const md = {
|
|
70
|
+
stage: 'end',
|
|
71
|
+
pluginType,
|
|
72
|
+
pluginName,
|
|
73
|
+
duration,
|
|
74
|
+
status,
|
|
75
|
+
context,
|
|
76
|
+
pid: process.pid,
|
|
77
|
+
platform: process.platform,
|
|
78
|
+
nodeVersion: process.version,
|
|
79
|
+
};
|
|
80
|
+
if (Array.isArray(result?.vectors))
|
|
81
|
+
md.resultSize = { vectorCount: result.vectors.length };
|
|
82
|
+
else if (Array.isArray(result))
|
|
83
|
+
md.resultSize = { vectorCount: result.length };
|
|
84
|
+
|
|
85
|
+
this._events.push({
|
|
86
|
+
timestamp: this.nowISO(),
|
|
87
|
+
severity: EventSeverity.DEBUG,
|
|
88
|
+
sessionId: this._sessionId || this.startSession(),
|
|
89
|
+
eventType: EventTypes.PLUGIN_END,
|
|
90
|
+
message: `Completed ${pluginType} plugin: ${pluginName} (${duration}ms)`,
|
|
91
|
+
metadata: md,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
logPluginError({ pluginType, pluginName, duration, error, context = {} }) {
|
|
96
|
+
this._events.push({
|
|
97
|
+
timestamp: this.nowISO(),
|
|
98
|
+
severity: EventSeverity.ERROR,
|
|
99
|
+
sessionId: this._sessionId || this.startSession(),
|
|
100
|
+
eventType: EventTypes.PLUGIN_ERROR,
|
|
101
|
+
message: `Failed ${pluginType} plugin: ${pluginName} - ${error?.message}`,
|
|
102
|
+
metadata: {
|
|
103
|
+
stage: 'error',
|
|
104
|
+
pluginType,
|
|
105
|
+
pluginName,
|
|
106
|
+
duration,
|
|
107
|
+
status: 'error',
|
|
108
|
+
error: error
|
|
109
|
+
? { name: error.name, message: error.message, code: error.code }
|
|
110
|
+
: undefined,
|
|
111
|
+
context,
|
|
112
|
+
pid: process.pid,
|
|
113
|
+
platform: process.platform,
|
|
114
|
+
nodeVersion: process.version,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
logStageStart(stage) {
|
|
120
|
+
this._events.push({
|
|
121
|
+
timestamp: this.nowISO(),
|
|
122
|
+
severity: EventSeverity.INFO,
|
|
123
|
+
sessionId: this._sessionId || this.startSession(),
|
|
124
|
+
eventType: EventTypes.STAGE_START,
|
|
125
|
+
message: `Starting pipeline stage: ${stage}`,
|
|
126
|
+
metadata: {
|
|
127
|
+
stage,
|
|
128
|
+
pid: process.pid,
|
|
129
|
+
platform: process.platform,
|
|
130
|
+
nodeVersion: process.version,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
logMemoryWarning({ memoryUsage, threshold = 512 }) {
|
|
136
|
+
const usedBytes =
|
|
137
|
+
typeof memoryUsage?.heapUsed === 'number'
|
|
138
|
+
? memoryUsage.heapUsed
|
|
139
|
+
: typeof memoryUsage?.rss === 'number'
|
|
140
|
+
? memoryUsage.rss
|
|
141
|
+
: 0;
|
|
142
|
+
const usedMB = usedBytes / (1024 * 1024);
|
|
143
|
+
const usagePercentage = +((usedMB / threshold) * 100).toFixed(2);
|
|
144
|
+
|
|
145
|
+
this._events.push({
|
|
146
|
+
timestamp: this.nowISO(),
|
|
147
|
+
severity: EventSeverity.WARN || 'warn',
|
|
148
|
+
sessionId: this._sessionId || this.startSession(),
|
|
149
|
+
eventType: 'memory.warning',
|
|
150
|
+
message: 'High memory usage',
|
|
151
|
+
metadata: { memoryUsage, threshold, usagePercentage },
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
getEventHistory({
|
|
156
|
+
eventType,
|
|
157
|
+
severity,
|
|
158
|
+
pluginType,
|
|
159
|
+
since,
|
|
160
|
+
until,
|
|
161
|
+
limit,
|
|
162
|
+
} = {}) {
|
|
163
|
+
let list = [...this._events];
|
|
164
|
+
|
|
165
|
+
if (since)
|
|
166
|
+
list = list.filter((e) => new Date(e.timestamp) >= new Date(since));
|
|
167
|
+
if (until)
|
|
168
|
+
list = list.filter((e) => new Date(e.timestamp) <= new Date(until));
|
|
169
|
+
if (eventType) list = list.filter((e) => e.eventType === eventType);
|
|
170
|
+
if (severity) list = list.filter((e) => e.severity === severity);
|
|
171
|
+
if (pluginType)
|
|
172
|
+
list = list.filter(
|
|
173
|
+
(e) =>
|
|
174
|
+
e.metadata?.pluginType?.toLowerCase() ===
|
|
175
|
+
String(pluginType).toLowerCase(),
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
list.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
|
|
179
|
+
if (typeof limit === 'number') list = list.slice(-limit);
|
|
180
|
+
|
|
181
|
+
return list;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
exportEvents(filters) {
|
|
185
|
+
const filtered = this.getEventHistory(filters);
|
|
186
|
+
return JSON.stringify({
|
|
187
|
+
sessionId: this._sessionId,
|
|
188
|
+
eventCount: filtered.length,
|
|
189
|
+
events: filtered,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
logEvent(eventType, severity, metadata = {}, message) {
|
|
194
|
+
this._events.push({
|
|
195
|
+
timestamp: this.nowISO(),
|
|
196
|
+
eventType,
|
|
197
|
+
sessionId: this._sessionId || this.startSession(),
|
|
198
|
+
severity,
|
|
199
|
+
message: message || `Event: ${eventType}`,
|
|
200
|
+
metadata,
|
|
201
|
+
});
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
clearHistory() {
|
|
206
|
+
this._events = [];
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
logStageEnd(stage, duration, metadata = {}) {
|
|
211
|
+
this._events.push({
|
|
212
|
+
timestamp: this.nowISO(),
|
|
213
|
+
eventType: 'stage.end',
|
|
214
|
+
sessionId: this._sessionId || this.startSession(),
|
|
215
|
+
severity: 'info',
|
|
216
|
+
message: `Stage ${stage} completed in ${duration}ms`,
|
|
217
|
+
metadata: {
|
|
218
|
+
stage,
|
|
219
|
+
duration,
|
|
220
|
+
type: 'stage_lifecycle',
|
|
221
|
+
...metadata,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
get sessionId() {
|
|
228
|
+
return this._sessionId || this.startSession();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
getSessionStats() {
|
|
232
|
+
return {
|
|
233
|
+
sessionId: this.sessionId,
|
|
234
|
+
totalEvents: this._events.length,
|
|
235
|
+
startTime: this._sessionStartTime || new Date().toISOString(),
|
|
236
|
+
eventTypes: [...new Set(this._events.map((e) => e.eventType))],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
module.exports = { PipelineEventLogger, EventTypes, EventSeverity };
|