@lov3kaizen/agentsea-evaluate 0.5.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.

Potentially problematic release.


This version of @lov3kaizen/agentsea-evaluate might be problematic. Click here for more details.

Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +339 -0
  3. package/dist/annotation/index.d.mts +3 -0
  4. package/dist/annotation/index.d.ts +3 -0
  5. package/dist/annotation/index.js +630 -0
  6. package/dist/annotation/index.mjs +22 -0
  7. package/dist/chunk-5JRYKRSE.mjs +2791 -0
  8. package/dist/chunk-EUXXIZK3.mjs +676 -0
  9. package/dist/chunk-NBMUSATK.mjs +596 -0
  10. package/dist/chunk-PAQ2TTJJ.mjs +1105 -0
  11. package/dist/chunk-TUMNJN2S.mjs +416 -0
  12. package/dist/continuous/index.d.mts +2 -0
  13. package/dist/continuous/index.d.ts +2 -0
  14. package/dist/continuous/index.js +707 -0
  15. package/dist/continuous/index.mjs +16 -0
  16. package/dist/datasets/index.d.mts +1 -0
  17. package/dist/datasets/index.d.ts +1 -0
  18. package/dist/datasets/index.js +456 -0
  19. package/dist/datasets/index.mjs +14 -0
  20. package/dist/evaluation/index.d.mts +1 -0
  21. package/dist/evaluation/index.d.ts +1 -0
  22. package/dist/evaluation/index.js +2853 -0
  23. package/dist/evaluation/index.mjs +78 -0
  24. package/dist/feedback/index.d.mts +2 -0
  25. package/dist/feedback/index.d.ts +2 -0
  26. package/dist/feedback/index.js +1158 -0
  27. package/dist/feedback/index.mjs +40 -0
  28. package/dist/index-6Pbiq7ny.d.mts +234 -0
  29. package/dist/index-6Pbiq7ny.d.ts +234 -0
  30. package/dist/index-BNTycFEA.d.mts +479 -0
  31. package/dist/index-BNTycFEA.d.ts +479 -0
  32. package/dist/index-CTYCfWfH.d.mts +543 -0
  33. package/dist/index-CTYCfWfH.d.ts +543 -0
  34. package/dist/index-Cq5LwG_3.d.mts +322 -0
  35. package/dist/index-Cq5LwG_3.d.ts +322 -0
  36. package/dist/index-bPghFsfP.d.mts +315 -0
  37. package/dist/index-bPghFsfP.d.ts +315 -0
  38. package/dist/index.d.mts +81 -0
  39. package/dist/index.d.ts +81 -0
  40. package/dist/index.js +5962 -0
  41. package/dist/index.mjs +429 -0
  42. package/package.json +102 -0
@@ -0,0 +1,676 @@
1
+ // src/continuous/ContinuousEval.ts
2
+ import { EventEmitter as EventEmitter2 } from "eventemitter3";
3
+
4
+ // src/continuous/ABTestRunner.ts
5
+ import { EventEmitter } from "eventemitter3";
6
+ import { nanoid } from "nanoid";
7
+ var ABTestRunner = class extends EventEmitter {
8
+ id;
9
+ name;
10
+ config;
11
+ status = "draft";
12
+ startedAt;
13
+ completedAt;
14
+ controlSamples = /* @__PURE__ */ new Map();
15
+ treatmentSamples = /* @__PURE__ */ new Map();
16
+ sampleCount = 0;
17
+ constructor(config) {
18
+ super();
19
+ this.id = nanoid();
20
+ this.name = config.name;
21
+ this.config = config;
22
+ }
23
+ /**
24
+ * Start the A/B test
25
+ */
26
+ start() {
27
+ if (this.status !== "draft") {
28
+ throw new Error(`Cannot start test in ${this.status} status`);
29
+ }
30
+ this.status = "running";
31
+ this.startedAt = Date.now();
32
+ this.emit("test:started");
33
+ return Promise.resolve();
34
+ }
35
+ /**
36
+ * Stop the A/B test
37
+ */
38
+ stop() {
39
+ this.status = "completed";
40
+ this.completedAt = Date.now();
41
+ const results = this.getResults();
42
+ this.emit("test:completed", results);
43
+ return results;
44
+ }
45
+ /**
46
+ * Pause the test
47
+ */
48
+ pause() {
49
+ if (this.status === "running") {
50
+ this.status = "paused";
51
+ }
52
+ }
53
+ /**
54
+ * Resume the test
55
+ */
56
+ resume() {
57
+ if (this.status === "paused") {
58
+ this.status = "running";
59
+ }
60
+ }
61
+ /**
62
+ * Assign a sample to a variant
63
+ */
64
+ assignVariant() {
65
+ if (this.status !== "running") {
66
+ throw new Error("Test is not running");
67
+ }
68
+ const isControl = Math.random() >= this.config.trafficSplit;
69
+ const variant = isControl ? "control" : "treatment";
70
+ const assignment = {
71
+ variant,
72
+ testId: this.id,
73
+ assignedAt: Date.now()
74
+ };
75
+ this.emit("sample:assigned", assignment);
76
+ return variant;
77
+ }
78
+ /**
79
+ * Record sample result
80
+ */
81
+ recordSample(variant, sampleId, scores) {
82
+ if (this.status !== "running") {
83
+ throw new Error("Test is not running");
84
+ }
85
+ const samples = variant === "control" ? this.controlSamples : this.treatmentSamples;
86
+ samples.set(sampleId, scores);
87
+ this.sampleCount++;
88
+ if (this.sampleCount >= this.config.minSamples) {
89
+ this.checkSignificance();
90
+ }
91
+ if (this.config.maxDuration && this.startedAt && Date.now() - this.startedAt > this.config.maxDuration) {
92
+ this.stop();
93
+ }
94
+ }
95
+ /**
96
+ * Get current results
97
+ */
98
+ getResults() {
99
+ const metrics = {};
100
+ for (const metric of this.config.metrics) {
101
+ metrics[metric] = this.calculateMetricResult(metric);
102
+ }
103
+ let controlWins = 0;
104
+ let treatmentWins = 0;
105
+ for (const result of Object.values(metrics)) {
106
+ if (result.isSignificant) {
107
+ if (result.winner === "control") controlWins++;
108
+ else if (result.winner === "treatment") treatmentWins++;
109
+ }
110
+ }
111
+ let winner = "none";
112
+ if (controlWins > treatmentWins) winner = "control";
113
+ else if (treatmentWins > controlWins) winner = "treatment";
114
+ const isSignificant = Object.values(metrics).some((m) => m.isSignificant);
115
+ const confidence = isSignificant ? Math.max(...Object.values(metrics).map((m) => 1 - m.pValue)) : 0;
116
+ return {
117
+ controlSamples: this.controlSamples.size,
118
+ treatmentSamples: this.treatmentSamples.size,
119
+ metrics,
120
+ winner,
121
+ isSignificant,
122
+ confidence,
123
+ recommendation: this.generateRecommendation(
124
+ winner,
125
+ isSignificant,
126
+ metrics
127
+ )
128
+ };
129
+ }
130
+ /**
131
+ * Calculate result for a single metric
132
+ */
133
+ calculateMetricResult(metric) {
134
+ const controlScores = this.getScoresForMetric(this.controlSamples, metric);
135
+ const treatmentScores = this.getScoresForMetric(
136
+ this.treatmentSamples,
137
+ metric
138
+ );
139
+ const controlSummary = this.calculateSummary(controlScores);
140
+ const treatmentSummary = this.calculateSummary(treatmentScores);
141
+ const difference = treatmentSummary.mean - controlSummary.mean;
142
+ const differencePercent = controlSummary.mean !== 0 ? difference / controlSummary.mean * 100 : 0;
143
+ const pValue = this.calculatePValue(controlScores, treatmentScores);
144
+ const isSignificant = pValue < (this.config.significanceLevel ?? 0.05);
145
+ let winner = "none";
146
+ if (isSignificant) {
147
+ winner = difference > 0 ? "treatment" : "control";
148
+ }
149
+ return {
150
+ control: controlSummary,
151
+ treatment: treatmentSummary,
152
+ difference,
153
+ differencePercent,
154
+ pValue,
155
+ isSignificant,
156
+ winner
157
+ };
158
+ }
159
+ /**
160
+ * Get scores for a metric from samples
161
+ */
162
+ getScoresForMetric(samples, metric) {
163
+ const scores = [];
164
+ for (const sampleScores of samples.values()) {
165
+ if (metric in sampleScores) {
166
+ scores.push(sampleScores[metric]);
167
+ }
168
+ }
169
+ return scores;
170
+ }
171
+ /**
172
+ * Calculate summary statistics
173
+ */
174
+ calculateSummary(scores) {
175
+ if (scores.length === 0) {
176
+ return {
177
+ mean: 0,
178
+ std: 0,
179
+ sampleCount: 0,
180
+ confidenceInterval: [0, 0]
181
+ };
182
+ }
183
+ const mean = scores.reduce((a, b) => a + b, 0) / scores.length;
184
+ const variance = scores.reduce((sum, s) => sum + Math.pow(s - mean, 2), 0) / scores.length;
185
+ const std = Math.sqrt(variance);
186
+ const se = std / Math.sqrt(scores.length);
187
+ const margin = 1.96 * se;
188
+ return {
189
+ mean,
190
+ std,
191
+ sampleCount: scores.length,
192
+ confidenceInterval: [mean - margin, mean + margin]
193
+ };
194
+ }
195
+ /**
196
+ * Calculate p-value using Welch's t-test approximation
197
+ */
198
+ calculatePValue(control, treatment) {
199
+ if (control.length < 2 || treatment.length < 2) return 1;
200
+ const n1 = control.length;
201
+ const n2 = treatment.length;
202
+ const mean1 = control.reduce((a, b) => a + b, 0) / n1;
203
+ const mean2 = treatment.reduce((a, b) => a + b, 0) / n2;
204
+ const var1 = control.reduce((sum, x) => sum + Math.pow(x - mean1, 2), 0) / (n1 - 1);
205
+ const var2 = treatment.reduce((sum, x) => sum + Math.pow(x - mean2, 2), 0) / (n2 - 1);
206
+ const se = Math.sqrt(var1 / n1 + var2 / n2);
207
+ if (se === 0) return 1;
208
+ const t = Math.abs(mean1 - mean2) / se;
209
+ const pValue = 2 * (1 - this.normalCDF(t));
210
+ return Math.max(0, Math.min(1, pValue));
211
+ }
212
+ /**
213
+ * Normal CDF approximation
214
+ */
215
+ normalCDF(x) {
216
+ const a1 = 0.254829592;
217
+ const a2 = -0.284496736;
218
+ const a3 = 1.421413741;
219
+ const a4 = -1.453152027;
220
+ const a5 = 1.061405429;
221
+ const p = 0.3275911;
222
+ const sign = x < 0 ? -1 : 1;
223
+ x = Math.abs(x) / Math.sqrt(2);
224
+ const t = 1 / (1 + p * x);
225
+ const y = 1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
226
+ return 0.5 * (1 + sign * y);
227
+ }
228
+ /**
229
+ * Check for statistical significance
230
+ */
231
+ checkSignificance() {
232
+ for (const metric of this.config.metrics) {
233
+ const result = this.calculateMetricResult(metric);
234
+ if (result.isSignificant && result.winner !== "none") {
235
+ this.emit("test:significant", metric, result.winner);
236
+ }
237
+ }
238
+ }
239
+ /**
240
+ * Generate recommendation
241
+ */
242
+ generateRecommendation(winner, isSignificant, metrics) {
243
+ if (!isSignificant) {
244
+ const totalSamples = this.controlSamples.size + this.treatmentSamples.size;
245
+ if (totalSamples < this.config.minSamples) {
246
+ return `Not enough samples yet. Need ${this.config.minSamples - totalSamples} more.`;
247
+ }
248
+ return "No significant difference detected. Consider running longer or adjusting variants.";
249
+ }
250
+ if (winner === "treatment") {
251
+ const improvements = Object.entries(metrics).filter(([, r]) => r.winner === "treatment").map(([m, r]) => `${m}: +${r.differencePercent.toFixed(1)}%`);
252
+ return `Treatment variant wins. Improvements: ${improvements.join(", ")}`;
253
+ }
254
+ if (winner === "control") {
255
+ return "Control variant performs better. Consider keeping current configuration.";
256
+ }
257
+ return "Mixed results. Review individual metrics for details.";
258
+ }
259
+ /**
260
+ * Get test status
261
+ */
262
+ getStatus() {
263
+ return this.status;
264
+ }
265
+ /**
266
+ * Get test configuration
267
+ */
268
+ getConfig() {
269
+ return { ...this.config };
270
+ }
271
+ /**
272
+ * Get test timestamps
273
+ */
274
+ getTimestamps() {
275
+ return {
276
+ startedAt: this.startedAt,
277
+ completedAt: this.completedAt
278
+ };
279
+ }
280
+ };
281
+ function createABTestRunner(config) {
282
+ return new ABTestRunner(config);
283
+ }
284
+
285
+ // src/continuous/ContinuousEval.ts
286
+ var ContinuousEval = class extends EventEmitter2 {
287
+ pipeline;
288
+ sampleRate;
289
+ status = "stopped";
290
+ startedAt;
291
+ lastEvalAt;
292
+ totalEvaluations = 0;
293
+ passedCount = 0;
294
+ scoreHistory = {};
295
+ alertManager;
296
+ abTests = /* @__PURE__ */ new Map();
297
+ intervalId;
298
+ constructor(config) {
299
+ super();
300
+ this.pipeline = config.pipeline;
301
+ this.sampleRate = config.sampleRate;
302
+ }
303
+ /**
304
+ * Set alert manager
305
+ */
306
+ setAlerts(alertManager, rules) {
307
+ this.alertManager = alertManager;
308
+ for (const [metric, rule] of Object.entries(rules)) {
309
+ alertManager.addRule({
310
+ metric,
311
+ threshold: rule.threshold,
312
+ direction: rule.direction
313
+ });
314
+ }
315
+ }
316
+ /**
317
+ * Start monitoring
318
+ */
319
+ start() {
320
+ if (this.status === "running") return;
321
+ this.status = "running";
322
+ this.startedAt = Date.now();
323
+ this.emit("status:changed", this.status);
324
+ this.emit("eval:started");
325
+ }
326
+ /**
327
+ * Stop monitoring
328
+ */
329
+ stop() {
330
+ this.status = "stopped";
331
+ if (this.intervalId) {
332
+ clearInterval(this.intervalId);
333
+ this.intervalId = void 0;
334
+ }
335
+ this.emit("status:changed", this.status);
336
+ }
337
+ /**
338
+ * Pause monitoring
339
+ */
340
+ pause() {
341
+ if (this.status === "running") {
342
+ this.status = "paused";
343
+ this.emit("status:changed", this.status);
344
+ }
345
+ }
346
+ /**
347
+ * Resume monitoring
348
+ */
349
+ resume() {
350
+ if (this.status === "paused") {
351
+ this.status = "running";
352
+ this.emit("status:changed", this.status);
353
+ }
354
+ }
355
+ /**
356
+ * Evaluate a sample
357
+ */
358
+ async evaluate(input) {
359
+ if (Math.random() > this.sampleRate) {
360
+ return null;
361
+ }
362
+ if (this.status !== "running") {
363
+ return null;
364
+ }
365
+ try {
366
+ const result = await this.pipeline.evaluate(input);
367
+ this.totalEvaluations++;
368
+ this.lastEvalAt = Date.now();
369
+ if (result.passed) {
370
+ this.passedCount++;
371
+ }
372
+ for (const [metric, score] of Object.entries(result.scores)) {
373
+ if (!this.scoreHistory[metric]) {
374
+ this.scoreHistory[metric] = [];
375
+ }
376
+ this.scoreHistory[metric].push(score);
377
+ if (this.scoreHistory[metric].length > 1e3) {
378
+ this.scoreHistory[metric].shift();
379
+ }
380
+ if (this.alertManager) {
381
+ this.alertManager.check(metric, score);
382
+ }
383
+ }
384
+ this.emit("eval:completed", result);
385
+ return result;
386
+ } catch (error) {
387
+ this.status = "error";
388
+ this.emit("eval:error", error);
389
+ this.emit("status:changed", this.status);
390
+ return null;
391
+ }
392
+ }
393
+ /**
394
+ * Get statistics
395
+ */
396
+ getStats() {
397
+ const avgScores = {};
398
+ for (const [metric, scores] of Object.entries(this.scoreHistory)) {
399
+ if (scores.length > 0) {
400
+ avgScores[metric] = scores.reduce((a, b) => a + b, 0) / scores.length;
401
+ }
402
+ }
403
+ return {
404
+ status: this.status,
405
+ startedAt: this.startedAt,
406
+ lastEvalAt: this.lastEvalAt,
407
+ totalEvaluations: this.totalEvaluations,
408
+ passRate: this.totalEvaluations > 0 ? this.passedCount / this.totalEvaluations : 0,
409
+ avgScores,
410
+ alertsTriggered: this.alertManager?.getAlertCount() ?? 0
411
+ };
412
+ }
413
+ /**
414
+ * Create A/B test
415
+ */
416
+ createABTest(config) {
417
+ const test = new ABTestRunner(config);
418
+ this.abTests.set(test.id, test);
419
+ return test;
420
+ }
421
+ /**
422
+ * Get A/B test
423
+ */
424
+ getABTest(id) {
425
+ return this.abTests.get(id);
426
+ }
427
+ /**
428
+ * Get all A/B tests
429
+ */
430
+ getABTests() {
431
+ return Array.from(this.abTests.values());
432
+ }
433
+ /**
434
+ * Get score history for a metric
435
+ */
436
+ getScoreHistory(metric) {
437
+ return this.scoreHistory[metric] ?? [];
438
+ }
439
+ /**
440
+ * Reset statistics
441
+ */
442
+ reset() {
443
+ this.totalEvaluations = 0;
444
+ this.passedCount = 0;
445
+ this.scoreHistory = {};
446
+ this.lastEvalAt = void 0;
447
+ }
448
+ };
449
+ function createContinuousEval(config) {
450
+ return new ContinuousEval(config);
451
+ }
452
+
453
+ // src/continuous/AlertManager.ts
454
+ import { EventEmitter as EventEmitter3 } from "eventemitter3";
455
+ import { nanoid as nanoid2 } from "nanoid";
456
+ var AlertManager = class extends EventEmitter3 {
457
+ channels;
458
+ rules = /* @__PURE__ */ new Map();
459
+ activeAlerts = /* @__PURE__ */ new Map();
460
+ cooldownMs;
461
+ lastAlertTime = /* @__PURE__ */ new Map();
462
+ alertCount = 0;
463
+ constructor(config) {
464
+ super();
465
+ this.channels = config.channels;
466
+ this.cooldownMs = config.cooldownMs ?? 3e5;
467
+ if (config.rules) {
468
+ for (const [metric, rule] of Object.entries(config.rules)) {
469
+ this.rules.set(metric, rule);
470
+ }
471
+ }
472
+ }
473
+ /**
474
+ * Add an alert rule
475
+ */
476
+ addRule(rule) {
477
+ this.rules.set(rule.metric, rule);
478
+ }
479
+ /**
480
+ * Remove an alert rule
481
+ */
482
+ removeRule(metric) {
483
+ return this.rules.delete(metric);
484
+ }
485
+ /**
486
+ * Check value against rules
487
+ */
488
+ check(metric, value) {
489
+ const rule = this.rules.get(metric);
490
+ if (!rule) return null;
491
+ const shouldAlert = rule.direction === "above" && value > rule.threshold || rule.direction === "below" && value < rule.threshold;
492
+ if (shouldAlert) {
493
+ return this.triggerAlert(rule, metric, value);
494
+ } else {
495
+ const existingAlert = this.activeAlerts.get(metric);
496
+ if (existingAlert) {
497
+ this.resolveAlert(metric);
498
+ }
499
+ }
500
+ return null;
501
+ }
502
+ /**
503
+ * Trigger an alert
504
+ */
505
+ triggerAlert(rule, metric, value) {
506
+ const lastTime = this.lastAlertTime.get(metric);
507
+ if (lastTime && Date.now() - lastTime < this.cooldownMs) {
508
+ return null;
509
+ }
510
+ const alert = {
511
+ id: nanoid2(),
512
+ rule,
513
+ metric,
514
+ currentValue: value,
515
+ threshold: rule.threshold,
516
+ severity: rule.severity ?? "warning",
517
+ message: this.formatMessage(rule, metric, value),
518
+ triggeredAt: Date.now()
519
+ };
520
+ this.activeAlerts.set(metric, alert);
521
+ this.lastAlertTime.set(metric, Date.now());
522
+ this.alertCount++;
523
+ this.emit("alert:triggered", alert);
524
+ void this.sendNotifications(alert);
525
+ return alert;
526
+ }
527
+ /**
528
+ * Resolve an alert
529
+ */
530
+ resolveAlert(metric) {
531
+ const alert = this.activeAlerts.get(metric);
532
+ if (alert) {
533
+ alert.resolvedAt = Date.now();
534
+ this.activeAlerts.delete(metric);
535
+ this.emit("alert:resolved", alert);
536
+ }
537
+ }
538
+ /**
539
+ * Acknowledge an alert
540
+ */
541
+ acknowledgeAlert(alertId) {
542
+ for (const alert of this.activeAlerts.values()) {
543
+ if (alert.id === alertId) {
544
+ alert.acknowledged = true;
545
+ return true;
546
+ }
547
+ }
548
+ return false;
549
+ }
550
+ /**
551
+ * Send notifications
552
+ */
553
+ async sendNotifications(alert) {
554
+ for (const channel of this.channels) {
555
+ try {
556
+ await this.sendToChannel(channel, alert);
557
+ const notification = {
558
+ alertId: alert.id,
559
+ channel: channel.type,
560
+ sentAt: Date.now(),
561
+ success: true
562
+ };
563
+ this.emit("notification:sent", notification);
564
+ } catch (error) {
565
+ const notification = {
566
+ alertId: alert.id,
567
+ channel: channel.type,
568
+ sentAt: Date.now(),
569
+ success: false,
570
+ error: error.message
571
+ };
572
+ this.emit("notification:sent", notification);
573
+ }
574
+ }
575
+ }
576
+ /**
577
+ * Send to a specific channel
578
+ */
579
+ async sendToChannel(channel, alert) {
580
+ switch (channel.type) {
581
+ case "webhook":
582
+ if (channel.webhook) {
583
+ await fetch(channel.webhook, {
584
+ method: "POST",
585
+ headers: { "Content-Type": "application/json" },
586
+ body: JSON.stringify({
587
+ alert: {
588
+ id: alert.id,
589
+ metric: alert.metric,
590
+ severity: alert.severity,
591
+ message: alert.message,
592
+ value: alert.currentValue,
593
+ threshold: alert.threshold,
594
+ triggeredAt: new Date(alert.triggeredAt).toISOString()
595
+ }
596
+ })
597
+ });
598
+ }
599
+ break;
600
+ case "slack":
601
+ if (channel.webhook) {
602
+ await fetch(channel.webhook, {
603
+ method: "POST",
604
+ headers: { "Content-Type": "application/json" },
605
+ body: JSON.stringify({
606
+ text: `\u{1F6A8} *${alert.severity.toUpperCase()}*: ${alert.message}`,
607
+ attachments: [
608
+ {
609
+ color: alert.severity === "critical" ? "danger" : "warning",
610
+ fields: [
611
+ { title: "Metric", value: alert.metric, short: true },
612
+ {
613
+ title: "Value",
614
+ value: alert.currentValue.toFixed(4),
615
+ short: true
616
+ },
617
+ {
618
+ title: "Threshold",
619
+ value: alert.threshold.toString(),
620
+ short: true
621
+ }
622
+ ]
623
+ }
624
+ ]
625
+ })
626
+ });
627
+ }
628
+ break;
629
+ case "email":
630
+ console.log(`[Email Alert] To: ${channel.to?.join(", ")}`);
631
+ console.log(`Subject: Alert: ${alert.metric} - ${alert.severity}`);
632
+ console.log(`Body: ${alert.message}`);
633
+ break;
634
+ case "pagerduty":
635
+ console.log(`[PagerDuty Alert] ${alert.severity}: ${alert.message}`);
636
+ break;
637
+ }
638
+ }
639
+ /**
640
+ * Format alert message
641
+ */
642
+ formatMessage(rule, metric, value) {
643
+ const direction = rule.direction === "above" ? "exceeded" : "dropped below";
644
+ return `${metric} ${direction} threshold: ${value.toFixed(4)} (threshold: ${rule.threshold})`;
645
+ }
646
+ /**
647
+ * Get active alerts
648
+ */
649
+ getActiveAlerts() {
650
+ return Array.from(this.activeAlerts.values());
651
+ }
652
+ /**
653
+ * Get alert count
654
+ */
655
+ getAlertCount() {
656
+ return this.alertCount;
657
+ }
658
+ /**
659
+ * Get rules
660
+ */
661
+ getRules() {
662
+ return Array.from(this.rules.values());
663
+ }
664
+ };
665
+ function createAlertManager(config) {
666
+ return new AlertManager(config);
667
+ }
668
+
669
+ export {
670
+ ABTestRunner,
671
+ createABTestRunner,
672
+ ContinuousEval,
673
+ createContinuousEval,
674
+ AlertManager,
675
+ createAlertManager
676
+ };