@devilsdev/rag-pipeline-utils 2.6.2 → 2.7.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/BENCHMARKS.md +7 -1
- package/CHANGELOG.md +121 -0
- package/README.md +35 -24
- package/dist/index.cjs +4164 -1825
- package/dist/index.d.ts +265 -256
- package/dist/index.mjs +1 -1
- package/dist/types/cache/memory-cache.d.ts +4 -1
- package/dist/types/cache/redis-cache.d.ts +4 -1
- package/dist/types/cli/services/instrument.d.ts +14 -0
- package/dist/types/cli/services/rag-service.d.ts +140 -0
- package/dist/types/cli/shared/config-context.d.ts +9 -0
- package/dist/types/config/component-factory.d.ts +57 -0
- package/dist/types/config/enhanced-ragrc-schema.d.ts +648 -0
- package/dist/types/config/load-config.d.ts +18 -0
- package/dist/types/config/normalize-config.d.ts +9 -0
- package/dist/types/core/observability/event-logger.d.ts +211 -0
- package/dist/types/core/observability/metrics.d.ts +585 -0
- package/dist/types/core/performance/parallel-processor.d.ts +92 -0
- package/dist/types/core/plugin-registry.d.ts +5 -0
- package/dist/types/dag/core/execution-scheduler.d.ts +3 -1
- package/dist/types/dag/dag-engine.d.ts +15 -2
- package/dist/types/dev/dev-server.d.ts +136 -0
- package/dist/types/dev/hot-reload.d.ts +226 -0
- package/dist/types/ecosystem/plugin-analytics-dashboard.d.ts +141 -0
- package/dist/types/ecosystem/plugin-hub.d.ts +161 -0
- package/dist/types/ecosystem/plugin-installer.d.ts +40 -0
- package/dist/types/ecosystem/plugin-probe.d.ts +21 -0
- package/dist/types/ecosystem/plugin-scanner.d.ts +30 -0
- package/dist/types/ecosystem/tar-extract.d.ts +24 -0
- package/dist/types/enterprise/audit-logging.d.ts +217 -0
- package/dist/types/evaluate/compare.d.ts +140 -0
- package/dist/types/evaluate/dataset.d.ts +43 -0
- package/dist/types/evaluate/evaluator.d.ts +14 -0
- package/dist/types/evaluate/report.d.ts +56 -0
- package/dist/types/evaluate/synthetic.d.ts +64 -0
- package/dist/types/loader/csv-loader.d.ts +10 -0
- package/dist/types/loader/document-reader.d.ts +18 -0
- package/dist/types/loader/html-loader.d.ts +21 -0
- package/dist/types/loader/markdown-loader.d.ts +21 -0
- package/dist/types/retrieval/bm25-search.d.ts +4 -0
- package/dist/types/retrieval/file-vector-store.d.ts +4 -1
- package/dist/types/retrieval/hybrid-retriever.d.ts +4 -0
- package/dist/types/retrieval/pgvector-retriever.d.ts +123 -0
- package/dist/types/retrieval/qdrant-retriever.d.ts +106 -0
- package/dist/types/security/validator.d.ts +11 -1
- package/dist/types/testing.d.ts +2 -0
- package/dist/types/utils/batch-processor.d.ts +205 -0
- package/dist/types/utils/connection-pool.d.ts +158 -0
- package/dist/types/utils/error-formatter.d.ts +312 -0
- package/dist/types/utils/logger.d.ts +29 -4
- package/dist/types/utils/rate-limiter.d.ts +13 -8
- package/dist/types/utils/retry.d.ts +10 -0
- package/package.json +12 -2
- package/src/cache/memory-cache.js +4 -1
- package/src/cache/redis-cache.js +4 -1
- package/src/cli/enhanced-cli-commands.js +79 -0
- package/src/cli/handlers/ai-handler.js +2 -2
- package/src/cli/handlers/eval-handler.js +201 -0
- package/src/cli/handlers/generate-handler.js +103 -0
- package/src/cli/services/benchmark.js +2 -2
- package/src/cli/services/rag-service.js +59 -10
- package/src/cli/shared/cli-utils.js +40 -1
- package/src/config/component-factory.js +32 -0
- package/src/connectors/local-embedder.js +20 -13
- package/src/core/observability/event-logger.js +135 -1
- package/src/core/observability/metrics.js +223 -5
- package/src/core/performance/parallel-processor.js +2 -0
- package/src/core/plugin-registry.js +5 -1
- package/src/dag/core/execution-scheduler.js +2 -0
- package/src/dag/dag-engine.js +13 -0
- package/src/dev/dev-server.js +6 -0
- package/src/ecosystem/plugin-hub.js +4 -0
- package/src/enterprise/audit-logging.js +5 -0
- package/src/evaluate/compare.js +395 -0
- package/src/evaluate/dataset.js +207 -0
- package/src/evaluate/report.js +350 -0
- package/src/evaluate/synthetic.js +246 -0
- package/src/index.js +17 -0
- package/src/retrieval/bm25-search.js +4 -0
- package/src/retrieval/file-vector-store.js +4 -1
- package/src/retrieval/hybrid-retriever.js +4 -0
- package/src/retrieval/pgvector-retriever.js +420 -0
- package/src/retrieval/qdrant-retriever.js +361 -0
- package/src/security/validator.js +8 -0
- package/src/testing.js +2 -0
- package/src/utils/batch-processor.js +7 -3
- package/src/utils/error-formatter.js +48 -20
- package/src/utils/logger.js +31 -1
- package/src/utils/rate-limiter.js +9 -4
- package/src/utils/retry.js +10 -1
|
@@ -1,31 +1,72 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Event type names used by PipelineEventLogger. The logger also emits
|
|
5
|
+
* 'stage.end' and 'memory.warning', which have no entry here.
|
|
6
|
+
* @type {{PLUGIN_START: string, PLUGIN_END: string, PLUGIN_ERROR: string, STAGE_START: string, STAGE_ERROR: string}}
|
|
7
|
+
*/
|
|
3
8
|
const EventTypes = {
|
|
9
|
+
/** A plugin call started. */
|
|
4
10
|
PLUGIN_START: 'plugin.start',
|
|
11
|
+
/** A plugin call finished. */
|
|
5
12
|
PLUGIN_END: 'plugin.end',
|
|
13
|
+
/** A plugin call failed. */
|
|
6
14
|
PLUGIN_ERROR: 'plugin.error',
|
|
15
|
+
/** A pipeline stage started. */
|
|
7
16
|
STAGE_START: 'stage.start',
|
|
17
|
+
/** A pipeline stage failed. Not emitted by PipelineEventLogger itself. */
|
|
8
18
|
STAGE_ERROR: 'stage.error',
|
|
9
19
|
};
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Severity levels used by PipelineEventLogger. Memory warnings use 'warn',
|
|
23
|
+
* which has no entry here.
|
|
24
|
+
* @type {{DEBUG: string, INFO: string, ERROR: string}}
|
|
25
|
+
*/
|
|
26
|
+
const EventSeverity = {
|
|
27
|
+
/** Plugin start and end events. */
|
|
28
|
+
DEBUG: 'debug',
|
|
29
|
+
/** Stage events. */
|
|
30
|
+
INFO: 'info',
|
|
31
|
+
/** Plugin errors. */
|
|
32
|
+
ERROR: 'error',
|
|
33
|
+
};
|
|
12
34
|
|
|
35
|
+
/**
|
|
36
|
+
* In-memory log of pipeline events (plugin and stage lifecycle, memory
|
|
37
|
+
* warnings, custom events) tagged with a session id. A session is started
|
|
38
|
+
* on the first event if startSession was not called.
|
|
39
|
+
*/
|
|
13
40
|
class PipelineEventLogger {
|
|
14
41
|
constructor() {
|
|
15
42
|
this._events = [];
|
|
16
43
|
this._sessionId = null;
|
|
17
44
|
}
|
|
18
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Start a new session with a fresh id and start time. Existing events are kept.
|
|
48
|
+
* @returns {string} The new session id
|
|
49
|
+
*/
|
|
19
50
|
startSession() {
|
|
20
51
|
this._sessionId = `session_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
21
52
|
this._sessionStartTime = new Date().toISOString();
|
|
22
53
|
return this._sessionId;
|
|
23
54
|
}
|
|
24
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Current time as an ISO 8601 string.
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
25
60
|
nowISO() {
|
|
26
61
|
return new Date().toISOString();
|
|
27
62
|
}
|
|
28
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Describe a value's size: length for arrays and strings, key count for
|
|
66
|
+
* objects, type only for null and primitives.
|
|
67
|
+
* @param {*} v - Value to describe
|
|
68
|
+
* @returns {{type: string, length?: number, keys?: number}}
|
|
69
|
+
*/
|
|
29
70
|
getInputSize(v) {
|
|
30
71
|
if (Array.isArray(v)) return { type: 'array', length: v.length };
|
|
31
72
|
if (typeof v === 'string') return { type: 'string', length: v.length };
|
|
@@ -34,10 +75,24 @@ class PipelineEventLogger {
|
|
|
34
75
|
return { type: 'object', keys: Object.keys(v).length };
|
|
35
76
|
return { type: typeof v };
|
|
36
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Same as getInputSize.
|
|
80
|
+
* @param {*} v - Value to describe
|
|
81
|
+
* @returns {{type: string, length?: number, keys?: number}}
|
|
82
|
+
*/
|
|
37
83
|
getResultSize(v) {
|
|
38
84
|
return this.getInputSize(v);
|
|
39
85
|
}
|
|
40
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Record a debug-level plugin.start event with the input size and process info.
|
|
89
|
+
* @param {Object} event
|
|
90
|
+
* @param {string} event.pluginType - Plugin type, such as embedder or retriever
|
|
91
|
+
* @param {string} event.pluginName - Plugin name
|
|
92
|
+
* @param {*} [event.input] - Plugin input; only its size is recorded
|
|
93
|
+
* @param {Object<string, *>} [event.context={}] - Extra metadata
|
|
94
|
+
* @returns {void}
|
|
95
|
+
*/
|
|
41
96
|
logPluginStart({ pluginType, pluginName, input, context = {} }) {
|
|
42
97
|
this._events.push({
|
|
43
98
|
timestamp: this.nowISO(),
|
|
@@ -58,6 +113,18 @@ class PipelineEventLogger {
|
|
|
58
113
|
});
|
|
59
114
|
}
|
|
60
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Record a debug-level plugin.end event. When the result is an array, or
|
|
118
|
+
* has a vectors array, its length is recorded as resultSize.vectorCount.
|
|
119
|
+
* @param {Object} event
|
|
120
|
+
* @param {string} event.pluginType - Plugin type
|
|
121
|
+
* @param {string} event.pluginName - Plugin name
|
|
122
|
+
* @param {number} [event.duration] - Duration in milliseconds
|
|
123
|
+
* @param {*} [event.result] - Plugin result; only its length is recorded
|
|
124
|
+
* @param {string} [event.status='success'] - Outcome
|
|
125
|
+
* @param {Object<string, *>} [event.context={}] - Extra metadata
|
|
126
|
+
* @returns {void}
|
|
127
|
+
*/
|
|
61
128
|
logPluginEnd({
|
|
62
129
|
pluginType,
|
|
63
130
|
pluginName,
|
|
@@ -92,6 +159,16 @@ class PipelineEventLogger {
|
|
|
92
159
|
});
|
|
93
160
|
}
|
|
94
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Record an error-level plugin.error event with the error's name, message and code.
|
|
164
|
+
* @param {Object} event
|
|
165
|
+
* @param {string} event.pluginType - Plugin type
|
|
166
|
+
* @param {string} event.pluginName - Plugin name
|
|
167
|
+
* @param {number} [event.duration] - Duration in milliseconds
|
|
168
|
+
* @param {Error & {code?: string}} [event.error] - The error thrown
|
|
169
|
+
* @param {Object<string, *>} [event.context={}] - Extra metadata
|
|
170
|
+
* @returns {void}
|
|
171
|
+
*/
|
|
95
172
|
logPluginError({ pluginType, pluginName, duration, error, context = {} }) {
|
|
96
173
|
this._events.push({
|
|
97
174
|
timestamp: this.nowISO(),
|
|
@@ -116,6 +193,11 @@ class PipelineEventLogger {
|
|
|
116
193
|
});
|
|
117
194
|
}
|
|
118
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Record an info-level stage.start event.
|
|
198
|
+
* @param {string} stage - Stage name
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
119
201
|
logStageStart(stage) {
|
|
120
202
|
this._events.push({
|
|
121
203
|
timestamp: this.nowISO(),
|
|
@@ -132,6 +214,14 @@ class PipelineEventLogger {
|
|
|
132
214
|
});
|
|
133
215
|
}
|
|
134
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Record a warn-level memory.warning event. usagePercentage is heapUsed
|
|
219
|
+
* (or rss if heapUsed is missing) in MB as a percentage of threshold.
|
|
220
|
+
* @param {Object} event
|
|
221
|
+
* @param {{heapUsed?: number, rss?: number}} event.memoryUsage - Memory figures in bytes, as from process.memoryUsage()
|
|
222
|
+
* @param {number} [event.threshold=512] - Threshold in MB
|
|
223
|
+
* @returns {void}
|
|
224
|
+
*/
|
|
135
225
|
logMemoryWarning({ memoryUsage, threshold = 512 }) {
|
|
136
226
|
const usedBytes =
|
|
137
227
|
typeof memoryUsage?.heapUsed === 'number'
|
|
@@ -152,6 +242,17 @@ class PipelineEventLogger {
|
|
|
152
242
|
});
|
|
153
243
|
}
|
|
154
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Recorded events, oldest first, optionally filtered.
|
|
247
|
+
* @param {Object} [filters]
|
|
248
|
+
* @param {string} [filters.eventType]
|
|
249
|
+
* @param {string} [filters.severity]
|
|
250
|
+
* @param {string} [filters.pluginType]
|
|
251
|
+
* @param {string|number|Date} [filters.since] - Only events at or after this time
|
|
252
|
+
* @param {string|number|Date} [filters.until] - Only events at or before this time
|
|
253
|
+
* @param {number} [filters.limit] - Keep only the most recent `limit` events
|
|
254
|
+
* @returns {Object[]}
|
|
255
|
+
*/
|
|
155
256
|
getEventHistory({
|
|
156
257
|
eventType,
|
|
157
258
|
severity,
|
|
@@ -181,6 +282,11 @@ class PipelineEventLogger {
|
|
|
181
282
|
return list;
|
|
182
283
|
}
|
|
183
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Serialize the session id and the events matching the filters.
|
|
287
|
+
* @param {Object} [filters] - Same filters as getEventHistory
|
|
288
|
+
* @returns {string} JSON string with sessionId, eventCount and events
|
|
289
|
+
*/
|
|
184
290
|
exportEvents(filters) {
|
|
185
291
|
const filtered = this.getEventHistory(filters);
|
|
186
292
|
return JSON.stringify({
|
|
@@ -190,6 +296,14 @@ class PipelineEventLogger {
|
|
|
190
296
|
});
|
|
191
297
|
}
|
|
192
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Record an event of any type.
|
|
301
|
+
* @param {string} eventType - Event type
|
|
302
|
+
* @param {string} severity - Severity level
|
|
303
|
+
* @param {Object<string, *>} [metadata={}] - Event metadata
|
|
304
|
+
* @param {string} [message] - Message; defaults to 'Event: ' plus the event type
|
|
305
|
+
* @returns {this}
|
|
306
|
+
*/
|
|
193
307
|
logEvent(eventType, severity, metadata = {}, message) {
|
|
194
308
|
this._events.push({
|
|
195
309
|
timestamp: this.nowISO(),
|
|
@@ -202,11 +316,22 @@ class PipelineEventLogger {
|
|
|
202
316
|
return this;
|
|
203
317
|
}
|
|
204
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Remove all recorded events. The session id is kept.
|
|
321
|
+
* @returns {this}
|
|
322
|
+
*/
|
|
205
323
|
clearHistory() {
|
|
206
324
|
this._events = [];
|
|
207
325
|
return this;
|
|
208
326
|
}
|
|
209
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Record an info-level stage.end event.
|
|
330
|
+
* @param {string} stage - Stage name
|
|
331
|
+
* @param {number} duration - Duration in milliseconds
|
|
332
|
+
* @param {Object<string, *>} [metadata={}] - Extra metadata merged into the event metadata
|
|
333
|
+
* @returns {this}
|
|
334
|
+
*/
|
|
210
335
|
logStageEnd(stage, duration, metadata = {}) {
|
|
211
336
|
this._events.push({
|
|
212
337
|
timestamp: this.nowISO(),
|
|
@@ -224,10 +349,19 @@ class PipelineEventLogger {
|
|
|
224
349
|
return this;
|
|
225
350
|
}
|
|
226
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Current session id. Starts a session if none is active.
|
|
354
|
+
* @returns {string}
|
|
355
|
+
*/
|
|
227
356
|
get sessionId() {
|
|
228
357
|
return this._sessionId || this.startSession();
|
|
229
358
|
}
|
|
230
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Session id, total event count, session start time and the distinct event
|
|
362
|
+
* types recorded. Starts a session if none is active.
|
|
363
|
+
* @returns {{sessionId: string, totalEvents: number, startTime: string, eventTypes: string[]}}
|
|
364
|
+
*/
|
|
231
365
|
getSessionStats() {
|
|
232
366
|
return {
|
|
233
367
|
sessionId: this.sessionId,
|
|
@@ -5,8 +5,13 @@ const MetricType = {
|
|
|
5
5
|
GAUGE: 'gauge',
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
/**
|
|
8
|
+
/** Monotonic counter that only goes up until reset. */
|
|
9
9
|
class Counter {
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} name - Metric name
|
|
12
|
+
* @param {string} [description=''] - Human-readable description
|
|
13
|
+
* @param {Object<string, string>} [labels={}] - Static labels attached to the metric
|
|
14
|
+
*/
|
|
10
15
|
constructor(name, description = '', labels = {}) {
|
|
11
16
|
this._type = MetricType.COUNTER;
|
|
12
17
|
this.name = name;
|
|
@@ -14,14 +19,28 @@ class Counter {
|
|
|
14
19
|
this.labels = labels || {};
|
|
15
20
|
this.value = 0;
|
|
16
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Add to the counter.
|
|
24
|
+
* @param {number} [n=1] - Amount to add
|
|
25
|
+
* @returns {void}
|
|
26
|
+
* @throws {Error} If n is negative
|
|
27
|
+
*/
|
|
17
28
|
inc(n = 1) {
|
|
18
29
|
if (n < 0)
|
|
19
30
|
throw new Error('Counter can only be incremented by non-negative values');
|
|
20
31
|
this.value += n;
|
|
21
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Set the value back to 0.
|
|
35
|
+
* @returns {void}
|
|
36
|
+
*/
|
|
22
37
|
reset() {
|
|
23
38
|
this.value = 0;
|
|
24
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Snapshot of the metric with the current time as timestamp.
|
|
42
|
+
* @returns {{name: string, description: string, type: string, value: number, labels: Object<string, string>, timestamp: string}}
|
|
43
|
+
*/
|
|
25
44
|
toJSON() {
|
|
26
45
|
return {
|
|
27
46
|
name: this.name,
|
|
@@ -34,8 +53,13 @@ class Counter {
|
|
|
34
53
|
}
|
|
35
54
|
}
|
|
36
55
|
|
|
37
|
-
/** Gauge */
|
|
56
|
+
/** Gauge holding a value that can be set, raised or lowered. */
|
|
38
57
|
class Gauge {
|
|
58
|
+
/**
|
|
59
|
+
* @param {string} name - Metric name
|
|
60
|
+
* @param {string} [description=''] - Human-readable description
|
|
61
|
+
* @param {Object<string, string>} [labels={}] - Static labels attached to the metric
|
|
62
|
+
*/
|
|
39
63
|
constructor(name, description = '', labels = {}) {
|
|
40
64
|
this._type = MetricType.GAUGE;
|
|
41
65
|
this.name = name;
|
|
@@ -43,18 +67,41 @@ class Gauge {
|
|
|
43
67
|
this.labels = labels || {};
|
|
44
68
|
this.value = 0;
|
|
45
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Set the value.
|
|
72
|
+
* @param {number} v - New value
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
46
75
|
set(v) {
|
|
47
76
|
this.value = v;
|
|
48
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Add to the value.
|
|
80
|
+
* @param {number} [n=1] - Amount to add
|
|
81
|
+
* @returns {void}
|
|
82
|
+
*/
|
|
49
83
|
inc(n = 1) {
|
|
50
84
|
this.value += n;
|
|
51
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Subtract from the value.
|
|
88
|
+
* @param {number} [n=1] - Amount to subtract
|
|
89
|
+
* @returns {void}
|
|
90
|
+
*/
|
|
52
91
|
dec(n = 1) {
|
|
53
92
|
this.value -= n;
|
|
54
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Set the value back to 0.
|
|
96
|
+
* @returns {void}
|
|
97
|
+
*/
|
|
55
98
|
reset() {
|
|
56
99
|
this.value = 0;
|
|
57
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Snapshot of the metric with the current time as timestamp.
|
|
103
|
+
* @returns {{name: string, description: string, type: string, value: number, labels: Object<string, string>, timestamp: string}}
|
|
104
|
+
*/
|
|
58
105
|
toJSON() {
|
|
59
106
|
return {
|
|
60
107
|
name: this.name,
|
|
@@ -67,8 +114,17 @@ class Gauge {
|
|
|
67
114
|
}
|
|
68
115
|
}
|
|
69
116
|
|
|
70
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Histogram with cumulative bucket counts. It also keeps every observed value
|
|
119
|
+
* in memory to compute percentiles and standard deviation.
|
|
120
|
+
*/
|
|
71
121
|
class Histogram {
|
|
122
|
+
/**
|
|
123
|
+
* @param {string} name - Metric name
|
|
124
|
+
* @param {string} [description=''] - Human-readable description
|
|
125
|
+
* @param {Object<string, string>} [labels={}] - Static labels attached to the metric
|
|
126
|
+
* @param {number[]} [buckets] - Bucket upper bounds, sorted ascending on construction. A +Inf bucket is added.
|
|
127
|
+
*/
|
|
72
128
|
constructor(
|
|
73
129
|
name,
|
|
74
130
|
description = '',
|
|
@@ -88,6 +144,11 @@ class Histogram {
|
|
|
88
144
|
this._obs = [];
|
|
89
145
|
}
|
|
90
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Record a value. Non-numbers and NaN are ignored.
|
|
149
|
+
* @param {number} v - Observed value
|
|
150
|
+
* @returns {void}
|
|
151
|
+
*/
|
|
91
152
|
observe(v) {
|
|
92
153
|
if (typeof v !== 'number' || Number.isNaN(v)) return;
|
|
93
154
|
this._obs.push(v);
|
|
@@ -105,6 +166,12 @@ class Histogram {
|
|
|
105
166
|
this.bucketCounts[i] += 1;
|
|
106
167
|
}
|
|
107
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Percentiles of the observed values by the nearest-rank method. Returns 0
|
|
171
|
+
* for each percentile when nothing has been observed.
|
|
172
|
+
* @param {number[]} [percentiles=[50, 95, 99]] - Percentiles to compute, 0-100
|
|
173
|
+
* @returns {Object<number, number>} Value for each requested percentile
|
|
174
|
+
*/
|
|
108
175
|
getPercentiles(percentiles = [50, 95, 99]) {
|
|
109
176
|
if (this._obs.length === 0)
|
|
110
177
|
return Object.fromEntries(percentiles.map((p) => [p, 0]));
|
|
@@ -121,6 +188,11 @@ class Histogram {
|
|
|
121
188
|
return out;
|
|
122
189
|
}
|
|
123
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Mean, population standard deviation, min, max, count and sum of the
|
|
193
|
+
* observed values. With no observations, min is Infinity and max is -Infinity.
|
|
194
|
+
* @returns {{mean: number, stdDev: number, min: number, max: number, count: number, sum: number}}
|
|
195
|
+
*/
|
|
124
196
|
getStatistics() {
|
|
125
197
|
if (this.count === 0) {
|
|
126
198
|
return {
|
|
@@ -147,6 +219,10 @@ class Histogram {
|
|
|
147
219
|
};
|
|
148
220
|
}
|
|
149
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Clear all bucket counts, statistics and stored observations.
|
|
224
|
+
* @returns {void}
|
|
225
|
+
*/
|
|
150
226
|
reset() {
|
|
151
227
|
this.bucketCounts.fill(0);
|
|
152
228
|
this.sum = 0;
|
|
@@ -155,6 +231,10 @@ class Histogram {
|
|
|
155
231
|
this.max = -Infinity;
|
|
156
232
|
this._obs = [];
|
|
157
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Cumulative count per bucket bound (plus '+Inf') together with getStatistics().
|
|
236
|
+
* @returns {{buckets: Object<string, number>, mean: number, stdDev: number, min: number, max: number, count: number, sum: number}}
|
|
237
|
+
*/
|
|
158
238
|
export() {
|
|
159
239
|
// Map bucket value -> cumulative count
|
|
160
240
|
const bucketsObj = {};
|
|
@@ -164,6 +244,11 @@ class Histogram {
|
|
|
164
244
|
const stats = this.getStatistics();
|
|
165
245
|
return { buckets: bucketsObj, ...stats };
|
|
166
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Snapshot of the histogram with the current time as timestamp. Does not
|
|
249
|
+
* include min, max or percentiles.
|
|
250
|
+
* @returns {{name: string, description: string, type: string, count: number, sum: number, buckets: number[], bucketCounts: number[], labels: Object<string, string>, timestamp: string}}
|
|
251
|
+
*/
|
|
167
252
|
toJSON() {
|
|
168
253
|
return {
|
|
169
254
|
name: this.name,
|
|
@@ -179,11 +264,17 @@ class Histogram {
|
|
|
179
264
|
}
|
|
180
265
|
}
|
|
181
266
|
|
|
182
|
-
/**
|
|
267
|
+
/** Registry of Counter, Histogram and Gauge instances keyed by name. */
|
|
183
268
|
class MetricsRegistry {
|
|
184
269
|
constructor() {
|
|
185
270
|
this._metrics = new Map(); // name -> metric instance
|
|
186
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* Add a metric under its name.
|
|
274
|
+
* @param {Counter|Histogram|Gauge} metric - Metric to register
|
|
275
|
+
* @returns {void}
|
|
276
|
+
* @throws {Error} If a metric with the same name is already registered
|
|
277
|
+
*/
|
|
187
278
|
register(metric) {
|
|
188
279
|
if (this._metrics.has(metric.name)) {
|
|
189
280
|
throw new Error(
|
|
@@ -192,15 +283,36 @@ class MetricsRegistry {
|
|
|
192
283
|
}
|
|
193
284
|
this._metrics.set(metric.name, metric);
|
|
194
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Look up a metric by name.
|
|
288
|
+
* @param {string} name - Metric name
|
|
289
|
+
* @returns {Counter|Histogram|Gauge|undefined} The metric, or undefined if not registered
|
|
290
|
+
*/
|
|
195
291
|
getMetric(name) {
|
|
196
292
|
return this._metrics.get(name);
|
|
197
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* All registered metrics in registration order.
|
|
296
|
+
* @returns {Array<Counter|Histogram|Gauge>}
|
|
297
|
+
*/
|
|
198
298
|
getAllMetrics() {
|
|
199
299
|
return Array.from(this._metrics.values());
|
|
200
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Remove every registered metric.
|
|
303
|
+
* @returns {void}
|
|
304
|
+
*/
|
|
201
305
|
clear() {
|
|
202
306
|
this._metrics.clear();
|
|
203
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Return the metric registered under name, or create and register a Counter.
|
|
310
|
+
* An existing metric is returned as is, even if it is not a Counter.
|
|
311
|
+
* @param {string} name - Metric name
|
|
312
|
+
* @param {string} [description] - Description for a new counter
|
|
313
|
+
* @param {Object<string, string>} [labels={}] - Labels for a new counter
|
|
314
|
+
* @returns {Counter}
|
|
315
|
+
*/
|
|
204
316
|
getOrCreateCounter(name, description, labels = {}) {
|
|
205
317
|
if (this._metrics.has(name)) {
|
|
206
318
|
return this._metrics.get(name);
|
|
@@ -209,6 +321,15 @@ class MetricsRegistry {
|
|
|
209
321
|
this.register(counter);
|
|
210
322
|
return counter;
|
|
211
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Return the metric registered under name, or create and register a
|
|
326
|
+
* Histogram. An existing metric is returned as is, even if it is not a Histogram.
|
|
327
|
+
* @param {string} name - Metric name
|
|
328
|
+
* @param {string} [description] - Description for a new histogram
|
|
329
|
+
* @param {Object<string, string>} [labels={}] - Labels for a new histogram
|
|
330
|
+
* @param {number[]} [buckets] - Bucket bounds for a new histogram
|
|
331
|
+
* @returns {Histogram}
|
|
332
|
+
*/
|
|
212
333
|
getOrCreateHistogram(name, description, labels = {}, buckets) {
|
|
213
334
|
if (this._metrics.has(name)) {
|
|
214
335
|
return this._metrics.get(name);
|
|
@@ -217,6 +338,14 @@ class MetricsRegistry {
|
|
|
217
338
|
this.register(histogram);
|
|
218
339
|
return histogram;
|
|
219
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Return the metric registered under name, or create and register a Gauge.
|
|
343
|
+
* An existing metric is returned as is, even if it is not a Gauge.
|
|
344
|
+
* @param {string} name - Metric name
|
|
345
|
+
* @param {string} [description] - Description for a new gauge
|
|
346
|
+
* @param {Object<string, string>} [labels={}] - Labels for a new gauge
|
|
347
|
+
* @returns {Gauge}
|
|
348
|
+
*/
|
|
220
349
|
getOrCreateGauge(name, description, labels = {}) {
|
|
221
350
|
if (this._metrics.has(name)) {
|
|
222
351
|
return this._metrics.get(name);
|
|
@@ -225,6 +354,10 @@ class MetricsRegistry {
|
|
|
225
354
|
this.register(gauge);
|
|
226
355
|
return gauge;
|
|
227
356
|
}
|
|
357
|
+
/**
|
|
358
|
+
* Serialize all metrics (their toJSON output) with a timestamp.
|
|
359
|
+
* @returns {string} JSON string with timestamp and metrics fields
|
|
360
|
+
*/
|
|
228
361
|
exportMetrics() {
|
|
229
362
|
return JSON.stringify({
|
|
230
363
|
timestamp: new Date().toISOString(),
|
|
@@ -233,7 +366,10 @@ class MetricsRegistry {
|
|
|
233
366
|
}
|
|
234
367
|
}
|
|
235
368
|
|
|
236
|
-
/**
|
|
369
|
+
/**
|
|
370
|
+
* In-memory totals for pipeline operations: embedding, retrieval and LLM
|
|
371
|
+
* calls, errors, operation counts, concurrency, backpressure and heap usage.
|
|
372
|
+
*/
|
|
237
373
|
class PipelineMetrics {
|
|
238
374
|
constructor() {
|
|
239
375
|
this.counters = {
|
|
@@ -279,6 +415,14 @@ class PipelineMetrics {
|
|
|
279
415
|
this.concurrency = { maxConcurrency: 0, concurrencyValues: [] };
|
|
280
416
|
}
|
|
281
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Record one embedding call.
|
|
420
|
+
* @param {string} provider - Provider name (unused)
|
|
421
|
+
* @param {number} duration - Duration in milliseconds
|
|
422
|
+
* @param {number} tokens - Tokens embedded
|
|
423
|
+
* @param {number} batches - Batches sent
|
|
424
|
+
* @returns {void}
|
|
425
|
+
*/
|
|
282
426
|
recordEmbedding(provider, duration, tokens, batches) {
|
|
283
427
|
this.embedding.operations++;
|
|
284
428
|
this.embedding.totalDuration += duration;
|
|
@@ -287,6 +431,13 @@ class PipelineMetrics {
|
|
|
287
431
|
this.embedding.durations.push(duration);
|
|
288
432
|
}
|
|
289
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Record one retrieval call.
|
|
436
|
+
* @param {string} provider - Provider name (unused)
|
|
437
|
+
* @param {number} duration - Duration in milliseconds
|
|
438
|
+
* @param {number} results - Number of results returned
|
|
439
|
+
* @returns {void}
|
|
440
|
+
*/
|
|
290
441
|
recordRetrieval(provider, duration, results) {
|
|
291
442
|
this.retrieval.operations++;
|
|
292
443
|
this.retrieval.totalDuration += duration;
|
|
@@ -294,6 +445,15 @@ class PipelineMetrics {
|
|
|
294
445
|
this.retrieval.durations.push(duration);
|
|
295
446
|
}
|
|
296
447
|
|
|
448
|
+
/**
|
|
449
|
+
* Record one LLM call.
|
|
450
|
+
* @param {string} provider - Provider name (unused)
|
|
451
|
+
* @param {number} duration - Duration in milliseconds
|
|
452
|
+
* @param {number} inputTokens - Prompt tokens
|
|
453
|
+
* @param {number} outputTokens - Completion tokens
|
|
454
|
+
* @param {boolean} [streaming] - Whether the call streamed its output
|
|
455
|
+
* @returns {void}
|
|
456
|
+
*/
|
|
297
457
|
recordLLM(provider, duration, inputTokens, outputTokens, streaming) {
|
|
298
458
|
this.llm.operations++;
|
|
299
459
|
this.llm.totalDuration += duration;
|
|
@@ -305,6 +465,11 @@ class PipelineMetrics {
|
|
|
305
465
|
this.llm.outputTokens.push(outputTokens);
|
|
306
466
|
}
|
|
307
467
|
|
|
468
|
+
/**
|
|
469
|
+
* Store heapUsed and heapTotal from process.memoryUsage() and the used
|
|
470
|
+
* percentage, rounded.
|
|
471
|
+
* @returns {void}
|
|
472
|
+
*/
|
|
308
473
|
recordMemoryUsage() {
|
|
309
474
|
const memUsage = process.memoryUsage();
|
|
310
475
|
this.memory.heapUsed = memUsage.heapUsed;
|
|
@@ -314,6 +479,15 @@ class PipelineMetrics {
|
|
|
314
479
|
);
|
|
315
480
|
}
|
|
316
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Count an error by type and by component. Only the types 'plugin' and
|
|
484
|
+
* 'stage' are counted by type; other types are counted only by component.
|
|
485
|
+
* @param {string} type - Error type, 'plugin' or 'stage'
|
|
486
|
+
* @param {string} [component] - Plugin or component name
|
|
487
|
+
* @param {string} [provider] - Provider name (unused)
|
|
488
|
+
* @param {Error} [error] - The error (unused)
|
|
489
|
+
* @returns {void}
|
|
490
|
+
*/
|
|
317
491
|
recordError(type, component, provider, error) {
|
|
318
492
|
if (type && type in this.errorsByType) this.errorsByType[type]++;
|
|
319
493
|
if (component)
|
|
@@ -321,11 +495,28 @@ class PipelineMetrics {
|
|
|
321
495
|
(this.errorsByPlugin[component] || 0) + 1;
|
|
322
496
|
}
|
|
323
497
|
|
|
498
|
+
/**
|
|
499
|
+
* Count an operation as started and active.
|
|
500
|
+
* @param {string} [type] - Operation type (unused)
|
|
501
|
+
* @param {string} [component] - Component name (unused)
|
|
502
|
+
* @param {string} [provider] - Provider name (unused)
|
|
503
|
+
* @returns {void}
|
|
504
|
+
*/
|
|
324
505
|
recordOperationStart(type, component, provider) {
|
|
325
506
|
this.counters.operationsTotal.inc(1);
|
|
326
507
|
this.counters.operationsActive.inc(1);
|
|
327
508
|
}
|
|
328
509
|
|
|
510
|
+
/**
|
|
511
|
+
* Mark an active operation as finished. A status of 'error' or 'failed'
|
|
512
|
+
* counts as failed; any other status counts as successful.
|
|
513
|
+
* @param {string} [type] - Operation type (unused)
|
|
514
|
+
* @param {string} [component] - Component name (unused)
|
|
515
|
+
* @param {string} [provider] - Provider name (unused)
|
|
516
|
+
* @param {number} [duration] - Duration in milliseconds (unused)
|
|
517
|
+
* @param {string} [status] - Outcome of the operation
|
|
518
|
+
* @returns {void}
|
|
519
|
+
*/
|
|
329
520
|
recordOperationEnd(type, component, provider, duration, status) {
|
|
330
521
|
this.counters.operationsActive.value = Math.max(
|
|
331
522
|
0,
|
|
@@ -336,6 +527,12 @@ class PipelineMetrics {
|
|
|
336
527
|
else this.counters.operationsSuccessful.inc(1);
|
|
337
528
|
}
|
|
338
529
|
|
|
530
|
+
/**
|
|
531
|
+
* Record a concurrency sample. Keeps the highest max seen and every average.
|
|
532
|
+
* @param {number} maxConcurrency - Peak concurrency in the sample
|
|
533
|
+
* @param {number} avgConcurrency - Average concurrency in the sample
|
|
534
|
+
* @returns {void}
|
|
535
|
+
*/
|
|
339
536
|
recordConcurrency(maxConcurrency, avgConcurrency) {
|
|
340
537
|
this.concurrency.maxConcurrency = Math.max(
|
|
341
538
|
this.concurrency.maxConcurrency,
|
|
@@ -344,6 +541,13 @@ class PipelineMetrics {
|
|
|
344
541
|
this.concurrency.concurrencyValues.push(avgConcurrency);
|
|
345
542
|
}
|
|
346
543
|
|
|
544
|
+
/**
|
|
545
|
+
* Count a backpressure event and keep the buffer size as a sample.
|
|
546
|
+
* @param {string} action - 'applied' or 'released'; other values are not counted
|
|
547
|
+
* @param {number} [bufferSize] - Buffer size at the time of the event
|
|
548
|
+
* @param {number} [threshold] - Backpressure threshold (unused)
|
|
549
|
+
* @returns {void}
|
|
550
|
+
*/
|
|
347
551
|
recordBackpressure(action, bufferSize, threshold) {
|
|
348
552
|
if (action === 'applied') this.backpressureApplied++;
|
|
349
553
|
if (action === 'released') this.backpressureReleased++;
|
|
@@ -351,6 +555,11 @@ class PipelineMetrics {
|
|
|
351
555
|
this.backpressureSamples.push(bufferSize);
|
|
352
556
|
}
|
|
353
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Totals and averages for every recorded category. Averages are 0 when
|
|
560
|
+
* nothing was recorded.
|
|
561
|
+
* @returns Summary grouped by embedding, retrieval, llm, memory, errors, operations, concurrency and backpressure
|
|
562
|
+
*/
|
|
354
563
|
getSummary() {
|
|
355
564
|
const backpressureMean = this.backpressureSamples.length
|
|
356
565
|
? this.backpressureSamples.reduce((a, b) => a + b, 0) /
|
|
@@ -426,6 +635,10 @@ class PipelineMetrics {
|
|
|
426
635
|
};
|
|
427
636
|
}
|
|
428
637
|
|
|
638
|
+
/**
|
|
639
|
+
* getSummary() plus the raw recorded values, with a timestamp.
|
|
640
|
+
* @returns Object with timestamp, summary and rawMetrics
|
|
641
|
+
*/
|
|
429
642
|
exportMetrics() {
|
|
430
643
|
return {
|
|
431
644
|
timestamp: new Date().toISOString(),
|
|
@@ -447,6 +660,10 @@ class PipelineMetrics {
|
|
|
447
660
|
};
|
|
448
661
|
}
|
|
449
662
|
|
|
663
|
+
/**
|
|
664
|
+
* Reset every counter, total and sample to its initial value.
|
|
665
|
+
* @returns {void}
|
|
666
|
+
*/
|
|
450
667
|
clearMetrics() {
|
|
451
668
|
this.counters.operationsTotal.reset();
|
|
452
669
|
this.counters.operationsSuccessful.reset();
|
|
@@ -485,6 +702,7 @@ class PipelineMetrics {
|
|
|
485
702
|
}
|
|
486
703
|
}
|
|
487
704
|
|
|
705
|
+
/** Shared PipelineMetrics instance. */
|
|
488
706
|
const pipelineMetrics = new PipelineMetrics();
|
|
489
707
|
|
|
490
708
|
module.exports = {
|