@elsium-ai/observe 0.2.3 → 0.3.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/dist/experiment.d.ts +28 -0
- package/dist/experiment.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -6
- package/package.json +2 -2
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ExperimentVariant {
|
|
2
|
+
name: string;
|
|
3
|
+
weight: number;
|
|
4
|
+
config: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export interface ExperimentResults {
|
|
7
|
+
name: string;
|
|
8
|
+
totalAssignments: number;
|
|
9
|
+
variants: Record<string, {
|
|
10
|
+
assignments: number;
|
|
11
|
+
metrics: Record<string, {
|
|
12
|
+
sum: number;
|
|
13
|
+
count: number;
|
|
14
|
+
avg: number;
|
|
15
|
+
}>;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export interface Experiment {
|
|
19
|
+
assign(userId?: string): ExperimentVariant;
|
|
20
|
+
record(variant: string, metrics: Record<string, number>): void;
|
|
21
|
+
results(): ExperimentResults;
|
|
22
|
+
}
|
|
23
|
+
export interface ExperimentConfig {
|
|
24
|
+
name: string;
|
|
25
|
+
variants: ExperimentVariant[];
|
|
26
|
+
}
|
|
27
|
+
export declare function createExperiment(config: ExperimentConfig): Experiment;
|
|
28
|
+
//# sourceMappingURL=experiment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment.d.ts","sourceRoot":"","sources":["../src/experiment.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,MAAM,CACf,MAAM,EACN;QACC,WAAW,EAAE,MAAM,CAAA;QACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KACpE,CACD,CAAA;CACD;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAA;IAC1C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9D,OAAO,IAAI,iBAAiB,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,iBAAiB,EAAE,CAAA;CAC7B;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA0FrE"}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export { createAuditTrail, auditMiddleware } from './audit';
|
|
|
10
10
|
export type { AuditEventType, AuditEvent, AuditStorageAdapter, AuditQueryFilter, AuditIntegrityResult, AuditTrailConfig, AuditTrail, } from './audit';
|
|
11
11
|
export { createProvenanceTracker } from './provenance';
|
|
12
12
|
export type { ProvenanceRecord, ProvenanceTracker } from './provenance';
|
|
13
|
+
export { createExperiment } from './experiment';
|
|
14
|
+
export type { Experiment, ExperimentConfig, ExperimentVariant, ExperimentResults, } from './experiment';
|
|
13
15
|
export { toOTelSpan, toOTelExportRequest, toTraceparent, parseTraceparent, injectTraceContext, extractTraceContext, createOTLPExporter, } from './otel';
|
|
14
16
|
export type { OTelSpan, OTelSpanKind, OTelStatusCode, OTelAttribute, OTelAttributeValue, OTelEvent, OTelResource, OTelExportRequest, TraceContext, OTLPExporterConfig, } from './otel';
|
|
15
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAG1F,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACnE,YAAY,EACX,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,cAAc,GACd,MAAM,eAAe,CAAA;AAGtB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAG9F,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG9D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC3D,YAAY,EACX,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,GACV,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAGvE,OAAO,EACN,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,QAAQ,CAAA;AACf,YAAY,EACX,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,GAClB,MAAM,QAAQ,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAG1F,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACnE,YAAY,EACX,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,cAAc,GACd,MAAM,eAAe,CAAA;AAGtB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAG9F,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG9D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAC3D,YAAY,EACX,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,GACV,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAGvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,YAAY,EACX,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,GACjB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACN,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,QAAQ,CAAA;AACf,YAAY,EACX,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,GAClB,MAAM,QAAQ,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -140,6 +140,11 @@ function createLogger(options = {}) {
|
|
|
140
140
|
}
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
+
// ../core/src/schema.ts
|
|
144
|
+
var log = createLogger();
|
|
145
|
+
// ../core/src/registry.ts
|
|
146
|
+
var log2 = createLogger();
|
|
147
|
+
var BLOCKED_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
143
148
|
// src/span.ts
|
|
144
149
|
function createSpan(name, options = {}) {
|
|
145
150
|
const id = generateId("spn");
|
|
@@ -492,7 +497,7 @@ function createCostEngine(config = {}) {
|
|
|
492
497
|
}
|
|
493
498
|
// src/tracer.ts
|
|
494
499
|
import { writeFileSync } from "node:fs";
|
|
495
|
-
var
|
|
500
|
+
var log3 = createLogger();
|
|
496
501
|
function observe(config = {}) {
|
|
497
502
|
const {
|
|
498
503
|
output = ["console"],
|
|
@@ -515,7 +520,7 @@ function observe(config = {}) {
|
|
|
515
520
|
try {
|
|
516
521
|
writeFileSync(filename, JSON.stringify(spansToExport, null, 2));
|
|
517
522
|
} catch (err2) {
|
|
518
|
-
|
|
523
|
+
log3.error("Failed to write trace file", {
|
|
519
524
|
error: err2 instanceof Error ? err2.message : String(err2)
|
|
520
525
|
});
|
|
521
526
|
}
|
|
@@ -590,7 +595,7 @@ function observe(config = {}) {
|
|
|
590
595
|
function consoleHandler(span) {
|
|
591
596
|
const duration = span.durationMs !== undefined ? `${span.durationMs}ms` : "running";
|
|
592
597
|
const status = span.status === "error" ? "[ERROR]" : span.status === "ok" ? "[OK]" : "[...]";
|
|
593
|
-
|
|
598
|
+
log3.info("span", {
|
|
594
599
|
trace: span.traceId,
|
|
595
600
|
span: span.name,
|
|
596
601
|
kind: span.kind,
|
|
@@ -920,8 +925,86 @@ function createProvenanceTracker(options) {
|
|
|
920
925
|
}
|
|
921
926
|
};
|
|
922
927
|
}
|
|
928
|
+
// src/experiment.ts
|
|
929
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
930
|
+
var log4 = createLogger();
|
|
931
|
+
function createExperiment(config) {
|
|
932
|
+
const { name, variants } = config;
|
|
933
|
+
if (variants.length === 0) {
|
|
934
|
+
throw new Error("Experiment must have at least one variant");
|
|
935
|
+
}
|
|
936
|
+
const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);
|
|
937
|
+
const stats = {};
|
|
938
|
+
for (const v of variants) {
|
|
939
|
+
stats[v.name] = { assignments: 0, metrics: {} };
|
|
940
|
+
}
|
|
941
|
+
function hashAssign(userId) {
|
|
942
|
+
const hash = createHash3("sha256").update(`${name}:${userId}`).digest();
|
|
943
|
+
const value = hash.readUInt32BE(0) % 1e4 / 1e4;
|
|
944
|
+
return pickVariant(value);
|
|
945
|
+
}
|
|
946
|
+
function randomAssign() {
|
|
947
|
+
const value = Math.random();
|
|
948
|
+
return pickVariant(value);
|
|
949
|
+
}
|
|
950
|
+
function pickVariant(value) {
|
|
951
|
+
let cumulative = 0;
|
|
952
|
+
for (const v of variants) {
|
|
953
|
+
cumulative += v.weight / totalWeight;
|
|
954
|
+
if (value < cumulative)
|
|
955
|
+
return v;
|
|
956
|
+
}
|
|
957
|
+
return variants[variants.length - 1];
|
|
958
|
+
}
|
|
959
|
+
return {
|
|
960
|
+
assign(userId) {
|
|
961
|
+
const variant = userId ? hashAssign(userId) : randomAssign();
|
|
962
|
+
const s = stats[variant.name];
|
|
963
|
+
if (s)
|
|
964
|
+
s.assignments++;
|
|
965
|
+
log4.debug("Experiment assignment", {
|
|
966
|
+
experiment: name,
|
|
967
|
+
variant: variant.name,
|
|
968
|
+
userId
|
|
969
|
+
});
|
|
970
|
+
return variant;
|
|
971
|
+
},
|
|
972
|
+
record(variant, metrics) {
|
|
973
|
+
const s = stats[variant];
|
|
974
|
+
if (!s)
|
|
975
|
+
return;
|
|
976
|
+
for (const [key, value] of Object.entries(metrics)) {
|
|
977
|
+
if (!s.metrics[key]) {
|
|
978
|
+
s.metrics[key] = { sum: 0, count: 0 };
|
|
979
|
+
}
|
|
980
|
+
s.metrics[key].sum += value;
|
|
981
|
+
s.metrics[key].count++;
|
|
982
|
+
}
|
|
983
|
+
},
|
|
984
|
+
results() {
|
|
985
|
+
let totalAssignments = 0;
|
|
986
|
+
const variantResults = {};
|
|
987
|
+
for (const [vName, s] of Object.entries(stats)) {
|
|
988
|
+
totalAssignments += s.assignments;
|
|
989
|
+
const metricsResult = {};
|
|
990
|
+
for (const [key, m] of Object.entries(s.metrics)) {
|
|
991
|
+
metricsResult[key] = {
|
|
992
|
+
sum: m.sum,
|
|
993
|
+
count: m.count,
|
|
994
|
+
avg: m.count > 0 ? m.sum / m.count : 0
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
variantResults[vName] = {
|
|
998
|
+
assignments: s.assignments,
|
|
999
|
+
metrics: metricsResult
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
return { name, totalAssignments, variants: variantResults };
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
923
1006
|
// src/otel.ts
|
|
924
|
-
var
|
|
1007
|
+
var log5 = createLogger();
|
|
925
1008
|
var SPAN_KIND_MAP = {
|
|
926
1009
|
llm: 3,
|
|
927
1010
|
tool: 1,
|
|
@@ -1062,10 +1145,10 @@ function createOTLPExporter(config) {
|
|
|
1062
1145
|
body: JSON.stringify(payload)
|
|
1063
1146
|
});
|
|
1064
1147
|
if (!response.ok) {
|
|
1065
|
-
|
|
1148
|
+
log5.error(`OTLP export failed: ${response.status} ${response.statusText}`);
|
|
1066
1149
|
}
|
|
1067
1150
|
} catch (err2) {
|
|
1068
|
-
|
|
1151
|
+
log5.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
|
|
1069
1152
|
}
|
|
1070
1153
|
}
|
|
1071
1154
|
function startAutoFlush() {
|
|
@@ -1114,6 +1197,7 @@ export {
|
|
|
1114
1197
|
createProvenanceTracker,
|
|
1115
1198
|
createOTLPExporter,
|
|
1116
1199
|
createMetrics,
|
|
1200
|
+
createExperiment,
|
|
1117
1201
|
createCostEngine,
|
|
1118
1202
|
createAuditTrail,
|
|
1119
1203
|
auditMiddleware
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elsium-ai/observe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Observability, tracing, and cost tracking for ElsiumAI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eric Utrera <ebutrera9103@gmail.com>",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dev": "bun --watch src/index.ts"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@elsium-ai/core": "^0.
|
|
29
|
+
"@elsium-ai/core": "^0.3.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"typescript": "^5.7.0"
|