agent-inspect 1.5.0 → 1.7.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 +41 -0
- package/README.md +14 -4
- package/docs/ADAPTER-CONFORMANCE.md +35 -0
- package/docs/ADAPTERS.md +79 -1
- package/docs/API.md +184 -10
- package/docs/ARCHITECTURE.md +4 -0
- package/docs/CLI.md +41 -12
- package/docs/KNOWN-ISSUES.md +11 -1
- package/docs/LIMITATIONS.md +19 -2
- package/docs/SCHEMA.md +17 -7
- package/package.json +23 -2
- 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,655 @@
|
|
|
1
|
+
import { resolveRedactionProfile, applyProfileMetadataCaps } from './chunk-EDTQHZPM.mjs';
|
|
2
|
+
import { Redactor } from './chunk-VU6O5QAH.mjs';
|
|
3
|
+
import { isStepType, ensureTraceDir, getTraceFilePath, warn, FALLBACK_TRACE_DIR, parseTraceJsonl } from './chunk-VTIB5MDK.mjs';
|
|
4
|
+
import { isPersistedInspectEvent } from './chunk-74XZ6N7Q.mjs';
|
|
5
|
+
import { writeFile, readFile, readdir, stat, appendFile } from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
// packages/core/src/trace-event-safety.ts
|
|
9
|
+
var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
|
|
10
|
+
var DEFAULT_MAX_PREVIEW_LENGTH = 500;
|
|
11
|
+
var DEFAULT_MAX_EVENT_BYTES = 65536;
|
|
12
|
+
function isRecord(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
function isPreviewKey(key) {
|
|
16
|
+
return key.toLowerCase().includes("preview");
|
|
17
|
+
}
|
|
18
|
+
function truncateString(value, maxLen) {
|
|
19
|
+
if (maxLen <= 0) return "\u2026";
|
|
20
|
+
if (value.length <= maxLen) return value;
|
|
21
|
+
return `${value.slice(0, maxLen)}\u2026`;
|
|
22
|
+
}
|
|
23
|
+
function byteLength(text) {
|
|
24
|
+
return Buffer.byteLength(text, "utf8");
|
|
25
|
+
}
|
|
26
|
+
function resolveTraceSafetyOptions(options) {
|
|
27
|
+
const redact = options?.redact;
|
|
28
|
+
let redactEnabled = true;
|
|
29
|
+
let redactionRules;
|
|
30
|
+
if (redact === false) {
|
|
31
|
+
redactEnabled = false;
|
|
32
|
+
} else if (redact === true || redact === void 0) {
|
|
33
|
+
redactEnabled = true;
|
|
34
|
+
} else if (isRecord(redact)) {
|
|
35
|
+
redactEnabled = true;
|
|
36
|
+
redactionRules = redact.rules;
|
|
37
|
+
}
|
|
38
|
+
const profile = options?.redactionProfile ?? "local";
|
|
39
|
+
const resolvedProfile = resolveRedactionProfile(profile);
|
|
40
|
+
const userMaxMetadata = typeof options?.maxMetadataValueLength === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : void 0;
|
|
41
|
+
const userMaxPreview = typeof options?.maxPreviewLength === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : void 0;
|
|
42
|
+
let maxMetadataValueLength = userMaxMetadata ?? DEFAULT_MAX_METADATA_VALUE_LENGTH;
|
|
43
|
+
let maxPreviewLength = userMaxPreview ?? DEFAULT_MAX_PREVIEW_LENGTH;
|
|
44
|
+
if (redactEnabled && profile !== "local") {
|
|
45
|
+
const capped = applyProfileMetadataCaps(
|
|
46
|
+
maxMetadataValueLength,
|
|
47
|
+
maxPreviewLength,
|
|
48
|
+
resolvedProfile
|
|
49
|
+
);
|
|
50
|
+
maxMetadataValueLength = capped.maxMetadataValueLength;
|
|
51
|
+
maxPreviewLength = capped.maxPreviewLength;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
redactEnabled,
|
|
55
|
+
redactionRules,
|
|
56
|
+
redactionProfile: profile,
|
|
57
|
+
profileExtraKeys: redactEnabled ? resolvedProfile.extraKeys : [],
|
|
58
|
+
maxMetadataValueLength,
|
|
59
|
+
maxPreviewLength,
|
|
60
|
+
maxEventBytes: typeof options?.maxEventBytes === "number" && Number.isFinite(options.maxEventBytes) && options.maxEventBytes > 0 ? Math.floor(options.maxEventBytes) : DEFAULT_MAX_EVENT_BYTES
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function boundMetadataValue(key, value, opts, seen, depth) {
|
|
64
|
+
if (depth > 32) return "[MaxDepth]";
|
|
65
|
+
if (typeof value === "bigint") {
|
|
66
|
+
return `${value.toString()}n`;
|
|
67
|
+
}
|
|
68
|
+
if (typeof value === "function") {
|
|
69
|
+
return "[Function]";
|
|
70
|
+
}
|
|
71
|
+
if (typeof value === "symbol") {
|
|
72
|
+
return "[Symbol]";
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
75
|
+
return String(value);
|
|
76
|
+
}
|
|
77
|
+
if (value === void 0) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (value === null || typeof value !== "object") {
|
|
81
|
+
if (typeof value === "string") {
|
|
82
|
+
const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
|
|
83
|
+
return truncateString(value, max);
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
if (seen.has(value)) return "[Circular]";
|
|
88
|
+
seen.add(value);
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
const maxItems = 50;
|
|
91
|
+
const out2 = value.slice(0, maxItems).map(
|
|
92
|
+
(item, index) => boundMetadataValue(String(index), item, opts, seen, depth + 1)
|
|
93
|
+
);
|
|
94
|
+
if (value.length > maxItems) {
|
|
95
|
+
out2.push(`\u2026(+${value.length - maxItems} more)`);
|
|
96
|
+
}
|
|
97
|
+
return out2;
|
|
98
|
+
}
|
|
99
|
+
const record = value;
|
|
100
|
+
const out = {};
|
|
101
|
+
try {
|
|
102
|
+
for (const [k, v] of Object.entries(record)) {
|
|
103
|
+
out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
return { truncated: true, reason: "metadataEnumerationFailed" };
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
function redactMetadata(metadata, opts) {
|
|
111
|
+
if (!opts.redactEnabled) return { ...metadata };
|
|
112
|
+
const redactor = new Redactor({
|
|
113
|
+
rules: opts.redactionRules,
|
|
114
|
+
extraKeys: opts.profileExtraKeys
|
|
115
|
+
});
|
|
116
|
+
return redactor.redactRecord(metadata);
|
|
117
|
+
}
|
|
118
|
+
function prepareMetadataForDisk(metadata, opts) {
|
|
119
|
+
try {
|
|
120
|
+
const preBounded = boundMetadataValue(
|
|
121
|
+
"metadata",
|
|
122
|
+
metadata,
|
|
123
|
+
opts,
|
|
124
|
+
/* @__PURE__ */ new WeakSet(),
|
|
125
|
+
0
|
|
126
|
+
);
|
|
127
|
+
const redacted = redactMetadata(
|
|
128
|
+
isRecord(preBounded) ? preBounded : {},
|
|
129
|
+
opts
|
|
130
|
+
);
|
|
131
|
+
const bounded = boundMetadataValue(
|
|
132
|
+
"metadata",
|
|
133
|
+
redacted,
|
|
134
|
+
opts,
|
|
135
|
+
/* @__PURE__ */ new WeakSet(),
|
|
136
|
+
0
|
|
137
|
+
);
|
|
138
|
+
return isRecord(bounded) ? bounded : {};
|
|
139
|
+
} catch {
|
|
140
|
+
return { truncated: true, reason: "metadataPreparationFailed" };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function truncateErrorStack(event, maxLen) {
|
|
144
|
+
if (event.event !== "run_completed" && event.event !== "step_completed") {
|
|
145
|
+
return event;
|
|
146
|
+
}
|
|
147
|
+
if (!event.error?.stack || typeof event.error.stack !== "string") {
|
|
148
|
+
return event;
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
...event,
|
|
152
|
+
error: {
|
|
153
|
+
...event.error,
|
|
154
|
+
stack: truncateString(event.error.stack, maxLen)
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function replaceMetadataWithTruncationMarker(event, originalApproxBytes) {
|
|
159
|
+
const marker = {
|
|
160
|
+
truncated: true,
|
|
161
|
+
reason: "maxEventBytes",
|
|
162
|
+
originalApproxBytes
|
|
163
|
+
};
|
|
164
|
+
if (event.event === "run_started") {
|
|
165
|
+
return { ...event, metadata: marker };
|
|
166
|
+
}
|
|
167
|
+
if (event.event === "step_started") {
|
|
168
|
+
return { ...event, metadata: marker };
|
|
169
|
+
}
|
|
170
|
+
return event;
|
|
171
|
+
}
|
|
172
|
+
function shrinkMetadataLimits(opts, factor) {
|
|
173
|
+
return {
|
|
174
|
+
...opts,
|
|
175
|
+
maxMetadataValueLength: Math.max(32, Math.floor(opts.maxMetadataValueLength * factor)),
|
|
176
|
+
maxPreviewLength: Math.max(16, Math.floor(opts.maxPreviewLength * factor))
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function applyMetadataToEvent(event, metadata) {
|
|
180
|
+
if (event.event === "run_started") {
|
|
181
|
+
return { ...event, metadata };
|
|
182
|
+
}
|
|
183
|
+
if (event.event === "step_started") {
|
|
184
|
+
return { ...event, metadata };
|
|
185
|
+
}
|
|
186
|
+
return event;
|
|
187
|
+
}
|
|
188
|
+
function eventHasMetadata(event) {
|
|
189
|
+
return (event.event === "run_started" || event.event === "step_started") && event.metadata !== void 0;
|
|
190
|
+
}
|
|
191
|
+
function getEventMetadata(event) {
|
|
192
|
+
if (event.event === "run_started" || event.event === "step_started") {
|
|
193
|
+
return event.metadata;
|
|
194
|
+
}
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
function prepareTraceEventForDisk(event, opts) {
|
|
198
|
+
try {
|
|
199
|
+
let working = { ...event };
|
|
200
|
+
const rawMetadata = getEventMetadata(working);
|
|
201
|
+
if (rawMetadata !== void 0) {
|
|
202
|
+
const safe = prepareMetadataForDisk(rawMetadata, opts);
|
|
203
|
+
working = applyMetadataToEvent(working, safe);
|
|
204
|
+
}
|
|
205
|
+
let serialized = serializeEvent(working);
|
|
206
|
+
if (serialized === "") {
|
|
207
|
+
return working;
|
|
208
|
+
}
|
|
209
|
+
let bytes = byteLength(serialized);
|
|
210
|
+
if (bytes <= opts.maxEventBytes) {
|
|
211
|
+
return working;
|
|
212
|
+
}
|
|
213
|
+
if (rawMetadata !== void 0) {
|
|
214
|
+
for (const factor of [0.5, 0.25, 0.1]) {
|
|
215
|
+
const tighter = shrinkMetadataLimits(opts, factor);
|
|
216
|
+
const shrunk = prepareMetadataForDisk(rawMetadata, tighter);
|
|
217
|
+
working = applyMetadataToEvent(working, shrunk);
|
|
218
|
+
serialized = serializeEvent(working);
|
|
219
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
220
|
+
return working;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
working = replaceMetadataWithTruncationMarker(working, bytes);
|
|
224
|
+
serialized = serializeEvent(working);
|
|
225
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
226
|
+
return working;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
working = truncateErrorStack(working, Math.min(opts.maxMetadataValueLength, 500));
|
|
230
|
+
serialized = serializeEvent(working);
|
|
231
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
232
|
+
return working;
|
|
233
|
+
}
|
|
234
|
+
if (eventHasMetadata(working)) {
|
|
235
|
+
working = replaceMetadataWithTruncationMarker(working, bytes);
|
|
236
|
+
serialized = serializeEvent(working);
|
|
237
|
+
if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
|
|
238
|
+
return working;
|
|
239
|
+
}
|
|
240
|
+
if (working.event === "run_started") {
|
|
241
|
+
const { metadata: _meta, ...rest } = working;
|
|
242
|
+
working = rest;
|
|
243
|
+
} else if (working.event === "step_started") {
|
|
244
|
+
const { metadata: _meta, ...rest } = working;
|
|
245
|
+
working = rest;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return working;
|
|
249
|
+
} catch {
|
|
250
|
+
if (event.event === "run_started" || event.event === "step_started") {
|
|
251
|
+
return applyMetadataToEvent(event, {
|
|
252
|
+
truncated: true,
|
|
253
|
+
reason: "prepareTraceEventFailed"
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return event;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function safeGet(record, key) {
|
|
260
|
+
try {
|
|
261
|
+
return record[key];
|
|
262
|
+
} catch {
|
|
263
|
+
return void 0;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function optionalBoundedString(value, _key, opts) {
|
|
267
|
+
if (typeof value !== "string") return void 0;
|
|
268
|
+
return truncateString(value, opts.maxMetadataValueLength);
|
|
269
|
+
}
|
|
270
|
+
function requiredBoundedString(value, key, opts) {
|
|
271
|
+
const out = optionalBoundedString(value, key, opts);
|
|
272
|
+
return out && out.length > 0 ? out : void 0;
|
|
273
|
+
}
|
|
274
|
+
function preparePersistedSummaryForDisk(key, value, opts) {
|
|
275
|
+
try {
|
|
276
|
+
const redactor = new Redactor({
|
|
277
|
+
rules: opts.redactionRules,
|
|
278
|
+
extraKeys: opts.profileExtraKeys
|
|
279
|
+
});
|
|
280
|
+
const redacted = opts.redactEnabled ? redactor.redactValue(key, value) : value;
|
|
281
|
+
return boundMetadataValue(key, redacted, opts, /* @__PURE__ */ new WeakSet(), 0);
|
|
282
|
+
} catch {
|
|
283
|
+
return { truncated: true, reason: "summaryPreparationFailed" };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function preparePersistedErrorForDisk(value, opts) {
|
|
287
|
+
if (!isRecord(value)) return void 0;
|
|
288
|
+
try {
|
|
289
|
+
const redactor = new Redactor({
|
|
290
|
+
rules: opts.redactionRules,
|
|
291
|
+
extraKeys: opts.profileExtraKeys
|
|
292
|
+
});
|
|
293
|
+
const rawMessage = safeGet(value, "message");
|
|
294
|
+
const redactedMessage = opts.redactEnabled ? redactor.redactValue("message", rawMessage) : rawMessage;
|
|
295
|
+
const boundedMessage = boundMetadataValue(
|
|
296
|
+
"message",
|
|
297
|
+
redactedMessage,
|
|
298
|
+
opts,
|
|
299
|
+
/* @__PURE__ */ new WeakSet(),
|
|
300
|
+
0
|
|
301
|
+
);
|
|
302
|
+
const message = typeof boundedMessage === "string" && boundedMessage.length > 0 ? boundedMessage : "Unknown error";
|
|
303
|
+
const out = { message };
|
|
304
|
+
const name = optionalBoundedString(safeGet(value, "name"), "name", opts);
|
|
305
|
+
const code = optionalBoundedString(safeGet(value, "code"), "code", opts);
|
|
306
|
+
if (name !== void 0) out.name = name;
|
|
307
|
+
if (code !== void 0) out.code = code;
|
|
308
|
+
return out;
|
|
309
|
+
} catch {
|
|
310
|
+
return { message: "Error preparation failed" };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function prepareTokenUsage(value) {
|
|
314
|
+
if (!isRecord(value)) return void 0;
|
|
315
|
+
const out = {};
|
|
316
|
+
for (const key of ["input", "output", "total", "cached"]) {
|
|
317
|
+
const item = safeGet(value, key);
|
|
318
|
+
if (typeof item === "number" && Number.isFinite(item) && item >= 0) {
|
|
319
|
+
out[key] = item;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
323
|
+
}
|
|
324
|
+
function prepareTraceContext(value, opts) {
|
|
325
|
+
if (!isRecord(value)) return void 0;
|
|
326
|
+
const out = {};
|
|
327
|
+
const traceId = optionalBoundedString(safeGet(value, "traceId"), "traceId", opts);
|
|
328
|
+
const spanId = optionalBoundedString(safeGet(value, "spanId"), "spanId", opts);
|
|
329
|
+
const parentSpanId = optionalBoundedString(
|
|
330
|
+
safeGet(value, "parentSpanId"),
|
|
331
|
+
"parentSpanId",
|
|
332
|
+
opts
|
|
333
|
+
);
|
|
334
|
+
if (traceId !== void 0) out.traceId = traceId;
|
|
335
|
+
if (spanId !== void 0) out.spanId = spanId;
|
|
336
|
+
if (parentSpanId !== void 0) out.parentSpanId = parentSpanId;
|
|
337
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
338
|
+
}
|
|
339
|
+
function serializedPersistedEvent(event) {
|
|
340
|
+
try {
|
|
341
|
+
return JSON.stringify(event);
|
|
342
|
+
} catch {
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function persistedEventByteLength(event) {
|
|
347
|
+
const serialized = serializedPersistedEvent(event);
|
|
348
|
+
return serialized === void 0 ? void 0 : byteLength(serialized);
|
|
349
|
+
}
|
|
350
|
+
function minimalPersistedEvent(event, opts, originalApproxBytes) {
|
|
351
|
+
return {
|
|
352
|
+
schemaVersion: "0.2",
|
|
353
|
+
eventId: truncateString(event.eventId, 128),
|
|
354
|
+
runId: truncateString(event.runId, 128),
|
|
355
|
+
kind: event.kind,
|
|
356
|
+
name: truncateString(event.name, 128),
|
|
357
|
+
...event.status !== void 0 ? { status: event.status } : {},
|
|
358
|
+
timestamp: truncateString(event.timestamp, 128),
|
|
359
|
+
confidence: event.confidence,
|
|
360
|
+
source: {
|
|
361
|
+
type: event.source.type,
|
|
362
|
+
...event.source.name !== void 0 ? { name: truncateString(event.source.name, 128) } : {},
|
|
363
|
+
...event.source.version !== void 0 ? { version: truncateString(event.source.version, 128) } : {}
|
|
364
|
+
},
|
|
365
|
+
attributes: {
|
|
366
|
+
truncated: true,
|
|
367
|
+
reason: "maxEventBytes",
|
|
368
|
+
originalApproxBytes,
|
|
369
|
+
maxEventBytes: opts.maxEventBytes
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function tinyPersistedEvent(event) {
|
|
374
|
+
return {
|
|
375
|
+
schemaVersion: "0.2",
|
|
376
|
+
eventId: truncateString(event.eventId, 32),
|
|
377
|
+
runId: truncateString(event.runId, 32),
|
|
378
|
+
kind: event.kind,
|
|
379
|
+
name: truncateString(event.name, 32),
|
|
380
|
+
timestamp: truncateString(event.timestamp, 32),
|
|
381
|
+
confidence: event.confidence,
|
|
382
|
+
source: { type: event.source.type },
|
|
383
|
+
attributes: { truncated: true, reason: "maxEventBytes" }
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function enforcePersistedEventSize(event, opts) {
|
|
387
|
+
const bytes = persistedEventByteLength(event);
|
|
388
|
+
if (bytes === void 0) return void 0;
|
|
389
|
+
if (bytes <= opts.maxEventBytes) return event;
|
|
390
|
+
const minimal = minimalPersistedEvent(event, opts, bytes);
|
|
391
|
+
const minimalBytes = persistedEventByteLength(minimal);
|
|
392
|
+
if (minimalBytes !== void 0 && minimalBytes <= opts.maxEventBytes) {
|
|
393
|
+
return minimal;
|
|
394
|
+
}
|
|
395
|
+
const tiny = tinyPersistedEvent(event);
|
|
396
|
+
return isPersistedInspectEvent(tiny) ? tiny : void 0;
|
|
397
|
+
}
|
|
398
|
+
function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOptions()) {
|
|
399
|
+
try {
|
|
400
|
+
if (!isRecord(value)) return void 0;
|
|
401
|
+
const source = safeGet(value, "source");
|
|
402
|
+
if (!isRecord(source)) return void 0;
|
|
403
|
+
const candidate = {
|
|
404
|
+
schemaVersion: safeGet(value, "schemaVersion"),
|
|
405
|
+
eventId: requiredBoundedString(safeGet(value, "eventId"), "eventId", opts) ?? "",
|
|
406
|
+
runId: requiredBoundedString(safeGet(value, "runId"), "runId", opts) ?? "",
|
|
407
|
+
kind: safeGet(value, "kind"),
|
|
408
|
+
name: requiredBoundedString(safeGet(value, "name"), "name", opts) ?? "",
|
|
409
|
+
timestamp: requiredBoundedString(safeGet(value, "timestamp"), "timestamp", opts) ?? "",
|
|
410
|
+
confidence: safeGet(value, "confidence"),
|
|
411
|
+
source: {
|
|
412
|
+
type: safeGet(source, "type")
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const parentId = requiredBoundedString(safeGet(value, "parentId"), "parentId", opts);
|
|
416
|
+
const status = safeGet(value, "status");
|
|
417
|
+
const startedAt = optionalBoundedString(safeGet(value, "startedAt"), "startedAt", opts);
|
|
418
|
+
const endedAt = optionalBoundedString(safeGet(value, "endedAt"), "endedAt", opts);
|
|
419
|
+
const durationMs = safeGet(value, "durationMs");
|
|
420
|
+
const sourceName = optionalBoundedString(safeGet(source, "name"), "name", opts);
|
|
421
|
+
const sourceVersion = optionalBoundedString(safeGet(source, "version"), "version", opts);
|
|
422
|
+
if (parentId !== void 0) candidate.parentId = parentId;
|
|
423
|
+
if (status === "running" || status === "ok" || status === "error" || status === "unknown") {
|
|
424
|
+
candidate.status = status;
|
|
425
|
+
}
|
|
426
|
+
if (startedAt !== void 0) candidate.startedAt = startedAt;
|
|
427
|
+
if (endedAt !== void 0) candidate.endedAt = endedAt;
|
|
428
|
+
if (typeof durationMs === "number" && Number.isFinite(durationMs) && durationMs >= 0) {
|
|
429
|
+
candidate.durationMs = durationMs;
|
|
430
|
+
}
|
|
431
|
+
if (sourceName !== void 0) candidate.source.name = sourceName;
|
|
432
|
+
if (sourceVersion !== void 0) candidate.source.version = sourceVersion;
|
|
433
|
+
const attributes = safeGet(value, "attributes");
|
|
434
|
+
if (isRecord(attributes)) {
|
|
435
|
+
candidate.attributes = prepareMetadataForDisk(attributes, opts);
|
|
436
|
+
}
|
|
437
|
+
if (safeGet(value, "inputSummary") !== void 0) {
|
|
438
|
+
candidate.inputSummary = preparePersistedSummaryForDisk(
|
|
439
|
+
"input",
|
|
440
|
+
safeGet(value, "inputSummary"),
|
|
441
|
+
opts
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
if (safeGet(value, "outputSummary") !== void 0) {
|
|
445
|
+
candidate.outputSummary = preparePersistedSummaryForDisk(
|
|
446
|
+
"output",
|
|
447
|
+
safeGet(value, "outputSummary"),
|
|
448
|
+
opts
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
const error = preparePersistedErrorForDisk(safeGet(value, "error"), opts);
|
|
452
|
+
if (error !== void 0) candidate.error = error;
|
|
453
|
+
const tokenUsage = prepareTokenUsage(safeGet(value, "tokenUsage"));
|
|
454
|
+
if (tokenUsage !== void 0) candidate.tokenUsage = tokenUsage;
|
|
455
|
+
const trace = prepareTraceContext(safeGet(value, "trace"), opts);
|
|
456
|
+
if (trace !== void 0) candidate.trace = trace;
|
|
457
|
+
if (!isPersistedInspectEvent(candidate)) return void 0;
|
|
458
|
+
return enforcePersistedEventSize(candidate, opts);
|
|
459
|
+
} catch {
|
|
460
|
+
return void 0;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// packages/core/src/storage.ts
|
|
465
|
+
function isRecord2(value) {
|
|
466
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
467
|
+
}
|
|
468
|
+
function nonEmptyString(value) {
|
|
469
|
+
return typeof value === "string" && value.trim() !== "";
|
|
470
|
+
}
|
|
471
|
+
function finiteNumber(value) {
|
|
472
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
473
|
+
}
|
|
474
|
+
function optionalErrorInfo(value) {
|
|
475
|
+
if (value === void 0) return true;
|
|
476
|
+
if (!isRecord2(value)) return false;
|
|
477
|
+
if (typeof value.message !== "string") return false;
|
|
478
|
+
if ("stack" in value && value.stack !== void 0) {
|
|
479
|
+
if (typeof value.stack !== "string") return false;
|
|
480
|
+
}
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
function validateEvent(event) {
|
|
484
|
+
if (!isRecord2(event)) return false;
|
|
485
|
+
if (event.schemaVersion !== "0.1") return false;
|
|
486
|
+
if (!finiteNumber(event.timestamp)) return false;
|
|
487
|
+
if (typeof event.event !== "string") return false;
|
|
488
|
+
switch (event.event) {
|
|
489
|
+
case "run_started": {
|
|
490
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
case "run_completed": {
|
|
499
|
+
return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
500
|
+
}
|
|
501
|
+
case "step_started": {
|
|
502
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
if (event.parentId !== void 0 && typeof event.parentId !== "string") {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
case "step_completed": {
|
|
514
|
+
return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
515
|
+
}
|
|
516
|
+
default:
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
function serializeEvent(event) {
|
|
521
|
+
try {
|
|
522
|
+
return JSON.stringify(event);
|
|
523
|
+
} catch {
|
|
524
|
+
return "";
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
async function initializeTraceFile(runId, traceDir) {
|
|
528
|
+
try {
|
|
529
|
+
const usable = await ensureTraceDir(traceDir);
|
|
530
|
+
const filePath = getTraceFilePath(runId, usable);
|
|
531
|
+
await writeFile(filePath, "", "utf-8");
|
|
532
|
+
return filePath;
|
|
533
|
+
} catch (e) {
|
|
534
|
+
warn("Failed to initialize trace file", e);
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
const usable = await ensureTraceDir(FALLBACK_TRACE_DIR);
|
|
538
|
+
const filePath = getTraceFilePath(runId, usable);
|
|
539
|
+
await writeFile(filePath, "", "utf-8");
|
|
540
|
+
return filePath;
|
|
541
|
+
} catch (e) {
|
|
542
|
+
warn("Failed to initialize trace file on fallback directory", e);
|
|
543
|
+
return void 0;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function ensureEventWithinBounds(event) {
|
|
547
|
+
const line = serializeEvent(event);
|
|
548
|
+
if (line === "") return event;
|
|
549
|
+
const bytes = Buffer.byteLength(line, "utf8");
|
|
550
|
+
if (bytes <= DEFAULT_MAX_EVENT_BYTES) return event;
|
|
551
|
+
return prepareTraceEventForDisk(event, resolveTraceSafetyOptions());
|
|
552
|
+
}
|
|
553
|
+
async function writeTraceEvent(event, traceDir) {
|
|
554
|
+
const bounded = ensureEventWithinBounds(event);
|
|
555
|
+
if (!validateEvent(bounded)) {
|
|
556
|
+
warn("Skipped invalid trace event (validation failed)");
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
const line = serializeEvent(bounded);
|
|
560
|
+
if (line === "") {
|
|
561
|
+
warn("Skipped trace event (serialization failed)");
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const payload = `${line}
|
|
565
|
+
`;
|
|
566
|
+
const tryAppend = async (dir) => {
|
|
567
|
+
try {
|
|
568
|
+
const usable = await ensureTraceDir(dir);
|
|
569
|
+
const filePath = getTraceFilePath(event.runId, usable);
|
|
570
|
+
await appendFile(filePath, payload, "utf-8");
|
|
571
|
+
return true;
|
|
572
|
+
} catch {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
if (await tryAppend(traceDir)) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
warn(`Failed to append trace event for run ${event.runId}`);
|
|
580
|
+
if (await tryAppend(FALLBACK_TRACE_DIR)) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
warn("Failed to append trace event to fallback directory");
|
|
584
|
+
}
|
|
585
|
+
async function readTraceFile(runId, traceDir) {
|
|
586
|
+
try {
|
|
587
|
+
const filePath = getTraceFilePath(runId, traceDir);
|
|
588
|
+
return await readFile(filePath, "utf-8");
|
|
589
|
+
} catch (e) {
|
|
590
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
591
|
+
return void 0;
|
|
592
|
+
}
|
|
593
|
+
warn("Unexpected error reading trace file", e);
|
|
594
|
+
return void 0;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
async function readTraceEvents(runId, traceDir) {
|
|
598
|
+
try {
|
|
599
|
+
const filePath = getTraceFilePath(runId, traceDir);
|
|
600
|
+
return await readTraceEventsFromFile(filePath);
|
|
601
|
+
} catch (e) {
|
|
602
|
+
warn("Failed to read trace events", e);
|
|
603
|
+
return [];
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
async function readTraceEventsFromFile(filePath) {
|
|
607
|
+
try {
|
|
608
|
+
const raw = await readFile(filePath, "utf-8");
|
|
609
|
+
return parseTraceJsonl(raw, { validate: validateEvent }).events;
|
|
610
|
+
} catch (e) {
|
|
611
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
612
|
+
return [];
|
|
613
|
+
}
|
|
614
|
+
warn("Failed to read trace events from file", e);
|
|
615
|
+
return [];
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async function listTraceFiles(traceDir) {
|
|
619
|
+
try {
|
|
620
|
+
const usable = path.resolve(traceDir);
|
|
621
|
+
const names = await readdir(usable);
|
|
622
|
+
const jsonl = names.filter((n) => n.endsWith(".jsonl"));
|
|
623
|
+
const withStat = await Promise.all(
|
|
624
|
+
jsonl.map(async (name) => {
|
|
625
|
+
try {
|
|
626
|
+
const st = await stat(path.join(usable, name));
|
|
627
|
+
return { name, mtime: st.mtimeMs };
|
|
628
|
+
} catch {
|
|
629
|
+
return { name, mtime: 0 };
|
|
630
|
+
}
|
|
631
|
+
})
|
|
632
|
+
);
|
|
633
|
+
withStat.sort((a, b) => {
|
|
634
|
+
if (b.mtime !== a.mtime) return b.mtime - a.mtime;
|
|
635
|
+
return a.name.localeCompare(b.name);
|
|
636
|
+
});
|
|
637
|
+
return withStat.map((x) => x.name);
|
|
638
|
+
} catch {
|
|
639
|
+
return [];
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function getRunIdFromTraceFileName(fileName) {
|
|
643
|
+
try {
|
|
644
|
+
const base = path.basename(fileName);
|
|
645
|
+
if (!base.endsWith(".jsonl")) return void 0;
|
|
646
|
+
const id = base.slice(0, -".jsonl".length);
|
|
647
|
+
return id === "" ? void 0 : id;
|
|
648
|
+
} catch {
|
|
649
|
+
return void 0;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
export { DEFAULT_MAX_EVENT_BYTES, DEFAULT_MAX_METADATA_VALUE_LENGTH, DEFAULT_MAX_PREVIEW_LENGTH, getRunIdFromTraceFileName, initializeTraceFile, listTraceFiles, prepareMetadataForDisk, preparePersistedInspectEventForWrite, prepareTraceEventForDisk, readTraceEvents, readTraceEventsFromFile, readTraceFile, resolveTraceSafetyOptions, serializeEvent, validateEvent, writeTraceEvent };
|
|
654
|
+
//# sourceMappingURL=chunk-57S5D6HR.mjs.map
|
|
655
|
+
//# sourceMappingURL=chunk-57S5D6HR.mjs.map
|