@warlock.js/ai-panoptic 4.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.
Files changed (124) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/LICENSE +21 -0
  3. package/README.md +111 -0
  4. package/cjs/index.cjs +1370 -0
  5. package/cjs/index.cjs.map +1 -0
  6. package/esm/collector/collector.d.mts +19 -0
  7. package/esm/collector/collector.d.mts.map +1 -0
  8. package/esm/collector/collector.mjs +89 -0
  9. package/esm/collector/collector.mjs.map +1 -0
  10. package/esm/collector/extract-span-attributes.d.mts +29 -0
  11. package/esm/collector/extract-span-attributes.d.mts.map +1 -0
  12. package/esm/collector/extract-span-attributes.mjs +76 -0
  13. package/esm/collector/extract-span-attributes.mjs.map +1 -0
  14. package/esm/collector/index.d.mts +5 -0
  15. package/esm/collector/normalize-error.d.mts +27 -0
  16. package/esm/collector/normalize-error.d.mts.map +1 -0
  17. package/esm/collector/normalize-error.mjs +49 -0
  18. package/esm/collector/normalize-error.mjs.map +1 -0
  19. package/esm/collector/report-to-span.d.mts +31 -0
  20. package/esm/collector/report-to-span.d.mts.map +1 -0
  21. package/esm/collector/report-to-span.mjs +53 -0
  22. package/esm/collector/report-to-span.mjs.map +1 -0
  23. package/esm/collector/report-to-trace.d.mts +35 -0
  24. package/esm/collector/report-to-trace.d.mts.map +1 -0
  25. package/esm/collector/report-to-trace.mjs +53 -0
  26. package/esm/collector/report-to-trace.mjs.map +1 -0
  27. package/esm/contracts/collector.contract.d.mts +63 -0
  28. package/esm/contracts/collector.contract.d.mts.map +1 -0
  29. package/esm/contracts/exporter.contract.d.mts +76 -0
  30. package/esm/contracts/exporter.contract.d.mts.map +1 -0
  31. package/esm/contracts/index.d.mts +3 -0
  32. package/esm/contracts/trace.type.d.mts +122 -0
  33. package/esm/contracts/trace.type.d.mts.map +1 -0
  34. package/esm/exporters/console/console-exporter.d.mts +25 -0
  35. package/esm/exporters/console/console-exporter.d.mts.map +1 -0
  36. package/esm/exporters/console/console-exporter.mjs +79 -0
  37. package/esm/exporters/console/console-exporter.mjs.map +1 -0
  38. package/esm/exporters/console/console-exporter.type.d.mts +36 -0
  39. package/esm/exporters/console/console-exporter.type.d.mts.map +1 -0
  40. package/esm/exporters/console/format-span-line.d.mts +17 -0
  41. package/esm/exporters/console/format-span-line.d.mts.map +1 -0
  42. package/esm/exporters/console/format-span-line.mjs +41 -0
  43. package/esm/exporters/console/format-span-line.mjs.map +1 -0
  44. package/esm/exporters/console/index.d.mts +3 -0
  45. package/esm/exporters/file/file-exporter.d.mts +23 -0
  46. package/esm/exporters/file/file-exporter.d.mts.map +1 -0
  47. package/esm/exporters/file/file-exporter.mjs +93 -0
  48. package/esm/exporters/file/file-exporter.mjs.map +1 -0
  49. package/esm/exporters/file/file-exporter.type.d.mts +39 -0
  50. package/esm/exporters/file/file-exporter.type.d.mts.map +1 -0
  51. package/esm/exporters/file/index.d.mts +2 -0
  52. package/esm/exporters/index.d.mts +12 -0
  53. package/esm/exporters/index.mjs +12 -0
  54. package/esm/exporters/langfuse/index.d.mts +2 -0
  55. package/esm/exporters/langfuse/index.mjs +3 -0
  56. package/esm/exporters/langfuse/langfuse-exporter.d.mts +27 -0
  57. package/esm/exporters/langfuse/langfuse-exporter.d.mts.map +1 -0
  58. package/esm/exporters/langfuse/langfuse-exporter.mjs +158 -0
  59. package/esm/exporters/langfuse/langfuse-exporter.mjs.map +1 -0
  60. package/esm/exporters/langfuse/langfuse-exporter.type.d.mts +90 -0
  61. package/esm/exporters/langfuse/langfuse-exporter.type.d.mts.map +1 -0
  62. package/esm/exporters/otel/index.d.mts +2 -0
  63. package/esm/exporters/otel/index.mjs +3 -0
  64. package/esm/exporters/otel/otel-exporter.d.mts +29 -0
  65. package/esm/exporters/otel/otel-exporter.d.mts.map +1 -0
  66. package/esm/exporters/otel/otel-exporter.mjs +142 -0
  67. package/esm/exporters/otel/otel-exporter.mjs.map +1 -0
  68. package/esm/exporters/otel/otel-exporter.type.d.mts +39 -0
  69. package/esm/exporters/otel/otel-exporter.type.d.mts.map +1 -0
  70. package/esm/exporters/utils/gen-ai-attributes.d.mts +65 -0
  71. package/esm/exporters/utils/gen-ai-attributes.d.mts.map +1 -0
  72. package/esm/exporters/utils/gen-ai-attributes.mjs +88 -0
  73. package/esm/exporters/utils/gen-ai-attributes.mjs.map +1 -0
  74. package/esm/exporters/utils/index.d.mts +3 -0
  75. package/esm/exporters/utils/total-cost.d.mts +20 -0
  76. package/esm/exporters/utils/total-cost.d.mts.map +1 -0
  77. package/esm/exporters/utils/total-cost.mjs +23 -0
  78. package/esm/exporters/utils/total-cost.mjs.map +1 -0
  79. package/esm/exporters/utils/walk-spans.d.mts +18 -0
  80. package/esm/exporters/utils/walk-spans.d.mts.map +1 -0
  81. package/esm/exporters/utils/walk-spans.mjs +21 -0
  82. package/esm/exporters/utils/walk-spans.mjs.map +1 -0
  83. package/esm/index.d.mts +31 -0
  84. package/esm/index.mjs +22 -0
  85. package/esm/panoptic/index.d.mts +4 -0
  86. package/esm/panoptic/panoptic-middleware.d.mts +38 -0
  87. package/esm/panoptic/panoptic-middleware.d.mts.map +1 -0
  88. package/esm/panoptic/panoptic-middleware.mjs +68 -0
  89. package/esm/panoptic/panoptic-middleware.mjs.map +1 -0
  90. package/esm/panoptic/panoptic-target.type.d.mts +53 -0
  91. package/esm/panoptic/panoptic-target.type.d.mts.map +1 -0
  92. package/esm/panoptic/panoptic.d.mts +37 -0
  93. package/esm/panoptic/panoptic.d.mts.map +1 -0
  94. package/esm/panoptic/panoptic.mjs +134 -0
  95. package/esm/panoptic/panoptic.mjs.map +1 -0
  96. package/esm/panoptic/panoptic.type.d.mts +100 -0
  97. package/esm/panoptic/panoptic.type.d.mts.map +1 -0
  98. package/esm/store/in-memory-trace-store.d.mts +32 -0
  99. package/esm/store/in-memory-trace-store.d.mts.map +1 -0
  100. package/esm/store/in-memory-trace-store.mjs +134 -0
  101. package/esm/store/in-memory-trace-store.mjs.map +1 -0
  102. package/esm/store/index.d.mts +6 -0
  103. package/esm/store/index.mjs +5 -0
  104. package/esm/store/match-trace.d.mts +21 -0
  105. package/esm/store/match-trace.d.mts.map +1 -0
  106. package/esm/store/match-trace.mjs +44 -0
  107. package/esm/store/match-trace.mjs.map +1 -0
  108. package/esm/store/sum-usage.d.mts +34 -0
  109. package/esm/store/sum-usage.d.mts.map +1 -0
  110. package/esm/store/sum-usage.mjs +65 -0
  111. package/esm/store/sum-usage.mjs.map +1 -0
  112. package/esm/store/trace-aggregate.type.d.mts +51 -0
  113. package/esm/store/trace-aggregate.type.d.mts.map +1 -0
  114. package/esm/store/trace-query.type.d.mts +45 -0
  115. package/esm/store/trace-query.type.d.mts.map +1 -0
  116. package/esm/store/trace-store.contract.d.mts +55 -0
  117. package/esm/store/trace-store.contract.d.mts.map +1 -0
  118. package/llms-full.txt +450 -0
  119. package/llms.txt +11 -0
  120. package/package.json +40 -0
  121. package/skills/README.md +17 -0
  122. package/skills/export-traces/SKILL.md +152 -0
  123. package/skills/observe-with-panoptic/SKILL.md +128 -0
  124. package/skills/query-traces/SKILL.md +152 -0
@@ -0,0 +1,41 @@
1
+ import { totalCostUsd } from "../utils/total-cost.mjs";
2
+
3
+ //#region ../@warlock.js/ai-panoptic/src/exporters/console/format-span-line.ts
4
+ /**
5
+ * Render a single {@link TraceSpan} as one scannable console line:
6
+ * `<status> <type> "<name>" — <duration>ms, <tokens> tok[, $<cost>]`.
7
+ * `depth` controls leading indentation when printing a tree. Pure — no
8
+ * side effects — so it is trivially testable and reused by both the
9
+ * per-trace summary and the per-span streaming line.
10
+ *
11
+ * @example
12
+ * formatSpanLine(span, 1);
13
+ * // ' ok agent "router" — 1240ms, 470 tok, $0.0021'
14
+ */
15
+ function formatSpanLine(span, depth = 0) {
16
+ const indent = " ".repeat(depth);
17
+ const marker = statusMarker(span.status);
18
+ const cost = totalCostUsd(span.usage);
19
+ const costSuffix = cost === void 0 ? "" : `, $${cost.toFixed(4)}`;
20
+ let line = `${indent}${marker} ${span.type} "${span.name}" — ${span.duration}ms, ${span.usage.total} tok${costSuffix}`;
21
+ if (span.error) line += ` [${span.error.type}: ${span.error.message}]`;
22
+ return line;
23
+ }
24
+ /**
25
+ * Short ASCII marker for a span's terminal status. Plain ASCII (no
26
+ * emoji/color codes) so output stays clean in log aggregators and CI.
27
+ */
28
+ function statusMarker(status) {
29
+ switch (status) {
30
+ case "completed": return "ok";
31
+ case "failed": return "ERR";
32
+ case "cancelled": return "cancel";
33
+ case "max-iterations": return "max-iter";
34
+ case "awaiting-input": return "await";
35
+ default: return status;
36
+ }
37
+ }
38
+
39
+ //#endregion
40
+ export { formatSpanLine };
41
+ //# sourceMappingURL=format-span-line.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-span-line.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/format-span-line.ts"],"sourcesContent":["import type { TraceSpan } from \"../../contracts\";\nimport { totalCostUsd } from \"../utils\";\n\n/**\n * Render a single {@link TraceSpan} as one scannable console line:\n * `<status> <type> \"<name>\" — <duration>ms, <tokens> tok[, $<cost>]`.\n * `depth` controls leading indentation when printing a tree. Pure — no\n * side effects — so it is trivially testable and reused by both the\n * per-trace summary and the per-span streaming line.\n *\n * @example\n * formatSpanLine(span, 1);\n * // ' ok agent \"router\" — 1240ms, 470 tok, $0.0021'\n */\nexport function formatSpanLine(span: TraceSpan, depth = 0): string {\n const indent = \" \".repeat(depth);\n const marker = statusMarker(span.status);\n const cost = totalCostUsd(span.usage);\n const costSuffix = cost === undefined ? \"\" : `, $${cost.toFixed(4)}`;\n\n let line = `${indent}${marker} ${span.type} \"${span.name}\" — ${span.duration}ms, ${span.usage.total} tok${costSuffix}`;\n\n if (span.error) {\n line += ` [${span.error.type}: ${span.error.message}]`;\n }\n\n return line;\n}\n\n/**\n * Short ASCII marker for a span's terminal status. Plain ASCII (no\n * emoji/color codes) so output stays clean in log aggregators and CI.\n */\nfunction statusMarker(status: TraceSpan[\"status\"]): string {\n switch (status) {\n case \"completed\":\n return \"ok\";\n case \"failed\":\n return \"ERR\";\n case \"cancelled\":\n return \"cancel\";\n case \"max-iterations\":\n return \"max-iter\";\n case \"awaiting-input\":\n return \"await\";\n default:\n return status;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAgB,eAAe,MAAiB,QAAQ,GAAW;CACjE,MAAM,SAAS,KAAK,OAAO,KAAK;CAChC,MAAM,SAAS,aAAa,KAAK,MAAM;CACvC,MAAM,OAAO,aAAa,KAAK,KAAK;CACpC,MAAM,aAAa,SAAS,SAAY,KAAK,MAAM,KAAK,QAAQ,CAAC;CAEjE,IAAI,OAAO,GAAG,SAAS,OAAO,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,SAAS,MAAM,KAAK,MAAM,MAAM,MAAM;CAE1G,IAAI,KAAK,OACP,QAAQ,KAAK,KAAK,MAAM,KAAK,IAAI,KAAK,MAAM,QAAQ;CAGtD,OAAO;AACT;;;;;AAMA,SAAS,aAAa,QAAqC;CACzD,QAAQ,QAAR;EACE,KAAK,aACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,kBACH,OAAO;EACT,KAAK,kBACH,OAAO;EACT,SACE,OAAO;CACX;AACF"}
@@ -0,0 +1,3 @@
1
+ import { ConsoleExporterOptions, ConsoleLike } from "./console-exporter.type.mjs";
2
+ import { consoleExporter } from "./console-exporter.mjs";
3
+ import { formatSpanLine } from "./format-span-line.mjs";
@@ -0,0 +1,23 @@
1
+ import { ExporterContract } from "../../contracts/exporter.contract.mjs";
2
+ import { FileExporterOptions } from "./file-exporter.type.mjs";
3
+
4
+ //#region ../@warlock.js/ai-panoptic/src/exporters/file/file-exporter.d.ts
5
+ /**
6
+ * Zero-dependency {@link ExporterContract} that appends completed traces
7
+ * to a JSON-Lines file (one JSON record per line by default). Buffers in
8
+ * memory and flushes either every `flushEvery` traces or on an explicit
9
+ * `flush()` / `shutdown()`, so a batch of traces costs one append.
10
+ *
11
+ * Useful as a durable local sink (replay traces later, ship the file to
12
+ * a backend out of band) and as a test fixture for the pipeline without
13
+ * a vendor SDK.
14
+ *
15
+ * @example
16
+ * collector.use(fileExporter({ path: "storage/traces.jsonl" }));
17
+ * // on shutdown:
18
+ * await collector.shutdown(); // drains the buffer
19
+ */
20
+ declare function fileExporter(options: FileExporterOptions): ExporterContract;
21
+ //#endregion
22
+ export { fileExporter };
23
+ //# sourceMappingURL=file-exporter.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/file/file-exporter.ts"],"mappings":";;;;;;;AAsBA;;;;;;;;AAA4E;;;;iBAA5D,YAAA,CAAa,OAAA,EAAS,mBAAA,GAAsB,gBAAgB"}
@@ -0,0 +1,93 @@
1
+ import { appendFile, mkdir } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+
4
+ //#region ../@warlock.js/ai-panoptic/src/exporters/file/file-exporter.ts
5
+ const EXPORTER_NAME = "file";
6
+ /**
7
+ * Zero-dependency {@link ExporterContract} that appends completed traces
8
+ * to a JSON-Lines file (one JSON record per line by default). Buffers in
9
+ * memory and flushes either every `flushEvery` traces or on an explicit
10
+ * `flush()` / `shutdown()`, so a batch of traces costs one append.
11
+ *
12
+ * Useful as a durable local sink (replay traces later, ship the file to
13
+ * a backend out of band) and as a test fixture for the pipeline without
14
+ * a vendor SDK.
15
+ *
16
+ * @example
17
+ * collector.use(fileExporter({ path: "storage/traces.jsonl" }));
18
+ * // on shutdown:
19
+ * await collector.shutdown(); // drains the buffer
20
+ */
21
+ function fileExporter(options) {
22
+ const writer = new FileTraceWriter(options);
23
+ return {
24
+ name: EXPORTER_NAME,
25
+ async export(trace) {
26
+ await writer.add(trace);
27
+ },
28
+ async flush() {
29
+ await writer.flush();
30
+ },
31
+ async shutdown() {
32
+ await writer.flush();
33
+ }
34
+ };
35
+ }
36
+ /**
37
+ * Internal buffered writer for {@link fileExporter}. Owns the pending
38
+ * trace buffer and the directory-created guard across the exporter's
39
+ * lifetime; kept unexported so callers only ever see the factory.
40
+ */
41
+ var FileTraceWriter = class {
42
+ constructor(options) {
43
+ this.buffer = [];
44
+ this.directoryReady = false;
45
+ this.path = options.path;
46
+ this.flushEvery = Math.max(1, options.flushEvery ?? 1);
47
+ this.pretty = options.pretty ?? false;
48
+ }
49
+ /**
50
+ * Buffer one trace and flush when the buffer reaches `flushEvery`.
51
+ */
52
+ async add(trace) {
53
+ this.buffer.push({
54
+ type: "trace",
55
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
56
+ trace
57
+ });
58
+ if (this.buffer.length >= this.flushEvery) await this.flush();
59
+ }
60
+ /**
61
+ * Serialize and append every buffered record, then clear the buffer.
62
+ * No-op when nothing is pending so callers can flush defensively.
63
+ */
64
+ async flush() {
65
+ if (this.buffer.length === 0) return;
66
+ const pending = this.buffer;
67
+ this.buffer = [];
68
+ await this.ensureDirectory();
69
+ const payload = pending.map((record) => this.serialize(record)).join("");
70
+ await appendFile(this.path, payload, "utf8");
71
+ }
72
+ /**
73
+ * Create the parent directory once, lazily, on the first write. Stores
74
+ * a guard so subsequent flushes skip the syscall.
75
+ */
76
+ async ensureDirectory() {
77
+ if (this.directoryReady) return;
78
+ await mkdir(dirname(this.path), { recursive: true });
79
+ this.directoryReady = true;
80
+ }
81
+ /**
82
+ * Render one record as a newline-terminated JSON string. Pretty mode
83
+ * indents for human reading; compact mode keeps the file valid JSON
84
+ * Lines (exactly one record per physical line).
85
+ */
86
+ serialize(record) {
87
+ return `${this.pretty ? JSON.stringify(record, void 0, 2) : JSON.stringify(record)}\n`;
88
+ }
89
+ };
90
+
91
+ //#endregion
92
+ export { fileExporter };
93
+ //# sourceMappingURL=file-exporter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-exporter.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/file/file-exporter.ts"],"sourcesContent":["import { appendFile, mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { ExporterContract, Trace } from \"../../contracts\";\nimport type { FileExporterOptions, TraceRecord } from \"./file-exporter.type\";\n\nconst EXPORTER_NAME = \"file\";\n\n/**\n * Zero-dependency {@link ExporterContract} that appends completed traces\n * to a JSON-Lines file (one JSON record per line by default). Buffers in\n * memory and flushes either every `flushEvery` traces or on an explicit\n * `flush()` / `shutdown()`, so a batch of traces costs one append.\n *\n * Useful as a durable local sink (replay traces later, ship the file to\n * a backend out of band) and as a test fixture for the pipeline without\n * a vendor SDK.\n *\n * @example\n * collector.use(fileExporter({ path: \"storage/traces.jsonl\" }));\n * // on shutdown:\n * await collector.shutdown(); // drains the buffer\n */\nexport function fileExporter(options: FileExporterOptions): ExporterContract {\n const writer = new FileTraceWriter(options);\n\n return {\n name: EXPORTER_NAME,\n async export(trace: Trace): Promise<void> {\n await writer.add(trace);\n },\n async flush(): Promise<void> {\n await writer.flush();\n },\n async shutdown(): Promise<void> {\n await writer.flush();\n },\n };\n}\n\n/**\n * Internal buffered writer for {@link fileExporter}. Owns the pending\n * trace buffer and the directory-created guard across the exporter's\n * lifetime; kept unexported so callers only ever see the factory.\n */\nclass FileTraceWriter {\n private readonly path: string;\n private readonly flushEvery: number;\n private readonly pretty: boolean;\n private buffer: TraceRecord[] = [];\n private directoryReady = false;\n\n public constructor(options: FileExporterOptions) {\n this.path = options.path;\n this.flushEvery = Math.max(1, options.flushEvery ?? 1);\n this.pretty = options.pretty ?? false;\n }\n\n /**\n * Buffer one trace and flush when the buffer reaches `flushEvery`.\n */\n public async add(trace: Trace): Promise<void> {\n this.buffer.push({\n type: \"trace\",\n exportedAt: new Date().toISOString(),\n trace,\n });\n\n if (this.buffer.length >= this.flushEvery) {\n await this.flush();\n }\n }\n\n /**\n * Serialize and append every buffered record, then clear the buffer.\n * No-op when nothing is pending so callers can flush defensively.\n */\n public async flush(): Promise<void> {\n if (this.buffer.length === 0) {\n return;\n }\n\n const pending = this.buffer;\n this.buffer = [];\n\n await this.ensureDirectory();\n\n const payload = pending.map((record) => this.serialize(record)).join(\"\");\n\n await appendFile(this.path, payload, \"utf8\");\n }\n\n /**\n * Create the parent directory once, lazily, on the first write. Stores\n * a guard so subsequent flushes skip the syscall.\n */\n private async ensureDirectory(): Promise<void> {\n if (this.directoryReady) {\n return;\n }\n\n await mkdir(dirname(this.path), { recursive: true });\n this.directoryReady = true;\n }\n\n /**\n * Render one record as a newline-terminated JSON string. Pretty mode\n * indents for human reading; compact mode keeps the file valid JSON\n * Lines (exactly one record per physical line).\n */\n private serialize(record: TraceRecord): string {\n const json = this.pretty\n ? JSON.stringify(record, undefined, 2)\n : JSON.stringify(record);\n\n return `${json}\\n`;\n }\n}\n"],"mappings":";;;;AAKA,MAAM,gBAAgB;;;;;;;;;;;;;;;;AAiBtB,SAAgB,aAAa,SAAgD;CAC3E,MAAM,SAAS,IAAI,gBAAgB,OAAO;CAE1C,OAAO;EACL,MAAM;EACN,MAAM,OAAO,OAA6B;GACxC,MAAM,OAAO,IAAI,KAAK;EACxB;EACA,MAAM,QAAuB;GAC3B,MAAM,OAAO,MAAM;EACrB;EACA,MAAM,WAA0B;GAC9B,MAAM,OAAO,MAAM;EACrB;CACF;AACF;;;;;;AAOA,IAAM,kBAAN,MAAsB;CAOpB,AAAO,YAAY,SAA8B;gBAHjB,CAAC;wBACR;EAGvB,KAAK,OAAO,QAAQ;EACpB,KAAK,aAAa,KAAK,IAAI,GAAG,QAAQ,cAAc,CAAC;EACrD,KAAK,SAAS,QAAQ,UAAU;CAClC;;;;CAKA,MAAa,IAAI,OAA6B;EAC5C,KAAK,OAAO,KAAK;GACf,MAAM;GACN,6BAAY,IAAI,KAAK,EAAC,CAAC,YAAY;GACnC;EACF,CAAC;EAED,IAAI,KAAK,OAAO,UAAU,KAAK,YAC7B,MAAM,KAAK,MAAM;CAErB;;;;;CAMA,MAAa,QAAuB;EAClC,IAAI,KAAK,OAAO,WAAW,GACzB;EAGF,MAAM,UAAU,KAAK;EACrB,KAAK,SAAS,CAAC;EAEf,MAAM,KAAK,gBAAgB;EAE3B,MAAM,UAAU,QAAQ,KAAK,WAAW,KAAK,UAAU,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE;EAEvE,MAAM,WAAW,KAAK,MAAM,SAAS,MAAM;CAC7C;;;;;CAMA,MAAc,kBAAiC;EAC7C,IAAI,KAAK,gBACP;EAGF,MAAM,MAAM,QAAQ,KAAK,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EACnD,KAAK,iBAAiB;CACxB;;;;;;CAOA,AAAQ,UAAU,QAA6B;EAK7C,OAAO,GAJM,KAAK,SACd,KAAK,UAAU,QAAQ,QAAW,CAAC,IACnC,KAAK,UAAU,MAAM,EAEV;CACjB;AACF"}
@@ -0,0 +1,39 @@
1
+ import { Trace } from "../../contracts/trace.type.mjs";
2
+ //#region ../@warlock.js/ai-panoptic/src/exporters/file/file-exporter.type.d.ts
3
+ /**
4
+ * One JSON-Lines record the {@link fileExporter} appends per trace. A
5
+ * thin envelope around {@link Trace} carrying the wire-format `type` and
6
+ * the time the line was written, so a downstream reader can tell records
7
+ * apart and order them without re-deriving anything from the payload.
8
+ */
9
+ type TraceRecord = {
10
+ /** Discriminator for the record format — always `"trace"` today. */type: "trace"; /** ISO-8601 timestamp the exporter wrote this record. */
11
+ exportedAt: string; /** The completed trace, verbatim. */
12
+ trace: Trace;
13
+ };
14
+ /**
15
+ * Options for {@link fileExporter}.
16
+ */
17
+ type FileExporterOptions = {
18
+ /**
19
+ * Absolute or cwd-relative path of the JSON-Lines file traces are
20
+ * appended to. The parent directory is created on first write if
21
+ * missing. Required.
22
+ */
23
+ path: string;
24
+ /**
25
+ * Flush the in-memory buffer to disk once it reaches this many traces.
26
+ * Lower values mean more frequent, smaller writes; higher values batch
27
+ * for throughput. Defaults to `1` (write every trace immediately).
28
+ */
29
+ flushEvery?: number;
30
+ /**
31
+ * Pretty-print each record across multiple lines instead of one
32
+ * compact JSON line. Defaults to `false` — compact keeps the file
33
+ * valid JSON Lines (one record per line).
34
+ */
35
+ pretty?: boolean;
36
+ };
37
+ //#endregion
38
+ export { FileExporterOptions, TraceRecord };
39
+ //# sourceMappingURL=file-exporter.type.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-exporter.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/file/file-exporter.type.ts"],"mappings":";;;;;AAQA;;;KAAY,WAAA;EAEV,oEAAA,IAAA,WAIA;EAFA,UAAA,UAEY;EAAZ,KAAA,EAAO,KAAK;AAAA;;;;KAMF,mBAAA;EAYV;;;AAMM;;EAZN,IAAA;;;;;;EAMA,UAAA;;;;;;EAMA,MAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import { FileExporterOptions, TraceRecord } from "./file-exporter.type.mjs";
2
+ import { fileExporter } from "./file-exporter.mjs";
@@ -0,0 +1,12 @@
1
+ import { ConsoleExporterOptions, ConsoleLike } from "./console/console-exporter.type.mjs";
2
+ import { consoleExporter } from "./console/console-exporter.mjs";
3
+ import { formatSpanLine } from "./console/format-span-line.mjs";
4
+ import { FileExporterOptions, TraceRecord } from "./file/file-exporter.type.mjs";
5
+ import { fileExporter } from "./file/file-exporter.mjs";
6
+ import { LangfuseClientLike, LangfuseExporterOptions, LangfuseObservationBody, LangfuseObservationEndBody, LangfuseObservationLevel, LangfuseObservationLike, LangfuseTraceBody, LangfuseTraceLike, LangfuseUsageBody } from "./langfuse/langfuse-exporter.type.mjs";
7
+ import { langfuseExporter } from "./langfuse/langfuse-exporter.mjs";
8
+ import { OtelExporterOptions } from "./otel/otel-exporter.type.mjs";
9
+ import { otelExporter } from "./otel/otel-exporter.mjs";
10
+ import { AttributeValue, GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes } from "./utils/gen-ai-attributes.mjs";
11
+ import { totalCostUsd } from "./utils/total-cost.mjs";
12
+ import { walkSpans } from "./utils/walk-spans.mjs";
@@ -0,0 +1,12 @@
1
+ import { walkSpans } from "./utils/walk-spans.mjs";
2
+ import { totalCostUsd } from "./utils/total-cost.mjs";
3
+ import { GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes } from "./utils/gen-ai-attributes.mjs";
4
+ import { formatSpanLine } from "./console/format-span-line.mjs";
5
+ import { consoleExporter } from "./console/console-exporter.mjs";
6
+ import { fileExporter } from "./file/file-exporter.mjs";
7
+ import { langfuseExporter } from "./langfuse/langfuse-exporter.mjs";
8
+ import "./langfuse/index.mjs";
9
+ import { otelExporter } from "./otel/otel-exporter.mjs";
10
+ import "./otel/index.mjs";
11
+
12
+ export { };
@@ -0,0 +1,2 @@
1
+ import { LangfuseClientLike, LangfuseExporterOptions, LangfuseObservationBody, LangfuseObservationEndBody, LangfuseObservationLevel, LangfuseObservationLike, LangfuseTraceBody, LangfuseTraceLike, LangfuseUsageBody } from "./langfuse-exporter.type.mjs";
2
+ import { langfuseExporter } from "./langfuse-exporter.mjs";
@@ -0,0 +1,3 @@
1
+ import { langfuseExporter } from "./langfuse-exporter.mjs";
2
+
3
+ export { };
@@ -0,0 +1,27 @@
1
+ import { ExporterContract } from "../../contracts/exporter.contract.mjs";
2
+ import { LangfuseExporterOptions } from "./langfuse-exporter.type.mjs";
3
+
4
+ //#region ../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.d.ts
5
+ /**
6
+ * {@link ExporterContract} that maps Panoptic traces onto Langfuse
7
+ * traces and observations. Lazily imports `langfuse` so it stays an
8
+ * OPTIONAL peer — importing this module never forces the SDK to be
9
+ * installed, and a missing SDK surfaces as a curated "install this"
10
+ * error when the exporter first needs to build a client.
11
+ *
12
+ * The root {@link TraceSpan} becomes a Langfuse trace; each descendant
13
+ * becomes a nested observation — a `generation` when it produced tokens
14
+ * (LLM-backed agents, supervisors), otherwise a plain `span` (tools,
15
+ * callbacks). Timing, status, version, and rolled-up `usage` are mapped
16
+ * 1:1; the rest of the GenAI attributes ride along as observation
17
+ * metadata.
18
+ *
19
+ * @example
20
+ * collector.use(langfuseExporter({ publicKey: "pk-...", secretKey: "sk-..." }));
21
+ * // or reuse an existing client:
22
+ * collector.use(langfuseExporter({ client: myLangfuse }));
23
+ */
24
+ declare function langfuseExporter(options: LangfuseExporterOptions): ExporterContract;
25
+ //#endregion
26
+ export { langfuseExporter };
27
+ //# sourceMappingURL=langfuse-exporter.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuse-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.ts"],"mappings":";;;;;;;AA+EA;;;;;;;;AAAoF;;;;;;;;iBAApE,gBAAA,CAAiB,OAAA,EAAS,uBAAA,GAA0B,gBAAgB"}
@@ -0,0 +1,158 @@
1
+ import { toGenAiAttributes } from "../utils/gen-ai-attributes.mjs";
2
+
3
+ //#region ../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.ts
4
+ const EXPORTER_NAME = "langfuse";
5
+ let LangfuseSdk;
6
+ let isModuleExists = null;
7
+ let loadingPromise;
8
+ const LANGFUSE_INSTALL_INSTRUCTIONS = `
9
+ The Panoptic Langfuse exporter requires the langfuse package.
10
+ Install it with:
11
+
12
+ npm install langfuse
13
+
14
+ Or with your preferred package manager:
15
+
16
+ pnpm add langfuse
17
+ yarn add langfuse
18
+ `.trim();
19
+ /**
20
+ * Settle the lazy import of `langfuse` once, concurrency-safe. Only
21
+ * needed when the caller did not pass a ready `client`. A bare `catch`
22
+ * flips the flag to `false`; the curated install string surfaces at use
23
+ * time, never a raw module-resolution stack trace.
24
+ */
25
+ function loadLangfuse() {
26
+ if (isModuleExists !== null) return Promise.resolve();
27
+ if (loadingPromise) return loadingPromise;
28
+ loadingPromise = (async () => {
29
+ try {
30
+ LangfuseSdk = await import("langfuse");
31
+ isModuleExists = true;
32
+ } catch {
33
+ isModuleExists = false;
34
+ }
35
+ })();
36
+ return loadingPromise;
37
+ }
38
+ /**
39
+ * {@link ExporterContract} that maps Panoptic traces onto Langfuse
40
+ * traces and observations. Lazily imports `langfuse` so it stays an
41
+ * OPTIONAL peer — importing this module never forces the SDK to be
42
+ * installed, and a missing SDK surfaces as a curated "install this"
43
+ * error when the exporter first needs to build a client.
44
+ *
45
+ * The root {@link TraceSpan} becomes a Langfuse trace; each descendant
46
+ * becomes a nested observation — a `generation` when it produced tokens
47
+ * (LLM-backed agents, supervisors), otherwise a plain `span` (tools,
48
+ * callbacks). Timing, status, version, and rolled-up `usage` are mapped
49
+ * 1:1; the rest of the GenAI attributes ride along as observation
50
+ * metadata.
51
+ *
52
+ * @example
53
+ * collector.use(langfuseExporter({ publicKey: "pk-...", secretKey: "sk-..." }));
54
+ * // or reuse an existing client:
55
+ * collector.use(langfuseExporter({ client: myLangfuse }));
56
+ */
57
+ function langfuseExporter(options) {
58
+ let client = options.client;
59
+ if (!client) loadLangfuse();
60
+ const resolveClient = async () => {
61
+ if (client) return client;
62
+ await loadLangfuse();
63
+ if (!isModuleExists) throw new Error(LANGFUSE_INSTALL_INSTRUCTIONS);
64
+ client = new LangfuseSdk.Langfuse({
65
+ publicKey: options.publicKey,
66
+ secretKey: options.secretKey,
67
+ baseUrl: options.baseUrl
68
+ });
69
+ return client;
70
+ };
71
+ return {
72
+ name: EXPORTER_NAME,
73
+ async export(trace) {
74
+ emitTrace(await resolveClient(), trace);
75
+ },
76
+ async flush() {
77
+ if (!client) return;
78
+ await client.flushAsync();
79
+ },
80
+ async shutdown() {
81
+ if (!client) return;
82
+ await client.shutdownAsync();
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * Create the Langfuse trace from the root span, then recurse the
88
+ * children into nested observations.
89
+ */
90
+ function emitTrace(client, trace) {
91
+ const root = trace.root;
92
+ const langfuseTrace = client.trace({
93
+ id: root.traceId,
94
+ name: root.name,
95
+ sessionId: trace.sessionId,
96
+ version: root.version,
97
+ timestamp: new Date(root.startedAt),
98
+ metadata: toGenAiAttributes(root)
99
+ });
100
+ for (const child of root.children) emitObservation(langfuseTrace, child);
101
+ }
102
+ /**
103
+ * Map one {@link TraceSpan} onto a Langfuse observation under `parent`,
104
+ * then recurse its children. Token-producing spans become
105
+ * `generation`s; everything else becomes a plain `span`.
106
+ */
107
+ function emitObservation(parent, span) {
108
+ const body = {
109
+ id: span.spanId,
110
+ name: span.name,
111
+ startTime: new Date(span.startedAt),
112
+ endTime: new Date(span.endedAt),
113
+ level: toLevel(span),
114
+ statusMessage: span.error?.message,
115
+ version: span.version,
116
+ metadata: toGenAiAttributes(span)
117
+ };
118
+ let observation;
119
+ if (producedTokens(span)) {
120
+ body.usage = {
121
+ input: span.usage.input,
122
+ output: span.usage.output,
123
+ total: span.usage.total,
124
+ unit: "TOKENS"
125
+ };
126
+ observation = parent.generation(body);
127
+ } else observation = parent.span(body);
128
+ for (const child of span.children) emitObservation(observation, child);
129
+ observation.end({ endTime: body.endTime });
130
+ }
131
+ /**
132
+ * A span counts as an LLM `generation` when it metered any tokens. Pure
133
+ * tools/callbacks contribute zero own-cost and map to plain spans.
134
+ *
135
+ * **Known limitation.** `TraceSpan.usage` is the ROLLED-UP usage (this
136
+ * node's own cost plus the sum of its children), not own-usage — the
137
+ * core `BaseReport` exposes no separate own-usage field, so a composite
138
+ * node (e.g. an agent that itself made no model call but whose tool
139
+ * children did) is classified as a `generation` on its children's
140
+ * tokens. We cannot classify on own-usage until the report shape carries
141
+ * it; the rolled-up `usage` block emitted on such a generation therefore
142
+ * double-counts tokens already attributed to descendant observations.
143
+ */
144
+ function producedTokens(span) {
145
+ return span.usage.total > 0;
146
+ }
147
+ /**
148
+ * Map the Panoptic span status onto a Langfuse observation level —
149
+ * failed/cancelled spans surface as `ERROR`, everything else `DEFAULT`.
150
+ */
151
+ function toLevel(span) {
152
+ if (span.status === "failed" || span.status === "cancelled") return "ERROR";
153
+ return "DEFAULT";
154
+ }
155
+
156
+ //#endregion
157
+ export { langfuseExporter };
158
+ //# sourceMappingURL=langfuse-exporter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuse-exporter.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.ts"],"sourcesContent":["import type { ExporterContract, Trace, TraceSpan } from \"../../contracts\";\nimport { toGenAiAttributes } from \"../utils\";\nimport type {\n LangfuseClientLike,\n LangfuseExporterOptions,\n LangfuseObservationBody,\n LangfuseObservationLevel,\n LangfuseObservationLike,\n LangfuseTraceLike,\n} from \"./langfuse-exporter.type\";\n\nconst EXPORTER_NAME = \"langfuse\";\n\n// ============================================================\n// Lazily-loaded langfuse SDK (OPTIONAL peer)\n// ============================================================\n\nlet LangfuseSdk: typeof import(\"langfuse\");\nlet isModuleExists: boolean | null = null;\nlet loadingPromise: Promise<void> | undefined;\n\nconst LANGFUSE_INSTALL_INSTRUCTIONS = `\nThe Panoptic Langfuse exporter requires the langfuse package.\nInstall it with:\n\n npm install langfuse\n\nOr with your preferred package manager:\n\n pnpm add langfuse\n yarn add langfuse\n`.trim();\n\n/**\n * Settle the lazy import of `langfuse` once, concurrency-safe. Only\n * needed when the caller did not pass a ready `client`. A bare `catch`\n * flips the flag to `false`; the curated install string surfaces at use\n * time, never a raw module-resolution stack trace.\n */\nfunction loadLangfuse(): Promise<void> {\n if (isModuleExists !== null) {\n return Promise.resolve();\n }\n\n if (loadingPromise) {\n return loadingPromise;\n }\n\n loadingPromise = (async () => {\n try {\n LangfuseSdk = await import(\"langfuse\");\n isModuleExists = true;\n } catch {\n isModuleExists = false;\n }\n })();\n\n return loadingPromise;\n}\n\n/**\n * {@link ExporterContract} that maps Panoptic traces onto Langfuse\n * traces and observations. Lazily imports `langfuse` so it stays an\n * OPTIONAL peer — importing this module never forces the SDK to be\n * installed, and a missing SDK surfaces as a curated \"install this\"\n * error when the exporter first needs to build a client.\n *\n * The root {@link TraceSpan} becomes a Langfuse trace; each descendant\n * becomes a nested observation — a `generation` when it produced tokens\n * (LLM-backed agents, supervisors), otherwise a plain `span` (tools,\n * callbacks). Timing, status, version, and rolled-up `usage` are mapped\n * 1:1; the rest of the GenAI attributes ride along as observation\n * metadata.\n *\n * @example\n * collector.use(langfuseExporter({ publicKey: \"pk-...\", secretKey: \"sk-...\" }));\n * // or reuse an existing client:\n * collector.use(langfuseExporter({ client: myLangfuse }));\n */\nexport function langfuseExporter(options: LangfuseExporterOptions): ExporterContract {\n let client: LangfuseClientLike | undefined = options.client;\n\n if (!client) {\n loadLangfuse();\n }\n\n const resolveClient = async (): Promise<LangfuseClientLike> => {\n if (client) {\n return client;\n }\n\n await loadLangfuse();\n\n if (!isModuleExists) {\n throw new Error(LANGFUSE_INSTALL_INSTRUCTIONS);\n }\n\n client = new LangfuseSdk.Langfuse({\n publicKey: options.publicKey,\n secretKey: options.secretKey,\n baseUrl: options.baseUrl,\n }) as unknown as LangfuseClientLike;\n\n return client;\n };\n\n return {\n name: EXPORTER_NAME,\n async export(trace: Trace): Promise<void> {\n const activeClient = await resolveClient();\n emitTrace(activeClient, trace);\n },\n async flush(): Promise<void> {\n if (!client) {\n return;\n }\n\n await client.flushAsync();\n },\n async shutdown(): Promise<void> {\n if (!client) {\n return;\n }\n\n await client.shutdownAsync();\n },\n };\n}\n\n/**\n * Create the Langfuse trace from the root span, then recurse the\n * children into nested observations.\n */\nfunction emitTrace(client: LangfuseClientLike, trace: Trace): void {\n const root = trace.root;\n\n const langfuseTrace = client.trace({\n id: root.traceId,\n name: root.name,\n sessionId: trace.sessionId,\n version: root.version,\n timestamp: new Date(root.startedAt),\n metadata: toGenAiAttributes(root),\n });\n\n for (const child of root.children) {\n emitObservation(langfuseTrace, child);\n }\n}\n\n/**\n * Map one {@link TraceSpan} onto a Langfuse observation under `parent`,\n * then recurse its children. Token-producing spans become\n * `generation`s; everything else becomes a plain `span`.\n */\nfunction emitObservation(\n parent: LangfuseTraceLike | LangfuseObservationLike,\n span: TraceSpan,\n): void {\n const body: LangfuseObservationBody = {\n id: span.spanId,\n name: span.name,\n startTime: new Date(span.startedAt),\n endTime: new Date(span.endedAt),\n level: toLevel(span),\n statusMessage: span.error?.message,\n version: span.version,\n metadata: toGenAiAttributes(span),\n };\n\n let observation: LangfuseObservationLike;\n\n if (producedTokens(span)) {\n body.usage = {\n input: span.usage.input,\n output: span.usage.output,\n total: span.usage.total,\n unit: \"TOKENS\",\n };\n observation = parent.generation(body);\n } else {\n observation = parent.span(body);\n }\n\n for (const child of span.children) {\n emitObservation(observation, child);\n }\n\n // Explicitly end the observation. The body already carries `endTime`,\n // so this is idempotent — but the SDK only finalizes (and flushes) an\n // observation on `end()`, so without it long-lived clients can leave\n // observations open. Safe against the local `LangfuseObservationLike`\n // shape, which declares `end(body?)`.\n observation.end({ endTime: body.endTime });\n}\n\n/**\n * A span counts as an LLM `generation` when it metered any tokens. Pure\n * tools/callbacks contribute zero own-cost and map to plain spans.\n *\n * **Known limitation.** `TraceSpan.usage` is the ROLLED-UP usage (this\n * node's own cost plus the sum of its children), not own-usage — the\n * core `BaseReport` exposes no separate own-usage field, so a composite\n * node (e.g. an agent that itself made no model call but whose tool\n * children did) is classified as a `generation` on its children's\n * tokens. We cannot classify on own-usage until the report shape carries\n * it; the rolled-up `usage` block emitted on such a generation therefore\n * double-counts tokens already attributed to descendant observations.\n */\nfunction producedTokens(span: TraceSpan): boolean {\n return span.usage.total > 0;\n}\n\n/**\n * Map the Panoptic span status onto a Langfuse observation level —\n * failed/cancelled spans surface as `ERROR`, everything else `DEFAULT`.\n */\nfunction toLevel(span: TraceSpan): LangfuseObservationLevel {\n if (span.status === \"failed\" || span.status === \"cancelled\") {\n return \"ERROR\";\n }\n\n return \"DEFAULT\";\n}\n"],"mappings":";;;AAWA,MAAM,gBAAgB;AAMtB,IAAI;AACJ,IAAI,iBAAiC;AACrC,IAAI;AAEJ,MAAM,gCAAgC;;;;;;;;;;EAUpC,KAAK;;;;;;;AAQP,SAAS,eAA8B;CACrC,IAAI,mBAAmB,MACrB,OAAO,QAAQ,QAAQ;CAGzB,IAAI,gBACF,OAAO;CAGT,kBAAkB,YAAY;EAC5B,IAAI;GACF,cAAc,MAAM,OAAO;GAC3B,iBAAiB;EACnB,QAAQ;GACN,iBAAiB;EACnB;CACF,EAAC,CAAE;CAEH,OAAO;AACT;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,iBAAiB,SAAoD;CACnF,IAAI,SAAyC,QAAQ;CAErD,IAAI,CAAC,QACH,aAAa;CAGf,MAAM,gBAAgB,YAAyC;EAC7D,IAAI,QACF,OAAO;EAGT,MAAM,aAAa;EAEnB,IAAI,CAAC,gBACH,MAAM,IAAI,MAAM,6BAA6B;EAG/C,SAAS,IAAI,YAAY,SAAS;GAChC,WAAW,QAAQ;GACnB,WAAW,QAAQ;GACnB,SAAS,QAAQ;EACnB,CAAC;EAED,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EACN,MAAM,OAAO,OAA6B;GAExC,UAAU,MADiB,cAAc,GACjB,KAAK;EAC/B;EACA,MAAM,QAAuB;GAC3B,IAAI,CAAC,QACH;GAGF,MAAM,OAAO,WAAW;EAC1B;EACA,MAAM,WAA0B;GAC9B,IAAI,CAAC,QACH;GAGF,MAAM,OAAO,cAAc;EAC7B;CACF;AACF;;;;;AAMA,SAAS,UAAU,QAA4B,OAAoB;CACjE,MAAM,OAAO,MAAM;CAEnB,MAAM,gBAAgB,OAAO,MAAM;EACjC,IAAI,KAAK;EACT,MAAM,KAAK;EACX,WAAW,MAAM;EACjB,SAAS,KAAK;EACd,WAAW,IAAI,KAAK,KAAK,SAAS;EAClC,UAAU,kBAAkB,IAAI;CAClC,CAAC;CAED,KAAK,MAAM,SAAS,KAAK,UACvB,gBAAgB,eAAe,KAAK;AAExC;;;;;;AAOA,SAAS,gBACP,QACA,MACM;CACN,MAAM,OAAgC;EACpC,IAAI,KAAK;EACT,MAAM,KAAK;EACX,WAAW,IAAI,KAAK,KAAK,SAAS;EAClC,SAAS,IAAI,KAAK,KAAK,OAAO;EAC9B,OAAO,QAAQ,IAAI;EACnB,eAAe,KAAK,OAAO;EAC3B,SAAS,KAAK;EACd,UAAU,kBAAkB,IAAI;CAClC;CAEA,IAAI;CAEJ,IAAI,eAAe,IAAI,GAAG;EACxB,KAAK,QAAQ;GACX,OAAO,KAAK,MAAM;GAClB,QAAQ,KAAK,MAAM;GACnB,OAAO,KAAK,MAAM;GAClB,MAAM;EACR;EACA,cAAc,OAAO,WAAW,IAAI;CACtC,OACE,cAAc,OAAO,KAAK,IAAI;CAGhC,KAAK,MAAM,SAAS,KAAK,UACvB,gBAAgB,aAAa,KAAK;CAQpC,YAAY,IAAI,EAAE,SAAS,KAAK,QAAQ,CAAC;AAC3C;;;;;;;;;;;;;;AAeA,SAAS,eAAe,MAA0B;CAChD,OAAO,KAAK,MAAM,QAAQ;AAC5B;;;;;AAMA,SAAS,QAAQ,MAA2C;CAC1D,IAAI,KAAK,WAAW,YAAY,KAAK,WAAW,aAC9C,OAAO;CAGT,OAAO;AACT"}
@@ -0,0 +1,90 @@
1
+ //#region ../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.type.d.ts
2
+ /**
3
+ * Minimal structural view of the parts of the `langfuse` SDK the
4
+ * exporter actually calls. Declared locally (rather than importing the
5
+ * SDK's own types) so this module type-checks even when `langfuse` is
6
+ * not installed — it is an OPTIONAL peer, lazily imported at runtime.
7
+ * The shape tracks Langfuse SDK v3: a client creates a trace, a trace
8
+ * creates nested `span` / `generation` observations, and the client is
9
+ * drained with `flushAsync` / `shutdownAsync`.
10
+ */
11
+ type LangfuseClientLike = {
12
+ trace(body: LangfuseTraceBody): LangfuseTraceLike;
13
+ flushAsync(): Promise<unknown>;
14
+ shutdownAsync(): Promise<unknown>;
15
+ };
16
+ /**
17
+ * A Langfuse trace handle — creates nested observations and carries the
18
+ * trace-level metadata Panoptic maps the root span onto.
19
+ */
20
+ type LangfuseTraceLike = {
21
+ span(body: LangfuseObservationBody): LangfuseObservationLike;
22
+ generation(body: LangfuseObservationBody): LangfuseObservationLike;
23
+ };
24
+ /**
25
+ * A Langfuse observation handle (span or generation) — nests further
26
+ * children and is closed with `end()`.
27
+ */
28
+ type LangfuseObservationLike = {
29
+ span(body: LangfuseObservationBody): LangfuseObservationLike;
30
+ generation(body: LangfuseObservationBody): LangfuseObservationLike;
31
+ end(body?: LangfuseObservationEndBody): unknown;
32
+ };
33
+ /** Subset of the Langfuse trace-creation body Panoptic populates. */
34
+ type LangfuseTraceBody = {
35
+ id?: string;
36
+ name?: string;
37
+ sessionId?: string;
38
+ version?: string;
39
+ timestamp?: Date;
40
+ metadata?: Record<string, unknown>;
41
+ };
42
+ /** Subset of the Langfuse observation-creation body Panoptic populates. */
43
+ type LangfuseObservationBody = {
44
+ id?: string;
45
+ name?: string;
46
+ startTime?: Date;
47
+ endTime?: Date;
48
+ level?: LangfuseObservationLevel;
49
+ statusMessage?: string;
50
+ version?: string;
51
+ usage?: LangfuseUsageBody;
52
+ metadata?: Record<string, unknown>;
53
+ };
54
+ /** Body accepted by `observation.end()`. */
55
+ type LangfuseObservationEndBody = {
56
+ endTime?: Date;
57
+ level?: LangfuseObservationLevel;
58
+ statusMessage?: string;
59
+ };
60
+ /** Langfuse usage block (`input`/`output`/`total` token counts). */
61
+ type LangfuseUsageBody = {
62
+ input?: number;
63
+ output?: number;
64
+ total?: number;
65
+ unit?: "TOKENS";
66
+ };
67
+ /** Langfuse observation severity levels. */
68
+ type LangfuseObservationLevel = "DEFAULT" | "DEBUG" | "WARNING" | "ERROR";
69
+ /**
70
+ * Options for {@link langfuseExporter}.
71
+ *
72
+ * Either pass an already-constructed Langfuse `client`, or pass the
73
+ * credentials and let the exporter construct one lazily (so `langfuse`
74
+ * stays an optional peer that is only imported when this exporter is
75
+ * actually used).
76
+ */
77
+ type LangfuseExporterOptions = {
78
+ /**
79
+ * A pre-built Langfuse client (any object matching
80
+ * {@link LangfuseClientLike}, including a real `Langfuse` instance).
81
+ * When supplied, the exporter never imports the SDK itself.
82
+ */
83
+ client?: LangfuseClientLike; /** Langfuse public key — used to construct a client when `client` is omitted. */
84
+ publicKey?: string; /** Langfuse secret key — used to construct a client when `client` is omitted. */
85
+ secretKey?: string; /** Langfuse host base URL. Optional; defaults to the SDK's own default. */
86
+ baseUrl?: string;
87
+ };
88
+ //#endregion
89
+ export { LangfuseClientLike, LangfuseExporterOptions, LangfuseObservationBody, LangfuseObservationEndBody, LangfuseObservationLevel, LangfuseObservationLike, LangfuseTraceBody, LangfuseTraceLike, LangfuseUsageBody };
90
+ //# sourceMappingURL=langfuse-exporter.type.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuse-exporter.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.type.ts"],"mappings":";;AASA;;;;;;;;KAAY,kBAAA;EACV,KAAA,CAAM,IAAA,EAAM,iBAAA,GAAoB,iBAAA;EAChC,UAAA,IAAc,OAAA;EACd,aAAA,IAAiB,OAAA;AAAA;;;;;KAOP,iBAAA;EACV,IAAA,CAAK,IAAA,EAAM,uBAAA,GAA0B,uBAAA;EACrC,UAAA,CAAW,IAAA,EAAM,uBAAA,GAA0B,uBAAA;AAAA;;;;;KAOjC,uBAAA;EACV,IAAA,CAAK,IAAA,EAAM,uBAAA,GAA0B,uBAAA;EACrC,UAAA,CAAW,IAAA,EAAM,uBAAA,GAA0B,uBAAA;EAC3C,GAAA,CAAI,IAAA,GAAO,0BAAA;AAAA;;KAID,iBAAA;EACV,EAAA;EACA,IAAA;EACA,SAAA;EACA,OAAA;EACA,SAAA,GAAY,IAAA;EACZ,QAAA,GAAW,MAAM;AAAA;;KAIP,uBAAA;EACV,EAAA;EACA,IAAA;EACA,SAAA,GAAY,IAAA;EACZ,OAAA,GAAU,IAAA;EACV,KAAA,GAAQ,wBAAA;EACR,aAAA;EACA,OAAA;EACA,KAAA,GAAQ,iBAAA;EACR,QAAA,GAAW,MAAA;AAAA;;KAID,0BAAA;EACV,OAAA,GAAU,IAAA;EACV,KAAA,GAAQ,wBAAwB;EAChC,aAAA;AAAA;;KAIU,iBAAA;EACV,KAAA;EACA,MAAA;EACA,KAAA;EACA,IAAA;AAAA;;KAIU,wBAAA;;;;;;;;;KAUA,uBAAA;EAtCA;;;;;EA4CV,MAAA,GAAS,kBAAkB,EApCnB;EAsCR,SAAA,WArCiB;EAuCjB,SAAA,WA/CA;EAiDA,OAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import { OtelExporterOptions } from "./otel-exporter.type.mjs";
2
+ import { otelExporter } from "./otel-exporter.mjs";
@@ -0,0 +1,3 @@
1
+ import { otelExporter } from "./otel-exporter.mjs";
2
+
3
+ export { };
@@ -0,0 +1,29 @@
1
+ import { ExporterContract } from "../../contracts/exporter.contract.mjs";
2
+ import { OtelExporterOptions } from "./otel-exporter.type.mjs";
3
+
4
+ //#region ../@warlock.js/ai-panoptic/src/exporters/otel/otel-exporter.d.ts
5
+ /**
6
+ * {@link ExporterContract} that maps Panoptic traces onto OpenTelemetry
7
+ * spans following the GenAI semantic conventions (`gen_ai.*`
8
+ * attributes). Lazily imports `@opentelemetry/api` so it stays an
9
+ * OPTIONAL peer — importing this module never forces the SDK to be
10
+ * installed, and a missing SDK surfaces as a curated "install this"
11
+ * error on first `export`, not a boot-time stack trace.
12
+ *
13
+ * The exporter emits onto a `Tracer` you supply (or fetches one from the
14
+ * globally registered provider). It never configures the SDK — wiring a
15
+ * `TracerProvider`, processors, and span exporters is the host app's
16
+ * job, exactly as with any other OTel instrumentation.
17
+ *
18
+ * Each {@link TraceSpan} becomes one OTel span with the source span's
19
+ * start/end times and parent relationship reconstructed, so the emitted
20
+ * tree matches the original execution tree.
21
+ *
22
+ * @example
23
+ * // app already set up @opentelemetry/sdk-trace-base + a provider
24
+ * collector.use(otelExporter({ tracerName: "my-app", system: "openai" }));
25
+ */
26
+ declare function otelExporter(options?: OtelExporterOptions): ExporterContract;
27
+ //#endregion
28
+ export { otelExporter };
29
+ //# sourceMappingURL=otel-exporter.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/otel/otel-exporter.ts"],"mappings":";;;;;;;AAiFA;;;;;;;;AAAiF;;;;;;;;;;iBAAjE,YAAA,CAAa,OAAA,GAAS,mBAAA,GAA2B,gBAAgB"}