nexus-ai-pro 2.0.0 → 2.2.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/API_STABILITY.md +65 -0
- package/CHANGELOG.md +267 -1
- package/MIGRATING.md +1 -1
- package/README.md +17 -8
- package/dist/agent/create-agent.d.ts +9 -1
- package/dist/agent/create-agent.js +40 -1
- package/dist/cache/memory-cache.d.ts +8 -0
- package/dist/cache/memory-cache.js +9 -0
- package/dist/cache/semantic-cache.d.ts +6 -3
- package/dist/cache/semantic-cache.js +5 -2
- package/dist/cli/args.js +3 -0
- package/dist/cli/db.d.ts +16 -4
- package/dist/cli/db.js +169 -22
- package/dist/cli/doctor.d.ts +17 -0
- package/dist/cli/doctor.js +53 -0
- package/dist/cli/graph.d.ts +9 -0
- package/dist/cli/graph.js +47 -0
- package/dist/cli.js +21 -2
- package/dist/core/lifecycle.js +11 -6
- package/dist/core/nexus.d.ts +12 -2
- package/dist/core/nexus.js +106 -23
- package/dist/doctor/index.d.ts +90 -0
- package/dist/doctor/index.js +237 -0
- package/dist/evals/judge.d.ts +11 -0
- package/dist/evals/judge.js +33 -0
- package/dist/evaluate/index.d.ts +1 -0
- package/dist/evaluate/index.js +1 -0
- package/dist/evaluate/provenance.d.ts +22 -0
- package/dist/evaluate/provenance.js +10 -0
- package/dist/evaluate/run.js +20 -4
- package/dist/graph/durability.d.ts +27 -0
- package/dist/graph/durability.js +66 -0
- package/dist/graph/errors.d.ts +30 -4
- package/dist/graph/errors.js +18 -2
- package/dist/graph/event-stream.d.ts +75 -0
- package/dist/graph/event-stream.js +289 -0
- package/dist/graph/functional.d.ts +80 -7
- package/dist/graph/functional.js +138 -35
- package/dist/graph/graph.d.ts +56 -8
- package/dist/graph/graph.js +331 -49
- package/dist/graph/index.d.ts +4 -2
- package/dist/graph/index.js +3 -1
- package/dist/graph/lint.d.ts +57 -0
- package/dist/graph/lint.js +141 -0
- package/dist/graph/run-control.d.ts +28 -0
- package/dist/graph/run-control.js +26 -0
- package/dist/images/evals.js +4 -2
- package/dist/operations/adapters.d.ts +52 -4
- package/dist/operations/adapters.js +194 -7
- package/dist/operations/runner.js +14 -15
- package/dist/operations/stats.js +8 -1
- package/dist/operations/store.d.ts +5 -1
- package/dist/operations/store.js +7 -0
- package/dist/ops/circuit-breaker.d.ts +52 -0
- package/dist/ops/circuit-breaker.js +4 -0
- package/dist/ops/circuit-store.d.ts +13 -2
- package/dist/ops/circuit-store.js +68 -0
- package/dist/ops/circuit-sync.d.ts +17 -0
- package/dist/ops/circuit-sync.js +86 -0
- package/dist/ops/health.d.ts +24 -0
- package/dist/ops/health.js +38 -10
- package/dist/ops/index.d.ts +1 -1
- package/dist/ops/index.js +1 -1
- package/dist/ops/rate-limit-adapters.d.ts +23 -0
- package/dist/ops/rate-limit-adapters.js +34 -0
- package/dist/ops/rate-limiter.d.ts +14 -2
- package/dist/ops/rate-limiter.js +31 -0
- package/dist/postgres/circuits.d.ts +21 -4
- package/dist/postgres/circuits.js +65 -4
- package/dist/postgres/client.d.ts +0 -2
- package/dist/postgres/client.js +0 -4
- package/dist/postgres/evaluate.d.ts +16 -4
- package/dist/postgres/evaluate.js +17 -5
- package/dist/postgres/index.d.ts +32 -11
- package/dist/postgres/index.js +65 -31
- package/dist/postgres/migrations.d.ts +60 -0
- package/dist/postgres/migrations.js +121 -0
- package/dist/postgres/operations.d.ts +14 -3
- package/dist/postgres/operations.js +45 -15
- package/dist/postgres/prompts.d.ts +11 -2
- package/dist/postgres/prompts.js +14 -3
- package/dist/postgres/rollups.d.ts +35 -0
- package/dist/postgres/rollups.js +129 -0
- package/dist/postgres/store.d.ts +11 -2
- package/dist/postgres/store.js +14 -3
- package/dist/postgres/traces.d.ts +13 -3
- package/dist/postgres/traces.js +25 -3
- package/dist/postgres/vectors.d.ts +11 -2
- package/dist/postgres/vectors.js +14 -3
- package/dist/router/auto-router.d.ts +34 -7
- package/dist/router/auto-router.js +201 -68
- package/dist/server/assistant.d.ts +44 -0
- package/dist/server/assistant.js +39 -0
- package/dist/server/errors.d.ts +12 -0
- package/dist/server/errors.js +7 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/runs.d.ts +28 -1
- package/dist/server/runs.js +110 -14
- package/dist/sqlite/index.d.ts +16 -3
- package/dist/sqlite/index.js +16 -3
- package/dist/sqlite/migrations.d.ts +26 -0
- package/dist/sqlite/migrations.js +63 -0
- package/dist/sqlite/operations.d.ts +14 -3
- package/dist/sqlite/operations.js +42 -15
- package/dist/sqlite/store.d.ts +9 -2
- package/dist/sqlite/store.js +13 -3
- package/dist/sqlite/vectors.d.ts +11 -2
- package/dist/sqlite/vectors.js +13 -2
- package/dist/store/tenant.d.ts +12 -0
- package/dist/store/tenant.js +29 -0
- package/dist/tenancy/index.d.ts +113 -0
- package/dist/tenancy/index.js +233 -0
- package/dist/testing/record.d.ts +42 -0
- package/dist/testing/record.js +57 -5
- package/dist/tracing/index.d.ts +3 -3
- package/dist/tracing/index.js +2 -2
- package/dist/tracing/instrument.js +30 -0
- package/dist/tracing/otlp.d.ts +91 -0
- package/dist/tracing/otlp.js +124 -0
- package/dist/tracing/rollups.d.ts +100 -0
- package/dist/tracing/rollups.js +139 -0
- package/dist/tracing/stores.d.ts +17 -0
- package/dist/tracing/stores.js +23 -0
- package/dist/tracing/tracer.d.ts +50 -4
- package/dist/tracing/tracer.js +85 -6
- package/dist/types/config.d.ts +33 -2
- package/dist/types/evaluate.d.ts +37 -0
- package/dist/types/graph.d.ts +354 -9
- package/dist/types/graph.js +3 -1
- package/dist/types/messages.d.ts +5 -0
- package/dist/types/operations.d.ts +22 -2
- package/dist/types/response.d.ts +20 -0
- package/dist/types/server.d.ts +18 -0
- package/dist/types/tracing.d.ts +11 -0
- package/dist/utils/schema-migrations.d.ts +97 -0
- package/dist/utils/schema-migrations.js +91 -0
- package/dist/utils/signals.d.ts +17 -0
- package/dist/utils/signals.js +26 -0
- package/dist/utils/tenant.d.ts +14 -0
- package/dist/utils/tenant.js +16 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +1 -0
- package/dist-cjs/agent/create-agent.d.ts +9 -1
- package/dist-cjs/agent/create-agent.js +40 -1
- package/dist-cjs/cache/memory-cache.d.ts +8 -0
- package/dist-cjs/cache/memory-cache.js +9 -0
- package/dist-cjs/cache/semantic-cache.d.ts +6 -3
- package/dist-cjs/cache/semantic-cache.js +5 -2
- package/dist-cjs/cli/args.js +3 -0
- package/dist-cjs/cli/db.d.ts +16 -4
- package/dist-cjs/cli/db.js +200 -20
- package/dist-cjs/cli/doctor.d.ts +17 -0
- package/dist-cjs/cli/doctor.js +56 -0
- package/dist-cjs/cli/graph.d.ts +9 -0
- package/dist-cjs/cli/graph.js +50 -0
- package/dist-cjs/core/lifecycle.js +11 -6
- package/dist-cjs/core/nexus.d.ts +12 -2
- package/dist-cjs/core/nexus.js +106 -23
- package/dist-cjs/doctor/index.d.ts +90 -0
- package/dist-cjs/doctor/index.js +276 -0
- package/dist-cjs/evals/judge.d.ts +11 -0
- package/dist-cjs/evals/judge.js +33 -0
- package/dist-cjs/evaluate/index.d.ts +1 -0
- package/dist-cjs/evaluate/index.js +3 -1
- package/dist-cjs/evaluate/provenance.d.ts +22 -0
- package/dist-cjs/evaluate/provenance.js +14 -0
- package/dist-cjs/evaluate/run.js +20 -4
- package/dist-cjs/graph/durability.d.ts +27 -0
- package/dist-cjs/graph/durability.js +70 -0
- package/dist-cjs/graph/errors.d.ts +30 -4
- package/dist-cjs/graph/errors.js +20 -3
- package/dist-cjs/graph/event-stream.d.ts +75 -0
- package/dist-cjs/graph/event-stream.js +295 -0
- package/dist-cjs/graph/functional.d.ts +80 -7
- package/dist-cjs/graph/functional.js +137 -34
- package/dist-cjs/graph/graph.d.ts +56 -8
- package/dist-cjs/graph/graph.js +330 -48
- package/dist-cjs/graph/index.d.ts +4 -2
- package/dist-cjs/graph/index.js +7 -1
- package/dist-cjs/graph/lint.d.ts +57 -0
- package/dist-cjs/graph/lint.js +144 -0
- package/dist-cjs/graph/run-control.d.ts +28 -0
- package/dist-cjs/graph/run-control.js +30 -0
- package/dist-cjs/images/evals.js +4 -2
- package/dist-cjs/operations/adapters.d.ts +52 -4
- package/dist-cjs/operations/adapters.js +193 -6
- package/dist-cjs/operations/runner.js +14 -15
- package/dist-cjs/operations/stats.js +8 -1
- package/dist-cjs/operations/store.d.ts +5 -1
- package/dist-cjs/operations/store.js +7 -0
- package/dist-cjs/ops/circuit-breaker.d.ts +52 -0
- package/dist-cjs/ops/circuit-breaker.js +4 -0
- package/dist-cjs/ops/circuit-store.d.ts +13 -2
- package/dist-cjs/ops/circuit-store.js +68 -0
- package/dist-cjs/ops/circuit-sync.d.ts +17 -0
- package/dist-cjs/ops/circuit-sync.js +87 -0
- package/dist-cjs/ops/health.d.ts +24 -0
- package/dist-cjs/ops/health.js +38 -10
- package/dist-cjs/ops/index.d.ts +1 -1
- package/dist-cjs/ops/rate-limit-adapters.d.ts +23 -0
- package/dist-cjs/ops/rate-limit-adapters.js +35 -1
- package/dist-cjs/ops/rate-limiter.d.ts +14 -2
- package/dist-cjs/ops/rate-limiter.js +32 -0
- package/dist-cjs/postgres/circuits.d.ts +21 -4
- package/dist-cjs/postgres/circuits.js +98 -3
- package/dist-cjs/postgres/client.d.ts +0 -2
- package/dist-cjs/postgres/client.js +0 -5
- package/dist-cjs/postgres/evaluate.d.ts +16 -4
- package/dist-cjs/postgres/evaluate.js +50 -4
- package/dist-cjs/postgres/index.d.ts +32 -11
- package/dist-cjs/postgres/index.js +69 -20
- package/dist-cjs/postgres/migrations.d.ts +60 -0
- package/dist-cjs/postgres/migrations.js +129 -0
- package/dist-cjs/postgres/operations.d.ts +14 -3
- package/dist-cjs/postgres/operations.js +78 -14
- package/dist-cjs/postgres/prompts.d.ts +11 -2
- package/dist-cjs/postgres/prompts.js +47 -2
- package/dist-cjs/postgres/rollups.d.ts +35 -0
- package/dist-cjs/postgres/rollups.js +168 -0
- package/dist-cjs/postgres/store.d.ts +11 -2
- package/dist-cjs/postgres/store.js +47 -2
- package/dist-cjs/postgres/traces.d.ts +13 -3
- package/dist-cjs/postgres/traces.js +58 -2
- package/dist-cjs/postgres/vectors.d.ts +11 -2
- package/dist-cjs/postgres/vectors.js +47 -2
- package/dist-cjs/router/auto-router.d.ts +34 -7
- package/dist-cjs/router/auto-router.js +201 -68
- package/dist-cjs/server/assistant.d.ts +44 -0
- package/dist-cjs/server/assistant.js +39 -0
- package/dist-cjs/server/errors.d.ts +12 -0
- package/dist-cjs/server/errors.js +9 -1
- package/dist-cjs/server/index.d.ts +1 -1
- package/dist-cjs/server/index.js +2 -1
- package/dist-cjs/server/runs.d.ts +28 -1
- package/dist-cjs/server/runs.js +109 -13
- package/dist-cjs/sqlite/index.d.ts +16 -3
- package/dist-cjs/sqlite/index.js +31 -10
- package/dist-cjs/sqlite/migrations.d.ts +26 -0
- package/dist-cjs/sqlite/migrations.js +71 -0
- package/dist-cjs/sqlite/operations.d.ts +14 -3
- package/dist-cjs/sqlite/operations.js +76 -15
- package/dist-cjs/sqlite/store.d.ts +9 -2
- package/dist-cjs/sqlite/store.js +47 -3
- package/dist-cjs/sqlite/vectors.d.ts +11 -2
- package/dist-cjs/sqlite/vectors.js +47 -2
- package/dist-cjs/store/tenant.d.ts +12 -0
- package/dist-cjs/store/tenant.js +33 -0
- package/dist-cjs/tenancy/index.d.ts +113 -0
- package/dist-cjs/tenancy/index.js +250 -0
- package/dist-cjs/testing/record.d.ts +42 -0
- package/dist-cjs/testing/record.js +57 -5
- package/dist-cjs/tracing/index.d.ts +3 -3
- package/dist-cjs/tracing/index.js +4 -1
- package/dist-cjs/tracing/instrument.js +30 -0
- package/dist-cjs/tracing/otlp.d.ts +91 -0
- package/dist-cjs/tracing/otlp.js +129 -0
- package/dist-cjs/tracing/rollups.d.ts +100 -0
- package/dist-cjs/tracing/rollups.js +147 -0
- package/dist-cjs/tracing/stores.d.ts +17 -0
- package/dist-cjs/tracing/stores.js +24 -0
- package/dist-cjs/tracing/tracer.d.ts +50 -4
- package/dist-cjs/tracing/tracer.js +87 -6
- package/dist-cjs/types/config.d.ts +33 -2
- package/dist-cjs/types/evaluate.d.ts +37 -0
- package/dist-cjs/types/graph.d.ts +354 -9
- package/dist-cjs/types/graph.js +3 -1
- package/dist-cjs/types/messages.d.ts +5 -0
- package/dist-cjs/types/operations.d.ts +22 -2
- package/dist-cjs/types/response.d.ts +20 -0
- package/dist-cjs/types/server.d.ts +18 -0
- package/dist-cjs/types/tracing.d.ts +11 -0
- package/dist-cjs/utils/schema-migrations.d.ts +97 -0
- package/dist-cjs/utils/schema-migrations.js +102 -0
- package/dist-cjs/utils/signals.d.ts +17 -0
- package/dist-cjs/utils/signals.js +29 -0
- package/dist-cjs/utils/tenant.d.ts +14 -0
- package/dist-cjs/utils/tenant.js +22 -0
- package/dist-cjs/version.d.ts +5 -0
- package/dist-cjs/version.js +4 -0
- package/llms.txt +4 -3
- package/package.json +110 -2
package/dist/testing/record.d.ts
CHANGED
|
@@ -32,6 +32,40 @@ export interface RecordedResponse {
|
|
|
32
32
|
body: string;
|
|
33
33
|
/** How `body` is encoded. */
|
|
34
34
|
bodyEncoding: 'utf8' | 'base64';
|
|
35
|
+
/**
|
|
36
|
+
* The body as it arrived, chunk by chunk, with when each came, when recorded with `timing`. A
|
|
37
|
+
* paced replay sends these; an instant one sends `body`, which holds the same bytes.
|
|
38
|
+
*/
|
|
39
|
+
chunks?: RecordedChunk[];
|
|
40
|
+
}
|
|
41
|
+
/** One piece of a streamed response, and when it arrived. */
|
|
42
|
+
export interface RecordedChunk {
|
|
43
|
+
/** Milliseconds after the response started. */
|
|
44
|
+
atMs: number;
|
|
45
|
+
/** The bytes, as text or base64. */
|
|
46
|
+
body: string;
|
|
47
|
+
/** How `body` is encoded. */
|
|
48
|
+
bodyEncoding: 'utf8' | 'base64';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* How a replayed stream is paced, for a recording made with `timing`.
|
|
52
|
+
*
|
|
53
|
+
* - `instant` (the default) sends the whole body at once, as a recording without timing does.
|
|
54
|
+
* - `original` sends each chunk when it arrived, relative to the first.
|
|
55
|
+
* - A number scales the gaps: `0.1` is ten times faster, `2` twice as slow.
|
|
56
|
+
* - A function is awaited before each chunk, so a test can release them one at a time.
|
|
57
|
+
*/
|
|
58
|
+
export type ReplayPace = 'instant' | 'original' | number | ((chunk: ReplayChunkInfo) => Promise<void> | void);
|
|
59
|
+
/** What a pacing function is told about the chunk it releases. */
|
|
60
|
+
export interface ReplayChunkInfo {
|
|
61
|
+
/** Its position, from 0. */
|
|
62
|
+
index: number;
|
|
63
|
+
/** How many chunks the response has. */
|
|
64
|
+
count: number;
|
|
65
|
+
/** When it arrived when recorded, in milliseconds after the response started. */
|
|
66
|
+
atMs: number;
|
|
67
|
+
/** The recorded gap since the chunk before it, in milliseconds. */
|
|
68
|
+
delayMs: number;
|
|
35
69
|
}
|
|
36
70
|
/** One request and the response it got, as written to a fixture file. */
|
|
37
71
|
export interface RecordedExchange {
|
|
@@ -86,6 +120,12 @@ export interface RecordOptions extends FixtureOptions {
|
|
|
86
120
|
redact?: (exchange: RecordedExchange) => RecordedExchange;
|
|
87
121
|
/** Replaces the system clock, for `recordedAt`. */
|
|
88
122
|
now?: () => Date;
|
|
123
|
+
/**
|
|
124
|
+
* Keeps each chunk of a response and when it arrived, so a replay can reproduce a stream's pace
|
|
125
|
+
* as well as its bytes: for testing idle timeouts, cancellation, backpressure, and streaming UIs.
|
|
126
|
+
* Defaults to false.
|
|
127
|
+
*/
|
|
128
|
+
timing?: boolean;
|
|
89
129
|
}
|
|
90
130
|
/** Options for replaying. */
|
|
91
131
|
export interface ReplayOptions extends FixtureOptions {
|
|
@@ -96,6 +136,8 @@ export interface ReplayOptions extends FixtureOptions {
|
|
|
96
136
|
onMissing?: 'throw' | 'live';
|
|
97
137
|
/** The real fetch, for `onMissing: 'live'`. */
|
|
98
138
|
fetch?: typeof globalThis.fetch;
|
|
139
|
+
/** How a stream recorded with `timing` is paced. Defaults to `instant`. */
|
|
140
|
+
pace?: ReplayPace;
|
|
99
141
|
}
|
|
100
142
|
/** A fetch that also lets a test wait for every fixture it has written. */
|
|
101
143
|
export type RecordingFetch = typeof globalThis.fetch & {
|
package/dist/testing/record.js
CHANGED
|
@@ -24,7 +24,10 @@ export function recordingFetch(options) {
|
|
|
24
24
|
const captured = await captureRequest(copyOf(input, init), options);
|
|
25
25
|
const real = options.fetch ?? globalThis.fetch;
|
|
26
26
|
const response = await real(input, init);
|
|
27
|
-
const bytes
|
|
27
|
+
const { bytes, chunks } = options.timing
|
|
28
|
+
? await readTimed(response)
|
|
29
|
+
: { bytes: new Uint8Array(await response.arrayBuffer()), chunks: undefined };
|
|
30
|
+
const contentType = response.headers.get('content-type');
|
|
28
31
|
const index = counters.get(captured.key) ?? 0;
|
|
29
32
|
counters.set(captured.key, index + 1);
|
|
30
33
|
let exchange = {
|
|
@@ -35,7 +38,10 @@ export function recordingFetch(options) {
|
|
|
35
38
|
status: response.status,
|
|
36
39
|
...(response.statusText ? { statusText: response.statusText } : {}),
|
|
37
40
|
headers: withoutTransportHeaders(redactHeaders(response.headers, options.redactHeaders)),
|
|
38
|
-
...encodeBody(bytes,
|
|
41
|
+
...encodeBody(bytes, contentType),
|
|
42
|
+
...(chunks
|
|
43
|
+
? { chunks: chunks.map((chunk) => ({ atMs: chunk.atMs, ...encodeBody(chunk.bytes, contentType) })) }
|
|
44
|
+
: {}),
|
|
39
45
|
},
|
|
40
46
|
recordedAt: now().toISOString(),
|
|
41
47
|
};
|
|
@@ -71,9 +77,13 @@ export function replayFetch(options) {
|
|
|
71
77
|
const position = served.get(captured.key) ?? 0;
|
|
72
78
|
served.set(captured.key, position + 1);
|
|
73
79
|
const exchange = recordings[Math.min(position, recordings.length - 1)];
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
const pace = options.pace ?? 'instant';
|
|
81
|
+
const chunks = exchange.response.chunks;
|
|
82
|
+
const body = pace !== 'instant' && chunks?.length
|
|
83
|
+
? pacedBody(chunks, pace, request.signal)
|
|
84
|
+
: exchange.response.bodyEncoding === 'base64'
|
|
85
|
+
? Buffer.from(exchange.response.body, 'base64')
|
|
86
|
+
: exchange.response.body;
|
|
77
87
|
return new Response(isNullBodyStatus(exchange.response.status) ? null : body, {
|
|
78
88
|
status: exchange.response.status,
|
|
79
89
|
statusText: exchange.response.statusText ?? '',
|
|
@@ -181,6 +191,48 @@ function encodeBody(bytes, contentType) {
|
|
|
181
191
|
}
|
|
182
192
|
return { body: Buffer.from(bytes).toString('base64'), bodyEncoding: 'base64' };
|
|
183
193
|
}
|
|
194
|
+
async function readTimed(response) {
|
|
195
|
+
const chunks = [];
|
|
196
|
+
if (!response.body)
|
|
197
|
+
return { bytes: new Uint8Array(), chunks };
|
|
198
|
+
const started = performance.now();
|
|
199
|
+
const reader = response.body.getReader();
|
|
200
|
+
for (;;) {
|
|
201
|
+
const { value, done } = await reader.read();
|
|
202
|
+
if (done)
|
|
203
|
+
break;
|
|
204
|
+
chunks.push({ atMs: Math.round(performance.now() - started), bytes: value });
|
|
205
|
+
}
|
|
206
|
+
const bytes = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.bytes.length, 0));
|
|
207
|
+
let offset = 0;
|
|
208
|
+
for (const chunk of chunks) {
|
|
209
|
+
bytes.set(chunk.bytes, offset);
|
|
210
|
+
offset += chunk.bytes.length;
|
|
211
|
+
}
|
|
212
|
+
return { bytes, chunks };
|
|
213
|
+
}
|
|
214
|
+
function pacedBody(chunks, pace, signal) {
|
|
215
|
+
let index = 0;
|
|
216
|
+
return new ReadableStream({
|
|
217
|
+
async pull(controller) {
|
|
218
|
+
const chunk = chunks[index];
|
|
219
|
+
if (!chunk || signal.aborted) {
|
|
220
|
+
controller.close();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const delayMs = Math.max(0, chunk.atMs - (index === 0 ? chunk.atMs : chunks[index - 1].atMs));
|
|
224
|
+
if (typeof pace === 'function')
|
|
225
|
+
await pace({ index, count: chunks.length, atMs: chunk.atMs, delayMs });
|
|
226
|
+
else {
|
|
227
|
+
const wait = pace === 'original' ? delayMs : delayMs * pace;
|
|
228
|
+
if (wait > 0)
|
|
229
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
230
|
+
}
|
|
231
|
+
index += 1;
|
|
232
|
+
controller.enqueue(chunk.bodyEncoding === 'base64' ? Buffer.from(chunk.body, 'base64') : new TextEncoder().encode(chunk.body));
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
184
236
|
function isNullBodyStatus(status) {
|
|
185
237
|
return status === 101 || status === 204 || status === 205 || status === 304;
|
|
186
238
|
}
|
package/dist/tracing/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { type AlertEvent, AlertEvaluator, type AlertMetric, type AlertNotifier, type AlertRule, createWebhookNotifier, measure, type WebhookNotifierOptions, } from './alerts.js';
|
|
2
2
|
export { compareTraces, formatTree, type RunDifference, type TraceComparison } from './compare.js';
|
|
3
3
|
export { type GraphTracing, type GraphTracingOptions, type ModelClientLike, traceGraph, traceModelClient, } from './instrument.js';
|
|
4
|
-
export { applyQuery, assembleTree, JsonlTraceStore, type JsonlTraceStoreOptions, MemoryTraceStore, type MemoryTraceStoreOptions, } from './stores.js';
|
|
5
|
-
export { type FinishRunOptions, type RunHandle, type StartRunOptions, stripFields, Tracer, type TracerOptions, } from './tracer.js';
|
|
6
|
-
export type { RedactionPolicy, Run, RunFeedback, RunKind, RunQuery, RunStatus, RunTree, SamplingPolicy, TraceStore, } from '../types/tracing.js';
|
|
4
|
+
export { applyQuery, assembleTree, closeAbandonedRuns, type CloseAbandonedRunsOptions, JsonlTraceStore, type JsonlTraceStoreOptions, MemoryTraceStore, type MemoryTraceStoreOptions, } from './stores.js';
|
|
5
|
+
export { type FinishRunOptions, type RunHandle, type StartRunOptions, stripFields, Tracer, type TracerOptions, w3cSpanId, w3cTraceId, } from './tracer.js';
|
|
6
|
+
export type { RedactionPolicy, Run, RunFeedback, RunKind, RunQuery, RunStatus, RunTree, SamplingPolicy, TraceExporter, TraceStore, } from '../types/tracing.js';
|
package/dist/tracing/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AlertEvaluator, createWebhookNotifier, measure, } from './alerts.js';
|
|
2
2
|
export { compareTraces, formatTree } from './compare.js';
|
|
3
3
|
export { traceGraph, traceModelClient, } from './instrument.js';
|
|
4
|
-
export { applyQuery, assembleTree, JsonlTraceStore, MemoryTraceStore, } from './stores.js';
|
|
5
|
-
export { stripFields, Tracer, } from './tracer.js';
|
|
4
|
+
export { applyQuery, assembleTree, closeAbandonedRuns, JsonlTraceStore, MemoryTraceStore, } from './stores.js';
|
|
5
|
+
export { stripFields, Tracer, w3cSpanId, w3cTraceId, } from './tracer.js';
|
|
@@ -9,6 +9,7 @@ export function traceGraph(tracer, options = {}) {
|
|
|
9
9
|
const active = new Map();
|
|
10
10
|
const retries = new Map();
|
|
11
11
|
const emitted = new Map();
|
|
12
|
+
const tools = new Map();
|
|
12
13
|
const onEvent = (event) => {
|
|
13
14
|
switch (event.type) {
|
|
14
15
|
case 'task_start': {
|
|
@@ -25,6 +26,29 @@ export function traceGraph(tracer, options = {}) {
|
|
|
25
26
|
retries.set(event.taskId, event.attempt);
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
29
|
+
case 'tool': {
|
|
30
|
+
const key = `${event.taskId}:${event.tool.id}`;
|
|
31
|
+
if (event.tool.phase === 'start') {
|
|
32
|
+
const parent = active.get(event.taskId) ?? root;
|
|
33
|
+
tools.set(key, parent.child({
|
|
34
|
+
name: event.tool.name,
|
|
35
|
+
kind: 'tool',
|
|
36
|
+
inputs: event.tool.args,
|
|
37
|
+
metadata: { callId: event.tool.id },
|
|
38
|
+
}));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (event.tool.phase === 'progress')
|
|
42
|
+
return;
|
|
43
|
+
const handle = tools.get(key);
|
|
44
|
+
if (!handle)
|
|
45
|
+
return;
|
|
46
|
+
tools.delete(key);
|
|
47
|
+
void handle.finish(event.tool.phase === 'error'
|
|
48
|
+
? { error: new Error(event.tool.error ?? 'The tool failed') }
|
|
49
|
+
: { outputs: event.tool.result });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
28
52
|
case 'custom': {
|
|
29
53
|
emitted.set(event.taskId, [...(emitted.get(event.taskId) ?? []), event.data]);
|
|
30
54
|
return;
|
|
@@ -53,6 +77,10 @@ export function traceGraph(tracer, options = {}) {
|
|
|
53
77
|
root,
|
|
54
78
|
runFor: (node) => [...active.values()].find((handle) => handle.id && nameOf(active, handle) === node),
|
|
55
79
|
async finish(result) {
|
|
80
|
+
for (const [key, handle] of tools) {
|
|
81
|
+
tools.delete(key);
|
|
82
|
+
await handle.finish({ metadata: { unfinished: true } });
|
|
83
|
+
}
|
|
56
84
|
for (const [taskId, handle] of active) {
|
|
57
85
|
active.delete(taskId);
|
|
58
86
|
await handle.finish({ metadata: { unfinished: true } });
|
|
@@ -112,6 +140,8 @@ export function traceModelClient(client, tracer, options = {}) {
|
|
|
112
140
|
model: response.meta?.modelUsed,
|
|
113
141
|
finishReason: response.finishReason,
|
|
114
142
|
...(request.metadata?.prompt === undefined ? {} : { prompt: request.metadata.prompt }),
|
|
143
|
+
...(response.meta?.cache ? { cache: response.meta.cache } : {}),
|
|
144
|
+
...(request.tenantId ? { tenantId: request.tenantId } : {}),
|
|
115
145
|
},
|
|
116
146
|
});
|
|
117
147
|
return response;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Run, TraceExporter } from '../types/tracing.js';
|
|
2
|
+
/** Options for `OtlpTraceExporter`. */
|
|
3
|
+
export interface OtlpTraceExporterOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The collector's OTLP/HTTP base URL, such as `http://localhost:4318`. Spans are posted to
|
|
6
|
+
* `/v1/traces` under it, as JSON.
|
|
7
|
+
*/
|
|
8
|
+
endpoint: string;
|
|
9
|
+
/** Headers on every request, such as an API key a hosted backend wants. */
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
/** `service.name` on every span. Defaults to `nexus-ai-pro`. */
|
|
12
|
+
serviceName?: string;
|
|
13
|
+
/** More resource attributes, such as `deployment.environment.name` or `service.version`. */
|
|
14
|
+
resource?: Record<string, string | number | boolean>;
|
|
15
|
+
/** Spans sent per request. Defaults to 100. */
|
|
16
|
+
maxBatch?: number;
|
|
17
|
+
/** How long a span waits for others to batch with, in milliseconds. Defaults to 2,000. */
|
|
18
|
+
flushIntervalMs?: number;
|
|
19
|
+
/** Replaces the global `fetch`, for tests or a proxy. */
|
|
20
|
+
fetch?: typeof globalThis.fetch;
|
|
21
|
+
/** Called when a batch cannot be sent. The batch is dropped; a trace is never worth a retry storm. */
|
|
22
|
+
onError?: (error: unknown) => void;
|
|
23
|
+
}
|
|
24
|
+
type AttributeValue = {
|
|
25
|
+
stringValue: string;
|
|
26
|
+
} | {
|
|
27
|
+
intValue: string;
|
|
28
|
+
} | {
|
|
29
|
+
doubleValue: number;
|
|
30
|
+
} | {
|
|
31
|
+
boolValue: boolean;
|
|
32
|
+
};
|
|
33
|
+
/** One span in OTLP's JSON encoding. */
|
|
34
|
+
export interface OtlpSpan {
|
|
35
|
+
/** 32 hex digits. */
|
|
36
|
+
traceId: string;
|
|
37
|
+
/** 16 hex digits. */
|
|
38
|
+
spanId: string;
|
|
39
|
+
/** 16 hex digits, absent for a root span. */
|
|
40
|
+
parentSpanId?: string;
|
|
41
|
+
/** The span's name. */
|
|
42
|
+
name: string;
|
|
43
|
+
/** 1 internal, 3 client. */
|
|
44
|
+
kind: number;
|
|
45
|
+
/** Nanoseconds since the epoch, as a decimal string. */
|
|
46
|
+
startTimeUnixNano: string;
|
|
47
|
+
/** Nanoseconds since the epoch, as a decimal string. */
|
|
48
|
+
endTimeUnixNano: string;
|
|
49
|
+
/** Typed attributes. */
|
|
50
|
+
attributes: Array<{
|
|
51
|
+
key: string;
|
|
52
|
+
value: AttributeValue;
|
|
53
|
+
}>;
|
|
54
|
+
/** 1 ok, 2 error. */
|
|
55
|
+
status: {
|
|
56
|
+
code: number;
|
|
57
|
+
message?: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Turns one finished run into an OpenTelemetry span, with the GenAI semantic conventions.
|
|
62
|
+
*
|
|
63
|
+
* A model run is a client span named `chat <model>` with `gen_ai.operation.name`,
|
|
64
|
+
* `gen_ai.provider.name`, `gen_ai.request.model`, `gen_ai.response.model`, and
|
|
65
|
+
* `gen_ai.usage.input_tokens` and `output_tokens`. A tool run carries `gen_ai.tool.name`, an agent
|
|
66
|
+
* run `gen_ai.agent.name`. What only Nexus knows goes under `nexus.*`: the run kind, a graph node and
|
|
67
|
+
* its step, the cost, and the run id. A failed run has `error.type` and an error status.
|
|
68
|
+
*/
|
|
69
|
+
export declare function runToOtlpSpan(run: Run): OtlpSpan;
|
|
70
|
+
/**
|
|
71
|
+
* Sends finished runs to any OpenTelemetry collector as OTLP/HTTP JSON, with no SDK to install.
|
|
72
|
+
*
|
|
73
|
+
* Pass it to a tracer's `exporters`, and every run the tracer keeps arrives as a span with the GenAI
|
|
74
|
+
* semantic conventions, so Grafana Tempo, Jaeger, Honeycomb, Datadog, New Relic, or any OTLP backend
|
|
75
|
+
* reads it as it reads the rest of the application. Spans are batched; `flush()` sends what is
|
|
76
|
+
* waiting. Trace ids are the W3C ids `RunHandle.traceparent()` propagates, so a trace that crossed
|
|
77
|
+
* processes arrives as one.
|
|
78
|
+
*/
|
|
79
|
+
export declare class OtlpTraceExporter implements TraceExporter {
|
|
80
|
+
private readonly options;
|
|
81
|
+
private readonly queue;
|
|
82
|
+
private timer;
|
|
83
|
+
private sending;
|
|
84
|
+
constructor(options: OtlpTraceExporterOptions);
|
|
85
|
+
/** Queues a run, sending a batch when one is full. Runs still in progress are skipped. */
|
|
86
|
+
export(run: Run): void;
|
|
87
|
+
/** Sends every span waiting. */
|
|
88
|
+
flush(): Promise<void>;
|
|
89
|
+
private send;
|
|
90
|
+
}
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { w3cSpanId, w3cTraceId } from './tracer.js';
|
|
2
|
+
const OPERATIONS = {
|
|
3
|
+
model: 'chat',
|
|
4
|
+
embedding: 'embeddings',
|
|
5
|
+
tool: 'execute_tool',
|
|
6
|
+
agent: 'invoke_agent',
|
|
7
|
+
};
|
|
8
|
+
export function runToOtlpSpan(run) {
|
|
9
|
+
const attributes = { 'nexus.run.kind': run.kind, 'nexus.run.id': run.id };
|
|
10
|
+
const operation = OPERATIONS[run.kind];
|
|
11
|
+
if (operation)
|
|
12
|
+
attributes['gen_ai.operation.name'] = operation;
|
|
13
|
+
if (run.provider)
|
|
14
|
+
attributes['gen_ai.provider.name'] = run.provider;
|
|
15
|
+
if (run.kind === 'model' || run.kind === 'embedding') {
|
|
16
|
+
const requested = run.metadata?.requestedModel;
|
|
17
|
+
if (typeof requested === 'string')
|
|
18
|
+
attributes['gen_ai.request.model'] = requested;
|
|
19
|
+
else if (run.model)
|
|
20
|
+
attributes['gen_ai.request.model'] = run.model;
|
|
21
|
+
if (run.model)
|
|
22
|
+
attributes['gen_ai.response.model'] = run.model;
|
|
23
|
+
const input = run.usage?.inputTokens ?? run.usage?.promptTokens;
|
|
24
|
+
const output = run.usage?.outputTokens ?? run.usage?.completionTokens;
|
|
25
|
+
if (input !== undefined)
|
|
26
|
+
attributes['gen_ai.usage.input_tokens'] = input;
|
|
27
|
+
if (output !== undefined)
|
|
28
|
+
attributes['gen_ai.usage.output_tokens'] = output;
|
|
29
|
+
}
|
|
30
|
+
if (run.kind === 'tool')
|
|
31
|
+
attributes['gen_ai.tool.name'] = run.name;
|
|
32
|
+
if (run.kind === 'agent')
|
|
33
|
+
attributes['gen_ai.agent.name'] = run.name;
|
|
34
|
+
if (run.kind === 'node') {
|
|
35
|
+
attributes['nexus.graph.node'] = run.name;
|
|
36
|
+
if (typeof run.metadata?.step === 'number')
|
|
37
|
+
attributes['nexus.graph.step'] = run.metadata.step;
|
|
38
|
+
}
|
|
39
|
+
if (run.cost !== undefined)
|
|
40
|
+
attributes['nexus.cost.usd'] = run.cost;
|
|
41
|
+
if (run.error)
|
|
42
|
+
attributes['error.type'] = run.error.name;
|
|
43
|
+
for (const tag of run.tags ?? [])
|
|
44
|
+
attributes[`nexus.tag.${tag}`] = true;
|
|
45
|
+
const started = Date.parse(run.startedAt);
|
|
46
|
+
const ended = run.endedAt ? Date.parse(run.endedAt) : started + (run.latencyMs ?? 0);
|
|
47
|
+
const name = run.kind === 'model' && run.model ? `chat ${run.model}` : operation ? `${operation} ${run.name}` : run.name;
|
|
48
|
+
return {
|
|
49
|
+
traceId: w3cTraceId(run.traceId),
|
|
50
|
+
spanId: w3cSpanId(run.id),
|
|
51
|
+
...(run.parentId ? { parentSpanId: w3cSpanId(run.parentId) } : {}),
|
|
52
|
+
name,
|
|
53
|
+
kind: run.kind === 'model' || run.kind === 'embedding' ? 3 : 1,
|
|
54
|
+
startTimeUnixNano: nanos(started),
|
|
55
|
+
endTimeUnixNano: nanos(ended),
|
|
56
|
+
attributes: Object.entries(attributes).map(([key, value]) => ({ key, value: typed(value) })),
|
|
57
|
+
status: run.status === 'error' ? { code: 2, ...(run.error ? { message: run.error.message } : {}) } : { code: 1 },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export class OtlpTraceExporter {
|
|
61
|
+
options;
|
|
62
|
+
queue = [];
|
|
63
|
+
timer;
|
|
64
|
+
sending = Promise.resolve();
|
|
65
|
+
constructor(options) {
|
|
66
|
+
this.options = options;
|
|
67
|
+
}
|
|
68
|
+
export(run) {
|
|
69
|
+
if (run.status === 'running')
|
|
70
|
+
return;
|
|
71
|
+
this.queue.push(runToOtlpSpan(run));
|
|
72
|
+
if (this.queue.length >= (this.options.maxBatch ?? 100)) {
|
|
73
|
+
void this.flush();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!this.timer) {
|
|
77
|
+
this.timer = setTimeout(() => void this.flush(), this.options.flushIntervalMs ?? 2_000);
|
|
78
|
+
this.timer.unref?.();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async flush() {
|
|
82
|
+
if (this.timer)
|
|
83
|
+
clearTimeout(this.timer);
|
|
84
|
+
this.timer = undefined;
|
|
85
|
+
while (this.queue.length > 0) {
|
|
86
|
+
const batch = this.queue.splice(0, this.options.maxBatch ?? 100);
|
|
87
|
+
this.sending = this.sending.then(() => this.send(batch));
|
|
88
|
+
}
|
|
89
|
+
await this.sending;
|
|
90
|
+
}
|
|
91
|
+
async send(spans) {
|
|
92
|
+
const resource = { 'service.name': this.options.serviceName ?? 'nexus-ai-pro', ...this.options.resource };
|
|
93
|
+
const body = {
|
|
94
|
+
resourceSpans: [
|
|
95
|
+
{
|
|
96
|
+
resource: { attributes: Object.entries(resource).map(([key, value]) => ({ key, value: typed(value) })) },
|
|
97
|
+
scopeSpans: [{ scope: { name: 'nexus-ai-pro' }, spans }],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
try {
|
|
102
|
+
const response = await (this.options.fetch ?? globalThis.fetch)(`${this.options.endpoint.replace(/\/+$/, '')}/v1/traces`, {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers: { 'content-type': 'application/json', ...this.options.headers },
|
|
105
|
+
body: JSON.stringify(body),
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok)
|
|
108
|
+
throw new Error(`The collector answered ${response.status}`);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
this.options.onError?.(error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function nanos(milliseconds) {
|
|
116
|
+
return `${BigInt(Math.round(milliseconds)) * 1000000n}`;
|
|
117
|
+
}
|
|
118
|
+
function typed(value) {
|
|
119
|
+
if (typeof value === 'boolean')
|
|
120
|
+
return { boolValue: value };
|
|
121
|
+
if (typeof value === 'number')
|
|
122
|
+
return Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
123
|
+
return { stringValue: value };
|
|
124
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Run, RunKind, TraceStore } from '../types/tracing.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hourly totals of runs, so a dashboard reads a few rows instead of every trace.
|
|
4
|
+
*
|
|
5
|
+
* Traces are the forensic record: everything about one run. A chart of cost or errors over a week
|
|
6
|
+
* needs none of that, only sums, and reading 100,000 traces to draw it is how a dashboard gets slow
|
|
7
|
+
* as the service grows. A rollup keeps one row per hour, kind, model, provider, and tenant, updated
|
|
8
|
+
* as runs finish.
|
|
9
|
+
*/
|
|
10
|
+
/** What one rollup row is counted by. */
|
|
11
|
+
export interface RollupKey {
|
|
12
|
+
/** The hour, as ISO-8601 truncated to the hour: `2026-10-04T13:00:00.000Z`. */
|
|
13
|
+
hour: string;
|
|
14
|
+
/** The run kind. */
|
|
15
|
+
kind: RunKind;
|
|
16
|
+
/** The run's name, for root runs, such as a graph or an assistant. Empty for others. */
|
|
17
|
+
name: string;
|
|
18
|
+
/** The model, or an empty string. */
|
|
19
|
+
model: string;
|
|
20
|
+
/** The provider, or an empty string. */
|
|
21
|
+
provider: string;
|
|
22
|
+
/** `metadata.tenantId`, or an empty string. */
|
|
23
|
+
tenant: string;
|
|
24
|
+
}
|
|
25
|
+
/** The totals of one rollup row. */
|
|
26
|
+
export interface RollupTotals {
|
|
27
|
+
/** Runs counted. */
|
|
28
|
+
runs: number;
|
|
29
|
+
/** Of those, runs that failed. */
|
|
30
|
+
errors: number;
|
|
31
|
+
/** Their cost. */
|
|
32
|
+
cost: number;
|
|
33
|
+
/** Input tokens reported. */
|
|
34
|
+
inputTokens: number;
|
|
35
|
+
/** Output tokens reported. */
|
|
36
|
+
outputTokens: number;
|
|
37
|
+
/** Latency counts per bucket of `ROLLUP_LATENCY_BOUNDS_MS`, for percentiles without the runs. */
|
|
38
|
+
latency: number[];
|
|
39
|
+
}
|
|
40
|
+
/** One rollup row: its key and its totals. */
|
|
41
|
+
export interface RollupRow extends RollupKey, RollupTotals {
|
|
42
|
+
}
|
|
43
|
+
/** Which rows to read. Every field narrows; the hour range is inclusive. */
|
|
44
|
+
export interface RollupQuery {
|
|
45
|
+
/** The first hour, ISO-8601. */
|
|
46
|
+
since?: string;
|
|
47
|
+
/** The last hour, ISO-8601. */
|
|
48
|
+
until?: string;
|
|
49
|
+
/** Rows of these kinds. */
|
|
50
|
+
kind?: RunKind | RunKind[];
|
|
51
|
+
/** Rows of this model. */
|
|
52
|
+
model?: string;
|
|
53
|
+
/** Rows of this provider. */
|
|
54
|
+
provider?: string;
|
|
55
|
+
/** Rows of this tenant. */
|
|
56
|
+
tenant?: string;
|
|
57
|
+
/** Rows of this name. */
|
|
58
|
+
name?: string;
|
|
59
|
+
}
|
|
60
|
+
/** Where rollup rows live. Adding to a row that does not exist creates it. */
|
|
61
|
+
export interface RollupStore {
|
|
62
|
+
/** Adds totals to the row for `key`. */
|
|
63
|
+
add(key: RollupKey, totals: RollupTotals): Promise<void> | void;
|
|
64
|
+
/** Rows matching a query, oldest hour first. */
|
|
65
|
+
query(query?: RollupQuery): Promise<RollupRow[]> | RollupRow[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Upper bounds of the latency buckets, in milliseconds; a last bucket holds everything slower. A
|
|
69
|
+
* percentile read from them is exact to the bucket, which is close enough for a chart.
|
|
70
|
+
*/
|
|
71
|
+
export declare const ROLLUP_LATENCY_BOUNDS_MS: readonly [10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 30000, 60000, 120000, 300000, 600000];
|
|
72
|
+
/** The latency at percentile `p`, 0 to 1, from rollup buckets: the bound of the bucket it falls in. */
|
|
73
|
+
export declare function rollupPercentile(latency: readonly number[], p: number): number | undefined;
|
|
74
|
+
/** Rows summed across their keys: a total over a day, a model, or a whole range. */
|
|
75
|
+
export declare function sumRollups(rows: readonly RollupTotals[]): RollupTotals;
|
|
76
|
+
/** Rollup rows in process memory. Rows are small, so a year of hourly rows for a few models fits easily. */
|
|
77
|
+
export declare class MemoryRollupStore implements RollupStore {
|
|
78
|
+
private readonly rows;
|
|
79
|
+
/** Adds totals to a row. */
|
|
80
|
+
add(key: RollupKey, totals: RollupTotals): void;
|
|
81
|
+
/** Rows matching a query, oldest hour first. */
|
|
82
|
+
query(query?: RollupQuery): RollupRow[];
|
|
83
|
+
/** Rows held. */
|
|
84
|
+
size(): number;
|
|
85
|
+
}
|
|
86
|
+
/** Options for `rollupTraceStore()`. */
|
|
87
|
+
export interface RollupTraceStoreOptions {
|
|
88
|
+
/** Which finished runs are counted. Defaults to every root run, and every model and embedding run. */
|
|
89
|
+
include?: (run: Run) => boolean;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Wraps a trace store so every run that finishes is also added to a rollup.
|
|
93
|
+
*
|
|
94
|
+
* Reads go to the wrapped store unchanged. A run is counted once, when it is saved finished; a save
|
|
95
|
+
* of a run still running, which an `incremental` tracer makes, is not counted, and neither is
|
|
96
|
+
* feedback added later.
|
|
97
|
+
*/
|
|
98
|
+
export declare function rollupTraceStore(store: TraceStore, rollups: RollupStore, options?: RollupTraceStoreOptions): TraceStore;
|
|
99
|
+
/** The rollup row a finished run belongs to. */
|
|
100
|
+
export declare function rollupKeyOf(run: Run): RollupKey;
|