agent-inspect 1.5.0 → 1.6.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 +35 -0
- package/README.md +12 -4
- package/docs/API.md +124 -9
- package/docs/ARCHITECTURE.md +4 -0
- package/docs/CLI.md +41 -12
- package/docs/KNOWN-ISSUES.md +8 -1
- package/docs/LIMITATIONS.md +11 -2
- package/docs/SCHEMA.md +16 -6
- package/package.json +21 -1
- package/packages/cli/dist/index.cjs +2449 -157
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +2450 -158
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +839 -18
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +98 -3
- package/packages/core/dist/advanced.d.ts +98 -3
- package/packages/core/dist/advanced.mjs +7 -4
- package/packages/core/dist/chunk-57S5D6HR.mjs +655 -0
- package/packages/core/dist/chunk-57S5D6HR.mjs.map +1 -0
- package/packages/core/dist/chunk-6QSLZCBJ.mjs +743 -0
- package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +1 -0
- package/packages/core/dist/chunk-6SZPTECC.mjs +342 -0
- package/packages/core/dist/chunk-6SZPTECC.mjs.map +1 -0
- package/packages/core/dist/{chunk-QX3ZMPUF.mjs → chunk-74XZ6N7Q.mjs} +13 -55
- package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +1 -0
- package/packages/core/dist/{chunk-QPAU2TPA.mjs → chunk-HR7G62IE.mjs} +4 -4
- package/packages/core/dist/{chunk-QPAU2TPA.mjs.map → chunk-HR7G62IE.mjs.map} +1 -1
- package/packages/core/dist/chunk-S4YWKV4G.mjs +48 -0
- package/packages/core/dist/chunk-S4YWKV4G.mjs.map +1 -0
- package/packages/core/dist/chunk-TFLPUZ56.mjs +1571 -0
- package/packages/core/dist/chunk-TFLPUZ56.mjs.map +1 -0
- package/packages/core/dist/{chunk-Q6EPNB3V.mjs → chunk-TZISEVLQ.mjs} +34 -183
- package/packages/core/dist/chunk-TZISEVLQ.mjs.map +1 -0
- package/packages/core/dist/chunk-U2BGPESY.mjs +150 -0
- package/packages/core/dist/chunk-U2BGPESY.mjs.map +1 -0
- package/packages/core/dist/chunk-VTIB5MDK.mjs +304 -0
- package/packages/core/dist/chunk-VTIB5MDK.mjs.map +1 -0
- package/packages/core/dist/{chunk-5EMIZZXD.mjs → chunk-Y56BPA3B.mjs} +87 -4
- package/packages/core/dist/chunk-Y56BPA3B.mjs.map +1 -0
- package/packages/core/dist/diff.d.cts +3 -2
- package/packages/core/dist/diff.d.ts +3 -2
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.d.cts +3 -2
- package/packages/core/dist/exporters.d.ts +3 -2
- package/packages/core/dist/exporters.mjs +2 -2
- package/packages/core/dist/index.cjs +2975 -229
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +27 -6
- package/packages/core/dist/index.d.ts +27 -6
- package/packages/core/dist/index.mjs +113 -60
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/{log-config-BzGmDYum.d.cts → inspect-event-Des4JDHo.d.cts} +1 -31
- package/packages/core/dist/{log-config-BzGmDYum.d.ts → inspect-event-Des4JDHo.d.ts} +1 -31
- package/packages/core/dist/log-config-BnH8Ykcb.d.cts +33 -0
- package/packages/core/dist/log-config-C1GcJPIM.d.ts +33 -0
- package/packages/core/dist/logs.d.cts +3 -2
- package/packages/core/dist/logs.d.ts +3 -2
- package/packages/core/dist/logs.mjs +3 -3
- package/packages/core/dist/persisted-inspect-event-0kaRADsp.d.cts +56 -0
- package/packages/core/dist/persisted-inspect-event-DiFto0K2.d.ts +56 -0
- package/packages/core/dist/persisted.cjs +38 -40
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +6 -55
- package/packages/core/dist/persisted.d.ts +6 -55
- package/packages/core/dist/persisted.mjs +4 -2
- package/packages/core/dist/readers.cjs +2590 -0
- package/packages/core/dist/readers.cjs.map +1 -0
- package/packages/core/dist/readers.d.cts +80 -0
- package/packages/core/dist/readers.d.ts +80 -0
- package/packages/core/dist/readers.mjs +9 -0
- package/packages/core/dist/readers.mjs.map +1 -0
- package/packages/core/dist/{types-CNbheSdk.d.cts → types-DB8jB6Jg.d.cts} +7 -1
- package/packages/core/dist/{types-Bkt7LS01.d.ts → types-tSix7tfv.d.ts} +7 -1
- package/packages/core/dist/writers.cjs +997 -0
- package/packages/core/dist/writers.cjs.map +1 -0
- package/packages/core/dist/writers.d.cts +62 -0
- package/packages/core/dist/writers.d.ts +62 -0
- package/packages/core/dist/writers.mjs +9 -0
- package/packages/core/dist/writers.mjs.map +1 -0
- package/packages/core/dist/chunk-5EMIZZXD.mjs.map +0 -1
- package/packages/core/dist/chunk-Q6EPNB3V.mjs.map +0 -1
- package/packages/core/dist/chunk-QX3ZMPUF.mjs.map +0 -1
- package/packages/core/dist/chunk-XDBND27A.mjs +0 -975
- package/packages/core/dist/chunk-XDBND27A.mjs.map +0 -1
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var promises = require('fs/promises');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var crypto = require('crypto');
|
|
6
|
+
var os = require('os');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
11
|
+
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
12
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
13
|
+
|
|
14
|
+
// packages/core/src/writers/index.ts
|
|
15
|
+
var DEFAULT_REDACT_KEYS = [
|
|
16
|
+
"authorization",
|
|
17
|
+
"cookie",
|
|
18
|
+
"token",
|
|
19
|
+
"apiKey",
|
|
20
|
+
"password",
|
|
21
|
+
"secret",
|
|
22
|
+
"email"
|
|
23
|
+
];
|
|
24
|
+
function isRecord(v) {
|
|
25
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
26
|
+
}
|
|
27
|
+
function toKey(s) {
|
|
28
|
+
return s.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
function stableHash(value) {
|
|
31
|
+
const h = crypto__default.default.createHash("sha256").update(value, "utf8").digest("hex");
|
|
32
|
+
return h.slice(0, 8);
|
|
33
|
+
}
|
|
34
|
+
function compileRules(rules, extraKeys) {
|
|
35
|
+
const out = /* @__PURE__ */ new Map();
|
|
36
|
+
const set = (r) => {
|
|
37
|
+
const k = toKey(r.key);
|
|
38
|
+
out.set(k, { ...r, key: k });
|
|
39
|
+
};
|
|
40
|
+
for (const k of DEFAULT_REDACT_KEYS) {
|
|
41
|
+
set({ key: k, strategy: "full" });
|
|
42
|
+
}
|
|
43
|
+
for (const k of extraKeys ?? []) {
|
|
44
|
+
if (typeof k === "string" && k.length > 0) {
|
|
45
|
+
set({ key: k, strategy: "full" });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const r of rules ?? []) {
|
|
49
|
+
if (typeof r === "string") {
|
|
50
|
+
set({ key: r, strategy: "full" });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const key = r.key;
|
|
54
|
+
if (r.strategy === "full") set({ key, strategy: "full" });
|
|
55
|
+
if (r.strategy === "hash") set({ key, strategy: "hash" });
|
|
56
|
+
if (r.strategy === "prefix") {
|
|
57
|
+
set({ key, strategy: "prefix", keep: typeof r.keep === "number" ? r.keep : 8 });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return [...out.values()];
|
|
61
|
+
}
|
|
62
|
+
var Redactor = class {
|
|
63
|
+
#rules;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
66
|
+
}
|
|
67
|
+
redactValue(key, value) {
|
|
68
|
+
const k = toKey(key);
|
|
69
|
+
const rule = this.#rules.find((r) => r.key === k);
|
|
70
|
+
if (!rule) {
|
|
71
|
+
return this.#redactNested(value);
|
|
72
|
+
}
|
|
73
|
+
if (rule.strategy === "full") return "[REDACTED]";
|
|
74
|
+
const asString = typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" ? String(value) : void 0;
|
|
75
|
+
if (rule.strategy === "prefix") {
|
|
76
|
+
if (asString === void 0) return "[REDACTED]";
|
|
77
|
+
const keep = Math.max(0, Math.floor(rule.keep));
|
|
78
|
+
return asString.length <= keep ? `${asString}\u2026` : `${asString.slice(0, keep)}\u2026`;
|
|
79
|
+
}
|
|
80
|
+
if (rule.strategy === "hash") {
|
|
81
|
+
if (asString === void 0) return "[HASH:unknown]";
|
|
82
|
+
return `[HASH:${stableHash(asString)}]`;
|
|
83
|
+
}
|
|
84
|
+
return this.#redactNested(value);
|
|
85
|
+
}
|
|
86
|
+
redactRecord(record) {
|
|
87
|
+
const out = {};
|
|
88
|
+
for (const [k, v] of Object.entries(record)) {
|
|
89
|
+
out[k] = this.redactValue(k, v);
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
#redactNested(value) {
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
return value.map((v) => this.#redactNested(v));
|
|
96
|
+
}
|
|
97
|
+
if (isRecord(value)) {
|
|
98
|
+
const out = {};
|
|
99
|
+
for (const [k, v] of Object.entries(value)) {
|
|
100
|
+
out[k] = this.redactValue(k, v);
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// packages/core/src/redaction-profiles.ts
|
|
109
|
+
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
110
|
+
"userEmail",
|
|
111
|
+
"customerEmail",
|
|
112
|
+
"phone",
|
|
113
|
+
"phoneNumber",
|
|
114
|
+
"address",
|
|
115
|
+
"ip",
|
|
116
|
+
"ipAddress",
|
|
117
|
+
"sessionId",
|
|
118
|
+
"requestId",
|
|
119
|
+
"correlationId",
|
|
120
|
+
"decisionId",
|
|
121
|
+
"groupId",
|
|
122
|
+
"customerId",
|
|
123
|
+
"userId",
|
|
124
|
+
"accountId",
|
|
125
|
+
"tenantId",
|
|
126
|
+
"orgId",
|
|
127
|
+
"organizationId",
|
|
128
|
+
"traceId",
|
|
129
|
+
"spanId",
|
|
130
|
+
"parentSpanId"
|
|
131
|
+
];
|
|
132
|
+
var STRICT_PROFILE_EXTRA_KEYS = [
|
|
133
|
+
"prompt",
|
|
134
|
+
"completion",
|
|
135
|
+
"input",
|
|
136
|
+
"output",
|
|
137
|
+
"inputPreview",
|
|
138
|
+
"outputPreview",
|
|
139
|
+
"message",
|
|
140
|
+
"messages",
|
|
141
|
+
"transcript",
|
|
142
|
+
"context",
|
|
143
|
+
"document",
|
|
144
|
+
"documents",
|
|
145
|
+
"chunk",
|
|
146
|
+
"chunks",
|
|
147
|
+
"retrieval",
|
|
148
|
+
"query"
|
|
149
|
+
];
|
|
150
|
+
function resolveRedactionProfile(profile = "local") {
|
|
151
|
+
switch (profile) {
|
|
152
|
+
case "local":
|
|
153
|
+
return { profile: "local", extraKeys: [] };
|
|
154
|
+
case "share":
|
|
155
|
+
return {
|
|
156
|
+
profile: "share",
|
|
157
|
+
extraKeys: SHARE_PROFILE_EXTRA_KEYS,
|
|
158
|
+
maxMetadataValueLengthCap: 500,
|
|
159
|
+
maxPreviewLengthCap: 200
|
|
160
|
+
};
|
|
161
|
+
case "strict":
|
|
162
|
+
return {
|
|
163
|
+
profile: "strict",
|
|
164
|
+
extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
|
|
165
|
+
maxMetadataValueLengthCap: 200,
|
|
166
|
+
maxPreviewLengthCap: 80
|
|
167
|
+
};
|
|
168
|
+
default:
|
|
169
|
+
return { profile: "local", extraKeys: [] };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// packages/core/src/types/persisted-inspect-event.ts
|
|
174
|
+
var INSPECT_KINDS = [
|
|
175
|
+
"RUN",
|
|
176
|
+
"AGENT",
|
|
177
|
+
"LLM",
|
|
178
|
+
"TOOL",
|
|
179
|
+
"CHAIN",
|
|
180
|
+
"RETRIEVER",
|
|
181
|
+
"DECISION",
|
|
182
|
+
"RESULT",
|
|
183
|
+
"ERROR",
|
|
184
|
+
"LOGIC",
|
|
185
|
+
"LOG"
|
|
186
|
+
];
|
|
187
|
+
var ATTRIBUTION_CONFIDENCES = [
|
|
188
|
+
"explicit",
|
|
189
|
+
"correlated",
|
|
190
|
+
"heuristic",
|
|
191
|
+
"unknown"
|
|
192
|
+
];
|
|
193
|
+
var PERSISTED_EVENT_SOURCE_TYPES = [
|
|
194
|
+
"manual",
|
|
195
|
+
"json-log",
|
|
196
|
+
"log4js",
|
|
197
|
+
"adapter",
|
|
198
|
+
"ai-sdk",
|
|
199
|
+
"otel"
|
|
200
|
+
];
|
|
201
|
+
var PERSISTED_EVENT_STATUSES = [
|
|
202
|
+
"running",
|
|
203
|
+
"ok",
|
|
204
|
+
"error",
|
|
205
|
+
"unknown"
|
|
206
|
+
];
|
|
207
|
+
function isRecord2(value) {
|
|
208
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
209
|
+
}
|
|
210
|
+
function isString(value) {
|
|
211
|
+
return typeof value === "string";
|
|
212
|
+
}
|
|
213
|
+
function isNonEmptyString(value) {
|
|
214
|
+
return typeof value === "string" && value.length > 0;
|
|
215
|
+
}
|
|
216
|
+
function isOptionalString(value) {
|
|
217
|
+
return value === void 0 || isString(value);
|
|
218
|
+
}
|
|
219
|
+
function isNonNegativeNumber(value) {
|
|
220
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
221
|
+
}
|
|
222
|
+
function isOptionalNonNegativeNumber(value) {
|
|
223
|
+
return value === void 0 || isNonNegativeNumber(value);
|
|
224
|
+
}
|
|
225
|
+
function isInspectKind(value) {
|
|
226
|
+
return typeof value === "string" && INSPECT_KINDS.includes(value);
|
|
227
|
+
}
|
|
228
|
+
function isAttributionConfidence(value) {
|
|
229
|
+
return typeof value === "string" && ATTRIBUTION_CONFIDENCES.includes(value);
|
|
230
|
+
}
|
|
231
|
+
function isPersistedEventSourceType(value) {
|
|
232
|
+
return typeof value === "string" && PERSISTED_EVENT_SOURCE_TYPES.includes(value);
|
|
233
|
+
}
|
|
234
|
+
function isPersistedEventStatus(value) {
|
|
235
|
+
return typeof value === "string" && PERSISTED_EVENT_STATUSES.includes(value);
|
|
236
|
+
}
|
|
237
|
+
function isPersistedEventSource(value) {
|
|
238
|
+
if (!isRecord2(value)) return false;
|
|
239
|
+
if (!isPersistedEventSourceType(value.type)) return false;
|
|
240
|
+
if (!isOptionalString(value.name)) return false;
|
|
241
|
+
if (!isOptionalString(value.version)) return false;
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
function isPersistedInspectError(value) {
|
|
245
|
+
if (!isRecord2(value)) return false;
|
|
246
|
+
if (!isNonEmptyString(value.message)) return false;
|
|
247
|
+
if (!isOptionalString(value.name)) return false;
|
|
248
|
+
if (!isOptionalString(value.code)) return false;
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
function isPersistedTokenUsage(value) {
|
|
252
|
+
if (!isRecord2(value)) return false;
|
|
253
|
+
if (!isOptionalNonNegativeNumber(value.input)) return false;
|
|
254
|
+
if (!isOptionalNonNegativeNumber(value.output)) return false;
|
|
255
|
+
if (!isOptionalNonNegativeNumber(value.total)) return false;
|
|
256
|
+
if (!isOptionalNonNegativeNumber(value.cached)) return false;
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
function isPersistedTraceContext(value) {
|
|
260
|
+
if (!isRecord2(value)) return false;
|
|
261
|
+
if (!isOptionalString(value.traceId)) return false;
|
|
262
|
+
if (!isOptionalString(value.spanId)) return false;
|
|
263
|
+
if (!isOptionalString(value.parentSpanId)) return false;
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
function isPersistedInspectEvent(value) {
|
|
267
|
+
if (!isRecord2(value)) return false;
|
|
268
|
+
if (value.schemaVersion !== "0.2") return false;
|
|
269
|
+
if (!isNonEmptyString(value.eventId)) return false;
|
|
270
|
+
if (!isNonEmptyString(value.runId)) return false;
|
|
271
|
+
if (!isInspectKind(value.kind)) return false;
|
|
272
|
+
if (!isNonEmptyString(value.name)) return false;
|
|
273
|
+
if (!isNonEmptyString(value.timestamp)) return false;
|
|
274
|
+
if (!isAttributionConfidence(value.confidence)) return false;
|
|
275
|
+
if (!isPersistedEventSource(value.source)) return false;
|
|
276
|
+
if (value.parentId !== void 0 && !isNonEmptyString(value.parentId)) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
if (value.status !== void 0 && !isPersistedEventStatus(value.status)) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (!isOptionalString(value.startedAt)) return false;
|
|
283
|
+
if (!isOptionalString(value.endedAt)) return false;
|
|
284
|
+
if (value.durationMs !== void 0 && !isNonNegativeNumber(value.durationMs)) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
if (value.attributes !== void 0 && !isRecord2(value.attributes)) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
if (value.error !== void 0 && !isPersistedInspectError(value.error)) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
if (value.tokenUsage !== void 0 && !isPersistedTokenUsage(value.tokenUsage)) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
if (value.trace !== void 0 && !isPersistedTraceContext(value.trace)) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
302
|
+
var RUNS_DIR_NAME = "runs";
|
|
303
|
+
var FALLBACK_TRACE_DIR = path__default.default.join(
|
|
304
|
+
os__default.default.tmpdir(),
|
|
305
|
+
"agent-inspect",
|
|
306
|
+
RUNS_DIR_NAME
|
|
307
|
+
);
|
|
308
|
+
function getDefaultTraceDir() {
|
|
309
|
+
const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
|
|
310
|
+
if (typeof envDir === "string" && envDir.trim() !== "") {
|
|
311
|
+
return envDir.trim();
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
const home = os__default.default.homedir();
|
|
315
|
+
if (typeof home !== "string" || home.trim() === "") {
|
|
316
|
+
return FALLBACK_TRACE_DIR;
|
|
317
|
+
}
|
|
318
|
+
return path__default.default.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
319
|
+
} catch {
|
|
320
|
+
return FALLBACK_TRACE_DIR;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function getTraceFilePath(runId, traceDir) {
|
|
324
|
+
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
325
|
+
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
326
|
+
safeId = path__default.default.basename(safeId);
|
|
327
|
+
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
328
|
+
safeId = "run_unknown";
|
|
329
|
+
}
|
|
330
|
+
return path__default.default.join(baseDir, `${safeId}.jsonl`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// packages/core/src/trace-event-safety.ts
|
|
334
|
+
var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
|
|
335
|
+
var DEFAULT_MAX_PREVIEW_LENGTH = 500;
|
|
336
|
+
var DEFAULT_MAX_EVENT_BYTES = 65536;
|
|
337
|
+
function isRecord3(value) {
|
|
338
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
339
|
+
}
|
|
340
|
+
function isPreviewKey(key) {
|
|
341
|
+
return key.toLowerCase().includes("preview");
|
|
342
|
+
}
|
|
343
|
+
function truncateString(value, maxLen) {
|
|
344
|
+
if (maxLen <= 0) return "\u2026";
|
|
345
|
+
if (value.length <= maxLen) return value;
|
|
346
|
+
return `${value.slice(0, maxLen)}\u2026`;
|
|
347
|
+
}
|
|
348
|
+
function byteLength(text) {
|
|
349
|
+
return Buffer.byteLength(text, "utf8");
|
|
350
|
+
}
|
|
351
|
+
function resolveTraceSafetyOptions(options) {
|
|
352
|
+
let redactEnabled = true;
|
|
353
|
+
let redactionRules;
|
|
354
|
+
{
|
|
355
|
+
redactEnabled = true;
|
|
356
|
+
}
|
|
357
|
+
const profile = "local";
|
|
358
|
+
const resolvedProfile = resolveRedactionProfile(profile);
|
|
359
|
+
let maxMetadataValueLength = DEFAULT_MAX_METADATA_VALUE_LENGTH;
|
|
360
|
+
let maxPreviewLength = DEFAULT_MAX_PREVIEW_LENGTH;
|
|
361
|
+
return {
|
|
362
|
+
redactEnabled,
|
|
363
|
+
redactionRules,
|
|
364
|
+
redactionProfile: profile,
|
|
365
|
+
profileExtraKeys: redactEnabled ? resolvedProfile.extraKeys : [],
|
|
366
|
+
maxMetadataValueLength,
|
|
367
|
+
maxPreviewLength,
|
|
368
|
+
maxEventBytes: DEFAULT_MAX_EVENT_BYTES
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function boundMetadataValue(key, value, opts, seen, depth) {
|
|
372
|
+
if (depth > 32) return "[MaxDepth]";
|
|
373
|
+
if (typeof value === "bigint") {
|
|
374
|
+
return `${value.toString()}n`;
|
|
375
|
+
}
|
|
376
|
+
if (typeof value === "function") {
|
|
377
|
+
return "[Function]";
|
|
378
|
+
}
|
|
379
|
+
if (typeof value === "symbol") {
|
|
380
|
+
return "[Symbol]";
|
|
381
|
+
}
|
|
382
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
383
|
+
return String(value);
|
|
384
|
+
}
|
|
385
|
+
if (value === void 0) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
if (value === null || typeof value !== "object") {
|
|
389
|
+
if (typeof value === "string") {
|
|
390
|
+
const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
|
|
391
|
+
return truncateString(value, max);
|
|
392
|
+
}
|
|
393
|
+
return value;
|
|
394
|
+
}
|
|
395
|
+
if (seen.has(value)) return "[Circular]";
|
|
396
|
+
seen.add(value);
|
|
397
|
+
if (Array.isArray(value)) {
|
|
398
|
+
const maxItems = 50;
|
|
399
|
+
const out2 = value.slice(0, maxItems).map(
|
|
400
|
+
(item, index) => boundMetadataValue(String(index), item, opts, seen, depth + 1)
|
|
401
|
+
);
|
|
402
|
+
if (value.length > maxItems) {
|
|
403
|
+
out2.push(`\u2026(+${value.length - maxItems} more)`);
|
|
404
|
+
}
|
|
405
|
+
return out2;
|
|
406
|
+
}
|
|
407
|
+
const record = value;
|
|
408
|
+
const out = {};
|
|
409
|
+
try {
|
|
410
|
+
for (const [k, v] of Object.entries(record)) {
|
|
411
|
+
out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
|
|
412
|
+
}
|
|
413
|
+
} catch {
|
|
414
|
+
return { truncated: true, reason: "metadataEnumerationFailed" };
|
|
415
|
+
}
|
|
416
|
+
return out;
|
|
417
|
+
}
|
|
418
|
+
function redactMetadata(metadata, opts) {
|
|
419
|
+
if (!opts.redactEnabled) return { ...metadata };
|
|
420
|
+
const redactor = new Redactor({
|
|
421
|
+
rules: opts.redactionRules,
|
|
422
|
+
extraKeys: opts.profileExtraKeys
|
|
423
|
+
});
|
|
424
|
+
return redactor.redactRecord(metadata);
|
|
425
|
+
}
|
|
426
|
+
function prepareMetadataForDisk(metadata, opts) {
|
|
427
|
+
try {
|
|
428
|
+
const preBounded = boundMetadataValue(
|
|
429
|
+
"metadata",
|
|
430
|
+
metadata,
|
|
431
|
+
opts,
|
|
432
|
+
/* @__PURE__ */ new WeakSet(),
|
|
433
|
+
0
|
|
434
|
+
);
|
|
435
|
+
const redacted = redactMetadata(
|
|
436
|
+
isRecord3(preBounded) ? preBounded : {},
|
|
437
|
+
opts
|
|
438
|
+
);
|
|
439
|
+
const bounded = boundMetadataValue(
|
|
440
|
+
"metadata",
|
|
441
|
+
redacted,
|
|
442
|
+
opts,
|
|
443
|
+
/* @__PURE__ */ new WeakSet(),
|
|
444
|
+
0
|
|
445
|
+
);
|
|
446
|
+
return isRecord3(bounded) ? bounded : {};
|
|
447
|
+
} catch {
|
|
448
|
+
return { truncated: true, reason: "metadataPreparationFailed" };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function safeGet(record, key) {
|
|
452
|
+
try {
|
|
453
|
+
return record[key];
|
|
454
|
+
} catch {
|
|
455
|
+
return void 0;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function optionalBoundedString(value, _key, opts) {
|
|
459
|
+
if (typeof value !== "string") return void 0;
|
|
460
|
+
return truncateString(value, opts.maxMetadataValueLength);
|
|
461
|
+
}
|
|
462
|
+
function requiredBoundedString(value, key, opts) {
|
|
463
|
+
const out = optionalBoundedString(value, key, opts);
|
|
464
|
+
return out && out.length > 0 ? out : void 0;
|
|
465
|
+
}
|
|
466
|
+
function preparePersistedSummaryForDisk(key, value, opts) {
|
|
467
|
+
try {
|
|
468
|
+
const redactor = new Redactor({
|
|
469
|
+
rules: opts.redactionRules,
|
|
470
|
+
extraKeys: opts.profileExtraKeys
|
|
471
|
+
});
|
|
472
|
+
const redacted = opts.redactEnabled ? redactor.redactValue(key, value) : value;
|
|
473
|
+
return boundMetadataValue(key, redacted, opts, /* @__PURE__ */ new WeakSet(), 0);
|
|
474
|
+
} catch {
|
|
475
|
+
return { truncated: true, reason: "summaryPreparationFailed" };
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function preparePersistedErrorForDisk(value, opts) {
|
|
479
|
+
if (!isRecord3(value)) return void 0;
|
|
480
|
+
try {
|
|
481
|
+
const redactor = new Redactor({
|
|
482
|
+
rules: opts.redactionRules,
|
|
483
|
+
extraKeys: opts.profileExtraKeys
|
|
484
|
+
});
|
|
485
|
+
const rawMessage = safeGet(value, "message");
|
|
486
|
+
const redactedMessage = opts.redactEnabled ? redactor.redactValue("message", rawMessage) : rawMessage;
|
|
487
|
+
const boundedMessage = boundMetadataValue(
|
|
488
|
+
"message",
|
|
489
|
+
redactedMessage,
|
|
490
|
+
opts,
|
|
491
|
+
/* @__PURE__ */ new WeakSet(),
|
|
492
|
+
0
|
|
493
|
+
);
|
|
494
|
+
const message = typeof boundedMessage === "string" && boundedMessage.length > 0 ? boundedMessage : "Unknown error";
|
|
495
|
+
const out = { message };
|
|
496
|
+
const name = optionalBoundedString(safeGet(value, "name"), "name", opts);
|
|
497
|
+
const code = optionalBoundedString(safeGet(value, "code"), "code", opts);
|
|
498
|
+
if (name !== void 0) out.name = name;
|
|
499
|
+
if (code !== void 0) out.code = code;
|
|
500
|
+
return out;
|
|
501
|
+
} catch {
|
|
502
|
+
return { message: "Error preparation failed" };
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function prepareTokenUsage(value) {
|
|
506
|
+
if (!isRecord3(value)) return void 0;
|
|
507
|
+
const out = {};
|
|
508
|
+
for (const key of ["input", "output", "total", "cached"]) {
|
|
509
|
+
const item = safeGet(value, key);
|
|
510
|
+
if (typeof item === "number" && Number.isFinite(item) && item >= 0) {
|
|
511
|
+
out[key] = item;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
515
|
+
}
|
|
516
|
+
function prepareTraceContext(value, opts) {
|
|
517
|
+
if (!isRecord3(value)) return void 0;
|
|
518
|
+
const out = {};
|
|
519
|
+
const traceId = optionalBoundedString(safeGet(value, "traceId"), "traceId", opts);
|
|
520
|
+
const spanId = optionalBoundedString(safeGet(value, "spanId"), "spanId", opts);
|
|
521
|
+
const parentSpanId = optionalBoundedString(
|
|
522
|
+
safeGet(value, "parentSpanId"),
|
|
523
|
+
"parentSpanId",
|
|
524
|
+
opts
|
|
525
|
+
);
|
|
526
|
+
if (traceId !== void 0) out.traceId = traceId;
|
|
527
|
+
if (spanId !== void 0) out.spanId = spanId;
|
|
528
|
+
if (parentSpanId !== void 0) out.parentSpanId = parentSpanId;
|
|
529
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
530
|
+
}
|
|
531
|
+
function serializedPersistedEvent(event) {
|
|
532
|
+
try {
|
|
533
|
+
return JSON.stringify(event);
|
|
534
|
+
} catch {
|
|
535
|
+
return void 0;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
function persistedEventByteLength(event) {
|
|
539
|
+
const serialized = serializedPersistedEvent(event);
|
|
540
|
+
return serialized === void 0 ? void 0 : byteLength(serialized);
|
|
541
|
+
}
|
|
542
|
+
function minimalPersistedEvent(event, opts, originalApproxBytes) {
|
|
543
|
+
return {
|
|
544
|
+
schemaVersion: "0.2",
|
|
545
|
+
eventId: truncateString(event.eventId, 128),
|
|
546
|
+
runId: truncateString(event.runId, 128),
|
|
547
|
+
kind: event.kind,
|
|
548
|
+
name: truncateString(event.name, 128),
|
|
549
|
+
...event.status !== void 0 ? { status: event.status } : {},
|
|
550
|
+
timestamp: truncateString(event.timestamp, 128),
|
|
551
|
+
confidence: event.confidence,
|
|
552
|
+
source: {
|
|
553
|
+
type: event.source.type,
|
|
554
|
+
...event.source.name !== void 0 ? { name: truncateString(event.source.name, 128) } : {},
|
|
555
|
+
...event.source.version !== void 0 ? { version: truncateString(event.source.version, 128) } : {}
|
|
556
|
+
},
|
|
557
|
+
attributes: {
|
|
558
|
+
truncated: true,
|
|
559
|
+
reason: "maxEventBytes",
|
|
560
|
+
originalApproxBytes,
|
|
561
|
+
maxEventBytes: opts.maxEventBytes
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
function tinyPersistedEvent(event) {
|
|
566
|
+
return {
|
|
567
|
+
schemaVersion: "0.2",
|
|
568
|
+
eventId: truncateString(event.eventId, 32),
|
|
569
|
+
runId: truncateString(event.runId, 32),
|
|
570
|
+
kind: event.kind,
|
|
571
|
+
name: truncateString(event.name, 32),
|
|
572
|
+
timestamp: truncateString(event.timestamp, 32),
|
|
573
|
+
confidence: event.confidence,
|
|
574
|
+
source: { type: event.source.type },
|
|
575
|
+
attributes: { truncated: true, reason: "maxEventBytes" }
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function enforcePersistedEventSize(event, opts) {
|
|
579
|
+
const bytes = persistedEventByteLength(event);
|
|
580
|
+
if (bytes === void 0) return void 0;
|
|
581
|
+
if (bytes <= opts.maxEventBytes) return event;
|
|
582
|
+
const minimal = minimalPersistedEvent(event, opts, bytes);
|
|
583
|
+
const minimalBytes = persistedEventByteLength(minimal);
|
|
584
|
+
if (minimalBytes !== void 0 && minimalBytes <= opts.maxEventBytes) {
|
|
585
|
+
return minimal;
|
|
586
|
+
}
|
|
587
|
+
const tiny = tinyPersistedEvent(event);
|
|
588
|
+
return isPersistedInspectEvent(tiny) ? tiny : void 0;
|
|
589
|
+
}
|
|
590
|
+
function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOptions()) {
|
|
591
|
+
try {
|
|
592
|
+
if (!isRecord3(value)) return void 0;
|
|
593
|
+
const source = safeGet(value, "source");
|
|
594
|
+
if (!isRecord3(source)) return void 0;
|
|
595
|
+
const candidate = {
|
|
596
|
+
schemaVersion: safeGet(value, "schemaVersion"),
|
|
597
|
+
eventId: requiredBoundedString(safeGet(value, "eventId"), "eventId", opts) ?? "",
|
|
598
|
+
runId: requiredBoundedString(safeGet(value, "runId"), "runId", opts) ?? "",
|
|
599
|
+
kind: safeGet(value, "kind"),
|
|
600
|
+
name: requiredBoundedString(safeGet(value, "name"), "name", opts) ?? "",
|
|
601
|
+
timestamp: requiredBoundedString(safeGet(value, "timestamp"), "timestamp", opts) ?? "",
|
|
602
|
+
confidence: safeGet(value, "confidence"),
|
|
603
|
+
source: {
|
|
604
|
+
type: safeGet(source, "type")
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
const parentId = requiredBoundedString(safeGet(value, "parentId"), "parentId", opts);
|
|
608
|
+
const status = safeGet(value, "status");
|
|
609
|
+
const startedAt = optionalBoundedString(safeGet(value, "startedAt"), "startedAt", opts);
|
|
610
|
+
const endedAt = optionalBoundedString(safeGet(value, "endedAt"), "endedAt", opts);
|
|
611
|
+
const durationMs = safeGet(value, "durationMs");
|
|
612
|
+
const sourceName = optionalBoundedString(safeGet(source, "name"), "name", opts);
|
|
613
|
+
const sourceVersion = optionalBoundedString(safeGet(source, "version"), "version", opts);
|
|
614
|
+
if (parentId !== void 0) candidate.parentId = parentId;
|
|
615
|
+
if (status === "running" || status === "ok" || status === "error" || status === "unknown") {
|
|
616
|
+
candidate.status = status;
|
|
617
|
+
}
|
|
618
|
+
if (startedAt !== void 0) candidate.startedAt = startedAt;
|
|
619
|
+
if (endedAt !== void 0) candidate.endedAt = endedAt;
|
|
620
|
+
if (typeof durationMs === "number" && Number.isFinite(durationMs) && durationMs >= 0) {
|
|
621
|
+
candidate.durationMs = durationMs;
|
|
622
|
+
}
|
|
623
|
+
if (sourceName !== void 0) candidate.source.name = sourceName;
|
|
624
|
+
if (sourceVersion !== void 0) candidate.source.version = sourceVersion;
|
|
625
|
+
const attributes = safeGet(value, "attributes");
|
|
626
|
+
if (isRecord3(attributes)) {
|
|
627
|
+
candidate.attributes = prepareMetadataForDisk(attributes, opts);
|
|
628
|
+
}
|
|
629
|
+
if (safeGet(value, "inputSummary") !== void 0) {
|
|
630
|
+
candidate.inputSummary = preparePersistedSummaryForDisk(
|
|
631
|
+
"input",
|
|
632
|
+
safeGet(value, "inputSummary"),
|
|
633
|
+
opts
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
if (safeGet(value, "outputSummary") !== void 0) {
|
|
637
|
+
candidate.outputSummary = preparePersistedSummaryForDisk(
|
|
638
|
+
"output",
|
|
639
|
+
safeGet(value, "outputSummary"),
|
|
640
|
+
opts
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
const error = preparePersistedErrorForDisk(safeGet(value, "error"), opts);
|
|
644
|
+
if (error !== void 0) candidate.error = error;
|
|
645
|
+
const tokenUsage = prepareTokenUsage(safeGet(value, "tokenUsage"));
|
|
646
|
+
if (tokenUsage !== void 0) candidate.tokenUsage = tokenUsage;
|
|
647
|
+
const trace = prepareTraceContext(safeGet(value, "trace"), opts);
|
|
648
|
+
if (trace !== void 0) candidate.trace = trace;
|
|
649
|
+
if (!isPersistedInspectEvent(candidate)) return void 0;
|
|
650
|
+
return enforcePersistedEventSize(candidate, opts);
|
|
651
|
+
} catch {
|
|
652
|
+
return void 0;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// packages/core/src/writers/index.ts
|
|
657
|
+
var DEFAULT_TRACE_SAFETY = resolveTraceSafetyOptions();
|
|
658
|
+
function createInitialStats() {
|
|
659
|
+
return {
|
|
660
|
+
writtenEvents: 0,
|
|
661
|
+
droppedEvents: 0,
|
|
662
|
+
flushCount: 0
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
function markFlush(stats) {
|
|
666
|
+
stats.flushCount += 1;
|
|
667
|
+
stats.lastFlushAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
668
|
+
}
|
|
669
|
+
function cloneStats(stats) {
|
|
670
|
+
return { ...stats };
|
|
671
|
+
}
|
|
672
|
+
function normalizeError(error) {
|
|
673
|
+
if (error instanceof Error && error.message.trim() !== "") {
|
|
674
|
+
return error.message;
|
|
675
|
+
}
|
|
676
|
+
if (typeof error === "string" && error.trim() !== "") {
|
|
677
|
+
return error;
|
|
678
|
+
}
|
|
679
|
+
return "Unknown trace writer error";
|
|
680
|
+
}
|
|
681
|
+
function recordDropped(stats, error) {
|
|
682
|
+
stats.droppedEvents += 1;
|
|
683
|
+
stats.lastError = normalizeError(error);
|
|
684
|
+
}
|
|
685
|
+
function prepareWriterEvent(event) {
|
|
686
|
+
return preparePersistedInspectEventForWrite(event, DEFAULT_TRACE_SAFETY);
|
|
687
|
+
}
|
|
688
|
+
function resolveFilePath(event, options) {
|
|
689
|
+
if (options.filePath && options.filePath.trim() !== "") {
|
|
690
|
+
return path__default.default.resolve(options.filePath);
|
|
691
|
+
}
|
|
692
|
+
return getTraceFilePath(event.runId, options.dir);
|
|
693
|
+
}
|
|
694
|
+
function serializeEvent2(event) {
|
|
695
|
+
return `${JSON.stringify(event)}
|
|
696
|
+
`;
|
|
697
|
+
}
|
|
698
|
+
async function appendEventLine(event, options) {
|
|
699
|
+
const filePath = resolveFilePath(event, options);
|
|
700
|
+
await promises.mkdir(path__default.default.dirname(filePath), { recursive: true });
|
|
701
|
+
await promises.appendFile(filePath, serializeEvent2(event), "utf-8");
|
|
702
|
+
}
|
|
703
|
+
async function appendEventBatch(events, options) {
|
|
704
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
705
|
+
let dropped = 0;
|
|
706
|
+
let lastError;
|
|
707
|
+
for (const event of events) {
|
|
708
|
+
try {
|
|
709
|
+
const filePath = resolveFilePath(event, options);
|
|
710
|
+
const line = serializeEvent2(event);
|
|
711
|
+
const lines = byPath.get(filePath);
|
|
712
|
+
if (lines) {
|
|
713
|
+
lines.push(line);
|
|
714
|
+
} else {
|
|
715
|
+
byPath.set(filePath, [line]);
|
|
716
|
+
}
|
|
717
|
+
} catch (error) {
|
|
718
|
+
dropped += 1;
|
|
719
|
+
lastError = normalizeError(error);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
let written = 0;
|
|
723
|
+
for (const [filePath, lines] of byPath) {
|
|
724
|
+
try {
|
|
725
|
+
await promises.mkdir(path__default.default.dirname(filePath), { recursive: true });
|
|
726
|
+
await promises.appendFile(filePath, lines.join(""), "utf-8");
|
|
727
|
+
written += lines.length;
|
|
728
|
+
} catch (error) {
|
|
729
|
+
dropped += lines.length;
|
|
730
|
+
lastError = normalizeError(error);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return lastError ? { written, dropped, lastError } : { written, dropped };
|
|
734
|
+
}
|
|
735
|
+
function memoryWriter() {
|
|
736
|
+
const events = [];
|
|
737
|
+
const stats = createInitialStats();
|
|
738
|
+
return {
|
|
739
|
+
async write(event) {
|
|
740
|
+
const safe = prepareWriterEvent(event);
|
|
741
|
+
if (safe === void 0) {
|
|
742
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
events.push(safe);
|
|
746
|
+
stats.writtenEvents += 1;
|
|
747
|
+
},
|
|
748
|
+
async flush() {
|
|
749
|
+
markFlush(stats);
|
|
750
|
+
},
|
|
751
|
+
async close() {
|
|
752
|
+
},
|
|
753
|
+
getStats() {
|
|
754
|
+
return cloneStats(stats);
|
|
755
|
+
},
|
|
756
|
+
getEvents() {
|
|
757
|
+
return events.map((event) => structuredClone(event));
|
|
758
|
+
},
|
|
759
|
+
clear() {
|
|
760
|
+
events.length = 0;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
function nullWriter() {
|
|
765
|
+
const stats = createInitialStats();
|
|
766
|
+
return {
|
|
767
|
+
async write() {
|
|
768
|
+
stats.writtenEvents += 1;
|
|
769
|
+
},
|
|
770
|
+
async flush() {
|
|
771
|
+
markFlush(stats);
|
|
772
|
+
},
|
|
773
|
+
async close() {
|
|
774
|
+
},
|
|
775
|
+
getStats() {
|
|
776
|
+
return cloneStats(stats);
|
|
777
|
+
}
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function fileWriter(options = {}) {
|
|
781
|
+
const stats = createInitialStats();
|
|
782
|
+
let closed = false;
|
|
783
|
+
let queue = Promise.resolve();
|
|
784
|
+
const enqueue = (event) => {
|
|
785
|
+
const operation = queue.then(async () => {
|
|
786
|
+
if (closed) {
|
|
787
|
+
recordDropped(stats, "Trace writer is closed");
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
await appendEventLine(event, options);
|
|
792
|
+
stats.writtenEvents += 1;
|
|
793
|
+
} catch (error) {
|
|
794
|
+
recordDropped(stats, error);
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
queue = operation.catch(() => {
|
|
798
|
+
});
|
|
799
|
+
return operation.catch(() => {
|
|
800
|
+
});
|
|
801
|
+
};
|
|
802
|
+
return {
|
|
803
|
+
write(event) {
|
|
804
|
+
const safe = prepareWriterEvent(event);
|
|
805
|
+
if (safe === void 0) {
|
|
806
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
807
|
+
return Promise.resolve();
|
|
808
|
+
}
|
|
809
|
+
return enqueue(safe);
|
|
810
|
+
},
|
|
811
|
+
async flush() {
|
|
812
|
+
await queue;
|
|
813
|
+
markFlush(stats);
|
|
814
|
+
},
|
|
815
|
+
async close() {
|
|
816
|
+
if (closed) return;
|
|
817
|
+
await queue;
|
|
818
|
+
closed = true;
|
|
819
|
+
},
|
|
820
|
+
getStats() {
|
|
821
|
+
return cloneStats(stats);
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
function positiveInteger(value, fallback) {
|
|
826
|
+
if (value === void 0) return fallback;
|
|
827
|
+
if (!Number.isFinite(value) || value <= 0) return fallback;
|
|
828
|
+
return Math.floor(value);
|
|
829
|
+
}
|
|
830
|
+
function nonNegativeInteger(value, fallback) {
|
|
831
|
+
if (value === void 0) return fallback;
|
|
832
|
+
if (!Number.isFinite(value) || value < 0) return fallback;
|
|
833
|
+
return Math.floor(value);
|
|
834
|
+
}
|
|
835
|
+
function bufferedFileWriter(options = {}) {
|
|
836
|
+
const stats = createInitialStats();
|
|
837
|
+
const maxQueueSize = positiveInteger(options.maxQueueSize, 1e3);
|
|
838
|
+
const flushIntervalMs = nonNegativeInteger(options.flushIntervalMs, 250);
|
|
839
|
+
const maxBatchSize = positiveInteger(options.maxBatchSize, 100);
|
|
840
|
+
const overflow = options.overflow ?? "drop-oldest";
|
|
841
|
+
const pending = [];
|
|
842
|
+
let closed = false;
|
|
843
|
+
let timer;
|
|
844
|
+
let chain = Promise.resolve();
|
|
845
|
+
const clearTimer = () => {
|
|
846
|
+
if (timer !== void 0) {
|
|
847
|
+
clearTimeout(timer);
|
|
848
|
+
timer = void 0;
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
const scheduleFlush = () => {
|
|
852
|
+
if (closed || timer !== void 0 || pending.length === 0) return;
|
|
853
|
+
timer = setTimeout(() => {
|
|
854
|
+
timer = void 0;
|
|
855
|
+
void drain(false);
|
|
856
|
+
}, flushIntervalMs);
|
|
857
|
+
if (timer && typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") {
|
|
858
|
+
timer.unref();
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
const drainBatch = async (drainAll) => {
|
|
862
|
+
clearTimer();
|
|
863
|
+
do {
|
|
864
|
+
const batch = pending.splice(0, maxBatchSize);
|
|
865
|
+
if (batch.length === 0) break;
|
|
866
|
+
const result = await appendEventBatch(batch, options);
|
|
867
|
+
stats.writtenEvents += result.written;
|
|
868
|
+
stats.droppedEvents += result.dropped;
|
|
869
|
+
if (result.lastError) {
|
|
870
|
+
stats.lastError = result.lastError;
|
|
871
|
+
}
|
|
872
|
+
} while (drainAll && pending.length > 0);
|
|
873
|
+
if (pending.length > 0) scheduleFlush();
|
|
874
|
+
};
|
|
875
|
+
const drain = (drainAll) => {
|
|
876
|
+
const operation = chain.then(() => drainBatch(drainAll));
|
|
877
|
+
chain = operation.catch(() => {
|
|
878
|
+
});
|
|
879
|
+
return operation.catch(() => {
|
|
880
|
+
});
|
|
881
|
+
};
|
|
882
|
+
return {
|
|
883
|
+
async write(event) {
|
|
884
|
+
if (closed) {
|
|
885
|
+
recordDropped(stats, "Trace writer is closed");
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const safe = prepareWriterEvent(event);
|
|
889
|
+
if (safe === void 0) {
|
|
890
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (pending.length >= maxQueueSize) {
|
|
894
|
+
if (overflow === "drop-newest") {
|
|
895
|
+
recordDropped(stats, "Trace writer queue overflow");
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
pending.shift();
|
|
899
|
+
recordDropped(stats, "Trace writer queue overflow");
|
|
900
|
+
}
|
|
901
|
+
try {
|
|
902
|
+
pending.push(safe);
|
|
903
|
+
} catch (error) {
|
|
904
|
+
recordDropped(stats, error);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
scheduleFlush();
|
|
908
|
+
},
|
|
909
|
+
async flush() {
|
|
910
|
+
await drain(true);
|
|
911
|
+
markFlush(stats);
|
|
912
|
+
},
|
|
913
|
+
async close() {
|
|
914
|
+
if (closed) return;
|
|
915
|
+
await drain(true);
|
|
916
|
+
closed = true;
|
|
917
|
+
clearTimer();
|
|
918
|
+
},
|
|
919
|
+
getStats() {
|
|
920
|
+
return cloneStats(stats);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
function compositeWriter(writersOrOptions) {
|
|
925
|
+
const stats = createInitialStats();
|
|
926
|
+
const writers = Array.isArray(writersOrOptions) ? [...writersOrOptions] : [...writersOrOptions.writers];
|
|
927
|
+
let closed = false;
|
|
928
|
+
const recordChildFailure = (error) => {
|
|
929
|
+
stats.droppedEvents += 1;
|
|
930
|
+
stats.lastError = normalizeError(error);
|
|
931
|
+
};
|
|
932
|
+
return {
|
|
933
|
+
async write(event) {
|
|
934
|
+
if (closed) {
|
|
935
|
+
recordDropped(stats, "Trace writer is closed");
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
const safe = prepareWriterEvent(event);
|
|
939
|
+
if (safe === void 0) {
|
|
940
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
const childResults = await Promise.all(
|
|
944
|
+
writers.map(async (writer) => {
|
|
945
|
+
try {
|
|
946
|
+
await writer.write(structuredClone(safe));
|
|
947
|
+
return true;
|
|
948
|
+
} catch (error) {
|
|
949
|
+
recordChildFailure(error);
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
})
|
|
953
|
+
);
|
|
954
|
+
if (childResults.some(Boolean)) {
|
|
955
|
+
stats.writtenEvents += 1;
|
|
956
|
+
} else {
|
|
957
|
+
recordDropped(stats, "No composite trace writer accepted the event");
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
async flush() {
|
|
961
|
+
await Promise.all(
|
|
962
|
+
writers.map(async (writer) => {
|
|
963
|
+
try {
|
|
964
|
+
await writer.flush?.();
|
|
965
|
+
} catch (error) {
|
|
966
|
+
stats.lastError = normalizeError(error);
|
|
967
|
+
}
|
|
968
|
+
})
|
|
969
|
+
);
|
|
970
|
+
markFlush(stats);
|
|
971
|
+
},
|
|
972
|
+
async close() {
|
|
973
|
+
if (closed) return;
|
|
974
|
+
await Promise.all(
|
|
975
|
+
writers.map(async (writer) => {
|
|
976
|
+
try {
|
|
977
|
+
await writer.close?.();
|
|
978
|
+
} catch (error) {
|
|
979
|
+
stats.lastError = normalizeError(error);
|
|
980
|
+
}
|
|
981
|
+
})
|
|
982
|
+
);
|
|
983
|
+
closed = true;
|
|
984
|
+
},
|
|
985
|
+
getStats() {
|
|
986
|
+
return cloneStats(stats);
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
exports.bufferedFileWriter = bufferedFileWriter;
|
|
992
|
+
exports.compositeWriter = compositeWriter;
|
|
993
|
+
exports.fileWriter = fileWriter;
|
|
994
|
+
exports.memoryWriter = memoryWriter;
|
|
995
|
+
exports.nullWriter = nullWriter;
|
|
996
|
+
//# sourceMappingURL=writers.cjs.map
|
|
997
|
+
//# sourceMappingURL=writers.cjs.map
|