agent-inspect 1.0.3 → 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.
@@ -1166,89 +1166,6 @@ function warn(message, error) {
1166
1166
  }
1167
1167
  console.warn(`${base}: ${formatError(error).message}`);
1168
1168
  }
1169
- var storage = new AsyncLocalStorage();
1170
- function toPublicContext(ctx) {
1171
- return {
1172
- runId: ctx.runId,
1173
- runName: ctx.runName,
1174
- traceDir: ctx.traceDir,
1175
- silent: ctx.silent,
1176
- metadata: ctx.metadata
1177
- };
1178
- }
1179
- function invoke(fn) {
1180
- return new Promise((resolve, reject) => {
1181
- try {
1182
- Promise.resolve(fn()).then(resolve, reject);
1183
- } catch (e) {
1184
- reject(e);
1185
- }
1186
- });
1187
- }
1188
- function getCurrentContext() {
1189
- try {
1190
- const s = storage.getStore();
1191
- if (!s) return void 0;
1192
- return toPublicContext(s);
1193
- } catch {
1194
- return void 0;
1195
- }
1196
- }
1197
- function getCurrentStepId() {
1198
- try {
1199
- return storage.getStore()?.currentStepId;
1200
- } catch {
1201
- return void 0;
1202
- }
1203
- }
1204
- function getParentStepId() {
1205
- return getCurrentStepId();
1206
- }
1207
- function getCurrentDepth() {
1208
- try {
1209
- const d = storage.getStore()?.currentDepth;
1210
- return typeof d === "number" && Number.isFinite(d) ? d : 0;
1211
- } catch {
1212
- return 0;
1213
- }
1214
- }
1215
- function isSilentContext() {
1216
- try {
1217
- const s = storage.getStore();
1218
- return s ? s.silent : false;
1219
- } catch {
1220
- return false;
1221
- }
1222
- }
1223
- function runWithStepContext(stepId, fn) {
1224
- let parent;
1225
- try {
1226
- parent = storage.getStore();
1227
- } catch {
1228
- parent = void 0;
1229
- }
1230
- if (!parent) {
1231
- return invoke(fn);
1232
- }
1233
- const derived = {
1234
- runId: parent.runId,
1235
- runName: parent.runName,
1236
- traceDir: parent.traceDir,
1237
- silent: parent.silent,
1238
- metadata: parent.metadata,
1239
- currentStepId: stepId,
1240
- currentDepth: parent.currentDepth + 1
1241
- };
1242
- return new Promise((resolve, reject) => {
1243
- storage.run(derived, () => {
1244
- try {
1245
- Promise.resolve(fn()).then(resolve, reject);
1246
- } catch (e) {
1247
- reject(e);
1248
- }
1249
- });
1250
- });
1251
- }
1252
1169
  function isRecord6(value) {
1253
1170
  return typeof value === "object" && value !== null && !Array.isArray(value);
1254
1171
  }
@@ -1311,12 +1228,20 @@ function serializeEvent(event) {
1311
1228
  return "";
1312
1229
  }
1313
1230
  }
1231
+ function ensureEventWithinBounds(event) {
1232
+ const line = serializeEvent(event);
1233
+ if (line === "") return event;
1234
+ const bytes = Buffer.byteLength(line, "utf8");
1235
+ if (bytes <= DEFAULT_MAX_EVENT_BYTES) return event;
1236
+ return prepareTraceEventForDisk(event, resolveTraceSafetyOptions());
1237
+ }
1314
1238
  async function writeTraceEvent(event, traceDir) {
1315
- if (!validateEvent(event)) {
1239
+ const bounded = ensureEventWithinBounds(event);
1240
+ if (!validateEvent(bounded)) {
1316
1241
  warn("Skipped invalid trace event (validation failed)");
1317
1242
  return;
1318
1243
  }
1319
- const line = serializeEvent(event);
1244
+ const line = serializeEvent(bounded);
1320
1245
  if (line === "") {
1321
1246
  warn("Skipped trace event (serialization failed)");
1322
1247
  return;
@@ -1383,6 +1308,297 @@ async function readTraceEvents(runId, traceDir) {
1383
1308
  }
1384
1309
  return out;
1385
1310
  }
1311
+
1312
+ // packages/core/src/trace-event-safety.ts
1313
+ var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
1314
+ var DEFAULT_MAX_PREVIEW_LENGTH = 500;
1315
+ var DEFAULT_MAX_EVENT_BYTES = 65536;
1316
+ function isRecord7(value) {
1317
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1318
+ }
1319
+ function isPreviewKey(key) {
1320
+ return key.toLowerCase().includes("preview");
1321
+ }
1322
+ function truncateString(value, maxLen) {
1323
+ if (maxLen <= 0) return "\u2026";
1324
+ if (value.length <= maxLen) return value;
1325
+ return `${value.slice(0, maxLen)}\u2026`;
1326
+ }
1327
+ function byteLength(text) {
1328
+ return Buffer.byteLength(text, "utf8");
1329
+ }
1330
+ function resolveTraceSafetyOptions(options) {
1331
+ let redactEnabled = true;
1332
+ let redactionRules;
1333
+ {
1334
+ redactEnabled = true;
1335
+ }
1336
+ return {
1337
+ redactEnabled,
1338
+ redactionRules,
1339
+ maxMetadataValueLength: "undefined" === "number" && Number.isFinite(options.maxMetadataValueLength) && options.maxMetadataValueLength >= 0 ? Math.floor(options.maxMetadataValueLength) : DEFAULT_MAX_METADATA_VALUE_LENGTH,
1340
+ maxPreviewLength: "undefined" === "number" && Number.isFinite(options.maxPreviewLength) && options.maxPreviewLength >= 0 ? Math.floor(options.maxPreviewLength) : DEFAULT_MAX_PREVIEW_LENGTH,
1341
+ maxEventBytes: "undefined" === "number" && Number.isFinite(options.maxEventBytes) && options.maxEventBytes > 0 ? Math.floor(options.maxEventBytes) : DEFAULT_MAX_EVENT_BYTES
1342
+ };
1343
+ }
1344
+ function boundMetadataValue(key, value, opts, seen, depth) {
1345
+ if (depth > 32) return "[MaxDepth]";
1346
+ if (value === null || typeof value !== "object") {
1347
+ if (typeof value === "string") {
1348
+ const max = isPreviewKey(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
1349
+ return truncateString(value, max);
1350
+ }
1351
+ return value;
1352
+ }
1353
+ if (seen.has(value)) return "[Circular]";
1354
+ seen.add(value);
1355
+ if (Array.isArray(value)) {
1356
+ const maxItems = 50;
1357
+ const out2 = value.slice(0, maxItems).map(
1358
+ (item, index) => boundMetadataValue(String(index), item, opts, seen, depth + 1)
1359
+ );
1360
+ if (value.length > maxItems) {
1361
+ out2.push(`\u2026(+${value.length - maxItems} more)`);
1362
+ }
1363
+ return out2;
1364
+ }
1365
+ const record = value;
1366
+ const out = {};
1367
+ for (const [k, v] of Object.entries(record)) {
1368
+ out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
1369
+ }
1370
+ return out;
1371
+ }
1372
+ function redactMetadata(metadata, opts) {
1373
+ if (!opts.redactEnabled) return { ...metadata };
1374
+ const redactor = new Redactor({ rules: opts.redactionRules });
1375
+ return redactor.redactRecord(metadata);
1376
+ }
1377
+ function prepareMetadataForDisk(metadata, opts) {
1378
+ try {
1379
+ const redacted = redactMetadata(metadata, opts);
1380
+ const seen = /* @__PURE__ */ new WeakSet();
1381
+ const bounded = boundMetadataValue(
1382
+ "metadata",
1383
+ redacted,
1384
+ opts,
1385
+ seen,
1386
+ 0
1387
+ );
1388
+ return isRecord7(bounded) ? bounded : {};
1389
+ } catch {
1390
+ return { truncated: true, reason: "metadataPreparationFailed" };
1391
+ }
1392
+ }
1393
+ function truncateErrorStack(event, maxLen) {
1394
+ if (event.event !== "run_completed" && event.event !== "step_completed") {
1395
+ return event;
1396
+ }
1397
+ if (!event.error?.stack || typeof event.error.stack !== "string") {
1398
+ return event;
1399
+ }
1400
+ return {
1401
+ ...event,
1402
+ error: {
1403
+ ...event.error,
1404
+ stack: truncateString(event.error.stack, maxLen)
1405
+ }
1406
+ };
1407
+ }
1408
+ function replaceMetadataWithTruncationMarker(event, originalApproxBytes) {
1409
+ const marker = {
1410
+ truncated: true,
1411
+ reason: "maxEventBytes",
1412
+ originalApproxBytes
1413
+ };
1414
+ if (event.event === "run_started") {
1415
+ return { ...event, metadata: marker };
1416
+ }
1417
+ if (event.event === "step_started") {
1418
+ return { ...event, metadata: marker };
1419
+ }
1420
+ return event;
1421
+ }
1422
+ function shrinkMetadataLimits(opts, factor) {
1423
+ return {
1424
+ ...opts,
1425
+ maxMetadataValueLength: Math.max(32, Math.floor(opts.maxMetadataValueLength * factor)),
1426
+ maxPreviewLength: Math.max(16, Math.floor(opts.maxPreviewLength * factor))
1427
+ };
1428
+ }
1429
+ function applyMetadataToEvent(event, metadata) {
1430
+ if (event.event === "run_started") {
1431
+ return { ...event, metadata };
1432
+ }
1433
+ if (event.event === "step_started") {
1434
+ return { ...event, metadata };
1435
+ }
1436
+ return event;
1437
+ }
1438
+ function eventHasMetadata(event) {
1439
+ return (event.event === "run_started" || event.event === "step_started") && event.metadata !== void 0;
1440
+ }
1441
+ function getEventMetadata(event) {
1442
+ if (event.event === "run_started" || event.event === "step_started") {
1443
+ return event.metadata;
1444
+ }
1445
+ return void 0;
1446
+ }
1447
+ function prepareTraceEventForDisk(event, opts) {
1448
+ try {
1449
+ let working = { ...event };
1450
+ const rawMetadata = getEventMetadata(working);
1451
+ if (rawMetadata !== void 0) {
1452
+ const safe = prepareMetadataForDisk(rawMetadata, opts);
1453
+ working = applyMetadataToEvent(working, safe);
1454
+ }
1455
+ let serialized = serializeEvent(working);
1456
+ if (serialized === "") {
1457
+ return working;
1458
+ }
1459
+ let bytes = byteLength(serialized);
1460
+ if (bytes <= opts.maxEventBytes) {
1461
+ return working;
1462
+ }
1463
+ if (rawMetadata !== void 0) {
1464
+ for (const factor of [0.5, 0.25, 0.1]) {
1465
+ const tighter = shrinkMetadataLimits(opts, factor);
1466
+ const shrunk = prepareMetadataForDisk(rawMetadata, tighter);
1467
+ working = applyMetadataToEvent(working, shrunk);
1468
+ serialized = serializeEvent(working);
1469
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1470
+ return working;
1471
+ }
1472
+ }
1473
+ working = replaceMetadataWithTruncationMarker(working, bytes);
1474
+ serialized = serializeEvent(working);
1475
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1476
+ return working;
1477
+ }
1478
+ }
1479
+ working = truncateErrorStack(working, Math.min(opts.maxMetadataValueLength, 500));
1480
+ serialized = serializeEvent(working);
1481
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1482
+ return working;
1483
+ }
1484
+ if (eventHasMetadata(working)) {
1485
+ working = replaceMetadataWithTruncationMarker(working, bytes);
1486
+ serialized = serializeEvent(working);
1487
+ if (serialized !== "" && byteLength(serialized) <= opts.maxEventBytes) {
1488
+ return working;
1489
+ }
1490
+ if (working.event === "run_started") {
1491
+ const { metadata: _meta, ...rest } = working;
1492
+ working = rest;
1493
+ } else if (working.event === "step_started") {
1494
+ const { metadata: _meta, ...rest } = working;
1495
+ working = rest;
1496
+ }
1497
+ }
1498
+ return working;
1499
+ } catch {
1500
+ if (event.event === "run_started" || event.event === "step_started") {
1501
+ return applyMetadataToEvent(event, {
1502
+ truncated: true,
1503
+ reason: "prepareTraceEventFailed"
1504
+ });
1505
+ }
1506
+ return event;
1507
+ }
1508
+ }
1509
+
1510
+ // packages/core/src/context.ts
1511
+ var storage = new AsyncLocalStorage();
1512
+ function toPublicContext(ctx) {
1513
+ return {
1514
+ runId: ctx.runId,
1515
+ runName: ctx.runName,
1516
+ traceDir: ctx.traceDir,
1517
+ silent: ctx.silent,
1518
+ metadata: ctx.metadata
1519
+ };
1520
+ }
1521
+ function invoke(fn) {
1522
+ return new Promise((resolve, reject) => {
1523
+ try {
1524
+ Promise.resolve(fn()).then(resolve, reject);
1525
+ } catch (e) {
1526
+ reject(e);
1527
+ }
1528
+ });
1529
+ }
1530
+ function getCurrentContext() {
1531
+ try {
1532
+ const s = storage.getStore();
1533
+ if (!s) return void 0;
1534
+ return toPublicContext(s);
1535
+ } catch {
1536
+ return void 0;
1537
+ }
1538
+ }
1539
+ function getCurrentStepId() {
1540
+ try {
1541
+ return storage.getStore()?.currentStepId;
1542
+ } catch {
1543
+ return void 0;
1544
+ }
1545
+ }
1546
+ function getParentStepId() {
1547
+ return getCurrentStepId();
1548
+ }
1549
+ function getCurrentDepth() {
1550
+ try {
1551
+ const d = storage.getStore()?.currentDepth;
1552
+ return typeof d === "number" && Number.isFinite(d) ? d : 0;
1553
+ } catch {
1554
+ return 0;
1555
+ }
1556
+ }
1557
+ function isSilentContext() {
1558
+ try {
1559
+ const s = storage.getStore();
1560
+ return s ? s.silent : false;
1561
+ } catch {
1562
+ return false;
1563
+ }
1564
+ }
1565
+ function getTraceSafetyFromContext() {
1566
+ try {
1567
+ return storage.getStore()?.traceSafety;
1568
+ } catch {
1569
+ return void 0;
1570
+ }
1571
+ }
1572
+ function runWithStepContext(stepId, fn) {
1573
+ let parent;
1574
+ try {
1575
+ parent = storage.getStore();
1576
+ } catch {
1577
+ parent = void 0;
1578
+ }
1579
+ if (!parent) {
1580
+ return invoke(fn);
1581
+ }
1582
+ const derived = {
1583
+ runId: parent.runId,
1584
+ runName: parent.runName,
1585
+ traceDir: parent.traceDir,
1586
+ silent: parent.silent,
1587
+ metadata: parent.metadata,
1588
+ traceSafety: parent.traceSafety,
1589
+ currentStepId: stepId,
1590
+ currentDepth: parent.currentDepth + 1
1591
+ };
1592
+ return new Promise((resolve, reject) => {
1593
+ storage.run(derived, () => {
1594
+ try {
1595
+ Promise.resolve(fn()).then(resolve, reject);
1596
+ } catch (e) {
1597
+ reject(e);
1598
+ }
1599
+ });
1600
+ });
1601
+ }
1386
1602
  function resolveTraceDir(options = {}) {
1387
1603
  if (typeof options.dir === "string" && options.dir.trim() !== "") {
1388
1604
  return options.dir.trim();
@@ -1647,7 +1863,7 @@ var KNOWN_EVENTS = /* @__PURE__ */ new Set([
1647
1863
  "step_started",
1648
1864
  "step_completed"
1649
1865
  ]);
1650
- function isRecord7(value) {
1866
+ function isRecord8(value) {
1651
1867
  return typeof value === "object" && value !== null && !Array.isArray(value);
1652
1868
  }
1653
1869
  function safeParse(line) {
@@ -1669,7 +1885,7 @@ async function isAgentInspectTrace(filePath) {
1669
1885
  if (trimmed === "") continue;
1670
1886
  const parsed = safeParse(trimmed);
1671
1887
  if (!parsed) continue;
1672
- if (!isRecord7(parsed)) continue;
1888
+ if (!isRecord8(parsed)) continue;
1673
1889
  checked += 1;
1674
1890
  if (isTraceEvent(parsed)) return true;
1675
1891
  const ev = parsed.event;
@@ -2369,6 +2585,7 @@ async function stepImpl(name, fn, options) {
2369
2585
  const parentId = getParentStepId();
2370
2586
  const stepType = options?.type ?? "logic";
2371
2587
  const metadata = options?.metadata;
2588
+ const traceSafety = getTraceSafetyFromContext();
2372
2589
  const startTime = Date.now();
2373
2590
  await safeInstrumentation("writeTraceEvent(step_started)", async () => {
2374
2591
  const started = {
@@ -2383,7 +2600,8 @@ async function stepImpl(name, fn, options) {
2383
2600
  startTime,
2384
2601
  ...metadata !== void 0 ? { metadata } : {}
2385
2602
  };
2386
- await writeTraceEvent(started, context.traceDir);
2603
+ const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(started, traceSafety) : started;
2604
+ await writeTraceEvent(safe, context.traceDir);
2387
2605
  });
2388
2606
  await safeInstrumentation("printStepStart", () => {
2389
2607
  printStepStart(stepName, renderDepth);
@@ -2409,7 +2627,8 @@ async function stepImpl(name, fn, options) {
2409
2627
  durationMs: durationMs2,
2410
2628
  error: formatted
2411
2629
  };
2412
- await writeTraceEvent(completed, context.traceDir);
2630
+ const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
2631
+ await writeTraceEvent(safe, context.traceDir);
2413
2632
  });
2414
2633
  await safeInstrumentation("printStepComplete(error)", () => {
2415
2634
  printStepComplete(stepName, durationMs2, "error", renderDepth);
@@ -2435,7 +2654,8 @@ async function stepImpl(name, fn, options) {
2435
2654
  endTime,
2436
2655
  durationMs
2437
2656
  };
2438
- await writeTraceEvent(completed, context.traceDir);
2657
+ const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
2658
+ await writeTraceEvent(safe, context.traceDir);
2439
2659
  });
2440
2660
  await safeInstrumentation("printStepComplete(success)", () => {
2441
2661
  printStepComplete(stepName, durationMs, "success", renderDepth);