@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.
- package/CHANGELOG.md +47 -0
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/cjs/index.cjs +1370 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/collector/collector.d.mts +19 -0
- package/esm/collector/collector.d.mts.map +1 -0
- package/esm/collector/collector.mjs +89 -0
- package/esm/collector/collector.mjs.map +1 -0
- package/esm/collector/extract-span-attributes.d.mts +29 -0
- package/esm/collector/extract-span-attributes.d.mts.map +1 -0
- package/esm/collector/extract-span-attributes.mjs +76 -0
- package/esm/collector/extract-span-attributes.mjs.map +1 -0
- package/esm/collector/index.d.mts +5 -0
- package/esm/collector/normalize-error.d.mts +27 -0
- package/esm/collector/normalize-error.d.mts.map +1 -0
- package/esm/collector/normalize-error.mjs +49 -0
- package/esm/collector/normalize-error.mjs.map +1 -0
- package/esm/collector/report-to-span.d.mts +31 -0
- package/esm/collector/report-to-span.d.mts.map +1 -0
- package/esm/collector/report-to-span.mjs +53 -0
- package/esm/collector/report-to-span.mjs.map +1 -0
- package/esm/collector/report-to-trace.d.mts +35 -0
- package/esm/collector/report-to-trace.d.mts.map +1 -0
- package/esm/collector/report-to-trace.mjs +53 -0
- package/esm/collector/report-to-trace.mjs.map +1 -0
- package/esm/contracts/collector.contract.d.mts +63 -0
- package/esm/contracts/collector.contract.d.mts.map +1 -0
- package/esm/contracts/exporter.contract.d.mts +76 -0
- package/esm/contracts/exporter.contract.d.mts.map +1 -0
- package/esm/contracts/index.d.mts +3 -0
- package/esm/contracts/trace.type.d.mts +122 -0
- package/esm/contracts/trace.type.d.mts.map +1 -0
- package/esm/exporters/console/console-exporter.d.mts +25 -0
- package/esm/exporters/console/console-exporter.d.mts.map +1 -0
- package/esm/exporters/console/console-exporter.mjs +79 -0
- package/esm/exporters/console/console-exporter.mjs.map +1 -0
- package/esm/exporters/console/console-exporter.type.d.mts +36 -0
- package/esm/exporters/console/console-exporter.type.d.mts.map +1 -0
- package/esm/exporters/console/format-span-line.d.mts +17 -0
- package/esm/exporters/console/format-span-line.d.mts.map +1 -0
- package/esm/exporters/console/format-span-line.mjs +41 -0
- package/esm/exporters/console/format-span-line.mjs.map +1 -0
- package/esm/exporters/console/index.d.mts +3 -0
- package/esm/exporters/file/file-exporter.d.mts +23 -0
- package/esm/exporters/file/file-exporter.d.mts.map +1 -0
- package/esm/exporters/file/file-exporter.mjs +93 -0
- package/esm/exporters/file/file-exporter.mjs.map +1 -0
- package/esm/exporters/file/file-exporter.type.d.mts +39 -0
- package/esm/exporters/file/file-exporter.type.d.mts.map +1 -0
- package/esm/exporters/file/index.d.mts +2 -0
- package/esm/exporters/index.d.mts +12 -0
- package/esm/exporters/index.mjs +12 -0
- package/esm/exporters/langfuse/index.d.mts +2 -0
- package/esm/exporters/langfuse/index.mjs +3 -0
- package/esm/exporters/langfuse/langfuse-exporter.d.mts +27 -0
- package/esm/exporters/langfuse/langfuse-exporter.d.mts.map +1 -0
- package/esm/exporters/langfuse/langfuse-exporter.mjs +158 -0
- package/esm/exporters/langfuse/langfuse-exporter.mjs.map +1 -0
- package/esm/exporters/langfuse/langfuse-exporter.type.d.mts +90 -0
- package/esm/exporters/langfuse/langfuse-exporter.type.d.mts.map +1 -0
- package/esm/exporters/otel/index.d.mts +2 -0
- package/esm/exporters/otel/index.mjs +3 -0
- package/esm/exporters/otel/otel-exporter.d.mts +29 -0
- package/esm/exporters/otel/otel-exporter.d.mts.map +1 -0
- package/esm/exporters/otel/otel-exporter.mjs +142 -0
- package/esm/exporters/otel/otel-exporter.mjs.map +1 -0
- package/esm/exporters/otel/otel-exporter.type.d.mts +39 -0
- package/esm/exporters/otel/otel-exporter.type.d.mts.map +1 -0
- package/esm/exporters/utils/gen-ai-attributes.d.mts +65 -0
- package/esm/exporters/utils/gen-ai-attributes.d.mts.map +1 -0
- package/esm/exporters/utils/gen-ai-attributes.mjs +88 -0
- package/esm/exporters/utils/gen-ai-attributes.mjs.map +1 -0
- package/esm/exporters/utils/index.d.mts +3 -0
- package/esm/exporters/utils/total-cost.d.mts +20 -0
- package/esm/exporters/utils/total-cost.d.mts.map +1 -0
- package/esm/exporters/utils/total-cost.mjs +23 -0
- package/esm/exporters/utils/total-cost.mjs.map +1 -0
- package/esm/exporters/utils/walk-spans.d.mts +18 -0
- package/esm/exporters/utils/walk-spans.d.mts.map +1 -0
- package/esm/exporters/utils/walk-spans.mjs +21 -0
- package/esm/exporters/utils/walk-spans.mjs.map +1 -0
- package/esm/index.d.mts +31 -0
- package/esm/index.mjs +22 -0
- package/esm/panoptic/index.d.mts +4 -0
- package/esm/panoptic/panoptic-middleware.d.mts +38 -0
- package/esm/panoptic/panoptic-middleware.d.mts.map +1 -0
- package/esm/panoptic/panoptic-middleware.mjs +68 -0
- package/esm/panoptic/panoptic-middleware.mjs.map +1 -0
- package/esm/panoptic/panoptic-target.type.d.mts +53 -0
- package/esm/panoptic/panoptic-target.type.d.mts.map +1 -0
- package/esm/panoptic/panoptic.d.mts +37 -0
- package/esm/panoptic/panoptic.d.mts.map +1 -0
- package/esm/panoptic/panoptic.mjs +134 -0
- package/esm/panoptic/panoptic.mjs.map +1 -0
- package/esm/panoptic/panoptic.type.d.mts +100 -0
- package/esm/panoptic/panoptic.type.d.mts.map +1 -0
- package/esm/store/in-memory-trace-store.d.mts +32 -0
- package/esm/store/in-memory-trace-store.d.mts.map +1 -0
- package/esm/store/in-memory-trace-store.mjs +134 -0
- package/esm/store/in-memory-trace-store.mjs.map +1 -0
- package/esm/store/index.d.mts +6 -0
- package/esm/store/index.mjs +5 -0
- package/esm/store/match-trace.d.mts +21 -0
- package/esm/store/match-trace.d.mts.map +1 -0
- package/esm/store/match-trace.mjs +44 -0
- package/esm/store/match-trace.mjs.map +1 -0
- package/esm/store/sum-usage.d.mts +34 -0
- package/esm/store/sum-usage.d.mts.map +1 -0
- package/esm/store/sum-usage.mjs +65 -0
- package/esm/store/sum-usage.mjs.map +1 -0
- package/esm/store/trace-aggregate.type.d.mts +51 -0
- package/esm/store/trace-aggregate.type.d.mts.map +1 -0
- package/esm/store/trace-query.type.d.mts +45 -0
- package/esm/store/trace-query.type.d.mts.map +1 -0
- package/esm/store/trace-store.contract.d.mts +55 -0
- package/esm/store/trace-store.contract.d.mts.map +1 -0
- package/llms-full.txt +450 -0
- package/llms.txt +11 -0
- package/package.json +40 -0
- package/skills/README.md +17 -0
- package/skills/export-traces/SKILL.md +152 -0
- package/skills/observe-with-panoptic/SKILL.md +128 -0
- package/skills/query-traces/SKILL.md +152 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { GEN_AI_ATTRIBUTES, toGenAiAttributes } from "../utils/gen-ai-attributes.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/otel/otel-exporter.ts
|
|
4
|
+
const EXPORTER_NAME = "otel";
|
|
5
|
+
const DEFAULT_TRACER_NAME = "@warlock.js/ai-panoptic";
|
|
6
|
+
let OtelApi;
|
|
7
|
+
let isModuleExists = null;
|
|
8
|
+
let loadingPromise;
|
|
9
|
+
const OTEL_INSTALL_INSTRUCTIONS = `
|
|
10
|
+
The Panoptic OpenTelemetry exporter requires the @opentelemetry/api package.
|
|
11
|
+
Install it with:
|
|
12
|
+
|
|
13
|
+
npm install @opentelemetry/api
|
|
14
|
+
|
|
15
|
+
Or with your preferred package manager:
|
|
16
|
+
|
|
17
|
+
pnpm add @opentelemetry/api
|
|
18
|
+
yarn add @opentelemetry/api
|
|
19
|
+
`.trim();
|
|
20
|
+
/**
|
|
21
|
+
* Settle the lazy import of `@opentelemetry/api` once, concurrency-safe.
|
|
22
|
+
* A bare `catch` flips the flag to `false`; the curated install string
|
|
23
|
+
* surfaces at use time so a missing SDK never throws a raw module
|
|
24
|
+
* resolution error.
|
|
25
|
+
*/
|
|
26
|
+
function loadOtel() {
|
|
27
|
+
if (isModuleExists !== null) return Promise.resolve();
|
|
28
|
+
if (loadingPromise) return loadingPromise;
|
|
29
|
+
loadingPromise = (async () => {
|
|
30
|
+
try {
|
|
31
|
+
OtelApi = await import("@opentelemetry/api");
|
|
32
|
+
isModuleExists = true;
|
|
33
|
+
} catch {
|
|
34
|
+
isModuleExists = false;
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
return loadingPromise;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* {@link ExporterContract} that maps Panoptic traces onto OpenTelemetry
|
|
41
|
+
* spans following the GenAI semantic conventions (`gen_ai.*`
|
|
42
|
+
* attributes). Lazily imports `@opentelemetry/api` so it stays an
|
|
43
|
+
* OPTIONAL peer — importing this module never forces the SDK to be
|
|
44
|
+
* installed, and a missing SDK surfaces as a curated "install this"
|
|
45
|
+
* error on first `export`, not a boot-time stack trace.
|
|
46
|
+
*
|
|
47
|
+
* The exporter emits onto a `Tracer` you supply (or fetches one from the
|
|
48
|
+
* globally registered provider). It never configures the SDK — wiring a
|
|
49
|
+
* `TracerProvider`, processors, and span exporters is the host app's
|
|
50
|
+
* job, exactly as with any other OTel instrumentation.
|
|
51
|
+
*
|
|
52
|
+
* Each {@link TraceSpan} becomes one OTel span with the source span's
|
|
53
|
+
* start/end times and parent relationship reconstructed, so the emitted
|
|
54
|
+
* tree matches the original execution tree.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // app already set up @opentelemetry/sdk-trace-base + a provider
|
|
58
|
+
* collector.use(otelExporter({ tracerName: "my-app", system: "openai" }));
|
|
59
|
+
*/
|
|
60
|
+
function otelExporter(options = {}) {
|
|
61
|
+
loadOtel();
|
|
62
|
+
return {
|
|
63
|
+
name: EXPORTER_NAME,
|
|
64
|
+
async export(trace) {
|
|
65
|
+
await loadOtel();
|
|
66
|
+
if (!isModuleExists) throw new Error(OTEL_INSTALL_INSTRUCTIONS);
|
|
67
|
+
emitSpan(resolveTracer(options), trace.root, void 0, options);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve the `Tracer` spans are emitted on — the caller-supplied one,
|
|
73
|
+
* or one fetched from the globally registered provider by name.
|
|
74
|
+
*/
|
|
75
|
+
function resolveTracer(options) {
|
|
76
|
+
if (options.tracer) return options.tracer;
|
|
77
|
+
return OtelApi.trace.getTracer(options.tracerName ?? DEFAULT_TRACER_NAME, options.tracerVersion);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Recreate one {@link TraceSpan} (and its subtree) as OTel spans. The
|
|
81
|
+
* span is started with the source `startedAt`, parented under
|
|
82
|
+
* `parentContext` so the tree is preserved, annotated with GenAI
|
|
83
|
+
* attributes, given the mapped status, and ended at `endedAt`. Children
|
|
84
|
+
* recurse under this span's context.
|
|
85
|
+
*/
|
|
86
|
+
function emitSpan(tracer, span, parentContext, options) {
|
|
87
|
+
const startTime = toEpochMillis(span.startedAt);
|
|
88
|
+
const baseContext = parentContext ?? OtelApi.context.active();
|
|
89
|
+
const otelSpan = tracer.startSpan(span.name, { startTime }, baseContext);
|
|
90
|
+
applyAttributes(otelSpan, span, options);
|
|
91
|
+
applyStatus(otelSpan, span);
|
|
92
|
+
const childContext = OtelApi.trace.setSpan(baseContext, otelSpan);
|
|
93
|
+
for (const child of span.children) emitSpan(tracer, child, childContext, options);
|
|
94
|
+
otelSpan.end(toEpochMillis(span.endedAt));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Set the GenAI + Warlock attributes on the OTel span, defaulting
|
|
98
|
+
* `gen_ai.system` from the exporter options when the span carried none.
|
|
99
|
+
*/
|
|
100
|
+
function applyAttributes(otelSpan, span, options) {
|
|
101
|
+
const attributes = toGenAiAttributes(span);
|
|
102
|
+
if (options.system !== void 0 && attributes[GEN_AI_ATTRIBUTES.system] === void 0) attributes[GEN_AI_ATTRIBUTES.system] = options.system;
|
|
103
|
+
otelSpan.setAttributes(attributes);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Map the Panoptic span status onto the OTel span status, recording the
|
|
107
|
+
* normalized error as an exception event + ERROR status when present.
|
|
108
|
+
*/
|
|
109
|
+
function applyStatus(otelSpan, span) {
|
|
110
|
+
const codes = OtelApi.SpanStatusCode;
|
|
111
|
+
if (span.error) otelSpan.recordException({
|
|
112
|
+
name: span.error.type,
|
|
113
|
+
message: span.error.message,
|
|
114
|
+
stack: span.error.stack
|
|
115
|
+
});
|
|
116
|
+
if (span.status === "failed" || span.status === "cancelled") {
|
|
117
|
+
otelSpan.setStatus({
|
|
118
|
+
code: codes.ERROR,
|
|
119
|
+
message: span.error?.message
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (span.status === "max-iterations" || span.status === "awaiting-input") {
|
|
124
|
+
otelSpan.setStatus({
|
|
125
|
+
code: codes.UNSET,
|
|
126
|
+
message: span.status === "max-iterations" ? "Run hit the iteration cap without an explicit end" : "Run is awaiting the next input turn"
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
otelSpan.setStatus({ code: codes.OK });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Convert an ISO-8601 timestamp to epoch milliseconds — the `TimeInput`
|
|
134
|
+
* form OTel's `startSpan` / `Span.end` accept directly.
|
|
135
|
+
*/
|
|
136
|
+
function toEpochMillis(isoTimestamp) {
|
|
137
|
+
return new Date(isoTimestamp).getTime();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
export { otelExporter };
|
|
142
|
+
//# sourceMappingURL=otel-exporter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel-exporter.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/otel/otel-exporter.ts"],"sourcesContent":["import type {\n Context,\n Span,\n SpanStatusCode as SpanStatusCodeEnum,\n Tracer,\n} from \"@opentelemetry/api\";\nimport type { ExporterContract, Trace, TraceSpan } from \"../../contracts\";\nimport { toGenAiAttributes, GEN_AI_ATTRIBUTES } from \"../utils\";\nimport type { OtelExporterOptions } from \"./otel-exporter.type\";\n\nconst EXPORTER_NAME = \"otel\";\nconst DEFAULT_TRACER_NAME = \"@warlock.js/ai-panoptic\";\n\n// ============================================================\n// Lazily-loaded @opentelemetry/api (OPTIONAL peer)\n// ============================================================\n\nlet OtelApi: typeof import(\"@opentelemetry/api\");\nlet isModuleExists: boolean | null = null;\nlet loadingPromise: Promise<void> | undefined;\n\nconst OTEL_INSTALL_INSTRUCTIONS = `\nThe Panoptic OpenTelemetry exporter requires the @opentelemetry/api package.\nInstall it with:\n\n npm install @opentelemetry/api\n\nOr with your preferred package manager:\n\n pnpm add @opentelemetry/api\n yarn add @opentelemetry/api\n`.trim();\n\n/**\n * Settle the lazy import of `@opentelemetry/api` once, concurrency-safe.\n * A bare `catch` flips the flag to `false`; the curated install string\n * surfaces at use time so a missing SDK never throws a raw module\n * resolution error.\n */\nfunction loadOtel(): 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 OtelApi = await import(\"@opentelemetry/api\");\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 OpenTelemetry\n * spans following the GenAI semantic conventions (`gen_ai.*`\n * attributes). Lazily imports `@opentelemetry/api` 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 on first `export`, not a boot-time stack trace.\n *\n * The exporter emits onto a `Tracer` you supply (or fetches one from the\n * globally registered provider). It never configures the SDK — wiring a\n * `TracerProvider`, processors, and span exporters is the host app's\n * job, exactly as with any other OTel instrumentation.\n *\n * Each {@link TraceSpan} becomes one OTel span with the source span's\n * start/end times and parent relationship reconstructed, so the emitted\n * tree matches the original execution tree.\n *\n * @example\n * // app already set up @opentelemetry/sdk-trace-base + a provider\n * collector.use(otelExporter({ tracerName: \"my-app\", system: \"openai\" }));\n */\nexport function otelExporter(options: OtelExporterOptions = {}): ExporterContract {\n loadOtel();\n\n return {\n name: EXPORTER_NAME,\n async export(trace: Trace): Promise<void> {\n await loadOtel();\n\n if (!isModuleExists) {\n throw new Error(OTEL_INSTALL_INSTRUCTIONS);\n }\n\n const tracer = resolveTracer(options);\n emitSpan(tracer, trace.root, undefined, options);\n },\n };\n}\n\n/**\n * Resolve the `Tracer` spans are emitted on — the caller-supplied one,\n * or one fetched from the globally registered provider by name.\n */\nfunction resolveTracer(options: OtelExporterOptions): Tracer {\n if (options.tracer) {\n return options.tracer;\n }\n\n return OtelApi.trace.getTracer(\n options.tracerName ?? DEFAULT_TRACER_NAME,\n options.tracerVersion,\n );\n}\n\n/**\n * Recreate one {@link TraceSpan} (and its subtree) as OTel spans. The\n * span is started with the source `startedAt`, parented under\n * `parentContext` so the tree is preserved, annotated with GenAI\n * attributes, given the mapped status, and ended at `endedAt`. Children\n * recurse under this span's context.\n */\nfunction emitSpan(\n tracer: Tracer,\n span: TraceSpan,\n parentContext: Context | undefined,\n options: OtelExporterOptions,\n): void {\n const startTime = toEpochMillis(span.startedAt);\n const baseContext = parentContext ?? OtelApi.context.active();\n\n const otelSpan = tracer.startSpan(span.name, { startTime }, baseContext);\n\n applyAttributes(otelSpan, span, options);\n applyStatus(otelSpan, span);\n\n const childContext = OtelApi.trace.setSpan(baseContext, otelSpan);\n\n for (const child of span.children) {\n emitSpan(tracer, child, childContext, options);\n }\n\n otelSpan.end(toEpochMillis(span.endedAt));\n}\n\n/**\n * Set the GenAI + Warlock attributes on the OTel span, defaulting\n * `gen_ai.system` from the exporter options when the span carried none.\n */\nfunction applyAttributes(\n otelSpan: Span,\n span: TraceSpan,\n options: OtelExporterOptions,\n): void {\n const attributes = toGenAiAttributes(span);\n\n if (options.system !== undefined && attributes[GEN_AI_ATTRIBUTES.system] === undefined) {\n attributes[GEN_AI_ATTRIBUTES.system] = options.system;\n }\n\n otelSpan.setAttributes(attributes);\n}\n\n/**\n * Map the Panoptic span status onto the OTel span status, recording the\n * normalized error as an exception event + ERROR status when present.\n */\nfunction applyStatus(otelSpan: Span, span: TraceSpan): void {\n const codes: typeof SpanStatusCodeEnum = OtelApi.SpanStatusCode;\n\n if (span.error) {\n otelSpan.recordException({\n name: span.error.type,\n message: span.error.message,\n stack: span.error.stack,\n });\n }\n\n if (span.status === \"failed\" || span.status === \"cancelled\") {\n otelSpan.setStatus({\n code: codes.ERROR,\n message: span.error?.message,\n });\n return;\n }\n\n // A capped / paused run is neither a failure nor a clean success.\n // Mapping it to OK would let a hit iteration cap read as a healthy\n // run; leave the OTel status UNSET with a descriptive message so the\n // outcome is visible without being miscounted as an error.\n if (span.status === \"max-iterations\" || span.status === \"awaiting-input\") {\n otelSpan.setStatus({\n code: codes.UNSET,\n message:\n span.status === \"max-iterations\"\n ? \"Run hit the iteration cap without an explicit end\"\n : \"Run is awaiting the next input turn\",\n });\n return;\n }\n\n otelSpan.setStatus({ code: codes.OK });\n}\n\n/**\n * Convert an ISO-8601 timestamp to epoch milliseconds — the `TimeInput`\n * form OTel's `startSpan` / `Span.end` accept directly.\n */\nfunction toEpochMillis(isoTimestamp: string): number {\n return new Date(isoTimestamp).getTime();\n}\n"],"mappings":";;;AAUA,MAAM,gBAAgB;AACtB,MAAM,sBAAsB;AAM5B,IAAI;AACJ,IAAI,iBAAiC;AACrC,IAAI;AAEJ,MAAM,4BAA4B;;;;;;;;;;EAUhC,KAAK;;;;;;;AAQP,SAAS,WAA0B;CACjC,IAAI,mBAAmB,MACrB,OAAO,QAAQ,QAAQ;CAGzB,IAAI,gBACF,OAAO;CAGT,kBAAkB,YAAY;EAC5B,IAAI;GACF,UAAU,MAAM,OAAO;GACvB,iBAAiB;EACnB,QAAQ;GACN,iBAAiB;EACnB;CACF,EAAC,CAAE;CAEH,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,aAAa,UAA+B,CAAC,GAAqB;CAChF,SAAS;CAET,OAAO;EACL,MAAM;EACN,MAAM,OAAO,OAA6B;GACxC,MAAM,SAAS;GAEf,IAAI,CAAC,gBACH,MAAM,IAAI,MAAM,yBAAyB;GAI3C,SADe,cAAc,OACf,GAAG,MAAM,MAAM,QAAW,OAAO;EACjD;CACF;AACF;;;;;AAMA,SAAS,cAAc,SAAsC;CAC3D,IAAI,QAAQ,QACV,OAAO,QAAQ;CAGjB,OAAO,QAAQ,MAAM,UACnB,QAAQ,cAAc,qBACtB,QAAQ,aACV;AACF;;;;;;;;AASA,SAAS,SACP,QACA,MACA,eACA,SACM;CACN,MAAM,YAAY,cAAc,KAAK,SAAS;CAC9C,MAAM,cAAc,iBAAiB,QAAQ,QAAQ,OAAO;CAE5D,MAAM,WAAW,OAAO,UAAU,KAAK,MAAM,EAAE,UAAU,GAAG,WAAW;CAEvE,gBAAgB,UAAU,MAAM,OAAO;CACvC,YAAY,UAAU,IAAI;CAE1B,MAAM,eAAe,QAAQ,MAAM,QAAQ,aAAa,QAAQ;CAEhE,KAAK,MAAM,SAAS,KAAK,UACvB,SAAS,QAAQ,OAAO,cAAc,OAAO;CAG/C,SAAS,IAAI,cAAc,KAAK,OAAO,CAAC;AAC1C;;;;;AAMA,SAAS,gBACP,UACA,MACA,SACM;CACN,MAAM,aAAa,kBAAkB,IAAI;CAEzC,IAAI,QAAQ,WAAW,UAAa,WAAW,kBAAkB,YAAY,QAC3E,WAAW,kBAAkB,UAAU,QAAQ;CAGjD,SAAS,cAAc,UAAU;AACnC;;;;;AAMA,SAAS,YAAY,UAAgB,MAAuB;CAC1D,MAAM,QAAmC,QAAQ;CAEjD,IAAI,KAAK,OACP,SAAS,gBAAgB;EACvB,MAAM,KAAK,MAAM;EACjB,SAAS,KAAK,MAAM;EACpB,OAAO,KAAK,MAAM;CACpB,CAAC;CAGH,IAAI,KAAK,WAAW,YAAY,KAAK,WAAW,aAAa;EAC3D,SAAS,UAAU;GACjB,MAAM,MAAM;GACZ,SAAS,KAAK,OAAO;EACvB,CAAC;EACD;CACF;CAMA,IAAI,KAAK,WAAW,oBAAoB,KAAK,WAAW,kBAAkB;EACxE,SAAS,UAAU;GACjB,MAAM,MAAM;GACZ,SACE,KAAK,WAAW,mBACZ,sDACA;EACR,CAAC;EACD;CACF;CAEA,SAAS,UAAU,EAAE,MAAM,MAAM,GAAG,CAAC;AACvC;;;;;AAMA,SAAS,cAAc,cAA8B;CACnD,OAAO,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ;AACxC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Tracer } from "@opentelemetry/api";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/otel/otel-exporter.type.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Options for {@link otelExporter}.
|
|
6
|
+
*
|
|
7
|
+
* The exporter never owns a `TracerProvider` — wiring the SDK
|
|
8
|
+
* (`@opentelemetry/sdk-trace-base`, exporters, processors) is the host
|
|
9
|
+
* app's job. Pass either a ready {@link Tracer} or a name and let the
|
|
10
|
+
* exporter fetch one from the globally registered provider via
|
|
11
|
+
* `trace.getTracer(name)`.
|
|
12
|
+
*/
|
|
13
|
+
type OtelExporterOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* A `Tracer` to emit spans on. When omitted, the exporter lazily calls
|
|
16
|
+
* `trace.getTracer(tracerName, tracerVersion)` against the globally
|
|
17
|
+
* registered provider, so it works with whatever SDK the app set up.
|
|
18
|
+
*/
|
|
19
|
+
tracer?: Tracer;
|
|
20
|
+
/**
|
|
21
|
+
* Instrumentation-scope name passed to `trace.getTracer` when `tracer`
|
|
22
|
+
* is not supplied. Defaults to `"@warlock.js/ai-panoptic"`.
|
|
23
|
+
*/
|
|
24
|
+
tracerName?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Instrumentation-scope version passed alongside `tracerName`.
|
|
27
|
+
* Optional.
|
|
28
|
+
*/
|
|
29
|
+
tracerVersion?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Value of the `gen_ai.system` attribute set on every span when the
|
|
32
|
+
* span itself didn't carry one (e.g. `"openai"`, `"anthropic"`).
|
|
33
|
+
* Optional — omitted when neither this nor the span supplies it.
|
|
34
|
+
*/
|
|
35
|
+
system?: string;
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { OtelExporterOptions };
|
|
39
|
+
//# sourceMappingURL=otel-exporter.type.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel-exporter.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/otel/otel-exporter.type.ts"],"mappings":";;;;;AAWA;;;;;;;KAAY,mBAAA;EAsBV;;AAAM;;;EAhBN,MAAA,GAAS,MAAM;;;;;EAKf,UAAA;;;;;EAKA,aAAA;;;;;;EAMA,MAAA;AAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { TraceSpan } from "../../contracts/trace.type.mjs";
|
|
2
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/utils/gen-ai-attributes.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Subset of the OpenTelemetry GenAI semantic-convention attribute keys
|
|
5
|
+
* Panoptic emits. Kept as a named constant map (not inline string
|
|
6
|
+
* literals scattered through the mapper) so the convention names live in
|
|
7
|
+
* one place and a convention bump is a single edit.
|
|
8
|
+
*
|
|
9
|
+
* @see https://opentelemetry.io/docs/specs/semconv/gen-ai/
|
|
10
|
+
*/
|
|
11
|
+
declare const GEN_AI_ATTRIBUTES: {
|
|
12
|
+
readonly operationName: "gen_ai.operation.name";
|
|
13
|
+
readonly system: "gen_ai.system";
|
|
14
|
+
readonly requestModel: "gen_ai.request.model";
|
|
15
|
+
readonly responseModel: "gen_ai.response.model";
|
|
16
|
+
readonly usageInputTokens: "gen_ai.usage.input_tokens";
|
|
17
|
+
readonly usageOutputTokens: "gen_ai.usage.output_tokens";
|
|
18
|
+
readonly conversationId: "gen_ai.conversation.id";
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Panoptic-specific attribute keys that have no GenAI-convention
|
|
22
|
+
* equivalent. Namespaced under `warlock.*` so they never collide with a
|
|
23
|
+
* future `gen_ai.*` key the spec might add.
|
|
24
|
+
*/
|
|
25
|
+
declare const WARLOCK_ATTRIBUTES: {
|
|
26
|
+
readonly reportType: "warlock.report.type";
|
|
27
|
+
readonly version: "warlock.version";
|
|
28
|
+
readonly durationMs: "warlock.duration_ms";
|
|
29
|
+
readonly totalTokens: "gen_ai.usage.total_tokens";
|
|
30
|
+
readonly cachedTokens: "gen_ai.usage.cached_tokens";
|
|
31
|
+
readonly reasoningTokens: "gen_ai.usage.reasoning_tokens";
|
|
32
|
+
readonly costUsd: "warlock.cost.usd";
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Span attribute values an OpenTelemetry / Langfuse backend accepts.
|
|
36
|
+
* GenAI attributes are scalars; the framework's free-form
|
|
37
|
+
* `TraceSpan.attributes` may also carry these.
|
|
38
|
+
*/
|
|
39
|
+
type AttributeValue = string | number | boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Project a {@link TraceSpan} onto the OpenTelemetry GenAI
|
|
42
|
+
* semantic-convention attribute set.
|
|
43
|
+
*
|
|
44
|
+
* The vendor-neutral {@link TraceSpan} carries identity, timing, status,
|
|
45
|
+
* and rolled-up `usage` as first-class fields; model identity and other
|
|
46
|
+
* provider detail live in the free-form `attributes` bag the collector
|
|
47
|
+
* populated. This mapper folds both into a flat `gen_ai.*` /
|
|
48
|
+
* `warlock.*` attribute map ready to set on an OTel span or hand to a
|
|
49
|
+
* Langfuse generation.
|
|
50
|
+
*
|
|
51
|
+
* - `gen_ai.operation.name` / `gen_ai.system` / `gen_ai.request.model`
|
|
52
|
+
* are forwarded from the span's `attributes` when the collector set
|
|
53
|
+
* them; never invented here.
|
|
54
|
+
* - Token counts come from the span's typed `usage` rollup.
|
|
55
|
+
* - The free-form `attributes` are merged last so an explicit collector
|
|
56
|
+
* value wins over a derived one.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const attributes = toGenAiAttributes(span);
|
|
60
|
+
* // { "gen_ai.usage.input_tokens": 150, "gen_ai.usage.output_tokens": 320, ... }
|
|
61
|
+
*/
|
|
62
|
+
declare function toGenAiAttributes(span: TraceSpan): Record<string, AttributeValue>;
|
|
63
|
+
//#endregion
|
|
64
|
+
export { AttributeValue, GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes };
|
|
65
|
+
//# sourceMappingURL=gen-ai-attributes.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gen-ai-attributes.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/utils/gen-ai-attributes.ts"],"mappings":";;;;;AAWA;;;;;cAAa,iBAAA;EAAA;;;;;;;;;;;;;cAeA,kBAAA;EAAA;;;;;;;;;;AAea;AAwB1B;;KAxBY,cAAA;;;;;;;;;;;AAwBqE;;;;;;;;;;;;iBAAjE,iBAAA,CAAkB,IAAA,EAAM,SAAA,GAAY,MAAA,SAAe,cAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { totalCostUsd } from "./total-cost.mjs";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/utils/gen-ai-attributes.ts
|
|
4
|
+
/**
|
|
5
|
+
* Subset of the OpenTelemetry GenAI semantic-convention attribute keys
|
|
6
|
+
* Panoptic emits. Kept as a named constant map (not inline string
|
|
7
|
+
* literals scattered through the mapper) so the convention names live in
|
|
8
|
+
* one place and a convention bump is a single edit.
|
|
9
|
+
*
|
|
10
|
+
* @see https://opentelemetry.io/docs/specs/semconv/gen-ai/
|
|
11
|
+
*/
|
|
12
|
+
const GEN_AI_ATTRIBUTES = {
|
|
13
|
+
operationName: "gen_ai.operation.name",
|
|
14
|
+
system: "gen_ai.system",
|
|
15
|
+
requestModel: "gen_ai.request.model",
|
|
16
|
+
responseModel: "gen_ai.response.model",
|
|
17
|
+
usageInputTokens: "gen_ai.usage.input_tokens",
|
|
18
|
+
usageOutputTokens: "gen_ai.usage.output_tokens",
|
|
19
|
+
conversationId: "gen_ai.conversation.id"
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Panoptic-specific attribute keys that have no GenAI-convention
|
|
23
|
+
* equivalent. Namespaced under `warlock.*` so they never collide with a
|
|
24
|
+
* future `gen_ai.*` key the spec might add.
|
|
25
|
+
*/
|
|
26
|
+
const WARLOCK_ATTRIBUTES = {
|
|
27
|
+
reportType: "warlock.report.type",
|
|
28
|
+
version: "warlock.version",
|
|
29
|
+
durationMs: "warlock.duration_ms",
|
|
30
|
+
totalTokens: "gen_ai.usage.total_tokens",
|
|
31
|
+
cachedTokens: "gen_ai.usage.cached_tokens",
|
|
32
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
33
|
+
costUsd: "warlock.cost.usd"
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Project a {@link TraceSpan} onto the OpenTelemetry GenAI
|
|
37
|
+
* semantic-convention attribute set.
|
|
38
|
+
*
|
|
39
|
+
* The vendor-neutral {@link TraceSpan} carries identity, timing, status,
|
|
40
|
+
* and rolled-up `usage` as first-class fields; model identity and other
|
|
41
|
+
* provider detail live in the free-form `attributes` bag the collector
|
|
42
|
+
* populated. This mapper folds both into a flat `gen_ai.*` /
|
|
43
|
+
* `warlock.*` attribute map ready to set on an OTel span or hand to a
|
|
44
|
+
* Langfuse generation.
|
|
45
|
+
*
|
|
46
|
+
* - `gen_ai.operation.name` / `gen_ai.system` / `gen_ai.request.model`
|
|
47
|
+
* are forwarded from the span's `attributes` when the collector set
|
|
48
|
+
* them; never invented here.
|
|
49
|
+
* - Token counts come from the span's typed `usage` rollup.
|
|
50
|
+
* - The free-form `attributes` are merged last so an explicit collector
|
|
51
|
+
* value wins over a derived one.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const attributes = toGenAiAttributes(span);
|
|
55
|
+
* // { "gen_ai.usage.input_tokens": 150, "gen_ai.usage.output_tokens": 320, ... }
|
|
56
|
+
*/
|
|
57
|
+
function toGenAiAttributes(span) {
|
|
58
|
+
const attributes = {
|
|
59
|
+
[WARLOCK_ATTRIBUTES.reportType]: span.type,
|
|
60
|
+
[WARLOCK_ATTRIBUTES.durationMs]: span.duration,
|
|
61
|
+
[WARLOCK_ATTRIBUTES.totalTokens]: span.usage.total,
|
|
62
|
+
[GEN_AI_ATTRIBUTES.usageInputTokens]: span.usage.input,
|
|
63
|
+
[GEN_AI_ATTRIBUTES.usageOutputTokens]: span.usage.output
|
|
64
|
+
};
|
|
65
|
+
if (span.version !== void 0) attributes[WARLOCK_ATTRIBUTES.version] = span.version;
|
|
66
|
+
if (span.sessionId !== void 0) attributes[GEN_AI_ATTRIBUTES.conversationId] = span.sessionId;
|
|
67
|
+
if (span.usage.cachedTokens !== void 0) attributes[WARLOCK_ATTRIBUTES.cachedTokens] = span.usage.cachedTokens;
|
|
68
|
+
if (span.usage.reasoningTokens !== void 0) attributes[WARLOCK_ATTRIBUTES.reasoningTokens] = span.usage.reasoningTokens;
|
|
69
|
+
const cost = totalCostUsd(span.usage);
|
|
70
|
+
if (cost !== void 0) attributes[WARLOCK_ATTRIBUTES.costUsd] = cost;
|
|
71
|
+
mergeScalarAttributes(attributes, span.attributes);
|
|
72
|
+
return attributes;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Copy the scalar entries of a free-form attribute bag onto the target
|
|
76
|
+
* map. Non-scalar values (objects, arrays, functions) are skipped — OTel
|
|
77
|
+
* and Langfuse attribute values must be primitives, and the collector's
|
|
78
|
+
* bag may legitimately hold nested digests that don't belong on a span
|
|
79
|
+
* attribute. Explicit collector values overwrite derived ones.
|
|
80
|
+
*/
|
|
81
|
+
function mergeScalarAttributes(target, source) {
|
|
82
|
+
if (!source) return;
|
|
83
|
+
for (const [key, value] of Object.entries(source)) if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") target[key] = value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
export { GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes };
|
|
88
|
+
//# sourceMappingURL=gen-ai-attributes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gen-ai-attributes.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/utils/gen-ai-attributes.ts"],"sourcesContent":["import type { TraceSpan } from \"../../contracts\";\nimport { totalCostUsd } from \"./total-cost\";\n\n/**\n * Subset of the OpenTelemetry GenAI semantic-convention attribute keys\n * Panoptic emits. Kept as a named constant map (not inline string\n * literals scattered through the mapper) so the convention names live in\n * one place and a convention bump is a single edit.\n *\n * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/\n */\nexport const GEN_AI_ATTRIBUTES = {\n operationName: \"gen_ai.operation.name\",\n system: \"gen_ai.system\",\n requestModel: \"gen_ai.request.model\",\n responseModel: \"gen_ai.response.model\",\n usageInputTokens: \"gen_ai.usage.input_tokens\",\n usageOutputTokens: \"gen_ai.usage.output_tokens\",\n conversationId: \"gen_ai.conversation.id\",\n} as const;\n\n/**\n * Panoptic-specific attribute keys that have no GenAI-convention\n * equivalent. Namespaced under `warlock.*` so they never collide with a\n * future `gen_ai.*` key the spec might add.\n */\nexport const WARLOCK_ATTRIBUTES = {\n reportType: \"warlock.report.type\",\n version: \"warlock.version\",\n durationMs: \"warlock.duration_ms\",\n totalTokens: \"gen_ai.usage.total_tokens\",\n cachedTokens: \"gen_ai.usage.cached_tokens\",\n reasoningTokens: \"gen_ai.usage.reasoning_tokens\",\n costUsd: \"warlock.cost.usd\",\n} as const;\n\n/**\n * Span attribute values an OpenTelemetry / Langfuse backend accepts.\n * GenAI attributes are scalars; the framework's free-form\n * `TraceSpan.attributes` may also carry these.\n */\nexport type AttributeValue = string | number | boolean;\n\n/**\n * Project a {@link TraceSpan} onto the OpenTelemetry GenAI\n * semantic-convention attribute set.\n *\n * The vendor-neutral {@link TraceSpan} carries identity, timing, status,\n * and rolled-up `usage` as first-class fields; model identity and other\n * provider detail live in the free-form `attributes` bag the collector\n * populated. This mapper folds both into a flat `gen_ai.*` /\n * `warlock.*` attribute map ready to set on an OTel span or hand to a\n * Langfuse generation.\n *\n * - `gen_ai.operation.name` / `gen_ai.system` / `gen_ai.request.model`\n * are forwarded from the span's `attributes` when the collector set\n * them; never invented here.\n * - Token counts come from the span's typed `usage` rollup.\n * - The free-form `attributes` are merged last so an explicit collector\n * value wins over a derived one.\n *\n * @example\n * const attributes = toGenAiAttributes(span);\n * // { \"gen_ai.usage.input_tokens\": 150, \"gen_ai.usage.output_tokens\": 320, ... }\n */\nexport function toGenAiAttributes(span: TraceSpan): Record<string, AttributeValue> {\n const attributes: Record<string, AttributeValue> = {\n [WARLOCK_ATTRIBUTES.reportType]: span.type,\n [WARLOCK_ATTRIBUTES.durationMs]: span.duration,\n [WARLOCK_ATTRIBUTES.totalTokens]: span.usage.total,\n [GEN_AI_ATTRIBUTES.usageInputTokens]: span.usage.input,\n [GEN_AI_ATTRIBUTES.usageOutputTokens]: span.usage.output,\n };\n\n if (span.version !== undefined) {\n attributes[WARLOCK_ATTRIBUTES.version] = span.version;\n }\n\n if (span.sessionId !== undefined) {\n attributes[GEN_AI_ATTRIBUTES.conversationId] = span.sessionId;\n }\n\n if (span.usage.cachedTokens !== undefined) {\n attributes[WARLOCK_ATTRIBUTES.cachedTokens] = span.usage.cachedTokens;\n }\n\n if (span.usage.reasoningTokens !== undefined) {\n attributes[WARLOCK_ATTRIBUTES.reasoningTokens] = span.usage.reasoningTokens;\n }\n\n const cost = totalCostUsd(span.usage);\n\n if (cost !== undefined) {\n attributes[WARLOCK_ATTRIBUTES.costUsd] = cost;\n }\n\n mergeScalarAttributes(attributes, span.attributes);\n\n return attributes;\n}\n\n/**\n * Copy the scalar entries of a free-form attribute bag onto the target\n * map. Non-scalar values (objects, arrays, functions) are skipped — OTel\n * and Langfuse attribute values must be primitives, and the collector's\n * bag may legitimately hold nested digests that don't belong on a span\n * attribute. Explicit collector values overwrite derived ones.\n */\nfunction mergeScalarAttributes(\n target: Record<string, AttributeValue>,\n source: Record<string, unknown> | undefined,\n): void {\n if (!source) {\n return;\n }\n\n for (const [key, value] of Object.entries(source)) {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n target[key] = value;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAWA,MAAa,oBAAoB;CAC/B,eAAe;CACf,QAAQ;CACR,cAAc;CACd,eAAe;CACf,kBAAkB;CAClB,mBAAmB;CACnB,gBAAgB;AAClB;;;;;;AAOA,MAAa,qBAAqB;CAChC,YAAY;CACZ,SAAS;CACT,YAAY;CACZ,aAAa;CACb,cAAc;CACd,iBAAiB;CACjB,SAAS;AACX;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,kBAAkB,MAAiD;CACjF,MAAM,aAA6C;GAChD,mBAAmB,aAAa,KAAK;GACrC,mBAAmB,aAAa,KAAK;GACrC,mBAAmB,cAAc,KAAK,MAAM;GAC5C,kBAAkB,mBAAmB,KAAK,MAAM;GAChD,kBAAkB,oBAAoB,KAAK,MAAM;CACpD;CAEA,IAAI,KAAK,YAAY,QACnB,WAAW,mBAAmB,WAAW,KAAK;CAGhD,IAAI,KAAK,cAAc,QACrB,WAAW,kBAAkB,kBAAkB,KAAK;CAGtD,IAAI,KAAK,MAAM,iBAAiB,QAC9B,WAAW,mBAAmB,gBAAgB,KAAK,MAAM;CAG3D,IAAI,KAAK,MAAM,oBAAoB,QACjC,WAAW,mBAAmB,mBAAmB,KAAK,MAAM;CAG9D,MAAM,OAAO,aAAa,KAAK,KAAK;CAEpC,IAAI,SAAS,QACX,WAAW,mBAAmB,WAAW;CAG3C,sBAAsB,YAAY,KAAK,UAAU;CAEjD,OAAO;AACT;;;;;;;;AASA,SAAS,sBACP,QACA,QACM;CACN,IAAI,CAAC,QACH;CAGF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAC7E,OAAO,OAAO;AAGpB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Usage } from "@warlock.js/ai";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/utils/total-cost.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Collapse a {@link Usage.cost} breakdown into a single USD scalar by
|
|
6
|
+
* summing every populated field. Mirrors the formula documented on
|
|
7
|
+
* `Usage.cost` (input + output + cachedInput + cachedOutput), and also
|
|
8
|
+
* folds in `reasoning` for forward-safety when a provider prices
|
|
9
|
+
* reasoning tokens as a separate channel. Returns `undefined` when no
|
|
10
|
+
* pricing was attached, so exporters can omit the cost attribute
|
|
11
|
+
* entirely rather than reporting a misleading `0`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* totalCostUsd({ input: 1, output: 2, total: 3, cost: { input: 0.01, output: 0.04 } });
|
|
15
|
+
* // => 0.05
|
|
16
|
+
*/
|
|
17
|
+
declare function totalCostUsd(usage: Usage): number | undefined;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { totalCostUsd };
|
|
20
|
+
//# sourceMappingURL=total-cost.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"total-cost.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/utils/total-cost.ts"],"mappings":";;;;;AAeA;;;;AAAyC;;;;;;;iBAAzB,YAAA,CAAa,KAAY,EAAL,KAAK"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/utils/total-cost.ts
|
|
2
|
+
/**
|
|
3
|
+
* Collapse a {@link Usage.cost} breakdown into a single USD scalar by
|
|
4
|
+
* summing every populated field. Mirrors the formula documented on
|
|
5
|
+
* `Usage.cost` (input + output + cachedInput + cachedOutput), and also
|
|
6
|
+
* folds in `reasoning` for forward-safety when a provider prices
|
|
7
|
+
* reasoning tokens as a separate channel. Returns `undefined` when no
|
|
8
|
+
* pricing was attached, so exporters can omit the cost attribute
|
|
9
|
+
* entirely rather than reporting a misleading `0`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* totalCostUsd({ input: 1, output: 2, total: 3, cost: { input: 0.01, output: 0.04 } });
|
|
13
|
+
* // => 0.05
|
|
14
|
+
*/
|
|
15
|
+
function totalCostUsd(usage) {
|
|
16
|
+
const cost = usage.cost;
|
|
17
|
+
if (!cost) return;
|
|
18
|
+
return (cost.input ?? 0) + (cost.output ?? 0) + (cost.cachedInput ?? 0) + (cost.cachedOutput ?? 0) + (cost.reasoning ?? 0);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { totalCostUsd };
|
|
23
|
+
//# sourceMappingURL=total-cost.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"total-cost.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/utils/total-cost.ts"],"sourcesContent":["import type { Usage } from \"@warlock.js/ai\";\n\n/**\n * Collapse a {@link Usage.cost} breakdown into a single USD scalar by\n * summing every populated field. Mirrors the formula documented on\n * `Usage.cost` (input + output + cachedInput + cachedOutput), and also\n * folds in `reasoning` for forward-safety when a provider prices\n * reasoning tokens as a separate channel. Returns `undefined` when no\n * pricing was attached, so exporters can omit the cost attribute\n * entirely rather than reporting a misleading `0`.\n *\n * @example\n * totalCostUsd({ input: 1, output: 2, total: 3, cost: { input: 0.01, output: 0.04 } });\n * // => 0.05\n */\nexport function totalCostUsd(usage: Usage): number | undefined {\n const cost = usage.cost;\n\n if (!cost) {\n return undefined;\n }\n\n return (\n (cost.input ?? 0) +\n (cost.output ?? 0) +\n (cost.cachedInput ?? 0) +\n (cost.cachedOutput ?? 0) +\n (cost.reasoning ?? 0)\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,SAAgB,aAAa,OAAkC;CAC7D,MAAM,OAAO,MAAM;CAEnB,IAAI,CAAC,MACH;CAGF,QACG,KAAK,SAAS,MACd,KAAK,UAAU,MACf,KAAK,eAAe,MACpB,KAAK,gBAAgB,MACrB,KAAK,aAAa;AAEvB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TraceSpan } from "../../contracts/trace.type.mjs";
|
|
2
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/utils/walk-spans.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Depth-first pre-order traversal of a {@link TraceSpan} tree, yielding
|
|
5
|
+
* the root first and then each descendant in `children` (invocation)
|
|
6
|
+
* order. Exporters that emit a flat span stream — OpenTelemetry, the
|
|
7
|
+
* console table — walk the tree once with this instead of re-writing the
|
|
8
|
+
* recursion in every exporter.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* for (const span of walkSpans(trace.root)) {
|
|
12
|
+
* emit(span);
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
declare function walkSpans(root: TraceSpan): Generator<TraceSpan>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { walkSpans };
|
|
18
|
+
//# sourceMappingURL=walk-spans.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-spans.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/utils/walk-spans.ts"],"mappings":";;;;;AAcA;;;;;;;;;iBAAiB,SAAA,CAAU,IAAA,EAAM,SAAA,GAAY,SAAA,CAAU,SAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/utils/walk-spans.ts
|
|
2
|
+
/**
|
|
3
|
+
* Depth-first pre-order traversal of a {@link TraceSpan} tree, yielding
|
|
4
|
+
* the root first and then each descendant in `children` (invocation)
|
|
5
|
+
* order. Exporters that emit a flat span stream — OpenTelemetry, the
|
|
6
|
+
* console table — walk the tree once with this instead of re-writing the
|
|
7
|
+
* recursion in every exporter.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* for (const span of walkSpans(trace.root)) {
|
|
11
|
+
* emit(span);
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
function* walkSpans(root) {
|
|
15
|
+
yield root;
|
|
16
|
+
for (const child of root.children) yield* walkSpans(child);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { walkSpans };
|
|
21
|
+
//# sourceMappingURL=walk-spans.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-spans.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/utils/walk-spans.ts"],"sourcesContent":["import type { TraceSpan } from \"../../contracts\";\n\n/**\n * Depth-first pre-order traversal of a {@link TraceSpan} tree, yielding\n * the root first and then each descendant in `children` (invocation)\n * order. Exporters that emit a flat span stream — OpenTelemetry, the\n * console table — walk the tree once with this instead of re-writing the\n * recursion in every exporter.\n *\n * @example\n * for (const span of walkSpans(trace.root)) {\n * emit(span);\n * }\n */\nexport function* walkSpans(root: TraceSpan): Generator<TraceSpan> {\n yield root;\n\n for (const child of root.children) {\n yield* walkSpans(child);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,UAAiB,UAAU,MAAuC;CAChE,MAAM;CAEN,KAAK,MAAM,SAAS,KAAK,UACvB,OAAO,UAAU,KAAK;AAE1B"}
|
package/esm/index.d.mts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Trace, TraceSpan, TraceSpanError } from "./contracts/trace.type.mjs";
|
|
2
|
+
import { ExporterContract } from "./contracts/exporter.contract.mjs";
|
|
3
|
+
import { CollectorContract } from "./contracts/collector.contract.mjs";
|
|
4
|
+
import { createCollector } from "./collector/collector.mjs";
|
|
5
|
+
import { reportToTrace } from "./collector/report-to-trace.mjs";
|
|
6
|
+
import { reportToSpan } from "./collector/report-to-span.mjs";
|
|
7
|
+
import { extractSpanAttributes } from "./collector/extract-span-attributes.mjs";
|
|
8
|
+
import { normalizeError } from "./collector/normalize-error.mjs";
|
|
9
|
+
import { TraceAggregate } from "./store/trace-aggregate.type.mjs";
|
|
10
|
+
import { TraceQuery } from "./store/trace-query.type.mjs";
|
|
11
|
+
import { TraceStoreContract } from "./store/trace-store.contract.mjs";
|
|
12
|
+
import { InMemoryTraceStoreOptions, createInMemoryTraceStore } from "./store/in-memory-trace-store.mjs";
|
|
13
|
+
import { matchTrace } from "./store/match-trace.mjs";
|
|
14
|
+
import { emptyUsage, sumUsage } from "./store/sum-usage.mjs";
|
|
15
|
+
import { ConsoleExporterOptions, ConsoleLike } from "./exporters/console/console-exporter.type.mjs";
|
|
16
|
+
import { consoleExporter } from "./exporters/console/console-exporter.mjs";
|
|
17
|
+
import { formatSpanLine } from "./exporters/console/format-span-line.mjs";
|
|
18
|
+
import { FileExporterOptions, TraceRecord } from "./exporters/file/file-exporter.type.mjs";
|
|
19
|
+
import { fileExporter } from "./exporters/file/file-exporter.mjs";
|
|
20
|
+
import { LangfuseClientLike, LangfuseExporterOptions, LangfuseObservationBody, LangfuseObservationEndBody, LangfuseObservationLevel, LangfuseObservationLike, LangfuseTraceBody, LangfuseTraceLike, LangfuseUsageBody } from "./exporters/langfuse/langfuse-exporter.type.mjs";
|
|
21
|
+
import { langfuseExporter } from "./exporters/langfuse/langfuse-exporter.mjs";
|
|
22
|
+
import { OtelExporterOptions } from "./exporters/otel/otel-exporter.type.mjs";
|
|
23
|
+
import { otelExporter } from "./exporters/otel/otel-exporter.mjs";
|
|
24
|
+
import { AttributeValue, GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes } from "./exporters/utils/gen-ai-attributes.mjs";
|
|
25
|
+
import { totalCostUsd } from "./exporters/utils/total-cost.mjs";
|
|
26
|
+
import { walkSpans } from "./exporters/utils/walk-spans.mjs";
|
|
27
|
+
import { CompletedEventPayload, PanopticTarget } from "./panoptic/panoptic-target.type.mjs";
|
|
28
|
+
import { Panoptic, PanopticOptions } from "./panoptic/panoptic.type.mjs";
|
|
29
|
+
import { panoptic } from "./panoptic/panoptic.mjs";
|
|
30
|
+
import { createPanopticMiddleware } from "./panoptic/panoptic-middleware.mjs";
|
|
31
|
+
export { type AttributeValue, type CollectorContract, type CompletedEventPayload, type ConsoleExporterOptions, type ConsoleLike, type ExporterContract, type FileExporterOptions, GEN_AI_ATTRIBUTES, type InMemoryTraceStoreOptions, type LangfuseClientLike, type LangfuseExporterOptions, type LangfuseObservationBody, type LangfuseObservationEndBody, type LangfuseObservationLevel, type LangfuseObservationLike, type LangfuseTraceBody, type LangfuseTraceLike, type LangfuseUsageBody, type OtelExporterOptions, type Panoptic, type PanopticOptions, type PanopticTarget, type Trace, type TraceAggregate, type TraceQuery, type TraceRecord, type TraceSpan, type TraceSpanError, type TraceStoreContract, WARLOCK_ATTRIBUTES, consoleExporter, createCollector, createInMemoryTraceStore, createPanopticMiddleware, emptyUsage, extractSpanAttributes, fileExporter, formatSpanLine, langfuseExporter, matchTrace, normalizeError, otelExporter, panoptic, reportToSpan, reportToTrace, sumUsage, toGenAiAttributes, totalCostUsd, walkSpans };
|
package/esm/index.mjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { walkSpans } from "./exporters/utils/walk-spans.mjs";
|
|
2
|
+
import { normalizeError } from "./collector/normalize-error.mjs";
|
|
3
|
+
import { extractSpanAttributes } from "./collector/extract-span-attributes.mjs";
|
|
4
|
+
import { reportToSpan } from "./collector/report-to-span.mjs";
|
|
5
|
+
import { reportToTrace } from "./collector/report-to-trace.mjs";
|
|
6
|
+
import { createCollector } from "./collector/collector.mjs";
|
|
7
|
+
import { matchTrace } from "./store/match-trace.mjs";
|
|
8
|
+
import { emptyUsage, sumUsage } from "./store/sum-usage.mjs";
|
|
9
|
+
import { createInMemoryTraceStore } from "./store/in-memory-trace-store.mjs";
|
|
10
|
+
import "./store/index.mjs";
|
|
11
|
+
import { totalCostUsd } from "./exporters/utils/total-cost.mjs";
|
|
12
|
+
import { GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes } from "./exporters/utils/gen-ai-attributes.mjs";
|
|
13
|
+
import { formatSpanLine } from "./exporters/console/format-span-line.mjs";
|
|
14
|
+
import { consoleExporter } from "./exporters/console/console-exporter.mjs";
|
|
15
|
+
import { fileExporter } from "./exporters/file/file-exporter.mjs";
|
|
16
|
+
import { langfuseExporter } from "./exporters/langfuse/langfuse-exporter.mjs";
|
|
17
|
+
import { otelExporter } from "./exporters/otel/otel-exporter.mjs";
|
|
18
|
+
import "./exporters/index.mjs";
|
|
19
|
+
import { createPanopticMiddleware } from "./panoptic/panoptic-middleware.mjs";
|
|
20
|
+
import { panoptic } from "./panoptic/panoptic.mjs";
|
|
21
|
+
|
|
22
|
+
export { GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, consoleExporter, createCollector, createInMemoryTraceStore, createPanopticMiddleware, emptyUsage, extractSpanAttributes, fileExporter, formatSpanLine, langfuseExporter, matchTrace, normalizeError, otelExporter, panoptic, reportToSpan, reportToTrace, sumUsage, toGenAiAttributes, totalCostUsd, walkSpans };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { CollectorContract } from "../contracts/collector.contract.mjs";
|
|
2
|
+
import { AgentMiddleware } from "@warlock.js/ai";
|
|
3
|
+
|
|
4
|
+
//#region ../@warlock.js/ai-panoptic/src/panoptic/panoptic-middleware.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Build an {@link AgentMiddleware} that feeds a collector from the
|
|
7
|
+
* `execute`- and `supervisor`-level hooks. An alternative wiring to event
|
|
8
|
+
* subscription for apps that already compose cross-cutting concerns
|
|
9
|
+
* through the agent middleware pipeline (`[cache, budget, guardrail,
|
|
10
|
+
* observability]`). Declaring both hook maps lets a single middleware
|
|
11
|
+
* object work uniformly on agents (which fire the `execute` map) and
|
|
12
|
+
* supervisors (which fire the `supervisor` map) — registering it on a
|
|
13
|
+
* supervisor would otherwise install and collect nothing silently.
|
|
14
|
+
*
|
|
15
|
+
* Both terminal paths are covered on each surface:
|
|
16
|
+
* - `after` — fires on a run that produced a result. A run can complete
|
|
17
|
+
* with `result.error` populated (the engine still calls `after`), so
|
|
18
|
+
* the report AND the envelope error are collected; the error type and
|
|
19
|
+
* message land on the root span.
|
|
20
|
+
* - `onError` — fires when the run threw before assembling a result. The
|
|
21
|
+
* error carries the partial result's report on its envelope; when
|
|
22
|
+
* present it is collected, with the error itself threaded onto the
|
|
23
|
+
* root span so failed runs still produce a trace.
|
|
24
|
+
*
|
|
25
|
+
* The hooks never return a value, so they never mutate the agent's /
|
|
26
|
+
* supervisor's result. The `collect` call is fire-and-forget relative to
|
|
27
|
+
* the run — the collector isolates exporter failures internally, and we
|
|
28
|
+
* additionally swallow any rejection here so an observability fault can
|
|
29
|
+
* never surface on the run's hot path.
|
|
30
|
+
*
|
|
31
|
+
* @param collector - the collector traces are fed into.
|
|
32
|
+
* @param name - stable middleware name (kebab-case). Defaults to
|
|
33
|
+
* `"panoptic"`.
|
|
34
|
+
*/
|
|
35
|
+
declare function createPanopticMiddleware(collector: CollectorContract, name?: string): AgentMiddleware;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { createPanopticMiddleware };
|
|
38
|
+
//# sourceMappingURL=panoptic-middleware.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panoptic-middleware.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/panoptic/panoptic-middleware.ts"],"mappings":";;;;;;AAiCA;;;;;;;;;AAGkB;;;;;;;;;;;;;;;;;;;iBAHF,wBAAA,CACd,SAAA,EAAW,iBAAA,EACX,IAAA,YACC,eAAe"}
|