agent-inspect 1.0.2 → 1.1.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.
@@ -1176,89 +1176,6 @@ function warn(message, error) {
1176
1176
  }
1177
1177
  console.warn(`${base}: ${formatError(error).message}`);
1178
1178
  }
1179
- var storage = new async_hooks.AsyncLocalStorage();
1180
- function toPublicContext(ctx) {
1181
- return {
1182
- runId: ctx.runId,
1183
- runName: ctx.runName,
1184
- traceDir: ctx.traceDir,
1185
- silent: ctx.silent,
1186
- metadata: ctx.metadata
1187
- };
1188
- }
1189
- function invoke(fn) {
1190
- return new Promise((resolve, reject) => {
1191
- try {
1192
- Promise.resolve(fn()).then(resolve, reject);
1193
- } catch (e) {
1194
- reject(e);
1195
- }
1196
- });
1197
- }
1198
- function getCurrentContext() {
1199
- try {
1200
- const s = storage.getStore();
1201
- if (!s) return void 0;
1202
- return toPublicContext(s);
1203
- } catch {
1204
- return void 0;
1205
- }
1206
- }
1207
- function getCurrentStepId() {
1208
- try {
1209
- return storage.getStore()?.currentStepId;
1210
- } catch {
1211
- return void 0;
1212
- }
1213
- }
1214
- function getParentStepId() {
1215
- return getCurrentStepId();
1216
- }
1217
- function getCurrentDepth() {
1218
- try {
1219
- const d = storage.getStore()?.currentDepth;
1220
- return typeof d === "number" && Number.isFinite(d) ? d : 0;
1221
- } catch {
1222
- return 0;
1223
- }
1224
- }
1225
- function isSilentContext() {
1226
- try {
1227
- const s = storage.getStore();
1228
- return s ? s.silent : false;
1229
- } catch {
1230
- return false;
1231
- }
1232
- }
1233
- function runWithStepContext(stepId, fn) {
1234
- let parent;
1235
- try {
1236
- parent = storage.getStore();
1237
- } catch {
1238
- parent = void 0;
1239
- }
1240
- if (!parent) {
1241
- return invoke(fn);
1242
- }
1243
- const derived = {
1244
- runId: parent.runId,
1245
- runName: parent.runName,
1246
- traceDir: parent.traceDir,
1247
- silent: parent.silent,
1248
- metadata: parent.metadata,
1249
- currentStepId: stepId,
1250
- currentDepth: parent.currentDepth + 1
1251
- };
1252
- return new Promise((resolve, reject) => {
1253
- storage.run(derived, () => {
1254
- try {
1255
- Promise.resolve(fn()).then(resolve, reject);
1256
- } catch (e) {
1257
- reject(e);
1258
- }
1259
- });
1260
- });
1261
- }
1262
1179
  function isRecord6(value) {
1263
1180
  return typeof value === "object" && value !== null && !Array.isArray(value);
1264
1181
  }
@@ -1321,12 +1238,20 @@ function serializeEvent(event) {
1321
1238
  return "";
1322
1239
  }
1323
1240
  }
1241
+ function ensureEventWithinBounds(event) {
1242
+ const line = serializeEvent(event);
1243
+ if (line === "") return event;
1244
+ const bytes = Buffer.byteLength(line, "utf8");
1245
+ if (bytes <= DEFAULT_MAX_EVENT_BYTES) return event;
1246
+ return prepareTraceEventForDisk(event, resolveTraceSafetyOptions());
1247
+ }
1324
1248
  async function writeTraceEvent(event, traceDir) {
1325
- if (!validateEvent(event)) {
1249
+ const bounded = ensureEventWithinBounds(event);
1250
+ if (!validateEvent(bounded)) {
1326
1251
  warn("Skipped invalid trace event (validation failed)");
1327
1252
  return;
1328
1253
  }
1329
- const line = serializeEvent(event);
1254
+ const line = serializeEvent(bounded);
1330
1255
  if (line === "") {
1331
1256
  warn("Skipped trace event (serialization failed)");
1332
1257
  return;
@@ -1393,6 +1318,297 @@ async function readTraceEvents(runId, traceDir) {
1393
1318
  }
1394
1319
  return out;
1395
1320
  }
1321
+
1322
+ // packages/core/src/trace-event-safety.ts
1323
+ var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
1324
+ var DEFAULT_MAX_PREVIEW_LENGTH = 500;
1325
+ var DEFAULT_MAX_EVENT_BYTES = 65536;
1326
+ function isRecord7(value) {
1327
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1328
+ }
1329
+ function isPreviewKey(key) {
1330
+ return key.toLowerCase().includes("preview");
1331
+ }
1332
+ function truncateString(value, maxLen) {
1333
+ if (maxLen <= 0) return "\u2026";
1334
+ if (value.length <= maxLen) return value;
1335
+ return `${value.slice(0, maxLen)}\u2026`;
1336
+ }
1337
+ function byteLength(text) {
1338
+ return Buffer.byteLength(text, "utf8");
1339
+ }
1340
+ function resolveTraceSafetyOptions(options) {
1341
+ let redactEnabled = true;
1342
+ let redactionRules;
1343
+ {
1344
+ redactEnabled = true;
1345
+ }
1346
+ return {
1347
+ redactEnabled,
1348
+ redactionRules,
1349
+ maxMetadataValueLength: "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : DEFAULT_MAX_METADATA_VALUE_LENGTH,
1350
+ maxPreviewLength: "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : DEFAULT_MAX_PREVIEW_LENGTH,
1351
+ maxEventBytes: "undefined" === "number" && Number.isFinite(options.maxEventBytes) && options.maxEventBytes > 0 ? Math.floor(options.maxEventBytes) : DEFAULT_MAX_EVENT_BYTES
1352
+ };
1353
+ }
1354
+ function boundMetadataValue(key, value, opts, seen, depth) {
1355
+ if (depth > 32) return "[MaxDepth]";
1356
+ if (value === null || typeof value !== "object") {
1357
+ if (typeof value === "string") {
1358
+ const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
1359
+ return truncateString(value, max);
1360
+ }
1361
+ return value;
1362
+ }
1363
+ if (seen.has(value)) return "[Circular]";
1364
+ seen.add(value);
1365
+ if (Array.isArray(value)) {
1366
+ const maxItems = 50;
1367
+ const out2 = value.slice(0, maxItems).map(
1368
+ (item, index) => boundMetadataValue(String(index), item, opts, seen, depth + 1)
1369
+ );
1370
+ if (value.length > maxItems) {
1371
+ out2.push(`\u2026(+${value.length - maxItems} more)`);
1372
+ }
1373
+ return out2;
1374
+ }
1375
+ const record = value;
1376
+ const out = {};
1377
+ for (const [k, v] of Object.entries(record)) {
1378
+ out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
1379
+ }
1380
+ return out;
1381
+ }
1382
+ function redactMetadata(metadata, opts) {
1383
+ if (!opts.redactEnabled) return { ...metadata };
1384
+ const redactor = new Redactor({ rules: opts.redactionRules });
1385
+ return redactor.redactRecord(metadata);
1386
+ }
1387
+ function prepareMetadataForDisk(metadata, opts) {
1388
+ try {
1389
+ const redacted = redactMetadata(metadata, opts);
1390
+ const seen = /* @__PURE__ */ new WeakSet();
1391
+ const bounded = boundMetadataValue(
1392
+ "metadata",
1393
+ redacted,
1394
+ opts,
1395
+ seen,
1396
+ 0
1397
+ );
1398
+ return isRecord7(bounded) ? bounded : {};
1399
+ } catch {
1400
+ return { truncated: true, reason: "metadataPreparationFailed" };
1401
+ }
1402
+ }
1403
+ function truncateErrorStack(event, maxLen) {
1404
+ if (event.event !== "run_completed" && event.event !== "step_completed") {
1405
+ return event;
1406
+ }
1407
+ if (!event.error?.stack || typeof event.error.stack !== "string") {
1408
+ return event;
1409
+ }
1410
+ return {
1411
+ ...event,
1412
+ error: {
1413
+ ...event.error,
1414
+ stack: truncateString(event.error.stack, maxLen)
1415
+ }
1416
+ };
1417
+ }
1418
+ function replaceMetadataWithTruncationMarker(event, originalApproxBytes) {
1419
+ const marker = {
1420
+ truncated: true,
1421
+ reason: "maxEventBytes",
1422
+ originalApproxBytes
1423
+ };
1424
+ if (event.event === "run_started") {
1425
+ return { ...event, metadata: marker };
1426
+ }
1427
+ if (event.event === "step_started") {
1428
+ return { ...event, metadata: marker };
1429
+ }
1430
+ return event;
1431
+ }
1432
+ function shrinkMetadataLimits(opts, factor) {
1433
+ return {
1434
+ ...opts,
1435
+ maxMetadataValueLength: Math.max(32, Math.floor(opts.maxMetadataValueLength * factor)),
1436
+ maxPreviewLength: Math.max(16, Math.floor(opts.maxPreviewLength * factor))
1437
+ };
1438
+ }
1439
+ function applyMetadataToEvent(event, metadata) {
1440
+ if (event.event === "run_started") {
1441
+ return { ...event, metadata };
1442
+ }
1443
+ if (event.event === "step_started") {
1444
+ return { ...event, metadata };
1445
+ }
1446
+ return event;
1447
+ }
1448
+ function eventHasMetadata(event) {
1449
+ return (event.event === "run_started" || event.event === "step_started") && event.metadata !== void 0;
1450
+ }
1451
+ function getEventMetadata(event) {
1452
+ if (event.event === "run_started" || event.event === "step_started") {
1453
+ return event.metadata;
1454
+ }
1455
+ return void 0;
1456
+ }
1457
+ function prepareTraceEventForDisk(event, opts) {
1458
+ try {
1459
+ let working = { ...event };
1460
+ const rawMetadata = getEventMetadata(working);
1461
+ if (rawMetadata !== void 0) {
1462
+ const safe = prepareMetadataForDisk(rawMetadata, opts);
1463
+ working = applyMetadataToEvent(working, safe);
1464
+ }
1465
+ let serialized = serializeEvent(working);
1466
+ if (serialized === "") {
1467
+ return working;
1468
+ }
1469
+ let bytes = byteLength(serialized);
1470
+ if (bytes <= opts.maxEventBytes) {
1471
+ return working;
1472
+ }
1473
+ if (rawMetadata !== void 0) {
1474
+ for (const factor of [0.5, 0.25, 0.1]) {
1475
+ const tighter = shrinkMetadataLimits(opts, factor);
1476
+ const shrunk = prepareMetadataForDisk(rawMetadata, tighter);
1477
+ working = applyMetadataToEvent(working, shrunk);
1478
+ serialized = serializeEvent(working);
1479
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1480
+ return working;
1481
+ }
1482
+ }
1483
+ working = replaceMetadataWithTruncationMarker(working, bytes);
1484
+ serialized = serializeEvent(working);
1485
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1486
+ return working;
1487
+ }
1488
+ }
1489
+ working = truncateErrorStack(working, Math.min(opts.maxMetadataValueLength, 500));
1490
+ serialized = serializeEvent(working);
1491
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1492
+ return working;
1493
+ }
1494
+ if (eventHasMetadata(working)) {
1495
+ working = replaceMetadataWithTruncationMarker(working, bytes);
1496
+ serialized = serializeEvent(working);
1497
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1498
+ return working;
1499
+ }
1500
+ if (working.event === "run_started") {
1501
+ const { metadata: _meta, ...rest } = working;
1502
+ working = rest;
1503
+ } else if (working.event === "step_started") {
1504
+ const { metadata: _meta, ...rest } = working;
1505
+ working = rest;
1506
+ }
1507
+ }
1508
+ return working;
1509
+ } catch {
1510
+ if (event.event === "run_started" || event.event === "step_started") {
1511
+ return applyMetadataToEvent(event, {
1512
+ truncated: true,
1513
+ reason: "prepareTraceEventFailed"
1514
+ });
1515
+ }
1516
+ return event;
1517
+ }
1518
+ }
1519
+
1520
+ // packages/core/src/context.ts
1521
+ var storage = new async_hooks.AsyncLocalStorage();
1522
+ function toPublicContext(ctx) {
1523
+ return {
1524
+ runId: ctx.runId,
1525
+ runName: ctx.runName,
1526
+ traceDir: ctx.traceDir,
1527
+ silent: ctx.silent,
1528
+ metadata: ctx.metadata
1529
+ };
1530
+ }
1531
+ function invoke(fn) {
1532
+ return new Promise((resolve, reject) => {
1533
+ try {
1534
+ Promise.resolve(fn()).then(resolve, reject);
1535
+ } catch (e) {
1536
+ reject(e);
1537
+ }
1538
+ });
1539
+ }
1540
+ function getCurrentContext() {
1541
+ try {
1542
+ const s = storage.getStore();
1543
+ if (!s) return void 0;
1544
+ return toPublicContext(s);
1545
+ } catch {
1546
+ return void 0;
1547
+ }
1548
+ }
1549
+ function getCurrentStepId() {
1550
+ try {
1551
+ return storage.getStore()?.currentStepId;
1552
+ } catch {
1553
+ return void 0;
1554
+ }
1555
+ }
1556
+ function getParentStepId() {
1557
+ return getCurrentStepId();
1558
+ }
1559
+ function getCurrentDepth() {
1560
+ try {
1561
+ const d = storage.getStore()?.currentDepth;
1562
+ return typeof d === "number" && Number.isFinite(d) ? d : 0;
1563
+ } catch {
1564
+ return 0;
1565
+ }
1566
+ }
1567
+ function isSilentContext() {
1568
+ try {
1569
+ const s = storage.getStore();
1570
+ return s ? s.silent : false;
1571
+ } catch {
1572
+ return false;
1573
+ }
1574
+ }
1575
+ function getTraceSafetyFromContext() {
1576
+ try {
1577
+ return storage.getStore()?.traceSafety;
1578
+ } catch {
1579
+ return void 0;
1580
+ }
1581
+ }
1582
+ function runWithStepContext(stepId, fn) {
1583
+ let parent;
1584
+ try {
1585
+ parent = storage.getStore();
1586
+ } catch {
1587
+ parent = void 0;
1588
+ }
1589
+ if (!parent) {
1590
+ return invoke(fn);
1591
+ }
1592
+ const derived = {
1593
+ runId: parent.runId,
1594
+ runName: parent.runName,
1595
+ traceDir: parent.traceDir,
1596
+ silent: parent.silent,
1597
+ metadata: parent.metadata,
1598
+ traceSafety: parent.traceSafety,
1599
+ currentStepId: stepId,
1600
+ currentDepth: parent.currentDepth + 1
1601
+ };
1602
+ return new Promise((resolve, reject) => {
1603
+ storage.run(derived, () => {
1604
+ try {
1605
+ Promise.resolve(fn()).then(resolve, reject);
1606
+ } catch (e) {
1607
+ reject(e);
1608
+ }
1609
+ });
1610
+ });
1611
+ }
1396
1612
  function resolveTraceDir(options = {}) {
1397
1613
  if (typeof options.dir === "string" && options.dir.trim() !== "") {
1398
1614
  return options.dir.trim();
@@ -1657,7 +1873,7 @@ var KNOWN_EVENTS = /* @__PURE__ */ new Set([
1657
1873
  "step_started",
1658
1874
  "step_completed"
1659
1875
  ]);
1660
- function isRecord7(value) {
1876
+ function isRecord8(value) {
1661
1877
  return typeof value === "object" && value !== null && !Array.isArray(value);
1662
1878
  }
1663
1879
  function safeParse(line) {
@@ -1679,7 +1895,7 @@ async function isAgentInspectTrace(filePath) {
1679
1895
  if (trimmed === "") continue;
1680
1896
  const parsed = safeParse(trimmed);
1681
1897
  if (!parsed) continue;
1682
- if (!isRecord7(parsed)) continue;
1898
+ if (!isRecord8(parsed)) continue;
1683
1899
  checked += 1;
1684
1900
  if (isTraceEvent(parsed)) return true;
1685
1901
  const ev = parsed.event;
@@ -2379,6 +2595,7 @@ async function stepImpl(name, fn, options) {
2379
2595
  const parentId = getParentStepId();
2380
2596
  const stepType = options?.type ?? "logic";
2381
2597
  const metadata = options?.metadata;
2598
+ const traceSafety = getTraceSafetyFromContext();
2382
2599
  const startTime = Date.now();
2383
2600
  await safeInstrumentation("writeTraceEvent(step_started)", async () => {
2384
2601
  const started = {
@@ -2393,7 +2610,8 @@ async function stepImpl(name, fn, options) {
2393
2610
  startTime,
2394
2611
  ...metadata !== void 0 ? { metadata } : {}
2395
2612
  };
2396
- await writeTraceEvent(started, context.traceDir);
2613
+ const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(started, traceSafety) : started;
2614
+ await writeTraceEvent(safe, context.traceDir);
2397
2615
  });
2398
2616
  await safeInstrumentation("printStepStart", () => {
2399
2617
  printStepStart(stepName, renderDepth);
@@ -2419,7 +2637,8 @@ async function stepImpl(name, fn, options) {
2419
2637
  durationMs: durationMs2,
2420
2638
  error: formatted
2421
2639
  };
2422
- await writeTraceEvent(completed, context.traceDir);
2640
+ const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
2641
+ await writeTraceEvent(safe, context.traceDir);
2423
2642
  });
2424
2643
  await safeInstrumentation("printStepComplete(error)", () => {
2425
2644
  printStepComplete(stepName, durationMs2, "error", renderDepth);
@@ -2445,7 +2664,8 @@ async function stepImpl(name, fn, options) {
2445
2664
  endTime,
2446
2665
  durationMs
2447
2666
  };
2448
- await writeTraceEvent(completed, context.traceDir);
2667
+ const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
2668
+ await writeTraceEvent(safe, context.traceDir);
2449
2669
  });
2450
2670
  await safeInstrumentation("printStepComplete(success)", () => {
2451
2671
  printStepComplete(stepName, durationMs, "success", renderDepth);