agent-inspect 1.9.0 → 2.0.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +13 -9
  3. package/docs/ADAPTER-CONFORMANCE.md +1 -1
  4. package/docs/API.md +30 -29
  5. package/docs/CLI.md +41 -11
  6. package/docs/EXPORTS.md +1 -1
  7. package/docs/GETTING-STARTED.md +2 -1
  8. package/docs/KNOWN-ISSUES.md +8 -3
  9. package/docs/LIMITATIONS.md +6 -6
  10. package/docs/MIGRATION.md +8 -8
  11. package/docs/SCHEMA.md +29 -12
  12. package/package.json +1 -1
  13. package/packages/cli/dist/index.cjs +7135 -7481
  14. package/packages/cli/dist/index.cjs.map +1 -1
  15. package/packages/cli/dist/index.mjs +7135 -7481
  16. package/packages/cli/dist/index.mjs.map +1 -1
  17. package/packages/core/dist/advanced.cjs +2047 -26
  18. package/packages/core/dist/advanced.cjs.map +1 -1
  19. package/packages/core/dist/advanced.d.cts +346 -196
  20. package/packages/core/dist/advanced.d.ts +346 -196
  21. package/packages/core/dist/advanced.mjs +628 -5
  22. package/packages/core/dist/advanced.mjs.map +1 -1
  23. package/packages/core/dist/checks.d.cts +1 -1
  24. package/packages/core/dist/checks.d.ts +1 -1
  25. package/packages/core/dist/chunk-2ZXEMWGK.mjs +549 -0
  26. package/packages/core/dist/chunk-2ZXEMWGK.mjs.map +1 -0
  27. package/packages/core/dist/{chunk-57S5D6HR.mjs → chunk-4JVGFNQH.mjs} +50 -6
  28. package/packages/core/dist/chunk-4JVGFNQH.mjs.map +1 -0
  29. package/packages/core/dist/{chunk-6QSLZCBJ.mjs → chunk-A4V2H3YU.mjs} +329 -163
  30. package/packages/core/dist/chunk-A4V2H3YU.mjs.map +1 -0
  31. package/packages/core/dist/{chunk-74XZ6N7Q.mjs → chunk-IZBJAZGF.mjs} +12 -4
  32. package/packages/core/dist/chunk-IZBJAZGF.mjs.map +1 -0
  33. package/packages/core/dist/{chunk-VTIB5MDK.mjs → chunk-NQZPZ2FN.mjs} +15 -10
  34. package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +1 -0
  35. package/packages/core/dist/{chunk-TZISEVLQ.mjs → chunk-XUNJMAPD.mjs} +3 -3
  36. package/packages/core/dist/{chunk-TZISEVLQ.mjs.map → chunk-XUNJMAPD.mjs.map} +1 -1
  37. package/packages/core/dist/context-CSKnzpXR.d.cts +177 -0
  38. package/packages/core/dist/context-yv2VSDQF.d.ts +177 -0
  39. package/packages/core/dist/diff.d.cts +2 -2
  40. package/packages/core/dist/diff.d.ts +2 -2
  41. package/packages/core/dist/diff.mjs +473 -3
  42. package/packages/core/dist/diff.mjs.map +1 -1
  43. package/packages/core/dist/exporters.cjs +691 -0
  44. package/packages/core/dist/exporters.cjs.map +1 -1
  45. package/packages/core/dist/exporters.d.cts +24 -3
  46. package/packages/core/dist/exporters.d.ts +24 -3
  47. package/packages/core/dist/exporters.mjs +1113 -3
  48. package/packages/core/dist/exporters.mjs.map +1 -1
  49. package/packages/core/dist/index.cjs +1385 -8168
  50. package/packages/core/dist/index.cjs.map +1 -1
  51. package/packages/core/dist/index.d.cts +8 -350
  52. package/packages/core/dist/index.d.ts +8 -350
  53. package/packages/core/dist/index.mjs +18 -1478
  54. package/packages/core/dist/index.mjs.map +1 -1
  55. package/packages/core/dist/{log-config-DanPV3P9.d.cts → log-config-8aE5Kxtr.d.cts} +1 -1
  56. package/packages/core/dist/{log-config-BPHS4Sds.d.ts → log-config-DVimQJho.d.ts} +1 -1
  57. package/packages/core/dist/logs.d.cts +2 -2
  58. package/packages/core/dist/logs.d.ts +2 -2
  59. package/packages/core/dist/logs.mjs +785 -2
  60. package/packages/core/dist/logs.mjs.map +1 -1
  61. package/packages/core/dist/{persisted-inspect-event-Cw7TeYGr.d.ts → persisted-inspect-event-D-WpXeZX.d.ts} +14 -5
  62. package/packages/core/dist/{persisted-inspect-event-DHPfzUd8.d.cts → persisted-inspect-event-DHcHPUKv.d.cts} +14 -5
  63. package/packages/core/dist/persisted.cjs +11 -1
  64. package/packages/core/dist/persisted.cjs.map +1 -1
  65. package/packages/core/dist/persisted.d.cts +4 -4
  66. package/packages/core/dist/persisted.d.ts +4 -4
  67. package/packages/core/dist/persisted.mjs +150 -3
  68. package/packages/core/dist/persisted.mjs.map +1 -1
  69. package/packages/core/dist/readers.cjs +27 -10
  70. package/packages/core/dist/readers.cjs.map +1 -1
  71. package/packages/core/dist/readers.d.cts +1 -1
  72. package/packages/core/dist/readers.d.ts +1 -1
  73. package/packages/core/dist/readers.mjs +1580 -4
  74. package/packages/core/dist/readers.mjs.map +1 -1
  75. package/packages/core/dist/{types-Ap9uMdx_.d.ts → types-D-Y1kOU-.d.ts} +2 -2
  76. package/packages/core/dist/{types-B2-BU5CS.d.cts → types-DgMN3qow.d.cts} +2 -2
  77. package/packages/core/dist/writers.cjs +49 -3
  78. package/packages/core/dist/writers.cjs.map +1 -1
  79. package/packages/core/dist/writers.d.cts +1 -1
  80. package/packages/core/dist/writers.d.ts +1 -1
  81. package/packages/core/dist/writers.mjs +341 -4
  82. package/packages/core/dist/writers.mjs.map +1 -1
  83. package/packages/core/dist/chunk-57S5D6HR.mjs.map +0 -1
  84. package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +0 -1
  85. package/packages/core/dist/chunk-6SZPTECC.mjs +0 -342
  86. package/packages/core/dist/chunk-6SZPTECC.mjs.map +0 -1
  87. package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +0 -1
  88. package/packages/core/dist/chunk-HR7G62IE.mjs +0 -785
  89. package/packages/core/dist/chunk-HR7G62IE.mjs.map +0 -1
  90. package/packages/core/dist/chunk-TFLPUZ56.mjs +0 -1571
  91. package/packages/core/dist/chunk-TFLPUZ56.mjs.map +0 -1
  92. package/packages/core/dist/chunk-U2BGPESY.mjs +0 -150
  93. package/packages/core/dist/chunk-U2BGPESY.mjs.map +0 -1
  94. package/packages/core/dist/chunk-VTIB5MDK.mjs.map +0 -1
  95. package/packages/core/dist/chunk-Y56BPA3B.mjs +0 -990
  96. package/packages/core/dist/chunk-Y56BPA3B.mjs.map +0 -1
  97. package/packages/core/dist/chunk-YWAOOXLR.mjs +0 -475
  98. package/packages/core/dist/chunk-YWAOOXLR.mjs.map +0 -1
@@ -1,9 +1,1585 @@
1
- export { DEFAULT_TRACE_READERS, TraceReadError, agentInspectJsonlReader, detectTraceFormat, openInferenceJsonReader, openTrace, otlpJsonReader, readTrace } from './chunk-TFLPUZ56.mjs';
2
- import './chunk-TZISEVLQ.mjs';
1
+ import { persistedInspectEventsToRunTrees, traceEventToPersistedInspectEvent, traceEventsToPersistedInspectEvents } from './chunk-XUNJMAPD.mjs';
3
2
  import './chunk-S4YWKV4G.mjs';
4
3
  import './chunk-E5F2LQCX.mjs';
5
- import './chunk-VTIB5MDK.mjs';
6
- import './chunk-74XZ6N7Q.mjs';
4
+ import { parseTraceJsonl } from './chunk-NQZPZ2FN.mjs';
5
+ import './chunk-IZBJAZGF.mjs';
7
6
  import './chunk-7TGZLWEE.mjs';
7
+ import { readFile, readdir } from 'fs/promises';
8
+ import path from 'path';
9
+
10
+ var DEFAULT_MAX_TRACE_INPUT_BYTES = 10 * 1024 * 1024;
11
+ var MIN_DETECTION_CONFIDENCE = 0.5;
12
+ var AMBIGUOUS_CONFIDENCE_DELTA = 0.05;
13
+ var resolvedInputCache = /* @__PURE__ */ new WeakMap();
14
+ var OPENINFERENCE_READER_FORMAT = "openinference-json";
15
+ var OTLP_READER_FORMAT = "otlp-json";
16
+ var OPENINFERENCE_SPAN_KEYS = /* @__PURE__ */ new Set([
17
+ "trace_id",
18
+ "traceId",
19
+ "span_id",
20
+ "spanId",
21
+ "parent_span_id",
22
+ "parentSpanId",
23
+ "name",
24
+ "start_time_unix_nano",
25
+ "startTimeUnixNano",
26
+ "end_time_unix_nano",
27
+ "endTimeUnixNano",
28
+ "start_time",
29
+ "startTime",
30
+ "end_time",
31
+ "endTime",
32
+ "attributes",
33
+ "status",
34
+ "kind",
35
+ "span_kind",
36
+ "spanKind"
37
+ ]);
38
+ var OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS = [
39
+ "input.value",
40
+ "output.value",
41
+ "input.mime_type",
42
+ "output.mime_type",
43
+ "llm.input_messages",
44
+ "llm.output_messages",
45
+ "llm.prompts",
46
+ "llm.completions",
47
+ "retrieval.documents",
48
+ "reranker.input_documents",
49
+ "reranker.output_documents",
50
+ "document.content",
51
+ "gen_ai.prompt",
52
+ "gen_ai.completion",
53
+ "gen_ai.input.messages",
54
+ "gen_ai.output.messages"
55
+ ];
56
+ var OTLP_SPAN_KEYS = /* @__PURE__ */ new Set([
57
+ "traceId",
58
+ "spanId",
59
+ "parentSpanId",
60
+ "name",
61
+ "kind",
62
+ "startTimeUnixNano",
63
+ "endTimeUnixNano",
64
+ "attributes",
65
+ "events",
66
+ "status",
67
+ "droppedAttributesCount",
68
+ "droppedEventsCount",
69
+ "droppedLinksCount",
70
+ "links",
71
+ "flags"
72
+ ]);
73
+ var TraceReadError = class extends Error {
74
+ code;
75
+ warnings;
76
+ constructor(code, message, warnings = []) {
77
+ super(message);
78
+ this.name = "TraceReadError";
79
+ this.code = code;
80
+ this.warnings = warnings;
81
+ }
82
+ };
83
+ function normalizeCandidate(reader, candidate) {
84
+ const confidence = Number.isFinite(candidate.confidence) ? Math.max(0, Math.min(1, candidate.confidence)) : 0;
85
+ return {
86
+ ...candidate,
87
+ format: candidate.format || reader.format,
88
+ confidence,
89
+ readerName: candidate.readerName ?? reader.name
90
+ };
91
+ }
92
+ function sortCandidates(candidates) {
93
+ return [...candidates].sort((a, b) => {
94
+ if (b.confidence !== a.confidence) return b.confidence - a.confidence;
95
+ return a.format.localeCompare(b.format);
96
+ });
97
+ }
98
+ function collectWarnings(candidates) {
99
+ return candidates.flatMap((candidate) => candidate.warnings ?? []);
100
+ }
101
+ function dedupeWarnings(warnings) {
102
+ const seen = /* @__PURE__ */ new Set();
103
+ const out = [];
104
+ for (const warning of warnings) {
105
+ const key = [
106
+ warning.code,
107
+ warning.message,
108
+ warning.severity ?? "",
109
+ warning.sourceFile ?? "",
110
+ warning.line ?? "",
111
+ warning.field ?? ""
112
+ ].join("\0");
113
+ if (seen.has(key)) continue;
114
+ seen.add(key);
115
+ out.push(warning);
116
+ }
117
+ return out;
118
+ }
119
+ function attachSingleSourceFile(warnings, resolved) {
120
+ if (resolved.sourceFiles.length !== 1) return [...warnings];
121
+ const [sourceFile] = resolved.sourceFiles;
122
+ return warnings.map((warning) => ({
123
+ ...warning,
124
+ sourceFile: warning.sourceFile ?? sourceFile
125
+ }));
126
+ }
127
+ function findReaderByFormat(format, readers) {
128
+ return readers.find((reader) => reader.format === format);
129
+ }
130
+ async function jsonlFilesInDirectory(dirPath) {
131
+ const entries = await readdir(dirPath, { withFileTypes: true });
132
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
133
+ }
134
+ async function resolveInput(input) {
135
+ const cached = resolvedInputCache.get(input);
136
+ if (cached) return cached;
137
+ const promise = resolveInputUncached(input);
138
+ resolvedInputCache.set(input, promise);
139
+ return promise;
140
+ }
141
+ function assertInputWithinBounds(content, sourceFile) {
142
+ const bytes = Buffer.byteLength(content, "utf8");
143
+ if (bytes <= DEFAULT_MAX_TRACE_INPUT_BYTES) return;
144
+ throw new TraceReadError("unsupported_format", "Trace input exceeds the local reader size limit.", [
145
+ {
146
+ code: "input_too_large",
147
+ message: `Trace input is ${bytes} bytes; max is ${DEFAULT_MAX_TRACE_INPUT_BYTES} bytes.`,
148
+ severity: "error",
149
+ ...sourceFile !== void 0 ? { sourceFile } : {}
150
+ }
151
+ ]);
152
+ }
153
+ async function resolveInputUncached(input) {
154
+ if (input.type === "string") {
155
+ assertInputWithinBounds(input.content);
156
+ return { content: input.content, sourceFiles: [] };
157
+ }
158
+ if (input.type === "buffer") {
159
+ const content = input.content.toString("utf-8");
160
+ assertInputWithinBounds(content);
161
+ return { content, sourceFiles: [] };
162
+ }
163
+ if (input.type === "file") {
164
+ const content = await readFile(input.path, "utf-8");
165
+ assertInputWithinBounds(content, input.path);
166
+ return { content, sourceFiles: [input.path] };
167
+ }
168
+ if (input.type === "directory") {
169
+ const files = await jsonlFilesInDirectory(input.path);
170
+ const parts = await Promise.all(
171
+ files.map(async (file) => (await readFile(file, "utf-8")).trimEnd())
172
+ );
173
+ const content = parts.filter((part) => part.trim() !== "").join("\n");
174
+ assertInputWithinBounds(content, input.path);
175
+ return {
176
+ content,
177
+ sourceFiles: files
178
+ };
179
+ }
180
+ return void 0;
181
+ }
182
+ function detectJsonlFormat(content) {
183
+ let saw01 = false;
184
+ let saw02 = false;
185
+ let saw10 = false;
186
+ let validRows = 0;
187
+ let invalidJsonRows = 0;
188
+ let unknownSchemaRows = 0;
189
+ let firstInvalidJsonLine;
190
+ let firstUnknownSchemaLine;
191
+ let lineNumber = 0;
192
+ for (const line of content.split(/\r?\n/)) {
193
+ lineNumber += 1;
194
+ const trimmed = line.trim();
195
+ if (trimmed === "") continue;
196
+ let parsed;
197
+ try {
198
+ parsed = JSON.parse(trimmed);
199
+ } catch {
200
+ invalidJsonRows += 1;
201
+ firstInvalidJsonLine ??= lineNumber;
202
+ continue;
203
+ }
204
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && "schemaVersion" in parsed) {
205
+ const version = parsed.schemaVersion;
206
+ if (version === "0.1") {
207
+ saw01 = true;
208
+ validRows += 1;
209
+ continue;
210
+ }
211
+ if (version === "0.2") {
212
+ saw02 = true;
213
+ validRows += 1;
214
+ continue;
215
+ }
216
+ if (version === "1.0") {
217
+ saw10 = true;
218
+ validRows += 1;
219
+ continue;
220
+ }
221
+ }
222
+ unknownSchemaRows += 1;
223
+ firstUnknownSchemaLine ??= lineNumber;
224
+ }
225
+ const warnings = [];
226
+ if (invalidJsonRows > 0) {
227
+ warnings.push({
228
+ code: "invalid_jsonl_rows",
229
+ message: `Skipped ${invalidJsonRows} invalid JSONL row(s) during format detection.`,
230
+ severity: "warning",
231
+ ...firstInvalidJsonLine !== void 0 ? { line: firstInvalidJsonLine } : {}
232
+ });
233
+ }
234
+ if (unknownSchemaRows > 0) {
235
+ warnings.push({
236
+ code: "unknown_schema_rows",
237
+ message: `Skipped ${unknownSchemaRows} row(s) with unknown schemaVersion during format detection.`,
238
+ severity: "warning",
239
+ ...firstUnknownSchemaLine !== void 0 ? { line: firstUnknownSchemaLine } : {}
240
+ });
241
+ }
242
+ let format = "empty";
243
+ const seenFormats = [saw01, saw02, saw10].filter(Boolean).length;
244
+ if (seenFormats > 1) format = "mixed";
245
+ else if (saw01) format = "0.1";
246
+ else if (saw02) format = "0.2";
247
+ else if (saw10) format = "1.0";
248
+ return { format, validRows, warnings };
249
+ }
250
+ function agentInspectFormatLabel(format) {
251
+ switch (format) {
252
+ case "0.1":
253
+ return "agent-inspect-v0.1-jsonl";
254
+ case "0.2":
255
+ return "agent-inspect-v0.2-jsonl";
256
+ case "1.0":
257
+ return "agent-inspect-v1.0-jsonl";
258
+ case "mixed":
259
+ return "agent-inspect-mixed-jsonl";
260
+ default:
261
+ return "agent-inspect-jsonl";
262
+ }
263
+ }
264
+ function persistedEventsForParsedTrace(parsed) {
265
+ if ((parsed.format === "0.2" || parsed.format === "1.0") && parsed.persisted.length > 0) {
266
+ return [...parsed.persisted];
267
+ }
268
+ if (parsed.format === "mixed" && parsed.rows.length > 0) {
269
+ return parsed.rows.map((row, index) => {
270
+ if (row.format === "0.2" || row.format === "1.0") return row.event;
271
+ return traceEventToPersistedInspectEvent(row.event, {
272
+ eventIndex: index,
273
+ sourceName: "agent-inspect-jsonl-reader"
274
+ });
275
+ });
276
+ }
277
+ return traceEventsToPersistedInspectEvents(parsed.events, {
278
+ sourceName: "agent-inspect-jsonl-reader"
279
+ });
280
+ }
281
+ function isRecord(value) {
282
+ return typeof value === "object" && value !== null && !Array.isArray(value);
283
+ }
284
+ function isNonEmptyString(value) {
285
+ return typeof value === "string" && value.trim() !== "";
286
+ }
287
+ function readStringField(record, keys) {
288
+ for (const key of keys) {
289
+ const value = record[key];
290
+ if (isNonEmptyString(value)) return value;
291
+ }
292
+ return void 0;
293
+ }
294
+ function readRecordField(record, key) {
295
+ const value = record[key];
296
+ return isRecord(value) ? value : void 0;
297
+ }
298
+ function parseJsonDocument(content) {
299
+ return JSON.parse(content);
300
+ }
301
+ function looksLikeOpenInferenceSpan(value) {
302
+ if (!isRecord(value)) return false;
303
+ const attributes = readRecordField(value, "attributes");
304
+ return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
305
+ }
306
+ function extractOpenInferenceDocument(root) {
307
+ const warnings = [];
308
+ const unsupportedFields = [];
309
+ if (Array.isArray(root)) {
310
+ const spans = root.filter(looksLikeOpenInferenceSpan);
311
+ if (spans.length === 0) return void 0;
312
+ if (spans.length !== root.length) {
313
+ warnings.push({
314
+ code: "openinference_skipped_items",
315
+ message: "Skipped non-span item(s) in OpenInference span array.",
316
+ severity: "warning"
317
+ });
318
+ }
319
+ return {
320
+ spans,
321
+ confidence: 0.82,
322
+ description: "OpenInference span array",
323
+ warnings,
324
+ unsupportedFields
325
+ };
326
+ }
327
+ if (!isRecord(root)) return void 0;
328
+ const rootFormat = root.format;
329
+ const rootCompatibility = root.compatibility;
330
+ const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
331
+ if (Array.isArray(root.spans)) {
332
+ const spans = root.spans.filter(looksLikeOpenInferenceSpan);
333
+ if (spans.length === 0 && (rootFormat === "openinference" || rootCompatibility === "openinference-compatible")) {
334
+ warnings.push({
335
+ code: "openinference_no_valid_spans",
336
+ message: "OpenInference document did not contain any valid spans.",
337
+ severity: "error"
338
+ });
339
+ return {
340
+ spans,
341
+ confidence: 0.7,
342
+ description: "Malformed OpenInference document",
343
+ version,
344
+ warnings,
345
+ unsupportedFields
346
+ };
347
+ }
348
+ if (spans.length === 0) return void 0;
349
+ if (spans.length !== root.spans.length) {
350
+ warnings.push({
351
+ code: "openinference_skipped_spans",
352
+ message: "Skipped invalid OpenInference span item(s).",
353
+ severity: "warning"
354
+ });
355
+ }
356
+ return {
357
+ spans,
358
+ confidence: rootFormat === "openinference" || rootCompatibility === "openinference-compatible" ? 0.9 : 0.84,
359
+ description: rootFormat === "openinference" || rootCompatibility === "openinference-compatible" ? "OpenInference document" : "OpenInference spans document",
360
+ version,
361
+ warnings,
362
+ unsupportedFields
363
+ };
364
+ }
365
+ if (Array.isArray(root.data)) {
366
+ const spans = root.data.filter(looksLikeOpenInferenceSpan);
367
+ if (spans.length === 0) return void 0;
368
+ if (spans.length !== root.data.length) {
369
+ warnings.push({
370
+ code: "openinference_skipped_data_items",
371
+ message: "Skipped non-span item(s) in OpenInference data array.",
372
+ severity: "warning"
373
+ });
374
+ }
375
+ return {
376
+ spans,
377
+ confidence: 0.8,
378
+ description: "OpenInference data document",
379
+ version,
380
+ warnings,
381
+ unsupportedFields
382
+ };
383
+ }
384
+ if (looksLikeOpenInferenceSpan(root)) {
385
+ return {
386
+ spans: [root],
387
+ confidence: 0.76,
388
+ description: "OpenInference single span",
389
+ version,
390
+ warnings,
391
+ unsupportedFields
392
+ };
393
+ }
394
+ if (rootFormat === "openinference" || rootCompatibility === "openinference-compatible") {
395
+ warnings.push({
396
+ code: "openinference_missing_spans",
397
+ message: "OpenInference document is missing a spans array.",
398
+ severity: "error"
399
+ });
400
+ return {
401
+ spans: [],
402
+ confidence: 0.7,
403
+ description: "Malformed OpenInference document",
404
+ version,
405
+ warnings,
406
+ unsupportedFields
407
+ };
408
+ }
409
+ return void 0;
410
+ }
411
+ function parseUnixNanoToIso(value) {
412
+ if (typeof value === "bigint" && value >= 0n) {
413
+ return new Date(Number(value / 1000000n)).toISOString();
414
+ }
415
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
416
+ return new Date(Math.floor(value / 1e6)).toISOString();
417
+ }
418
+ if (typeof value === "string" && /^\d+$/.test(value)) {
419
+ return new Date(Number(BigInt(value) / 1000000n)).toISOString();
420
+ }
421
+ return void 0;
422
+ }
423
+ function parseIsoTime(value) {
424
+ if (!isNonEmptyString(value)) return void 0;
425
+ const ms = Date.parse(value);
426
+ if (!Number.isFinite(ms)) return void 0;
427
+ return new Date(ms).toISOString();
428
+ }
429
+ function readOpenInferenceTimestamp(span, nanoKeys, isoKeys) {
430
+ for (const key of nanoKeys) {
431
+ const iso = parseUnixNanoToIso(span[key]);
432
+ if (iso !== void 0) return iso;
433
+ }
434
+ for (const key of isoKeys) {
435
+ const iso = parseIsoTime(span[key]);
436
+ if (iso !== void 0) return iso;
437
+ }
438
+ return void 0;
439
+ }
440
+ function durationBetweenIso(startedAt, endedAt) {
441
+ if (startedAt === void 0 || endedAt === void 0) return void 0;
442
+ const startMs = Date.parse(startedAt);
443
+ const endMs = Date.parse(endedAt);
444
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs < startMs) {
445
+ return void 0;
446
+ }
447
+ return endMs - startMs;
448
+ }
449
+ function isSensitiveOpenInferenceAttribute(key) {
450
+ return OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS.some(
451
+ (sensitiveKey) => key === sensitiveKey || key.startsWith(`${sensitiveKey}.`) || key.endsWith(".message.content") || key.endsWith(".document.content")
452
+ );
453
+ }
454
+ function summarizeAttributeValue(value) {
455
+ if (typeof value === "string") {
456
+ return { type: "string", length: value.length };
457
+ }
458
+ if (typeof value === "number") {
459
+ return { type: "number", finite: Number.isFinite(value) };
460
+ }
461
+ if (typeof value === "boolean") {
462
+ return { type: "boolean" };
463
+ }
464
+ if (Array.isArray(value)) {
465
+ return { type: "array", length: value.length };
466
+ }
467
+ if (isRecord(value)) {
468
+ return { type: "object", keyCount: Object.keys(value).length };
469
+ }
470
+ if (value === null) {
471
+ return { type: "null" };
472
+ }
473
+ return { type: typeof value };
474
+ }
475
+ function sanitizeOpenInferenceAttributes(attributes, pathPrefix) {
476
+ const out = {};
477
+ const warnings = [];
478
+ const unsupportedFields = [];
479
+ const summarizedKeys = [];
480
+ for (const [key, value] of Object.entries(attributes)) {
481
+ if (isSensitiveOpenInferenceAttribute(key)) {
482
+ summarizedKeys.push(key);
483
+ out[`${key}.summary`] = summarizeAttributeValue(value);
484
+ unsupportedFields.push(`${pathPrefix}.attributes.${key}`);
485
+ continue;
486
+ }
487
+ out[key] = value;
488
+ }
489
+ if (summarizedKeys.length > 0) {
490
+ out["openinference.summarized_attributes"] = summarizedKeys;
491
+ warnings.push({
492
+ code: "openinference_sensitive_attribute_summarized",
493
+ message: "OpenInference prompt/output/document attribute(s) were summarized instead of copied verbatim.",
494
+ severity: "warning"
495
+ });
496
+ }
497
+ return { attributes: out, warnings, unsupportedFields };
498
+ }
499
+ function mapOpenInferenceKind(span, attributes, pathPrefix) {
500
+ const warnings = [];
501
+ const agentInspectKind = attributes["agent_inspect.kind"];
502
+ if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
503
+ return { kind: agentInspectKind, warnings };
504
+ }
505
+ const rawKind = readStringField(span, ["kind", "span_kind", "spanKind"]) ?? (typeof attributes["openinference.span.kind"] === "string" ? attributes["openinference.span.kind"] : void 0);
506
+ const normalized = rawKind?.toUpperCase();
507
+ switch (normalized) {
508
+ case "LLM":
509
+ return { kind: "LLM", warnings };
510
+ case "TOOL":
511
+ return { kind: "TOOL", warnings };
512
+ case "CHAIN":
513
+ return { kind: "CHAIN", warnings };
514
+ case "RETRIEVER":
515
+ return { kind: "RETRIEVER", warnings };
516
+ case "AGENT":
517
+ return { kind: "AGENT", warnings };
518
+ case "EMBEDDING":
519
+ warnings.push({
520
+ code: "openinference_kind_semantic_loss",
521
+ message: "OpenInference EMBEDDING span kind mapped to AgentInspect LLM.",
522
+ severity: "warning",
523
+ field: `${pathPrefix}.attributes.openinference.span.kind`
524
+ });
525
+ return { kind: "LLM", warnings };
526
+ case "RERANKER":
527
+ warnings.push({
528
+ code: "openinference_kind_semantic_loss",
529
+ message: "OpenInference RERANKER span kind mapped to AgentInspect RETRIEVER.",
530
+ severity: "warning",
531
+ field: `${pathPrefix}.attributes.openinference.span.kind`
532
+ });
533
+ return { kind: "RETRIEVER", warnings };
534
+ case "UNKNOWN":
535
+ case void 0:
536
+ warnings.push({
537
+ code: "openinference_kind_unknown",
538
+ message: "OpenInference span kind was missing or unknown; mapped to AgentInspect LOGIC.",
539
+ severity: "warning",
540
+ field: `${pathPrefix}.attributes.openinference.span.kind`
541
+ });
542
+ return { kind: "LOGIC", warnings };
543
+ default:
544
+ warnings.push({
545
+ code: "openinference_kind_unsupported",
546
+ message: `Unsupported OpenInference span kind "${rawKind}" mapped to AgentInspect LOGIC.`,
547
+ severity: "warning",
548
+ field: `${pathPrefix}.attributes.openinference.span.kind`
549
+ });
550
+ return { kind: "LOGIC", warnings };
551
+ }
552
+ }
553
+ function mapOpenInferenceStatus(status) {
554
+ if (!isRecord(status)) return void 0;
555
+ const rawCode = status.code;
556
+ if (typeof rawCode !== "string") return void 0;
557
+ switch (rawCode.toUpperCase()) {
558
+ case "OK":
559
+ return "ok";
560
+ case "ERROR":
561
+ return "error";
562
+ case "UNSET":
563
+ return "unknown";
564
+ default:
565
+ return "unknown";
566
+ }
567
+ }
568
+ function readOpenInferenceTokenUsage(attributes) {
569
+ const prompt = attributes["llm.token_count.prompt"];
570
+ const completion = attributes["llm.token_count.completion"];
571
+ const total = attributes["llm.token_count.total"];
572
+ const cached = attributes["llm.token_count.prompt_details.cache_read"];
573
+ const usage = {};
574
+ if (typeof prompt === "number" && Number.isFinite(prompt) && prompt >= 0) {
575
+ usage.input = prompt;
576
+ }
577
+ if (typeof completion === "number" && Number.isFinite(completion) && completion >= 0) {
578
+ usage.output = completion;
579
+ }
580
+ if (typeof total === "number" && Number.isFinite(total) && total >= 0) {
581
+ usage.total = total;
582
+ }
583
+ if (typeof cached === "number" && Number.isFinite(cached) && cached >= 0) {
584
+ usage.cached = cached;
585
+ }
586
+ if (usage.total === void 0 && usage.input !== void 0 && usage.output !== void 0) {
587
+ usage.total = usage.input + usage.output;
588
+ }
589
+ return Object.keys(usage).length > 0 ? usage : void 0;
590
+ }
591
+ function readOpenInferenceConfidence(attributes) {
592
+ const confidence = attributes["agent_inspect.confidence"];
593
+ if (confidence === "explicit" || confidence === "correlated" || confidence === "heuristic" || confidence === "unknown") {
594
+ return confidence;
595
+ }
596
+ return "correlated";
597
+ }
598
+ function mapOpenInferenceSpan(span, index, version) {
599
+ const pathPrefix = `spans[${index}]`;
600
+ const warnings = [];
601
+ const unsupportedFields = [];
602
+ const rawAttributes = readRecordField(span, "attributes") ?? {};
603
+ const sanitized = sanitizeOpenInferenceAttributes(rawAttributes, pathPrefix);
604
+ warnings.push(...sanitized.warnings);
605
+ unsupportedFields.push(...sanitized.unsupportedFields);
606
+ const attributes = { ...sanitized.attributes };
607
+ for (const [key, value] of Object.entries(span)) {
608
+ if (OPENINFERENCE_SPAN_KEYS.has(key)) continue;
609
+ unsupportedFields.push(`${pathPrefix}.${key}`);
610
+ if (value === null || typeof value !== "object") {
611
+ attributes[`openinference.${key}`] = value;
612
+ } else {
613
+ attributes[`openinference.${key}.summary`] = summarizeAttributeValue(value);
614
+ warnings.push({
615
+ code: "openinference_unsupported_field_summarized",
616
+ message: `Unsupported OpenInference span field "${key}" was summarized.`,
617
+ severity: "warning",
618
+ field: `${pathPrefix}.${key}`
619
+ });
620
+ }
621
+ }
622
+ const traceId = readStringField(span, ["trace_id", "traceId"]) ?? `trace-${index}`;
623
+ const spanId = readStringField(span, ["span_id", "spanId"]) ?? `span-${index}`;
624
+ const parentSpanId = readStringField(span, ["parent_span_id", "parentSpanId"]);
625
+ const name = readStringField(span, ["name"]) ?? spanId;
626
+ const startedAt = readOpenInferenceTimestamp(
627
+ span,
628
+ ["start_time_unix_nano", "startTimeUnixNano"],
629
+ ["start_time", "startTime"]
630
+ );
631
+ const endedAt = readOpenInferenceTimestamp(
632
+ span,
633
+ ["end_time_unix_nano", "endTimeUnixNano"],
634
+ ["end_time", "endTime"]
635
+ );
636
+ const timestamp = startedAt ?? "1970-01-01T00:00:00.000Z";
637
+ if (startedAt === void 0) {
638
+ warnings.push({
639
+ code: "openinference_missing_start_time",
640
+ message: "OpenInference span is missing a valid start time; using Unix epoch.",
641
+ severity: "warning",
642
+ field: `${pathPrefix}.start_time_unix_nano`
643
+ });
644
+ unsupportedFields.push(`${pathPrefix}.start_time_unix_nano`);
645
+ }
646
+ const { kind, warnings: kindWarnings } = mapOpenInferenceKind(
647
+ span,
648
+ rawAttributes,
649
+ pathPrefix
650
+ );
651
+ warnings.push(...kindWarnings);
652
+ const status = mapOpenInferenceStatus(span.status);
653
+ const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
654
+ const errorMessage = isRecord(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
655
+ const event = {
656
+ schemaVersion: "0.2",
657
+ eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
658
+ runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
659
+ kind,
660
+ name,
661
+ timestamp,
662
+ confidence: readOpenInferenceConfidence(rawAttributes),
663
+ source: {
664
+ type: "otel",
665
+ name: "openinference",
666
+ ...version !== void 0 ? { version } : {}
667
+ },
668
+ attributes,
669
+ trace: {
670
+ traceId,
671
+ spanId,
672
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
673
+ }
674
+ };
675
+ if (status !== void 0) {
676
+ event.status = status;
677
+ }
678
+ if (startedAt !== void 0) {
679
+ event.startedAt = startedAt;
680
+ }
681
+ if (endedAt !== void 0) {
682
+ event.endedAt = endedAt;
683
+ }
684
+ const durationMs = durationBetweenIso(startedAt, endedAt);
685
+ if (durationMs !== void 0) {
686
+ event.durationMs = durationMs;
687
+ }
688
+ if (tokenUsage !== void 0) {
689
+ event.tokenUsage = tokenUsage;
690
+ }
691
+ if (status === "error") {
692
+ event.error = {
693
+ message: errorMessage !== void 0 && errorMessage.trim() !== "" ? errorMessage : "OpenInference span error"
694
+ };
695
+ }
696
+ return {
697
+ event,
698
+ warnings,
699
+ unsupportedFields,
700
+ spanId,
701
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
702
+ };
703
+ }
704
+ function mapOpenInferenceEvents(document) {
705
+ const mapped = document.spans.map(
706
+ (span, index) => mapOpenInferenceSpan(span, index, document.version)
707
+ );
708
+ const spanIdToEventId = new Map(
709
+ mapped.map((span) => [span.spanId, span.event.eventId])
710
+ );
711
+ for (const span of mapped) {
712
+ if (span.parentSpanId === void 0) continue;
713
+ span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
714
+ }
715
+ return {
716
+ events: mapped.map((span) => span.event),
717
+ warnings: mapped.flatMap((span) => span.warnings),
718
+ unsupportedFields: mapped.flatMap((span) => span.unsupportedFields)
719
+ };
720
+ }
721
+ var openInferenceJsonReader = {
722
+ format: OPENINFERENCE_READER_FORMAT,
723
+ name: "OpenInference JSON",
724
+ async detect(input) {
725
+ const resolved = await resolveInput(input);
726
+ if (!resolved) return void 0;
727
+ let parsed;
728
+ try {
729
+ parsed = parseJsonDocument(resolved.content);
730
+ } catch {
731
+ return void 0;
732
+ }
733
+ const document = extractOpenInferenceDocument(parsed);
734
+ if (!document) return void 0;
735
+ return {
736
+ format: OPENINFERENCE_READER_FORMAT,
737
+ confidence: document.confidence,
738
+ readerName: "OpenInference JSON",
739
+ description: document.description,
740
+ warnings: attachSingleSourceFile(document.warnings, resolved)
741
+ };
742
+ },
743
+ async read(input) {
744
+ const resolved = await resolveInput(input);
745
+ if (!resolved) {
746
+ throw new TraceReadError(
747
+ "unsupported_format",
748
+ "OpenInference JSON reader requires file, string, or buffer input."
749
+ );
750
+ }
751
+ let parsed;
752
+ try {
753
+ parsed = parseJsonDocument(resolved.content);
754
+ } catch {
755
+ throw new TraceReadError("unsupported_format", "OpenInference JSON input is not valid JSON.", [
756
+ {
757
+ code: "openinference_invalid_json",
758
+ message: "OpenInference JSON reader could not parse the input as JSON.",
759
+ severity: "error"
760
+ }
761
+ ]);
762
+ }
763
+ const document = extractOpenInferenceDocument(parsed);
764
+ if (!document || document.spans.length === 0) {
765
+ throw new TraceReadError(
766
+ "unsupported_format",
767
+ "No valid OpenInference spans found.",
768
+ attachSingleSourceFile(
769
+ document?.warnings ?? [
770
+ {
771
+ code: "openinference_no_valid_spans",
772
+ message: "OpenInference JSON input did not contain valid spans.",
773
+ severity: "error"
774
+ }
775
+ ],
776
+ resolved
777
+ )
778
+ );
779
+ }
780
+ const mapped = mapOpenInferenceEvents(document);
781
+ const warnings = attachSingleSourceFile(
782
+ [...document.warnings, ...mapped.warnings],
783
+ resolved
784
+ );
785
+ const unsupportedFields = [
786
+ ...document.unsupportedFields,
787
+ ...mapped.unsupportedFields
788
+ ].sort((a, b) => a.localeCompare(b));
789
+ return {
790
+ format: OPENINFERENCE_READER_FORMAT,
791
+ events: mapped.events,
792
+ runs: persistedInspectEventsToRunTrees(mapped.events, { skipInvalid: true }),
793
+ warnings,
794
+ unsupportedFields,
795
+ sourceFiles: resolved.sourceFiles
796
+ };
797
+ }
798
+ };
799
+ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
800
+ if (!isRecord(value)) {
801
+ unsupportedFields.push(field);
802
+ warnings.push({
803
+ code: "otlp_attribute_value_invalid",
804
+ message: "OTLP attribute value was not an AnyValue object.",
805
+ severity: "warning",
806
+ field
807
+ });
808
+ return void 0;
809
+ }
810
+ if (typeof value.stringValue === "string") return value.stringValue;
811
+ if (typeof value.boolValue === "boolean") return value.boolValue;
812
+ if (typeof value.intValue === "number" && Number.isFinite(value.intValue)) {
813
+ return value.intValue;
814
+ }
815
+ if (typeof value.intValue === "string" && value.intValue.trim() !== "") {
816
+ const n = Number(value.intValue);
817
+ if (Number.isFinite(n)) return n;
818
+ }
819
+ if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
820
+ return value.doubleValue;
821
+ }
822
+ if (isRecord(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
823
+ return value.arrayValue.values.map(
824
+ (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
825
+ );
826
+ }
827
+ if (isRecord(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
828
+ const out = {};
829
+ for (const [index, item] of value.kvlistValue.values.entries()) {
830
+ if (!isRecord(item) || typeof item.key !== "string") {
831
+ unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
832
+ continue;
833
+ }
834
+ out[item.key] = parseOtlpAnyValue(
835
+ item.value,
836
+ `${field}.kvlistValue.values[${index}].value`,
837
+ warnings,
838
+ unsupportedFields
839
+ );
840
+ }
841
+ return out;
842
+ }
843
+ if (typeof value.bytesValue === "string") {
844
+ unsupportedFields.push(field);
845
+ warnings.push({
846
+ code: "otlp_bytes_value_summarized",
847
+ message: "OTLP bytesValue attribute was summarized instead of decoded.",
848
+ severity: "warning",
849
+ field
850
+ });
851
+ return { type: "bytes", length: value.bytesValue.length };
852
+ }
853
+ unsupportedFields.push(field);
854
+ warnings.push({
855
+ code: "otlp_attribute_value_unsupported",
856
+ message: "OTLP attribute value used an unsupported AnyValue shape.",
857
+ severity: "warning",
858
+ field
859
+ });
860
+ return void 0;
861
+ }
862
+ function parseOtlpAttributes(value, pathPrefix) {
863
+ const attributes = {};
864
+ const warnings = [];
865
+ const unsupportedFields = [];
866
+ if (value === void 0) {
867
+ return { attributes, warnings, unsupportedFields };
868
+ }
869
+ if (!Array.isArray(value)) {
870
+ unsupportedFields.push(pathPrefix);
871
+ warnings.push({
872
+ code: "otlp_attributes_invalid",
873
+ message: "OTLP attributes field was not an array.",
874
+ severity: "warning",
875
+ field: pathPrefix
876
+ });
877
+ return { attributes, warnings, unsupportedFields };
878
+ }
879
+ for (const [index, item] of value.entries()) {
880
+ const field = `${pathPrefix}[${index}]`;
881
+ if (!isRecord(item) || typeof item.key !== "string") {
882
+ unsupportedFields.push(field);
883
+ warnings.push({
884
+ code: "otlp_attribute_invalid",
885
+ message: "Skipped OTLP attribute without a string key.",
886
+ severity: "warning",
887
+ field
888
+ });
889
+ continue;
890
+ }
891
+ const parsed = parseOtlpAnyValue(
892
+ item.value,
893
+ `${field}.value`,
894
+ warnings,
895
+ unsupportedFields
896
+ );
897
+ if (parsed !== void 0) {
898
+ attributes[item.key] = parsed;
899
+ }
900
+ }
901
+ return { attributes, warnings, unsupportedFields };
902
+ }
903
+ function looksLikeOtlpSpan(value) {
904
+ return isRecord(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
905
+ }
906
+ function extractOtlpDocument(root) {
907
+ if (!isRecord(root) || !Array.isArray(root.resourceSpans)) return void 0;
908
+ const spans = [];
909
+ const warnings = [];
910
+ const unsupportedFields = [];
911
+ for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
912
+ const resourcePath = `resourceSpans[${resourceIndex}]`;
913
+ if (!isRecord(resourceSpan)) {
914
+ unsupportedFields.push(resourcePath);
915
+ continue;
916
+ }
917
+ const resource = readRecordField(resourceSpan, "resource");
918
+ const resourceParsed = parseOtlpAttributes(
919
+ resource?.attributes,
920
+ `${resourcePath}.resource.attributes`
921
+ );
922
+ warnings.push(...resourceParsed.warnings);
923
+ unsupportedFields.push(...resourceParsed.unsupportedFields);
924
+ if (!Array.isArray(resourceSpan.scopeSpans)) {
925
+ unsupportedFields.push(`${resourcePath}.scopeSpans`);
926
+ warnings.push({
927
+ code: "otlp_scope_spans_missing",
928
+ message: "OTLP resourceSpans entry did not contain a scopeSpans array.",
929
+ severity: "warning",
930
+ field: `${resourcePath}.scopeSpans`
931
+ });
932
+ continue;
933
+ }
934
+ for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
935
+ const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
936
+ if (!isRecord(scopeSpan)) {
937
+ unsupportedFields.push(scopePath);
938
+ continue;
939
+ }
940
+ const scope = readRecordField(scopeSpan, "scope");
941
+ const scopeParsed = parseOtlpAttributes(
942
+ scope?.attributes,
943
+ `${scopePath}.scope.attributes`
944
+ );
945
+ warnings.push(...scopeParsed.warnings);
946
+ unsupportedFields.push(...scopeParsed.unsupportedFields);
947
+ if (!Array.isArray(scopeSpan.spans)) {
948
+ unsupportedFields.push(`${scopePath}.spans`);
949
+ warnings.push({
950
+ code: "otlp_spans_missing",
951
+ message: "OTLP scopeSpans entry did not contain a spans array.",
952
+ severity: "warning",
953
+ field: `${scopePath}.spans`
954
+ });
955
+ continue;
956
+ }
957
+ for (const [spanIndex, span] of scopeSpan.spans.entries()) {
958
+ const spanPath = `${scopePath}.spans[${spanIndex}]`;
959
+ if (!looksLikeOtlpSpan(span)) {
960
+ unsupportedFields.push(spanPath);
961
+ warnings.push({
962
+ code: "otlp_invalid_span",
963
+ message: "Skipped OTLP span without required traceId, spanId, or name.",
964
+ severity: "warning",
965
+ field: spanPath
966
+ });
967
+ continue;
968
+ }
969
+ spans.push({
970
+ span,
971
+ resourceAttributes: resourceParsed.attributes,
972
+ scopeAttributes: scopeParsed.attributes,
973
+ scopeName: readStringField(scope ?? {}, ["name"]),
974
+ scopeVersion: readStringField(scope ?? {}, ["version"]),
975
+ pathPrefix: spanPath
976
+ });
977
+ }
978
+ }
979
+ }
980
+ if (spans.length === 0) {
981
+ warnings.push({
982
+ code: "otlp_no_valid_spans",
983
+ message: "OTLP JSON payload did not contain any valid spans.",
984
+ severity: "error"
985
+ });
986
+ return {
987
+ spans,
988
+ confidence: 0.7,
989
+ description: "Malformed OTLP JSON trace payload",
990
+ warnings,
991
+ unsupportedFields
992
+ };
993
+ }
994
+ return {
995
+ spans,
996
+ confidence: 0.93,
997
+ description: "OTLP JSON trace payload",
998
+ warnings,
999
+ unsupportedFields
1000
+ };
1001
+ }
1002
+ function mapOtlpStatus(status) {
1003
+ if (!isRecord(status)) return void 0;
1004
+ const rawCode = status.code;
1005
+ if (typeof rawCode !== "string") return void 0;
1006
+ switch (rawCode.toUpperCase()) {
1007
+ case "STATUS_CODE_OK":
1008
+ case "OK":
1009
+ return "ok";
1010
+ case "STATUS_CODE_ERROR":
1011
+ case "ERROR":
1012
+ return "error";
1013
+ case "STATUS_CODE_UNSET":
1014
+ case "UNSET":
1015
+ return "unknown";
1016
+ default:
1017
+ return "unknown";
1018
+ }
1019
+ }
1020
+ function readOtlpKind(attributes, pathPrefix) {
1021
+ const warnings = [];
1022
+ const agentInspectKind = attributes["agent_inspect.kind"];
1023
+ if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
1024
+ return { kind: agentInspectKind, warnings };
1025
+ }
1026
+ const operation = attributes["gen_ai.operation.name"];
1027
+ if (typeof operation === "string") {
1028
+ switch (operation) {
1029
+ case "generate_content":
1030
+ case "chat":
1031
+ return { kind: "LLM", warnings };
1032
+ case "execute_tool":
1033
+ return { kind: "TOOL", warnings };
1034
+ case "invoke_agent":
1035
+ return { kind: "AGENT", warnings };
1036
+ default:
1037
+ warnings.push({
1038
+ code: "otlp_gen_ai_operation_semantic_loss",
1039
+ message: `OTLP GenAI operation "${operation}" mapped to AgentInspect LOGIC.`,
1040
+ severity: "warning",
1041
+ field: `${pathPrefix}.attributes.gen_ai.operation.name`
1042
+ });
1043
+ return { kind: "LOGIC", warnings };
1044
+ }
1045
+ }
1046
+ warnings.push({
1047
+ code: "otlp_kind_unknown",
1048
+ message: "OTLP span had no AgentInspect kind or GenAI operation; mapped to LOGIC.",
1049
+ severity: "warning",
1050
+ field: `${pathPrefix}.attributes`
1051
+ });
1052
+ return { kind: "LOGIC", warnings };
1053
+ }
1054
+ function readOtlpTokenUsage(attributes) {
1055
+ const input = attributes["gen_ai.usage.input_tokens"];
1056
+ const output = attributes["gen_ai.usage.output_tokens"];
1057
+ const usage = {};
1058
+ if (typeof input === "number" && Number.isFinite(input) && input >= 0) {
1059
+ usage.input = input;
1060
+ }
1061
+ if (typeof output === "number" && Number.isFinite(output) && output >= 0) {
1062
+ usage.output = output;
1063
+ }
1064
+ if (usage.input !== void 0 && usage.output !== void 0) {
1065
+ usage.total = usage.input + usage.output;
1066
+ }
1067
+ return Object.keys(usage).length > 0 ? usage : void 0;
1068
+ }
1069
+ function readOtlpConfidence(attributes) {
1070
+ return readOpenInferenceConfidence(attributes);
1071
+ }
1072
+ function sanitizeOtlpAttributes(attributes, pathPrefix) {
1073
+ const ownerPath = pathPrefix.endsWith(".attributes") ? pathPrefix.slice(0, -".attributes".length) : pathPrefix;
1074
+ const sanitized = sanitizeOpenInferenceAttributes(attributes, ownerPath);
1075
+ return {
1076
+ ...sanitized,
1077
+ warnings: sanitized.warnings.map(
1078
+ (warning) => warning.code === "openinference_sensitive_attribute_summarized" ? {
1079
+ ...warning,
1080
+ code: "otlp_sensitive_attribute_summarized",
1081
+ message: "OTLP prompt/output/document attribute(s) were summarized instead of copied verbatim."
1082
+ } : warning
1083
+ )
1084
+ };
1085
+ }
1086
+ function mapOtlpEvents(value, pathPrefix) {
1087
+ const warnings = [];
1088
+ const unsupportedFields = [];
1089
+ if (value === void 0) return { warnings, unsupportedFields };
1090
+ if (!Array.isArray(value)) {
1091
+ unsupportedFields.push(pathPrefix);
1092
+ warnings.push({
1093
+ code: "otlp_events_invalid",
1094
+ message: "OTLP events field was not an array.",
1095
+ severity: "warning",
1096
+ field: pathPrefix
1097
+ });
1098
+ return { warnings, unsupportedFields };
1099
+ }
1100
+ const events = [];
1101
+ for (const [index, event] of value.entries()) {
1102
+ const eventPath = `${pathPrefix}[${index}]`;
1103
+ if (!isRecord(event)) {
1104
+ unsupportedFields.push(eventPath);
1105
+ continue;
1106
+ }
1107
+ const parsedAttributes = parseOtlpAttributes(
1108
+ event.attributes,
1109
+ `${eventPath}.attributes`
1110
+ );
1111
+ warnings.push(...parsedAttributes.warnings);
1112
+ unsupportedFields.push(...parsedAttributes.unsupportedFields);
1113
+ const sanitized = sanitizeOtlpAttributes(
1114
+ parsedAttributes.attributes,
1115
+ `${eventPath}.attributes`
1116
+ );
1117
+ warnings.push(...sanitized.warnings);
1118
+ unsupportedFields.push(...sanitized.unsupportedFields);
1119
+ const out = {};
1120
+ const name = readStringField(event, ["name"]);
1121
+ if (name !== void 0) {
1122
+ out.name = name;
1123
+ }
1124
+ const timestamp = parseUnixNanoToIso(event.timeUnixNano);
1125
+ if (timestamp !== void 0) {
1126
+ out.timestamp = timestamp;
1127
+ } else if (event.timeUnixNano !== void 0) {
1128
+ unsupportedFields.push(`${eventPath}.timeUnixNano`);
1129
+ warnings.push({
1130
+ code: "otlp_event_timestamp_invalid",
1131
+ message: "OTLP event timeUnixNano could not be parsed.",
1132
+ severity: "warning",
1133
+ field: `${eventPath}.timeUnixNano`
1134
+ });
1135
+ }
1136
+ if (Object.keys(sanitized.attributes).length > 0) {
1137
+ out.attributes = sanitized.attributes;
1138
+ }
1139
+ events.push(out);
1140
+ }
1141
+ return {
1142
+ events: events.length > 0 ? events : void 0,
1143
+ warnings,
1144
+ unsupportedFields
1145
+ };
1146
+ }
1147
+ function mapOtlpSpan(context) {
1148
+ const { span, pathPrefix } = context;
1149
+ const warnings = [];
1150
+ const unsupportedFields = [];
1151
+ const parsedSpanAttributes = parseOtlpAttributes(
1152
+ span.attributes,
1153
+ `${pathPrefix}.attributes`
1154
+ );
1155
+ warnings.push(...parsedSpanAttributes.warnings);
1156
+ unsupportedFields.push(...parsedSpanAttributes.unsupportedFields);
1157
+ const sanitizedSpanAttributes = sanitizeOtlpAttributes(
1158
+ parsedSpanAttributes.attributes,
1159
+ `${pathPrefix}.attributes`
1160
+ );
1161
+ warnings.push(...sanitizedSpanAttributes.warnings);
1162
+ unsupportedFields.push(...sanitizedSpanAttributes.unsupportedFields);
1163
+ const attributes = {
1164
+ ...sanitizedSpanAttributes.attributes
1165
+ };
1166
+ for (const [key, value] of Object.entries(context.resourceAttributes)) {
1167
+ attributes[`resource.${key}`] = value;
1168
+ }
1169
+ for (const [key, value] of Object.entries(context.scopeAttributes)) {
1170
+ attributes[`scope.${key}`] = value;
1171
+ }
1172
+ if (context.scopeName !== void 0) {
1173
+ attributes["scope.name"] = context.scopeName;
1174
+ }
1175
+ if (context.scopeVersion !== void 0) {
1176
+ attributes["scope.version"] = context.scopeVersion;
1177
+ }
1178
+ for (const [key, value] of Object.entries(span)) {
1179
+ if (OTLP_SPAN_KEYS.has(key)) continue;
1180
+ unsupportedFields.push(`${pathPrefix}.${key}`);
1181
+ if (value === null || typeof value !== "object") {
1182
+ attributes[`otlp.${key}`] = value;
1183
+ } else {
1184
+ attributes[`otlp.${key}.summary`] = summarizeAttributeValue(value);
1185
+ warnings.push({
1186
+ code: "otlp_unsupported_field_summarized",
1187
+ message: `Unsupported OTLP span field "${key}" was summarized.`,
1188
+ severity: "warning",
1189
+ field: `${pathPrefix}.${key}`
1190
+ });
1191
+ }
1192
+ }
1193
+ for (const key of [
1194
+ "droppedAttributesCount",
1195
+ "droppedEventsCount",
1196
+ "droppedLinksCount",
1197
+ "links"
1198
+ ]) {
1199
+ if (span[key] !== void 0) {
1200
+ unsupportedFields.push(`${pathPrefix}.${key}`);
1201
+ warnings.push({
1202
+ code: "otlp_span_field_not_mapped",
1203
+ message: `OTLP span field "${key}" is not represented in AgentInspect events.`,
1204
+ severity: "warning",
1205
+ field: `${pathPrefix}.${key}`
1206
+ });
1207
+ }
1208
+ }
1209
+ const events = mapOtlpEvents(span.events, `${pathPrefix}.events`);
1210
+ warnings.push(...events.warnings);
1211
+ unsupportedFields.push(...events.unsupportedFields);
1212
+ if (events.events !== void 0) {
1213
+ attributes["otlp.events"] = events.events;
1214
+ }
1215
+ const traceId = readStringField(span, ["traceId"]) ?? "trace-unknown";
1216
+ const spanId = readStringField(span, ["spanId"]) ?? "span-unknown";
1217
+ const parentSpanId = readStringField(span, ["parentSpanId"]);
1218
+ const startedAt = readOpenInferenceTimestamp(
1219
+ span,
1220
+ ["startTimeUnixNano"],
1221
+ []
1222
+ );
1223
+ const endedAt = readOpenInferenceTimestamp(span, ["endTimeUnixNano"], []);
1224
+ const timestamp = startedAt ?? "1970-01-01T00:00:00.000Z";
1225
+ if (startedAt === void 0) {
1226
+ unsupportedFields.push(`${pathPrefix}.startTimeUnixNano`);
1227
+ warnings.push({
1228
+ code: "otlp_missing_start_time",
1229
+ message: "OTLP span is missing a valid startTimeUnixNano; using Unix epoch.",
1230
+ severity: "warning",
1231
+ field: `${pathPrefix}.startTimeUnixNano`
1232
+ });
1233
+ }
1234
+ const { kind, warnings: kindWarnings } = readOtlpKind(
1235
+ parsedSpanAttributes.attributes,
1236
+ pathPrefix
1237
+ );
1238
+ warnings.push(...kindWarnings);
1239
+ const status = mapOtlpStatus(span.status);
1240
+ const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
1241
+ const errorMessage = isRecord(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
1242
+ const event = {
1243
+ schemaVersion: "0.2",
1244
+ eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
1245
+ runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
1246
+ kind,
1247
+ name: readStringField(span, ["name"]) ?? spanId,
1248
+ timestamp,
1249
+ confidence: readOtlpConfidence(parsedSpanAttributes.attributes),
1250
+ source: {
1251
+ type: "otel",
1252
+ name: context.scopeName ?? (typeof context.resourceAttributes["service.name"] === "string" ? context.resourceAttributes["service.name"] : "otlp-json"),
1253
+ ...context.scopeVersion !== void 0 ? { version: context.scopeVersion } : {}
1254
+ },
1255
+ attributes,
1256
+ trace: {
1257
+ traceId,
1258
+ spanId,
1259
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
1260
+ }
1261
+ };
1262
+ if (status !== void 0) {
1263
+ event.status = status;
1264
+ }
1265
+ if (startedAt !== void 0) {
1266
+ event.startedAt = startedAt;
1267
+ }
1268
+ if (endedAt !== void 0) {
1269
+ event.endedAt = endedAt;
1270
+ }
1271
+ const durationMs = durationBetweenIso(startedAt, endedAt);
1272
+ if (durationMs !== void 0) {
1273
+ event.durationMs = durationMs;
1274
+ }
1275
+ if (tokenUsage !== void 0) {
1276
+ event.tokenUsage = tokenUsage;
1277
+ }
1278
+ if (status === "error") {
1279
+ event.error = {
1280
+ message: errorMessage !== void 0 && errorMessage.trim() !== "" ? errorMessage : "OTLP span error"
1281
+ };
1282
+ }
1283
+ return {
1284
+ event,
1285
+ warnings,
1286
+ unsupportedFields,
1287
+ spanId,
1288
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
1289
+ };
1290
+ }
1291
+ function mapOtlpEventsToPersisted(document) {
1292
+ const mapped = document.spans.map((span) => mapOtlpSpan(span));
1293
+ const spanIdToEventId = new Map(
1294
+ mapped.map((span) => [span.spanId, span.event.eventId])
1295
+ );
1296
+ for (const span of mapped) {
1297
+ if (span.parentSpanId === void 0) continue;
1298
+ span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
1299
+ }
1300
+ return {
1301
+ events: mapped.map((span) => span.event),
1302
+ warnings: mapped.flatMap((span) => span.warnings),
1303
+ unsupportedFields: mapped.flatMap((span) => span.unsupportedFields)
1304
+ };
1305
+ }
1306
+ var otlpJsonReader = {
1307
+ format: OTLP_READER_FORMAT,
1308
+ name: "OTLP JSON",
1309
+ async detect(input) {
1310
+ const resolved = await resolveInput(input);
1311
+ if (!resolved) return void 0;
1312
+ let parsed;
1313
+ try {
1314
+ parsed = parseJsonDocument(resolved.content);
1315
+ } catch {
1316
+ return void 0;
1317
+ }
1318
+ const document = extractOtlpDocument(parsed);
1319
+ if (!document) return void 0;
1320
+ return {
1321
+ format: OTLP_READER_FORMAT,
1322
+ confidence: document.confidence,
1323
+ readerName: "OTLP JSON",
1324
+ description: document.description,
1325
+ warnings: attachSingleSourceFile(document.warnings, resolved)
1326
+ };
1327
+ },
1328
+ async read(input) {
1329
+ const resolved = await resolveInput(input);
1330
+ if (!resolved) {
1331
+ throw new TraceReadError(
1332
+ "unsupported_format",
1333
+ "OTLP JSON reader requires file, string, or buffer input."
1334
+ );
1335
+ }
1336
+ let parsed;
1337
+ try {
1338
+ parsed = parseJsonDocument(resolved.content);
1339
+ } catch {
1340
+ throw new TraceReadError("unsupported_format", "OTLP JSON input is not valid JSON.", [
1341
+ {
1342
+ code: "otlp_invalid_json",
1343
+ message: "OTLP JSON reader could not parse the input as JSON.",
1344
+ severity: "error"
1345
+ }
1346
+ ]);
1347
+ }
1348
+ const document = extractOtlpDocument(parsed);
1349
+ if (!document || document.spans.length === 0) {
1350
+ throw new TraceReadError(
1351
+ "unsupported_format",
1352
+ "No valid OTLP spans found.",
1353
+ attachSingleSourceFile(
1354
+ document?.warnings ?? [
1355
+ {
1356
+ code: "otlp_no_valid_spans",
1357
+ message: "OTLP JSON input did not contain valid spans.",
1358
+ severity: "error"
1359
+ }
1360
+ ],
1361
+ resolved
1362
+ )
1363
+ );
1364
+ }
1365
+ const mapped = mapOtlpEventsToPersisted(document);
1366
+ const warnings = attachSingleSourceFile(
1367
+ [...document.warnings, ...mapped.warnings],
1368
+ resolved
1369
+ );
1370
+ const unsupportedFields = [
1371
+ ...document.unsupportedFields,
1372
+ ...mapped.unsupportedFields
1373
+ ].sort((a, b) => a.localeCompare(b));
1374
+ return {
1375
+ format: OTLP_READER_FORMAT,
1376
+ events: mapped.events,
1377
+ runs: persistedInspectEventsToRunTrees(mapped.events, { skipInvalid: true }),
1378
+ warnings,
1379
+ unsupportedFields,
1380
+ sourceFiles: resolved.sourceFiles
1381
+ };
1382
+ }
1383
+ };
1384
+ var agentInspectJsonlReader = {
1385
+ format: "agent-inspect-jsonl",
1386
+ name: "AgentInspect JSONL",
1387
+ async detect(input) {
1388
+ const resolved = await resolveInput(input);
1389
+ if (!resolved) return void 0;
1390
+ const detected = detectJsonlFormat(resolved.content);
1391
+ if (detected.validRows === 0 || detected.format === "empty") {
1392
+ return void 0;
1393
+ }
1394
+ return {
1395
+ format: "agent-inspect-jsonl",
1396
+ confidence: 0.95,
1397
+ readerName: "AgentInspect JSONL",
1398
+ description: agentInspectFormatLabel(detected.format),
1399
+ warnings: attachSingleSourceFile(detected.warnings, resolved)
1400
+ };
1401
+ },
1402
+ async read(input) {
1403
+ const resolved = await resolveInput(input);
1404
+ if (!resolved) {
1405
+ throw new Error("AgentInspect JSONL reader requires file, directory, string, or buffer input.");
1406
+ }
1407
+ const parsed = parseTraceJsonl(resolved.content, { warnings: false });
1408
+ if (parsed.sourceEventCount === 0) {
1409
+ throw new Error("No valid AgentInspect JSONL events found.");
1410
+ }
1411
+ const events = persistedEventsForParsedTrace(parsed);
1412
+ return {
1413
+ format: agentInspectFormatLabel(parsed.format),
1414
+ events,
1415
+ runs: persistedInspectEventsToRunTrees(events, { skipInvalid: true }),
1416
+ warnings: parsed.format === "mixed" ? attachSingleSourceFile(
1417
+ [
1418
+ {
1419
+ code: "mixed_agent_inspect_jsonl",
1420
+ message: "Trace input mixes schemaVersion 0.1 and 0.2 rows; events were normalized for reading.",
1421
+ severity: "warning"
1422
+ }
1423
+ ],
1424
+ resolved
1425
+ ) : [],
1426
+ unsupportedFields: [],
1427
+ sourceFiles: resolved.sourceFiles
1428
+ };
1429
+ }
1430
+ };
1431
+ var DEFAULT_TRACE_READERS = [
1432
+ agentInspectJsonlReader,
1433
+ openInferenceJsonReader,
1434
+ otlpJsonReader
1435
+ ];
1436
+ async function detectTraceFormat(input, options = {}) {
1437
+ const readers = options.readers ?? DEFAULT_TRACE_READERS;
1438
+ if (options.format !== void 0) {
1439
+ const reader = findReaderByFormat(options.format, readers);
1440
+ if (!reader) {
1441
+ return {
1442
+ status: "unsupported",
1443
+ candidates: [],
1444
+ warnings: [
1445
+ {
1446
+ code: "unsupported_format",
1447
+ message: `No trace reader is registered for format "${options.format}".`,
1448
+ severity: "error"
1449
+ }
1450
+ ]
1451
+ };
1452
+ }
1453
+ return {
1454
+ status: "detected",
1455
+ format: reader.format,
1456
+ candidates: [
1457
+ {
1458
+ format: reader.format,
1459
+ confidence: 1,
1460
+ readerName: reader.name,
1461
+ description: "Explicit format override"
1462
+ }
1463
+ ],
1464
+ warnings: []
1465
+ };
1466
+ }
1467
+ const candidates = [];
1468
+ const warnings = [];
1469
+ for (const reader of readers) {
1470
+ try {
1471
+ const candidate = await reader.detect(input);
1472
+ if (candidate !== void 0) {
1473
+ candidates.push(normalizeCandidate(reader, candidate));
1474
+ }
1475
+ } catch (error) {
1476
+ if (error instanceof TraceReadError) {
1477
+ warnings.push(...error.warnings);
1478
+ continue;
1479
+ }
1480
+ warnings.push({
1481
+ code: "reader_detect_failed",
1482
+ message: error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed during detection.`,
1483
+ severity: "warning"
1484
+ });
1485
+ }
1486
+ }
1487
+ const sorted = sortCandidates(
1488
+ candidates.filter((candidate) => candidate.confidence >= MIN_DETECTION_CONFIDENCE)
1489
+ );
1490
+ const candidateWarnings = collectWarnings(sorted);
1491
+ const lowConfidenceWarnings = candidates.length > sorted.length ? [
1492
+ {
1493
+ code: "low_confidence_candidates",
1494
+ message: `Ignored ${candidates.length - sorted.length} low-confidence format candidate(s).`,
1495
+ severity: "info"
1496
+ }
1497
+ ] : [];
1498
+ const allWarnings = dedupeWarnings([
1499
+ ...warnings,
1500
+ ...candidateWarnings,
1501
+ ...lowConfidenceWarnings
1502
+ ]);
1503
+ if (sorted.length === 0) {
1504
+ return {
1505
+ status: "unsupported",
1506
+ candidates: [],
1507
+ warnings: allWarnings
1508
+ };
1509
+ }
1510
+ const [best, second] = sorted;
1511
+ if (second !== void 0 && best.confidence - second.confidence <= AMBIGUOUS_CONFIDENCE_DELTA) {
1512
+ return {
1513
+ status: "ambiguous",
1514
+ candidates: sorted,
1515
+ warnings: [
1516
+ ...allWarnings,
1517
+ {
1518
+ code: "ambiguous_format_candidates",
1519
+ message: `Top trace format candidates are within ${AMBIGUOUS_CONFIDENCE_DELTA} confidence.`,
1520
+ severity: "warning"
1521
+ }
1522
+ ]
1523
+ };
1524
+ }
1525
+ return {
1526
+ status: "detected",
1527
+ format: best.format,
1528
+ candidates: sorted,
1529
+ warnings: allWarnings
1530
+ };
1531
+ }
1532
+ async function readTrace(input, options = {}) {
1533
+ const readers = options.readers ?? DEFAULT_TRACE_READERS;
1534
+ const detection = await detectTraceFormat(input, options);
1535
+ if (detection.status === "unsupported" || detection.format === void 0) {
1536
+ throw new TraceReadError(
1537
+ "unsupported_format",
1538
+ "No trace reader could detect the input format.",
1539
+ detection.warnings
1540
+ );
1541
+ }
1542
+ if (detection.status === "ambiguous") {
1543
+ throw new TraceReadError(
1544
+ "ambiguous_format",
1545
+ "Multiple trace readers matched the input with equal confidence.",
1546
+ detection.warnings
1547
+ );
1548
+ }
1549
+ const reader = findReaderByFormat(detection.format, readers);
1550
+ if (!reader) {
1551
+ throw new TraceReadError(
1552
+ "unsupported_format",
1553
+ `No trace reader is registered for format "${detection.format}".`,
1554
+ detection.warnings
1555
+ );
1556
+ }
1557
+ try {
1558
+ const result = await reader.read(input, { format: detection.format });
1559
+ return {
1560
+ ...result,
1561
+ format: result.format || detection.format,
1562
+ warnings: [...detection.warnings, ...result.warnings]
1563
+ };
1564
+ } catch (error) {
1565
+ if (error instanceof TraceReadError) {
1566
+ throw new TraceReadError(
1567
+ error.code,
1568
+ error.message,
1569
+ dedupeWarnings([...detection.warnings, ...error.warnings])
1570
+ );
1571
+ }
1572
+ throw new TraceReadError(
1573
+ "reader_failed",
1574
+ error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed.`,
1575
+ detection.warnings
1576
+ );
1577
+ }
1578
+ }
1579
+ function openTrace(input, options = {}) {
1580
+ return readTrace(input, options);
1581
+ }
1582
+
1583
+ export { DEFAULT_TRACE_READERS, TraceReadError, agentInspectJsonlReader, detectTraceFormat, openInferenceJsonReader, openTrace, otlpJsonReader, readTrace };
8
1584
  //# sourceMappingURL=readers.mjs.map
9
1585
  //# sourceMappingURL=readers.mjs.map