agent-inspect 1.8.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.
- package/CHANGELOG.md +14 -0
- package/README.md +146 -23
- package/docs/ADAPTER-CONFORMANCE.md +1 -1
- package/docs/ADAPTERS.md +41 -6
- package/docs/API.md +123 -36
- package/docs/CLI.md +75 -11
- package/docs/EXPORTS.md +1 -1
- package/docs/GETTING-STARTED.md +72 -16
- package/docs/KNOWN-ISSUES.md +8 -3
- package/docs/LIMITATIONS.md +6 -6
- package/docs/LOG-TO-TREE-QUICKSTART.md +1 -2
- package/docs/MIGRATION.md +67 -0
- package/docs/SCHEMA.md +29 -12
- package/package.json +2 -2
- package/packages/cli/dist/index.cjs +7604 -7660
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +7604 -7660
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +2047 -26
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +346 -196
- package/packages/core/dist/advanced.d.ts +346 -196
- package/packages/core/dist/advanced.mjs +628 -5
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.d.cts +1 -1
- package/packages/core/dist/checks.d.ts +1 -1
- package/packages/core/dist/chunk-2ZXEMWGK.mjs +549 -0
- package/packages/core/dist/chunk-2ZXEMWGK.mjs.map +1 -0
- package/packages/core/dist/{chunk-57S5D6HR.mjs → chunk-4JVGFNQH.mjs} +50 -6
- package/packages/core/dist/chunk-4JVGFNQH.mjs.map +1 -0
- package/packages/core/dist/{chunk-6QSLZCBJ.mjs → chunk-A4V2H3YU.mjs} +329 -163
- package/packages/core/dist/chunk-A4V2H3YU.mjs.map +1 -0
- package/packages/core/dist/{chunk-74XZ6N7Q.mjs → chunk-IZBJAZGF.mjs} +12 -4
- package/packages/core/dist/chunk-IZBJAZGF.mjs.map +1 -0
- package/packages/core/dist/{chunk-VTIB5MDK.mjs → chunk-NQZPZ2FN.mjs} +15 -10
- package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +1 -0
- package/packages/core/dist/{chunk-TZISEVLQ.mjs → chunk-XUNJMAPD.mjs} +3 -3
- package/packages/core/dist/{chunk-TZISEVLQ.mjs.map → chunk-XUNJMAPD.mjs.map} +1 -1
- package/packages/core/dist/context-CSKnzpXR.d.cts +177 -0
- package/packages/core/dist/context-yv2VSDQF.d.ts +177 -0
- package/packages/core/dist/diff.d.cts +2 -2
- package/packages/core/dist/diff.d.ts +2 -2
- package/packages/core/dist/diff.mjs +473 -3
- package/packages/core/dist/diff.mjs.map +1 -1
- package/packages/core/dist/exporters.cjs +691 -0
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.d.cts +24 -3
- package/packages/core/dist/exporters.d.ts +24 -3
- package/packages/core/dist/exporters.mjs +1113 -3
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/index.cjs +1385 -8022
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +8 -313
- package/packages/core/dist/index.d.ts +8 -313
- package/packages/core/dist/index.mjs +18 -1331
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/{log-config-DanPV3P9.d.cts → log-config-8aE5Kxtr.d.cts} +1 -1
- package/packages/core/dist/{log-config-BPHS4Sds.d.ts → log-config-DVimQJho.d.ts} +1 -1
- package/packages/core/dist/logs.d.cts +2 -2
- package/packages/core/dist/logs.d.ts +2 -2
- package/packages/core/dist/logs.mjs +785 -2
- package/packages/core/dist/logs.mjs.map +1 -1
- package/packages/core/dist/{persisted-inspect-event-Cw7TeYGr.d.ts → persisted-inspect-event-D-WpXeZX.d.ts} +14 -5
- package/packages/core/dist/{persisted-inspect-event-DHPfzUd8.d.cts → persisted-inspect-event-DHcHPUKv.d.cts} +14 -5
- package/packages/core/dist/persisted.cjs +11 -1
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +4 -4
- package/packages/core/dist/persisted.d.ts +4 -4
- package/packages/core/dist/persisted.mjs +150 -3
- package/packages/core/dist/persisted.mjs.map +1 -1
- package/packages/core/dist/readers.cjs +27 -10
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.d.cts +1 -1
- package/packages/core/dist/readers.d.ts +1 -1
- package/packages/core/dist/readers.mjs +1580 -4
- package/packages/core/dist/readers.mjs.map +1 -1
- package/packages/core/dist/{types-Ap9uMdx_.d.ts → types-D-Y1kOU-.d.ts} +2 -2
- package/packages/core/dist/{types-B2-BU5CS.d.cts → types-DgMN3qow.d.cts} +2 -2
- package/packages/core/dist/writers.cjs +49 -3
- package/packages/core/dist/writers.cjs.map +1 -1
- package/packages/core/dist/writers.d.cts +1 -1
- package/packages/core/dist/writers.d.ts +1 -1
- package/packages/core/dist/writers.mjs +341 -4
- package/packages/core/dist/writers.mjs.map +1 -1
- package/packages/core/dist/chunk-57S5D6HR.mjs.map +0 -1
- package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +0 -1
- package/packages/core/dist/chunk-6SZPTECC.mjs +0 -342
- package/packages/core/dist/chunk-6SZPTECC.mjs.map +0 -1
- package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +0 -1
- package/packages/core/dist/chunk-HR7G62IE.mjs +0 -785
- package/packages/core/dist/chunk-HR7G62IE.mjs.map +0 -1
- package/packages/core/dist/chunk-TFLPUZ56.mjs +0 -1571
- package/packages/core/dist/chunk-TFLPUZ56.mjs.map +0 -1
- package/packages/core/dist/chunk-U2BGPESY.mjs +0 -150
- package/packages/core/dist/chunk-U2BGPESY.mjs.map +0 -1
- package/packages/core/dist/chunk-VTIB5MDK.mjs.map +0 -1
- package/packages/core/dist/chunk-Y56BPA3B.mjs +0 -990
- package/packages/core/dist/chunk-Y56BPA3B.mjs.map +0 -1
- package/packages/core/dist/chunk-YWAOOXLR.mjs +0 -475
- package/packages/core/dist/chunk-YWAOOXLR.mjs.map +0 -1
|
@@ -7,6 +7,8 @@ var path = require('path');
|
|
|
7
7
|
var os = require('os');
|
|
8
8
|
var process2 = require('process');
|
|
9
9
|
var tty = require('tty');
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
var readline = require('readline');
|
|
10
12
|
|
|
11
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
14
|
|
|
@@ -43,6 +45,25 @@ function extractCorrelationMetadata(record) {
|
|
|
43
45
|
}
|
|
44
46
|
return found ? out : void 0;
|
|
45
47
|
}
|
|
48
|
+
function buildRunStartedMetadata(options) {
|
|
49
|
+
if (!options) {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
const merged = options.metadata !== void 0 ? { ...options.metadata } : {};
|
|
53
|
+
if (isNonEmptyString(options.correlationId)) {
|
|
54
|
+
merged.correlationId = options.correlationId;
|
|
55
|
+
}
|
|
56
|
+
if (isNonEmptyString(options.requestId)) {
|
|
57
|
+
merged.requestId = options.requestId;
|
|
58
|
+
}
|
|
59
|
+
if (isNonEmptyString(options.decisionId)) {
|
|
60
|
+
merged.decisionId = options.decisionId;
|
|
61
|
+
}
|
|
62
|
+
if (isNonEmptyString(options.groupId)) {
|
|
63
|
+
merged.groupId = options.groupId;
|
|
64
|
+
}
|
|
65
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
66
|
+
}
|
|
46
67
|
var DEFAULT_REDACT_KEYS = [
|
|
47
68
|
"authorization",
|
|
48
69
|
"cookie",
|
|
@@ -212,6 +233,53 @@ function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, reso
|
|
|
212
233
|
return { maxMetadataValueLength: meta, maxPreviewLength: preview };
|
|
213
234
|
}
|
|
214
235
|
|
|
236
|
+
// packages/core/src/types.ts
|
|
237
|
+
var STEP_TYPES = [
|
|
238
|
+
"run",
|
|
239
|
+
"llm",
|
|
240
|
+
"tool",
|
|
241
|
+
"decision",
|
|
242
|
+
"logic",
|
|
243
|
+
"state",
|
|
244
|
+
"custom"
|
|
245
|
+
];
|
|
246
|
+
var STEP_STATUSES = [
|
|
247
|
+
"running",
|
|
248
|
+
"success",
|
|
249
|
+
"error"
|
|
250
|
+
];
|
|
251
|
+
function isRecord2(value) {
|
|
252
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
253
|
+
}
|
|
254
|
+
function isStepType(value) {
|
|
255
|
+
return typeof value === "string" && STEP_TYPES.includes(value);
|
|
256
|
+
}
|
|
257
|
+
function isStepStatus(value) {
|
|
258
|
+
return typeof value === "string" && STEP_STATUSES.includes(value);
|
|
259
|
+
}
|
|
260
|
+
function isTraceEvent(value) {
|
|
261
|
+
if (!isRecord2(value)) return false;
|
|
262
|
+
if (value.schemaVersion !== "0.1") return false;
|
|
263
|
+
if (typeof value.timestamp !== "number") return false;
|
|
264
|
+
if (typeof value.event !== "string") return false;
|
|
265
|
+
switch (value.event) {
|
|
266
|
+
case "run_started": {
|
|
267
|
+
return typeof value.runId === "string" && typeof value.name === "string" && typeof value.startTime === "number";
|
|
268
|
+
}
|
|
269
|
+
case "run_completed": {
|
|
270
|
+
return typeof value.runId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
271
|
+
}
|
|
272
|
+
case "step_started": {
|
|
273
|
+
return typeof value.runId === "string" && typeof value.stepId === "string" && typeof value.name === "string" && isStepType(value.type) && typeof value.startTime === "number";
|
|
274
|
+
}
|
|
275
|
+
case "step_completed": {
|
|
276
|
+
return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
277
|
+
}
|
|
278
|
+
default:
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
215
283
|
// packages/core/src/types/persisted-inspect-event.ts
|
|
216
284
|
var INSPECT_KINDS = [
|
|
217
285
|
"RUN",
|
|
@@ -246,7 +314,7 @@ var PERSISTED_EVENT_STATUSES = [
|
|
|
246
314
|
"error",
|
|
247
315
|
"unknown"
|
|
248
316
|
];
|
|
249
|
-
function
|
|
317
|
+
function isRecord3(value) {
|
|
250
318
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
251
319
|
}
|
|
252
320
|
function isString(value) {
|
|
@@ -277,21 +345,21 @@ function isPersistedEventStatus(value) {
|
|
|
277
345
|
return typeof value === "string" && PERSISTED_EVENT_STATUSES.includes(value);
|
|
278
346
|
}
|
|
279
347
|
function isPersistedEventSource(value) {
|
|
280
|
-
if (!
|
|
348
|
+
if (!isRecord3(value)) return false;
|
|
281
349
|
if (!isPersistedEventSourceType(value.type)) return false;
|
|
282
350
|
if (!isOptionalString(value.name)) return false;
|
|
283
351
|
if (!isOptionalString(value.version)) return false;
|
|
284
352
|
return true;
|
|
285
353
|
}
|
|
286
354
|
function isPersistedInspectError(value) {
|
|
287
|
-
if (!
|
|
355
|
+
if (!isRecord3(value)) return false;
|
|
288
356
|
if (!isNonEmptyString2(value.message)) return false;
|
|
289
357
|
if (!isOptionalString(value.name)) return false;
|
|
290
358
|
if (!isOptionalString(value.code)) return false;
|
|
291
359
|
return true;
|
|
292
360
|
}
|
|
293
361
|
function isPersistedTokenUsage(value) {
|
|
294
|
-
if (!
|
|
362
|
+
if (!isRecord3(value)) return false;
|
|
295
363
|
if (!isOptionalNonNegativeNumber(value.input)) return false;
|
|
296
364
|
if (!isOptionalNonNegativeNumber(value.output)) return false;
|
|
297
365
|
if (!isOptionalNonNegativeNumber(value.total)) return false;
|
|
@@ -299,15 +367,17 @@ function isPersistedTokenUsage(value) {
|
|
|
299
367
|
return true;
|
|
300
368
|
}
|
|
301
369
|
function isPersistedTraceContext(value) {
|
|
302
|
-
if (!
|
|
370
|
+
if (!isRecord3(value)) return false;
|
|
303
371
|
if (!isOptionalString(value.traceId)) return false;
|
|
304
372
|
if (!isOptionalString(value.spanId)) return false;
|
|
305
373
|
if (!isOptionalString(value.parentSpanId)) return false;
|
|
306
374
|
return true;
|
|
307
375
|
}
|
|
308
376
|
function isPersistedInspectEvent(value) {
|
|
309
|
-
if (!
|
|
310
|
-
if (value.schemaVersion !== "0.2")
|
|
377
|
+
if (!isRecord3(value)) return false;
|
|
378
|
+
if (value.schemaVersion !== "0.2" && value.schemaVersion !== "1.0") {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
311
381
|
if (!isNonEmptyString2(value.eventId)) return false;
|
|
312
382
|
if (!isNonEmptyString2(value.runId)) return false;
|
|
313
383
|
if (!isInspectKind(value.kind)) return false;
|
|
@@ -326,7 +396,7 @@ function isPersistedInspectEvent(value) {
|
|
|
326
396
|
if (value.durationMs !== void 0 && !isNonNegativeNumber(value.durationMs)) {
|
|
327
397
|
return false;
|
|
328
398
|
}
|
|
329
|
-
if (value.attributes !== void 0 && !
|
|
399
|
+
if (value.attributes !== void 0 && !isRecord3(value.attributes)) {
|
|
330
400
|
return false;
|
|
331
401
|
}
|
|
332
402
|
if (value.error !== void 0 && !isPersistedInspectError(value.error)) {
|
|
@@ -341,6 +411,272 @@ function isPersistedInspectEvent(value) {
|
|
|
341
411
|
return true;
|
|
342
412
|
}
|
|
343
413
|
|
|
414
|
+
// packages/core/src/persisted/to-trace-event.ts
|
|
415
|
+
function parseIsoToMs(iso) {
|
|
416
|
+
const parsed = Date.parse(iso);
|
|
417
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
418
|
+
}
|
|
419
|
+
function mapInspectKindToStepType(kind) {
|
|
420
|
+
switch (kind) {
|
|
421
|
+
case "LLM":
|
|
422
|
+
return "llm";
|
|
423
|
+
case "TOOL":
|
|
424
|
+
return "tool";
|
|
425
|
+
case "DECISION":
|
|
426
|
+
return "decision";
|
|
427
|
+
case "RUN":
|
|
428
|
+
return "run";
|
|
429
|
+
default:
|
|
430
|
+
return "logic";
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function mapPersistedStatusToStepStatus(status) {
|
|
434
|
+
switch (status) {
|
|
435
|
+
case "ok":
|
|
436
|
+
return "success";
|
|
437
|
+
case "error":
|
|
438
|
+
return "error";
|
|
439
|
+
case "running":
|
|
440
|
+
return "running";
|
|
441
|
+
default:
|
|
442
|
+
return void 0;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function mapPersistedStatusToRunStatus(status) {
|
|
446
|
+
switch (status) {
|
|
447
|
+
case "ok":
|
|
448
|
+
return "success";
|
|
449
|
+
case "error":
|
|
450
|
+
return "error";
|
|
451
|
+
case "running":
|
|
452
|
+
return "running";
|
|
453
|
+
default:
|
|
454
|
+
return void 0;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function mapPersistedError(error, attributes) {
|
|
458
|
+
if (!error?.message) return void 0;
|
|
459
|
+
const out = { message: error.message };
|
|
460
|
+
const stack = typeof attributes?.errorStack === "string" && attributes.errorStack.length > 0 ? attributes.errorStack : void 0;
|
|
461
|
+
if (stack) {
|
|
462
|
+
out.stack = stack;
|
|
463
|
+
}
|
|
464
|
+
return out;
|
|
465
|
+
}
|
|
466
|
+
function mapTokenUsageToMetadata(tokenUsage, attributes) {
|
|
467
|
+
const metadata = {};
|
|
468
|
+
if (attributes?.metadata && typeof attributes.metadata === "object") {
|
|
469
|
+
Object.assign(metadata, attributes.metadata);
|
|
470
|
+
}
|
|
471
|
+
if (tokenUsage) {
|
|
472
|
+
metadata.tokens = {
|
|
473
|
+
...tokenUsage.input !== void 0 ? { input: tokenUsage.input } : {},
|
|
474
|
+
...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {},
|
|
475
|
+
...tokenUsage.total !== void 0 ? { total: tokenUsage.total } : {},
|
|
476
|
+
...tokenUsage.cached !== void 0 ? { cached: tokenUsage.cached } : {}
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
480
|
+
}
|
|
481
|
+
function pickRunMetadata(attributes) {
|
|
482
|
+
if (!attributes) return void 0;
|
|
483
|
+
const metadata = attributes.metadata && typeof attributes.metadata === "object" ? { ...attributes.metadata } : {};
|
|
484
|
+
for (const key of [
|
|
485
|
+
"correlationId",
|
|
486
|
+
"requestId",
|
|
487
|
+
"decisionId",
|
|
488
|
+
"groupId"
|
|
489
|
+
]) {
|
|
490
|
+
const value = attributes[key];
|
|
491
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
492
|
+
metadata[key] = value;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
496
|
+
}
|
|
497
|
+
function resolveStepId(event) {
|
|
498
|
+
const attrs = event.attributes;
|
|
499
|
+
if (attrs && typeof attrs.stepId === "string" && attrs.stepId.trim() !== "") {
|
|
500
|
+
return attrs.stepId;
|
|
501
|
+
}
|
|
502
|
+
return event.eventId;
|
|
503
|
+
}
|
|
504
|
+
function resolveStepType(event) {
|
|
505
|
+
const attrs = event.attributes;
|
|
506
|
+
if (attrs && typeof attrs.stepType === "string") {
|
|
507
|
+
const t = attrs.stepType;
|
|
508
|
+
if (t === "run" || t === "llm" || t === "tool" || t === "decision" || t === "logic" || t === "state" || t === "custom") {
|
|
509
|
+
return t;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return mapInspectKindToStepType(event.kind);
|
|
513
|
+
}
|
|
514
|
+
function resolveTimes(event) {
|
|
515
|
+
const timestamp = parseIsoToMs(event.timestamp);
|
|
516
|
+
const startTime = event.startedAt !== void 0 ? parseIsoToMs(event.startedAt) : timestamp;
|
|
517
|
+
let endTime = event.endedAt !== void 0 ? parseIsoToMs(event.endedAt) : timestamp;
|
|
518
|
+
if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0 && event.endedAt === void 0) {
|
|
519
|
+
endTime = startTime + event.durationMs;
|
|
520
|
+
}
|
|
521
|
+
return { timestamp, startTime, endTime };
|
|
522
|
+
}
|
|
523
|
+
function fromLegacyRunStarted(event) {
|
|
524
|
+
const { timestamp, startTime } = resolveTimes(event);
|
|
525
|
+
const out = {
|
|
526
|
+
schemaVersion: "0.1",
|
|
527
|
+
event: "run_started",
|
|
528
|
+
timestamp,
|
|
529
|
+
runId: event.runId,
|
|
530
|
+
name: event.name,
|
|
531
|
+
startTime
|
|
532
|
+
};
|
|
533
|
+
const metadata = pickRunMetadata(event.attributes);
|
|
534
|
+
if (metadata) out.metadata = metadata;
|
|
535
|
+
return out;
|
|
536
|
+
}
|
|
537
|
+
function fromLegacyRunCompleted(event) {
|
|
538
|
+
const { timestamp, endTime } = resolveTimes(event);
|
|
539
|
+
const status = mapPersistedStatusToRunStatus(event.status) ?? "success";
|
|
540
|
+
const out = {
|
|
541
|
+
schemaVersion: "0.1",
|
|
542
|
+
event: "run_completed",
|
|
543
|
+
timestamp,
|
|
544
|
+
runId: event.runId,
|
|
545
|
+
status: status === "running" ? "success" : status,
|
|
546
|
+
endTime,
|
|
547
|
+
durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
|
|
548
|
+
};
|
|
549
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
550
|
+
if (error) out.error = error;
|
|
551
|
+
return out;
|
|
552
|
+
}
|
|
553
|
+
function fromLegacyStepStarted(event) {
|
|
554
|
+
const { timestamp, startTime } = resolveTimes(event);
|
|
555
|
+
const out = {
|
|
556
|
+
schemaVersion: "0.1",
|
|
557
|
+
event: "step_started",
|
|
558
|
+
timestamp,
|
|
559
|
+
runId: event.runId,
|
|
560
|
+
stepId: resolveStepId(event),
|
|
561
|
+
name: event.name,
|
|
562
|
+
type: resolveStepType(event),
|
|
563
|
+
startTime
|
|
564
|
+
};
|
|
565
|
+
if (event.parentId !== void 0) out.parentId = event.parentId;
|
|
566
|
+
const metadata = mapTokenUsageToMetadata(event.tokenUsage, event.attributes);
|
|
567
|
+
if (metadata) out.metadata = metadata;
|
|
568
|
+
return out;
|
|
569
|
+
}
|
|
570
|
+
function fromLegacyStepCompleted(event) {
|
|
571
|
+
const { timestamp, endTime } = resolveTimes(event);
|
|
572
|
+
const status = mapPersistedStatusToStepStatus(event.status) ?? "success";
|
|
573
|
+
const out = {
|
|
574
|
+
schemaVersion: "0.1",
|
|
575
|
+
event: "step_completed",
|
|
576
|
+
timestamp,
|
|
577
|
+
runId: event.runId,
|
|
578
|
+
stepId: resolveStepId(event),
|
|
579
|
+
status: status === "running" ? "success" : status,
|
|
580
|
+
endTime,
|
|
581
|
+
durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
|
|
582
|
+
};
|
|
583
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
584
|
+
if (error) out.error = error;
|
|
585
|
+
return out;
|
|
586
|
+
}
|
|
587
|
+
function fromNativeRun(event) {
|
|
588
|
+
const { timestamp, startTime, endTime } = resolveTimes(event);
|
|
589
|
+
const runStatus = mapPersistedStatusToRunStatus(event.status);
|
|
590
|
+
const out = [];
|
|
591
|
+
if (runStatus === "running" || event.startedAt !== void 0) {
|
|
592
|
+
const started = {
|
|
593
|
+
schemaVersion: "0.1",
|
|
594
|
+
event: "run_started",
|
|
595
|
+
timestamp,
|
|
596
|
+
runId: event.runId,
|
|
597
|
+
name: event.name,
|
|
598
|
+
startTime
|
|
599
|
+
};
|
|
600
|
+
const metadata = pickRunMetadata(event.attributes);
|
|
601
|
+
if (metadata) started.metadata = metadata;
|
|
602
|
+
out.push(started);
|
|
603
|
+
}
|
|
604
|
+
if (runStatus === "success" || runStatus === "error" || event.endedAt !== void 0) {
|
|
605
|
+
const completed = {
|
|
606
|
+
schemaVersion: "0.1",
|
|
607
|
+
event: "run_completed",
|
|
608
|
+
timestamp,
|
|
609
|
+
runId: event.runId,
|
|
610
|
+
status: runStatus === "error" ? "error" : "success",
|
|
611
|
+
endTime,
|
|
612
|
+
durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
|
|
613
|
+
};
|
|
614
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
615
|
+
if (error) completed.error = error;
|
|
616
|
+
out.push(completed);
|
|
617
|
+
}
|
|
618
|
+
if (out.length === 0) {
|
|
619
|
+
out.push(fromLegacyRunStarted(event));
|
|
620
|
+
}
|
|
621
|
+
return out;
|
|
622
|
+
}
|
|
623
|
+
function fromNativeStep(event) {
|
|
624
|
+
const { timestamp, startTime, endTime } = resolveTimes(event);
|
|
625
|
+
const stepStatus = mapPersistedStatusToStepStatus(event.status);
|
|
626
|
+
const stepId = resolveStepId(event);
|
|
627
|
+
const out = [];
|
|
628
|
+
const shouldEmitStarted = stepStatus === "running" || event.startedAt !== void 0 || stepStatus === "success" || stepStatus === "error";
|
|
629
|
+
if (shouldEmitStarted) {
|
|
630
|
+
const started = {
|
|
631
|
+
schemaVersion: "0.1",
|
|
632
|
+
event: "step_started",
|
|
633
|
+
timestamp,
|
|
634
|
+
runId: event.runId,
|
|
635
|
+
stepId,
|
|
636
|
+
name: event.name,
|
|
637
|
+
type: resolveStepType(event),
|
|
638
|
+
startTime
|
|
639
|
+
};
|
|
640
|
+
if (event.parentId !== void 0) started.parentId = event.parentId;
|
|
641
|
+
const metadata = mapTokenUsageToMetadata(event.tokenUsage, event.attributes);
|
|
642
|
+
if (metadata) started.metadata = metadata;
|
|
643
|
+
out.push(started);
|
|
644
|
+
}
|
|
645
|
+
if (stepStatus === "success" || stepStatus === "error" || event.endedAt !== void 0 || event.durationMs !== void 0) {
|
|
646
|
+
const completed = {
|
|
647
|
+
schemaVersion: "0.1",
|
|
648
|
+
event: "step_completed",
|
|
649
|
+
timestamp,
|
|
650
|
+
runId: event.runId,
|
|
651
|
+
stepId,
|
|
652
|
+
status: stepStatus === "error" ? "error" : "success",
|
|
653
|
+
endTime,
|
|
654
|
+
durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
|
|
655
|
+
};
|
|
656
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
657
|
+
if (error) completed.error = error;
|
|
658
|
+
out.push(completed);
|
|
659
|
+
}
|
|
660
|
+
if (out.length === 0) {
|
|
661
|
+
out.push(fromLegacyStepStarted(event));
|
|
662
|
+
}
|
|
663
|
+
return out;
|
|
664
|
+
}
|
|
665
|
+
function persistedInspectEventToTraceEvents(event) {
|
|
666
|
+
if (!isPersistedInspectEvent(event)) {
|
|
667
|
+
throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
|
|
668
|
+
}
|
|
669
|
+
const legacyEvent = event.attributes?.legacyEvent;
|
|
670
|
+
if (legacyEvent === "run_started") return [fromLegacyRunStarted(event)];
|
|
671
|
+
if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
|
|
672
|
+
if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
|
|
673
|
+
if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
|
|
674
|
+
if (event.kind === "RUN") {
|
|
675
|
+
return fromNativeRun(event);
|
|
676
|
+
}
|
|
677
|
+
return fromNativeStep(event);
|
|
678
|
+
}
|
|
679
|
+
|
|
344
680
|
// node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/url-alphabet/index.js
|
|
345
681
|
var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
346
682
|
|
|
@@ -370,6 +706,37 @@ function nanoid(size = 21) {
|
|
|
370
706
|
}
|
|
371
707
|
|
|
372
708
|
// packages/core/src/utils/duration.ts
|
|
709
|
+
function parseDuration(duration) {
|
|
710
|
+
const raw = typeof duration === "string" ? duration.trim() : "";
|
|
711
|
+
const match = raw.match(/^(\d+)(ms|[smhd])$/);
|
|
712
|
+
if (!match) {
|
|
713
|
+
throw new Error(
|
|
714
|
+
`Invalid duration format: ${duration}. Use a positive integer followed by ms, s, m, h, or d (e.g. 500ms, 30s, 5m, 2h, 7d).`
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
const amount = Number.parseInt(match[1], 10);
|
|
718
|
+
const unit = match[2];
|
|
719
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
720
|
+
throw new Error(
|
|
721
|
+
`Invalid duration amount: ${duration}. Amount must be a positive integer.`
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
switch (unit) {
|
|
725
|
+
case "ms":
|
|
726
|
+
return amount;
|
|
727
|
+
case "s":
|
|
728
|
+
return amount * 1e3;
|
|
729
|
+
case "m":
|
|
730
|
+
return amount * 60 * 1e3;
|
|
731
|
+
case "h":
|
|
732
|
+
return amount * 60 * 60 * 1e3;
|
|
733
|
+
case "d":
|
|
734
|
+
return amount * 24 * 60 * 60 * 1e3;
|
|
735
|
+
default: {
|
|
736
|
+
throw new Error(`Unknown duration unit: ${unit}`);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
373
740
|
function formatDuration(ms) {
|
|
374
741
|
if (!Number.isFinite(ms)) {
|
|
375
742
|
return "0ms";
|
|
@@ -514,7 +881,141 @@ function warn(message, error) {
|
|
|
514
881
|
console.warn(`${base}: ${formatError(error).message}`);
|
|
515
882
|
}
|
|
516
883
|
|
|
884
|
+
// packages/core/src/read-trace.ts
|
|
885
|
+
function isRecord4(value) {
|
|
886
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
887
|
+
}
|
|
888
|
+
function detectLineFormat(parsed) {
|
|
889
|
+
if (!isRecord4(parsed)) return "unknown";
|
|
890
|
+
if (parsed.schemaVersion === "0.1") return "0.1";
|
|
891
|
+
if (parsed.schemaVersion === "0.2") return "0.2";
|
|
892
|
+
if (parsed.schemaVersion === "1.0") return "1.0";
|
|
893
|
+
return "unknown";
|
|
894
|
+
}
|
|
895
|
+
function parseTraceJsonl(raw, options = {}) {
|
|
896
|
+
const validate = options.validate ?? isTraceEvent;
|
|
897
|
+
const emitWarning = (message) => {
|
|
898
|
+
if (options.warnings !== false) warn(message);
|
|
899
|
+
};
|
|
900
|
+
const persisted = [];
|
|
901
|
+
const traceEvents = [];
|
|
902
|
+
const rows = [];
|
|
903
|
+
let sourceEventCount = 0;
|
|
904
|
+
let saw01 = false;
|
|
905
|
+
let saw02 = false;
|
|
906
|
+
let saw10 = false;
|
|
907
|
+
let lineNumber = 0;
|
|
908
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
909
|
+
lineNumber += 1;
|
|
910
|
+
const trimmed = line.trim();
|
|
911
|
+
if (trimmed === "") continue;
|
|
912
|
+
let parsed;
|
|
913
|
+
try {
|
|
914
|
+
parsed = JSON.parse(trimmed);
|
|
915
|
+
} catch {
|
|
916
|
+
emitWarning("Skipped invalid JSON line in trace file");
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
const format2 = detectLineFormat(parsed);
|
|
920
|
+
if (format2 === "0.1") {
|
|
921
|
+
saw01 = true;
|
|
922
|
+
if (validate(parsed)) {
|
|
923
|
+
sourceEventCount += 1;
|
|
924
|
+
traceEvents.push(parsed);
|
|
925
|
+
rows.push({ format: "0.1", event: parsed, sourceLine: lineNumber });
|
|
926
|
+
} else {
|
|
927
|
+
emitWarning("Skipped invalid trace event line in trace file");
|
|
928
|
+
}
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
if (format2 === "0.2" || format2 === "1.0") {
|
|
932
|
+
if (format2 === "0.2") saw02 = true;
|
|
933
|
+
else saw10 = true;
|
|
934
|
+
if (isPersistedInspectEvent(parsed)) {
|
|
935
|
+
sourceEventCount += 1;
|
|
936
|
+
persisted.push(parsed);
|
|
937
|
+
rows.push({ format: format2, event: parsed, sourceLine: lineNumber });
|
|
938
|
+
traceEvents.push(...persistedInspectEventToTraceEvents(parsed));
|
|
939
|
+
} else {
|
|
940
|
+
emitWarning("Skipped invalid persisted inspect event line in trace file");
|
|
941
|
+
}
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
emitWarning("Skipped trace line with unknown schemaVersion");
|
|
945
|
+
}
|
|
946
|
+
const seenFormats = [saw01, saw02, saw10].filter(Boolean).length;
|
|
947
|
+
if (seenFormats > 1) {
|
|
948
|
+
emitWarning(
|
|
949
|
+
"Trace file mixes AgentInspect schemaVersion rows; normalizing all rows"
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
let format = "empty";
|
|
953
|
+
if (seenFormats > 1) format = "mixed";
|
|
954
|
+
else if (saw01) format = "0.1";
|
|
955
|
+
else if (saw02) format = "0.2";
|
|
956
|
+
else if (saw10) format = "1.0";
|
|
957
|
+
return { format, sourceEventCount, events: traceEvents, persisted, rows };
|
|
958
|
+
}
|
|
959
|
+
function unknownTraceFormatMessage() {
|
|
960
|
+
return "Unsupported trace format. Expected schemaVersion 0.1 (TraceEvent), 0.2 (PersistedInspectEvent), or 1.0 (PersistedInspectEvent).";
|
|
961
|
+
}
|
|
962
|
+
|
|
517
963
|
// packages/core/src/storage.ts
|
|
964
|
+
function isRecord5(value) {
|
|
965
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
966
|
+
}
|
|
967
|
+
function nonEmptyString(value) {
|
|
968
|
+
return typeof value === "string" && value.trim() !== "";
|
|
969
|
+
}
|
|
970
|
+
function finiteNumber(value) {
|
|
971
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
972
|
+
}
|
|
973
|
+
function optionalErrorInfo(value) {
|
|
974
|
+
if (value === void 0) return true;
|
|
975
|
+
if (!isRecord5(value)) return false;
|
|
976
|
+
if (typeof value.message !== "string") return false;
|
|
977
|
+
if ("stack" in value && value.stack !== void 0) {
|
|
978
|
+
if (typeof value.stack !== "string") return false;
|
|
979
|
+
}
|
|
980
|
+
return true;
|
|
981
|
+
}
|
|
982
|
+
function validateEvent(event) {
|
|
983
|
+
if (!isRecord5(event)) return false;
|
|
984
|
+
if (event.schemaVersion !== "0.1") return false;
|
|
985
|
+
if (!finiteNumber(event.timestamp)) return false;
|
|
986
|
+
if (typeof event.event !== "string") return false;
|
|
987
|
+
switch (event.event) {
|
|
988
|
+
case "run_started": {
|
|
989
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
|
|
990
|
+
return false;
|
|
991
|
+
}
|
|
992
|
+
if (event.metadata !== void 0 && !isRecord5(event.metadata)) {
|
|
993
|
+
return false;
|
|
994
|
+
}
|
|
995
|
+
return true;
|
|
996
|
+
}
|
|
997
|
+
case "run_completed": {
|
|
998
|
+
return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
999
|
+
}
|
|
1000
|
+
case "step_started": {
|
|
1001
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
if (event.parentId !== void 0 && typeof event.parentId !== "string") {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
if (event.metadata !== void 0 && !isRecord5(event.metadata)) {
|
|
1008
|
+
return false;
|
|
1009
|
+
}
|
|
1010
|
+
return true;
|
|
1011
|
+
}
|
|
1012
|
+
case "step_completed": {
|
|
1013
|
+
return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
1014
|
+
}
|
|
1015
|
+
default:
|
|
1016
|
+
return false;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
518
1019
|
function serializeEvent(event) {
|
|
519
1020
|
try {
|
|
520
1021
|
return JSON.stringify(event);
|
|
@@ -522,14 +1023,163 @@ function serializeEvent(event) {
|
|
|
522
1023
|
return "";
|
|
523
1024
|
}
|
|
524
1025
|
}
|
|
1026
|
+
async function initializeTraceFile(runId, traceDir) {
|
|
1027
|
+
try {
|
|
1028
|
+
const usable = await ensureTraceDir(traceDir);
|
|
1029
|
+
const filePath = getTraceFilePath(runId, usable);
|
|
1030
|
+
await promises.writeFile(filePath, "", "utf-8");
|
|
1031
|
+
return filePath;
|
|
1032
|
+
} catch (e) {
|
|
1033
|
+
warn("Failed to initialize trace file", e);
|
|
1034
|
+
}
|
|
1035
|
+
try {
|
|
1036
|
+
const usable = await ensureTraceDir(FALLBACK_TRACE_DIR);
|
|
1037
|
+
const filePath = getTraceFilePath(runId, usable);
|
|
1038
|
+
await promises.writeFile(filePath, "", "utf-8");
|
|
1039
|
+
return filePath;
|
|
1040
|
+
} catch (e) {
|
|
1041
|
+
warn("Failed to initialize trace file on fallback directory", e);
|
|
1042
|
+
return void 0;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function ensureEventWithinBounds(event) {
|
|
1046
|
+
const line = serializeEvent(event);
|
|
1047
|
+
if (line === "") return event;
|
|
1048
|
+
const bytes = Buffer.byteLength(line, "utf8");
|
|
1049
|
+
if (bytes <= DEFAULT_MAX_EVENT_BYTES) return event;
|
|
1050
|
+
return prepareTraceEventForDisk(event, resolveTraceSafetyOptions());
|
|
1051
|
+
}
|
|
1052
|
+
async function writeTraceEvent(event, traceDir) {
|
|
1053
|
+
const bounded = ensureEventWithinBounds(event);
|
|
1054
|
+
if (!validateEvent(bounded)) {
|
|
1055
|
+
warn("Skipped invalid trace event (validation failed)");
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
const line = serializeEvent(bounded);
|
|
1059
|
+
if (line === "") {
|
|
1060
|
+
warn("Skipped trace event (serialization failed)");
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
const payload = `${line}
|
|
1064
|
+
`;
|
|
1065
|
+
const tryAppend = async (dir) => {
|
|
1066
|
+
try {
|
|
1067
|
+
const usable = await ensureTraceDir(dir);
|
|
1068
|
+
const filePath = getTraceFilePath(event.runId, usable);
|
|
1069
|
+
await promises.appendFile(filePath, payload, "utf-8");
|
|
1070
|
+
return true;
|
|
1071
|
+
} catch {
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
if (await tryAppend(traceDir)) {
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
warn(`Failed to append trace event for run ${event.runId}`);
|
|
1079
|
+
if (await tryAppend(FALLBACK_TRACE_DIR)) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
warn("Failed to append trace event to fallback directory");
|
|
1083
|
+
}
|
|
1084
|
+
async function readTraceFile(runId, traceDir) {
|
|
1085
|
+
try {
|
|
1086
|
+
const filePath = getTraceFilePath(runId, traceDir);
|
|
1087
|
+
return await promises.readFile(filePath, "utf-8");
|
|
1088
|
+
} catch (e) {
|
|
1089
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
1090
|
+
return void 0;
|
|
1091
|
+
}
|
|
1092
|
+
warn("Unexpected error reading trace file", e);
|
|
1093
|
+
return void 0;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
async function readTraceEvents(runId, traceDir) {
|
|
1097
|
+
try {
|
|
1098
|
+
const filePath = getTraceFilePath(runId, traceDir);
|
|
1099
|
+
return await readTraceEventsFromFile(filePath);
|
|
1100
|
+
} catch (e) {
|
|
1101
|
+
warn("Failed to read trace events", e);
|
|
1102
|
+
return [];
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
async function readTraceEventsFromFile(filePath) {
|
|
1106
|
+
try {
|
|
1107
|
+
const raw = await promises.readFile(filePath, "utf-8");
|
|
1108
|
+
return parseTraceJsonl(raw, { validate: validateEvent }).events;
|
|
1109
|
+
} catch (e) {
|
|
1110
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
1111
|
+
return [];
|
|
1112
|
+
}
|
|
1113
|
+
warn("Failed to read trace events from file", e);
|
|
1114
|
+
return [];
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
async function listTraceFiles(traceDir) {
|
|
1118
|
+
try {
|
|
1119
|
+
const usable = path__default.default.resolve(traceDir);
|
|
1120
|
+
const names = await promises.readdir(usable);
|
|
1121
|
+
const jsonl = names.filter((n) => n.endsWith(".jsonl"));
|
|
1122
|
+
const withStat = await Promise.all(
|
|
1123
|
+
jsonl.map(async (name) => {
|
|
1124
|
+
try {
|
|
1125
|
+
const st = await promises.stat(path__default.default.join(usable, name));
|
|
1126
|
+
return { name, mtime: st.mtimeMs };
|
|
1127
|
+
} catch {
|
|
1128
|
+
return { name, mtime: 0 };
|
|
1129
|
+
}
|
|
1130
|
+
})
|
|
1131
|
+
);
|
|
1132
|
+
withStat.sort((a, b) => {
|
|
1133
|
+
if (b.mtime !== a.mtime) return b.mtime - a.mtime;
|
|
1134
|
+
return a.name.localeCompare(b.name);
|
|
1135
|
+
});
|
|
1136
|
+
return withStat.map((x) => x.name);
|
|
1137
|
+
} catch {
|
|
1138
|
+
return [];
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function getRunIdFromTraceFileName(fileName) {
|
|
1142
|
+
try {
|
|
1143
|
+
const base = path__default.default.basename(fileName);
|
|
1144
|
+
if (!base.endsWith(".jsonl")) return void 0;
|
|
1145
|
+
const id = base.slice(0, -".jsonl".length);
|
|
1146
|
+
return id === "" ? void 0 : id;
|
|
1147
|
+
} catch {
|
|
1148
|
+
return void 0;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
525
1151
|
|
|
526
1152
|
// packages/core/src/trace-event-safety.ts
|
|
527
1153
|
var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
|
|
528
1154
|
var DEFAULT_MAX_PREVIEW_LENGTH = 500;
|
|
529
1155
|
var DEFAULT_MAX_EVENT_BYTES = 65536;
|
|
530
|
-
function
|
|
1156
|
+
function isRecord6(value) {
|
|
531
1157
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
532
1158
|
}
|
|
1159
|
+
var KNOWN_PERSISTED_EVENT_FIELDS = /* @__PURE__ */ new Set([
|
|
1160
|
+
"schemaVersion",
|
|
1161
|
+
"eventId",
|
|
1162
|
+
"runId",
|
|
1163
|
+
"kind",
|
|
1164
|
+
"name",
|
|
1165
|
+
"parentId",
|
|
1166
|
+
"status",
|
|
1167
|
+
"timestamp",
|
|
1168
|
+
"startedAt",
|
|
1169
|
+
"endedAt",
|
|
1170
|
+
"durationMs",
|
|
1171
|
+
"confidence",
|
|
1172
|
+
"source",
|
|
1173
|
+
"attributes",
|
|
1174
|
+
"inputSummary",
|
|
1175
|
+
"outputSummary",
|
|
1176
|
+
"error",
|
|
1177
|
+
"tokenUsage",
|
|
1178
|
+
"trace"
|
|
1179
|
+
]);
|
|
1180
|
+
function isSafeExtensionFieldName(key) {
|
|
1181
|
+
return key !== "__proto__" && key !== "constructor" && key !== "prototype";
|
|
1182
|
+
}
|
|
533
1183
|
function isPreviewKey(key) {
|
|
534
1184
|
return key.toLowerCase().includes("preview");
|
|
535
1185
|
}
|
|
@@ -549,7 +1199,7 @@ function resolveTraceSafetyOptions(options) {
|
|
|
549
1199
|
redactEnabled = false;
|
|
550
1200
|
} else if (redact === true || redact === void 0) {
|
|
551
1201
|
redactEnabled = true;
|
|
552
|
-
} else if (
|
|
1202
|
+
} else if (isRecord6(redact)) {
|
|
553
1203
|
redactEnabled = true;
|
|
554
1204
|
redactionRules = redact.rules;
|
|
555
1205
|
}
|
|
@@ -643,7 +1293,7 @@ function prepareMetadataForDisk(metadata, opts) {
|
|
|
643
1293
|
0
|
|
644
1294
|
);
|
|
645
1295
|
const redacted = redactMetadata(
|
|
646
|
-
|
|
1296
|
+
isRecord6(preBounded) ? preBounded : {},
|
|
647
1297
|
opts
|
|
648
1298
|
);
|
|
649
1299
|
const bounded = boundMetadataValue(
|
|
@@ -653,7 +1303,7 @@ function prepareMetadataForDisk(metadata, opts) {
|
|
|
653
1303
|
/* @__PURE__ */ new WeakSet(),
|
|
654
1304
|
0
|
|
655
1305
|
);
|
|
656
|
-
return
|
|
1306
|
+
return isRecord6(bounded) ? bounded : {};
|
|
657
1307
|
} catch {
|
|
658
1308
|
return { truncated: true, reason: "metadataPreparationFailed" };
|
|
659
1309
|
}
|
|
@@ -802,7 +1452,7 @@ function preparePersistedSummaryForDisk(key, value, opts) {
|
|
|
802
1452
|
}
|
|
803
1453
|
}
|
|
804
1454
|
function preparePersistedErrorForDisk(value, opts) {
|
|
805
|
-
if (!
|
|
1455
|
+
if (!isRecord6(value)) return void 0;
|
|
806
1456
|
try {
|
|
807
1457
|
const redactor = new Redactor({
|
|
808
1458
|
rules: opts.redactionRules,
|
|
@@ -829,7 +1479,7 @@ function preparePersistedErrorForDisk(value, opts) {
|
|
|
829
1479
|
}
|
|
830
1480
|
}
|
|
831
1481
|
function prepareTokenUsage(value) {
|
|
832
|
-
if (!
|
|
1482
|
+
if (!isRecord6(value)) return void 0;
|
|
833
1483
|
const out = {};
|
|
834
1484
|
for (const key of ["input", "output", "total", "cached"]) {
|
|
835
1485
|
const item = safeGet(value, key);
|
|
@@ -840,7 +1490,7 @@ function prepareTokenUsage(value) {
|
|
|
840
1490
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
841
1491
|
}
|
|
842
1492
|
function prepareTraceContext(value, opts) {
|
|
843
|
-
if (!
|
|
1493
|
+
if (!isRecord6(value)) return void 0;
|
|
844
1494
|
const out = {};
|
|
845
1495
|
const traceId = optionalBoundedString(safeGet(value, "traceId"), "traceId", opts);
|
|
846
1496
|
const spanId = optionalBoundedString(safeGet(value, "spanId"), "spanId", opts);
|
|
@@ -854,6 +1504,25 @@ function prepareTraceContext(value, opts) {
|
|
|
854
1504
|
if (parentSpanId !== void 0) out.parentSpanId = parentSpanId;
|
|
855
1505
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
856
1506
|
}
|
|
1507
|
+
function preparePersistedExtensionFieldForDisk(key, value, opts) {
|
|
1508
|
+
if (isRecord6(value)) {
|
|
1509
|
+
return prepareMetadataForDisk(value, opts);
|
|
1510
|
+
}
|
|
1511
|
+
const prepared = prepareMetadataForDisk({ [key]: value }, opts);
|
|
1512
|
+
return Object.prototype.hasOwnProperty.call(prepared, key) ? prepared[key] : void 0;
|
|
1513
|
+
}
|
|
1514
|
+
function preserveV10ExtensionFields(source, candidate, opts) {
|
|
1515
|
+
if (candidate.schemaVersion !== "1.0") return;
|
|
1516
|
+
for (const [key, value] of Object.entries(source)) {
|
|
1517
|
+
if (KNOWN_PERSISTED_EVENT_FIELDS.has(key) || !isSafeExtensionFieldName(key)) {
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
const prepared = preparePersistedExtensionFieldForDisk(key, value, opts);
|
|
1521
|
+
if (prepared !== void 0) {
|
|
1522
|
+
candidate[key] = prepared;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
857
1526
|
function serializedPersistedEvent(event) {
|
|
858
1527
|
try {
|
|
859
1528
|
return JSON.stringify(event);
|
|
@@ -867,7 +1536,7 @@ function persistedEventByteLength(event) {
|
|
|
867
1536
|
}
|
|
868
1537
|
function minimalPersistedEvent(event, opts, originalApproxBytes) {
|
|
869
1538
|
return {
|
|
870
|
-
schemaVersion:
|
|
1539
|
+
schemaVersion: event.schemaVersion,
|
|
871
1540
|
eventId: truncateString(event.eventId, 128),
|
|
872
1541
|
runId: truncateString(event.runId, 128),
|
|
873
1542
|
kind: event.kind,
|
|
@@ -890,7 +1559,7 @@ function minimalPersistedEvent(event, opts, originalApproxBytes) {
|
|
|
890
1559
|
}
|
|
891
1560
|
function tinyPersistedEvent(event) {
|
|
892
1561
|
return {
|
|
893
|
-
schemaVersion:
|
|
1562
|
+
schemaVersion: event.schemaVersion,
|
|
894
1563
|
eventId: truncateString(event.eventId, 32),
|
|
895
1564
|
runId: truncateString(event.runId, 32),
|
|
896
1565
|
kind: event.kind,
|
|
@@ -915,9 +1584,9 @@ function enforcePersistedEventSize(event, opts) {
|
|
|
915
1584
|
}
|
|
916
1585
|
function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOptions()) {
|
|
917
1586
|
try {
|
|
918
|
-
if (!
|
|
1587
|
+
if (!isRecord6(value)) return void 0;
|
|
919
1588
|
const source = safeGet(value, "source");
|
|
920
|
-
if (!
|
|
1589
|
+
if (!isRecord6(source)) return void 0;
|
|
921
1590
|
const candidate = {
|
|
922
1591
|
schemaVersion: safeGet(value, "schemaVersion"),
|
|
923
1592
|
eventId: requiredBoundedString(safeGet(value, "eventId"), "eventId", opts) ?? "",
|
|
@@ -949,7 +1618,7 @@ function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOp
|
|
|
949
1618
|
if (sourceName !== void 0) candidate.source.name = sourceName;
|
|
950
1619
|
if (sourceVersion !== void 0) candidate.source.version = sourceVersion;
|
|
951
1620
|
const attributes = safeGet(value, "attributes");
|
|
952
|
-
if (
|
|
1621
|
+
if (isRecord6(attributes)) {
|
|
953
1622
|
candidate.attributes = prepareMetadataForDisk(attributes, opts);
|
|
954
1623
|
}
|
|
955
1624
|
if (safeGet(value, "inputSummary") !== void 0) {
|
|
@@ -972,6 +1641,7 @@ function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOp
|
|
|
972
1641
|
if (tokenUsage !== void 0) candidate.tokenUsage = tokenUsage;
|
|
973
1642
|
const trace = prepareTraceContext(safeGet(value, "trace"), opts);
|
|
974
1643
|
if (trace !== void 0) candidate.trace = trace;
|
|
1644
|
+
preserveV10ExtensionFields(value, candidate, opts);
|
|
975
1645
|
if (!isPersistedInspectEvent(candidate)) return void 0;
|
|
976
1646
|
return enforcePersistedEventSize(candidate, opts);
|
|
977
1647
|
} catch {
|
|
@@ -1287,6 +1957,7 @@ function createInspectorRuntime(options = {}) {
|
|
|
1287
1957
|
}
|
|
1288
1958
|
|
|
1289
1959
|
// packages/core/src/inspector.ts
|
|
1960
|
+
var INSPECTOR_PERSISTED_SCHEMA_VERSION = "1.0";
|
|
1290
1961
|
function normalizeName(name, fallback) {
|
|
1291
1962
|
if (typeof name !== "string" || name.trim() === "") return fallback;
|
|
1292
1963
|
return truncateName(name.trim(), 100);
|
|
@@ -1403,7 +2074,7 @@ function createInspector(options = {}) {
|
|
|
1403
2074
|
},
|
|
1404
2075
|
async () => {
|
|
1405
2076
|
await write({
|
|
1406
|
-
schemaVersion:
|
|
2077
|
+
schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
|
|
1407
2078
|
eventId: `${runId}_started`,
|
|
1408
2079
|
runId,
|
|
1409
2080
|
kind: "RUN",
|
|
@@ -1422,7 +2093,7 @@ function createInspector(options = {}) {
|
|
|
1422
2093
|
const result = await Promise.resolve(fn());
|
|
1423
2094
|
const endedAt = nowIso();
|
|
1424
2095
|
await write({
|
|
1425
|
-
schemaVersion:
|
|
2096
|
+
schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
|
|
1426
2097
|
eventId: `${runId}_completed`,
|
|
1427
2098
|
runId,
|
|
1428
2099
|
kind: "RUN",
|
|
@@ -1440,7 +2111,7 @@ function createInspector(options = {}) {
|
|
|
1440
2111
|
} catch (error) {
|
|
1441
2112
|
const endedAt = nowIso();
|
|
1442
2113
|
await write({
|
|
1443
|
-
schemaVersion:
|
|
2114
|
+
schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
|
|
1444
2115
|
eventId: `${runId}_completed`,
|
|
1445
2116
|
runId,
|
|
1446
2117
|
kind: "RUN",
|
|
@@ -1480,7 +2151,7 @@ function createInspector(options = {}) {
|
|
|
1480
2151
|
...stepOptions.metadata !== void 0 ? { metadata: stepOptions.metadata } : {}
|
|
1481
2152
|
};
|
|
1482
2153
|
await write({
|
|
1483
|
-
schemaVersion:
|
|
2154
|
+
schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
|
|
1484
2155
|
eventId: `${stepId}_started`,
|
|
1485
2156
|
runId: context.runId,
|
|
1486
2157
|
...parentId !== void 0 ? { parentId } : {},
|
|
@@ -1498,7 +2169,7 @@ function createInspector(options = {}) {
|
|
|
1498
2169
|
const result = await Promise.resolve(fn());
|
|
1499
2170
|
const endedAt = nowIso();
|
|
1500
2171
|
await write({
|
|
1501
|
-
schemaVersion:
|
|
2172
|
+
schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
|
|
1502
2173
|
eventId: `${stepId}_completed`,
|
|
1503
2174
|
runId: context.runId,
|
|
1504
2175
|
kind: stepTypeToKind(stepType),
|
|
@@ -1520,7 +2191,7 @@ function createInspector(options = {}) {
|
|
|
1520
2191
|
} catch (error) {
|
|
1521
2192
|
const endedAt = nowIso();
|
|
1522
2193
|
await write({
|
|
1523
|
-
schemaVersion:
|
|
2194
|
+
schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
|
|
1524
2195
|
eventId: `${stepId}_completed`,
|
|
1525
2196
|
runId: context.runId,
|
|
1526
2197
|
kind: stepTypeToKind(stepType),
|
|
@@ -2203,6 +2874,1324 @@ function printFailedAt(stepName) {
|
|
|
2203
2874
|
} catch {
|
|
2204
2875
|
}
|
|
2205
2876
|
}
|
|
2877
|
+
function resolveTraceDir(options = {}) {
|
|
2878
|
+
if (typeof options.dir === "string" && options.dir.trim() !== "") {
|
|
2879
|
+
return options.dir.trim();
|
|
2880
|
+
}
|
|
2881
|
+
const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
|
|
2882
|
+
if (typeof envDir === "string" && envDir.trim() !== "") {
|
|
2883
|
+
return envDir.trim();
|
|
2884
|
+
}
|
|
2885
|
+
return getDefaultTraceDir();
|
|
2886
|
+
}
|
|
2887
|
+
var TraceDirectory = class {
|
|
2888
|
+
#dir;
|
|
2889
|
+
constructor(options = {}) {
|
|
2890
|
+
this.#dir = resolveTraceDir(options);
|
|
2891
|
+
}
|
|
2892
|
+
getPath(filename) {
|
|
2893
|
+
return filename ? path__default.default.join(this.#dir, filename) : this.#dir;
|
|
2894
|
+
}
|
|
2895
|
+
async list() {
|
|
2896
|
+
try {
|
|
2897
|
+
const files = await promises.readdir(this.#dir);
|
|
2898
|
+
return files.filter((f) => f.endsWith(".jsonl"));
|
|
2899
|
+
} catch (e) {
|
|
2900
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
2901
|
+
return [];
|
|
2902
|
+
}
|
|
2903
|
+
throw e;
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
async getFileStats(filename) {
|
|
2907
|
+
return await promises.stat(this.getPath(filename));
|
|
2908
|
+
}
|
|
2909
|
+
};
|
|
2910
|
+
function isFiniteNumber(v) {
|
|
2911
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
2912
|
+
}
|
|
2913
|
+
function parseIsoToMs2(value) {
|
|
2914
|
+
if (value === void 0) return void 0;
|
|
2915
|
+
const parsed = Date.parse(value);
|
|
2916
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
2917
|
+
}
|
|
2918
|
+
async function extractMetadata(filePath, _quickScan) {
|
|
2919
|
+
const stats = await promises.stat(filePath);
|
|
2920
|
+
let runIdFromFile = path__default.default.basename(filePath);
|
|
2921
|
+
if (runIdFromFile.endsWith(".jsonl")) {
|
|
2922
|
+
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
2923
|
+
}
|
|
2924
|
+
const raw = await promises.readFile(filePath, "utf-8");
|
|
2925
|
+
const parsedTrace = parseTraceJsonl(raw, { warnings: false });
|
|
2926
|
+
let runId;
|
|
2927
|
+
let name;
|
|
2928
|
+
let startedAt;
|
|
2929
|
+
let endedAt;
|
|
2930
|
+
let explicitDurationMs;
|
|
2931
|
+
let hasRunStarted = false;
|
|
2932
|
+
let hasRunCompleted = false;
|
|
2933
|
+
let runCompletedStatus;
|
|
2934
|
+
let anyStepError = false;
|
|
2935
|
+
const anyKnownEvent = parsedTrace.sourceEventCount > 0;
|
|
2936
|
+
let persistedStatus;
|
|
2937
|
+
const persistedRun = parsedTrace.persisted.find(
|
|
2938
|
+
(event) => event.kind === "RUN"
|
|
2939
|
+
);
|
|
2940
|
+
if (persistedRun) {
|
|
2941
|
+
runId = persistedRun.runId;
|
|
2942
|
+
if (persistedRun.name.trim() !== "") {
|
|
2943
|
+
name = persistedRun.name;
|
|
2944
|
+
}
|
|
2945
|
+
startedAt = parseIsoToMs2(persistedRun.startedAt) ?? parseIsoToMs2(persistedRun.timestamp);
|
|
2946
|
+
endedAt = parseIsoToMs2(persistedRun.endedAt);
|
|
2947
|
+
if (isFiniteNumber(persistedRun.durationMs)) {
|
|
2948
|
+
explicitDurationMs = persistedRun.durationMs;
|
|
2949
|
+
if (endedAt === void 0 && startedAt !== void 0) {
|
|
2950
|
+
endedAt = startedAt + persistedRun.durationMs;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
if (persistedRun.status === "ok") persistedStatus = "success";
|
|
2954
|
+
else if (persistedRun.status === "error") persistedStatus = "error";
|
|
2955
|
+
else if (persistedRun.status === "running") persistedStatus = "running";
|
|
2956
|
+
else if (persistedRun.status === "unknown") persistedStatus = "unknown";
|
|
2957
|
+
} else {
|
|
2958
|
+
runId = parsedTrace.persisted[0]?.runId;
|
|
2959
|
+
}
|
|
2960
|
+
for (const e of parsedTrace.events) {
|
|
2961
|
+
if (runId === void 0 && typeof e.runId === "string") {
|
|
2962
|
+
runId = e.runId;
|
|
2963
|
+
}
|
|
2964
|
+
if (e.event === "run_started") {
|
|
2965
|
+
hasRunStarted = true;
|
|
2966
|
+
const rs = e;
|
|
2967
|
+
if (typeof rs.name === "string" && rs.name.trim() !== "") {
|
|
2968
|
+
name = rs.name;
|
|
2969
|
+
}
|
|
2970
|
+
if (isFiniteNumber(rs.startTime)) {
|
|
2971
|
+
startedAt = rs.startTime;
|
|
2972
|
+
} else if (isFiniteNumber(rs.timestamp)) {
|
|
2973
|
+
startedAt = rs.timestamp;
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
if (e.event === "run_completed") {
|
|
2977
|
+
hasRunCompleted = true;
|
|
2978
|
+
const rc = e;
|
|
2979
|
+
runCompletedStatus = rc.status;
|
|
2980
|
+
if (isFiniteNumber(rc.endTime)) endedAt = rc.endTime;
|
|
2981
|
+
else if (isFiniteNumber(rc.timestamp)) endedAt = rc.timestamp;
|
|
2982
|
+
if (isFiniteNumber(rc.durationMs)) explicitDurationMs = rc.durationMs;
|
|
2983
|
+
}
|
|
2984
|
+
if (e.event === "step_completed") {
|
|
2985
|
+
const sc = e;
|
|
2986
|
+
if (sc.status === "error") {
|
|
2987
|
+
anyStepError = true;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
const resolvedRunId = runId ?? runIdFromFile;
|
|
2992
|
+
let status = "unknown";
|
|
2993
|
+
if (hasRunCompleted && (runCompletedStatus === "success" || runCompletedStatus === "error")) {
|
|
2994
|
+
status = runCompletedStatus;
|
|
2995
|
+
} else if (anyStepError) {
|
|
2996
|
+
status = "error";
|
|
2997
|
+
} else if (persistedStatus !== void 0) {
|
|
2998
|
+
status = persistedStatus;
|
|
2999
|
+
} else if (hasRunStarted && !hasRunCompleted) {
|
|
3000
|
+
status = "running";
|
|
3001
|
+
} else if (anyKnownEvent) {
|
|
3002
|
+
status = "unknown";
|
|
3003
|
+
} else {
|
|
3004
|
+
status = "unknown";
|
|
3005
|
+
}
|
|
3006
|
+
const durationMs2 = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
|
|
3007
|
+
return {
|
|
3008
|
+
runId: resolvedRunId,
|
|
3009
|
+
name,
|
|
3010
|
+
status,
|
|
3011
|
+
startedAt,
|
|
3012
|
+
endedAt,
|
|
3013
|
+
durationMs: durationMs2,
|
|
3014
|
+
eventCount: parsedTrace.sourceEventCount,
|
|
3015
|
+
filePath,
|
|
3016
|
+
fileSize: stats.size,
|
|
3017
|
+
createdAt: stats.birthtime
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
function isNonNegativeFiniteNumber(value) {
|
|
3021
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
3022
|
+
}
|
|
3023
|
+
function buildRunSummary(events) {
|
|
3024
|
+
const started = events.find(
|
|
3025
|
+
(e) => e.event === "run_started"
|
|
3026
|
+
);
|
|
3027
|
+
const completed = events.filter(
|
|
3028
|
+
(e) => e.event === "run_completed"
|
|
3029
|
+
);
|
|
3030
|
+
const lastCompleted = completed[completed.length - 1];
|
|
3031
|
+
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
3032
|
+
const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
|
|
3033
|
+
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
3034
|
+
const durationMs2 = lastCompleted && isFiniteNumber(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
3035
|
+
started && isFiniteNumber(started.startTime) ? started.startTime : void 0;
|
|
3036
|
+
const steps = /* @__PURE__ */ new Map();
|
|
3037
|
+
for (const e of events) {
|
|
3038
|
+
if (e.event === "step_started") {
|
|
3039
|
+
const s = e;
|
|
3040
|
+
steps.set(s.stepId, {
|
|
3041
|
+
type: s.type,
|
|
3042
|
+
name: s.name,
|
|
3043
|
+
status: "running",
|
|
3044
|
+
parentId: s.parentId,
|
|
3045
|
+
tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
|
|
3046
|
+
tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
|
|
3047
|
+
tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
|
|
3048
|
+
tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
|
|
3049
|
+
});
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
for (const e of events) {
|
|
3053
|
+
if (e.event === "step_completed") {
|
|
3054
|
+
const c = e;
|
|
3055
|
+
const existing = steps.get(c.stepId);
|
|
3056
|
+
if (!existing) continue;
|
|
3057
|
+
existing.status = c.status;
|
|
3058
|
+
existing.durationMs = c.durationMs;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
let totalSteps = 0;
|
|
3062
|
+
let llmSteps = 0;
|
|
3063
|
+
let toolSteps = 0;
|
|
3064
|
+
let logicSteps = 0;
|
|
3065
|
+
let errorSteps = 0;
|
|
3066
|
+
let maxDepth = 0;
|
|
3067
|
+
let longestStep;
|
|
3068
|
+
let totalTokensInput = 0;
|
|
3069
|
+
let totalTokensOutput = 0;
|
|
3070
|
+
let totalTokensTotal = 0;
|
|
3071
|
+
let totalTokensCached = 0;
|
|
3072
|
+
let tokenBearingSteps = 0;
|
|
3073
|
+
let stepsWithKnownTotal = 0;
|
|
3074
|
+
let hasCachedTokens = false;
|
|
3075
|
+
const depthCache = /* @__PURE__ */ new Map();
|
|
3076
|
+
const computeDepth = (stepId) => {
|
|
3077
|
+
const cached = depthCache.get(stepId);
|
|
3078
|
+
if (cached !== void 0) return cached;
|
|
3079
|
+
const node = steps.get(stepId);
|
|
3080
|
+
if (!node) return 0;
|
|
3081
|
+
const parent = node.parentId;
|
|
3082
|
+
if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
|
|
3083
|
+
depthCache.set(stepId, 0);
|
|
3084
|
+
return 0;
|
|
3085
|
+
}
|
|
3086
|
+
const d = Math.min(1e3, computeDepth(parent) + 1);
|
|
3087
|
+
depthCache.set(stepId, d);
|
|
3088
|
+
return d;
|
|
3089
|
+
};
|
|
3090
|
+
for (const [id, s] of steps.entries()) {
|
|
3091
|
+
totalSteps += 1;
|
|
3092
|
+
if (s.type === "llm") llmSteps += 1;
|
|
3093
|
+
else if (s.type === "tool") toolSteps += 1;
|
|
3094
|
+
else logicSteps += 1;
|
|
3095
|
+
if (s.status === "error") errorSteps += 1;
|
|
3096
|
+
const depth = computeDepth(id);
|
|
3097
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
3098
|
+
if (typeof s.durationMs === "number" && Number.isFinite(s.durationMs)) {
|
|
3099
|
+
if (!longestStep || s.durationMs > longestStep.durationMs) {
|
|
3100
|
+
longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
|
|
3104
|
+
tokenBearingSteps += 1;
|
|
3105
|
+
if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
|
|
3106
|
+
if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
|
|
3107
|
+
if (s.tokensTotal !== void 0) {
|
|
3108
|
+
totalTokensTotal += s.tokensTotal;
|
|
3109
|
+
stepsWithKnownTotal += 1;
|
|
3110
|
+
} else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
|
|
3111
|
+
totalTokensTotal += s.tokensInput + s.tokensOutput;
|
|
3112
|
+
stepsWithKnownTotal += 1;
|
|
3113
|
+
}
|
|
3114
|
+
if (s.tokensCached !== void 0) {
|
|
3115
|
+
totalTokensCached += s.tokensCached;
|
|
3116
|
+
hasCachedTokens = true;
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
const summary = {
|
|
3121
|
+
runId,
|
|
3122
|
+
name,
|
|
3123
|
+
status,
|
|
3124
|
+
durationMs: durationMs2,
|
|
3125
|
+
totalSteps,
|
|
3126
|
+
llmSteps,
|
|
3127
|
+
toolSteps,
|
|
3128
|
+
logicSteps,
|
|
3129
|
+
errorSteps,
|
|
3130
|
+
maxDepth,
|
|
3131
|
+
...longestStep ? { longestStep } : {},
|
|
3132
|
+
...tokenBearingSteps > 0 ? {
|
|
3133
|
+
totalTokens: {
|
|
3134
|
+
input: totalTokensInput,
|
|
3135
|
+
output: totalTokensOutput,
|
|
3136
|
+
...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
|
|
3137
|
+
...hasCachedTokens ? { cached: totalTokensCached } : {}
|
|
3138
|
+
}
|
|
3139
|
+
} : {}
|
|
3140
|
+
};
|
|
3141
|
+
return summary;
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
// packages/core/src/trace-filter.ts
|
|
3145
|
+
function toLower(s) {
|
|
3146
|
+
return typeof s === "string" ? s.toLowerCase() : "";
|
|
3147
|
+
}
|
|
3148
|
+
function filterTraces(traces, options) {
|
|
3149
|
+
const input = [...traces];
|
|
3150
|
+
let out = input.filter((t) => {
|
|
3151
|
+
if (options.status && t.status !== options.status) return false;
|
|
3152
|
+
if (options.name) {
|
|
3153
|
+
const q = options.name.toLowerCase();
|
|
3154
|
+
const hay = `${toLower(t.name)} ${toLower(t.runId)}`;
|
|
3155
|
+
if (!hay.includes(q)) return false;
|
|
3156
|
+
}
|
|
3157
|
+
if (options.since) {
|
|
3158
|
+
const windowMs = parseDuration(options.since);
|
|
3159
|
+
const cutoff = Date.now() - windowMs;
|
|
3160
|
+
const started = typeof t.startedAt === "number" ? t.startedAt : void 0;
|
|
3161
|
+
const basis = started ?? t.createdAt.getTime();
|
|
3162
|
+
if (!Number.isFinite(basis) || basis < cutoff) return false;
|
|
3163
|
+
}
|
|
3164
|
+
return true;
|
|
3165
|
+
});
|
|
3166
|
+
out.sort((a, b) => {
|
|
3167
|
+
const aTime = (typeof a.startedAt === "number" ? a.startedAt : void 0) ?? a.createdAt.getTime();
|
|
3168
|
+
const bTime = (typeof b.startedAt === "number" ? b.startedAt : void 0) ?? b.createdAt.getTime();
|
|
3169
|
+
return bTime - aTime;
|
|
3170
|
+
});
|
|
3171
|
+
if (typeof options.limit === "number" && Number.isFinite(options.limit)) {
|
|
3172
|
+
const n = Math.max(0, Math.floor(options.limit));
|
|
3173
|
+
out = out.slice(0, n);
|
|
3174
|
+
}
|
|
3175
|
+
return out;
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
// packages/core/src/timeline.ts
|
|
3179
|
+
function finite(n) {
|
|
3180
|
+
return typeof n === "number" && Number.isFinite(n);
|
|
3181
|
+
}
|
|
3182
|
+
function pickStreamingMeta(metadata) {
|
|
3183
|
+
if (!metadata || typeof metadata !== "object") return void 0;
|
|
3184
|
+
const chunkCount = metadata.chunkCount;
|
|
3185
|
+
const streamDurationMs = metadata.streamDurationMs;
|
|
3186
|
+
const streamedCharCount = metadata.streamedCharCount;
|
|
3187
|
+
if (!finite(chunkCount) && !finite(streamDurationMs) && !finite(streamedCharCount)) {
|
|
3188
|
+
return void 0;
|
|
3189
|
+
}
|
|
3190
|
+
return {
|
|
3191
|
+
...finite(chunkCount) ? { chunkCount } : {},
|
|
3192
|
+
...finite(streamDurationMs) ? { streamDurationMs } : {},
|
|
3193
|
+
...finite(streamedCharCount) ? { streamedCharCount } : {}
|
|
3194
|
+
};
|
|
3195
|
+
}
|
|
3196
|
+
function pickCorrelation(metadata) {
|
|
3197
|
+
if (!metadata || typeof metadata !== "object") return void 0;
|
|
3198
|
+
const out = {};
|
|
3199
|
+
for (const key of [
|
|
3200
|
+
"correlationId",
|
|
3201
|
+
"requestId",
|
|
3202
|
+
"decisionId",
|
|
3203
|
+
"groupId"
|
|
3204
|
+
]) {
|
|
3205
|
+
const v = metadata[key];
|
|
3206
|
+
if (typeof v === "string" && v.trim() !== "") {
|
|
3207
|
+
out[key] = v;
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
3211
|
+
}
|
|
3212
|
+
function buildRunTimeline(events, options = {}) {
|
|
3213
|
+
const started = events.find(
|
|
3214
|
+
(e) => e.event === "run_started"
|
|
3215
|
+
);
|
|
3216
|
+
const completed = events.filter(
|
|
3217
|
+
(e) => e.event === "run_completed"
|
|
3218
|
+
);
|
|
3219
|
+
const lastCompleted = completed[completed.length - 1];
|
|
3220
|
+
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
3221
|
+
const runStart = started && finite(started.startTime) ? started.startTime : started && finite(started.timestamp) ? started.timestamp : void 0;
|
|
3222
|
+
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
3223
|
+
const steps = /* @__PURE__ */ new Map();
|
|
3224
|
+
for (const e of events) {
|
|
3225
|
+
if (e.event === "step_started") {
|
|
3226
|
+
const s = e;
|
|
3227
|
+
steps.set(s.stepId, {
|
|
3228
|
+
name: s.name,
|
|
3229
|
+
type: s.type,
|
|
3230
|
+
parentId: s.parentId,
|
|
3231
|
+
startedAt: finite(s.startTime) ? s.startTime : s.timestamp,
|
|
3232
|
+
status: "running",
|
|
3233
|
+
metadata: s.metadata
|
|
3234
|
+
});
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
for (const e of events) {
|
|
3238
|
+
if (e.event !== "step_completed") continue;
|
|
3239
|
+
const c = e;
|
|
3240
|
+
const node = steps.get(c.stepId);
|
|
3241
|
+
if (!node) continue;
|
|
3242
|
+
node.status = c.status;
|
|
3243
|
+
if (finite(c.durationMs)) node.durationMs = c.durationMs;
|
|
3244
|
+
}
|
|
3245
|
+
const depthCache = /* @__PURE__ */ new Map();
|
|
3246
|
+
const computeDepth = (stepId) => {
|
|
3247
|
+
const cached = depthCache.get(stepId);
|
|
3248
|
+
if (cached !== void 0) return cached;
|
|
3249
|
+
const node = steps.get(stepId);
|
|
3250
|
+
if (!node) return 0;
|
|
3251
|
+
const parent = node.parentId;
|
|
3252
|
+
if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
|
|
3253
|
+
depthCache.set(stepId, 0);
|
|
3254
|
+
return 0;
|
|
3255
|
+
}
|
|
3256
|
+
const d = Math.min(1e3, computeDepth(parent) + 1);
|
|
3257
|
+
depthCache.set(stepId, d);
|
|
3258
|
+
return d;
|
|
3259
|
+
};
|
|
3260
|
+
const entries = [];
|
|
3261
|
+
for (const [stepId, s] of steps.entries()) {
|
|
3262
|
+
const offsetMs = runStart !== void 0 && finite(s.startedAt) ? Math.max(0, s.startedAt - runStart) : 0;
|
|
3263
|
+
entries.push({
|
|
3264
|
+
stepId,
|
|
3265
|
+
name: s.name,
|
|
3266
|
+
type: s.type,
|
|
3267
|
+
status: s.status,
|
|
3268
|
+
depth: computeDepth(stepId),
|
|
3269
|
+
startedAt: s.startedAt,
|
|
3270
|
+
offsetMs,
|
|
3271
|
+
durationMs: s.durationMs,
|
|
3272
|
+
isError: s.status === "error",
|
|
3273
|
+
streaming: pickStreamingMeta(s.metadata)
|
|
3274
|
+
});
|
|
3275
|
+
}
|
|
3276
|
+
entries.sort((a, b) => a.startedAt - b.startedAt);
|
|
3277
|
+
const slowTopN = options.slowTopN ?? 3;
|
|
3278
|
+
if (options.focus === "slow" && entries.length > 0) {
|
|
3279
|
+
const ranked = [...entries].filter((e) => finite(e.durationMs)).sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
|
|
3280
|
+
const slowIds = new Set(
|
|
3281
|
+
ranked.slice(0, slowTopN).map((e) => e.stepId)
|
|
3282
|
+
);
|
|
3283
|
+
for (const e of entries) {
|
|
3284
|
+
if (slowIds.has(e.stepId)) e.slow = true;
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
return {
|
|
3288
|
+
runId,
|
|
3289
|
+
name: typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0,
|
|
3290
|
+
status,
|
|
3291
|
+
startedAt: runStart,
|
|
3292
|
+
endedAt: lastCompleted && finite(lastCompleted.endTime) ? lastCompleted.endTime : void 0,
|
|
3293
|
+
durationMs: lastCompleted && finite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0,
|
|
3294
|
+
correlation: pickCorrelation(
|
|
3295
|
+
started?.metadata
|
|
3296
|
+
),
|
|
3297
|
+
entries
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
function renderTimeline(timeline, options = {}) {
|
|
3301
|
+
const lines = [];
|
|
3302
|
+
lines.push(`Timeline: ${timeline.name ?? timeline.runId}`);
|
|
3303
|
+
lines.push(`Run ID: ${timeline.runId}`);
|
|
3304
|
+
lines.push(`Status: ${timeline.status}`);
|
|
3305
|
+
if (timeline.startedAt !== void 0) {
|
|
3306
|
+
lines.push(`Started: ${formatTimestamp(timeline.startedAt)}`);
|
|
3307
|
+
}
|
|
3308
|
+
if (timeline.durationMs !== void 0) {
|
|
3309
|
+
lines.push(`Duration: ${formatDuration2(timeline.durationMs)}`);
|
|
3310
|
+
}
|
|
3311
|
+
if (timeline.correlation) {
|
|
3312
|
+
const parts = Object.entries(timeline.correlation).filter(([, v]) => typeof v === "string").map(([k, v]) => `${k}=${v}`);
|
|
3313
|
+
if (parts.length > 0) {
|
|
3314
|
+
lines.push(`Correlation: ${parts.join(", ")}`);
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
lines.push("");
|
|
3318
|
+
lines.push("Steps (chronological):");
|
|
3319
|
+
const show = timeline.entries.filter((e) => {
|
|
3320
|
+
if (options.focus === "slow") return e.slow === true;
|
|
3321
|
+
return true;
|
|
3322
|
+
});
|
|
3323
|
+
if (show.length === 0) {
|
|
3324
|
+
lines.push(
|
|
3325
|
+
options.focus === "slow" ? "(no steps with duration for slow focus)" : "(no steps)"
|
|
3326
|
+
);
|
|
3327
|
+
return lines.join("\n");
|
|
3328
|
+
}
|
|
3329
|
+
for (const e of show) {
|
|
3330
|
+
const prefix = e.slow ? "[slow] " : "";
|
|
3331
|
+
const typeTag = e.type === "llm" ? "llm" : e.type === "tool" ? "tool" : e.type;
|
|
3332
|
+
const dur = e.durationMs !== void 0 ? formatDuration2(e.durationMs) : "-";
|
|
3333
|
+
const err = e.isError ? " error" : "";
|
|
3334
|
+
const off = formatDuration2(e.offsetMs);
|
|
3335
|
+
let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
|
|
3336
|
+
if (e.streaming?.chunkCount !== void 0) {
|
|
3337
|
+
line += ` chunks=${e.streaming.chunkCount}`;
|
|
3338
|
+
}
|
|
3339
|
+
if (e.streaming?.streamDurationMs !== void 0) {
|
|
3340
|
+
line += ` stream=${formatDuration2(e.streaming.streamDurationMs)}`;
|
|
3341
|
+
}
|
|
3342
|
+
lines.push(line);
|
|
3343
|
+
}
|
|
3344
|
+
return lines.join("\n");
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3347
|
+
// packages/core/src/what.ts
|
|
3348
|
+
function pickCorrelation2(metadata) {
|
|
3349
|
+
if (!metadata) return void 0;
|
|
3350
|
+
const out = {};
|
|
3351
|
+
for (const key of [
|
|
3352
|
+
"correlationId",
|
|
3353
|
+
"requestId",
|
|
3354
|
+
"decisionId",
|
|
3355
|
+
"groupId"
|
|
3356
|
+
]) {
|
|
3357
|
+
const value = metadata[key];
|
|
3358
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
3359
|
+
out[key] = value;
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
3363
|
+
}
|
|
3364
|
+
function stepMixLine(summary) {
|
|
3365
|
+
const parts = [];
|
|
3366
|
+
if (summary.llmSteps > 0) parts.push(`${summary.llmSteps} LLM`);
|
|
3367
|
+
if (summary.toolSteps > 0) parts.push(`${summary.toolSteps} tool`);
|
|
3368
|
+
if (summary.logicSteps > 0) parts.push(`${summary.logicSteps} logic`);
|
|
3369
|
+
return parts.length > 0 ? parts.join(", ") : "none";
|
|
3370
|
+
}
|
|
3371
|
+
function outcomeLine(summary) {
|
|
3372
|
+
if (summary.status === "success") {
|
|
3373
|
+
return summary.errorSteps > 0 ? "Completed with step errors recorded." : "Completed successfully.";
|
|
3374
|
+
}
|
|
3375
|
+
if (summary.status === "error") {
|
|
3376
|
+
if (summary.failedStepNames.length > 0) {
|
|
3377
|
+
const names = summary.failedStepNames.slice(0, 3).join(", ");
|
|
3378
|
+
const suffix = summary.failedStepNames.length > 3 ? ` (+${summary.failedStepNames.length - 3} more)` : "";
|
|
3379
|
+
return `Failed at step(s): ${names}${suffix}.`;
|
|
3380
|
+
}
|
|
3381
|
+
if (summary.runErrorMessage) {
|
|
3382
|
+
return `Run failed: ${summary.runErrorMessage}`;
|
|
3383
|
+
}
|
|
3384
|
+
return "Run failed.";
|
|
3385
|
+
}
|
|
3386
|
+
if (summary.status === "running") {
|
|
3387
|
+
return "Run is still in progress (no run_completed).";
|
|
3388
|
+
}
|
|
3389
|
+
return "Outcome unknown \u2014 inspect events may be incomplete.";
|
|
3390
|
+
}
|
|
3391
|
+
function buildRunWhatSummary(events) {
|
|
3392
|
+
const base = buildRunSummary(events);
|
|
3393
|
+
const started = events.find(
|
|
3394
|
+
(e) => e.event === "run_started"
|
|
3395
|
+
);
|
|
3396
|
+
const completed = events.filter(
|
|
3397
|
+
(e) => e.event === "run_completed"
|
|
3398
|
+
);
|
|
3399
|
+
const lastCompleted = completed[completed.length - 1];
|
|
3400
|
+
const failedStepNames = [];
|
|
3401
|
+
const stepNames = /* @__PURE__ */ new Map();
|
|
3402
|
+
for (const e of events) {
|
|
3403
|
+
if (e.event === "step_started") {
|
|
3404
|
+
const s = e;
|
|
3405
|
+
stepNames.set(s.stepId, s.name);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
for (const e of events) {
|
|
3409
|
+
if (e.event === "step_completed") {
|
|
3410
|
+
const sc = e;
|
|
3411
|
+
if (sc.status === "error") {
|
|
3412
|
+
failedStepNames.push(stepNames.get(sc.stepId) ?? sc.stepId);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
return {
|
|
3417
|
+
runId: base.runId,
|
|
3418
|
+
name: base.name,
|
|
3419
|
+
status: base.status,
|
|
3420
|
+
durationMs: base.durationMs,
|
|
3421
|
+
totalSteps: base.totalSteps,
|
|
3422
|
+
llmSteps: base.llmSteps,
|
|
3423
|
+
toolSteps: base.toolSteps,
|
|
3424
|
+
logicSteps: base.logicSteps,
|
|
3425
|
+
errorSteps: base.errorSteps,
|
|
3426
|
+
maxDepth: base.maxDepth,
|
|
3427
|
+
longestStep: base.longestStep,
|
|
3428
|
+
totalTokens: base.totalTokens,
|
|
3429
|
+
correlation: pickCorrelation2(started?.metadata),
|
|
3430
|
+
failedStepNames,
|
|
3431
|
+
runErrorMessage: lastCompleted?.error?.message
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
function renderRunWhat(summary, options = {}) {
|
|
3435
|
+
const showCorrelation = options.correlation !== false;
|
|
3436
|
+
const lines = [];
|
|
3437
|
+
const label = summary.name ?? summary.runId;
|
|
3438
|
+
lines.push(`What: ${label}`);
|
|
3439
|
+
const duration = summary.durationMs !== void 0 ? formatDuration2(summary.durationMs) : "\u2014";
|
|
3440
|
+
lines.push(
|
|
3441
|
+
`Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
|
|
3442
|
+
);
|
|
3443
|
+
if (summary.totalTokens) {
|
|
3444
|
+
const tokenParts = [
|
|
3445
|
+
`${summary.totalTokens.input} in`,
|
|
3446
|
+
`${summary.totalTokens.output} out`
|
|
3447
|
+
];
|
|
3448
|
+
if (summary.totalTokens.total !== void 0) {
|
|
3449
|
+
tokenParts.push(`${summary.totalTokens.total} total`);
|
|
3450
|
+
}
|
|
3451
|
+
if (summary.totalTokens.cached !== void 0) {
|
|
3452
|
+
tokenParts.push(`${summary.totalTokens.cached} cached`);
|
|
3453
|
+
}
|
|
3454
|
+
lines.push(`Tokens: ${tokenParts.join(" / ")}`);
|
|
3455
|
+
}
|
|
3456
|
+
if (showCorrelation && summary.correlation) {
|
|
3457
|
+
const parts = [];
|
|
3458
|
+
if (summary.correlation.correlationId) {
|
|
3459
|
+
parts.push(`correlationId=${summary.correlation.correlationId}`);
|
|
3460
|
+
}
|
|
3461
|
+
if (summary.correlation.requestId) {
|
|
3462
|
+
parts.push(`requestId=${summary.correlation.requestId}`);
|
|
3463
|
+
}
|
|
3464
|
+
if (summary.correlation.decisionId) {
|
|
3465
|
+
parts.push(`decisionId=${summary.correlation.decisionId}`);
|
|
3466
|
+
}
|
|
3467
|
+
if (summary.correlation.groupId) {
|
|
3468
|
+
parts.push(`groupId=${summary.correlation.groupId}`);
|
|
3469
|
+
}
|
|
3470
|
+
if (parts.length > 0) {
|
|
3471
|
+
lines.push(`Correlation: ${parts.join(", ")}`);
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
lines.push(`Outcome: ${outcomeLine(summary)}`);
|
|
3475
|
+
if (summary.longestStep && summary.totalSteps > 0) {
|
|
3476
|
+
lines.push(
|
|
3477
|
+
`Slowest: ${summary.longestStep.name} (${formatDuration2(summary.longestStep.durationMs)}, ${summary.longestStep.type})`
|
|
3478
|
+
);
|
|
3479
|
+
}
|
|
3480
|
+
if (summary.maxDepth > 0) {
|
|
3481
|
+
lines.push(`Max depth: ${summary.maxDepth}`);
|
|
3482
|
+
}
|
|
3483
|
+
return lines.join("\n");
|
|
3484
|
+
}
|
|
3485
|
+
|
|
3486
|
+
// packages/core/src/explain.ts
|
|
3487
|
+
function flatten(nodes, out = []) {
|
|
3488
|
+
for (const node of nodes) {
|
|
3489
|
+
out.push({ node, index: out.length + 1 });
|
|
3490
|
+
flatten(node.children, out);
|
|
3491
|
+
}
|
|
3492
|
+
return out;
|
|
3493
|
+
}
|
|
3494
|
+
function redactValue(redactor, key, value) {
|
|
3495
|
+
return redactor.redactValue(key, value);
|
|
3496
|
+
}
|
|
3497
|
+
function fact(id, label, value, redactor) {
|
|
3498
|
+
return {
|
|
3499
|
+
id,
|
|
3500
|
+
label,
|
|
3501
|
+
value: redactValue(redactor, id.split(".").at(-1) ?? id, value),
|
|
3502
|
+
source: "trace",
|
|
3503
|
+
confidence: "observed"
|
|
3504
|
+
};
|
|
3505
|
+
}
|
|
3506
|
+
function topKinds(run) {
|
|
3507
|
+
return Object.entries(run.metadata.kinds).filter(([, count]) => count > 0).sort((a, b) => {
|
|
3508
|
+
if (b[1] !== a[1]) return b[1] - a[1];
|
|
3509
|
+
return a[0].localeCompare(b[0]);
|
|
3510
|
+
}).slice(0, 5).map(([kind, count]) => `${kind}:${count}`);
|
|
3511
|
+
}
|
|
3512
|
+
function countErrorNodes(nodes) {
|
|
3513
|
+
return nodes.filter((entry) => entry.node.event.status === "error").length;
|
|
3514
|
+
}
|
|
3515
|
+
function slowestNode(nodes) {
|
|
3516
|
+
return nodes.filter((entry) => entry.node.event.durationMs !== void 0).sort((a, b) => {
|
|
3517
|
+
const delta = (b.node.event.durationMs ?? 0) - (a.node.event.durationMs ?? 0);
|
|
3518
|
+
return delta !== 0 ? delta : a.index - b.index;
|
|
3519
|
+
})[0];
|
|
3520
|
+
}
|
|
3521
|
+
function attributeFacts(nodes, redactor) {
|
|
3522
|
+
const facts = [];
|
|
3523
|
+
for (const entry of nodes) {
|
|
3524
|
+
const attrs = entry.node.event.attributes;
|
|
3525
|
+
if (attrs === void 0) continue;
|
|
3526
|
+
for (const key of Object.keys(attrs).sort()) {
|
|
3527
|
+
facts.push({
|
|
3528
|
+
id: `node.${entry.index}.attributes.${key}`,
|
|
3529
|
+
label: `${entry.node.event.name} attribute ${key}`,
|
|
3530
|
+
value: redactValue(redactor, key, attrs[key]),
|
|
3531
|
+
source: "trace",
|
|
3532
|
+
confidence: "observed"
|
|
3533
|
+
});
|
|
3534
|
+
if (facts.length >= 8) return facts;
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
return facts;
|
|
3538
|
+
}
|
|
3539
|
+
function buildFacts(run, redactor) {
|
|
3540
|
+
const nodes = flatten(run.children);
|
|
3541
|
+
const facts = [
|
|
3542
|
+
fact("run.id", "Run id", run.runId, redactor),
|
|
3543
|
+
fact("run.name", "Run name", run.name ?? run.runId, redactor),
|
|
3544
|
+
fact("run.status", "Run status", run.status ?? "unknown", redactor),
|
|
3545
|
+
fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
|
|
3546
|
+
fact("run.stepCount", "Top-level step count", run.children.length, redactor),
|
|
3547
|
+
fact("run.nodeCount", "Total node count", nodes.length, redactor),
|
|
3548
|
+
fact("run.errorNodeCount", "Error node count", countErrorNodes(nodes), redactor),
|
|
3549
|
+
fact("run.kinds", "Observed kind mix", topKinds(run), redactor)
|
|
3550
|
+
];
|
|
3551
|
+
if (run.durationMs !== void 0) {
|
|
3552
|
+
facts.push(fact("run.durationMs", "Run duration milliseconds", run.durationMs, redactor));
|
|
3553
|
+
}
|
|
3554
|
+
const slowest = slowestNode(nodes);
|
|
3555
|
+
if (slowest !== void 0) {
|
|
3556
|
+
facts.push(
|
|
3557
|
+
fact("run.slowestNode", "Slowest observed node", {
|
|
3558
|
+
name: slowest.node.event.name,
|
|
3559
|
+
kind: slowest.node.event.kind,
|
|
3560
|
+
durationMs: slowest.node.event.durationMs
|
|
3561
|
+
}, redactor)
|
|
3562
|
+
);
|
|
3563
|
+
}
|
|
3564
|
+
facts.push(...attributeFacts(nodes, redactor));
|
|
3565
|
+
return facts;
|
|
3566
|
+
}
|
|
3567
|
+
function buildInferences(run, facts) {
|
|
3568
|
+
const inferences = [];
|
|
3569
|
+
const errorFact = facts.find((item) => item.id === "run.errorNodeCount");
|
|
3570
|
+
const kindFact = facts.find((item) => item.id === "run.kinds");
|
|
3571
|
+
const durationFact = facts.find((item) => item.id === "run.durationMs");
|
|
3572
|
+
const errorNodeCount = typeof errorFact?.value === "number" ? errorFact.value : 0;
|
|
3573
|
+
if (run.status === "error" || errorNodeCount > 0) {
|
|
3574
|
+
inferences.push({
|
|
3575
|
+
id: "outcome.error",
|
|
3576
|
+
label: "Outcome",
|
|
3577
|
+
text: "The run recorded an error status or at least one error node.",
|
|
3578
|
+
evidence: ["run.status", "run.errorNodeCount"],
|
|
3579
|
+
confidence: "deterministic"
|
|
3580
|
+
});
|
|
3581
|
+
} else if (run.status === "ok") {
|
|
3582
|
+
inferences.push({
|
|
3583
|
+
id: "outcome.success",
|
|
3584
|
+
label: "Outcome",
|
|
3585
|
+
text: "The run completed without observed error nodes.",
|
|
3586
|
+
evidence: ["run.status", "run.errorNodeCount"],
|
|
3587
|
+
confidence: "deterministic"
|
|
3588
|
+
});
|
|
3589
|
+
}
|
|
3590
|
+
if (kindFact !== void 0) {
|
|
3591
|
+
inferences.push({
|
|
3592
|
+
id: "shape.kind-mix",
|
|
3593
|
+
label: "Trace shape",
|
|
3594
|
+
text: "The explanation is based on the observed event kind mix, not generated content.",
|
|
3595
|
+
evidence: [kindFact.id],
|
|
3596
|
+
confidence: "deterministic"
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3599
|
+
if (durationFact !== void 0) {
|
|
3600
|
+
inferences.push({
|
|
3601
|
+
id: "timing.duration",
|
|
3602
|
+
label: "Timing",
|
|
3603
|
+
text: "Timing claims are limited to persisted duration fields in the trace.",
|
|
3604
|
+
evidence: [durationFact.id],
|
|
3605
|
+
confidence: "deterministic"
|
|
3606
|
+
});
|
|
3607
|
+
}
|
|
3608
|
+
return inferences;
|
|
3609
|
+
}
|
|
3610
|
+
function buildLocalExplanation(run, options = {}) {
|
|
3611
|
+
const redactionProfile = options.redactionProfile ?? "local";
|
|
3612
|
+
const resolved = resolveRedactionProfile(redactionProfile);
|
|
3613
|
+
const redactor = new Redactor({ extraKeys: resolved.extraKeys });
|
|
3614
|
+
const mode = options.mode ?? "local";
|
|
3615
|
+
const facts = buildFacts(run, redactor);
|
|
3616
|
+
return {
|
|
3617
|
+
mode,
|
|
3618
|
+
runId: String(redactValue(redactor, "runId", run.runId)),
|
|
3619
|
+
...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
|
|
3620
|
+
...run.status !== void 0 ? { status: run.status } : {},
|
|
3621
|
+
redactionProfile,
|
|
3622
|
+
facts,
|
|
3623
|
+
inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
|
|
3624
|
+
notes: [
|
|
3625
|
+
"Generated locally without provider or network calls.",
|
|
3626
|
+
"Facts are observed from normalized trace data; inferences are deterministic labels."
|
|
3627
|
+
]
|
|
3628
|
+
};
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
// packages/core/src/stats.ts
|
|
3632
|
+
function percentile(sorted, p) {
|
|
3633
|
+
if (sorted.length === 0) return void 0;
|
|
3634
|
+
const idx = Math.min(
|
|
3635
|
+
sorted.length - 1,
|
|
3636
|
+
Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
|
|
3637
|
+
);
|
|
3638
|
+
return sorted[idx];
|
|
3639
|
+
}
|
|
3640
|
+
async function readRunStartedMetadata(filePath) {
|
|
3641
|
+
try {
|
|
3642
|
+
const events = await readTraceEventsFromFile(filePath);
|
|
3643
|
+
for (const event of events) {
|
|
3644
|
+
if (event.event !== "run_started") continue;
|
|
3645
|
+
const rs = event;
|
|
3646
|
+
if (rs.metadata && typeof rs.metadata === "object") {
|
|
3647
|
+
return rs.metadata;
|
|
3648
|
+
}
|
|
3649
|
+
return void 0;
|
|
3650
|
+
}
|
|
3651
|
+
} catch {
|
|
3652
|
+
}
|
|
3653
|
+
return void 0;
|
|
3654
|
+
}
|
|
3655
|
+
function metaMatchesCorrelation(metadata, correlationId, groupId) {
|
|
3656
|
+
if (correlationId) {
|
|
3657
|
+
const v = metadata?.correlationId;
|
|
3658
|
+
if (typeof v !== "string" || v !== correlationId) return false;
|
|
3659
|
+
}
|
|
3660
|
+
if (groupId) {
|
|
3661
|
+
const v = metadata?.groupId;
|
|
3662
|
+
if (typeof v !== "string" || v !== groupId) return false;
|
|
3663
|
+
}
|
|
3664
|
+
return true;
|
|
3665
|
+
}
|
|
3666
|
+
async function buildTraceStats(metas, options) {
|
|
3667
|
+
let filtered = filterTraces(metas, { since: options.since });
|
|
3668
|
+
if (options.correlationId || options.groupId) {
|
|
3669
|
+
const next = [];
|
|
3670
|
+
for (const m of filtered) {
|
|
3671
|
+
const md = await readRunStartedMetadata(m.filePath);
|
|
3672
|
+
if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
|
|
3673
|
+
next.push(m);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
filtered = next;
|
|
3677
|
+
}
|
|
3678
|
+
let successCount = 0;
|
|
3679
|
+
let errorCount = 0;
|
|
3680
|
+
let runningCount = 0;
|
|
3681
|
+
let unknownCount = 0;
|
|
3682
|
+
const durations = [];
|
|
3683
|
+
let totalSteps = 0;
|
|
3684
|
+
let totalLlmSteps = 0;
|
|
3685
|
+
let totalToolSteps = 0;
|
|
3686
|
+
let totalErrorSteps = 0;
|
|
3687
|
+
const slowestRuns = [];
|
|
3688
|
+
const slowestSteps = [];
|
|
3689
|
+
for (const m of filtered) {
|
|
3690
|
+
if (m.status === "success") successCount += 1;
|
|
3691
|
+
else if (m.status === "error") errorCount += 1;
|
|
3692
|
+
else if (m.status === "running") runningCount += 1;
|
|
3693
|
+
else unknownCount += 1;
|
|
3694
|
+
if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
|
|
3695
|
+
durations.push(m.durationMs);
|
|
3696
|
+
slowestRuns.push({
|
|
3697
|
+
runId: m.runId,
|
|
3698
|
+
name: m.name,
|
|
3699
|
+
durationMs: m.durationMs,
|
|
3700
|
+
status: m.status
|
|
3701
|
+
});
|
|
3702
|
+
}
|
|
3703
|
+
try {
|
|
3704
|
+
const events = await readTraceEventsFromFile(m.filePath);
|
|
3705
|
+
if (events.length === 0) continue;
|
|
3706
|
+
const summary = buildRunSummary(events);
|
|
3707
|
+
totalSteps += summary.totalSteps;
|
|
3708
|
+
totalLlmSteps += summary.llmSteps;
|
|
3709
|
+
totalToolSteps += summary.toolSteps;
|
|
3710
|
+
totalErrorSteps += summary.errorSteps;
|
|
3711
|
+
const steps = collectCompletedSteps(events, m.runId);
|
|
3712
|
+
for (const s of steps) {
|
|
3713
|
+
slowestSteps.push(s);
|
|
3714
|
+
}
|
|
3715
|
+
} catch {
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
|
|
3719
|
+
slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
|
|
3720
|
+
const runLimit = options.slowRunLimit ?? 5;
|
|
3721
|
+
const stepLimit = options.slowStepLimit ?? 5;
|
|
3722
|
+
const sortedDur = [...durations].sort((a, b) => a - b);
|
|
3723
|
+
const totalRuns = filtered.length;
|
|
3724
|
+
const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
|
|
3725
|
+
const sumDur = durations.reduce((a, b) => a + b, 0);
|
|
3726
|
+
return {
|
|
3727
|
+
traceDir: options.traceDir,
|
|
3728
|
+
...options.since ? { since: options.since } : {},
|
|
3729
|
+
...options.correlationId ? { correlationId: options.correlationId } : {},
|
|
3730
|
+
...options.groupId ? { groupId: options.groupId } : {},
|
|
3731
|
+
totalRuns,
|
|
3732
|
+
successCount,
|
|
3733
|
+
errorCount,
|
|
3734
|
+
runningCount,
|
|
3735
|
+
unknownCount,
|
|
3736
|
+
errorRate,
|
|
3737
|
+
duration: {
|
|
3738
|
+
...sortedDur.length > 0 ? {
|
|
3739
|
+
minMs: sortedDur[0],
|
|
3740
|
+
maxMs: sortedDur[sortedDur.length - 1],
|
|
3741
|
+
avgMs: sumDur / sortedDur.length,
|
|
3742
|
+
p50Ms: percentile(sortedDur, 50),
|
|
3743
|
+
p95Ms: percentile(sortedDur, 95)
|
|
3744
|
+
} : {}
|
|
3745
|
+
},
|
|
3746
|
+
totalSteps,
|
|
3747
|
+
avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
|
|
3748
|
+
totalLlmSteps,
|
|
3749
|
+
totalToolSteps,
|
|
3750
|
+
totalErrorSteps,
|
|
3751
|
+
slowestRuns: slowestRuns.slice(0, runLimit),
|
|
3752
|
+
slowestSteps: slowestSteps.slice(0, stepLimit)
|
|
3753
|
+
};
|
|
3754
|
+
}
|
|
3755
|
+
function collectCompletedSteps(events, runId) {
|
|
3756
|
+
const started = /* @__PURE__ */ new Map();
|
|
3757
|
+
const out = [];
|
|
3758
|
+
for (const e of events) {
|
|
3759
|
+
if (e.event === "step_started") {
|
|
3760
|
+
const s = e;
|
|
3761
|
+
started.set(s.stepId, { name: s.name, type: s.type });
|
|
3762
|
+
}
|
|
3763
|
+
if (e.event === "step_completed") {
|
|
3764
|
+
const c = e;
|
|
3765
|
+
if (c.status !== "success" && c.status !== "error") continue;
|
|
3766
|
+
if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
|
|
3767
|
+
continue;
|
|
3768
|
+
}
|
|
3769
|
+
const meta = started.get(c.stepId);
|
|
3770
|
+
out.push({
|
|
3771
|
+
runId,
|
|
3772
|
+
stepName: meta?.name ?? c.stepId,
|
|
3773
|
+
stepType: meta?.type ?? "logic",
|
|
3774
|
+
durationMs: c.durationMs
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
return out;
|
|
3779
|
+
}
|
|
3780
|
+
function renderTraceStats(stats) {
|
|
3781
|
+
const lines = [];
|
|
3782
|
+
lines.push("Trace stats (local)");
|
|
3783
|
+
lines.push(`Directory: ${stats.traceDir}`);
|
|
3784
|
+
if (stats.since) lines.push(`Since: ${stats.since}`);
|
|
3785
|
+
if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
|
|
3786
|
+
if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
|
|
3787
|
+
lines.push("");
|
|
3788
|
+
lines.push(`Runs: ${stats.totalRuns}`);
|
|
3789
|
+
lines.push(
|
|
3790
|
+
` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
|
|
3791
|
+
);
|
|
3792
|
+
lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
|
|
3793
|
+
if (stats.duration.avgMs !== void 0) {
|
|
3794
|
+
lines.push(
|
|
3795
|
+
`Duration: min ${formatDuration2(stats.duration.minMs ?? 0)} | avg ${formatDuration2(stats.duration.avgMs)} | p50 ${formatDuration2(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration2(stats.duration.p95Ms ?? 0)} | max ${formatDuration2(stats.duration.maxMs ?? 0)}`
|
|
3796
|
+
);
|
|
3797
|
+
}
|
|
3798
|
+
lines.push("");
|
|
3799
|
+
lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
|
|
3800
|
+
lines.push(
|
|
3801
|
+
` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
|
|
3802
|
+
);
|
|
3803
|
+
if (stats.slowestRuns.length > 0) {
|
|
3804
|
+
lines.push("");
|
|
3805
|
+
lines.push("Slowest runs:");
|
|
3806
|
+
for (const r of stats.slowestRuns) {
|
|
3807
|
+
lines.push(
|
|
3808
|
+
` ${r.runId} | ${r.name ?? "-"} | ${formatDuration2(r.durationMs ?? 0)} | ${r.status}`
|
|
3809
|
+
);
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
if (stats.slowestSteps.length > 0) {
|
|
3813
|
+
lines.push("");
|
|
3814
|
+
lines.push("Slowest steps:");
|
|
3815
|
+
for (const s of stats.slowestSteps) {
|
|
3816
|
+
lines.push(
|
|
3817
|
+
` ${s.runId} | ${s.stepType}:${s.stepName} | ${formatDuration2(s.durationMs)}`
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
return lines.join("\n");
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
// packages/core/src/search.ts
|
|
3825
|
+
function parseDurationFilter(expr) {
|
|
3826
|
+
const raw = expr.trim();
|
|
3827
|
+
const m = raw.match(/^(>=|<=|>|<)\s*(.+)$/);
|
|
3828
|
+
if (!m) {
|
|
3829
|
+
throw new Error(
|
|
3830
|
+
`Invalid --duration "${expr}". Use forms like >5s, >=500ms, <2m.`
|
|
3831
|
+
);
|
|
3832
|
+
}
|
|
3833
|
+
const op = m[1];
|
|
3834
|
+
const ms = parseDuration(m[2].trim());
|
|
3835
|
+
return { op, ms };
|
|
3836
|
+
}
|
|
3837
|
+
function durationMatches(valueMs, filter) {
|
|
3838
|
+
if (valueMs === void 0 || !Number.isFinite(valueMs)) return false;
|
|
3839
|
+
switch (filter.op) {
|
|
3840
|
+
case ">":
|
|
3841
|
+
return valueMs > filter.ms;
|
|
3842
|
+
case ">=":
|
|
3843
|
+
return valueMs >= filter.ms;
|
|
3844
|
+
case "<":
|
|
3845
|
+
return valueMs < filter.ms;
|
|
3846
|
+
case "<=":
|
|
3847
|
+
return valueMs <= filter.ms;
|
|
3848
|
+
default:
|
|
3849
|
+
return false;
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
function normalizeStepTypeFilter(kind, type) {
|
|
3853
|
+
const v = (kind ?? type)?.trim().toLowerCase();
|
|
3854
|
+
return v && v !== "" ? v : void 0;
|
|
3855
|
+
}
|
|
3856
|
+
function nameMatches(hay, needle) {
|
|
3857
|
+
return hay.toLowerCase().includes(needle.toLowerCase());
|
|
3858
|
+
}
|
|
3859
|
+
async function searchTraces(metas, options) {
|
|
3860
|
+
let filtered = filterTraces(metas, { since: options.since });
|
|
3861
|
+
const stepTypeFilter = normalizeStepTypeFilter(options.kind, options.type);
|
|
3862
|
+
const nameQuery = options.name?.trim();
|
|
3863
|
+
const toolQuery = options.tool?.trim();
|
|
3864
|
+
let durationFilter;
|
|
3865
|
+
if (options.duration) {
|
|
3866
|
+
durationFilter = parseDurationFilter(options.duration);
|
|
3867
|
+
}
|
|
3868
|
+
const limit = options.limit ?? 50;
|
|
3869
|
+
const hasContentFilter = Boolean(
|
|
3870
|
+
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
|
|
3871
|
+
);
|
|
3872
|
+
const results = [];
|
|
3873
|
+
if (!hasContentFilter) {
|
|
3874
|
+
for (const m of filtered) {
|
|
3875
|
+
results.push({
|
|
3876
|
+
runId: m.runId,
|
|
3877
|
+
runName: m.name,
|
|
3878
|
+
runStatus: m.status,
|
|
3879
|
+
timestamp: m.startedAt,
|
|
3880
|
+
durationMs: m.durationMs,
|
|
3881
|
+
matchReason: "trace in directory",
|
|
3882
|
+
matchedFields: ["run"],
|
|
3883
|
+
filePath: m.filePath
|
|
3884
|
+
});
|
|
3885
|
+
}
|
|
3886
|
+
return results.slice(0, limit);
|
|
3887
|
+
}
|
|
3888
|
+
for (const m of filtered) {
|
|
3889
|
+
if (options.status && m.status !== options.status) continue;
|
|
3890
|
+
let events = [];
|
|
3891
|
+
try {
|
|
3892
|
+
events = await readTraceEventsFromFile(m.filePath);
|
|
3893
|
+
} catch {
|
|
3894
|
+
continue;
|
|
3895
|
+
}
|
|
3896
|
+
if (events.length === 0) continue;
|
|
3897
|
+
const runMatches = matchRunLevel(m, {
|
|
3898
|
+
stepTypeFilter,
|
|
3899
|
+
nameQuery,
|
|
3900
|
+
toolQuery,
|
|
3901
|
+
durationFilter,
|
|
3902
|
+
statusFilter: options.status
|
|
3903
|
+
});
|
|
3904
|
+
results.push(...runMatches);
|
|
3905
|
+
const stepMatches = matchStepLevel(m, events, {
|
|
3906
|
+
stepTypeFilter,
|
|
3907
|
+
nameQuery,
|
|
3908
|
+
toolQuery,
|
|
3909
|
+
durationFilter,
|
|
3910
|
+
statusFilter: options.status
|
|
3911
|
+
});
|
|
3912
|
+
results.push(...stepMatches);
|
|
3913
|
+
}
|
|
3914
|
+
results.sort((a, b) => {
|
|
3915
|
+
const ta = a.timestamp ?? 0;
|
|
3916
|
+
const tb = b.timestamp ?? 0;
|
|
3917
|
+
if (ta !== tb) return ta - tb;
|
|
3918
|
+
const runCmp = a.runId.localeCompare(b.runId);
|
|
3919
|
+
if (runCmp !== 0) return runCmp;
|
|
3920
|
+
return (a.stepName ?? "").localeCompare(b.stepName ?? "");
|
|
3921
|
+
});
|
|
3922
|
+
return results.slice(0, limit);
|
|
3923
|
+
}
|
|
3924
|
+
function matchRunLevel(m, opts) {
|
|
3925
|
+
if (opts.stepTypeFilter || opts.toolQuery) return [];
|
|
3926
|
+
const out = [];
|
|
3927
|
+
const fields = [];
|
|
3928
|
+
if (opts.statusFilter && m.status === opts.statusFilter) {
|
|
3929
|
+
fields.push("run.status");
|
|
3930
|
+
}
|
|
3931
|
+
if (opts.nameQuery && nameMatches(m.name ?? m.runId, opts.nameQuery)) {
|
|
3932
|
+
fields.push("run.name");
|
|
3933
|
+
}
|
|
3934
|
+
if (opts.durationFilter && durationMatches(m.durationMs, opts.durationFilter)) {
|
|
3935
|
+
fields.push("run.durationMs");
|
|
3936
|
+
}
|
|
3937
|
+
if (fields.length === 0) return out;
|
|
3938
|
+
out.push({
|
|
3939
|
+
runId: m.runId,
|
|
3940
|
+
runName: m.name,
|
|
3941
|
+
runStatus: m.status,
|
|
3942
|
+
timestamp: m.startedAt,
|
|
3943
|
+
durationMs: m.durationMs,
|
|
3944
|
+
matchReason: `run match: ${fields.join(", ")}`,
|
|
3945
|
+
matchedFields: fields,
|
|
3946
|
+
filePath: m.filePath
|
|
3947
|
+
});
|
|
3948
|
+
return out;
|
|
3949
|
+
}
|
|
3950
|
+
function matchStepLevel(m, events, opts) {
|
|
3951
|
+
const out = [];
|
|
3952
|
+
const started = /* @__PURE__ */ new Map();
|
|
3953
|
+
for (const e of events) {
|
|
3954
|
+
if (e.event === "step_started") {
|
|
3955
|
+
started.set(e.stepId, e);
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
for (const e of events) {
|
|
3959
|
+
if (e.event !== "step_completed") continue;
|
|
3960
|
+
const c = e;
|
|
3961
|
+
const s = started.get(c.stepId);
|
|
3962
|
+
if (!s) continue;
|
|
3963
|
+
const fields = [];
|
|
3964
|
+
const stepType = s.type;
|
|
3965
|
+
if (opts.stepTypeFilter && stepType !== opts.stepTypeFilter) {
|
|
3966
|
+
continue;
|
|
3967
|
+
}
|
|
3968
|
+
const hasStepFilters = opts.stepTypeFilter || opts.nameQuery || opts.toolQuery || opts.durationFilter || opts.statusFilter === "error" || opts.statusFilter === "success";
|
|
3969
|
+
if (!hasStepFilters) continue;
|
|
3970
|
+
if (opts.statusFilter === "error" && c.status === "error") {
|
|
3971
|
+
fields.push("step.status");
|
|
3972
|
+
} else if (opts.statusFilter === "success" && c.status === "success") {
|
|
3973
|
+
fields.push("step.status");
|
|
3974
|
+
} else if (opts.statusFilter === "error" || opts.statusFilter === "success") {
|
|
3975
|
+
continue;
|
|
3976
|
+
}
|
|
3977
|
+
if (opts.nameQuery) {
|
|
3978
|
+
if (!nameMatches(s.name, opts.nameQuery)) continue;
|
|
3979
|
+
fields.push("step.name");
|
|
3980
|
+
}
|
|
3981
|
+
if (opts.toolQuery) {
|
|
3982
|
+
const toolName = typeof s.metadata?.toolName === "string" ? s.metadata.toolName : s.name;
|
|
3983
|
+
if (!nameMatches(toolName, opts.toolQuery)) continue;
|
|
3984
|
+
fields.push("step.tool");
|
|
3985
|
+
}
|
|
3986
|
+
if (opts.durationFilter) {
|
|
3987
|
+
if (!durationMatches(c.durationMs, opts.durationFilter)) continue;
|
|
3988
|
+
fields.push("step.durationMs");
|
|
3989
|
+
}
|
|
3990
|
+
if (opts.stepTypeFilter) {
|
|
3991
|
+
fields.push("step.type");
|
|
3992
|
+
}
|
|
3993
|
+
if (fields.length === 0) continue;
|
|
3994
|
+
out.push({
|
|
3995
|
+
runId: m.runId,
|
|
3996
|
+
runName: m.name,
|
|
3997
|
+
runStatus: m.status,
|
|
3998
|
+
stepId: c.stepId,
|
|
3999
|
+
stepName: s.name,
|
|
4000
|
+
stepType,
|
|
4001
|
+
timestamp: s.startTime ?? s.timestamp,
|
|
4002
|
+
durationMs: c.durationMs,
|
|
4003
|
+
matchReason: `step match: ${fields.join(", ")}`,
|
|
4004
|
+
matchedFields: fields,
|
|
4005
|
+
filePath: m.filePath
|
|
4006
|
+
});
|
|
4007
|
+
}
|
|
4008
|
+
return out;
|
|
4009
|
+
}
|
|
4010
|
+
async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
|
|
4011
|
+
const metas = [];
|
|
4012
|
+
for (const fileName of fileNames) {
|
|
4013
|
+
try {
|
|
4014
|
+
const filePath = getPath(fileName);
|
|
4015
|
+
const meta = await extractMetadata(filePath);
|
|
4016
|
+
metas.push(meta);
|
|
4017
|
+
} catch {
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
return metas;
|
|
4021
|
+
}
|
|
4022
|
+
var KNOWN_EVENTS = /* @__PURE__ */ new Set([
|
|
4023
|
+
"run_started",
|
|
4024
|
+
"run_completed",
|
|
4025
|
+
"step_started",
|
|
4026
|
+
"step_completed"
|
|
4027
|
+
]);
|
|
4028
|
+
function isRecord7(value) {
|
|
4029
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4030
|
+
}
|
|
4031
|
+
function safeParse(line) {
|
|
4032
|
+
try {
|
|
4033
|
+
return JSON.parse(line);
|
|
4034
|
+
} catch {
|
|
4035
|
+
return void 0;
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
async function isAgentInspectTrace(filePath) {
|
|
4039
|
+
try {
|
|
4040
|
+
const rl = readline.createInterface({
|
|
4041
|
+
input: fs.createReadStream(filePath, { encoding: "utf8" }),
|
|
4042
|
+
crlfDelay: Infinity
|
|
4043
|
+
});
|
|
4044
|
+
let checked = 0;
|
|
4045
|
+
for await (const line of rl) {
|
|
4046
|
+
const trimmed = line.trim();
|
|
4047
|
+
if (trimmed === "") continue;
|
|
4048
|
+
const parsed = safeParse(trimmed);
|
|
4049
|
+
if (!parsed) continue;
|
|
4050
|
+
if (!isRecord7(parsed)) continue;
|
|
4051
|
+
checked += 1;
|
|
4052
|
+
if (isTraceEvent(parsed)) return true;
|
|
4053
|
+
const ev = parsed.event;
|
|
4054
|
+
const runId = parsed.runId;
|
|
4055
|
+
if (typeof ev === "string" && KNOWN_EVENTS.has(ev) && typeof runId === "string") {
|
|
4056
|
+
return true;
|
|
4057
|
+
}
|
|
4058
|
+
if (checked >= 20) break;
|
|
4059
|
+
}
|
|
4060
|
+
return false;
|
|
4061
|
+
} catch {
|
|
4062
|
+
return false;
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
|
|
4066
|
+
// packages/core/src/inspect-run.ts
|
|
4067
|
+
function normalizeRunName(name) {
|
|
4068
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
4069
|
+
return "unnamed-run";
|
|
4070
|
+
}
|
|
4071
|
+
return truncateName(name.trim(), 100);
|
|
4072
|
+
}
|
|
4073
|
+
async function safeInstrumentation(label, op) {
|
|
4074
|
+
try {
|
|
4075
|
+
await Promise.resolve(op());
|
|
4076
|
+
} catch (e) {
|
|
4077
|
+
warn(`inspectRun: ${label}`, e);
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
async function inspectRun(name, fn, options) {
|
|
4081
|
+
if (typeof fn !== "function") {
|
|
4082
|
+
throw new TypeError("inspectRun requires `fn` to be a function");
|
|
4083
|
+
}
|
|
4084
|
+
if (options?.enabled === false) {
|
|
4085
|
+
return Promise.resolve(fn());
|
|
4086
|
+
}
|
|
4087
|
+
const runName = normalizeRunName(name);
|
|
4088
|
+
const runId = createRunId();
|
|
4089
|
+
const traceDir = resolveTraceDir({ dir: options?.traceDir });
|
|
4090
|
+
const traceSafety = resolveTraceSafetyOptions(options);
|
|
4091
|
+
const runMetadata = buildRunStartedMetadata(options);
|
|
4092
|
+
const context = {
|
|
4093
|
+
runId,
|
|
4094
|
+
runName,
|
|
4095
|
+
traceDir,
|
|
4096
|
+
silent: options?.silent ?? false,
|
|
4097
|
+
metadata: runMetadata
|
|
4098
|
+
};
|
|
4099
|
+
return runWithContext(context, async () => {
|
|
4100
|
+
const startTime = Date.now();
|
|
4101
|
+
let traceFilePath;
|
|
4102
|
+
await safeInstrumentation("initializeTraceFile", async () => {
|
|
4103
|
+
traceFilePath = await initializeTraceFile(runId, traceDir);
|
|
4104
|
+
});
|
|
4105
|
+
await safeInstrumentation("writeTraceEvent(run_started)", async () => {
|
|
4106
|
+
const started = {
|
|
4107
|
+
schemaVersion: "0.1",
|
|
4108
|
+
event: "run_started",
|
|
4109
|
+
timestamp: startTime,
|
|
4110
|
+
runId,
|
|
4111
|
+
name: runName,
|
|
4112
|
+
startTime,
|
|
4113
|
+
...runMetadata !== void 0 ? { metadata: runMetadata } : {}
|
|
4114
|
+
};
|
|
4115
|
+
await writeTraceEvent(
|
|
4116
|
+
prepareTraceEventForDisk(started, traceSafety),
|
|
4117
|
+
traceDir
|
|
4118
|
+
);
|
|
4119
|
+
});
|
|
4120
|
+
await safeInstrumentation("printRunStart", () => {
|
|
4121
|
+
printRunStart(runId, runName);
|
|
4122
|
+
});
|
|
4123
|
+
let result;
|
|
4124
|
+
try {
|
|
4125
|
+
result = await Promise.resolve(fn());
|
|
4126
|
+
} catch (userError) {
|
|
4127
|
+
const endTime2 = Date.now();
|
|
4128
|
+
const durationMs3 = endTime2 - startTime;
|
|
4129
|
+
const formatted = formatError(userError);
|
|
4130
|
+
const printPath2 = traceFilePath ?? getTraceFilePath(runId, traceDir);
|
|
4131
|
+
await safeInstrumentation("writeTraceEvent(run_completed error)", async () => {
|
|
4132
|
+
const completed = {
|
|
4133
|
+
schemaVersion: "0.1",
|
|
4134
|
+
event: "run_completed",
|
|
4135
|
+
timestamp: endTime2,
|
|
4136
|
+
runId,
|
|
4137
|
+
status: "error",
|
|
4138
|
+
endTime: endTime2,
|
|
4139
|
+
durationMs: durationMs3,
|
|
4140
|
+
error: formatted
|
|
4141
|
+
};
|
|
4142
|
+
await writeTraceEvent(
|
|
4143
|
+
prepareTraceEventForDisk(completed, traceSafety),
|
|
4144
|
+
traceDir
|
|
4145
|
+
);
|
|
4146
|
+
});
|
|
4147
|
+
await safeInstrumentation("printRunComplete(error)", () => {
|
|
4148
|
+
printRunComplete(runName, runId, durationMs3, "error", printPath2);
|
|
4149
|
+
});
|
|
4150
|
+
throw userError;
|
|
4151
|
+
}
|
|
4152
|
+
const endTime = Date.now();
|
|
4153
|
+
const durationMs2 = endTime - startTime;
|
|
4154
|
+
const printPath = traceFilePath ?? getTraceFilePath(runId, traceDir);
|
|
4155
|
+
await safeInstrumentation("writeTraceEvent(run_completed success)", async () => {
|
|
4156
|
+
const completed = {
|
|
4157
|
+
schemaVersion: "0.1",
|
|
4158
|
+
event: "run_completed",
|
|
4159
|
+
timestamp: endTime,
|
|
4160
|
+
runId,
|
|
4161
|
+
status: "success",
|
|
4162
|
+
endTime,
|
|
4163
|
+
durationMs: durationMs2
|
|
4164
|
+
};
|
|
4165
|
+
await writeTraceEvent(
|
|
4166
|
+
prepareTraceEventForDisk(completed, traceSafety),
|
|
4167
|
+
traceDir
|
|
4168
|
+
);
|
|
4169
|
+
});
|
|
4170
|
+
await safeInstrumentation("printRunComplete(success)", () => {
|
|
4171
|
+
printRunComplete(runName, runId, durationMs2, "success", printPath);
|
|
4172
|
+
});
|
|
4173
|
+
return result;
|
|
4174
|
+
}, traceSafety);
|
|
4175
|
+
}
|
|
4176
|
+
|
|
4177
|
+
// packages/core/src/maybe-inspect-run.ts
|
|
4178
|
+
var ENABLED_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on", "enabled"]);
|
|
4179
|
+
function isAgentInspectEnabled(value) {
|
|
4180
|
+
if (value === void 0) return false;
|
|
4181
|
+
const normalized = value.trim().toLowerCase();
|
|
4182
|
+
if (normalized === "") return false;
|
|
4183
|
+
return ENABLED_ENV_VALUES.has(normalized);
|
|
4184
|
+
}
|
|
4185
|
+
async function maybeInspectRun(name, fn, options) {
|
|
4186
|
+
if (typeof fn !== "function") {
|
|
4187
|
+
throw new TypeError("maybeInspectRun requires `fn` to be a function");
|
|
4188
|
+
}
|
|
4189
|
+
const enabled = options?.enabled !== void 0 ? options.enabled : isAgentInspectEnabled(process.env.AGENT_INSPECT);
|
|
4190
|
+
if (!enabled) {
|
|
4191
|
+
return Promise.resolve(fn());
|
|
4192
|
+
}
|
|
4193
|
+
return inspectRun(name, fn, options);
|
|
4194
|
+
}
|
|
2206
4195
|
|
|
2207
4196
|
exports.DEFAULT_MAX_EVENT_BYTES = DEFAULT_MAX_EVENT_BYTES;
|
|
2208
4197
|
exports.DEFAULT_MAX_METADATA_VALUE_LENGTH = DEFAULT_MAX_METADATA_VALUE_LENGTH;
|
|
@@ -2214,11 +4203,19 @@ exports.MAX_TERMINAL_DEPTH = MAX_TERMINAL_DEPTH;
|
|
|
2214
4203
|
exports.MAX_TERMINAL_NAME_LENGTH = MAX_TERMINAL_NAME_LENGTH;
|
|
2215
4204
|
exports.RUNS_DIR_NAME = RUNS_DIR_NAME;
|
|
2216
4205
|
exports.TERMINAL_INDENT = TERMINAL_INDENT;
|
|
4206
|
+
exports.TraceDirectory = TraceDirectory;
|
|
4207
|
+
exports.buildLocalExplanation = buildLocalExplanation;
|
|
4208
|
+
exports.buildRunSummary = buildRunSummary;
|
|
4209
|
+
exports.buildRunTimeline = buildRunTimeline;
|
|
4210
|
+
exports.buildRunWhatSummary = buildRunWhatSummary;
|
|
4211
|
+
exports.buildTraceStats = buildTraceStats;
|
|
2217
4212
|
exports.createInspector = createInspector;
|
|
2218
4213
|
exports.createInspectorRuntime = createInspectorRuntime;
|
|
2219
4214
|
exports.createRunId = createRunId;
|
|
2220
4215
|
exports.createStepId = createStepId;
|
|
2221
4216
|
exports.ensureTraceDir = ensureTraceDir;
|
|
4217
|
+
exports.extractMetadata = extractMetadata;
|
|
4218
|
+
exports.filterTraces = filterTraces;
|
|
2222
4219
|
exports.formatDuration = formatDuration2;
|
|
2223
4220
|
exports.formatError = formatError;
|
|
2224
4221
|
exports.formatTerminalName = formatTerminalName;
|
|
@@ -2232,11 +4229,24 @@ exports.getCurrentStepId = getCurrentStepId;
|
|
|
2232
4229
|
exports.getDefaultTraceDir = getDefaultTraceDir;
|
|
2233
4230
|
exports.getIndent = getIndent;
|
|
2234
4231
|
exports.getParentStepId = getParentStepId;
|
|
4232
|
+
exports.getRunIdFromTraceFileName = getRunIdFromTraceFileName;
|
|
2235
4233
|
exports.getTraceDirFromContext = getTraceDirFromContext;
|
|
2236
4234
|
exports.getTraceFilePath = getTraceFilePath;
|
|
2237
4235
|
exports.getTraceSafetyFromContext = getTraceSafetyFromContext;
|
|
2238
4236
|
exports.hasActiveContext = hasActiveContext;
|
|
4237
|
+
exports.initializeTraceFile = initializeTraceFile;
|
|
4238
|
+
exports.isAgentInspectEnabled = isAgentInspectEnabled;
|
|
4239
|
+
exports.isAgentInspectTrace = isAgentInspectTrace;
|
|
2239
4240
|
exports.isSilentContext = isSilentContext;
|
|
4241
|
+
exports.isStepStatus = isStepStatus;
|
|
4242
|
+
exports.isStepType = isStepType;
|
|
4243
|
+
exports.isTraceEvent = isTraceEvent;
|
|
4244
|
+
exports.listTraceFiles = listTraceFiles;
|
|
4245
|
+
exports.loadTraceMetadataList = loadTraceMetadataList;
|
|
4246
|
+
exports.maybeInspectRun = maybeInspectRun;
|
|
4247
|
+
exports.parseDuration = parseDuration;
|
|
4248
|
+
exports.parseDurationFilter = parseDurationFilter;
|
|
4249
|
+
exports.parseTraceJsonl = parseTraceJsonl;
|
|
2240
4250
|
exports.prepareMetadataForDisk = prepareMetadataForDisk;
|
|
2241
4251
|
exports.prepareTraceEventForDisk = prepareTraceEventForDisk;
|
|
2242
4252
|
exports.printError = printError;
|
|
@@ -2245,14 +4255,25 @@ exports.printRunComplete = printRunComplete;
|
|
|
2245
4255
|
exports.printRunStart = printRunStart;
|
|
2246
4256
|
exports.printStepComplete = printStepComplete;
|
|
2247
4257
|
exports.printStepStart = printStepStart;
|
|
4258
|
+
exports.readTraceEvents = readTraceEvents;
|
|
4259
|
+
exports.readTraceFile = readTraceFile;
|
|
2248
4260
|
exports.renderErrorLine = renderErrorLine;
|
|
2249
4261
|
exports.renderRunSummary = renderRunSummary;
|
|
4262
|
+
exports.renderRunWhat = renderRunWhat;
|
|
2250
4263
|
exports.renderStepLine = renderStepLine;
|
|
4264
|
+
exports.renderTimeline = renderTimeline;
|
|
4265
|
+
exports.renderTraceStats = renderTraceStats;
|
|
2251
4266
|
exports.resolveRedactionProfile = resolveRedactionProfile;
|
|
4267
|
+
exports.resolveTraceDir = resolveTraceDir;
|
|
2252
4268
|
exports.resolveTraceSafetyOptions = resolveTraceSafetyOptions;
|
|
2253
4269
|
exports.runWithContext = runWithContext;
|
|
2254
4270
|
exports.runWithStepContext = runWithStepContext;
|
|
4271
|
+
exports.searchTraces = searchTraces;
|
|
4272
|
+
exports.serializeEvent = serializeEvent;
|
|
2255
4273
|
exports.truncateName = truncateName;
|
|
4274
|
+
exports.unknownTraceFormatMessage = unknownTraceFormatMessage;
|
|
4275
|
+
exports.validateEvent = validateEvent;
|
|
2256
4276
|
exports.warn = warn;
|
|
4277
|
+
exports.writeTraceEvent = writeTraceEvent;
|
|
2257
4278
|
//# sourceMappingURL=advanced.cjs.map
|
|
2258
4279
|
//# sourceMappingURL=advanced.cjs.map
|