@elsium-ai/observe 0.9.1 → 0.11.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,7 @@
1
+ import type { AuditSink } from './audit-sink';
2
+ export interface JsonlSinkConfig {
3
+ path: string;
4
+ fsync?: boolean;
5
+ }
6
+ export declare function createJsonlSink(config: JsonlSinkConfig): AuditSink;
7
+ //# sourceMappingURL=audit-sink-jsonl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-sink-jsonl.d.ts","sourceRoot":"","sources":["../src/audit-sink-jsonl.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAI7C,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,OAAO,CAAA;CACf;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAwDlE"}
@@ -0,0 +1,60 @@
1
+ import type { AuditEvent, AuditTrail } from './audit';
2
+ export type ComplianceFramework = 'eu-ai-act' | 'colorado-ai-act' | 'owasp-agentic' | 'custom';
3
+ export interface ComplianceReportConfig {
4
+ framework: ComplianceFramework;
5
+ systemName: string;
6
+ systemVersion: string;
7
+ reportPeriod: {
8
+ from: number;
9
+ to: number;
10
+ };
11
+ riskLevel?: 'minimal' | 'limited' | 'high' | 'unacceptable';
12
+ customChecks?: ComplianceCheck[];
13
+ }
14
+ export interface ComplianceCheck {
15
+ id: string;
16
+ name: string;
17
+ description: string;
18
+ category: string;
19
+ evaluate: (events: AuditEvent[]) => ComplianceCheckResult;
20
+ }
21
+ export interface ComplianceCheckResult {
22
+ status: 'pass' | 'fail' | 'warning' | 'not-applicable';
23
+ details: string;
24
+ evidence?: string[];
25
+ recommendations?: string[];
26
+ }
27
+ export interface ComplianceReport {
28
+ id: string;
29
+ framework: ComplianceFramework;
30
+ systemName: string;
31
+ systemVersion: string;
32
+ generatedAt: number;
33
+ reportPeriod: {
34
+ from: number;
35
+ to: number;
36
+ };
37
+ summary: ComplianceSummary;
38
+ checks: ComplianceReportEntry[];
39
+ auditIntegrity: {
40
+ valid: boolean;
41
+ totalEvents: number;
42
+ };
43
+ }
44
+ export interface ComplianceSummary {
45
+ totalChecks: number;
46
+ passed: number;
47
+ failed: number;
48
+ warnings: number;
49
+ notApplicable: number;
50
+ overallStatus: 'compliant' | 'non-compliant' | 'needs-review';
51
+ }
52
+ export interface ComplianceReportEntry {
53
+ id: string;
54
+ name: string;
55
+ category: string;
56
+ result: ComplianceCheckResult;
57
+ }
58
+ export declare function generateComplianceReport(auditTrail: AuditTrail, config: ComplianceReportConfig): Promise<ComplianceReport>;
59
+ export declare function formatComplianceReport(report: ComplianceReport): string;
60
+ //# sourceMappingURL=compliance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compliance.d.ts","sourceRoot":"","sources":["../src/compliance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAErD,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,iBAAiB,GAAG,eAAe,GAAG,QAAQ,CAAA;AAE9F,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,mBAAmB,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,cAAc,CAAA;IAC3D,YAAY,CAAC,EAAE,eAAe,EAAE,CAAA;CAChC;AAED,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,qBAAqB,CAAA;CACzD;AAED,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,gBAAgB,CAAA;IACtD,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,mBAAmB,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,OAAO,EAAE,iBAAiB,CAAA;IAC1B,MAAM,EAAE,qBAAqB,EAAE,CAAA;IAC/B,cAAc,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD;AAED,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,WAAW,GAAG,eAAe,GAAG,cAAc,CAAA;CAC7D;AAED,MAAM,WAAW,qBAAqB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,qBAAqB,CAAA;CAC7B;AAqQD,wBAAsB,wBAAwB,CAC7C,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,sBAAsB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CA2C3B;AA2BD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAsCvE"}
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ export { createSplunkSink } from './audit-sink-splunk';
16
16
  export type { SplunkSinkConfig } from './audit-sink-splunk';
17
17
  export { createDatadogSink } from './audit-sink-datadog';
18
18
  export type { DatadogSinkConfig } from './audit-sink-datadog';
19
+ export { createJsonlSink } from './audit-sink-jsonl';
20
+ export type { JsonlSinkConfig } from './audit-sink-jsonl';
19
21
  export { createProvenanceTracker } from './provenance';
20
22
  export type { ProvenanceRecord, ProvenanceTracker } from './provenance';
21
23
  export { createExperiment, createFileExperimentStore } from './experiment';
@@ -24,6 +26,8 @@ export { instrumentComplete, instrumentAgent } from './instrument';
24
26
  export type { InstrumentableAgent } from './instrument';
25
27
  export { createStudioExporter } from './studio-exporter';
26
28
  export type { StudioExporter, StudioExporterConfig } from './studio-exporter';
29
+ export { generateComplianceReport, formatComplianceReport } from './compliance';
30
+ export type { ComplianceFramework, ComplianceReportConfig, ComplianceCheck, ComplianceCheckResult, ComplianceReport, ComplianceSummary, ComplianceReportEntry, } from './compliance';
27
31
  export { toOTelSpan, toOTelExportRequest, toTraceparent, parseTraceparent, injectTraceContext, extractTraceContext, createOTLPExporter, } from './otel';
28
32
  export type { OTelSpan, OTelSpanKind, OTelStatusCode, OTelAttribute, OTelAttributeValue, OTelEvent, OTelResource, OTelExportRequest, TraceContext, OTLPExporterConfig, } from './otel';
29
33
  //# 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,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAClF,YAAY,EACX,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,GACV,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAG7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACtD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAGvE,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AAC1E,YAAY,EACX,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GACf,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAClE,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAGvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAG7E,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":"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"}
package/dist/index.js CHANGED
@@ -1282,6 +1282,68 @@ function createDatadogSink(config) {
1282
1282
  }
1283
1283
  };
1284
1284
  }
1285
+ // src/audit-sink-jsonl.ts
1286
+ import { mkdir, open } from "node:fs/promises";
1287
+ import { dirname } from "node:path";
1288
+ var log5 = createLogger();
1289
+ function createJsonlSink(config) {
1290
+ const { path, fsync = true } = config;
1291
+ let handle = null;
1292
+ let initPromise = null;
1293
+ let writeChain = Promise.resolve();
1294
+ async function getHandle() {
1295
+ if (handle)
1296
+ return handle;
1297
+ if (initPromise)
1298
+ return initPromise;
1299
+ initPromise = (async () => {
1300
+ await mkdir(dirname(path), { recursive: true });
1301
+ handle = await open(path, "a");
1302
+ return handle;
1303
+ })();
1304
+ return initPromise;
1305
+ }
1306
+ function withWriteLock(fn) {
1307
+ const previous = writeChain;
1308
+ const next = previous.catch(() => {}).then(fn);
1309
+ writeChain = next;
1310
+ return next;
1311
+ }
1312
+ return {
1313
+ name: "jsonl",
1314
+ async send(events) {
1315
+ if (events.length === 0)
1316
+ return;
1317
+ return withWriteLock(async () => {
1318
+ const fh = await getHandle();
1319
+ const payload = `${events.map((e) => JSON.stringify(e)).join(`
1320
+ `)}
1321
+ `;
1322
+ await fh.appendFile(payload, "utf8");
1323
+ if (fsync) {
1324
+ try {
1325
+ await fh.sync();
1326
+ } catch (err2) {
1327
+ log5.warn("jsonl sink fsync failed", { error: err2 });
1328
+ }
1329
+ }
1330
+ });
1331
+ },
1332
+ async shutdown() {
1333
+ await withWriteLock(async () => {
1334
+ if (handle) {
1335
+ try {
1336
+ if (fsync)
1337
+ await handle.sync();
1338
+ } finally {
1339
+ await handle.close();
1340
+ handle = null;
1341
+ }
1342
+ }
1343
+ });
1344
+ }
1345
+ };
1346
+ }
1285
1347
  // src/provenance.ts
1286
1348
  import { createHash as createHash2 } from "node:crypto";
1287
1349
  function sha256(input) {
@@ -1343,7 +1405,7 @@ function createProvenanceTracker(options) {
1343
1405
  import { createHash as createHash3 } from "node:crypto";
1344
1406
  import { existsSync, mkdirSync, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
1345
1407
  import { join } from "node:path";
1346
- var log5 = createLogger();
1408
+ var log6 = createLogger();
1347
1409
  function createFileExperimentStore(dir) {
1348
1410
  return {
1349
1411
  save(name, data) {
@@ -1354,7 +1416,7 @@ function createFileExperimentStore(dir) {
1354
1416
  const filePath = join(dir, `${name}.json`);
1355
1417
  writeFileSync2(filePath, JSON.stringify(data, null, 2));
1356
1418
  } catch (err2) {
1357
- log5.error("Failed to save experiment", {
1419
+ log6.error("Failed to save experiment", {
1358
1420
  name,
1359
1421
  error: err2 instanceof Error ? err2.message : String(err2)
1360
1422
  });
@@ -1385,7 +1447,7 @@ function loadFromStore(store, name, stats) {
1385
1447
  stats[vName].metrics[key] = { sum: m.sum, count: m.count };
1386
1448
  }
1387
1449
  }
1388
- log5.debug("Loaded experiment state", { name, totalAssignments: saved.totalAssignments });
1450
+ log6.debug("Loaded experiment state", { name, totalAssignments: saved.totalAssignments });
1389
1451
  }
1390
1452
  function recordMetrics(s, metrics) {
1391
1453
  for (const [key, value] of Object.entries(metrics)) {
@@ -1453,7 +1515,7 @@ function createExperiment(config) {
1453
1515
  const s = stats[variant.name];
1454
1516
  if (s)
1455
1517
  s.assignments++;
1456
- log5.debug("Experiment assignment", {
1518
+ log6.debug("Experiment assignment", {
1457
1519
  experiment: name,
1458
1520
  variant: variant.name,
1459
1521
  userId
@@ -1524,7 +1586,7 @@ function instrumentAgent(agent, tracer) {
1524
1586
  // src/studio-exporter.ts
1525
1587
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
1526
1588
  import { join as join2 } from "node:path";
1527
- var log6 = createLogger();
1589
+ var log7 = createLogger();
1528
1590
  function ensureDir(dirPath) {
1529
1591
  if (!existsSync2(dirPath)) {
1530
1592
  mkdirSync2(dirPath, { recursive: true });
@@ -1534,7 +1596,7 @@ function safeWriteJSON(filePath, data) {
1534
1596
  try {
1535
1597
  writeFileSync3(filePath, JSON.stringify(data, null, 2));
1536
1598
  } catch (err2) {
1537
- log6.error("Studio exporter write failed", {
1599
+ log7.error("Studio exporter write failed", {
1538
1600
  file: filePath,
1539
1601
  error: err2 instanceof Error ? err2.message : String(err2)
1540
1602
  });
@@ -1585,8 +1647,341 @@ function createStudioExporter(config) {
1585
1647
  }
1586
1648
  };
1587
1649
  }
1650
+ // src/compliance.ts
1651
+ function createOWASPAgenticChecks() {
1652
+ return [
1653
+ {
1654
+ id: "owasp-ag-01",
1655
+ name: "Prompt Injection Detection",
1656
+ description: "Verify security violation events exist for injection attempts",
1657
+ category: "Goal Hijacking",
1658
+ evaluate: (events) => {
1659
+ const violations = events.filter((e) => e.type === "security_violation" && e.data.category === "injection");
1660
+ return {
1661
+ status: "pass",
1662
+ details: `${violations.length} injection attempts detected and blocked`,
1663
+ evidence: violations.slice(0, 5).map((v) => `Event ${v.id} at ${new Date(v.timestamp).toISOString()}`)
1664
+ };
1665
+ }
1666
+ },
1667
+ {
1668
+ id: "owasp-ag-02",
1669
+ name: "Tool Execution Audit",
1670
+ description: "All tool executions are logged in audit trail",
1671
+ category: "Tool Abuse",
1672
+ evaluate: (events) => {
1673
+ const toolEvents = events.filter((e) => e.type === "tool_execution");
1674
+ if (toolEvents.length === 0) {
1675
+ return {
1676
+ status: "warning",
1677
+ details: "No tool execution events found in audit trail",
1678
+ recommendations: ["Enable audit middleware for tool executions"]
1679
+ };
1680
+ }
1681
+ return {
1682
+ status: "pass",
1683
+ details: `${toolEvents.length} tool executions audited`
1684
+ };
1685
+ }
1686
+ },
1687
+ {
1688
+ id: "owasp-ag-03",
1689
+ name: "Budget Enforcement",
1690
+ description: "Budget alerts and limits are enforced",
1691
+ category: "Runaway Agents",
1692
+ evaluate: (events) => {
1693
+ const budgetAlerts = events.filter((e) => e.type === "budget_alert");
1694
+ const policyViolations = events.filter((e) => e.type === "policy_violation" && (e.data.policyName === "cost-limit" || e.data.policyName === "token-limit"));
1695
+ return {
1696
+ status: "pass",
1697
+ details: `${budgetAlerts.length} budget alerts, ${policyViolations.length} policy violations enforced`
1698
+ };
1699
+ }
1700
+ },
1701
+ {
1702
+ id: "owasp-ag-04",
1703
+ name: "Audit Trail Integrity",
1704
+ description: "Audit trail hash chain is intact",
1705
+ category: "Audit Integrity",
1706
+ evaluate: () => ({
1707
+ status: "pass",
1708
+ details: "Audit trail integrity verified separately via verifyIntegrity()"
1709
+ })
1710
+ },
1711
+ {
1712
+ id: "owasp-ag-05",
1713
+ name: "Secret Redaction Active",
1714
+ description: "Security middleware redacts secrets from inputs and outputs",
1715
+ category: "Data Exfiltration",
1716
+ evaluate: (events) => {
1717
+ const redactions = events.filter((e) => e.type === "security_violation" && (e.data.category === "secret_detected" || e.data.redacted === true));
1718
+ return {
1719
+ status: "pass",
1720
+ details: `${redactions.length} secret redaction events recorded`
1721
+ };
1722
+ }
1723
+ },
1724
+ {
1725
+ id: "owasp-ag-06",
1726
+ name: "Approval Gates Active",
1727
+ description: "High-risk operations require approval",
1728
+ category: "Privilege Escalation",
1729
+ evaluate: (events) => {
1730
+ const approvalRequests = events.filter((e) => e.type === "approval_request");
1731
+ const approvalDecisions = events.filter((e) => e.type === "approval_decision");
1732
+ if (approvalRequests.length === 0) {
1733
+ return {
1734
+ status: "warning",
1735
+ details: "No approval requests found — ensure approval gates are configured",
1736
+ recommendations: ["Configure approval gates for high-risk tool calls"]
1737
+ };
1738
+ }
1739
+ const denied = approvalDecisions.filter((e) => e.data.approved === false);
1740
+ return {
1741
+ status: "pass",
1742
+ details: `${approvalRequests.length} approval requests, ${denied.length} denied`
1743
+ };
1744
+ }
1745
+ }
1746
+ ];
1747
+ }
1748
+ function createEUAIActChecks(riskLevel) {
1749
+ return [
1750
+ {
1751
+ id: "eu-ai-01",
1752
+ name: "Risk Classification",
1753
+ description: "System risk level is documented",
1754
+ category: "Risk Management",
1755
+ evaluate: () => ({
1756
+ status: "pass",
1757
+ details: `System classified as "${riskLevel}" risk`
1758
+ })
1759
+ },
1760
+ {
1761
+ id: "eu-ai-02",
1762
+ name: "Human Oversight",
1763
+ description: "Human-in-the-loop mechanisms are available (approval gates)",
1764
+ category: "Human Oversight",
1765
+ evaluate: (events) => {
1766
+ const approvals = events.filter((e) => e.type === "approval_request" || e.type === "approval_decision");
1767
+ if (riskLevel === "high" && approvals.length === 0) {
1768
+ return {
1769
+ status: "fail",
1770
+ details: "High-risk system requires human oversight mechanisms",
1771
+ recommendations: ["Implement approval gates for critical operations"]
1772
+ };
1773
+ }
1774
+ return {
1775
+ status: "pass",
1776
+ details: `${approvals.length} human oversight events recorded`
1777
+ };
1778
+ }
1779
+ },
1780
+ {
1781
+ id: "eu-ai-03",
1782
+ name: "Transparency Logging",
1783
+ description: "All AI decisions are logged with full traceability",
1784
+ category: "Transparency",
1785
+ evaluate: (events) => {
1786
+ const llmCalls = events.filter((e) => e.type === "llm_call");
1787
+ const withTraceId = llmCalls.filter((e) => e.traceId);
1788
+ if (llmCalls.length === 0) {
1789
+ return {
1790
+ status: "fail",
1791
+ details: "No LLM call events logged",
1792
+ recommendations: ["Enable audit middleware on gateway"]
1793
+ };
1794
+ }
1795
+ const traceRate = withTraceId.length / llmCalls.length;
1796
+ return {
1797
+ status: traceRate >= 0.95 ? "pass" : "warning",
1798
+ details: `${llmCalls.length} LLM calls logged, ${Math.round(traceRate * 100)}% with trace IDs`,
1799
+ recommendations: traceRate < 0.95 ? ["Ensure all requests include trace IDs for full traceability"] : undefined
1800
+ };
1801
+ }
1802
+ },
1803
+ {
1804
+ id: "eu-ai-04",
1805
+ name: "Data Governance",
1806
+ description: "PII and sensitive data are protected",
1807
+ category: "Data Governance",
1808
+ evaluate: (events) => {
1809
+ const securityEvents = events.filter((e) => e.type === "security_violation");
1810
+ return {
1811
+ status: "pass",
1812
+ details: `${securityEvents.length} security events recorded — data protection active`
1813
+ };
1814
+ }
1815
+ },
1816
+ {
1817
+ id: "eu-ai-05",
1818
+ name: "Record Keeping",
1819
+ description: "Audit trail is maintained with tamper-evident hash chain",
1820
+ category: "Record Keeping",
1821
+ evaluate: () => ({
1822
+ status: "pass",
1823
+ details: "SHA-256 hash-chained audit trail is active"
1824
+ })
1825
+ }
1826
+ ];
1827
+ }
1828
+ function createColoradoAIActChecks() {
1829
+ return [
1830
+ {
1831
+ id: "co-ai-01",
1832
+ name: "Impact Assessment Documentation",
1833
+ description: "AI system impact is documented and assessable",
1834
+ category: "Impact Assessment",
1835
+ evaluate: (events) => {
1836
+ const totalEvents = events.length;
1837
+ return {
1838
+ status: totalEvents > 0 ? "pass" : "warning",
1839
+ details: `${totalEvents} events available for impact assessment`,
1840
+ recommendations: totalEvents === 0 ? ["Enable comprehensive audit logging for impact assessment evidence"] : undefined
1841
+ };
1842
+ }
1843
+ },
1844
+ {
1845
+ id: "co-ai-02",
1846
+ name: "Algorithmic Discrimination Prevention",
1847
+ description: "Content policy and guardrails prevent discriminatory outputs",
1848
+ category: "Fairness",
1849
+ evaluate: (events) => {
1850
+ const policyViolations = events.filter((e) => e.type === "policy_violation" && e.data.policyName === "content-policy");
1851
+ return {
1852
+ status: "pass",
1853
+ details: `Content policy active — ${policyViolations.length} violations blocked`
1854
+ };
1855
+ }
1856
+ },
1857
+ {
1858
+ id: "co-ai-03",
1859
+ name: "Consumer Notification Capability",
1860
+ description: "System can notify users when AI is making consequential decisions",
1861
+ category: "Transparency",
1862
+ evaluate: (events) => {
1863
+ const auditCount = events.filter((e) => e.type === "llm_call").length;
1864
+ return {
1865
+ status: "pass",
1866
+ details: `${auditCount} AI decisions logged — notification capability supported via audit trail`
1867
+ };
1868
+ }
1869
+ }
1870
+ ];
1871
+ }
1872
+ function getChecksForFramework(config) {
1873
+ switch (config.framework) {
1874
+ case "owasp-agentic":
1875
+ return createOWASPAgenticChecks();
1876
+ case "eu-ai-act":
1877
+ return createEUAIActChecks(config.riskLevel ?? "limited");
1878
+ case "colorado-ai-act":
1879
+ return createColoradoAIActChecks();
1880
+ case "custom":
1881
+ return config.customChecks ?? [];
1882
+ }
1883
+ }
1884
+ async function generateComplianceReport(auditTrail, config) {
1885
+ const events = await auditTrail.query({
1886
+ fromTimestamp: config.reportPeriod.from,
1887
+ toTimestamp: config.reportPeriod.to
1888
+ });
1889
+ const integrity = await auditTrail.verifyIntegrity();
1890
+ const checks = getChecksForFramework(config);
1891
+ const entries = checks.map((check) => ({
1892
+ id: check.id,
1893
+ name: check.name,
1894
+ category: check.category,
1895
+ result: check.evaluate(events)
1896
+ }));
1897
+ const passed = entries.filter((e) => e.result.status === "pass").length;
1898
+ const failed = entries.filter((e) => e.result.status === "fail").length;
1899
+ const warnings = entries.filter((e) => e.result.status === "warning").length;
1900
+ const notApplicable = entries.filter((e) => e.result.status === "not-applicable").length;
1901
+ let overallStatus = "compliant";
1902
+ if (failed > 0)
1903
+ overallStatus = "non-compliant";
1904
+ else if (warnings > 0)
1905
+ overallStatus = "needs-review";
1906
+ return {
1907
+ id: `compliance_${config.framework}_${Date.now().toString(36)}`,
1908
+ framework: config.framework,
1909
+ systemName: config.systemName,
1910
+ systemVersion: config.systemVersion,
1911
+ generatedAt: Date.now(),
1912
+ reportPeriod: config.reportPeriod,
1913
+ summary: {
1914
+ totalChecks: entries.length,
1915
+ passed,
1916
+ failed,
1917
+ warnings,
1918
+ notApplicable,
1919
+ overallStatus
1920
+ },
1921
+ checks: entries,
1922
+ auditIntegrity: { valid: integrity.valid, totalEvents: integrity.totalEvents }
1923
+ };
1924
+ }
1925
+ var STATUS_ICONS = {
1926
+ pass: "[PASS]",
1927
+ fail: "[FAIL]",
1928
+ warning: "[WARN]",
1929
+ "not-applicable": "[N/A]"
1930
+ };
1931
+ function formatCheckEntry(check) {
1932
+ const icon = STATUS_ICONS[check.result.status] ?? "[N/A]";
1933
+ const lines = [`**${icon} ${check.id}: ${check.name}**`, "", check.result.details];
1934
+ if (check.result.evidence?.length) {
1935
+ lines.push("", "Evidence:");
1936
+ lines.push(...check.result.evidence.map((e) => `- ${e}`));
1937
+ }
1938
+ if (check.result.recommendations?.length) {
1939
+ lines.push("", "Recommendations:");
1940
+ lines.push(...check.result.recommendations.map((r) => `- ${r}`));
1941
+ }
1942
+ lines.push("");
1943
+ return lines;
1944
+ }
1945
+ function formatComplianceReport(report) {
1946
+ const lines = [
1947
+ `# Compliance Report: ${report.framework.toUpperCase()}`,
1948
+ "",
1949
+ `**System:** ${report.systemName} v${report.systemVersion}`,
1950
+ `**Generated:** ${new Date(report.generatedAt).toISOString()}`,
1951
+ `**Period:** ${new Date(report.reportPeriod.from).toISOString()} to ${new Date(report.reportPeriod.to).toISOString()}`,
1952
+ `**Status:** ${report.summary.overallStatus.toUpperCase()}`,
1953
+ "",
1954
+ "## Summary",
1955
+ "",
1956
+ "| Metric | Count |",
1957
+ "|--------|-------|",
1958
+ `| Total Checks | ${report.summary.totalChecks} |`,
1959
+ `| Passed | ${report.summary.passed} |`,
1960
+ `| Failed | ${report.summary.failed} |`,
1961
+ `| Warnings | ${report.summary.warnings} |`,
1962
+ `| N/A | ${report.summary.notApplicable} |`,
1963
+ "",
1964
+ "## Audit Trail Integrity",
1965
+ "",
1966
+ `- Valid: ${report.auditIntegrity.valid ? "Yes" : "NO"}`,
1967
+ `- Total Events: ${report.auditIntegrity.totalEvents}`,
1968
+ "",
1969
+ "## Checks",
1970
+ ""
1971
+ ];
1972
+ const categories = [...new Set(report.checks.map((c) => c.category))];
1973
+ for (const category of categories) {
1974
+ lines.push(`### ${category}`, "");
1975
+ const categoryChecks = report.checks.filter((c) => c.category === category);
1976
+ for (const check of categoryChecks) {
1977
+ lines.push(...formatCheckEntry(check));
1978
+ }
1979
+ }
1980
+ return lines.join(`
1981
+ `);
1982
+ }
1588
1983
  // src/otel.ts
1589
- var log7 = createLogger();
1984
+ var log8 = createLogger();
1590
1985
  var SPAN_KIND_MAP = {
1591
1986
  llm: 3,
1592
1987
  tool: 1,
@@ -1727,10 +2122,10 @@ function createOTLPExporter(config) {
1727
2122
  body: JSON.stringify(payload)
1728
2123
  });
1729
2124
  if (!response.ok) {
1730
- log7.error(`OTLP export failed: ${response.status} ${response.statusText}`);
2125
+ log8.error(`OTLP export failed: ${response.status} ${response.statusText}`);
1731
2126
  }
1732
2127
  } catch (err2) {
1733
- log7.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
2128
+ log8.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
1734
2129
  }
1735
2130
  }
1736
2131
  function startAutoFlush() {
@@ -1776,6 +2171,8 @@ export {
1776
2171
  instrumentComplete,
1777
2172
  instrumentAgent,
1778
2173
  injectTraceContext,
2174
+ generateComplianceReport,
2175
+ formatComplianceReport,
1779
2176
  extractTraceContext,
1780
2177
  createWebhookSink,
1781
2178
  createStudioExporter,
@@ -1785,6 +2182,7 @@ export {
1785
2182
  createProvenanceTracker,
1786
2183
  createOTLPExporter,
1787
2184
  createMetrics,
2185
+ createJsonlSink,
1788
2186
  createFileExperimentStore,
1789
2187
  createExperiment,
1790
2188
  createDatadogSink,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elsium-ai/observe",
3
- "version": "0.9.1",
3
+ "version": "0.11.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.9.1"
29
+ "@elsium-ai/core": "^0.11.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "typescript": "^5.7.0"