@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,21 @@
|
|
|
1
|
+
import { Trace } from "../contracts/trace.type.mjs";
|
|
2
|
+
import { TraceQuery } from "./trace-query.type.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../@warlock.js/ai-panoptic/src/store/match-trace.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Test whether one trace satisfies a {@link TraceQuery}. Every declared
|
|
7
|
+
* filter field must match (logical AND); absent fields are ignored, so
|
|
8
|
+
* an empty / undefined filter matches every trace.
|
|
9
|
+
*
|
|
10
|
+
* Time bounds compare against the trace's root `startedAt`, parsed to
|
|
11
|
+
* an epoch once per call, inclusive on both ends. Status accepts a
|
|
12
|
+
* single value or an array (membership test). Identity fields are exact
|
|
13
|
+
* string equality.
|
|
14
|
+
*
|
|
15
|
+
* Pure — used by the store's `query` and `aggregate` so both share one
|
|
16
|
+
* matching definition.
|
|
17
|
+
*/
|
|
18
|
+
declare function matchTrace(trace: Trace, filter?: TraceQuery): boolean;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { matchTrace };
|
|
21
|
+
//# sourceMappingURL=match-trace.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match-trace.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/match-trace.ts"],"mappings":";;;;;;AAiBA;;;;;;;;;AAA4D;;iBAA5C,UAAA,CAAW,KAAA,EAAO,KAAA,EAAO,MAAA,GAAS,UAAU"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region ../@warlock.js/ai-panoptic/src/store/match-trace.ts
|
|
2
|
+
/**
|
|
3
|
+
* Test whether one trace satisfies a {@link TraceQuery}. Every declared
|
|
4
|
+
* filter field must match (logical AND); absent fields are ignored, so
|
|
5
|
+
* an empty / undefined filter matches every trace.
|
|
6
|
+
*
|
|
7
|
+
* Time bounds compare against the trace's root `startedAt`, parsed to
|
|
8
|
+
* an epoch once per call, inclusive on both ends. Status accepts a
|
|
9
|
+
* single value or an array (membership test). Identity fields are exact
|
|
10
|
+
* string equality.
|
|
11
|
+
*
|
|
12
|
+
* Pure — used by the store's `query` and `aggregate` so both share one
|
|
13
|
+
* matching definition.
|
|
14
|
+
*/
|
|
15
|
+
function matchTrace(trace, filter) {
|
|
16
|
+
if (!filter) return true;
|
|
17
|
+
if (filter.traceId !== void 0 && trace.traceId !== filter.traceId) return false;
|
|
18
|
+
if (filter.sessionId !== void 0 && trace.sessionId !== filter.sessionId) return false;
|
|
19
|
+
if (filter.status !== void 0 && !statusMatches(trace.root.status, filter.status)) return false;
|
|
20
|
+
const startedAt = Date.parse(trace.startedAt);
|
|
21
|
+
if (filter.startedAfter !== void 0 && startedAt < toEpoch(filter.startedAfter)) return false;
|
|
22
|
+
if (filter.startedBefore !== void 0 && startedAt > toEpoch(filter.startedBefore)) return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Membership test for the status filter — true when `status` equals the
|
|
27
|
+
* single wanted value, or is one of the wanted array.
|
|
28
|
+
*/
|
|
29
|
+
function statusMatches(status, wanted) {
|
|
30
|
+
if (Array.isArray(wanted)) return wanted.includes(status);
|
|
31
|
+
return status === wanted;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Normalize a time bound (ISO string or `Date`) to epoch milliseconds
|
|
35
|
+
* for comparison against a parsed `startedAt`.
|
|
36
|
+
*/
|
|
37
|
+
function toEpoch(bound) {
|
|
38
|
+
if (bound instanceof Date) return bound.getTime();
|
|
39
|
+
return Date.parse(bound);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { matchTrace };
|
|
44
|
+
//# sourceMappingURL=match-trace.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match-trace.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/match-trace.ts"],"sourcesContent":["import type { ReportStatus } from \"@warlock.js/ai\";\nimport type { Trace } from \"../contracts/trace.type\";\nimport type { TraceQuery } from \"./trace-query.type\";\n\n/**\n * Test whether one trace satisfies a {@link TraceQuery}. Every declared\n * filter field must match (logical AND); absent fields are ignored, so\n * an empty / undefined filter matches every trace.\n *\n * Time bounds compare against the trace's root `startedAt`, parsed to\n * an epoch once per call, inclusive on both ends. Status accepts a\n * single value or an array (membership test). Identity fields are exact\n * string equality.\n *\n * Pure — used by the store's `query` and `aggregate` so both share one\n * matching definition.\n */\nexport function matchTrace(trace: Trace, filter?: TraceQuery): boolean {\n if (!filter) {\n return true;\n }\n\n if (filter.traceId !== undefined && trace.traceId !== filter.traceId) {\n return false;\n }\n\n if (filter.sessionId !== undefined && trace.sessionId !== filter.sessionId) {\n return false;\n }\n\n if (filter.status !== undefined && !statusMatches(trace.root.status, filter.status)) {\n return false;\n }\n\n const startedAt = Date.parse(trace.startedAt);\n\n if (filter.startedAfter !== undefined && startedAt < toEpoch(filter.startedAfter)) {\n return false;\n }\n\n if (filter.startedBefore !== undefined && startedAt > toEpoch(filter.startedBefore)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Membership test for the status filter — true when `status` equals the\n * single wanted value, or is one of the wanted array.\n */\nfunction statusMatches(status: ReportStatus, wanted: ReportStatus | ReportStatus[]): boolean {\n if (Array.isArray(wanted)) {\n return wanted.includes(status);\n }\n\n return status === wanted;\n}\n\n/**\n * Normalize a time bound (ISO string or `Date`) to epoch milliseconds\n * for comparison against a parsed `startedAt`.\n */\nfunction toEpoch(bound: string | Date): number {\n if (bound instanceof Date) {\n return bound.getTime();\n }\n\n return Date.parse(bound);\n}\n"],"mappings":";;;;;;;;;;;;;;AAiBA,SAAgB,WAAW,OAAc,QAA8B;CACrE,IAAI,CAAC,QACH,OAAO;CAGT,IAAI,OAAO,YAAY,UAAa,MAAM,YAAY,OAAO,SAC3D,OAAO;CAGT,IAAI,OAAO,cAAc,UAAa,MAAM,cAAc,OAAO,WAC/D,OAAO;CAGT,IAAI,OAAO,WAAW,UAAa,CAAC,cAAc,MAAM,KAAK,QAAQ,OAAO,MAAM,GAChF,OAAO;CAGT,MAAM,YAAY,KAAK,MAAM,MAAM,SAAS;CAE5C,IAAI,OAAO,iBAAiB,UAAa,YAAY,QAAQ,OAAO,YAAY,GAC9E,OAAO;CAGT,IAAI,OAAO,kBAAkB,UAAa,YAAY,QAAQ,OAAO,aAAa,GAChF,OAAO;CAGT,OAAO;AACT;;;;;AAMA,SAAS,cAAc,QAAsB,QAAgD;CAC3F,IAAI,MAAM,QAAQ,MAAM,GACtB,OAAO,OAAO,SAAS,MAAM;CAG/B,OAAO,WAAW;AACpB;;;;;AAMA,SAAS,QAAQ,OAA8B;CAC7C,IAAI,iBAAiB,MACnB,OAAO,MAAM,QAAQ;CAGvB,OAAO,KAAK,MAAM,KAAK;AACzB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Usage } from "@warlock.js/ai";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/store/sum-usage.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Fold a child {@link Usage} into a running accumulator. Token channels
|
|
6
|
+
* (`input` / `output` / `total`) always sum; the optional cache /
|
|
7
|
+
* reasoning channels (`cachedTokens` / `cacheWriteTokens` /
|
|
8
|
+
* `reasoningTokens`) sum only when at least one side reported them, so
|
|
9
|
+
* a provider that never meters a channel doesn't fabricate a `0` for
|
|
10
|
+
* it. The `cost` breakdown is merged with the core framework's
|
|
11
|
+
* {@link accumulateCost}, keeping cost-rollup semantics identical to a
|
|
12
|
+
* native report tree — an unpriced contributor never erases a priced
|
|
13
|
+
* one.
|
|
14
|
+
*
|
|
15
|
+
* Pure: returns a fresh `Usage`, never mutates either argument. Seed an
|
|
16
|
+
* aggregation with {@link emptyUsage}.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* let total = emptyUsage();
|
|
20
|
+
* for (const trace of traces) {
|
|
21
|
+
* total = sumUsage(total, trace.usage);
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
declare function sumUsage(accumulator: Usage, next: Usage): Usage;
|
|
25
|
+
/**
|
|
26
|
+
* A zero-valued {@link Usage} to seed an aggregation. Only the required
|
|
27
|
+
* token channels are set; optional channels stay absent until a
|
|
28
|
+
* contributor reports them, preserving the "never reported" vs
|
|
29
|
+
* "reported as 0" distinction.
|
|
30
|
+
*/
|
|
31
|
+
declare function emptyUsage(): Usage;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { emptyUsage, sumUsage };
|
|
34
|
+
//# sourceMappingURL=sum-usage.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sum-usage.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/sum-usage.ts"],"mappings":";;;;;AAsBA;;;;;;;;;;;;;;AAAgE;AAoChE;;;iBApCgB,QAAA,CAAS,WAAA,EAAa,KAAA,EAAO,IAAA,EAAM,KAAA,GAAQ,KAAA;AAoCxB;;;;;;AAAA,iBAAnB,UAAA,IAAc,KAAK"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { accumulateCost } from "@warlock.js/ai";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/store/sum-usage.ts
|
|
4
|
+
/**
|
|
5
|
+
* Fold a child {@link Usage} into a running accumulator. Token channels
|
|
6
|
+
* (`input` / `output` / `total`) always sum; the optional cache /
|
|
7
|
+
* reasoning channels (`cachedTokens` / `cacheWriteTokens` /
|
|
8
|
+
* `reasoningTokens`) sum only when at least one side reported them, so
|
|
9
|
+
* a provider that never meters a channel doesn't fabricate a `0` for
|
|
10
|
+
* it. The `cost` breakdown is merged with the core framework's
|
|
11
|
+
* {@link accumulateCost}, keeping cost-rollup semantics identical to a
|
|
12
|
+
* native report tree — an unpriced contributor never erases a priced
|
|
13
|
+
* one.
|
|
14
|
+
*
|
|
15
|
+
* Pure: returns a fresh `Usage`, never mutates either argument. Seed an
|
|
16
|
+
* aggregation with {@link emptyUsage}.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* let total = emptyUsage();
|
|
20
|
+
* for (const trace of traces) {
|
|
21
|
+
* total = sumUsage(total, trace.usage);
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
function sumUsage(accumulator, next) {
|
|
25
|
+
const merged = {
|
|
26
|
+
input: accumulator.input + next.input,
|
|
27
|
+
output: accumulator.output + next.output,
|
|
28
|
+
total: accumulator.total + next.total
|
|
29
|
+
};
|
|
30
|
+
const cachedTokens = sumOptional(accumulator.cachedTokens, next.cachedTokens);
|
|
31
|
+
if (cachedTokens !== void 0) merged.cachedTokens = cachedTokens;
|
|
32
|
+
const cacheWriteTokens = sumOptional(accumulator.cacheWriteTokens, next.cacheWriteTokens);
|
|
33
|
+
if (cacheWriteTokens !== void 0) merged.cacheWriteTokens = cacheWriteTokens;
|
|
34
|
+
const reasoningTokens = sumOptional(accumulator.reasoningTokens, next.reasoningTokens);
|
|
35
|
+
if (reasoningTokens !== void 0) merged.reasoningTokens = reasoningTokens;
|
|
36
|
+
const cost = accumulateCost(accumulator.cost, next.cost);
|
|
37
|
+
if (cost !== void 0) merged.cost = cost;
|
|
38
|
+
return merged;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A zero-valued {@link Usage} to seed an aggregation. Only the required
|
|
42
|
+
* token channels are set; optional channels stay absent until a
|
|
43
|
+
* contributor reports them, preserving the "never reported" vs
|
|
44
|
+
* "reported as 0" distinction.
|
|
45
|
+
*/
|
|
46
|
+
function emptyUsage() {
|
|
47
|
+
return {
|
|
48
|
+
input: 0,
|
|
49
|
+
output: 0,
|
|
50
|
+
total: 0
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Add two optional token counts, treating either side's `undefined` as
|
|
55
|
+
* zero — but return `undefined` when both are absent, so an unreported
|
|
56
|
+
* channel stays unreported rather than collapsing to `0`.
|
|
57
|
+
*/
|
|
58
|
+
function sumOptional(accumulator, next) {
|
|
59
|
+
if (accumulator === void 0 && next === void 0) return;
|
|
60
|
+
return (accumulator ?? 0) + (next ?? 0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { emptyUsage, sumUsage };
|
|
65
|
+
//# sourceMappingURL=sum-usage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sum-usage.mjs","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/sum-usage.ts"],"sourcesContent":["import { accumulateCost, type Usage } from \"@warlock.js/ai\";\n\n/**\n * Fold a child {@link Usage} into a running accumulator. Token channels\n * (`input` / `output` / `total`) always sum; the optional cache /\n * reasoning channels (`cachedTokens` / `cacheWriteTokens` /\n * `reasoningTokens`) sum only when at least one side reported them, so\n * a provider that never meters a channel doesn't fabricate a `0` for\n * it. The `cost` breakdown is merged with the core framework's\n * {@link accumulateCost}, keeping cost-rollup semantics identical to a\n * native report tree — an unpriced contributor never erases a priced\n * one.\n *\n * Pure: returns a fresh `Usage`, never mutates either argument. Seed an\n * aggregation with {@link emptyUsage}.\n *\n * @example\n * let total = emptyUsage();\n * for (const trace of traces) {\n * total = sumUsage(total, trace.usage);\n * }\n */\nexport function sumUsage(accumulator: Usage, next: Usage): Usage {\n const merged: Usage = {\n input: accumulator.input + next.input,\n output: accumulator.output + next.output,\n total: accumulator.total + next.total,\n };\n\n const cachedTokens = sumOptional(accumulator.cachedTokens, next.cachedTokens);\n if (cachedTokens !== undefined) {\n merged.cachedTokens = cachedTokens;\n }\n\n const cacheWriteTokens = sumOptional(accumulator.cacheWriteTokens, next.cacheWriteTokens);\n if (cacheWriteTokens !== undefined) {\n merged.cacheWriteTokens = cacheWriteTokens;\n }\n\n const reasoningTokens = sumOptional(accumulator.reasoningTokens, next.reasoningTokens);\n if (reasoningTokens !== undefined) {\n merged.reasoningTokens = reasoningTokens;\n }\n\n const cost = accumulateCost(accumulator.cost, next.cost);\n if (cost !== undefined) {\n merged.cost = cost;\n }\n\n return merged;\n}\n\n/**\n * A zero-valued {@link Usage} to seed an aggregation. Only the required\n * token channels are set; optional channels stay absent until a\n * contributor reports them, preserving the \"never reported\" vs\n * \"reported as 0\" distinction.\n */\nexport function emptyUsage(): Usage {\n return {\n input: 0,\n output: 0,\n total: 0,\n };\n}\n\n/**\n * Add two optional token counts, treating either side's `undefined` as\n * zero — but return `undefined` when both are absent, so an unreported\n * channel stays unreported rather than collapsing to `0`.\n */\nfunction sumOptional(accumulator: number | undefined, next: number | undefined): number | undefined {\n if (accumulator === undefined && next === undefined) {\n return undefined;\n }\n\n return (accumulator ?? 0) + (next ?? 0);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,SAAS,aAAoB,MAAoB;CAC/D,MAAM,SAAgB;EACpB,OAAO,YAAY,QAAQ,KAAK;EAChC,QAAQ,YAAY,SAAS,KAAK;EAClC,OAAO,YAAY,QAAQ,KAAK;CAClC;CAEA,MAAM,eAAe,YAAY,YAAY,cAAc,KAAK,YAAY;CAC5E,IAAI,iBAAiB,QACnB,OAAO,eAAe;CAGxB,MAAM,mBAAmB,YAAY,YAAY,kBAAkB,KAAK,gBAAgB;CACxF,IAAI,qBAAqB,QACvB,OAAO,mBAAmB;CAG5B,MAAM,kBAAkB,YAAY,YAAY,iBAAiB,KAAK,eAAe;CACrF,IAAI,oBAAoB,QACtB,OAAO,kBAAkB;CAG3B,MAAM,OAAO,eAAe,YAAY,MAAM,KAAK,IAAI;CACvD,IAAI,SAAS,QACX,OAAO,OAAO;CAGhB,OAAO;AACT;;;;;;;AAQA,SAAgB,aAAoB;CAClC,OAAO;EACL,OAAO;EACP,QAAQ;EACR,OAAO;CACT;AACF;;;;;;AAOA,SAAS,YAAY,aAAiC,MAA8C;CAClG,IAAI,gBAAgB,UAAa,SAAS,QACxC;CAGF,QAAQ,eAAe,MAAM,QAAQ;AACvC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ModelPricing, Usage } from "@warlock.js/ai";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/store/trace-aggregate.type.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Rolled-up usage + cost across a set of stored traces, returned by the
|
|
6
|
+
* trace store's `aggregate`. Answers the headline observability
|
|
7
|
+
* questions — "how many runs, how many tokens, how much did it cost,
|
|
8
|
+
* how many failed" — for whatever slice a {@link
|
|
9
|
+
* import("./trace-query.type").TraceQuery} selected.
|
|
10
|
+
*
|
|
11
|
+
* `usage` sums the per-trace root `Usage` (already a rollup of own cost
|
|
12
|
+
* + children), so the totals reflect the entire run tree without
|
|
13
|
+
* re-walking spans. `cost` is the per-channel USD breakdown merged with
|
|
14
|
+
* the same `accumulateCost` logic the core framework uses to roll a
|
|
15
|
+
* report tree, so an unpriced trace never erases the cost of priced
|
|
16
|
+
* ones — `cost` stays `undefined` only when NO trace in the slice
|
|
17
|
+
* carried pricing.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const stats = store.aggregate({ sessionId: "session-42" });
|
|
21
|
+
* console.log(`${stats.traces} runs, ${stats.usage.total} tokens`);
|
|
22
|
+
* const totalUsd =
|
|
23
|
+
* (stats.cost?.input ?? 0) +
|
|
24
|
+
* (stats.cost?.output ?? 0) +
|
|
25
|
+
* (stats.cost?.cachedInput ?? 0) +
|
|
26
|
+
* (stats.cost?.cachedOutput ?? 0);
|
|
27
|
+
*/
|
|
28
|
+
type TraceAggregate = {
|
|
29
|
+
/** Number of traces matched by the query. */traces: number; /** Count of matched traces whose root status was `"completed"`. */
|
|
30
|
+
completed: number; /** Count of matched traces whose root status was `"failed"`. */
|
|
31
|
+
failed: number; /** Count of matched traces whose root status was `"cancelled"`. */
|
|
32
|
+
cancelled: number;
|
|
33
|
+
/**
|
|
34
|
+
* Summed token usage across every matched trace. `input` / `output` /
|
|
35
|
+
* `total` always present (zero when no traces matched); the optional
|
|
36
|
+
* cache / reasoning channels are summed only when at least one trace
|
|
37
|
+
* reported them.
|
|
38
|
+
*/
|
|
39
|
+
usage: Usage;
|
|
40
|
+
/**
|
|
41
|
+
* Merged per-channel USD cost across every matched trace, or
|
|
42
|
+
* `undefined` when no matched trace carried pricing. Same shape as
|
|
43
|
+
* `ModelPricing` so callers can read the input/output/cache split,
|
|
44
|
+
* not just one opaque number.
|
|
45
|
+
*/
|
|
46
|
+
cost?: ModelPricing; /** Summed wall-clock duration in milliseconds across matched traces. */
|
|
47
|
+
totalDuration: number;
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { TraceAggregate };
|
|
51
|
+
//# sourceMappingURL=trace-aggregate.type.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-aggregate.type.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/trace-aggregate.type.ts"],"mappings":";;;;;AA0BA;;;;;;;;;;;;;;AAwBe;;;;;;;;KAxBH,cAAA;+CAEV,MAAA;EAEA,SAAA;EAEA,MAAA;EAEA,SAAA;;;;;;;EAOA,KAAA,EAAO,KAAA;;;;;;;EAOP,IAAA,GAAO,YAAY;EAEnB,aAAA;AAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReportStatus } from "@warlock.js/ai";
|
|
2
|
+
|
|
3
|
+
//#region ../@warlock.js/ai-panoptic/src/store/trace-query.type.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Filter passed to the trace store's `query` / `aggregate`. Every field
|
|
6
|
+
* is optional and ANDed together — an absent field is "don't care", so
|
|
7
|
+
* an empty filter matches every stored trace. Designed so the common
|
|
8
|
+
* observability questions ("everything for session X", "failed runs in
|
|
9
|
+
* the last hour", "this one run") express as a single object.
|
|
10
|
+
*
|
|
11
|
+
* Time bounds match against each trace's root `startedAt` (the wall
|
|
12
|
+
* clock the run began), inclusive on both ends, accepting either an
|
|
13
|
+
* ISO-8601 string or a `Date` so callers can pass whichever they hold.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const failedToday = store.query({
|
|
17
|
+
* status: "failed",
|
|
18
|
+
* startedAfter: "2026-06-18T00:00:00.000Z",
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const sessionSpend = store.aggregate({ sessionId: "session-42" });
|
|
23
|
+
*/
|
|
24
|
+
type TraceQuery = {
|
|
25
|
+
/**
|
|
26
|
+
* Match a single trace by its `traceId` (equals the root run's
|
|
27
|
+
* `runId`). The most specific filter — narrows to at most one trace.
|
|
28
|
+
*/
|
|
29
|
+
traceId?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Match every trace whose root carried this `sessionId`. The primary
|
|
32
|
+
* grouping dimension for conversation / request-scoped rollups.
|
|
33
|
+
*/
|
|
34
|
+
sessionId?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Match traces whose root terminal `status` equals this value, or any
|
|
37
|
+
* of these values when an array is given.
|
|
38
|
+
*/
|
|
39
|
+
status?: ReportStatus | ReportStatus[]; /** Inclusive lower bound on the trace's root `startedAt`. */
|
|
40
|
+
startedAfter?: string | Date; /** Inclusive upper bound on the trace's root `startedAt`. */
|
|
41
|
+
startedBefore?: string | Date;
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
44
|
+
export { TraceQuery };
|
|
45
|
+
//# sourceMappingURL=trace-query.type.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-query.type.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/trace-query.type.ts"],"mappings":";;;;;AAsBA;;;;;;;;;;;;;;;;;;KAAY,UAAA;EAmBmB;;;;EAd7B,OAAA;;;;;EAKA,SAAA;;;;;EAKA,MAAA,GAAS,YAAA,GAAe,YAAA;EAExB,YAAA,YAAwB,IAAA;EAExB,aAAA,YAAyB,IAAA;AAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Trace } from "../contracts/trace.type.mjs";
|
|
2
|
+
import { TraceAggregate } from "./trace-aggregate.type.mjs";
|
|
3
|
+
import { TraceQuery } from "./trace-query.type.mjs";
|
|
4
|
+
|
|
5
|
+
//#region ../@warlock.js/ai-panoptic/src/store/trace-store.contract.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Contract for a Panoptic trace store — a queryable sink that retains
|
|
8
|
+
* collected {@link Trace}s so an app can answer observability questions
|
|
9
|
+
* after the fact: pull one run by id, list every run for a session,
|
|
10
|
+
* slice failed runs in a time window, or roll usage + cost across any
|
|
11
|
+
* of those slices.
|
|
12
|
+
*
|
|
13
|
+
* A store is itself a valid place for a `Collector` to fan out to: the
|
|
14
|
+
* in-memory implementation ({@link import("./in-memory-trace-store").createInMemoryTraceStore})
|
|
15
|
+
* doubles as an `ExporterContract`, so wiring it into a collector is a
|
|
16
|
+
* single `collector.use(store)` and the store fills as traces complete.
|
|
17
|
+
*
|
|
18
|
+
* **Retention is the implementation's concern.** This contract makes no
|
|
19
|
+
* promise about durability or eviction — the in-memory store keeps
|
|
20
|
+
* everything until `clear`, bounded only by an optional capacity cap.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const store = createInMemoryTraceStore();
|
|
24
|
+
* collector.use(store);
|
|
25
|
+
* // later:
|
|
26
|
+
* const failed = store.query({ status: "failed" });
|
|
27
|
+
* const spend = store.aggregate({ sessionId });
|
|
28
|
+
*/
|
|
29
|
+
interface TraceStoreContract {
|
|
30
|
+
/**
|
|
31
|
+
* Ingest one finalized trace. Replaces any existing trace with the
|
|
32
|
+
* same `traceId` (re-collecting a run overwrites rather than
|
|
33
|
+
* duplicates).
|
|
34
|
+
*/
|
|
35
|
+
add(trace: Trace): void;
|
|
36
|
+
/** Retrieve a single trace by its `traceId`, or `undefined` if absent. */
|
|
37
|
+
get(traceId: string): Trace | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Return every stored trace matching the filter, newest-started
|
|
40
|
+
* first. An empty filter returns all traces.
|
|
41
|
+
*/
|
|
42
|
+
query(filter?: TraceQuery): Trace[];
|
|
43
|
+
/**
|
|
44
|
+
* Roll usage + cost (and status counts) across every trace matching
|
|
45
|
+
* the filter. An empty filter aggregates the whole store.
|
|
46
|
+
*/
|
|
47
|
+
aggregate(filter?: TraceQuery): TraceAggregate;
|
|
48
|
+
/** Total number of traces currently retained. */
|
|
49
|
+
readonly size: number;
|
|
50
|
+
/** Remove every stored trace. */
|
|
51
|
+
clear(): void;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { TraceStoreContract };
|
|
55
|
+
//# sourceMappingURL=trace-store.contract.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-store.contract.d.mts","names":[],"sources":["../../../../../../../@warlock.js/ai-panoptic/src/store/trace-store.contract.ts"],"mappings":";;;;;;;AA2BA;;;;;;;;;;;;;;;;;;;;;UAAiB,kBAAA;EAqBI;;;;;EAfnB,GAAA,CAAI,KAAA,EAAO,KAAA;EAqBN;EAlBL,GAAA,CAAI,OAAA,WAAkB,KAAA;;;;;EAMtB,KAAA,CAAM,MAAA,GAAS,UAAA,GAAa,KAAA;;;;;EAM5B,SAAA,CAAU,MAAA,GAAS,UAAA,GAAa,cAAA;;WAGvB,IAAA;;EAGT,KAAA;AAAA"}
|