@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.
@@ -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
@@ -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 log = createLogger();
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
- log.error("Failed to write trace file", {
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
- log.info("span", {
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 log2 = createLogger();
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
- log2.error(`OTLP export failed: ${response.status} ${response.statusText}`);
1148
+ log5.error(`OTLP export failed: ${response.status} ${response.statusText}`);
1066
1149
  }
1067
1150
  } catch (err2) {
1068
- log2.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
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.2.3",
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.2.3"
29
+ "@elsium-ai/core": "^0.3.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "typescript": "^5.7.0"