@airprompter/agent-telemetry 0.1.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/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # @airprompter/agent-telemetry
2
+
3
+ The content-free telemetry spool and its uploader: minute windows per
4
+ `(tag, versionId, arm, model, status, errorClass)` written as append-only
5
+ NDJSON segments (`DirectorySink`: 0600, `.open` until fsync + rename, crash
6
+ recovery) or held in memory on a serverless host (`MemorySink`), the host
7
+ budget, and `SpoolUploader` — direct to your prefix in object storage under
8
+ a short-lived grant, with quarantine and the last-upload marker. The row
9
+ shape (`@airprompter/agent-core`) has no field for prompt text, output or
10
+ an end-user identifier. Install it alone when your own instrumentation
11
+ writes the spool.
12
+
13
+ ```ts
14
+ import { SpoolWriter, DirectorySink } from "@airprompter/agent-telemetry";
15
+
16
+ const writer = new SpoolWriter(new DirectorySink(spoolDir, instanceId), { instanceId, instanceClass: "resident", sdk: "my-app/1.0" });
17
+ writer.observe({ tag, versionId, arm, model, status: "ok", latencyMs, tokens: { input, output } }, Date.now());
18
+ ```
19
+
20
+ `SpoolUploader` ships to an `UploadSink`: AirPrompter's by default, or one
21
+ you pass (`sink:`) — `@airprompter/otel-bridge` sends the windows to your
22
+ OpenTelemetry collector with no grant and no key.
23
+
24
+ This package never imports the sync or the runtime package.
25
+
26
+ One of five packages released in lockstep — `@airprompter/agent-core`, `-sync`,
27
+ `-runtime`, `-telemetry` and the facade `@airprompter/agent-sdk` — one
28
+ version, exact-pinned siblings. The direction is core → clients → sdk and is
29
+ linted. The full README, the module map and the compatibility table are in
30
+ [`sdk-typescript/README.md`](https://github.com/airprompter/airprompter-agent-sdk/tree/main/sdk-typescript);
31
+ the protocol is in [`protocol/`](https://github.com/airprompter/airprompter-agent-sdk/tree/main/protocol).
32
+ BSD-3-Clause.
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * `@airprompter/agent-telemetry` — the content-free spool and its uploader:
4
+ * minute windows written as append-only segments (or held in memory on a
5
+ * serverless host), the host budget, and the direct-to-object-store upload
6
+ * under a grant. Builds on the row schemas in `@airprompter/agent-core`
7
+ * and never imports the sync or the runtime package (S10): a customer's
8
+ * own instrumentation can write the spool with this package alone.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.OPEN_SEGMENT_NAME = exports.SEGMENT_NAME = exports.OPEN_SEGMENT_RECLAIM_MS = exports.EXPORTED_CAP_BYTES = exports.QUARANTINE_RETENTION_MS = exports.QUARANTINE_CAP_BYTES = exports.LAST_UPLOAD_MARKER = exports.GRANT_REFRESH_MARGIN_MS = exports.UPLOAD_BACKOFF_CAP_MS = exports.UPLOAD_BACKOFF_BASE_MS = exports.backoffDelayMs = exports.multipartBody = exports.postSegment = exports.inspectSegment = exports.validateSpoolRow = exports.airprompterUploadSink = exports.SpoolUploader = exports.epochMinute = exports.minuteOf = exports.latencyBucketIndex = exports.LATENCY_BUCKET_EDGES_MS = exports.SERVERLESS_BUFFER_BYTES = exports.HOST_SPOOL_BUDGET_BYTES = exports.SEGMENT_MAX_BYTES = exports.segmentName = exports.SegmentPlanner = exports.MemorySink = exports.DirectorySink = exports.SpoolWriter = void 0;
12
+ var writer_js_1 = require("./spool/writer.js");
13
+ Object.defineProperty(exports, "SpoolWriter", { enumerable: true, get: function () { return writer_js_1.SpoolWriter; } });
14
+ Object.defineProperty(exports, "DirectorySink", { enumerable: true, get: function () { return writer_js_1.DirectorySink; } });
15
+ Object.defineProperty(exports, "MemorySink", { enumerable: true, get: function () { return writer_js_1.MemorySink; } });
16
+ Object.defineProperty(exports, "SegmentPlanner", { enumerable: true, get: function () { return writer_js_1.SegmentPlanner; } });
17
+ Object.defineProperty(exports, "segmentName", { enumerable: true, get: function () { return writer_js_1.segmentName; } });
18
+ Object.defineProperty(exports, "SEGMENT_MAX_BYTES", { enumerable: true, get: function () { return writer_js_1.SEGMENT_MAX_BYTES; } });
19
+ Object.defineProperty(exports, "HOST_SPOOL_BUDGET_BYTES", { enumerable: true, get: function () { return writer_js_1.HOST_SPOOL_BUDGET_BYTES; } });
20
+ Object.defineProperty(exports, "SERVERLESS_BUFFER_BYTES", { enumerable: true, get: function () { return writer_js_1.SERVERLESS_BUFFER_BYTES; } });
21
+ var agent_core_1 = require("@airprompter/agent-core");
22
+ Object.defineProperty(exports, "LATENCY_BUCKET_EDGES_MS", { enumerable: true, get: function () { return agent_core_1.LATENCY_BUCKET_EDGES_MS; } });
23
+ Object.defineProperty(exports, "latencyBucketIndex", { enumerable: true, get: function () { return agent_core_1.latencyBucketIndex; } });
24
+ Object.defineProperty(exports, "minuteOf", { enumerable: true, get: function () { return agent_core_1.minuteOf; } });
25
+ Object.defineProperty(exports, "epochMinute", { enumerable: true, get: function () { return agent_core_1.epochMinute; } });
26
+ var uploader_js_1 = require("./uploader.js");
27
+ Object.defineProperty(exports, "SpoolUploader", { enumerable: true, get: function () { return uploader_js_1.SpoolUploader; } });
28
+ Object.defineProperty(exports, "airprompterUploadSink", { enumerable: true, get: function () { return uploader_js_1.airprompterUploadSink; } });
29
+ Object.defineProperty(exports, "validateSpoolRow", { enumerable: true, get: function () { return uploader_js_1.validateSpoolRow; } });
30
+ Object.defineProperty(exports, "inspectSegment", { enumerable: true, get: function () { return uploader_js_1.inspectSegment; } });
31
+ Object.defineProperty(exports, "postSegment", { enumerable: true, get: function () { return uploader_js_1.postSegment; } });
32
+ Object.defineProperty(exports, "multipartBody", { enumerable: true, get: function () { return uploader_js_1.multipartBody; } });
33
+ Object.defineProperty(exports, "backoffDelayMs", { enumerable: true, get: function () { return uploader_js_1.backoffDelayMs; } });
34
+ Object.defineProperty(exports, "UPLOAD_BACKOFF_BASE_MS", { enumerable: true, get: function () { return uploader_js_1.UPLOAD_BACKOFF_BASE_MS; } });
35
+ Object.defineProperty(exports, "UPLOAD_BACKOFF_CAP_MS", { enumerable: true, get: function () { return uploader_js_1.UPLOAD_BACKOFF_CAP_MS; } });
36
+ Object.defineProperty(exports, "GRANT_REFRESH_MARGIN_MS", { enumerable: true, get: function () { return uploader_js_1.GRANT_REFRESH_MARGIN_MS; } });
37
+ Object.defineProperty(exports, "LAST_UPLOAD_MARKER", { enumerable: true, get: function () { return uploader_js_1.LAST_UPLOAD_MARKER; } });
38
+ Object.defineProperty(exports, "QUARANTINE_CAP_BYTES", { enumerable: true, get: function () { return uploader_js_1.QUARANTINE_CAP_BYTES; } });
39
+ Object.defineProperty(exports, "QUARANTINE_RETENTION_MS", { enumerable: true, get: function () { return uploader_js_1.QUARANTINE_RETENTION_MS; } });
40
+ Object.defineProperty(exports, "EXPORTED_CAP_BYTES", { enumerable: true, get: function () { return uploader_js_1.EXPORTED_CAP_BYTES; } });
41
+ Object.defineProperty(exports, "OPEN_SEGMENT_RECLAIM_MS", { enumerable: true, get: function () { return uploader_js_1.OPEN_SEGMENT_RECLAIM_MS; } });
42
+ Object.defineProperty(exports, "SEGMENT_NAME", { enumerable: true, get: function () { return uploader_js_1.SEGMENT_NAME; } });
43
+ Object.defineProperty(exports, "OPEN_SEGMENT_NAME", { enumerable: true, get: function () { return uploader_js_1.OPEN_SEGMENT_NAME; } });
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,+CAA6K;AAApK,wGAAA,WAAW,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,uGAAA,UAAU,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,wGAAA,WAAW,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,oHAAA,uBAAuB,OAAA;AAAE,oHAAA,uBAAuB,OAAA;AAEjJ,sDAA6G;AAApG,qHAAA,uBAAuB,OAAA;AAAE,gHAAA,kBAAkB,OAAA;AAAE,sGAAA,QAAQ,OAAA;AAAE,yGAAA,WAAW,OAAA;AAI3E,6CAA4W;AAAnW,4GAAA,aAAa,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,0GAAA,WAAW,OAAA;AAAE,4GAAA,aAAa,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,qHAAA,sBAAsB,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AAAE,sHAAA,uBAAuB,OAAA;AAAE,iHAAA,kBAAkB,OAAA;AAAE,mHAAA,oBAAoB,OAAA;AAAE,sHAAA,uBAAuB,OAAA;AAAE,iHAAA,kBAAkB,OAAA;AAAE,sHAAA,uBAAuB,OAAA;AAAE,2GAAA,YAAY,OAAA;AAAE,gHAAA,iBAAiB,OAAA"}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,387 @@
1
+ "use strict";
2
+ /**
3
+ * The spool writer (`protocol/spool-format.md`, D52/D66).
4
+ *
5
+ * Minute windows accumulate in memory per dimension set
6
+ * `(tag, versionId, arm, model, status, errorClass)` and are written as
7
+ * `window` rows when the minute closes. Segments are append-only NDJSON
8
+ * under `<store>/spool/telemetry/`, open as `seg-<inst>-<epochMinute>-<n>.ndjson.open`,
9
+ * closed by fsync + rename; rotated at the minute boundary or 1 MiB. Nothing
10
+ * here can carry prompt text, output, or an end-user identifier — the row
11
+ * shape has no field for them. Serverless hosts use the memory sink and
12
+ * flush at invocation end.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SpoolWriter = exports.DirectorySink = exports.MemorySink = exports.SegmentPlanner = exports.SERVERLESS_BUFFER_BYTES = exports.HOST_SPOOL_BUDGET_BYTES = exports.SEGMENT_MAX_BYTES = exports.epochMinute = exports.minuteOf = exports.latencyBucketIndex = exports.LATENCY_BUCKET_EDGES_MS = void 0;
16
+ exports.segmentName = segmentName;
17
+ const node_path_1 = require("node:path");
18
+ const agent_core_1 = require("@airprompter/agent-core");
19
+ var agent_core_2 = require("@airprompter/agent-core");
20
+ Object.defineProperty(exports, "LATENCY_BUCKET_EDGES_MS", { enumerable: true, get: function () { return agent_core_2.LATENCY_BUCKET_EDGES_MS; } });
21
+ Object.defineProperty(exports, "latencyBucketIndex", { enumerable: true, get: function () { return agent_core_2.latencyBucketIndex; } });
22
+ Object.defineProperty(exports, "minuteOf", { enumerable: true, get: function () { return agent_core_2.minuteOf; } });
23
+ Object.defineProperty(exports, "epochMinute", { enumerable: true, get: function () { return agent_core_2.epochMinute; } });
24
+ exports.SEGMENT_MAX_BYTES = 1024 * 1024;
25
+ /** A host keeps this much closed, unsent spool before the oldest segments are evicted (spool-format.md). */
26
+ exports.HOST_SPOOL_BUDGET_BYTES = 100 * 1024 * 1024;
27
+ /** A serverless invocation keeps this much in memory; beyond it the oldest rows go and a `dropped` row says so. */
28
+ exports.SERVERLESS_BUFFER_BYTES = 256 * 1024;
29
+ function segmentName(instanceId, minute, n) {
30
+ return `seg-${instanceId}-${minute}-${n}.ndjson`;
31
+ }
32
+ /** Which segment an appended line lands in: a new one on a new minute, or when the line would push past 1 MiB. Pure; `protocol/vectors/spool.json` pins it. */
33
+ class SegmentPlanner {
34
+ instanceId;
35
+ openMinute = null;
36
+ openBytes = 0;
37
+ n = 0;
38
+ constructor(instanceId) {
39
+ this.instanceId = instanceId;
40
+ }
41
+ append(epochMs, lineBytes) {
42
+ const minute = (0, agent_core_1.epochMinute)(epochMs);
43
+ const rotated = this.openMinute === null || minute !== this.openMinute || this.openBytes + lineBytes > exports.SEGMENT_MAX_BYTES;
44
+ if (rotated) {
45
+ this.n = minute === this.openMinute ? this.n + 1 : 0;
46
+ this.openMinute = minute;
47
+ this.openBytes = 0;
48
+ }
49
+ this.openBytes += lineBytes;
50
+ return { segment: segmentName(this.instanceId, this.openMinute, this.n), rotated };
51
+ }
52
+ }
53
+ exports.SegmentPlanner = SegmentPlanner;
54
+ /**
55
+ * The serverless buffer: rows in memory up to `budgetBytes` (256 KiB by
56
+ * default). When a row would push past the budget the OLDEST rows are
57
+ * evicted and counted; the next flush (invocation end) hands back the
58
+ * surviving rows followed by one `dropped` row carrying the count and the
59
+ * bytes lost, so an over-chatty invocation is reported, never silent.
60
+ */
61
+ class MemorySink {
62
+ identity;
63
+ budgetBytes;
64
+ kind = "memory";
65
+ rows = [];
66
+ bytes = 0;
67
+ droppedRows = 0;
68
+ droppedBytes = 0;
69
+ constructor(identity = null, budgetBytes = exports.SERVERLESS_BUFFER_BYTES) {
70
+ this.identity = identity;
71
+ this.budgetBytes = budgetBytes;
72
+ }
73
+ append(row) {
74
+ const size = Buffer.byteLength(JSON.stringify(row), "utf8") + 1;
75
+ this.rows.push(row);
76
+ this.bytes += size;
77
+ while (this.bytes > this.budgetBytes && this.rows.length > 1) {
78
+ const oldest = this.rows.shift();
79
+ const lost = Buffer.byteLength(JSON.stringify(oldest), "utf8") + 1;
80
+ this.bytes -= lost;
81
+ this.droppedRows += 1;
82
+ this.droppedBytes += lost;
83
+ }
84
+ }
85
+ flush(_nowMs) { }
86
+ /** The buffered rows, then a `dropped` row when eviction happened since the last drain. */
87
+ drain(nowMs = Date.now()) {
88
+ const rows = this.rows.splice(0, this.rows.length);
89
+ this.bytes = 0;
90
+ if (this.droppedRows > 0 && this.identity) {
91
+ rows.push({ type: "dropped", v: 1, at: new Date(nowMs).toISOString().replace(/\.\d{3}Z$/, "Z"), instanceId: this.identity.instanceId, segments: this.droppedRows, bytes: this.droppedBytes });
92
+ this.droppedRows = 0;
93
+ this.droppedBytes = 0;
94
+ }
95
+ return rows;
96
+ }
97
+ get dropped() {
98
+ return { rows: this.droppedRows, bytes: this.droppedBytes };
99
+ }
100
+ }
101
+ exports.MemorySink = MemorySink;
102
+ /**
103
+ * Segments on disk, through an `FsPort`. Never throws: the request path calls
104
+ * `append`, and a full disk, an I/O error or a file a sibling process took
105
+ * away are counted, reported as a `dropped` row when writing works again,
106
+ * and surfaced on `faults` — never surfaced to the caller as an exception.
107
+ */
108
+ class DirectorySink {
109
+ dir;
110
+ instanceId;
111
+ budgetBytes;
112
+ kind = "directory";
113
+ fd = null;
114
+ openPath = null;
115
+ planner;
116
+ fs;
117
+ faults = { pendingRows: 0, pendingBytes: 0, byCode: {}, last: null };
118
+ constructor(dir, instanceId, budgetBytes = exports.HOST_SPOOL_BUDGET_BYTES, fs = agent_core_1.nodeFs) {
119
+ this.dir = dir;
120
+ this.instanceId = instanceId;
121
+ this.budgetBytes = budgetBytes;
122
+ this.fs = fs;
123
+ this.planner = new SegmentPlanner(instanceId);
124
+ this.guard("open_spool", () => {
125
+ this.fs.mkdirp((0, node_path_1.join)(dir, "exported"), 0o700);
126
+ this.fs.mkdirp((0, node_path_1.join)(dir, "quarantine"), 0o700);
127
+ });
128
+ this.recoverOpenSegments();
129
+ }
130
+ /** Run a filesystem step; on failure count it by code and return false. The sink never throws. */
131
+ guard(step, run) {
132
+ try {
133
+ run();
134
+ return true;
135
+ }
136
+ catch (error) {
137
+ const code = (0, agent_core_1.fsFailureCode)(error);
138
+ this.faults.byCode[code] = (this.faults.byCode[code] ?? 0) + 1;
139
+ this.faults.last = `${step}: ${code}`;
140
+ return false;
141
+ }
142
+ }
143
+ /** A writer that crashed left `.open` files; the same writer closes them on its next start (a partial last line is the daemon's to skip). */
144
+ recoverOpenSegments() {
145
+ let names = [];
146
+ this.guard("list_spool", () => void (names = this.fs.list(this.dir)));
147
+ for (const name of names) {
148
+ if (name.startsWith(`seg-${this.instanceId}-`) && name.endsWith(".ndjson.open")) {
149
+ const path = (0, node_path_1.join)(this.dir, name);
150
+ this.guard("recover_open_segment", () => {
151
+ const fd = this.fs.open(path, "r+");
152
+ try {
153
+ this.fs.fsync(fd);
154
+ }
155
+ finally {
156
+ this.fs.close(fd);
157
+ }
158
+ this.fs.rename(path, path.slice(0, -".open".length));
159
+ });
160
+ }
161
+ }
162
+ }
163
+ append(row, nowMs) {
164
+ const line = Buffer.from(`${JSON.stringify(row)}\n`, "utf8");
165
+ const plan = this.planner.append(nowMs, line.length);
166
+ if (plan.rotated || this.fd === null) {
167
+ this.flush(nowMs);
168
+ const opened = this.guard("open_segment", () => {
169
+ // A name already on disk (a previous process of the same instance in the same minute) is skipped, never appended to.
170
+ let name = plan.segment;
171
+ while (this.fs.exists((0, node_path_1.join)(this.dir, name)) || this.fs.exists((0, node_path_1.join)(this.dir, `${name}.open`))) {
172
+ this.planner.n += 1;
173
+ name = segmentName(this.instanceId, this.planner.openMinute, this.planner.n);
174
+ }
175
+ const openPath = (0, node_path_1.join)(this.dir, `${name}.open`);
176
+ this.fd = this.fs.open(openPath, "a", 0o600);
177
+ this.openPath = openPath;
178
+ });
179
+ if (!opened) {
180
+ this.fd = null;
181
+ this.openPath = null;
182
+ this.lose(1, line.length);
183
+ return;
184
+ }
185
+ this.reportPendingLoss(nowMs);
186
+ if (this.fd === null) {
187
+ // The loss could not even be said (still no space): this row joins it.
188
+ this.lose(1, line.length);
189
+ return;
190
+ }
191
+ }
192
+ const fd = this.fd;
193
+ if (!this.guard("write_row", () => this.fs.write(fd, line))) {
194
+ // What was written before this row is good; close the segment (a partial last line is the daemon's to skip) and count the row.
195
+ this.closeOpen();
196
+ this.lose(1, line.length);
197
+ }
198
+ }
199
+ /** A row the sink could not keep. Counted now; said in a `dropped` row when a write succeeds again. */
200
+ lose(rows, bytes) {
201
+ this.faults.pendingRows += rows;
202
+ this.faults.pendingBytes += bytes;
203
+ }
204
+ /** Rows lost to failures become one `dropped` row (rows counted as `segments`, as the memory sink does) in the segment just opened. */
205
+ reportPendingLoss(nowMs) {
206
+ if (this.faults.pendingRows === 0 || this.fd === null)
207
+ return;
208
+ const rows = this.faults.pendingRows;
209
+ const bytes = this.faults.pendingBytes;
210
+ const line = Buffer.from(`${JSON.stringify({ type: "dropped", v: 1, at: isoSeconds(nowMs), instanceId: this.instanceId, segments: rows, bytes })}\n`, "utf8");
211
+ const fd = this.fd;
212
+ if (this.guard("write_dropped_row", () => this.fs.write(fd, line))) {
213
+ this.faults.pendingRows = 0;
214
+ this.faults.pendingBytes = 0;
215
+ }
216
+ else {
217
+ this.closeOpen();
218
+ }
219
+ }
220
+ flush(nowMs) {
221
+ if (this.fd === null || !this.openPath)
222
+ return;
223
+ this.closeOpen();
224
+ // Over budget after this close: evict the oldest, then write the loss as its own small closed segment, at once.
225
+ const evicted = this.enforceBudget();
226
+ if (evicted) {
227
+ const at = nowMs ?? Date.now();
228
+ this.append({ type: "dropped", v: 1, at: isoSeconds(at), instanceId: this.instanceId, segments: evicted.segments, bytes: evicted.bytes }, at);
229
+ this.closeOpen();
230
+ }
231
+ }
232
+ closeOpen() {
233
+ if (this.fd === null || !this.openPath)
234
+ return;
235
+ const fd = this.fd;
236
+ const openPath = this.openPath;
237
+ this.fd = null;
238
+ this.openPath = null;
239
+ const synced = this.guard("fsync_segment", () => this.fs.fsync(fd));
240
+ this.guard("close_segment", () => this.fs.close(fd));
241
+ // A segment that did not fsync is not closed: it stays `.open` for the next start to recover (its bytes are on disk or they are not).
242
+ if (synced)
243
+ this.guard("close_segment", () => this.fs.rename(openPath, openPath.slice(0, -".open".length)));
244
+ }
245
+ /** Over the host budget: evict the OLDEST closed, unsent segments and say how much went (spool-format.md). A file a sibling took away is skipped. */
246
+ enforceBudget() {
247
+ const sizes = [];
248
+ let total = 0;
249
+ for (const name of this.closedSegments()) {
250
+ this.guard("stat_segment", () => {
251
+ const size = this.fs.stat((0, node_path_1.join)(this.dir, name)).size;
252
+ sizes.push({ name, size });
253
+ total += size;
254
+ });
255
+ }
256
+ let evicted = 0;
257
+ let evictedBytes = 0;
258
+ for (const { name, size } of sizes) {
259
+ if (total <= this.budgetBytes)
260
+ break;
261
+ // Gone already (the daemon or a sibling evicted it): it no longer counts, and nothing was lost here.
262
+ const removed = this.guard("evict_segment", () => this.fs.unlink((0, node_path_1.join)(this.dir, name)));
263
+ total -= size;
264
+ if (!removed)
265
+ continue;
266
+ evicted += 1;
267
+ evictedBytes += size;
268
+ }
269
+ return evicted > 0 ? { segments: evicted, bytes: evictedBytes } : null;
270
+ }
271
+ closedSegments() {
272
+ let names = [];
273
+ this.guard("list_spool", () => void (names = this.fs.list(this.dir)));
274
+ return names.filter((name) => name.startsWith("seg-") && name.endsWith(".ndjson")).sort();
275
+ }
276
+ depth() {
277
+ const segments = this.closedSegments();
278
+ let bytes = 0;
279
+ for (const name of segments)
280
+ this.guard("stat_segment", () => void (bytes += this.fs.stat((0, node_path_1.join)(this.dir, name)).size));
281
+ return { segments: segments.length, bytes };
282
+ }
283
+ }
284
+ exports.DirectorySink = DirectorySink;
285
+ /** ISO-8601 to the second, the spool's timestamp form. */
286
+ function isoSeconds(ms) {
287
+ return new Date(ms).toISOString().replace(/\.\d{3}Z$/, "Z");
288
+ }
289
+ /** Accumulates observations into minute windows and hands closed windows to the sink. */
290
+ class SpoolWriter {
291
+ sink;
292
+ identity;
293
+ open = new Map();
294
+ openMinute = null;
295
+ constructor(sink, identity) {
296
+ this.sink = sink;
297
+ this.identity = identity;
298
+ }
299
+ window(dimensions, nowMs) {
300
+ const minute = (0, agent_core_1.minuteOf)(nowMs);
301
+ if (this.openMinute !== null && this.openMinute !== minute)
302
+ this.closeWindows(nowMs);
303
+ this.openMinute = minute;
304
+ const errorClass = dimensions.errorClass ?? null;
305
+ const key = [dimensions.tag, dimensions.versionId, dimensions.arm, dimensions.model, dimensions.status, errorClass ?? ""].join("\u0000");
306
+ let row = this.open.get(key);
307
+ if (!row) {
308
+ row = {
309
+ type: "window",
310
+ v: 1,
311
+ minute,
312
+ instanceId: this.identity.instanceId,
313
+ instanceClass: this.identity.instanceClass,
314
+ tag: dimensions.tag,
315
+ versionId: dimensions.versionId,
316
+ arm: dimensions.arm,
317
+ model: dimensions.model,
318
+ status: dimensions.status,
319
+ errorClass,
320
+ usageSource: dimensions.usageSource ?? "reported",
321
+ count: 0,
322
+ latencyMs: { buckets: new Array(agent_core_1.LATENCY_BUCKET_EDGES_MS.length).fill(0), sum: 0 },
323
+ tokens: { input: 0, output: 0 },
324
+ sdk: this.identity.sdk,
325
+ };
326
+ this.open.set(key, row);
327
+ }
328
+ return row;
329
+ }
330
+ observe(observation, nowMs) {
331
+ const row = this.window(observation, nowMs);
332
+ row.count += 1;
333
+ const bucket = (0, agent_core_1.latencyBucketIndex)(observation.latencyMs);
334
+ row.latencyMs.buckets[bucket] = (row.latencyMs.buckets[bucket] ?? 0) + 1;
335
+ row.latencyMs.sum += Math.max(0, Math.round(observation.latencyMs));
336
+ row.tokens.input += observation.tokens?.input ?? 0;
337
+ row.tokens.output += observation.tokens?.output ?? 0;
338
+ if (observation.tokens?.cachedInput)
339
+ row.tokens.cachedInput = (row.tokens.cachedInput ?? 0) + observation.tokens.cachedInput;
340
+ if (observation.checks) {
341
+ row.checks = { passed: (row.checks?.passed ?? 0) + (observation.checks.passed ?? 0), failed: (row.checks?.failed ?? 0) + (observation.checks.failed ?? 0) };
342
+ }
343
+ if (observation.outcomes)
344
+ mergeOutcomes(row, observation.outcomes);
345
+ }
346
+ /** T29: output-check counts against a run already counted (an app that evaluated after the fact): the run's window, no extra count. */
347
+ checks(dimensions, counts, nowMs) {
348
+ const row = this.window({ ...dimensions, status: "ok" }, nowMs);
349
+ row.checks = { passed: (row.checks?.passed ?? 0) + counts.passed, failed: (row.checks?.failed ?? 0) + counts.failed };
350
+ }
351
+ /** Quality signals against a run already counted: they ride on the run's window (status ok) and never add to `count`. */
352
+ outcomes(dimensions, outcomes, nowMs) {
353
+ mergeOutcomes(this.window({ ...dimensions, status: "ok" }, nowMs), outcomes);
354
+ }
355
+ refusal(row, nowMs) {
356
+ this.sink.append({ type: "refusal", v: 1, instanceId: this.identity.instanceId, ...row }, nowMs);
357
+ }
358
+ /** Write every open window and close the segment. Called at the minute boundary, at shutdown, and at invocation end on serverless. */
359
+ closeWindows(nowMs) {
360
+ for (const row of this.open.values())
361
+ this.sink.append(row, nowMs);
362
+ this.open.clear();
363
+ this.openMinute = null;
364
+ this.sink.flush(nowMs);
365
+ }
366
+ /** S6: close the windows of a minute that has passed (and the segment with them) without touching the current minute — the runtime's spool timer calls this, so an idle writer never leaves the last minute of a burst parked in an `.open` file. */
367
+ closeStaleWindows(nowMs) {
368
+ if (this.openMinute !== null && this.openMinute !== (0, agent_core_1.minuteOf)(nowMs))
369
+ this.closeWindows(nowMs);
370
+ }
371
+ get openWindowCount() {
372
+ return this.open.size;
373
+ }
374
+ }
375
+ exports.SpoolWriter = SpoolWriter;
376
+ function mergeOutcomes(row, outcomes) {
377
+ row.outcomes ??= {};
378
+ for (const [name, value] of Object.entries(outcomes)) {
379
+ if (!/^[a-z][a-zA-Z0-9]{0,31}$/.test(name))
380
+ continue;
381
+ if (typeof value === "number" && !Number.isFinite(value))
382
+ continue;
383
+ const current = row.outcomes[name] ?? { n: 0, sum: 0 };
384
+ row.outcomes[name] = { n: current.n + 1, sum: current.sum + (typeof value === "boolean" ? (value ? 1 : 0) : value) };
385
+ }
386
+ }
387
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/spool/writer.ts"],"names":[],"mappings":"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"}