@warlock.js/ai-panoptic 4.3.0 → 4.4.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 +9 -1
- package/cjs/index.cjs +259 -52
- package/cjs/index.cjs.map +1 -1
- package/esm/collector/collector.d.mts +2 -1
- package/esm/collector/collector.d.mts.map +1 -1
- package/esm/collector/collector.mjs +10 -4
- package/esm/collector/collector.mjs.map +1 -1
- package/esm/collector/content-capture.type.d.mts +42 -0
- package/esm/collector/content-capture.type.d.mts.map +1 -0
- package/esm/collector/index.d.mts +1 -0
- package/esm/collector/report-to-span.d.mts +8 -1
- package/esm/collector/report-to-span.d.mts.map +1 -1
- package/esm/collector/report-to-span.mjs +66 -2
- package/esm/collector/report-to-span.mjs.map +1 -1
- package/esm/collector/report-to-trace.d.mts +2 -1
- package/esm/collector/report-to-trace.d.mts.map +1 -1
- package/esm/collector/report-to-trace.mjs +2 -2
- package/esm/collector/report-to-trace.mjs.map +1 -1
- package/esm/contracts/trace.type.d.mts +22 -3
- package/esm/contracts/trace.type.d.mts.map +1 -1
- package/esm/exporters/console/console-exporter.d.mts +11 -3
- package/esm/exporters/console/console-exporter.d.mts.map +1 -1
- package/esm/exporters/console/console-exporter.mjs +31 -13
- package/esm/exporters/console/console-exporter.mjs.map +1 -1
- package/esm/exporters/console/console-exporter.type.d.mts +15 -0
- package/esm/exporters/console/console-exporter.type.d.mts.map +1 -1
- package/esm/exporters/console/format-span-io.d.mts +27 -0
- package/esm/exporters/console/format-span-io.d.mts.map +1 -0
- package/esm/exporters/console/format-span-io.mjs +52 -0
- package/esm/exporters/console/format-span-io.mjs.map +1 -0
- package/esm/exporters/console/index.d.mts +2 -1
- package/esm/exporters/index.d.mts +1 -0
- package/esm/exporters/index.mjs +1 -0
- package/esm/exporters/langfuse/langfuse-exporter.d.mts +10 -6
- package/esm/exporters/langfuse/langfuse-exporter.d.mts.map +1 -1
- package/esm/exporters/langfuse/langfuse-exporter.mjs +77 -30
- package/esm/exporters/langfuse/langfuse-exporter.mjs.map +1 -1
- package/esm/exporters/langfuse/langfuse-exporter.type.d.mts +3 -1
- package/esm/exporters/langfuse/langfuse-exporter.type.d.mts.map +1 -1
- package/esm/exporters/otel/otel-exporter.mjs +15 -0
- package/esm/exporters/otel/otel-exporter.mjs.map +1 -1
- package/esm/exporters/utils/gen-ai-attributes.d.mts +3 -1
- package/esm/exporters/utils/gen-ai-attributes.d.mts.map +1 -1
- package/esm/exporters/utils/gen-ai-attributes.mjs +5 -1
- package/esm/exporters/utils/gen-ai-attributes.mjs.map +1 -1
- package/esm/index.d.mts +3 -1
- package/esm/index.mjs +2 -1
- package/esm/panoptic/panoptic.d.mts.map +1 -1
- package/esm/panoptic/panoptic.mjs +4 -1
- package/esm/panoptic/panoptic.mjs.map +1 -1
- package/esm/panoptic/panoptic.type.d.mts +17 -0
- package/esm/panoptic/panoptic.type.d.mts.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TraceSpan } from "../contracts/trace.type.mjs";
|
|
2
|
+
import { ContentCaptureOptions } from "./content-capture.type.mjs";
|
|
2
3
|
import { BaseReport } from "@warlock.js/ai";
|
|
3
4
|
|
|
4
5
|
//#region ../@warlock.js/ai-panoptic/src/collector/report-to-span.d.ts
|
|
@@ -17,6 +18,12 @@ import { BaseReport } from "@warlock.js/ai";
|
|
|
17
18
|
* identity, tool trip index) is routed into the optional `attributes`
|
|
18
19
|
* bag via {@link extractSpanAttributes}.
|
|
19
20
|
*
|
|
21
|
+
* When {@link ContentCaptureOptions.captureContent} is set, the raw
|
|
22
|
+
* prompt/response (agents) and args/result (tools) are additionally
|
|
23
|
+
* copied onto `span.input` / `span.output` — off by default because
|
|
24
|
+
* payloads are large and often sensitive. A {@link ContentRedactor} can
|
|
25
|
+
* mask each value first.
|
|
26
|
+
*
|
|
20
27
|
* No external lookup is needed — a `BaseReport` already carries
|
|
21
28
|
* everything a span requires, so a collector can flatten a tree without
|
|
22
29
|
* consulting any other source.
|
|
@@ -25,7 +32,7 @@ import { BaseReport } from "@warlock.js/ai";
|
|
|
25
32
|
* const root = reportToSpan(result.report);
|
|
26
33
|
* console.log(root.spanId, root.traceId, root.children.length);
|
|
27
34
|
*/
|
|
28
|
-
declare function reportToSpan(report: BaseReport): TraceSpan;
|
|
35
|
+
declare function reportToSpan(report: BaseReport, options?: ContentCaptureOptions): TraceSpan;
|
|
29
36
|
//#endregion
|
|
30
37
|
export { reportToSpan };
|
|
31
38
|
//# sourceMappingURL=report-to-span.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-to-span.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-span.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"report-to-span.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-span.ts"],"mappings":";;;;;;;AAmCA;;;;;;;;;;;;;;AAA4F;;;;;;;;;;;;;iBAA5E,YAAA,CAAa,MAAA,EAAQ,UAAA,EAAY,OAAA,GAAU,qBAAA,GAAwB,SAAA"}
|
|
@@ -17,6 +17,12 @@ import { extractSpanAttributes } from "./extract-span-attributes.mjs";
|
|
|
17
17
|
* identity, tool trip index) is routed into the optional `attributes`
|
|
18
18
|
* bag via {@link extractSpanAttributes}.
|
|
19
19
|
*
|
|
20
|
+
* When {@link ContentCaptureOptions.captureContent} is set, the raw
|
|
21
|
+
* prompt/response (agents) and args/result (tools) are additionally
|
|
22
|
+
* copied onto `span.input` / `span.output` — off by default because
|
|
23
|
+
* payloads are large and often sensitive. A {@link ContentRedactor} can
|
|
24
|
+
* mask each value first.
|
|
25
|
+
*
|
|
20
26
|
* No external lookup is needed — a `BaseReport` already carries
|
|
21
27
|
* everything a span requires, so a collector can flatten a tree without
|
|
22
28
|
* consulting any other source.
|
|
@@ -25,7 +31,7 @@ import { extractSpanAttributes } from "./extract-span-attributes.mjs";
|
|
|
25
31
|
* const root = reportToSpan(result.report);
|
|
26
32
|
* console.log(root.spanId, root.traceId, root.children.length);
|
|
27
33
|
*/
|
|
28
|
-
function reportToSpan(report) {
|
|
34
|
+
function reportToSpan(report, options) {
|
|
29
35
|
const span = {
|
|
30
36
|
spanId: report.runId,
|
|
31
37
|
traceId: report.rootRunId,
|
|
@@ -36,7 +42,7 @@ function reportToSpan(report) {
|
|
|
36
42
|
endedAt: report.endedAt,
|
|
37
43
|
duration: report.duration,
|
|
38
44
|
usage: report.usage,
|
|
39
|
-
children: report.children.map(reportToSpan)
|
|
45
|
+
children: report.children.map((child) => reportToSpan(child, options))
|
|
40
46
|
};
|
|
41
47
|
if (report.parentRunId !== void 0) span.parentSpanId = report.parentRunId;
|
|
42
48
|
if (report.sessionId !== void 0) span.sessionId = report.sessionId;
|
|
@@ -45,8 +51,66 @@ function reportToSpan(report) {
|
|
|
45
51
|
if (error !== void 0) span.error = error;
|
|
46
52
|
const attributes = extractSpanAttributes(report);
|
|
47
53
|
if (attributes !== void 0) span.attributes = attributes;
|
|
54
|
+
if (options?.captureContent) captureContent(span, report, options.redactContent);
|
|
48
55
|
return span;
|
|
49
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Copy the node's raw content onto `span.input` / `span.output`.
|
|
59
|
+
*
|
|
60
|
+
* - Tools carry the call arguments + return value directly on the report
|
|
61
|
+
* (`ToolCall.input` / `ToolCall.output`).
|
|
62
|
+
* - Agents carry a `trips[]` history; the first trip's `input` is the
|
|
63
|
+
* real user prompt, and the last NON-EMPTY trip `output` is the final
|
|
64
|
+
* response text. (A failed / max-trips run can end on a trip whose
|
|
65
|
+
* `output` is `""` or tool-call-only, so we scan back for the last one
|
|
66
|
+
* that carried text rather than surfacing an empty string. Intermediate
|
|
67
|
+
* trips also store a `"[tool results]"` placeholder upstream.)
|
|
68
|
+
*
|
|
69
|
+
* Each value is passed through the optional {@link ContentRedactor};
|
|
70
|
+
* a redactor returning `undefined` drops the field.
|
|
71
|
+
*/
|
|
72
|
+
function captureContent(span, report, redact) {
|
|
73
|
+
const node = report;
|
|
74
|
+
let input;
|
|
75
|
+
let output;
|
|
76
|
+
if (report.type === "tool") {
|
|
77
|
+
input = node.input;
|
|
78
|
+
output = node.output;
|
|
79
|
+
} else if (Array.isArray(node.trips) && node.trips.length > 0) {
|
|
80
|
+
input = node.trips[0]?.input;
|
|
81
|
+
output = lastNonEmptyOutput(node.trips);
|
|
82
|
+
}
|
|
83
|
+
if (input !== void 0) {
|
|
84
|
+
const value = redact ? redact(input, {
|
|
85
|
+
name: span.name,
|
|
86
|
+
type: span.type,
|
|
87
|
+
field: "input"
|
|
88
|
+
}) : input;
|
|
89
|
+
if (value !== void 0) span.input = value;
|
|
90
|
+
}
|
|
91
|
+
if (output !== void 0) {
|
|
92
|
+
const value = redact ? redact(output, {
|
|
93
|
+
name: span.name,
|
|
94
|
+
type: span.type,
|
|
95
|
+
field: "output"
|
|
96
|
+
}) : output;
|
|
97
|
+
if (value !== void 0) span.output = value;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The last trip output that actually carries text — the agent's final
|
|
102
|
+
* response on the happy path. A failed or max-trips run can end on a trip
|
|
103
|
+
* whose `output` is `""` or tool-call-only, so we scan backwards for the
|
|
104
|
+
* last trip that produced text rather than blindly taking the final trip
|
|
105
|
+
* (which would surface an empty string). Returns `undefined` when no trip
|
|
106
|
+
* produced any output.
|
|
107
|
+
*/
|
|
108
|
+
function lastNonEmptyOutput(trips) {
|
|
109
|
+
for (let i = trips.length - 1; i >= 0; i -= 1) {
|
|
110
|
+
const out = trips[i]?.output;
|
|
111
|
+
if (typeof out === "string" ? out.length > 0 : out !== void 0) return out;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
50
114
|
|
|
51
115
|
//#endregion
|
|
52
116
|
export { reportToSpan };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-to-span.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-span.ts"],"sourcesContent":["import type { BaseReport } from \"@warlock.js/ai\";\nimport type { TraceSpan } from \"../contracts/trace.type\";\nimport { extractSpanAttributes } from \"./extract-span-attributes\";\nimport { normalizeError } from \"./normalize-error\";\n\n/**\n * Project one {@link BaseReport} node — and its entire subtree — into a\n * {@link TraceSpan}. Pure and recursive: identity, timing, status, and\n * the rolled-up `usage` map across 1:1 from the report; lineage maps\n * `runId → spanId`, `parentRunId → parentSpanId`, `rootRunId → traceId`;\n * children recurse in invocation order so the span tree mirrors the\n * report tree exactly.\n *\n * The error is normalized to the JSON-safe {@link\n * import(\"../contracts/trace.type\").TraceSpanError} shape only when the\n * node carried one (failed / cancelled). Primitive-specific detail that\n * has no first-class span field (trip / step / iteration counts, model\n * identity, tool trip index) is routed into the optional `attributes`\n * bag via {@link extractSpanAttributes}.\n *\n * No external lookup is needed — a `BaseReport` already carries\n * everything a span requires, so a collector can flatten a tree without\n * consulting any other source.\n *\n * @example\n * const root = reportToSpan(result.report);\n * console.log(root.spanId, root.traceId, root.children.length);\n */\nexport function reportToSpan(report: BaseReport): TraceSpan {\n const span: TraceSpan = {\n spanId: report.runId,\n traceId: report.rootRunId,\n name: report.name,\n type: report.type,\n status: report.status,\n startedAt: report.startedAt,\n endedAt: report.endedAt,\n duration: report.duration,\n usage: report.usage,\n children: report.children.map(reportToSpan),\n };\n\n if (report.parentRunId !== undefined) {\n span.parentSpanId = report.parentRunId;\n }\n\n if (report.sessionId !== undefined) {\n span.sessionId = report.sessionId;\n }\n\n if (report.version !== undefined) {\n span.version = report.version;\n }\n\n const error = normalizeError((report as { error?: unknown }).error);\n if (error !== undefined) {\n span.error = error;\n }\n\n const attributes = extractSpanAttributes(report);\n if (attributes !== undefined) {\n span.attributes = attributes;\n }\n\n return span;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"report-to-span.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-span.ts"],"sourcesContent":["import type { BaseReport } from \"@warlock.js/ai\";\nimport type { TraceSpan } from \"../contracts/trace.type\";\nimport type { ContentCaptureOptions, ContentRedactor } from \"./content-capture.type\";\nimport { extractSpanAttributes } from \"./extract-span-attributes\";\nimport { normalizeError } from \"./normalize-error\";\n\n/**\n * Project one {@link BaseReport} node — and its entire subtree — into a\n * {@link TraceSpan}. Pure and recursive: identity, timing, status, and\n * the rolled-up `usage` map across 1:1 from the report; lineage maps\n * `runId → spanId`, `parentRunId → parentSpanId`, `rootRunId → traceId`;\n * children recurse in invocation order so the span tree mirrors the\n * report tree exactly.\n *\n * The error is normalized to the JSON-safe {@link\n * import(\"../contracts/trace.type\").TraceSpanError} shape only when the\n * node carried one (failed / cancelled). Primitive-specific detail that\n * has no first-class span field (trip / step / iteration counts, model\n * identity, tool trip index) is routed into the optional `attributes`\n * bag via {@link extractSpanAttributes}.\n *\n * When {@link ContentCaptureOptions.captureContent} is set, the raw\n * prompt/response (agents) and args/result (tools) are additionally\n * copied onto `span.input` / `span.output` — off by default because\n * payloads are large and often sensitive. A {@link ContentRedactor} can\n * mask each value first.\n *\n * No external lookup is needed — a `BaseReport` already carries\n * everything a span requires, so a collector can flatten a tree without\n * consulting any other source.\n *\n * @example\n * const root = reportToSpan(result.report);\n * console.log(root.spanId, root.traceId, root.children.length);\n */\nexport function reportToSpan(report: BaseReport, options?: ContentCaptureOptions): TraceSpan {\n const span: TraceSpan = {\n spanId: report.runId,\n traceId: report.rootRunId,\n name: report.name,\n type: report.type,\n status: report.status,\n startedAt: report.startedAt,\n endedAt: report.endedAt,\n duration: report.duration,\n usage: report.usage,\n children: report.children.map((child) => reportToSpan(child, options)),\n };\n\n if (report.parentRunId !== undefined) {\n span.parentSpanId = report.parentRunId;\n }\n\n if (report.sessionId !== undefined) {\n span.sessionId = report.sessionId;\n }\n\n if (report.version !== undefined) {\n span.version = report.version;\n }\n\n const error = normalizeError((report as { error?: unknown }).error);\n if (error !== undefined) {\n span.error = error;\n }\n\n const attributes = extractSpanAttributes(report);\n if (attributes !== undefined) {\n span.attributes = attributes;\n }\n\n if (options?.captureContent) {\n captureContent(span, report, options.redactContent);\n }\n\n return span;\n}\n\n/** Per-primitive content fields read off a widened report node. */\ntype ContentReport = {\n input?: unknown;\n output?: unknown;\n trips?: Array<{ input?: unknown; output?: unknown }>;\n};\n\n/**\n * Copy the node's raw content onto `span.input` / `span.output`.\n *\n * - Tools carry the call arguments + return value directly on the report\n * (`ToolCall.input` / `ToolCall.output`).\n * - Agents carry a `trips[]` history; the first trip's `input` is the\n * real user prompt, and the last NON-EMPTY trip `output` is the final\n * response text. (A failed / max-trips run can end on a trip whose\n * `output` is `\"\"` or tool-call-only, so we scan back for the last one\n * that carried text rather than surfacing an empty string. Intermediate\n * trips also store a `\"[tool results]\"` placeholder upstream.)\n *\n * Each value is passed through the optional {@link ContentRedactor};\n * a redactor returning `undefined` drops the field.\n */\nfunction captureContent(span: TraceSpan, report: BaseReport, redact?: ContentRedactor): void {\n const node = report as BaseReport & ContentReport;\n\n let input: unknown;\n let output: unknown;\n\n if (report.type === \"tool\") {\n input = node.input;\n output = node.output;\n } else if (Array.isArray(node.trips) && node.trips.length > 0) {\n input = node.trips[0]?.input;\n output = lastNonEmptyOutput(node.trips);\n }\n\n if (input !== undefined) {\n const value = redact ? redact(input, { name: span.name, type: span.type, field: \"input\" }) : input;\n if (value !== undefined) {\n span.input = value;\n }\n }\n\n if (output !== undefined) {\n const value = redact ? redact(output, { name: span.name, type: span.type, field: \"output\" }) : output;\n if (value !== undefined) {\n span.output = value;\n }\n }\n}\n\n/**\n * The last trip output that actually carries text — the agent's final\n * response on the happy path. A failed or max-trips run can end on a trip\n * whose `output` is `\"\"` or tool-call-only, so we scan backwards for the\n * last trip that produced text rather than blindly taking the final trip\n * (which would surface an empty string). Returns `undefined` when no trip\n * produced any output.\n */\nfunction lastNonEmptyOutput(trips: Array<{ output?: unknown }>): unknown {\n for (let i = trips.length - 1; i >= 0; i -= 1) {\n const out = trips[i]?.output;\n const hasText = typeof out === \"string\" ? out.length > 0 : out !== undefined;\n\n if (hasText) {\n return out;\n }\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,aAAa,QAAoB,SAA4C;CAC3F,MAAM,OAAkB;EACtB,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,MAAM,OAAO;EACb,QAAQ,OAAO;EACf,WAAW,OAAO;EAClB,SAAS,OAAO;EAChB,UAAU,OAAO;EACjB,OAAO,OAAO;EACd,UAAU,OAAO,SAAS,KAAK,UAAU,aAAa,OAAO,OAAO,CAAC;CACvE;CAEA,IAAI,OAAO,gBAAgB,QACzB,KAAK,eAAe,OAAO;CAG7B,IAAI,OAAO,cAAc,QACvB,KAAK,YAAY,OAAO;CAG1B,IAAI,OAAO,YAAY,QACrB,KAAK,UAAU,OAAO;CAGxB,MAAM,QAAQ,eAAgB,OAA+B,KAAK;CAClE,IAAI,UAAU,QACZ,KAAK,QAAQ;CAGf,MAAM,aAAa,sBAAsB,MAAM;CAC/C,IAAI,eAAe,QACjB,KAAK,aAAa;CAGpB,IAAI,SAAS,gBACX,eAAe,MAAM,QAAQ,QAAQ,aAAa;CAGpD,OAAO;AACT;;;;;;;;;;;;;;;;AAwBA,SAAS,eAAe,MAAiB,QAAoB,QAAgC;CAC3F,MAAM,OAAO;CAEb,IAAI;CACJ,IAAI;CAEJ,IAAI,OAAO,SAAS,QAAQ;EAC1B,QAAQ,KAAK;EACb,SAAS,KAAK;CAChB,OAAO,IAAI,MAAM,QAAQ,KAAK,KAAK,KAAK,KAAK,MAAM,SAAS,GAAG;EAC7D,QAAQ,KAAK,MAAM,EAAE,EAAE;EACvB,SAAS,mBAAmB,KAAK,KAAK;CACxC;CAEA,IAAI,UAAU,QAAW;EACvB,MAAM,QAAQ,SAAS,OAAO,OAAO;GAAE,MAAM,KAAK;GAAM,MAAM,KAAK;GAAM,OAAO;EAAQ,CAAC,IAAI;EAC7F,IAAI,UAAU,QACZ,KAAK,QAAQ;CAEjB;CAEA,IAAI,WAAW,QAAW;EACxB,MAAM,QAAQ,SAAS,OAAO,QAAQ;GAAE,MAAM,KAAK;GAAM,MAAM,KAAK;GAAM,OAAO;EAAS,CAAC,IAAI;EAC/F,IAAI,UAAU,QACZ,KAAK,SAAS;CAElB;AACF;;;;;;;;;AAUA,SAAS,mBAAmB,OAA6C;CACvE,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;EAC7C,MAAM,MAAM,MAAM,EAAE,EAAE;EAGtB,IAFgB,OAAO,QAAQ,WAAW,IAAI,SAAS,IAAI,QAAQ,QAGjE,OAAO;CAEX;AAGF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Trace } from "../contracts/trace.type.mjs";
|
|
2
|
+
import { ContentCaptureOptions } from "./content-capture.type.mjs";
|
|
2
3
|
import { BaseReport } from "@warlock.js/ai";
|
|
3
4
|
|
|
4
5
|
//#region ../@warlock.js/ai-panoptic/src/collector/report-to-trace.d.ts
|
|
@@ -29,7 +30,7 @@ import { BaseReport } from "@warlock.js/ai";
|
|
|
29
30
|
* const trace = reportToTrace(result.report, result.error);
|
|
30
31
|
* console.log(trace.traceId, trace.usage.total, trace.duration);
|
|
31
32
|
*/
|
|
32
|
-
declare function reportToTrace(report: BaseReport, rootError?: unknown): Trace;
|
|
33
|
+
declare function reportToTrace(report: BaseReport, rootError?: unknown, options?: ContentCaptureOptions): Trace;
|
|
33
34
|
//#endregion
|
|
34
35
|
export { reportToTrace };
|
|
35
36
|
//# sourceMappingURL=report-to-trace.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-to-trace.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-trace.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"report-to-trace.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-trace.ts"],"mappings":";;;;;;;AAiCA;;;;;;;;;;;;;;;AAIQ;;;;;;;;;;iBAJQ,aAAA,CACd,MAAA,EAAQ,UAAA,EACR,SAAA,YACA,OAAA,GAAU,qBAAA,GACT,KAAA"}
|
|
@@ -29,8 +29,8 @@ import { reportToSpan } from "./report-to-span.mjs";
|
|
|
29
29
|
* const trace = reportToTrace(result.report, result.error);
|
|
30
30
|
* console.log(trace.traceId, trace.usage.total, trace.duration);
|
|
31
31
|
*/
|
|
32
|
-
function reportToTrace(report, rootError) {
|
|
33
|
-
const root = reportToSpan(report);
|
|
32
|
+
function reportToTrace(report, rootError, options) {
|
|
33
|
+
const root = reportToSpan(report, options);
|
|
34
34
|
if (root.error === void 0) {
|
|
35
35
|
const error = normalizeError(rootError);
|
|
36
36
|
if (error !== void 0) root.error = error;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-to-trace.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-trace.ts"],"sourcesContent":["import type { BaseReport } from \"@warlock.js/ai\";\nimport type { Trace } from \"../contracts/trace.type\";\nimport { normalizeError } from \"./normalize-error\";\nimport { reportToSpan } from \"./report-to-span\";\n\n/**\n * Project an outermost {@link BaseReport} (one whole `.execute()` /\n * `.invoke()` run) into a {@link Trace} — the root {@link\n * import(\"../contracts/trace.type\").TraceSpan} plus the trace-wide\n * rollups exporters need without re-walking the tree.\n *\n * The trace-level identity and rollups all read off the root span the\n * projection already built (`traceId`, `usage`, timing), so the trace\n * envelope never disagrees with its own root. `reportSchemaVersion` is\n * mirrored from the root report when present (it is stamped only on\n * root nodes upstream) so exporters can branch on the source shape.\n *\n * Pure — the same input always yields the same trace. The collector\n * exposes this as `toTrace` so callers can inspect the normalized shape\n * without dispatching to exporters.\n *\n * The optional `rootError` threads the failing run's envelope error\n * (`BaseResult.error`) onto the root span. The error lives on the result\n * envelope, never on the `BaseReport` tree, so without this a failed root\n * would export `status` with no error type/message. Applied only when the\n * root span carries none of its own; the subtree projection stays pure\n * (each child surfaces its own report-level error, if any).\n *\n * @example\n * const trace = reportToTrace(result.report, result.error);\n * console.log(trace.traceId, trace.usage.total, trace.duration);\n */\nexport function reportToTrace(report: BaseReport
|
|
1
|
+
{"version":3,"file":"report-to-trace.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/collector/report-to-trace.ts"],"sourcesContent":["import type { BaseReport } from \"@warlock.js/ai\";\nimport type { Trace } from \"../contracts/trace.type\";\nimport type { ContentCaptureOptions } from \"./content-capture.type\";\nimport { normalizeError } from \"./normalize-error\";\nimport { reportToSpan } from \"./report-to-span\";\n\n/**\n * Project an outermost {@link BaseReport} (one whole `.execute()` /\n * `.invoke()` run) into a {@link Trace} — the root {@link\n * import(\"../contracts/trace.type\").TraceSpan} plus the trace-wide\n * rollups exporters need without re-walking the tree.\n *\n * The trace-level identity and rollups all read off the root span the\n * projection already built (`traceId`, `usage`, timing), so the trace\n * envelope never disagrees with its own root. `reportSchemaVersion` is\n * mirrored from the root report when present (it is stamped only on\n * root nodes upstream) so exporters can branch on the source shape.\n *\n * Pure — the same input always yields the same trace. The collector\n * exposes this as `toTrace` so callers can inspect the normalized shape\n * without dispatching to exporters.\n *\n * The optional `rootError` threads the failing run's envelope error\n * (`BaseResult.error`) onto the root span. The error lives on the result\n * envelope, never on the `BaseReport` tree, so without this a failed root\n * would export `status` with no error type/message. Applied only when the\n * root span carries none of its own; the subtree projection stays pure\n * (each child surfaces its own report-level error, if any).\n *\n * @example\n * const trace = reportToTrace(result.report, result.error);\n * console.log(trace.traceId, trace.usage.total, trace.duration);\n */\nexport function reportToTrace(\n report: BaseReport,\n rootError?: unknown,\n options?: ContentCaptureOptions,\n): Trace {\n const root = reportToSpan(report, options);\n\n if (root.error === undefined) {\n const error = normalizeError(rootError);\n\n if (error !== undefined) {\n root.error = error;\n }\n }\n\n const trace: Trace = {\n traceId: root.traceId,\n root,\n startedAt: root.startedAt,\n endedAt: root.endedAt,\n duration: root.duration,\n usage: root.usage,\n };\n\n if (root.sessionId !== undefined) {\n trace.sessionId = root.sessionId;\n }\n\n if (report.reportSchemaVersion !== undefined) {\n trace.reportSchemaVersion = report.reportSchemaVersion;\n }\n\n return trace;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,SAAgB,cACd,QACA,WACA,SACO;CACP,MAAM,OAAO,aAAa,QAAQ,OAAO;CAEzC,IAAI,KAAK,UAAU,QAAW;EAC5B,MAAM,QAAQ,eAAe,SAAS;EAEtC,IAAI,UAAU,QACZ,KAAK,QAAQ;CAEjB;CAEA,MAAM,QAAe;EACnB,SAAS,KAAK;EACd;EACA,WAAW,KAAK;EAChB,SAAS,KAAK;EACd,UAAU,KAAK;EACf,OAAO,KAAK;CACd;CAEA,IAAI,KAAK,cAAc,QACrB,MAAM,YAAY,KAAK;CAGzB,IAAI,OAAO,wBAAwB,QACjC,MAAM,sBAAsB,OAAO;CAGrC,OAAO;AACT"}
|
|
@@ -13,7 +13,9 @@ import { ReportStatus, ReportType, Usage } from "@warlock.js/ai";
|
|
|
13
13
|
* about — identity (`spanId` / `parentSpanId` / `traceId`), timing
|
|
14
14
|
* (`startedAt` / `endedAt` / `duration`), outcome (`status` / `error`),
|
|
15
15
|
* and cost (`usage`) — so a collector can flatten a `BaseReport` tree
|
|
16
|
-
* into spans without consulting any other source.
|
|
16
|
+
* into spans without consulting any other source. Raw content — prompts,
|
|
17
|
+
* responses, and tool payloads — is captured onto `input` / `output`
|
|
18
|
+
* only when the collector opts in via `captureContent` (off by default).
|
|
17
19
|
*
|
|
18
20
|
* @example
|
|
19
21
|
* const root: TraceSpan = {
|
|
@@ -75,10 +77,27 @@ type TraceSpan = {
|
|
|
75
77
|
/**
|
|
76
78
|
* Free-form attribute bag forwarded verbatim onto the backend span
|
|
77
79
|
* (OTel attributes, Langfuse metadata). Collectors populate this with
|
|
78
|
-
* primitive-specific
|
|
79
|
-
* that has no first-class
|
|
80
|
+
* primitive-specific metadata (trip / step / iteration counts, model
|
|
81
|
+
* identity, the tool's originating trip index) that has no first-class
|
|
82
|
+
* field here. Raw prompts / completions / tool payloads do NOT live
|
|
83
|
+
* here — they go on {@link TraceSpan.input} / {@link TraceSpan.output}
|
|
84
|
+
* under content capture. Absent when empty.
|
|
80
85
|
*/
|
|
81
86
|
attributes?: Record<string, unknown>;
|
|
87
|
+
/**
|
|
88
|
+
* Captured input for this node — an agent's first-trip prompt or a
|
|
89
|
+
* tool's call arguments — present ONLY when the collector ran with
|
|
90
|
+
* content capture enabled (`captureContent`), off by default because
|
|
91
|
+
* payloads are large and often sensitive. Typed `unknown`: agent
|
|
92
|
+
* prompts are strings, tool args are the validated argument value.
|
|
93
|
+
*/
|
|
94
|
+
input?: unknown;
|
|
95
|
+
/**
|
|
96
|
+
* Captured output for this node — an agent's final response text or a
|
|
97
|
+
* tool's return value — present only under content capture (see
|
|
98
|
+
* {@link TraceSpan.input}).
|
|
99
|
+
*/
|
|
100
|
+
output?: unknown;
|
|
82
101
|
/**
|
|
83
102
|
* Child spans, mirroring `BaseReport.children` in invocation order.
|
|
84
103
|
* Empty for leaf spans (pure tools). Exporters that emit a flat
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace.type.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/contracts/trace.type.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"trace.type.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/contracts/trace.type.ts"],"mappings":";;;;;AAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAAY,SAAA;EA2DG;;;;EAtDb,MAAA;EA0EmB;AAAA;AAQrB;;EA7EE,YAAA;EA6EwB;;;;;AAMnB;EA5EL,OAAA;EAqFe;;;;;EA/Ef,SAAA,WAqFM;EAnFN,IAAA;EAuFA;;;;;EAjFA,OAAA,WA2FmB;EAzFnB,IAAA,EAAM,UAAA;EAEN,MAAA,EAAQ,YAAA;EAER,SAAA;EAEA,OAAA;EAEA,QAAA;EAEA,KAAA,EAAO,KAAA;;;;;;EAMP,KAAA,GAAQ,cAAA;;;;;;;;;;EAUR,UAAA,GAAa,MAAA;;;;;;;;EAQb,KAAA;;;;;;EAMA,MAAA;;;;;;EAMA,QAAA,EAAU,SAAA;AAAA;;;;;;KAQA,cAAA;6EAEV,IAAA;EAEA,OAAA;EAEA,KAAA;AAAA;;;;;;;KASU,KAAA;mEAEV,OAAA;EAEA,SAAA;EAEA,IAAA,EAAM,SAAA;EAEN,SAAA;EAEA,OAAA;EAEA,QAAA;EAEA,KAAA,EAAO,KAAK;;;;;;EAMZ,mBAAA;AAAA"}
|
|
@@ -8,9 +8,10 @@ import { ConsoleExporterOptions } from "./console-exporter.type.mjs";
|
|
|
8
8
|
* as the reference implementation of the contract.
|
|
9
9
|
*
|
|
10
10
|
* By default it prints one summary line per completed trace. Set
|
|
11
|
-
* `tree: true` to print the full indented span tree,
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* `tree: true` to print the full indented span tree, `io: true` to also
|
|
12
|
+
* print each span's captured `input` / `output` (needs the collector's
|
|
13
|
+
* `captureContent`), and `streaming: true` to print each span the moment
|
|
14
|
+
* it finalizes (via the optional `exportSpan` hook).
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* collector.use(consoleExporter());
|
|
@@ -18,6 +19,13 @@ import { ConsoleExporterOptions } from "./console-exporter.type.mjs";
|
|
|
18
19
|
*
|
|
19
20
|
* @example
|
|
20
21
|
* collector.use(consoleExporter({ tree: true }));
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Full content trace — prompts, responses, and tool I/O:
|
|
25
|
+
* const observe = panoptic({
|
|
26
|
+
* captureContent: true,
|
|
27
|
+
* exporters: [consoleExporter({ tree: true, io: true })],
|
|
28
|
+
* });
|
|
21
29
|
*/
|
|
22
30
|
declare function consoleExporter(options?: ConsoleExporterOptions): ExporterContract;
|
|
23
31
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"console-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.ts"],"mappings":";;;;;;;AAiCA;;;;;;;;AAAuF;;;;;;;;;;;;;;iBAAvE,eAAA,CAAgB,OAAA,GAAS,sBAAA,GAA8B,gBAAgB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { walkSpans } from "../utils/walk-spans.mjs";
|
|
2
|
+
import { formatSpanIO } from "./format-span-io.mjs";
|
|
2
3
|
import { formatSpanLine } from "./format-span-line.mjs";
|
|
3
4
|
|
|
4
5
|
//#region ../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.ts
|
|
@@ -9,9 +10,10 @@ const EXPORTER_NAME = "console";
|
|
|
9
10
|
* as the reference implementation of the contract.
|
|
10
11
|
*
|
|
11
12
|
* By default it prints one summary line per completed trace. Set
|
|
12
|
-
* `tree: true` to print the full indented span tree,
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* `tree: true` to print the full indented span tree, `io: true` to also
|
|
14
|
+
* print each span's captured `input` / `output` (needs the collector's
|
|
15
|
+
* `captureContent`), and `streaming: true` to print each span the moment
|
|
16
|
+
* it finalizes (via the optional `exportSpan` hook).
|
|
15
17
|
*
|
|
16
18
|
* @example
|
|
17
19
|
* collector.use(consoleExporter());
|
|
@@ -19,36 +21,52 @@ const EXPORTER_NAME = "console";
|
|
|
19
21
|
*
|
|
20
22
|
* @example
|
|
21
23
|
* collector.use(consoleExporter({ tree: true }));
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Full content trace — prompts, responses, and tool I/O:
|
|
27
|
+
* const observe = panoptic({
|
|
28
|
+
* captureContent: true,
|
|
29
|
+
* exporters: [consoleExporter({ tree: true, io: true })],
|
|
30
|
+
* });
|
|
22
31
|
*/
|
|
23
32
|
function consoleExporter(options = {}) {
|
|
24
33
|
const sink = options.console ?? console;
|
|
25
34
|
const tree = options.tree ?? false;
|
|
35
|
+
const io = options.io ?? false;
|
|
36
|
+
const ioMaxChars = options.ioMaxChars;
|
|
26
37
|
const exporter = {
|
|
27
38
|
name: EXPORTER_NAME,
|
|
28
39
|
export(trace) {
|
|
29
|
-
writeTrace(sink, trace, tree);
|
|
40
|
+
writeTrace(sink, trace, tree, io, ioMaxChars);
|
|
30
41
|
}
|
|
31
42
|
};
|
|
32
43
|
if (options.streaming) exporter.exportSpan = (span) => {
|
|
33
44
|
sink.log(formatSpanLine(span));
|
|
45
|
+
if (io) for (const line of formatSpanIO(span, 0, ioMaxChars)) sink.log(line);
|
|
34
46
|
};
|
|
35
47
|
return exporter;
|
|
36
48
|
}
|
|
37
49
|
/**
|
|
38
50
|
* Write a completed trace — either a single root summary line or the
|
|
39
|
-
* full indented tree
|
|
40
|
-
*
|
|
51
|
+
* full indented tree, each span optionally followed by its captured
|
|
52
|
+
* `input` / `output`. Failed / cancelled spans route to `console.error`
|
|
53
|
+
* so they surface at the right severity in log aggregators.
|
|
41
54
|
*/
|
|
42
|
-
function writeTrace(sink, trace, tree) {
|
|
55
|
+
function writeTrace(sink, trace, tree, io, ioMaxChars) {
|
|
43
56
|
if (!tree) {
|
|
44
|
-
|
|
45
|
-
writeAtSeverity(sink, trace.root.status, line);
|
|
57
|
+
writeSpan(sink, trace.root, 0, io, ioMaxChars);
|
|
46
58
|
return;
|
|
47
59
|
}
|
|
48
|
-
for (const span of walkSpans(trace.root))
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
for (const span of walkSpans(trace.root)) writeSpan(sink, span, spanDepth(trace.root, span.spanId), io, ioMaxChars);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Write one span's line and — when `io` is on — its captured content,
|
|
64
|
+
* all routed at the span's own severity so a failed span keeps its
|
|
65
|
+
* content beside it in the error stream.
|
|
66
|
+
*/
|
|
67
|
+
function writeSpan(sink, span, depth, io, ioMaxChars) {
|
|
68
|
+
writeAtSeverity(sink, span.status, formatSpanLine(span, depth));
|
|
69
|
+
if (io) for (const line of formatSpanIO(span, depth, ioMaxChars)) writeAtSeverity(sink, span.status, line);
|
|
52
70
|
}
|
|
53
71
|
/**
|
|
54
72
|
* Route a line to `error` when the span failed/cancelled, otherwise to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-exporter.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.ts"],"sourcesContent":["import type { ExporterContract, Trace, TraceSpan } from \"../../contracts\";\nimport { walkSpans } from \"../utils\";\nimport type { ConsoleExporterOptions, ConsoleLike } from \"./console-exporter.type\";\nimport { formatSpanLine } from \"./format-span-line\";\n\nconst EXPORTER_NAME = \"console\";\n\n/**\n * Zero-dependency {@link ExporterContract} that prints traces to a\n * console-like sink. The simplest exporter — useful in development and\n * as the reference implementation of the contract.\n *\n * By default it prints one summary line per completed trace. Set\n * `tree: true` to print the full indented span tree,
|
|
1
|
+
{"version":3,"file":"console-exporter.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.ts"],"sourcesContent":["import type { ExporterContract, Trace, TraceSpan } from \"../../contracts\";\nimport { walkSpans } from \"../utils\";\nimport type { ConsoleExporterOptions, ConsoleLike } from \"./console-exporter.type\";\nimport { formatSpanIO } from \"./format-span-io\";\nimport { formatSpanLine } from \"./format-span-line\";\n\nconst EXPORTER_NAME = \"console\";\n\n/**\n * Zero-dependency {@link ExporterContract} that prints traces to a\n * console-like sink. The simplest exporter — useful in development and\n * as the reference implementation of the contract.\n *\n * By default it prints one summary line per completed trace. Set\n * `tree: true` to print the full indented span tree, `io: true` to also\n * print each span's captured `input` / `output` (needs the collector's\n * `captureContent`), and `streaming: true` to print each span the moment\n * it finalizes (via the optional `exportSpan` hook).\n *\n * @example\n * collector.use(consoleExporter());\n * // ok workflow \"checkout\" — 2103ms, 1820 tok, $0.0094\n *\n * @example\n * collector.use(consoleExporter({ tree: true }));\n *\n * @example\n * // Full content trace — prompts, responses, and tool I/O:\n * const observe = panoptic({\n * captureContent: true,\n * exporters: [consoleExporter({ tree: true, io: true })],\n * });\n */\nexport function consoleExporter(options: ConsoleExporterOptions = {}): ExporterContract {\n const sink: ConsoleLike = options.console ?? console;\n const tree = options.tree ?? false;\n const io = options.io ?? false;\n const ioMaxChars = options.ioMaxChars;\n\n const exporter: ExporterContract = {\n name: EXPORTER_NAME,\n export(trace: Trace): void {\n writeTrace(sink, trace, tree, io, ioMaxChars);\n },\n };\n\n if (options.streaming) {\n exporter.exportSpan = (span: TraceSpan): void => {\n sink.log(formatSpanLine(span));\n\n if (io) {\n for (const line of formatSpanIO(span, 0, ioMaxChars)) {\n sink.log(line);\n }\n }\n };\n }\n\n return exporter;\n}\n\n/**\n * Write a completed trace — either a single root summary line or the\n * full indented tree, each span optionally followed by its captured\n * `input` / `output`. Failed / cancelled spans route to `console.error`\n * so they surface at the right severity in log aggregators.\n */\nfunction writeTrace(\n sink: ConsoleLike,\n trace: Trace,\n tree: boolean,\n io: boolean,\n ioMaxChars: number | undefined,\n): void {\n if (!tree) {\n writeSpan(sink, trace.root, 0, io, ioMaxChars);\n return;\n }\n\n for (const span of walkSpans(trace.root)) {\n const depth = spanDepth(trace.root, span.spanId);\n writeSpan(sink, span, depth, io, ioMaxChars);\n }\n}\n\n/**\n * Write one span's line and — when `io` is on — its captured content,\n * all routed at the span's own severity so a failed span keeps its\n * content beside it in the error stream.\n */\nfunction writeSpan(\n sink: ConsoleLike,\n span: TraceSpan,\n depth: number,\n io: boolean,\n ioMaxChars: number | undefined,\n): void {\n writeAtSeverity(sink, span.status, formatSpanLine(span, depth));\n\n if (io) {\n for (const line of formatSpanIO(span, depth, ioMaxChars)) {\n writeAtSeverity(sink, span.status, line);\n }\n }\n}\n\n/**\n * Route a line to `error` when the span failed/cancelled, otherwise to\n * `log`. Keeps healthy traces out of the error stream.\n */\nfunction writeAtSeverity(sink: ConsoleLike, status: TraceSpan[\"status\"], line: string): void {\n if (status === \"failed\" || status === \"cancelled\") {\n sink.error(line);\n return;\n }\n\n sink.log(line);\n}\n\n/**\n * Depth of `targetSpanId` below `root` for indentation. Walks the tree\n * once; returns 0 when the span is the root or not found.\n */\nfunction spanDepth(root: TraceSpan, targetSpanId: string, depth = 0): number {\n if (root.spanId === targetSpanId) {\n return depth;\n }\n\n for (const child of root.children) {\n const found = spanDepth(child, targetSpanId, depth + 1);\n\n if (found > 0) {\n return found;\n }\n }\n\n return 0;\n}\n"],"mappings":";;;;;AAMA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BtB,SAAgB,gBAAgB,UAAkC,CAAC,GAAqB;CACtF,MAAM,OAAoB,QAAQ,WAAW;CAC7C,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,KAAK,QAAQ,MAAM;CACzB,MAAM,aAAa,QAAQ;CAE3B,MAAM,WAA6B;EACjC,MAAM;EACN,OAAO,OAAoB;GACzB,WAAW,MAAM,OAAO,MAAM,IAAI,UAAU;EAC9C;CACF;CAEA,IAAI,QAAQ,WACV,SAAS,cAAc,SAA0B;EAC/C,KAAK,IAAI,eAAe,IAAI,CAAC;EAE7B,IAAI,IACF,KAAK,MAAM,QAAQ,aAAa,MAAM,GAAG,UAAU,GACjD,KAAK,IAAI,IAAI;CAGnB;CAGF,OAAO;AACT;;;;;;;AAQA,SAAS,WACP,MACA,OACA,MACA,IACA,YACM;CACN,IAAI,CAAC,MAAM;EACT,UAAU,MAAM,MAAM,MAAM,GAAG,IAAI,UAAU;EAC7C;CACF;CAEA,KAAK,MAAM,QAAQ,UAAU,MAAM,IAAI,GAErC,UAAU,MAAM,MADF,UAAU,MAAM,MAAM,KAAK,MACf,GAAG,IAAI,UAAU;AAE/C;;;;;;AAOA,SAAS,UACP,MACA,MACA,OACA,IACA,YACM;CACN,gBAAgB,MAAM,KAAK,QAAQ,eAAe,MAAM,KAAK,CAAC;CAE9D,IAAI,IACF,KAAK,MAAM,QAAQ,aAAa,MAAM,OAAO,UAAU,GACrD,gBAAgB,MAAM,KAAK,QAAQ,IAAI;AAG7C;;;;;AAMA,SAAS,gBAAgB,MAAmB,QAA6B,MAAoB;CAC3F,IAAI,WAAW,YAAY,WAAW,aAAa;EACjD,KAAK,MAAM,IAAI;EACf;CACF;CAEA,KAAK,IAAI,IAAI;AACf;;;;;AAMA,SAAS,UAAU,MAAiB,cAAsB,QAAQ,GAAW;CAC3E,IAAI,KAAK,WAAW,cAClB,OAAO;CAGT,KAAK,MAAM,SAAS,KAAK,UAAU;EACjC,MAAM,QAAQ,UAAU,OAAO,cAAc,QAAQ,CAAC;EAEtD,IAAI,QAAQ,GACV,OAAO;CAEX;CAEA,OAAO;AACT"}
|
|
@@ -30,6 +30,21 @@ type ConsoleExporterOptions = {
|
|
|
30
30
|
* present, so leaving this off omits the method entirely.
|
|
31
31
|
*/
|
|
32
32
|
streaming?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Also print each span's captured content — `TraceSpan.input` /
|
|
35
|
+
* `output` — as extra indented `in:` / `out:` lines beneath the span.
|
|
36
|
+
* Defaults to `false`. Requires the collector to run with content
|
|
37
|
+
* capture (`captureContent`); without it spans carry no content and
|
|
38
|
+
* this is a no-op.
|
|
39
|
+
*/
|
|
40
|
+
io?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Max characters of captured content shown per `in:` / `out:` line
|
|
43
|
+
* before truncation — only when {@link ConsoleExporterOptions.io} is on.
|
|
44
|
+
* Defaults to `500`. Raise it for fuller payloads, or use the file
|
|
45
|
+
* exporter for untruncated content.
|
|
46
|
+
*/
|
|
47
|
+
ioMaxChars?: number;
|
|
33
48
|
};
|
|
34
49
|
//#endregion
|
|
35
50
|
export { ConsoleExporterOptions, ConsoleLike };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-exporter.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.type.ts"],"mappings":";;AAMA;;;;;KAAY,WAAA;EACV,GAAA,IAAO,IAAA;EACP,KAAA,IAAS,IAAA;AAAA;AAAI;AAMf;;AANe,KAMH,sBAAA;EAKW;;;;EAArB,OAAA,GAAU,WAAW;
|
|
1
|
+
{"version":3,"file":"console-exporter.type.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/console-exporter.type.ts"],"mappings":";;AAMA;;;;;KAAY,WAAA;EACV,GAAA,IAAO,IAAA;EACP,KAAA,IAAS,IAAA;AAAA;AAAI;AAMf;;AANe,KAMH,sBAAA;EAKW;;;;EAArB,OAAA,GAAU,WAAW;EAoBrB;;;AAOU;;EArBV,IAAA;;;;;;EAMA,SAAA;;;;;;;;EAQA,EAAA;;;;;;;EAOA,UAAA;AAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TraceSpan } from "../../contracts/trace.type.mjs";
|
|
2
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/console/format-span-io.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Render a span's captured content ({@link TraceSpan.input} /
|
|
5
|
+
* {@link TraceSpan.output}) as extra indented console lines, one level
|
|
6
|
+
* below the span's own line:
|
|
7
|
+
*
|
|
8
|
+
* ```text
|
|
9
|
+
* ok agent "market-research" — 1794ms, 224 tok, $0.0008
|
|
10
|
+
* in: Research the market for Acme Coffee Roasters …
|
|
11
|
+
* out: Demand is steady; specialty buyers skew premium …
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Returns `[]` when the span carries no content — capture disabled, or a
|
|
15
|
+
* composite node with no own I/O. Each value is stringified (JSON for
|
|
16
|
+
* non-strings), whitespace-collapsed to stay scannable, and truncated to
|
|
17
|
+
* `maxChars` (default {@link DEFAULT_IO_MAX_CHARS}) with an ellipsis. Use
|
|
18
|
+
* the file exporter for the full, untruncated payload.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* formatSpanIO(toolSpan, 1);
|
|
22
|
+
* // [' in: {"query":"specialty coffee demand"}', ' out: {"results":[…]}']
|
|
23
|
+
*/
|
|
24
|
+
declare function formatSpanIO(span: TraceSpan, depth?: number, maxChars?: number): string[];
|
|
25
|
+
//#endregion
|
|
26
|
+
export { formatSpanIO };
|
|
27
|
+
//# sourceMappingURL=format-span-io.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-span-io.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/format-span-io.ts"],"mappings":";;;;;AA0BA;;;;;;;;;AAAwF;;;;;;;;;iBAAxE,YAAA,CAAa,IAAA,EAAM,SAAS,EAAE,KAAA,WAAW,QAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai-panoptic/src/exporters/console/format-span-io.ts
|
|
2
|
+
/** Default cap on how many characters of captured content a console line shows. */
|
|
3
|
+
const DEFAULT_IO_MAX_CHARS = 500;
|
|
4
|
+
/**
|
|
5
|
+
* Render a span's captured content ({@link TraceSpan.input} /
|
|
6
|
+
* {@link TraceSpan.output}) as extra indented console lines, one level
|
|
7
|
+
* below the span's own line:
|
|
8
|
+
*
|
|
9
|
+
* ```text
|
|
10
|
+
* ok agent "market-research" — 1794ms, 224 tok, $0.0008
|
|
11
|
+
* in: Research the market for Acme Coffee Roasters …
|
|
12
|
+
* out: Demand is steady; specialty buyers skew premium …
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* Returns `[]` when the span carries no content — capture disabled, or a
|
|
16
|
+
* composite node with no own I/O. Each value is stringified (JSON for
|
|
17
|
+
* non-strings), whitespace-collapsed to stay scannable, and truncated to
|
|
18
|
+
* `maxChars` (default {@link DEFAULT_IO_MAX_CHARS}) with an ellipsis. Use
|
|
19
|
+
* the file exporter for the full, untruncated payload.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* formatSpanIO(toolSpan, 1);
|
|
23
|
+
* // [' in: {"query":"specialty coffee demand"}', ' out: {"results":[…]}']
|
|
24
|
+
*/
|
|
25
|
+
function formatSpanIO(span, depth = 0, maxChars = DEFAULT_IO_MAX_CHARS) {
|
|
26
|
+
const lines = [];
|
|
27
|
+
const indent = " ".repeat(depth + 1);
|
|
28
|
+
if (span.input !== void 0) lines.push(`${indent}in: ${preview(span.input, maxChars)}`);
|
|
29
|
+
if (span.output !== void 0) lines.push(`${indent}out: ${preview(span.output, maxChars)}`);
|
|
30
|
+
return lines;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One-line, length-capped preview of a captured value. Strings pass
|
|
34
|
+
* through; everything else is JSON-stringified (falling back to
|
|
35
|
+
* `String()` on a circular / unstringifiable value). Internal whitespace
|
|
36
|
+
* is collapsed so the preview never breaks the tree layout.
|
|
37
|
+
*/
|
|
38
|
+
function preview(value, maxChars) {
|
|
39
|
+
const collapsed = (typeof value === "string" ? value : stringify(value)).replace(/\s+/g, " ").trim();
|
|
40
|
+
return collapsed.length > maxChars ? `${collapsed.slice(0, maxChars)}…` : collapsed;
|
|
41
|
+
}
|
|
42
|
+
function stringify(value) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.stringify(value) ?? String(value);
|
|
45
|
+
} catch {
|
|
46
|
+
return String(value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { formatSpanIO };
|
|
52
|
+
//# sourceMappingURL=format-span-io.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-span-io.mjs","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/console/format-span-io.ts"],"sourcesContent":["import type { TraceSpan } from \"../../contracts\";\n\n/** Default cap on how many characters of captured content a console line shows. */\nconst DEFAULT_IO_MAX_CHARS = 500;\n\n/**\n * Render a span's captured content ({@link TraceSpan.input} /\n * {@link TraceSpan.output}) as extra indented console lines, one level\n * below the span's own line:\n *\n * ```text\n * ok agent \"market-research\" — 1794ms, 224 tok, $0.0008\n * in: Research the market for Acme Coffee Roasters …\n * out: Demand is steady; specialty buyers skew premium …\n * ```\n *\n * Returns `[]` when the span carries no content — capture disabled, or a\n * composite node with no own I/O. Each value is stringified (JSON for\n * non-strings), whitespace-collapsed to stay scannable, and truncated to\n * `maxChars` (default {@link DEFAULT_IO_MAX_CHARS}) with an ellipsis. Use\n * the file exporter for the full, untruncated payload.\n *\n * @example\n * formatSpanIO(toolSpan, 1);\n * // [' in: {\"query\":\"specialty coffee demand\"}', ' out: {\"results\":[…]}']\n */\nexport function formatSpanIO(span: TraceSpan, depth = 0, maxChars = DEFAULT_IO_MAX_CHARS): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth + 1);\n\n if (span.input !== undefined) {\n lines.push(`${indent}in: ${preview(span.input, maxChars)}`);\n }\n\n if (span.output !== undefined) {\n lines.push(`${indent}out: ${preview(span.output, maxChars)}`);\n }\n\n return lines;\n}\n\n/**\n * One-line, length-capped preview of a captured value. Strings pass\n * through; everything else is JSON-stringified (falling back to\n * `String()` on a circular / unstringifiable value). Internal whitespace\n * is collapsed so the preview never breaks the tree layout.\n */\nfunction preview(value: unknown, maxChars: number): string {\n const text = typeof value === \"string\" ? value : stringify(value);\n const collapsed = text.replace(/\\s+/g, \" \").trim();\n\n return collapsed.length > maxChars ? `${collapsed.slice(0, maxChars)}…` : collapsed;\n}\n\nfunction stringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n"],"mappings":";;AAGA,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;AAuB7B,SAAgB,aAAa,MAAiB,QAAQ,GAAG,WAAW,sBAAgC;CAClG,MAAM,QAAkB,CAAC;CACzB,MAAM,SAAS,KAAK,OAAO,QAAQ,CAAC;CAEpC,IAAI,KAAK,UAAU,QACjB,MAAM,KAAK,GAAG,OAAO,OAAO,QAAQ,KAAK,OAAO,QAAQ,GAAG;CAG7D,IAAI,KAAK,WAAW,QAClB,MAAM,KAAK,GAAG,OAAO,OAAO,QAAQ,KAAK,QAAQ,QAAQ,GAAG;CAG9D,OAAO;AACT;;;;;;;AAQA,SAAS,QAAQ,OAAgB,UAA0B;CAEzD,MAAM,aADO,OAAO,UAAU,WAAW,QAAQ,UAAU,KAAK,EAC1C,CAAC,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;CAEjD,OAAO,UAAU,SAAS,WAAW,GAAG,UAAU,MAAM,GAAG,QAAQ,EAAE,KAAK;AAC5E;AAEA,SAAS,UAAU,OAAwB;CACzC,IAAI;EACF,OAAO,KAAK,UAAU,KAAK,KAAK,OAAO,KAAK;CAC9C,QAAQ;EACN,OAAO,OAAO,KAAK;CACrB;AACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { ConsoleExporterOptions, ConsoleLike } from "./console-exporter.type.mjs";
|
|
2
2
|
import { consoleExporter } from "./console-exporter.mjs";
|
|
3
|
-
import { formatSpanLine } from "./format-span-line.mjs";
|
|
3
|
+
import { formatSpanLine } from "./format-span-line.mjs";
|
|
4
|
+
import { formatSpanIO } from "./format-span-io.mjs";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConsoleExporterOptions, ConsoleLike } from "./console/console-exporter.type.mjs";
|
|
2
2
|
import { consoleExporter } from "./console/console-exporter.mjs";
|
|
3
3
|
import { formatSpanLine } from "./console/format-span-line.mjs";
|
|
4
|
+
import { formatSpanIO } from "./console/format-span-io.mjs";
|
|
4
5
|
import { FileExporterOptions, TraceRecord } from "./file/file-exporter.type.mjs";
|
|
5
6
|
import { fileExporter } from "./file/file-exporter.mjs";
|
|
6
7
|
import { LangfuseClientLike, LangfuseExporterOptions, LangfuseObservationBody, LangfuseObservationEndBody, LangfuseObservationLevel, LangfuseObservationLike, LangfuseTraceBody, LangfuseTraceLike, LangfuseUsageBody } from "./langfuse/langfuse-exporter.type.mjs";
|
package/esm/exporters/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { walkSpans } from "./utils/walk-spans.mjs";
|
|
2
2
|
import { totalCostUsd } from "./utils/total-cost.mjs";
|
|
3
3
|
import { GEN_AI_ATTRIBUTES, WARLOCK_ATTRIBUTES, toGenAiAttributes } from "./utils/gen-ai-attributes.mjs";
|
|
4
|
+
import { formatSpanIO } from "./console/format-span-io.mjs";
|
|
4
5
|
import { formatSpanLine } from "./console/format-span-line.mjs";
|
|
5
6
|
import { consoleExporter } from "./console/console-exporter.mjs";
|
|
6
7
|
import { fileExporter } from "./file/file-exporter.mjs";
|
|
@@ -9,12 +9,16 @@ import { LangfuseExporterOptions } from "./langfuse-exporter.type.mjs";
|
|
|
9
9
|
* installed, and a missing SDK surfaces as a curated "install this"
|
|
10
10
|
* error when the exporter first needs to build a client.
|
|
11
11
|
*
|
|
12
|
-
* The root {@link TraceSpan} becomes a Langfuse trace
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* The root {@link TraceSpan} becomes a Langfuse trace AND its top
|
|
13
|
+
* observation (so the root execution's own tokens are metered, not just
|
|
14
|
+
* its children's); every node is an observation — a `generation` when it
|
|
15
|
+
* metered its OWN tokens (LLM-backed agents, supervisors), otherwise a
|
|
16
|
+
* plain `span` (tools, callbacks, and composite nodes whose tokens came
|
|
17
|
+
* only from children). Timing, status, and version map 1:1; each
|
|
18
|
+
* generation reports its own token usage (rolled-up minus children) so
|
|
19
|
+
* the trace total isn't double-counted; non-usage GenAI attributes ride
|
|
20
|
+
* along as metadata, and captured content (under `captureContent`)
|
|
21
|
+
* surfaces as native `input` / `output`.
|
|
18
22
|
*
|
|
19
23
|
* @example
|
|
20
24
|
* collector.use(langfuseExporter({ publicKey: "pk-...", secretKey: "sk-..." }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langfuse-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"langfuse-exporter.d.mts","names":[],"sources":["../../../../../../../../@warlock.js/ai-panoptic/src/exporters/langfuse/langfuse-exporter.ts"],"mappings":";;;;;;;AAoFA;;;;;;;;AAAoF;;;;;;;;;;;;iBAApE,gBAAA,CAAiB,OAAA,EAAS,uBAAA,GAA0B,gBAAgB"}
|