agent-inspect 1.3.0 → 1.5.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 +47 -4
- package/README.md +59 -37
- package/docs/ADAPTERS.md +117 -31
- package/docs/API.md +24 -6
- package/docs/CLI.md +126 -1
- package/docs/DIFF.md +8 -0
- package/docs/EXPORTS.md +86 -15
- package/docs/GETTING-STARTED.md +48 -2
- package/docs/KNOWN-ISSUES.md +6 -0
- package/docs/LIMITATIONS.md +11 -3
- package/docs/LOGS.md +22 -0
- package/docs/SCHEMA.md +8 -5
- package/docs/SCREENSHOTS.md +190 -9
- package/package.json +51 -1
- package/packages/cli/dist/index.cjs +3253 -1662
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +3253 -1662
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +1437 -0
- package/packages/core/dist/advanced.cjs.map +1 -0
- package/packages/core/dist/advanced.d.cts +159 -0
- package/packages/core/dist/advanced.d.ts +159 -0
- package/packages/core/dist/advanced.mjs +8 -0
- package/packages/core/dist/advanced.mjs.map +1 -0
- package/packages/core/dist/chunk-5EMIZZXD.mjs +907 -0
- package/packages/core/dist/chunk-5EMIZZXD.mjs.map +1 -0
- package/packages/core/dist/chunk-7TGZLWEE.mjs +35 -0
- package/packages/core/dist/chunk-7TGZLWEE.mjs.map +1 -0
- package/packages/core/dist/chunk-BT7CATSD.mjs +497 -0
- package/packages/core/dist/chunk-BT7CATSD.mjs.map +1 -0
- package/packages/core/dist/chunk-E5F2LQCX.mjs +83 -0
- package/packages/core/dist/chunk-E5F2LQCX.mjs.map +1 -0
- package/packages/core/dist/chunk-EDTQHZPM.mjs +88 -0
- package/packages/core/dist/chunk-EDTQHZPM.mjs.map +1 -0
- package/packages/core/dist/chunk-HY7H3CQM.mjs +127 -0
- package/packages/core/dist/chunk-HY7H3CQM.mjs.map +1 -0
- package/packages/core/dist/chunk-Q6EPNB3V.mjs +539 -0
- package/packages/core/dist/chunk-Q6EPNB3V.mjs.map +1 -0
- package/packages/core/dist/chunk-QPAU2TPA.mjs +785 -0
- package/packages/core/dist/chunk-QPAU2TPA.mjs.map +1 -0
- package/packages/core/dist/chunk-QX3ZMPUF.mjs +451 -0
- package/packages/core/dist/chunk-QX3ZMPUF.mjs.map +1 -0
- package/packages/core/dist/chunk-VU6O5QAH.mjs +99 -0
- package/packages/core/dist/chunk-VU6O5QAH.mjs.map +1 -0
- package/packages/core/dist/chunk-XDBND27A.mjs +975 -0
- package/packages/core/dist/chunk-XDBND27A.mjs.map +1 -0
- package/packages/core/dist/chunk-YWAOOXLR.mjs +475 -0
- package/packages/core/dist/chunk-YWAOOXLR.mjs.map +1 -0
- package/packages/core/dist/diff.cjs +993 -0
- package/packages/core/dist/diff.cjs.map +1 -0
- package/packages/core/dist/diff.d.cts +81 -0
- package/packages/core/dist/diff.d.ts +81 -0
- package/packages/core/dist/diff.mjs +5 -0
- package/packages/core/dist/diff.mjs.map +1 -0
- package/packages/core/dist/exporters.cjs +1228 -0
- package/packages/core/dist/exporters.cjs.map +1 -0
- package/packages/core/dist/exporters.d.cts +113 -0
- package/packages/core/dist/exporters.d.ts +113 -0
- package/packages/core/dist/exporters.mjs +6 -0
- package/packages/core/dist/exporters.mjs.map +1 -0
- package/packages/core/dist/index.cjs +2982 -1829
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +201 -892
- package/packages/core/dist/index.d.ts +201 -892
- package/packages/core/dist/index.mjs +780 -4620
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/log-config-BzGmDYum.d.cts +71 -0
- package/packages/core/dist/log-config-BzGmDYum.d.ts +71 -0
- package/packages/core/dist/logs.cjs +1007 -0
- package/packages/core/dist/logs.cjs.map +1 -0
- package/packages/core/dist/logs.d.cts +137 -0
- package/packages/core/dist/logs.d.ts +137 -0
- package/packages/core/dist/logs.mjs +6 -0
- package/packages/core/dist/logs.mjs.map +1 -0
- package/packages/core/dist/persisted.cjs +1057 -0
- package/packages/core/dist/persisted.cjs.map +1 -0
- package/packages/core/dist/persisted.d.cts +160 -0
- package/packages/core/dist/persisted.d.ts +160 -0
- package/packages/core/dist/persisted.mjs +5 -0
- package/packages/core/dist/persisted.mjs.map +1 -0
- package/packages/core/dist/types-Bkt7LS01.d.ts +226 -0
- package/packages/core/dist/types-CNbheSdk.d.cts +226 -0
|
@@ -0,0 +1,1228 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
8
|
+
|
|
9
|
+
// packages/core/src/exporters/types.ts
|
|
10
|
+
var EXPORT_PAYLOAD_VERSION = "0.1.2";
|
|
11
|
+
var DEFAULT_REDACT_KEYS = [
|
|
12
|
+
"authorization",
|
|
13
|
+
"cookie",
|
|
14
|
+
"token",
|
|
15
|
+
"apiKey",
|
|
16
|
+
"password",
|
|
17
|
+
"secret",
|
|
18
|
+
"email"
|
|
19
|
+
];
|
|
20
|
+
function isRecord(v) {
|
|
21
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
22
|
+
}
|
|
23
|
+
function toKey(s) {
|
|
24
|
+
return s.toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
function stableHash(value) {
|
|
27
|
+
const h = crypto__default.default.createHash("sha256").update(value, "utf8").digest("hex");
|
|
28
|
+
return h.slice(0, 8);
|
|
29
|
+
}
|
|
30
|
+
function compileRules(rules, extraKeys) {
|
|
31
|
+
const out = /* @__PURE__ */ new Map();
|
|
32
|
+
const set = (r) => {
|
|
33
|
+
const k = toKey(r.key);
|
|
34
|
+
out.set(k, { ...r, key: k });
|
|
35
|
+
};
|
|
36
|
+
for (const k of DEFAULT_REDACT_KEYS) {
|
|
37
|
+
set({ key: k, strategy: "full" });
|
|
38
|
+
}
|
|
39
|
+
for (const k of extraKeys ?? []) {
|
|
40
|
+
if (typeof k === "string" && k.length > 0) {
|
|
41
|
+
set({ key: k, strategy: "full" });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const r of rules ?? []) {
|
|
45
|
+
if (typeof r === "string") {
|
|
46
|
+
set({ key: r, strategy: "full" });
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const key = r.key;
|
|
50
|
+
if (r.strategy === "full") set({ key, strategy: "full" });
|
|
51
|
+
if (r.strategy === "hash") set({ key, strategy: "hash" });
|
|
52
|
+
if (r.strategy === "prefix") {
|
|
53
|
+
set({ key, strategy: "prefix", keep: typeof r.keep === "number" ? r.keep : 8 });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [...out.values()];
|
|
57
|
+
}
|
|
58
|
+
var Redactor = class {
|
|
59
|
+
#rules;
|
|
60
|
+
constructor(options) {
|
|
61
|
+
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
62
|
+
}
|
|
63
|
+
redactValue(key, value) {
|
|
64
|
+
const k = toKey(key);
|
|
65
|
+
const rule = this.#rules.find((r) => r.key === k);
|
|
66
|
+
if (!rule) {
|
|
67
|
+
return this.#redactNested(value);
|
|
68
|
+
}
|
|
69
|
+
if (rule.strategy === "full") return "[REDACTED]";
|
|
70
|
+
const asString = typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" ? String(value) : void 0;
|
|
71
|
+
if (rule.strategy === "prefix") {
|
|
72
|
+
if (asString === void 0) return "[REDACTED]";
|
|
73
|
+
const keep = Math.max(0, Math.floor(rule.keep));
|
|
74
|
+
return asString.length <= keep ? `${asString}\u2026` : `${asString.slice(0, keep)}\u2026`;
|
|
75
|
+
}
|
|
76
|
+
if (rule.strategy === "hash") {
|
|
77
|
+
if (asString === void 0) return "[HASH:unknown]";
|
|
78
|
+
return `[HASH:${stableHash(asString)}]`;
|
|
79
|
+
}
|
|
80
|
+
return this.#redactNested(value);
|
|
81
|
+
}
|
|
82
|
+
redactRecord(record) {
|
|
83
|
+
const out = {};
|
|
84
|
+
for (const [k, v] of Object.entries(record)) {
|
|
85
|
+
out[k] = this.redactValue(k, v);
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
#redactNested(value) {
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
return value.map((v) => this.#redactNested(v));
|
|
92
|
+
}
|
|
93
|
+
if (isRecord(value)) {
|
|
94
|
+
const out = {};
|
|
95
|
+
for (const [k, v] of Object.entries(value)) {
|
|
96
|
+
out[k] = this.redactValue(k, v);
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// packages/core/src/redaction-profiles.ts
|
|
105
|
+
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
106
|
+
"userEmail",
|
|
107
|
+
"customerEmail",
|
|
108
|
+
"phone",
|
|
109
|
+
"phoneNumber",
|
|
110
|
+
"address",
|
|
111
|
+
"ip",
|
|
112
|
+
"ipAddress",
|
|
113
|
+
"sessionId",
|
|
114
|
+
"requestId",
|
|
115
|
+
"correlationId",
|
|
116
|
+
"decisionId",
|
|
117
|
+
"groupId",
|
|
118
|
+
"customerId",
|
|
119
|
+
"userId",
|
|
120
|
+
"accountId",
|
|
121
|
+
"tenantId",
|
|
122
|
+
"orgId",
|
|
123
|
+
"organizationId",
|
|
124
|
+
"traceId",
|
|
125
|
+
"spanId",
|
|
126
|
+
"parentSpanId"
|
|
127
|
+
];
|
|
128
|
+
var STRICT_PROFILE_EXTRA_KEYS = [
|
|
129
|
+
"prompt",
|
|
130
|
+
"completion",
|
|
131
|
+
"input",
|
|
132
|
+
"output",
|
|
133
|
+
"inputPreview",
|
|
134
|
+
"outputPreview",
|
|
135
|
+
"message",
|
|
136
|
+
"messages",
|
|
137
|
+
"transcript",
|
|
138
|
+
"context",
|
|
139
|
+
"document",
|
|
140
|
+
"documents",
|
|
141
|
+
"chunk",
|
|
142
|
+
"chunks",
|
|
143
|
+
"retrieval",
|
|
144
|
+
"query"
|
|
145
|
+
];
|
|
146
|
+
function resolveRedactionProfile(profile = "local") {
|
|
147
|
+
switch (profile) {
|
|
148
|
+
case "local":
|
|
149
|
+
return { profile: "local", extraKeys: [] };
|
|
150
|
+
case "share":
|
|
151
|
+
return {
|
|
152
|
+
profile: "share",
|
|
153
|
+
extraKeys: SHARE_PROFILE_EXTRA_KEYS,
|
|
154
|
+
maxMetadataValueLengthCap: 500,
|
|
155
|
+
maxPreviewLengthCap: 200
|
|
156
|
+
};
|
|
157
|
+
case "strict":
|
|
158
|
+
return {
|
|
159
|
+
profile: "strict",
|
|
160
|
+
extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
|
|
161
|
+
maxMetadataValueLengthCap: 200,
|
|
162
|
+
maxPreviewLengthCap: 80
|
|
163
|
+
};
|
|
164
|
+
default:
|
|
165
|
+
return { profile: "local", extraKeys: [] };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function isPreviewKey(key) {
|
|
169
|
+
return key.toLowerCase().includes("preview");
|
|
170
|
+
}
|
|
171
|
+
function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, resolved) {
|
|
172
|
+
let meta = maxMetadataValueLength;
|
|
173
|
+
let preview = maxPreviewLength;
|
|
174
|
+
if (resolved.maxMetadataValueLengthCap !== void 0) {
|
|
175
|
+
meta = Math.min(meta, resolved.maxMetadataValueLengthCap);
|
|
176
|
+
}
|
|
177
|
+
if (resolved.maxPreviewLengthCap !== void 0) {
|
|
178
|
+
preview = Math.min(preview, resolved.maxPreviewLengthCap);
|
|
179
|
+
}
|
|
180
|
+
return { maxMetadataValueLength: meta, maxPreviewLength: preview };
|
|
181
|
+
}
|
|
182
|
+
function truncateStringForProfile(value, key, maxMetadataValueLength, maxPreviewLength) {
|
|
183
|
+
const max = isPreviewKey(key) ? maxPreviewLength : maxMetadataValueLength;
|
|
184
|
+
if (max <= 0) return "\u2026";
|
|
185
|
+
if (value.length <= max) return value;
|
|
186
|
+
return `${value.slice(0, max)}\u2026`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// packages/core/src/exporters/redact-export.ts
|
|
190
|
+
function isRecord2(value) {
|
|
191
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
192
|
+
}
|
|
193
|
+
function deepClone(value) {
|
|
194
|
+
if (value === null || typeof value !== "object") {
|
|
195
|
+
return value;
|
|
196
|
+
}
|
|
197
|
+
if (Array.isArray(value)) {
|
|
198
|
+
return value.map((item) => deepClone(item));
|
|
199
|
+
}
|
|
200
|
+
const out = {};
|
|
201
|
+
for (const [k, v] of Object.entries(value)) {
|
|
202
|
+
out[k] = deepClone(v);
|
|
203
|
+
}
|
|
204
|
+
return out;
|
|
205
|
+
}
|
|
206
|
+
function boundAttributeValues(record, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
207
|
+
if (depth > 32) {
|
|
208
|
+
return { truncated: true, reason: "maxDepth" };
|
|
209
|
+
}
|
|
210
|
+
const out = {};
|
|
211
|
+
for (const [key, value] of Object.entries(record)) {
|
|
212
|
+
out[key] = boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth);
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
function boundValue(value, key, maxMetadataValueLength, maxPreviewLength, seen, depth) {
|
|
217
|
+
if (value === null || typeof value !== "object") {
|
|
218
|
+
if (typeof value === "string") {
|
|
219
|
+
return truncateStringForProfile(
|
|
220
|
+
value,
|
|
221
|
+
key,
|
|
222
|
+
maxMetadataValueLength,
|
|
223
|
+
maxPreviewLength
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return value;
|
|
227
|
+
}
|
|
228
|
+
if (seen.has(value)) return "[Circular]";
|
|
229
|
+
seen.add(value);
|
|
230
|
+
if (Array.isArray(value)) {
|
|
231
|
+
return value.slice(0, 50).map(
|
|
232
|
+
(item, index) => boundValue(
|
|
233
|
+
item,
|
|
234
|
+
String(index),
|
|
235
|
+
maxMetadataValueLength,
|
|
236
|
+
maxPreviewLength,
|
|
237
|
+
seen,
|
|
238
|
+
depth + 1
|
|
239
|
+
)
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
return boundAttributeValues(
|
|
243
|
+
value,
|
|
244
|
+
maxMetadataValueLength,
|
|
245
|
+
maxPreviewLength,
|
|
246
|
+
seen,
|
|
247
|
+
depth + 1
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPreviewLength) {
|
|
251
|
+
if (!attrs || Object.keys(attrs).length === 0) {
|
|
252
|
+
return attrs;
|
|
253
|
+
}
|
|
254
|
+
const redacted = redactor.redactRecord(attrs);
|
|
255
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
256
|
+
const bounded = boundAttributeValues(
|
|
257
|
+
redacted,
|
|
258
|
+
maxMetadataValueLength,
|
|
259
|
+
maxPreviewLength,
|
|
260
|
+
seen,
|
|
261
|
+
0
|
|
262
|
+
);
|
|
263
|
+
const err = bounded.error;
|
|
264
|
+
if (isRecord2(err) && typeof err.message === "string") {
|
|
265
|
+
bounded.error = {
|
|
266
|
+
...err,
|
|
267
|
+
message: truncateStringForProfile(
|
|
268
|
+
err.message,
|
|
269
|
+
"message",
|
|
270
|
+
maxMetadataValueLength,
|
|
271
|
+
maxPreviewLength
|
|
272
|
+
),
|
|
273
|
+
...typeof err.stack === "string" ? {
|
|
274
|
+
stack: truncateStringForProfile(
|
|
275
|
+
err.stack,
|
|
276
|
+
"stack",
|
|
277
|
+
maxMetadataValueLength,
|
|
278
|
+
maxPreviewLength
|
|
279
|
+
)
|
|
280
|
+
} : {}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return bounded;
|
|
284
|
+
}
|
|
285
|
+
function redactRunTreeForExport(tree, options) {
|
|
286
|
+
const profile = options?.redactionProfile ?? "local";
|
|
287
|
+
if (profile === "local") {
|
|
288
|
+
return deepClone(tree);
|
|
289
|
+
}
|
|
290
|
+
const resolved = resolveRedactionProfile(profile);
|
|
291
|
+
const { maxMetadataValueLength, maxPreviewLength } = applyProfileMetadataCaps(
|
|
292
|
+
2e3,
|
|
293
|
+
500,
|
|
294
|
+
resolved
|
|
295
|
+
);
|
|
296
|
+
const redactor = new Redactor({ extraKeys: resolved.extraKeys });
|
|
297
|
+
const clone = deepClone(tree);
|
|
298
|
+
function walk(nodes) {
|
|
299
|
+
for (const node of nodes) {
|
|
300
|
+
if (node.event.attributes !== void 0) {
|
|
301
|
+
node.event.attributes = redactEventAttributes(
|
|
302
|
+
node.event.attributes,
|
|
303
|
+
redactor,
|
|
304
|
+
maxMetadataValueLength,
|
|
305
|
+
maxPreviewLength
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
if (node.children.length > 0) {
|
|
309
|
+
walk(node.children);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
walk(clone.children);
|
|
314
|
+
return clone;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// packages/core/src/exporters/helpers.ts
|
|
318
|
+
var REDACT_SUBSTRINGS = [
|
|
319
|
+
"authorization",
|
|
320
|
+
"cookie",
|
|
321
|
+
"token",
|
|
322
|
+
"apikey",
|
|
323
|
+
"password",
|
|
324
|
+
"secret",
|
|
325
|
+
"email"
|
|
326
|
+
];
|
|
327
|
+
function shouldRedactKey(key) {
|
|
328
|
+
const k = key.toLowerCase();
|
|
329
|
+
for (const s of REDACT_SUBSTRINGS) {
|
|
330
|
+
if (k.includes(s)) return true;
|
|
331
|
+
}
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
function safeString(value, maxLength) {
|
|
335
|
+
if (value === null || value === void 0) return "";
|
|
336
|
+
let s;
|
|
337
|
+
if (typeof value === "string") s = value;
|
|
338
|
+
else if (typeof value === "number" || typeof value === "boolean") s = String(value);
|
|
339
|
+
else s = stableJson(value, false);
|
|
340
|
+
if (maxLength !== void 0 && maxLength >= 0 && s.length > maxLength) {
|
|
341
|
+
return `${s.slice(0, maxLength)}\u2026`;
|
|
342
|
+
}
|
|
343
|
+
return s;
|
|
344
|
+
}
|
|
345
|
+
function escapeMarkdown(value) {
|
|
346
|
+
return value.replace(/\|/g, "\\|").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n/g, " ");
|
|
347
|
+
}
|
|
348
|
+
function escapeHtml(value) {
|
|
349
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
350
|
+
}
|
|
351
|
+
function sortKeysDeep(input) {
|
|
352
|
+
if (input === null || typeof input !== "object") return input;
|
|
353
|
+
if (Array.isArray(input)) return input.map(sortKeysDeep);
|
|
354
|
+
const o = input;
|
|
355
|
+
const out = {};
|
|
356
|
+
for (const k of Object.keys(o).sort()) {
|
|
357
|
+
out[k] = sortKeysDeep(o[k]);
|
|
358
|
+
}
|
|
359
|
+
return out;
|
|
360
|
+
}
|
|
361
|
+
function stableJson(value, pretty) {
|
|
362
|
+
const sorted = sortKeysDeep(value);
|
|
363
|
+
return pretty === true ? JSON.stringify(sorted, null, 2) : JSON.stringify(sorted);
|
|
364
|
+
}
|
|
365
|
+
function compactAttributes(attrs, options) {
|
|
366
|
+
if (attrs === void 0) return {};
|
|
367
|
+
const maxLen = options?.maxLength ?? 500;
|
|
368
|
+
const redacted = options?.redacted ?? true;
|
|
369
|
+
const out = {};
|
|
370
|
+
for (const key of Object.keys(attrs).sort()) {
|
|
371
|
+
if (redacted && shouldRedactKey(key)) {
|
|
372
|
+
out[key] = "[REDACTED]";
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
const v = attrs[key];
|
|
376
|
+
out[key] = compactValue(v, maxLen, redacted);
|
|
377
|
+
}
|
|
378
|
+
return out;
|
|
379
|
+
}
|
|
380
|
+
function compactValue(value, maxLen, redacted) {
|
|
381
|
+
if (value === null || typeof value !== "object") {
|
|
382
|
+
return typeof value === "string" ? safeString(value, maxLen) : value;
|
|
383
|
+
}
|
|
384
|
+
if (Array.isArray(value)) {
|
|
385
|
+
const arr = value.slice(0, 20).map((x) => compactValue(x, maxLen, redacted));
|
|
386
|
+
if (value.length > 20) arr.push(`\u2026(+${value.length - 20} more)`);
|
|
387
|
+
return arr;
|
|
388
|
+
}
|
|
389
|
+
const o = value;
|
|
390
|
+
const inner = {};
|
|
391
|
+
for (const k of Object.keys(o)) {
|
|
392
|
+
if (redacted && shouldRedactKey(k)) inner[k] = "[REDACTED]";
|
|
393
|
+
else inner[k] = compactValue(o[k], maxLen, redacted);
|
|
394
|
+
}
|
|
395
|
+
return inner;
|
|
396
|
+
}
|
|
397
|
+
function summarizeTree(tree) {
|
|
398
|
+
const flat = flattenTree(tree);
|
|
399
|
+
const errorNodes = flat.filter((n) => n.event.status === "error").length;
|
|
400
|
+
return {
|
|
401
|
+
runId: tree.runId,
|
|
402
|
+
name: tree.name,
|
|
403
|
+
status: tree.status,
|
|
404
|
+
startedAt: tree.startedAt,
|
|
405
|
+
endedAt: tree.endedAt,
|
|
406
|
+
durationMs: tree.durationMs,
|
|
407
|
+
stepCount: flat.length,
|
|
408
|
+
errorStepCount: errorNodes,
|
|
409
|
+
totalEvents: tree.metadata.totalEvents,
|
|
410
|
+
confidenceBreakdown: { ...tree.metadata.confidenceBreakdown },
|
|
411
|
+
kinds: { ...tree.metadata.kinds }
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function flattenTree(tree) {
|
|
415
|
+
const out = [];
|
|
416
|
+
function walk(nodes) {
|
|
417
|
+
for (const n of nodes) {
|
|
418
|
+
out.push(n);
|
|
419
|
+
if (n.children.length > 0) walk(n.children);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
walk(tree.children);
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
function zeroKinds() {
|
|
426
|
+
return {
|
|
427
|
+
RUN: 0,
|
|
428
|
+
AGENT: 0,
|
|
429
|
+
LLM: 0,
|
|
430
|
+
TOOL: 0,
|
|
431
|
+
CHAIN: 0,
|
|
432
|
+
RETRIEVER: 0,
|
|
433
|
+
DECISION: 0,
|
|
434
|
+
RESULT: 0,
|
|
435
|
+
ERROR: 0,
|
|
436
|
+
LOGIC: 0,
|
|
437
|
+
LOG: 0
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// packages/core/src/exporters/html-exporter.ts
|
|
442
|
+
function renderTreeHtml(nodes, ulClass = "tree") {
|
|
443
|
+
if (nodes.length === 0) return "";
|
|
444
|
+
const parts = [`<ul class="${ulClass}">`];
|
|
445
|
+
for (const n of nodes) {
|
|
446
|
+
const ev = n.event;
|
|
447
|
+
const status = ev.status ?? "?";
|
|
448
|
+
const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
|
|
449
|
+
parts.push("<li>");
|
|
450
|
+
parts.push(
|
|
451
|
+
`<span class="nm">${escapeHtml(ev.name)}</span> <span class="meta">[${escapeHtml(ev.kind)}] ${escapeHtml(status)} (${escapeHtml(dur)})</span>`
|
|
452
|
+
);
|
|
453
|
+
if (n.children.length > 0) {
|
|
454
|
+
parts.push(renderTreeHtml(n.children, "tree nested"));
|
|
455
|
+
}
|
|
456
|
+
parts.push("</li>");
|
|
457
|
+
}
|
|
458
|
+
parts.push("</ul>");
|
|
459
|
+
return parts.join("");
|
|
460
|
+
}
|
|
461
|
+
function exportHtml(tree, options) {
|
|
462
|
+
const warnings = [];
|
|
463
|
+
const includeMetadata = options?.includeMetadata ?? true;
|
|
464
|
+
const includeAttributes = options?.includeAttributes ?? false;
|
|
465
|
+
const includeErrors = options?.includeErrors ?? true;
|
|
466
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
467
|
+
const redacted = options?.redacted ?? true;
|
|
468
|
+
const titleName = escapeHtml(tree.name ?? tree.runId);
|
|
469
|
+
const summaryRows = [];
|
|
470
|
+
summaryRows.push(
|
|
471
|
+
`<tr><th scope="row">runId</th><td><code>${escapeHtml(tree.runId)}</code></td></tr>`
|
|
472
|
+
);
|
|
473
|
+
if (tree.name !== void 0) {
|
|
474
|
+
summaryRows.push(`<tr><th scope="row">name</th><td>${escapeHtml(tree.name)}</td></tr>`);
|
|
475
|
+
}
|
|
476
|
+
summaryRows.push(
|
|
477
|
+
`<tr><th scope="row">status</th><td>${escapeHtml(String(tree.status ?? "unknown"))}</td></tr>`
|
|
478
|
+
);
|
|
479
|
+
summaryRows.push(
|
|
480
|
+
`<tr><th scope="row">durationMs</th><td>${tree.durationMs !== void 0 ? escapeHtml(String(tree.durationMs)) : "\u2014"}</td></tr>`
|
|
481
|
+
);
|
|
482
|
+
summaryRows.push(
|
|
483
|
+
`<tr><th scope="row">startedAt</th><td>${tree.startedAt !== void 0 ? escapeHtml(String(tree.startedAt)) : "\u2014"}</td></tr>`
|
|
484
|
+
);
|
|
485
|
+
summaryRows.push(
|
|
486
|
+
`<tr><th scope="row">endedAt</th><td>${tree.endedAt !== void 0 ? escapeHtml(String(tree.endedAt)) : "\u2014"}</td></tr>`
|
|
487
|
+
);
|
|
488
|
+
summaryRows.push(
|
|
489
|
+
`<tr><th scope="row">totalEvents</th><td>${escapeHtml(String(tree.metadata.totalEvents))}</td></tr>`
|
|
490
|
+
);
|
|
491
|
+
let confidenceHtml = "";
|
|
492
|
+
if (includeMetadata) {
|
|
493
|
+
const cb = tree.metadata.confidenceBreakdown;
|
|
494
|
+
confidenceHtml += "<h3>Confidence breakdown</h3><table><thead><tr><th>bucket</th><th>count</th></tr></thead><tbody>";
|
|
495
|
+
for (const k of Object.keys(cb).sort()) {
|
|
496
|
+
const key = k;
|
|
497
|
+
confidenceHtml += `<tr><td>${escapeHtml(key)}</td><td>${cb[key]}</td></tr>`;
|
|
498
|
+
}
|
|
499
|
+
confidenceHtml += "</tbody></table>";
|
|
500
|
+
confidenceHtml += "<h3>Kind breakdown</h3><table><thead><tr><th>kind</th><th>count</th></tr></thead><tbody>";
|
|
501
|
+
for (const k of Object.keys(tree.metadata.kinds).sort()) {
|
|
502
|
+
const key = k;
|
|
503
|
+
const c = tree.metadata.kinds[key];
|
|
504
|
+
if (c > 0) confidenceHtml += `<tr><td>${escapeHtml(key)}</td><td>${c}</td></tr>`;
|
|
505
|
+
}
|
|
506
|
+
confidenceHtml += "</tbody></table>";
|
|
507
|
+
}
|
|
508
|
+
const flat = flattenTree(tree);
|
|
509
|
+
const errors = flat.filter((n) => n.event.status === "error");
|
|
510
|
+
let errorsHtml = "";
|
|
511
|
+
if (includeErrors && errors.length > 0) {
|
|
512
|
+
errorsHtml += "<h2>Errors</h2><ul>";
|
|
513
|
+
for (const n of errors) {
|
|
514
|
+
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
|
|
515
|
+
n.event.attributes.error.message,
|
|
516
|
+
maxLen
|
|
517
|
+
) : "";
|
|
518
|
+
errorsHtml += `<li><strong>${escapeHtml(n.event.name)}</strong> (${escapeHtml(n.event.eventId)}): ${escapeHtml(msg || "error")}</li>`;
|
|
519
|
+
}
|
|
520
|
+
errorsHtml += "</ul>";
|
|
521
|
+
}
|
|
522
|
+
let attrsHtml = "";
|
|
523
|
+
if (includeAttributes) {
|
|
524
|
+
attrsHtml += "<h2>Attributes (bounded)</h2>";
|
|
525
|
+
for (const n of flat) {
|
|
526
|
+
if (!n.event.attributes || Object.keys(n.event.attributes).length === 0) continue;
|
|
527
|
+
const compact = compactAttributes(n.event.attributes, {
|
|
528
|
+
maxLength: maxLen,
|
|
529
|
+
redacted
|
|
530
|
+
});
|
|
531
|
+
attrsHtml += `<h3>${escapeHtml(n.event.name)}</h3><pre class="json">${escapeHtml(stableJson(compact, true))}</pre>`;
|
|
532
|
+
}
|
|
533
|
+
warnings.push(
|
|
534
|
+
"Attributes may still contain sensitive data; review exports before sharing."
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const css = `
|
|
538
|
+
body{font-family:system-ui,sans-serif;line-height:1.5;margin:1.5rem;max-width:960px;color:#111}
|
|
539
|
+
h1{font-size:1.35rem}
|
|
540
|
+
h2{font-size:1.1rem;margin-top:1.5rem}
|
|
541
|
+
table{border-collapse:collapse;margin:0.75rem 0}
|
|
542
|
+
th,td{border:1px solid #ccc;padding:0.35rem 0.6rem;text-align:left}
|
|
543
|
+
th{background:#f5f5f5}
|
|
544
|
+
pre.json{background:#f8f8f8;padding:0.75rem;overflow:auto;font-size:0.85rem}
|
|
545
|
+
ul.tree{list-style:none;padding-left:1rem}
|
|
546
|
+
ul.tree.nested{padding-left:1.25rem;border-left:1px solid #ddd;margin:0.25rem 0}
|
|
547
|
+
.nm{font-weight:600}
|
|
548
|
+
.meta{color:#555;font-size:0.9rem}
|
|
549
|
+
footer{margin-top:2rem;font-size:0.85rem;color:#555}
|
|
550
|
+
`.trim();
|
|
551
|
+
const html = `<!doctype html>
|
|
552
|
+
<html lang="en">
|
|
553
|
+
<head>
|
|
554
|
+
<meta charset="utf-8"/>
|
|
555
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
556
|
+
<title>${titleName}</title>
|
|
557
|
+
<style>${css}</style>
|
|
558
|
+
</head>
|
|
559
|
+
<body>
|
|
560
|
+
<header><h1>AgentInspect Run: ${titleName}</h1></header>
|
|
561
|
+
<p class="note">Generated locally by AgentInspect.</p>
|
|
562
|
+
${includeMetadata ? `<section class="summary"><h2>Summary</h2><table>${summaryRows.join("")}</table>${confidenceHtml}</section>` : ""}
|
|
563
|
+
<section class="tree"><h2>Execution tree</h2>${tree.children.length > 0 ? renderTreeHtml(tree.children) : "<p>No steps recorded.</p>"}</section>
|
|
564
|
+
${errorsHtml}
|
|
565
|
+
${attrsHtml}
|
|
566
|
+
<footer>Generated locally by AgentInspect. Review for sensitive data before sharing.</footer>
|
|
567
|
+
</body>
|
|
568
|
+
</html>`;
|
|
569
|
+
return {
|
|
570
|
+
format: "html",
|
|
571
|
+
content: html,
|
|
572
|
+
contentType: "text/html",
|
|
573
|
+
fileExtension: ".html",
|
|
574
|
+
warnings
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// packages/core/src/exporters/markdown-exporter.ts
|
|
579
|
+
function renderTreeAscii(nodes, indent = "") {
|
|
580
|
+
const lines = [];
|
|
581
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
582
|
+
const n = nodes[i];
|
|
583
|
+
const last = i === nodes.length - 1;
|
|
584
|
+
const branch = last ? "\u2514\u2500 " : "\u251C\u2500 ";
|
|
585
|
+
const ev = n.event;
|
|
586
|
+
const status = ev.status ?? "?";
|
|
587
|
+
const dur = ev.durationMs !== void 0 && Number.isFinite(ev.durationMs) ? `${ev.durationMs}ms` : "-";
|
|
588
|
+
lines.push(`${indent}${branch}${escapeMarkdown(ev.name)} [${ev.kind}] ${status} (${dur})`);
|
|
589
|
+
const nextIndent = indent + (last ? " " : "\u2502 ");
|
|
590
|
+
if (n.children.length > 0) {
|
|
591
|
+
const childStr = renderTreeAscii(n.children, nextIndent);
|
|
592
|
+
if (childStr.length > 0) lines.push(childStr);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return lines.join("\n");
|
|
596
|
+
}
|
|
597
|
+
function exportMarkdown(tree, options) {
|
|
598
|
+
const warnings = [];
|
|
599
|
+
const includeMetadata = options?.includeMetadata ?? true;
|
|
600
|
+
const includeAttributes = options?.includeAttributes ?? false;
|
|
601
|
+
const includeErrors = options?.includeErrors ?? true;
|
|
602
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
603
|
+
const redacted = options?.redacted ?? true;
|
|
604
|
+
const titleName = tree.name ?? tree.runId;
|
|
605
|
+
const lines = [];
|
|
606
|
+
lines.push(`# AgentInspect Run: ${escapeMarkdown(titleName)}`);
|
|
607
|
+
lines.push("");
|
|
608
|
+
lines.push("Generated locally by AgentInspect. Review for sensitive data before sharing.");
|
|
609
|
+
lines.push("");
|
|
610
|
+
if (includeMetadata) {
|
|
611
|
+
lines.push("## Summary");
|
|
612
|
+
lines.push("");
|
|
613
|
+
lines.push(`- **runId**: ${escapeMarkdown(tree.runId)}`);
|
|
614
|
+
if (tree.name !== void 0) lines.push(`- **name**: ${escapeMarkdown(tree.name)}`);
|
|
615
|
+
lines.push(`- **status**: ${escapeMarkdown(String(tree.status ?? "unknown"))}`);
|
|
616
|
+
lines.push(
|
|
617
|
+
`- **durationMs**: ${tree.durationMs !== void 0 ? escapeMarkdown(String(tree.durationMs)) : "-"}`
|
|
618
|
+
);
|
|
619
|
+
lines.push(
|
|
620
|
+
`- **startedAt**: ${tree.startedAt !== void 0 ? escapeMarkdown(String(tree.startedAt)) : "-"}`
|
|
621
|
+
);
|
|
622
|
+
lines.push(
|
|
623
|
+
`- **endedAt**: ${tree.endedAt !== void 0 ? escapeMarkdown(String(tree.endedAt)) : "-"}`
|
|
624
|
+
);
|
|
625
|
+
lines.push(`- **totalEvents**: ${tree.metadata.totalEvents}`);
|
|
626
|
+
lines.push("");
|
|
627
|
+
lines.push("### Confidence breakdown");
|
|
628
|
+
lines.push("");
|
|
629
|
+
lines.push("| bucket | count |");
|
|
630
|
+
lines.push("| --- | --- |");
|
|
631
|
+
for (const k of Object.keys(tree.metadata.confidenceBreakdown).sort()) {
|
|
632
|
+
const key = k;
|
|
633
|
+
lines.push(
|
|
634
|
+
`| ${escapeMarkdown(key)} | ${tree.metadata.confidenceBreakdown[key]} |`
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
lines.push("");
|
|
638
|
+
lines.push("### Kind breakdown");
|
|
639
|
+
lines.push("");
|
|
640
|
+
lines.push("| kind | count |");
|
|
641
|
+
lines.push("| --- | --- |");
|
|
642
|
+
for (const k of Object.keys(tree.metadata.kinds).sort()) {
|
|
643
|
+
const key = k;
|
|
644
|
+
const c = tree.metadata.kinds[key];
|
|
645
|
+
if (c > 0) lines.push(`| ${escapeMarkdown(key)} | ${c} |`);
|
|
646
|
+
}
|
|
647
|
+
lines.push("");
|
|
648
|
+
}
|
|
649
|
+
lines.push("## Execution tree");
|
|
650
|
+
lines.push("");
|
|
651
|
+
lines.push("```text");
|
|
652
|
+
lines.push(
|
|
653
|
+
tree.children.length > 0 ? renderTreeAscii(tree.children) : "(no steps)"
|
|
654
|
+
);
|
|
655
|
+
lines.push("```");
|
|
656
|
+
lines.push("");
|
|
657
|
+
const flat = flattenTree(tree);
|
|
658
|
+
const errors = flat.filter((n) => n.event.status === "error");
|
|
659
|
+
if (includeErrors && errors.length > 0) {
|
|
660
|
+
lines.push("## Errors");
|
|
661
|
+
lines.push("");
|
|
662
|
+
for (const n of errors) {
|
|
663
|
+
const msg = n.event.attributes && typeof n.event.attributes.error === "object" ? safeString(
|
|
664
|
+
n.event.attributes.error.message,
|
|
665
|
+
maxLen
|
|
666
|
+
) : "";
|
|
667
|
+
lines.push(
|
|
668
|
+
`- **${escapeMarkdown(n.event.name)}** (${escapeMarkdown(n.event.eventId)}): ${escapeMarkdown(msg || "error")}`
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
lines.push("");
|
|
672
|
+
}
|
|
673
|
+
if (includeAttributes) {
|
|
674
|
+
lines.push("## Attributes (bounded)");
|
|
675
|
+
lines.push("");
|
|
676
|
+
for (const n of flat) {
|
|
677
|
+
if (!n.event.attributes || Object.keys(n.event.attributes).length === 0) continue;
|
|
678
|
+
const compact = compactAttributes(n.event.attributes, {
|
|
679
|
+
maxLength: maxLen,
|
|
680
|
+
redacted
|
|
681
|
+
});
|
|
682
|
+
lines.push(`### ${escapeMarkdown(n.event.name)}`);
|
|
683
|
+
lines.push("");
|
|
684
|
+
lines.push("```json");
|
|
685
|
+
lines.push(stableJson(compact, true));
|
|
686
|
+
lines.push("```");
|
|
687
|
+
lines.push("");
|
|
688
|
+
}
|
|
689
|
+
warnings.push(
|
|
690
|
+
"Attributes may still contain sensitive data; review exports before sharing."
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
return {
|
|
694
|
+
format: "markdown",
|
|
695
|
+
content: lines.join("\n"),
|
|
696
|
+
contentType: "text/markdown",
|
|
697
|
+
fileExtension: ".md",
|
|
698
|
+
warnings
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
function hexFrom(seed, byteLen) {
|
|
702
|
+
return crypto__default.default.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
|
|
703
|
+
}
|
|
704
|
+
function mapInspectKindToOI(kind, warnings) {
|
|
705
|
+
switch (kind) {
|
|
706
|
+
case "LLM":
|
|
707
|
+
return { openInferenceKind: "LLM" };
|
|
708
|
+
case "TOOL":
|
|
709
|
+
return { openInferenceKind: "TOOL" };
|
|
710
|
+
case "CHAIN":
|
|
711
|
+
return { openInferenceKind: "CHAIN" };
|
|
712
|
+
case "RETRIEVER":
|
|
713
|
+
return { openInferenceKind: "RETRIEVER" };
|
|
714
|
+
case "AGENT":
|
|
715
|
+
return { openInferenceKind: "AGENT" };
|
|
716
|
+
case "DECISION":
|
|
717
|
+
warnings.push(
|
|
718
|
+
`Ambiguous kind DECISION mapped to CHAIN for span compatibility (${EXPORT_PAYLOAD_VERSION}).`
|
|
719
|
+
);
|
|
720
|
+
return { openInferenceKind: "CHAIN" };
|
|
721
|
+
case "RESULT":
|
|
722
|
+
warnings.push(
|
|
723
|
+
`Ambiguous kind RESULT mapped to UNKNOWN for span compatibility (${EXPORT_PAYLOAD_VERSION}).`
|
|
724
|
+
);
|
|
725
|
+
return { openInferenceKind: "UNKNOWN" };
|
|
726
|
+
case "ERROR":
|
|
727
|
+
warnings.push(`ERROR kind mapped to CHAIN for span compatibility.`);
|
|
728
|
+
return { openInferenceKind: "CHAIN" };
|
|
729
|
+
case "LOG":
|
|
730
|
+
case "LOGIC":
|
|
731
|
+
case "RUN":
|
|
732
|
+
warnings.push(`${kind} mapped to CHAIN for span compatibility.`);
|
|
733
|
+
return { openInferenceKind: "CHAIN" };
|
|
734
|
+
default:
|
|
735
|
+
warnings.push(`Unhandled InspectKind ${kind} mapped to UNKNOWN.`);
|
|
736
|
+
return { openInferenceKind: "UNKNOWN" };
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
function exportOpenInference(tree, options) {
|
|
740
|
+
const warnings = [
|
|
741
|
+
"OpenInference-compatible JSON export is experimental until verified against specific backends.",
|
|
742
|
+
"This file was generated locally and not sent anywhere."
|
|
743
|
+
];
|
|
744
|
+
const traceId = hexFrom(`trace:${tree.runId}`, 16);
|
|
745
|
+
const includeAttributes = options?.includeAttributes ?? false;
|
|
746
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
747
|
+
const pretty = options?.pretty ?? true;
|
|
748
|
+
const spans = [];
|
|
749
|
+
for (const n of flattenTree(tree)) {
|
|
750
|
+
const ev = n.event;
|
|
751
|
+
const spanId = hexFrom(`${tree.runId}:${ev.eventId}`, 8);
|
|
752
|
+
const parentSpanHex = ev.parentId ? hexFrom(`${tree.runId}:${ev.parentId}`, 8) : void 0;
|
|
753
|
+
const startNs = Math.round(ev.timestamp * 1e6);
|
|
754
|
+
let endNs;
|
|
755
|
+
if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
|
|
756
|
+
endNs = startNs + Math.round(ev.durationMs * 1e6);
|
|
757
|
+
}
|
|
758
|
+
const { openInferenceKind } = mapInspectKindToOI(ev.kind, warnings);
|
|
759
|
+
const attrs = {
|
|
760
|
+
"openinference.span.kind": openInferenceKind,
|
|
761
|
+
"agent_inspect.kind": ev.kind,
|
|
762
|
+
"agent_inspect.confidence": ev.confidence,
|
|
763
|
+
"agent_inspect.source.type": ev.source.type,
|
|
764
|
+
"agent_inspect.run_id": tree.runId,
|
|
765
|
+
"agent_inspect.event_id": ev.eventId,
|
|
766
|
+
"agent_inspect.status": ev.status ?? "unset"
|
|
767
|
+
};
|
|
768
|
+
if (ev.durationMs !== void 0) {
|
|
769
|
+
attrs["agent_inspect.duration_ms"] = ev.durationMs;
|
|
770
|
+
}
|
|
771
|
+
const meta = ev.attributes;
|
|
772
|
+
if (meta?.model !== void 0 && typeof meta.model === "string") {
|
|
773
|
+
attrs["llm.model_name"] = meta.model;
|
|
774
|
+
}
|
|
775
|
+
const tokens = meta?.tokens;
|
|
776
|
+
if (tokens && typeof tokens === "object" && tokens !== null) {
|
|
777
|
+
const inp = tokens.input;
|
|
778
|
+
const outp = tokens.output;
|
|
779
|
+
if (typeof inp === "number") attrs["llm.token_count.prompt"] = inp;
|
|
780
|
+
if (typeof outp === "number") attrs["llm.token_count.completion"] = outp;
|
|
781
|
+
}
|
|
782
|
+
if (includeAttributes && meta && typeof meta === "object") {
|
|
783
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
784
|
+
if (k === "tokens" || k === "model") continue;
|
|
785
|
+
if (v !== void 0 && v !== null && typeof v !== "object") {
|
|
786
|
+
attrs[`agent_inspect.preview.${k}`] = typeof v === "string" ? v.slice(0, maxLen) : v;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
let status;
|
|
791
|
+
if (ev.status === "error") {
|
|
792
|
+
const msg = meta && typeof meta.error === "object" && meta.error !== null ? String(meta.error.message ?? "error") : "error";
|
|
793
|
+
status = { code: "ERROR", message: msg.slice(0, maxLen) };
|
|
794
|
+
} else if (ev.status === "ok") {
|
|
795
|
+
status = { code: "OK" };
|
|
796
|
+
} else {
|
|
797
|
+
status = { code: "UNSET" };
|
|
798
|
+
}
|
|
799
|
+
spans.push({
|
|
800
|
+
trace_id: traceId,
|
|
801
|
+
span_id: spanId,
|
|
802
|
+
parent_span_id: parentSpanHex,
|
|
803
|
+
name: ev.name,
|
|
804
|
+
start_time_unix_nano: startNs,
|
|
805
|
+
end_time_unix_nano: endNs,
|
|
806
|
+
attributes: attrs,
|
|
807
|
+
status
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
const payload = {
|
|
811
|
+
exporter: "agent-inspect",
|
|
812
|
+
format: "openinference",
|
|
813
|
+
compatibility: "openinference-compatible",
|
|
814
|
+
version: EXPORT_PAYLOAD_VERSION,
|
|
815
|
+
trace_id: traceId,
|
|
816
|
+
spans,
|
|
817
|
+
warnings
|
|
818
|
+
};
|
|
819
|
+
return {
|
|
820
|
+
format: "openinference",
|
|
821
|
+
content: JSON.stringify(payload, null, pretty ? 2 : void 0),
|
|
822
|
+
contentType: "application/json",
|
|
823
|
+
fileExtension: ".openinference.json",
|
|
824
|
+
warnings
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
function hexFrom2(seed, byteLen) {
|
|
828
|
+
return crypto__default.default.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
|
|
829
|
+
}
|
|
830
|
+
function stringAttr(key, value) {
|
|
831
|
+
return { key, value: { stringValue: value } };
|
|
832
|
+
}
|
|
833
|
+
function intAttr(key, value) {
|
|
834
|
+
return { key, value: { intValue: String(value) } };
|
|
835
|
+
}
|
|
836
|
+
function genAiOperationName(kind) {
|
|
837
|
+
switch (kind) {
|
|
838
|
+
case "LLM":
|
|
839
|
+
return "generate_content";
|
|
840
|
+
case "TOOL":
|
|
841
|
+
return "execute_tool";
|
|
842
|
+
case "AGENT":
|
|
843
|
+
return "invoke_agent";
|
|
844
|
+
default:
|
|
845
|
+
return void 0;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function exportOtlpJson(tree, options) {
|
|
849
|
+
const warnings = [
|
|
850
|
+
"OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
|
|
851
|
+
"Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload."
|
|
852
|
+
];
|
|
853
|
+
const traceId = hexFrom2(`trace:${tree.runId}`, 16);
|
|
854
|
+
const includeAttributes = options?.includeAttributes ?? false;
|
|
855
|
+
const maxLen = options?.maxAttributeLength ?? 500;
|
|
856
|
+
const pretty = options?.pretty ?? true;
|
|
857
|
+
const flat = flattenTree(tree);
|
|
858
|
+
const spans = [];
|
|
859
|
+
for (const n of flat) {
|
|
860
|
+
const ev = n.event;
|
|
861
|
+
const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
|
|
862
|
+
const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
|
|
863
|
+
const startNs = String(Math.round(ev.timestamp * 1e6));
|
|
864
|
+
let endNs;
|
|
865
|
+
if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
|
|
866
|
+
endNs = String(Math.round(ev.timestamp * 1e6 + ev.durationMs * 1e6));
|
|
867
|
+
}
|
|
868
|
+
const attrs = [
|
|
869
|
+
stringAttr("agent_inspect.kind", ev.kind),
|
|
870
|
+
stringAttr("agent_inspect.confidence", ev.confidence),
|
|
871
|
+
stringAttr("agent_inspect.source.type", ev.source.type),
|
|
872
|
+
stringAttr("agent_inspect.run_id", tree.runId),
|
|
873
|
+
stringAttr("agent_inspect.event_id", ev.eventId),
|
|
874
|
+
stringAttr("agent_inspect.status", ev.status ?? "unset")
|
|
875
|
+
];
|
|
876
|
+
if (ev.durationMs !== void 0) {
|
|
877
|
+
attrs.push(intAttr("agent_inspect.duration_ms", ev.durationMs));
|
|
878
|
+
}
|
|
879
|
+
const op = genAiOperationName(ev.kind);
|
|
880
|
+
if (op !== void 0) {
|
|
881
|
+
attrs.push(stringAttr("gen_ai.operation.name", op));
|
|
882
|
+
}
|
|
883
|
+
const meta = ev.attributes;
|
|
884
|
+
if (meta?.model !== void 0 && typeof meta.model === "string") {
|
|
885
|
+
attrs.push(stringAttr("gen_ai.request.model", meta.model.slice(0, maxLen)));
|
|
886
|
+
}
|
|
887
|
+
const tokens = meta?.tokens;
|
|
888
|
+
if (tokens && typeof tokens === "object" && tokens !== null) {
|
|
889
|
+
const inp = tokens.input;
|
|
890
|
+
const outp = tokens.output;
|
|
891
|
+
if (typeof inp === "number") attrs.push(intAttr("gen_ai.usage.input_tokens", inp));
|
|
892
|
+
if (typeof outp === "number") attrs.push(intAttr("gen_ai.usage.output_tokens", outp));
|
|
893
|
+
}
|
|
894
|
+
if (includeAttributes && meta && typeof meta === "object") {
|
|
895
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
896
|
+
if (k === "tokens" || k === "model") continue;
|
|
897
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
898
|
+
attrs.push(
|
|
899
|
+
stringAttr(
|
|
900
|
+
`agent_inspect.preview.${k}`,
|
|
901
|
+
typeof v === "string" ? v.slice(0, maxLen) : String(v)
|
|
902
|
+
)
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
let statusCode = "STATUS_CODE_UNSET";
|
|
908
|
+
let statusMessage;
|
|
909
|
+
if (ev.status === "error") {
|
|
910
|
+
statusCode = "STATUS_CODE_ERROR";
|
|
911
|
+
statusMessage = meta && typeof meta.error === "object" && meta.error !== null ? String(meta.error.message ?? "error").slice(0, maxLen) : "error";
|
|
912
|
+
} else if (ev.status === "ok") {
|
|
913
|
+
statusCode = "STATUS_CODE_OK";
|
|
914
|
+
}
|
|
915
|
+
const spanJson = {
|
|
916
|
+
traceId,
|
|
917
|
+
spanId,
|
|
918
|
+
name: ev.name,
|
|
919
|
+
kind: "SPAN_KIND_INTERNAL",
|
|
920
|
+
startTimeUnixNano: startNs,
|
|
921
|
+
attributes: attrs,
|
|
922
|
+
status: {
|
|
923
|
+
code: statusCode,
|
|
924
|
+
...statusMessage !== void 0 ? { message: statusMessage } : {}
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
if (parentSpanId !== void 0) {
|
|
928
|
+
spanJson.parentSpanId = parentSpanId;
|
|
929
|
+
}
|
|
930
|
+
if (endNs !== void 0) {
|
|
931
|
+
spanJson.endTimeUnixNano = endNs;
|
|
932
|
+
}
|
|
933
|
+
spans.push(spanJson);
|
|
934
|
+
}
|
|
935
|
+
const payload = {
|
|
936
|
+
resourceSpans: [
|
|
937
|
+
{
|
|
938
|
+
resource: {
|
|
939
|
+
attributes: [stringAttr("service.name", "agent-inspect")]
|
|
940
|
+
},
|
|
941
|
+
scopeSpans: [
|
|
942
|
+
{
|
|
943
|
+
scope: { name: "agent-inspect" },
|
|
944
|
+
spans
|
|
945
|
+
}
|
|
946
|
+
]
|
|
947
|
+
}
|
|
948
|
+
]
|
|
949
|
+
};
|
|
950
|
+
return {
|
|
951
|
+
format: "otlp-json",
|
|
952
|
+
content: JSON.stringify(payload, null, pretty ? 2 : void 0),
|
|
953
|
+
contentType: "application/json",
|
|
954
|
+
fileExtension: ".otlp.json",
|
|
955
|
+
warnings
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// packages/core/src/exporters/validation.ts
|
|
960
|
+
var EXPERIMENTAL = "Experimental compatibility export \u2014 verify against your target tooling before relying on it.";
|
|
961
|
+
function validateExportContent(format, content) {
|
|
962
|
+
const errors = [];
|
|
963
|
+
const warnings = [EXPERIMENTAL];
|
|
964
|
+
if (format === "markdown") {
|
|
965
|
+
if (!content.startsWith("# AgentInspect Run")) {
|
|
966
|
+
errors.push('Markdown export must start with "# AgentInspect Run"');
|
|
967
|
+
}
|
|
968
|
+
return { ok: errors.length === 0, format, errors, warnings };
|
|
969
|
+
}
|
|
970
|
+
if (format === "html") {
|
|
971
|
+
const lower = content.toLowerCase();
|
|
972
|
+
if (!lower.includes("<!doctype html")) {
|
|
973
|
+
errors.push("HTML export must include <!doctype html>");
|
|
974
|
+
}
|
|
975
|
+
if (/<\s*script\b/i.test(content)) {
|
|
976
|
+
errors.push("HTML export must not contain script tags");
|
|
977
|
+
}
|
|
978
|
+
if (/<\s*link\b[^>]*href\s*=/i.test(content)) {
|
|
979
|
+
warnings.push("HTML export contains link tags \u2014 ensure no external stylesheets.");
|
|
980
|
+
}
|
|
981
|
+
return { ok: errors.length === 0, format, errors, warnings };
|
|
982
|
+
}
|
|
983
|
+
if (format === "openinference") {
|
|
984
|
+
let parsed;
|
|
985
|
+
try {
|
|
986
|
+
parsed = JSON.parse(content);
|
|
987
|
+
} catch {
|
|
988
|
+
errors.push("OpenInference export is not valid JSON");
|
|
989
|
+
return { ok: false, format, errors, warnings };
|
|
990
|
+
}
|
|
991
|
+
if (!parsed || typeof parsed !== "object") {
|
|
992
|
+
errors.push("OpenInference export JSON must be an object");
|
|
993
|
+
return { ok: false, format, errors, warnings };
|
|
994
|
+
}
|
|
995
|
+
const o = parsed;
|
|
996
|
+
if (o.format !== "openinference") {
|
|
997
|
+
errors.push('OpenInference export must include format: "openinference"');
|
|
998
|
+
}
|
|
999
|
+
if (!Array.isArray(o.spans)) {
|
|
1000
|
+
errors.push("OpenInference export must include a spans array");
|
|
1001
|
+
}
|
|
1002
|
+
warnings.push("OpenInference-compatible JSON is not guaranteed for every backend.");
|
|
1003
|
+
return { ok: errors.length === 0, format, errors, warnings };
|
|
1004
|
+
}
|
|
1005
|
+
if (format === "otlp-json") {
|
|
1006
|
+
let parsed;
|
|
1007
|
+
try {
|
|
1008
|
+
parsed = JSON.parse(content);
|
|
1009
|
+
} catch {
|
|
1010
|
+
errors.push("OTLP JSON export is not valid JSON");
|
|
1011
|
+
return { ok: false, format, errors, warnings };
|
|
1012
|
+
}
|
|
1013
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1014
|
+
errors.push("OTLP JSON export must be an object");
|
|
1015
|
+
return { ok: false, format, errors, warnings };
|
|
1016
|
+
}
|
|
1017
|
+
const o = parsed;
|
|
1018
|
+
if (!Array.isArray(o.resourceSpans)) {
|
|
1019
|
+
errors.push("OTLP JSON export must include resourceSpans array");
|
|
1020
|
+
}
|
|
1021
|
+
warnings.push(
|
|
1022
|
+
"OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation."
|
|
1023
|
+
);
|
|
1024
|
+
return { ok: errors.length === 0, format, errors, warnings };
|
|
1025
|
+
}
|
|
1026
|
+
errors.push(`Unsupported export format`);
|
|
1027
|
+
return { ok: false, format, errors, warnings };
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// packages/core/src/exporters/manual-trace-adapter.ts
|
|
1031
|
+
function stepTypeToInspectKind(t) {
|
|
1032
|
+
switch (t) {
|
|
1033
|
+
case "llm":
|
|
1034
|
+
return "LLM";
|
|
1035
|
+
case "tool":
|
|
1036
|
+
return "TOOL";
|
|
1037
|
+
case "decision":
|
|
1038
|
+
return "DECISION";
|
|
1039
|
+
case "run":
|
|
1040
|
+
return "CHAIN";
|
|
1041
|
+
default:
|
|
1042
|
+
return "LOGIC";
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function mapStepStatus(s) {
|
|
1046
|
+
if (s === void 0) return "running";
|
|
1047
|
+
if (s === "success") return "ok";
|
|
1048
|
+
return "error";
|
|
1049
|
+
}
|
|
1050
|
+
function manualTraceEventsToRunTree(events) {
|
|
1051
|
+
const started = events.find((e) => e.event === "run_started");
|
|
1052
|
+
if (!started || started.event !== "run_started") {
|
|
1053
|
+
throw new Error("Invalid trace: missing run_started");
|
|
1054
|
+
}
|
|
1055
|
+
const runId = started.runId;
|
|
1056
|
+
const runName = started.name;
|
|
1057
|
+
const completedAll = events.filter((e) => e.event === "run_completed");
|
|
1058
|
+
const lastCompleted = completedAll[completedAll.length - 1];
|
|
1059
|
+
let runStatus;
|
|
1060
|
+
if (lastCompleted === void 0) {
|
|
1061
|
+
runStatus = "running";
|
|
1062
|
+
} else if (lastCompleted.status === "success") {
|
|
1063
|
+
runStatus = "ok";
|
|
1064
|
+
} else {
|
|
1065
|
+
runStatus = "error";
|
|
1066
|
+
}
|
|
1067
|
+
const startedAt = started.startTime;
|
|
1068
|
+
const endedAt = lastCompleted !== void 0 && runStatus !== "running" ? lastCompleted.endTime : void 0;
|
|
1069
|
+
const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
1070
|
+
const steps = /* @__PURE__ */ new Map();
|
|
1071
|
+
for (const e of events) {
|
|
1072
|
+
if (e.event !== "step_started") continue;
|
|
1073
|
+
const s = e;
|
|
1074
|
+
steps.set(s.stepId, {
|
|
1075
|
+
id: s.stepId,
|
|
1076
|
+
parentId: s.parentId,
|
|
1077
|
+
name: s.name,
|
|
1078
|
+
type: s.type,
|
|
1079
|
+
startTime: s.startTime,
|
|
1080
|
+
timestamp: s.timestamp,
|
|
1081
|
+
metadata: s.metadata
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
for (const e of events) {
|
|
1085
|
+
if (e.event !== "step_completed") continue;
|
|
1086
|
+
const acc = steps.get(e.stepId);
|
|
1087
|
+
if (!acc) continue;
|
|
1088
|
+
acc.status = e.status;
|
|
1089
|
+
acc.endTime = e.endTime;
|
|
1090
|
+
acc.durationMs = e.durationMs;
|
|
1091
|
+
if (e.error?.message) {
|
|
1092
|
+
acc.error = e.error;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const inspectNodes = /* @__PURE__ */ new Map();
|
|
1096
|
+
for (const acc of steps.values()) {
|
|
1097
|
+
const kind = stepTypeToInspectKind(acc.type);
|
|
1098
|
+
const status = mapStepStatus(acc.status);
|
|
1099
|
+
const attrs = { ...acc.metadata ?? {} };
|
|
1100
|
+
if (acc.error?.message) {
|
|
1101
|
+
attrs.error = acc.error;
|
|
1102
|
+
}
|
|
1103
|
+
const evt = {
|
|
1104
|
+
eventId: acc.id,
|
|
1105
|
+
runId,
|
|
1106
|
+
parentId: acc.parentId,
|
|
1107
|
+
name: acc.name,
|
|
1108
|
+
kind,
|
|
1109
|
+
timestamp: acc.timestamp,
|
|
1110
|
+
status,
|
|
1111
|
+
durationMs: acc.durationMs,
|
|
1112
|
+
attributes: Object.keys(attrs).length > 0 ? attrs : void 0,
|
|
1113
|
+
confidence: "explicit",
|
|
1114
|
+
source: { type: "manual" }
|
|
1115
|
+
};
|
|
1116
|
+
inspectNodes.set(acc.id, { event: evt, children: [], depth: 0 });
|
|
1117
|
+
}
|
|
1118
|
+
const roots = [];
|
|
1119
|
+
const sortByStart = (a, b) => a.event.timestamp - b.event.timestamp;
|
|
1120
|
+
for (const node of inspectNodes.values()) {
|
|
1121
|
+
const pid = node.event.parentId;
|
|
1122
|
+
if (pid !== void 0 && inspectNodes.has(pid)) {
|
|
1123
|
+
inspectNodes.get(pid).children.push(node);
|
|
1124
|
+
} else {
|
|
1125
|
+
roots.push(node);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
roots.sort(sortByStart);
|
|
1129
|
+
for (const n of inspectNodes.values()) {
|
|
1130
|
+
n.children.sort(sortByStart);
|
|
1131
|
+
}
|
|
1132
|
+
const assignDepth = (n, depth) => {
|
|
1133
|
+
n.depth = depth;
|
|
1134
|
+
for (const c of n.children) assignDepth(c, depth + 1);
|
|
1135
|
+
};
|
|
1136
|
+
for (const r of roots) assignDepth(r, 0);
|
|
1137
|
+
const confidenceBreakdown = {
|
|
1138
|
+
explicit: 0,
|
|
1139
|
+
correlated: 0,
|
|
1140
|
+
heuristic: 0,
|
|
1141
|
+
unknown: 0
|
|
1142
|
+
};
|
|
1143
|
+
const kinds = zeroKinds();
|
|
1144
|
+
function countWalk(nodes) {
|
|
1145
|
+
for (const n of nodes) {
|
|
1146
|
+
confidenceBreakdown[n.event.confidence] += 1;
|
|
1147
|
+
kinds[n.event.kind] += 1;
|
|
1148
|
+
if (n.children.length > 0) countWalk(n.children);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
countWalk(roots);
|
|
1152
|
+
return {
|
|
1153
|
+
runId,
|
|
1154
|
+
name: runName,
|
|
1155
|
+
status: runStatus,
|
|
1156
|
+
startedAt,
|
|
1157
|
+
endedAt,
|
|
1158
|
+
durationMs,
|
|
1159
|
+
children: roots,
|
|
1160
|
+
metadata: {
|
|
1161
|
+
totalEvents: inspectNodes.size,
|
|
1162
|
+
confidenceBreakdown,
|
|
1163
|
+
kinds
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// packages/core/src/exporters/index.ts
|
|
1169
|
+
function mergeExportDefaults(options) {
|
|
1170
|
+
return {
|
|
1171
|
+
format: options.format,
|
|
1172
|
+
includeMetadata: options.includeMetadata ?? true,
|
|
1173
|
+
includeAttributes: options.includeAttributes ?? false,
|
|
1174
|
+
includeErrors: options.includeErrors ?? true,
|
|
1175
|
+
pretty: options.pretty ?? true,
|
|
1176
|
+
redacted: options.redacted ?? true,
|
|
1177
|
+
maxAttributeLength: options.maxAttributeLength ?? 500,
|
|
1178
|
+
redactionProfile: options.redactionProfile ?? "local"
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
function exportRunTree(tree, options) {
|
|
1182
|
+
const opts = mergeExportDefaults(options);
|
|
1183
|
+
const exportTree = opts.redactionProfile === "local" ? tree : redactRunTreeForExport(tree, { redactionProfile: opts.redactionProfile });
|
|
1184
|
+
switch (opts.format) {
|
|
1185
|
+
case "markdown":
|
|
1186
|
+
return exportMarkdown(exportTree, opts);
|
|
1187
|
+
case "html":
|
|
1188
|
+
return exportHtml(exportTree, opts);
|
|
1189
|
+
case "openinference":
|
|
1190
|
+
return exportOpenInference(exportTree, opts);
|
|
1191
|
+
case "otlp-json":
|
|
1192
|
+
return exportOtlpJson(exportTree, opts);
|
|
1193
|
+
default: {
|
|
1194
|
+
const _x = opts.format;
|
|
1195
|
+
throw new Error(`Unsupported export format: ${String(_x)}`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
function validateExport(result) {
|
|
1200
|
+
const base = validateExportContent(result.format, result.content);
|
|
1201
|
+
return {
|
|
1202
|
+
ok: base.ok,
|
|
1203
|
+
format: base.format,
|
|
1204
|
+
errors: base.errors,
|
|
1205
|
+
warnings: [...result.warnings, ...base.warnings]
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
exports.EXPORT_PAYLOAD_VERSION = EXPORT_PAYLOAD_VERSION;
|
|
1210
|
+
exports.compactAttributes = compactAttributes;
|
|
1211
|
+
exports.escapeHtml = escapeHtml;
|
|
1212
|
+
exports.escapeMarkdown = escapeMarkdown;
|
|
1213
|
+
exports.exportHtml = exportHtml;
|
|
1214
|
+
exports.exportMarkdown = exportMarkdown;
|
|
1215
|
+
exports.exportOpenInference = exportOpenInference;
|
|
1216
|
+
exports.exportOtlpJson = exportOtlpJson;
|
|
1217
|
+
exports.exportRunTree = exportRunTree;
|
|
1218
|
+
exports.flattenTree = flattenTree;
|
|
1219
|
+
exports.manualTraceEventsToRunTree = manualTraceEventsToRunTree;
|
|
1220
|
+
exports.mergeExportDefaults = mergeExportDefaults;
|
|
1221
|
+
exports.redactRunTreeForExport = redactRunTreeForExport;
|
|
1222
|
+
exports.safeString = safeString;
|
|
1223
|
+
exports.stableJson = stableJson;
|
|
1224
|
+
exports.summarizeTree = summarizeTree;
|
|
1225
|
+
exports.validateExport = validateExport;
|
|
1226
|
+
exports.validateExportContent = validateExportContent;
|
|
1227
|
+
//# sourceMappingURL=exporters.cjs.map
|
|
1228
|
+
//# sourceMappingURL=exporters.cjs.map
|