@browserbasehq/stagehand 1.2.0 → 1.3.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/dist/index.js CHANGED
@@ -604,13 +604,15 @@ var OpenAIClient = class {
604
604
  return __async(this, null, function* () {
605
605
  const _a = options, { image: _ } = _a, optionsWithoutImage = __objRest(_a, ["image"]);
606
606
  this.logger({
607
- category: "OpenAI",
608
- message: `Creating chat completion with options: ${JSON.stringify(
609
- optionsWithoutImage,
610
- null,
611
- 2
612
- )}`,
613
- level: 1
607
+ category: "openai",
608
+ message: "creating chat completion",
609
+ level: 1,
610
+ auxiliary: {
611
+ options: {
612
+ value: JSON.stringify(optionsWithoutImage),
613
+ type: "object"
614
+ }
615
+ }
614
616
  });
615
617
  const cacheOptions = {
616
618
  model: options.model,
@@ -627,15 +629,31 @@ var OpenAIClient = class {
627
629
  if (cachedResponse) {
628
630
  this.logger({
629
631
  category: "llm_cache",
630
- message: `LLM Cache hit - returning cached response`,
631
- level: 1
632
+ message: "LLM cache hit - returning cached response",
633
+ level: 1,
634
+ auxiliary: {
635
+ requestId: {
636
+ value: this.requestId,
637
+ type: "string"
638
+ },
639
+ cachedResponse: {
640
+ value: JSON.stringify(cachedResponse),
641
+ type: "object"
642
+ }
643
+ }
632
644
  });
633
645
  return cachedResponse;
634
646
  } else {
635
647
  this.logger({
636
648
  category: "llm_cache",
637
- message: `LLM Cache miss - no cached response found`,
638
- level: 1
649
+ message: "LLM cache miss - no cached response found",
650
+ level: 1,
651
+ auxiliary: {
652
+ requestId: {
653
+ value: this.requestId,
654
+ type: "string"
655
+ }
656
+ }
639
657
  });
640
658
  }
641
659
  }
@@ -666,9 +684,19 @@ var OpenAIClient = class {
666
684
  response_format: responseFormat
667
685
  }));
668
686
  this.logger({
669
- category: "OpenAI",
670
- message: `Response: ${JSON.stringify(response, null, 2)}`,
671
- level: 1
687
+ category: "openai",
688
+ message: "response",
689
+ level: 1,
690
+ auxiliary: {
691
+ response: {
692
+ value: JSON.stringify(response),
693
+ type: "object"
694
+ },
695
+ requestId: {
696
+ value: this.requestId,
697
+ type: "string"
698
+ }
699
+ }
672
700
  });
673
701
  if (response_model) {
674
702
  const extractedData = response.choices[0].message.content;
@@ -683,6 +711,25 @@ var OpenAIClient = class {
683
711
  return __spreadValues({}, parsedData);
684
712
  }
685
713
  if (this.enableCaching) {
714
+ this.logger({
715
+ category: "llm_cache",
716
+ message: "caching response",
717
+ level: 1,
718
+ auxiliary: {
719
+ requestId: {
720
+ value: this.requestId,
721
+ type: "string"
722
+ },
723
+ cacheOptions: {
724
+ value: JSON.stringify(cacheOptions),
725
+ type: "object"
726
+ },
727
+ response: {
728
+ value: JSON.stringify(response),
729
+ type: "object"
730
+ }
731
+ }
732
+ });
686
733
  this.cache.set(cacheOptions, response, this.requestId);
687
734
  }
688
735
  return response;
@@ -708,13 +755,15 @@ var AnthropicClient = class {
708
755
  var _b, _c, _d, _e, _f, _g, _h;
709
756
  const _a = options, { image: _ } = _a, optionsWithoutImage = __objRest(_a, ["image"]);
710
757
  this.logger({
711
- category: "Anthropic",
712
- message: `Creating chat completion with options: ${JSON.stringify(
713
- optionsWithoutImage,
714
- null,
715
- 2
716
- )}`,
717
- level: 1
758
+ category: "anthropic",
759
+ message: "creating chat completion",
760
+ level: 1,
761
+ auxiliary: {
762
+ options: {
763
+ value: JSON.stringify(optionsWithoutImage),
764
+ type: "object"
765
+ }
766
+ }
718
767
  });
719
768
  const cacheOptions = {
720
769
  model: options.model,
@@ -730,15 +779,39 @@ var AnthropicClient = class {
730
779
  if (cachedResponse) {
731
780
  this.logger({
732
781
  category: "llm_cache",
733
- message: `LLM Cache hit - returning cached response`,
734
- level: 1
782
+ message: "LLM cache hit - returning cached response",
783
+ level: 1,
784
+ auxiliary: {
785
+ cachedResponse: {
786
+ value: JSON.stringify(cachedResponse),
787
+ type: "object"
788
+ },
789
+ requestId: {
790
+ value: this.requestId,
791
+ type: "string"
792
+ },
793
+ cacheOptions: {
794
+ value: JSON.stringify(cacheOptions),
795
+ type: "object"
796
+ }
797
+ }
735
798
  });
736
799
  return cachedResponse;
737
800
  } else {
738
801
  this.logger({
739
802
  category: "llm_cache",
740
- message: `LLM Cache miss - no cached response found`,
741
- level: 1
803
+ message: "LLM cache miss - no cached response found",
804
+ level: 1,
805
+ auxiliary: {
806
+ cacheOptions: {
807
+ value: JSON.stringify(cacheOptions),
808
+ type: "object"
809
+ },
810
+ requestId: {
811
+ value: this.requestId,
812
+ type: "string"
813
+ }
814
+ }
742
815
  });
743
816
  }
744
817
  }
@@ -808,9 +881,19 @@ var AnthropicClient = class {
808
881
  temperature: options.temperature
809
882
  });
810
883
  this.logger({
811
- category: "Anthropic",
812
- message: `Response: ${JSON.stringify(response, null, 2)}`,
813
- level: 1
884
+ category: "anthropic",
885
+ message: "response",
886
+ level: 1,
887
+ auxiliary: {
888
+ response: {
889
+ value: JSON.stringify(response),
890
+ type: "object"
891
+ },
892
+ requestId: {
893
+ value: this.requestId,
894
+ type: "string"
895
+ }
896
+ }
814
897
  });
815
898
  const transformedResponse = {
816
899
  id: response.id,
@@ -842,8 +925,19 @@ var AnthropicClient = class {
842
925
  }
843
926
  };
844
927
  this.logger({
845
- category: "Anthropic",
846
- message: "Transformed response: " + JSON.stringify(transformedResponse)
928
+ category: "anthropic",
929
+ message: "transformed response",
930
+ level: 1,
931
+ auxiliary: {
932
+ transformedResponse: {
933
+ value: JSON.stringify(transformedResponse),
934
+ type: "object"
935
+ },
936
+ requestId: {
937
+ value: this.requestId,
938
+ type: "string"
939
+ }
940
+ }
847
941
  });
848
942
  if (options.response_model) {
849
943
  const toolUse = response.content.find((c) => c.type === "tool_use");
@@ -859,6 +953,17 @@ var AnthropicClient = class {
859
953
  retries: ((_h = options.retries) != null ? _h : 0) + 1
860
954
  }));
861
955
  }
956
+ this.logger({
957
+ category: "anthropic",
958
+ message: "error creating chat completion",
959
+ level: 1,
960
+ auxiliary: {
961
+ requestId: {
962
+ value: this.requestId,
963
+ type: "string"
964
+ }
965
+ }
966
+ });
862
967
  throw new Error(
863
968
  "Create Chat Completion Failed: No tool use with input in response"
864
969
  );
@@ -866,6 +971,25 @@ var AnthropicClient = class {
866
971
  }
867
972
  if (this.enableCaching) {
868
973
  this.cache.set(cacheOptions, transformedResponse, this.requestId);
974
+ this.logger({
975
+ category: "anthropic",
976
+ message: "cached response",
977
+ level: 1,
978
+ auxiliary: {
979
+ requestId: {
980
+ value: this.requestId,
981
+ type: "string"
982
+ },
983
+ transformedResponse: {
984
+ value: JSON.stringify(transformedResponse),
985
+ type: "object"
986
+ },
987
+ cacheOptions: {
988
+ value: JSON.stringify(cacheOptions),
989
+ type: "object"
990
+ }
991
+ }
992
+ });
869
993
  }
870
994
  return transformedResponse;
871
995
  });
@@ -904,8 +1028,18 @@ var BaseCache = class {
904
1028
  process.on("uncaughtException", (err) => {
905
1029
  this.logger({
906
1030
  category: "base_cache",
907
- message: `Uncaught exception: ${err}`,
908
- level: 2
1031
+ message: "uncaught exception",
1032
+ level: 2,
1033
+ auxiliary: {
1034
+ error: {
1035
+ value: err.message,
1036
+ type: "string"
1037
+ },
1038
+ trace: {
1039
+ value: err.stack,
1040
+ type: "string"
1041
+ }
1042
+ }
909
1043
  });
910
1044
  if (this.lockAcquired) {
911
1045
  releaseLockAndExit();
@@ -917,8 +1051,14 @@ var BaseCache = class {
917
1051
  fs.mkdirSync(this.cacheDir, { recursive: true });
918
1052
  this.logger({
919
1053
  category: "base_cache",
920
- message: `Created cache directory at ${this.cacheDir}`,
921
- level: 1
1054
+ message: "created cache directory",
1055
+ level: 1,
1056
+ auxiliary: {
1057
+ cacheDir: {
1058
+ value: this.cacheDir,
1059
+ type: "string"
1060
+ }
1061
+ }
922
1062
  });
923
1063
  }
924
1064
  }
@@ -989,8 +1129,18 @@ var BaseCache = class {
989
1129
  } catch (error) {
990
1130
  this.logger({
991
1131
  category: "base_cache",
992
- message: `Error releasing lock: ${error}`,
993
- level: 2
1132
+ message: "error releasing lock",
1133
+ level: 2,
1134
+ auxiliary: {
1135
+ error: {
1136
+ value: error.message,
1137
+ type: "string"
1138
+ },
1139
+ trace: {
1140
+ value: error.stack,
1141
+ type: "string"
1142
+ }
1143
+ }
994
1144
  });
995
1145
  }
996
1146
  }
@@ -1002,7 +1152,7 @@ var BaseCache = class {
1002
1152
  if (!(yield this.acquireLock())) {
1003
1153
  this.logger({
1004
1154
  category: "llm_cache",
1005
- message: "Failed to acquire lock for cleanup",
1155
+ message: "failed to acquire lock for cleanup",
1006
1156
  level: 2
1007
1157
  });
1008
1158
  return;
@@ -1021,15 +1171,31 @@ var BaseCache = class {
1021
1171
  this.writeCache(cache);
1022
1172
  this.logger({
1023
1173
  category: "llm_cache",
1024
- message: `Cleaned up ${entriesRemoved} stale cache entries`,
1025
- level: 1
1174
+ message: "cleaned up stale cache entries",
1175
+ level: 1,
1176
+ auxiliary: {
1177
+ entriesRemoved: {
1178
+ value: entriesRemoved.toString(),
1179
+ type: "integer"
1180
+ }
1181
+ }
1026
1182
  });
1027
1183
  }
1028
1184
  } catch (error) {
1029
1185
  this.logger({
1030
1186
  category: "llm_cache",
1031
- message: `Error during cache cleanup: ${error}`,
1032
- level: 2
1187
+ message: "error during cache cleanup",
1188
+ level: 2,
1189
+ auxiliary: {
1190
+ error: {
1191
+ value: error.message,
1192
+ type: "string"
1193
+ },
1194
+ trace: {
1195
+ value: error.stack,
1196
+ type: "string"
1197
+ }
1198
+ }
1033
1199
  });
1034
1200
  } finally {
1035
1201
  this.releaseLock();
@@ -1044,8 +1210,18 @@ var BaseCache = class {
1044
1210
  } catch (error) {
1045
1211
  this.logger({
1046
1212
  category: "base_cache",
1047
- message: `Error reading cache file: ${error}. Resetting cache.`,
1048
- level: 1
1213
+ message: "error reading cache file. resetting cache.",
1214
+ level: 1,
1215
+ auxiliary: {
1216
+ error: {
1217
+ value: error.message,
1218
+ type: "string"
1219
+ },
1220
+ trace: {
1221
+ value: error.stack,
1222
+ type: "string"
1223
+ }
1224
+ }
1049
1225
  });
1050
1226
  this.resetCache();
1051
1227
  return {};
@@ -1064,8 +1240,18 @@ var BaseCache = class {
1064
1240
  } catch (error) {
1065
1241
  this.logger({
1066
1242
  category: "base_cache",
1067
- message: `Error writing cache file: ${error}`,
1068
- level: 2
1243
+ message: "error writing cache file",
1244
+ level: 2,
1245
+ auxiliary: {
1246
+ error: {
1247
+ value: error.message,
1248
+ type: "string"
1249
+ },
1250
+ trace: {
1251
+ value: error.stack,
1252
+ type: "string"
1253
+ }
1254
+ }
1069
1255
  });
1070
1256
  } finally {
1071
1257
  this.releaseLock();
@@ -1098,8 +1284,18 @@ var BaseCache = class {
1098
1284
  } catch (error) {
1099
1285
  this.logger({
1100
1286
  category: "base_cache",
1101
- message: `Error getting cache: ${error}. Resetting cache.`,
1102
- level: 1
1287
+ message: "error getting cache. resetting cache.",
1288
+ level: 1,
1289
+ auxiliary: {
1290
+ error: {
1291
+ value: error.message,
1292
+ type: "string"
1293
+ },
1294
+ trace: {
1295
+ value: error.stack,
1296
+ type: "string"
1297
+ }
1298
+ }
1103
1299
  });
1104
1300
  this.resetCache();
1105
1301
  return null;
@@ -1137,8 +1333,18 @@ var BaseCache = class {
1137
1333
  } catch (error) {
1138
1334
  this.logger({
1139
1335
  category: "base_cache",
1140
- message: `Error setting cache: ${error}. Resetting cache.`,
1141
- level: 1
1336
+ message: "error setting cache. resetting cache.",
1337
+ level: 1,
1338
+ auxiliary: {
1339
+ error: {
1340
+ value: error.message,
1341
+ type: "string"
1342
+ },
1343
+ trace: {
1344
+ value: error.stack,
1345
+ type: "string"
1346
+ }
1347
+ }
1142
1348
  });
1143
1349
  this.resetCache();
1144
1350
  } finally {
@@ -1175,8 +1381,18 @@ var BaseCache = class {
1175
1381
  } catch (error) {
1176
1382
  this.logger({
1177
1383
  category: "base_cache",
1178
- message: `Error removing cache entry: ${error}`,
1179
- level: 2
1384
+ message: "error removing cache entry",
1385
+ level: 2,
1386
+ auxiliary: {
1387
+ error: {
1388
+ value: error.message,
1389
+ type: "string"
1390
+ },
1391
+ trace: {
1392
+ value: error.stack,
1393
+ type: "string"
1394
+ }
1395
+ }
1180
1396
  });
1181
1397
  } finally {
1182
1398
  this.releaseLock();
@@ -1223,16 +1439,36 @@ var BaseCache = class {
1223
1439
  } else {
1224
1440
  this.logger({
1225
1441
  category: "base_cache",
1226
- message: `No cache entries found for requestId ${requestId}`,
1227
- level: 1
1442
+ message: "no cache entries found for requestId",
1443
+ level: 1,
1444
+ auxiliary: {
1445
+ requestId: {
1446
+ value: requestId,
1447
+ type: "string"
1448
+ }
1449
+ }
1228
1450
  });
1229
1451
  }
1230
1452
  delete this.requestIdToUsedHashes[requestId];
1231
1453
  } catch (error) {
1232
1454
  this.logger({
1233
1455
  category: "base_cache",
1234
- message: `Error deleting cache for requestId ${requestId}: ${error}`,
1235
- level: 2
1456
+ message: "error deleting cache for requestId",
1457
+ level: 2,
1458
+ auxiliary: {
1459
+ error: {
1460
+ value: error.message,
1461
+ type: "string"
1462
+ },
1463
+ trace: {
1464
+ value: error.stack,
1465
+ type: "string"
1466
+ },
1467
+ requestId: {
1468
+ value: requestId,
1469
+ type: "string"
1470
+ }
1471
+ }
1236
1472
  });
1237
1473
  } finally {
1238
1474
  this.releaseLock();
@@ -1249,8 +1485,18 @@ var BaseCache = class {
1249
1485
  } catch (error) {
1250
1486
  this.logger({
1251
1487
  category: "base_cache",
1252
- message: `Error resetting cache: ${error}`,
1253
- level: 2
1488
+ message: "error resetting cache",
1489
+ level: 2,
1490
+ auxiliary: {
1491
+ error: {
1492
+ value: error.message,
1493
+ type: "string"
1494
+ },
1495
+ trace: {
1496
+ value: error.stack,
1497
+ type: "string"
1498
+ }
1499
+ }
1254
1500
  });
1255
1501
  } finally {
1256
1502
  this.releaseLock();
@@ -1306,12 +1552,22 @@ var LLMProvider = class {
1306
1552
  };
1307
1553
  this.logger = logger;
1308
1554
  this.enableCaching = enableCaching;
1309
- this.cache = new LLMCache(logger);
1555
+ this.cache = enableCaching ? new LLMCache(logger) : void 0;
1310
1556
  }
1311
1557
  cleanRequestCache(requestId) {
1558
+ if (!this.enableCaching) {
1559
+ return;
1560
+ }
1312
1561
  this.logger({
1313
1562
  category: "llm_cache",
1314
- message: `Cleaning up cache for requestId: ${requestId}`
1563
+ message: "cleaning up cache",
1564
+ level: 1,
1565
+ auxiliary: {
1566
+ requestId: {
1567
+ value: requestId,
1568
+ type: "string"
1569
+ }
1570
+ }
1315
1571
  });
1316
1572
  this.cache.deleteCacheForRequestId(requestId);
1317
1573
  }
@@ -1341,31 +1597,45 @@ var LLMProvider = class {
1341
1597
  }
1342
1598
  };
1343
1599
 
1344
- // lib/index.ts
1345
- var import_path2 = __toESM(require("path"));
1346
-
1347
1600
  // lib/vision.ts
1348
1601
  var import_fs = __toESM(require("fs"));
1349
1602
  var import_path = __toESM(require("path"));
1350
1603
  var import_sharp = __toESM(require("sharp"));
1351
1604
  var import_child_process = require("child_process");
1352
- var ScreenshotService = class _ScreenshotService {
1353
- constructor(page, selectorMap, verbose, isDebugEnabled = false) {
1605
+
1606
+ // lib/utils.ts
1607
+ var import_crypto = __toESM(require("crypto"));
1608
+ function generateId(operation) {
1609
+ return import_crypto.default.createHash("sha256").update(operation).digest("hex");
1610
+ }
1611
+ function logLineToString(logLine) {
1612
+ var _a;
1613
+ const timestamp = logLine.timestamp || (/* @__PURE__ */ new Date()).toISOString();
1614
+ if ((_a = logLine.auxiliary) == null ? void 0 : _a.error) {
1615
+ return `${timestamp}::[stagehand:${logLine.category}] ${logLine.message}
1616
+ ${logLine.auxiliary.error.value}
1617
+ ${logLine.auxiliary.trace.value}`;
1618
+ }
1619
+ return `${timestamp}::[stagehand:${logLine.category}] ${logLine.message} ${logLine.auxiliary ? JSON.stringify(logLine.auxiliary) : ""}`;
1620
+ }
1621
+
1622
+ // lib/vision.ts
1623
+ var ScreenshotService = class {
1624
+ constructor(page, selectorMap, verbose, externalLogger, isDebugEnabled = false) {
1354
1625
  this.annotationBoxes = [];
1355
1626
  this.numberPositions = [];
1356
1627
  this.page = page;
1357
1628
  this.selectorMap = selectorMap;
1358
1629
  this.isDebugEnabled = isDebugEnabled;
1359
1630
  this.verbose = verbose;
1631
+ this.externalLogger = externalLogger;
1360
1632
  }
1361
- log({
1362
- category,
1363
- message,
1364
- level = 1
1365
- }) {
1366
- if (this.verbose >= level) {
1367
- const categoryString = category ? `:${category}` : "";
1368
- console.log(`[stagehand${categoryString}] ${message}`);
1633
+ log(logLine) {
1634
+ if (this.verbose >= logLine.level) {
1635
+ console.log(logLineToString(logLine));
1636
+ }
1637
+ if (this.externalLogger) {
1638
+ this.externalLogger(logLine);
1369
1639
  }
1370
1640
  }
1371
1641
  getScreenshot(fullpage = true, quality) {
@@ -1382,21 +1652,40 @@ var ScreenshotService = class _ScreenshotService {
1382
1652
  }
1383
1653
  getScreenshotPixelCount(screenshot) {
1384
1654
  return __async(this, null, function* () {
1655
+ var _a, _b, _c, _d;
1385
1656
  const image = (0, import_sharp.default)(screenshot);
1386
1657
  const metadata = yield image.metadata();
1387
1658
  if (!metadata.width || !metadata.height) {
1388
1659
  this.log({
1389
- category: "Error",
1660
+ category: "screenshotService",
1390
1661
  message: "Unable to determine image dimensions.",
1391
- level: 0
1662
+ level: 0,
1663
+ auxiliary: {
1664
+ width: {
1665
+ value: (_b = (_a = metadata.width) == null ? void 0 : _a.toString()) != null ? _b : "undefined",
1666
+ type: "string"
1667
+ // might be undefined
1668
+ },
1669
+ height: {
1670
+ value: (_d = (_c = metadata.height) == null ? void 0 : _c.toString()) != null ? _d : "undefined",
1671
+ type: "string"
1672
+ // might be undefined
1673
+ }
1674
+ }
1392
1675
  });
1393
1676
  throw new Error("Unable to determine image dimensions.");
1394
1677
  }
1395
1678
  const pixelCount = metadata.width * metadata.height;
1396
1679
  this.log({
1397
- category: "Info",
1398
- message: `Screenshot pixel count: ${pixelCount}`,
1399
- level: 1
1680
+ category: "screenshotService",
1681
+ message: "got screenshot pixel count",
1682
+ level: 1,
1683
+ auxiliary: {
1684
+ pixelCount: {
1685
+ value: pixelCount.toString(),
1686
+ type: "integer"
1687
+ }
1688
+ }
1400
1689
  });
1401
1690
  return pixelCount;
1402
1691
  });
@@ -1408,6 +1697,17 @@ var ScreenshotService = class _ScreenshotService {
1408
1697
  const screenshot = yield this.getScreenshot(fullpage);
1409
1698
  const image = (0, import_sharp.default)(screenshot);
1410
1699
  const { width, height } = yield image.metadata();
1700
+ this.log({
1701
+ category: "screenshotService",
1702
+ message: "annotating screenshot",
1703
+ level: 2,
1704
+ auxiliary: {
1705
+ selectorMap: {
1706
+ value: JSON.stringify(this.selectorMap),
1707
+ type: "object"
1708
+ }
1709
+ }
1710
+ });
1411
1711
  const svgAnnotations = yield Promise.all(
1412
1712
  Object.entries(this.selectorMap).map(
1413
1713
  (_0) => __async(this, [_0], function* ([id, selectors]) {
@@ -1428,7 +1728,7 @@ var ScreenshotService = class _ScreenshotService {
1428
1728
  `;
1429
1729
  const annotatedScreenshot = yield image.composite([{ input: Buffer.from(svg), top: 0, left: 0 }]).toBuffer();
1430
1730
  if (this.isDebugEnabled) {
1431
- yield _ScreenshotService.saveAndOpenScreenshot(annotatedScreenshot);
1731
+ yield this.saveAndOpenScreenshot(annotatedScreenshot);
1432
1732
  }
1433
1733
  return annotatedScreenshot;
1434
1734
  });
@@ -1478,9 +1778,23 @@ var ScreenshotService = class _ScreenshotService {
1478
1778
  `;
1479
1779
  } catch (error) {
1480
1780
  this.log({
1481
- category: "Vision",
1482
- message: `Warning: Failed to create annotation for element ${id}: ${error}, trace: ${error.stack}`,
1483
- level: 0
1781
+ category: "screenshotService",
1782
+ message: "warning: failed to create annotation for element",
1783
+ level: 1,
1784
+ auxiliary: {
1785
+ element_id: {
1786
+ value: id,
1787
+ type: "string"
1788
+ },
1789
+ error: {
1790
+ value: error.message,
1791
+ type: "string"
1792
+ },
1793
+ trace: {
1794
+ value: error.stack,
1795
+ type: "string"
1796
+ }
1797
+ }
1484
1798
  });
1485
1799
  return "";
1486
1800
  }
@@ -1510,7 +1824,7 @@ var ScreenshotService = class _ScreenshotService {
1510
1824
  ) < circleRadius * 2
1511
1825
  );
1512
1826
  }
1513
- static saveAndOpenScreenshot(screenshot) {
1827
+ saveAndOpenScreenshot(screenshot) {
1514
1828
  return __async(this, null, function* () {
1515
1829
  const screenshotDir = import_path.default.join(process.cwd(), "screenshots");
1516
1830
  if (!import_fs.default.existsSync(screenshotDir)) {
@@ -1519,7 +1833,17 @@ var ScreenshotService = class _ScreenshotService {
1519
1833
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1520
1834
  const filename = import_path.default.join(screenshotDir, `screenshot-${timestamp}.png`);
1521
1835
  import_fs.default.writeFileSync(filename, screenshot);
1522
- console.log(`Screenshot saved to: ${filename}`);
1836
+ this.log({
1837
+ category: "screenshotService",
1838
+ message: "screenshot saved",
1839
+ level: 1,
1840
+ auxiliary: {
1841
+ filename: {
1842
+ value: filename,
1843
+ type: "string"
1844
+ }
1845
+ }
1846
+ });
1523
1847
  if (process.platform === "win32") {
1524
1848
  (0, import_child_process.exec)(`start ${filename}`);
1525
1849
  } else if (process.platform === "darwin") {
@@ -1564,8 +1888,26 @@ var ActionCache = class _ActionCache extends BaseCache {
1564
1888
  }) {
1565
1889
  this.logger({
1566
1890
  category: "action_cache",
1567
- message: `Adding action step to cache: ${action}, requestId: ${requestId}, url: ${url}, previousSelectors: ${previousSelectors}`,
1568
- level: 1
1891
+ message: "adding action step to cache",
1892
+ level: 1,
1893
+ auxiliary: {
1894
+ action: {
1895
+ value: action,
1896
+ type: "string"
1897
+ },
1898
+ requestId: {
1899
+ value: requestId,
1900
+ type: "string"
1901
+ },
1902
+ url: {
1903
+ value: url,
1904
+ type: "string"
1905
+ },
1906
+ previousSelectors: {
1907
+ value: JSON.stringify(previousSelectors),
1908
+ type: "object"
1909
+ }
1910
+ }
1569
1911
  });
1570
1912
  yield this.set(
1571
1913
  { url, action, previousSelectors },
@@ -1617,8 +1959,14 @@ var ActionCache = class _ActionCache extends BaseCache {
1617
1959
  yield __superGet(_ActionCache.prototype, this, "deleteCacheForRequestId").call(this, requestId);
1618
1960
  this.logger({
1619
1961
  category: "action_cache",
1620
- message: `Cleared action for ID: ${requestId}`,
1621
- level: 1
1962
+ message: "cleared action for ID",
1963
+ level: 1,
1964
+ auxiliary: {
1965
+ requestId: {
1966
+ value: requestId,
1967
+ type: "string"
1968
+ }
1969
+ }
1622
1970
  });
1623
1971
  });
1624
1972
  }
@@ -1637,12 +1985,6 @@ var ActionCache = class _ActionCache extends BaseCache {
1637
1985
  }
1638
1986
  };
1639
1987
 
1640
- // lib/utils.ts
1641
- var import_crypto = __toESM(require("crypto"));
1642
- function generateId(operation) {
1643
- return import_crypto.default.createHash("sha256").update(operation).digest("hex");
1644
- }
1645
-
1646
1988
  // lib/handlers/actHandler.ts
1647
1989
  var StagehandActHandler = class {
1648
1990
  constructor({
@@ -1662,7 +2004,7 @@ var StagehandActHandler = class {
1662
2004
  this.enableCaching = enableCaching;
1663
2005
  this.logger = logger;
1664
2006
  this.waitForSettledDom = waitForSettledDom;
1665
- this.actionCache = new ActionCache(this.logger);
2007
+ this.actionCache = enableCaching ? new ActionCache(this.logger) : void 0;
1666
2008
  this.defaultModelName = defaultModelName;
1667
2009
  this.startDomDebug = startDomDebug;
1668
2010
  this.cleanupDomDebug = cleanupDomDebug;
@@ -1693,8 +2035,14 @@ var StagehandActHandler = class {
1693
2035
  if (completed) {
1694
2036
  this.stagehand.log({
1695
2037
  category: "action",
1696
- message: `Action marked as completed, Verifying if this is true...`,
1697
- level: 1
2038
+ message: "action marked as completed, verifying if this is true...",
2039
+ level: 1,
2040
+ auxiliary: {
2041
+ action: {
2042
+ value: action,
2043
+ type: "string"
2044
+ }
2045
+ }
1698
2046
  });
1699
2047
  let domElements = void 0;
1700
2048
  let fullpageScreenshot = void 0;
@@ -1703,20 +2051,31 @@ var StagehandActHandler = class {
1703
2051
  const screenshotService = new ScreenshotService(
1704
2052
  this.stagehand.page,
1705
2053
  selectorMap,
1706
- this.verbose
2054
+ this.verbose,
2055
+ this.logger
1707
2056
  );
1708
2057
  fullpageScreenshot = yield screenshotService.getScreenshot(true, 15);
1709
2058
  } catch (e) {
1710
2059
  this.stagehand.log({
1711
2060
  category: "action",
1712
- message: `Error getting full page screenshot: ${e.message}
1713
- . Trying again...`,
1714
- level: 1
2061
+ message: "error getting full page screenshot. trying again...",
2062
+ level: 1,
2063
+ auxiliary: {
2064
+ error: {
2065
+ value: e.message,
2066
+ type: "string"
2067
+ },
2068
+ trace: {
2069
+ value: e.stack,
2070
+ type: "string"
2071
+ }
2072
+ }
1715
2073
  });
1716
2074
  const screenshotService = new ScreenshotService(
1717
2075
  this.stagehand.page,
1718
2076
  selectorMap,
1719
- this.verbose
2077
+ this.verbose,
2078
+ this.logger
1720
2079
  );
1721
2080
  fullpageScreenshot = yield screenshotService.getScreenshot(true, 15);
1722
2081
  }
@@ -1739,8 +2098,18 @@ var StagehandActHandler = class {
1739
2098
  });
1740
2099
  this.stagehand.log({
1741
2100
  category: "action",
1742
- message: `Action completion verification result: ${actionCompleted}`,
1743
- level: 1
2101
+ message: "action completion verification result",
2102
+ level: 1,
2103
+ auxiliary: {
2104
+ action: {
2105
+ value: action,
2106
+ type: "string"
2107
+ },
2108
+ result: {
2109
+ value: actionCompleted.toString(),
2110
+ type: "boolean"
2111
+ }
2112
+ }
1744
2113
  });
1745
2114
  }
1746
2115
  return actionCompleted;
@@ -1748,13 +2117,20 @@ var StagehandActHandler = class {
1748
2117
  }
1749
2118
  _performPlaywrightMethod(method, args, xpath, domSettleTimeoutMs) {
1750
2119
  return __async(this, null, function* () {
2120
+ var _a, _b;
1751
2121
  const locator = this.stagehand.page.locator(`xpath=${xpath}`).first();
1752
2122
  const initialUrl = this.stagehand.page.url();
1753
2123
  if (method === "scrollIntoView") {
1754
2124
  this.stagehand.log({
1755
2125
  category: "action",
1756
- message: `Scrolling element into view`,
1757
- level: 2
2126
+ message: "scrolling element into view",
2127
+ level: 2,
2128
+ auxiliary: {
2129
+ xpath: {
2130
+ value: xpath,
2131
+ type: "string"
2132
+ }
2133
+ }
1758
2134
  });
1759
2135
  try {
1760
2136
  yield locator.evaluate((element) => {
@@ -1762,17 +2138,43 @@ var StagehandActHandler = class {
1762
2138
  }).catch((e) => {
1763
2139
  this.stagehand.log({
1764
2140
  category: "action",
1765
- message: `Error scrolling element into view: ${e.message}
1766
- Trace: ${e.stack}`,
1767
- level: 1
2141
+ message: "error scrolling element into view",
2142
+ level: 1,
2143
+ auxiliary: {
2144
+ error: {
2145
+ value: e.message,
2146
+ type: "string"
2147
+ },
2148
+ trace: {
2149
+ value: e.stack,
2150
+ type: "string"
2151
+ },
2152
+ xpath: {
2153
+ value: xpath,
2154
+ type: "string"
2155
+ }
2156
+ }
1768
2157
  });
1769
2158
  });
1770
2159
  } catch (e) {
1771
2160
  this.stagehand.log({
1772
2161
  category: "action",
1773
- message: `Error scrolling element into view: ${e.message}
1774
- Trace: ${e.stack}`,
1775
- level: 1
2162
+ message: "error scrolling element into view",
2163
+ level: 1,
2164
+ auxiliary: {
2165
+ error: {
2166
+ value: e.message,
2167
+ type: "string"
2168
+ },
2169
+ trace: {
2170
+ value: e.stack,
2171
+ type: "string"
2172
+ },
2173
+ xpath: {
2174
+ value: xpath,
2175
+ type: "string"
2176
+ }
2177
+ }
1776
2178
  });
1777
2179
  throw new PlaywrightCommandException(e.message);
1778
2180
  }
@@ -1789,9 +2191,22 @@ Trace: ${e.stack}`,
1789
2191
  } catch (e) {
1790
2192
  this.logger({
1791
2193
  category: "action",
1792
- message: `Error filling element: ${e.message}
1793
- Trace: ${e.stack}`,
1794
- level: 1
2194
+ message: "error filling element",
2195
+ level: 1,
2196
+ auxiliary: {
2197
+ error: {
2198
+ value: e.message,
2199
+ type: "string"
2200
+ },
2201
+ trace: {
2202
+ value: e.stack,
2203
+ type: "string"
2204
+ },
2205
+ xpath: {
2206
+ value: xpath,
2207
+ type: "string"
2208
+ }
2209
+ }
1795
2210
  });
1796
2211
  throw new PlaywrightCommandException(e.message);
1797
2212
  }
@@ -1802,36 +2217,80 @@ Trace: ${e.stack}`,
1802
2217
  } catch (e) {
1803
2218
  this.logger({
1804
2219
  category: "action",
1805
- message: `Error pressing key: ${e.message}
1806
- Trace: ${e.stack}`,
1807
- level: 1
2220
+ message: "error pressing key",
2221
+ level: 1,
2222
+ auxiliary: {
2223
+ error: {
2224
+ value: e.message,
2225
+ type: "string"
2226
+ },
2227
+ trace: {
2228
+ value: e.stack,
2229
+ type: "string"
2230
+ },
2231
+ key: {
2232
+ value: (_b = (_a = args[0]) == null ? void 0 : _a.toString()) != null ? _b : "unknown",
2233
+ type: "string"
2234
+ }
2235
+ }
1808
2236
  });
1809
2237
  throw new PlaywrightCommandException(e.message);
1810
2238
  }
1811
2239
  } else if (typeof locator[method] === "function") {
1812
2240
  this.logger({
1813
2241
  category: "action",
1814
- message: `Page URL before action: ${this.stagehand.page.url()}`,
1815
- level: 2
2242
+ message: "page URL before action",
2243
+ level: 2,
2244
+ auxiliary: {
2245
+ url: {
2246
+ value: this.stagehand.page.url(),
2247
+ type: "string"
2248
+ }
2249
+ }
1816
2250
  });
1817
2251
  try {
1818
2252
  yield locator[method](...args);
1819
2253
  } catch (e) {
1820
2254
  this.logger({
1821
2255
  category: "action",
1822
- message: `Error performing method ${method} with args ${JSON.stringify(
1823
- args
1824
- )}: ${e.message}
1825
- Trace: ${e.stack}`,
1826
- level: 1
2256
+ message: "error performing method",
2257
+ level: 1,
2258
+ auxiliary: {
2259
+ error: {
2260
+ value: e.message,
2261
+ type: "string"
2262
+ },
2263
+ trace: {
2264
+ value: e.stack,
2265
+ type: "string"
2266
+ },
2267
+ xpath: {
2268
+ value: xpath,
2269
+ type: "string"
2270
+ },
2271
+ method: {
2272
+ value: method,
2273
+ type: "string"
2274
+ },
2275
+ args: {
2276
+ value: JSON.stringify(args),
2277
+ type: "object"
2278
+ }
2279
+ }
1827
2280
  });
1828
2281
  throw new PlaywrightCommandException(e.message);
1829
2282
  }
1830
2283
  if (method === "click") {
1831
2284
  this.logger({
1832
2285
  category: "action",
1833
- message: `Clicking element, checking for page navigation`,
1834
- level: 1
2286
+ message: "clicking element, checking for page navigation",
2287
+ level: 1,
2288
+ auxiliary: {
2289
+ xpath: {
2290
+ value: xpath,
2291
+ type: "string"
2292
+ }
2293
+ }
1835
2294
  });
1836
2295
  const newOpenedTab = yield Promise.race([
1837
2296
  new Promise((resolve) => {
@@ -1841,14 +2300,26 @@ Trace: ${e.stack}`,
1841
2300
  ]);
1842
2301
  this.logger({
1843
2302
  category: "action",
1844
- message: `Clicked element, ${newOpenedTab ? "opened a new tab" : "no new tabs opened"}`,
1845
- level: 1
2303
+ message: "clicked element",
2304
+ level: 1,
2305
+ auxiliary: {
2306
+ newOpenedTab: {
2307
+ value: newOpenedTab ? "opened a new tab" : "no new tabs opened",
2308
+ type: "string"
2309
+ }
2310
+ }
1846
2311
  });
1847
2312
  if (newOpenedTab) {
1848
2313
  this.logger({
1849
2314
  category: "action",
1850
- message: `New page detected (new tab) with URL: ${newOpenedTab.url()}`,
1851
- level: 1
2315
+ message: "new page detected (new tab) with URL",
2316
+ level: 1,
2317
+ auxiliary: {
2318
+ url: {
2319
+ value: newOpenedTab.url(),
2320
+ type: "string"
2321
+ }
2322
+ }
1852
2323
  });
1853
2324
  yield newOpenedTab.close();
1854
2325
  yield this.stagehand.page.goto(newOpenedTab.url());
@@ -1861,28 +2332,40 @@ Trace: ${e.stack}`,
1861
2332
  ]).catch((e) => {
1862
2333
  this.logger({
1863
2334
  category: "action",
1864
- message: `Network idle timeout hit`,
2335
+ message: "network idle timeout hit",
1865
2336
  level: 1
1866
2337
  });
1867
2338
  });
1868
2339
  this.logger({
1869
2340
  category: "action",
1870
- message: `Finished waiting for (possible) page navigation`,
2341
+ message: "finished waiting for (possible) page navigation",
1871
2342
  level: 1
1872
2343
  });
1873
2344
  if (this.stagehand.page.url() !== initialUrl) {
1874
2345
  this.logger({
1875
2346
  category: "action",
1876
- message: `New page detected with URL: ${this.stagehand.page.url()}`,
1877
- level: 1
2347
+ message: "new page detected with URL",
2348
+ level: 1,
2349
+ auxiliary: {
2350
+ url: {
2351
+ value: this.stagehand.page.url(),
2352
+ type: "string"
2353
+ }
2354
+ }
1878
2355
  });
1879
2356
  }
1880
2357
  }
1881
2358
  } else {
1882
2359
  this.logger({
1883
2360
  category: "action",
1884
- message: `Chosen method ${method} is invalid`,
1885
- level: 1
2361
+ message: "chosen method is invalid",
2362
+ level: 1,
2363
+ auxiliary: {
2364
+ method: {
2365
+ value: method,
2366
+ type: "string"
2367
+ }
2368
+ }
1886
2369
  });
1887
2370
  throw new PlaywrightCommandMethodNotSupportedException(
1888
2371
  `Method ${method} not supported`
@@ -1924,8 +2407,18 @@ Trace: ${e.stack}`,
1924
2407
  } catch (e) {
1925
2408
  this.logger({
1926
2409
  category: "action",
1927
- message: `Element with XPath ${xpath} not found within ${timeout}ms.`,
1928
- level: 1
2410
+ message: "element not found within timeout",
2411
+ level: 1,
2412
+ auxiliary: {
2413
+ xpath: {
2414
+ value: xpath,
2415
+ type: "string"
2416
+ },
2417
+ timeout_ms: {
2418
+ value: timeout.toString(),
2419
+ type: "integer"
2420
+ }
2421
+ }
1929
2422
  });
1930
2423
  return null;
1931
2424
  }
@@ -1935,34 +2428,62 @@ Trace: ${e.stack}`,
1935
2428
  return __async(this, null, function* () {
1936
2429
  this.logger({
1937
2430
  category: "action",
1938
- message: `Checking if cached step is valid: ${cachedStep.xpath}, ${cachedStep.savedComponentString}`,
1939
- level: 1
2431
+ message: "checking if cached step is valid",
2432
+ level: 1,
2433
+ auxiliary: {
2434
+ xpath: {
2435
+ value: cachedStep.xpath,
2436
+ type: "string"
2437
+ },
2438
+ savedComponentString: {
2439
+ value: cachedStep.savedComponentString,
2440
+ type: "string"
2441
+ }
2442
+ }
1940
2443
  });
1941
2444
  try {
1942
2445
  const locator = yield this.getElement(cachedStep.xpath);
1943
2446
  if (!locator) {
1944
2447
  this.logger({
1945
2448
  category: "action",
1946
- message: `Locator not found for xpath: ${cachedStep.xpath}`,
1947
- level: 1
2449
+ message: "locator not found for xpath",
2450
+ level: 1,
2451
+ auxiliary: {
2452
+ xpath: {
2453
+ value: cachedStep.xpath,
2454
+ type: "string"
2455
+ }
2456
+ }
1948
2457
  });
1949
2458
  return false;
1950
2459
  }
1951
2460
  this.logger({
1952
2461
  category: "action",
1953
- message: `locator element: ${yield this._getComponentString(locator)}`,
1954
- level: 1
2462
+ message: "locator element",
2463
+ level: 1,
2464
+ auxiliary: {
2465
+ componentString: {
2466
+ value: yield this._getComponentString(locator),
2467
+ type: "string"
2468
+ }
2469
+ }
1955
2470
  });
1956
2471
  let currentComponent = yield this._getComponentString(locator);
1957
2472
  this.logger({
1958
2473
  category: "action",
1959
- message: `Current text: ${currentComponent}`,
1960
- level: 1
2474
+ message: "current text",
2475
+ level: 1,
2476
+ auxiliary: {
2477
+ componentString: {
2478
+ value: currentComponent,
2479
+ type: "string"
2480
+ }
2481
+ }
1961
2482
  });
1962
2483
  if (!currentComponent || !cachedStep.savedComponentString) {
1963
2484
  this.logger({
1964
2485
  category: "action",
1965
- message: `Current text or cached text is undefined`,
2486
+ message: "current text or cached text is undefined",
1966
2487
  level: 1
1967
2488
  });
1968
2489
  return false;
@@ -1972,8 +2493,18 @@ Trace: ${e.stack}`,
1972
2493
  if (normalizedCurrentText !== normalizedCachedText) {
1973
2494
  this.logger({
1974
2495
  category: "action",
1975
- message: `Current text and cached text do not match: ${normalizedCurrentText} !== ${normalizedCachedText}`,
1976
- level: 1
2496
+ message: "current text and cached text do not match",
2497
+ level: 1,
2498
+ auxiliary: {
2499
+ currentText: {
2500
+ value: normalizedCurrentText,
2501
+ type: "string"
2502
+ },
2503
+ cachedText: {
2504
+ value: normalizedCachedText,
2505
+ type: "string"
2506
+ }
2507
+ }
1977
2508
  });
1978
2509
  return false;
1979
2510
  }
@@ -1981,9 +2512,18 @@ Trace: ${e.stack}`,
1981
2512
  } catch (e) {
1982
2513
  this.logger({
1983
2514
  category: "action",
1984
- message: `Error checking if cached step is valid: ${e.message}
1985
- Trace: ${e.stack}`,
1986
- level: 1
2515
+ message: "error checking if cached step is valid",
2516
+ level: 1,
2517
+ auxiliary: {
2518
+ error: {
2519
+ value: e.message,
2520
+ type: "string"
2521
+ },
2522
+ trace: {
2523
+ value: e.stack,
2524
+ type: "string"
2525
+ }
2526
+ }
1987
2527
  });
1988
2528
  return false;
1989
2529
  }
@@ -2019,6 +2559,10 @@ Trace: ${e.stack}`,
2019
2559
  model,
2020
2560
  domSettleTimeoutMs
2021
2561
  }) {
2562
+ var _a, _b;
2563
+ if (!this.enableCaching) {
2564
+ return null;
2565
+ }
2022
2566
  const cacheObj = {
2023
2567
  url: this.stagehand.page.url(),
2024
2568
  action,
@@ -2027,24 +2571,40 @@ Trace: ${e.stack}`,
2027
2571
  };
2028
2572
  this.logger({
2029
2573
  category: "action",
2030
- message: `Checking action cache for: ${JSON.stringify(cacheObj)}`,
2031
- level: 1
2574
+ message: "checking action cache",
2575
+ level: 1,
2576
+ auxiliary: {
2577
+ cacheObj: {
2578
+ value: JSON.stringify(cacheObj),
2579
+ type: "object"
2580
+ }
2581
+ }
2032
2582
  });
2033
2583
  const cachedStep = yield this.actionCache.getActionStep(cacheObj);
2034
2584
  if (!cachedStep) {
2035
2585
  this.logger({
2036
2586
  category: "action",
2037
- message: `Action cache miss: ${JSON.stringify(cacheObj)}`,
2038
- level: 1
2587
+ message: "action cache miss",
2588
+ level: 1,
2589
+ auxiliary: {
2590
+ cacheObj: {
2591
+ value: JSON.stringify(cacheObj),
2592
+ type: "object"
2593
+ }
2594
+ }
2039
2595
  });
2040
2596
  return null;
2041
2597
  }
2042
2598
  this.logger({
2043
2599
  category: "action",
2044
- message: `Action cache semi-hit: ${cachedStep.playwrightCommand.method} with args: ${JSON.stringify(
2045
- cachedStep.playwrightCommand.args
2046
- )}`,
2047
- level: 1
2600
+ message: "action cache semi-hit",
2601
+ level: 1,
2602
+ auxiliary: {
2603
+ playwrightCommand: {
2604
+ value: JSON.stringify(cachedStep.playwrightCommand),
2605
+ type: "object"
2606
+ }
2607
+ }
2048
2608
  });
2049
2609
  try {
2050
2610
  const validXpath = yield this._getValidCachedStepXpath({
@@ -2053,24 +2613,40 @@ Trace: ${e.stack}`,
2053
2613
  });
2054
2614
  this.logger({
2055
2615
  category: "action",
2056
- message: `Cached action step is valid: ${validXpath !== null}`,
2057
- level: 1
2616
+ message: "cached action step is valid",
2617
+ level: 1,
2618
+ auxiliary: {
2619
+ validXpath: {
2620
+ value: validXpath,
2621
+ type: "string"
2622
+ }
2623
+ }
2058
2624
  });
2059
2625
  if (!validXpath) {
2060
2626
  this.logger({
2061
2627
  category: "action",
2062
- message: `Cached action step is invalid, removing...`,
2063
- level: 1
2628
+ message: "cached action step is invalid, removing...",
2629
+ level: 1,
2630
+ auxiliary: {
2631
+ cacheObj: {
2632
+ value: JSON.stringify(cacheObj),
2633
+ type: "object"
2634
+ }
2635
+ }
2064
2636
  });
2065
- yield this.actionCache.removeActionStep(cacheObj);
2637
+ yield (_a = this.actionCache) == null ? void 0 : _a.removeActionStep(cacheObj);
2066
2638
  return null;
2067
2639
  }
2068
2640
  this.logger({
2069
2641
  category: "action",
2070
- message: `Action Cache Hit: ${cachedStep.playwrightCommand.method} with args: ${JSON.stringify(
2071
- cachedStep.playwrightCommand.args
2072
- )}`,
2073
- level: 1
2642
+ message: "action cache hit",
2643
+ level: 1,
2644
+ auxiliary: {
2645
+ playwrightCommand: {
2646
+ value: JSON.stringify(cachedStep.playwrightCommand),
2647
+ type: "object"
2648
+ }
2649
+ }
2074
2650
  });
2075
2651
  cachedStep.playwrightCommand.args = cachedStep.playwrightCommand.args.map(
2076
2652
  (arg) => {
@@ -2102,13 +2678,19 @@ Trace: ${e.stack}`,
2102
2678
  });
2103
2679
  this.logger({
2104
2680
  category: "action",
2105
- message: `Action completion verification result from cache: ${actionCompleted}`,
2106
- level: 1
2681
+ message: "action completion verification result from cache",
2682
+ level: 1,
2683
+ auxiliary: {
2684
+ actionCompleted: {
2685
+ value: actionCompleted.toString(),
2686
+ type: "boolean"
2687
+ }
2688
+ }
2107
2689
  });
2108
2690
  if (actionCompleted) {
2109
2691
  return {
2110
2692
  success: true,
2111
- message: "Action completed successfully using cached step",
2693
+ message: "action completed successfully using cached step",
2112
2694
  action
2113
2695
  };
2114
2696
  }
@@ -2130,11 +2712,20 @@ Trace: ${e.stack}`,
2130
2712
  } catch (exception) {
2131
2713
  this.logger({
2132
2714
  category: "action",
2133
- message: `Error performing cached action step: ${exception.message}
2134
- Trace: ${exception.stack}`,
2135
- level: 1
2715
+ message: "error performing cached action step",
2716
+ level: 1,
2717
+ auxiliary: {
2718
+ error: {
2719
+ value: exception.message,
2720
+ type: "string"
2721
+ },
2722
+ trace: {
2723
+ value: exception.stack,
2724
+ type: "string"
2725
+ }
2726
+ }
2136
2727
  });
2137
- yield this.actionCache.removeActionStep(cacheObj);
2728
+ yield (_b = this.actionCache) == null ? void 0 : _b.removeActionStep(cacheObj);
2138
2729
  return null;
2139
2730
  }
2140
2731
  });
@@ -2154,7 +2745,7 @@ Trace: ${exception.stack}`,
2154
2745
  skipActionCacheForThisStep = false,
2155
2746
  domSettleTimeoutMs
2156
2747
  }) {
2157
- var _a;
2748
+ var _a, _b;
2158
2749
  try {
2159
2750
  yield this.waitForSettledDom(domSettleTimeoutMs);
2160
2751
  yield this.startDomDebug();
@@ -2196,20 +2787,40 @@ Trace: ${exception.stack}`,
2196
2787
  if (!modelsWithVision.includes(model) && (useVision !== false || verifierUseVision)) {
2197
2788
  this.logger({
2198
2789
  category: "action",
2199
- message: `${model} does not support vision, but useVision was set to ${useVision}. Defaulting to false.`,
2200
- level: 1
2790
+ message: "model does not support vision but useVision was not false. defaulting to false.",
2791
+ level: 1,
2792
+ auxiliary: {
2793
+ model: {
2794
+ value: model,
2795
+ type: "string"
2796
+ },
2797
+ useVision: {
2798
+ value: useVision.toString(),
2799
+ type: "boolean"
2800
+ }
2801
+ }
2201
2802
  });
2202
2803
  useVision = false;
2203
2804
  verifierUseVision = false;
2204
2805
  }
2205
2806
  this.logger({
2206
2807
  category: "action",
2207
- message: `Running / Continuing action: ${action} on page: ${this.stagehand.page.url()}`,
2208
- level: 2
2808
+ message: "running / continuing action",
2809
+ level: 2,
2810
+ auxiliary: {
2811
+ action: {
2812
+ value: action,
2813
+ type: "string"
2814
+ },
2815
+ pageUrl: {
2816
+ value: this.stagehand.page.url(),
2817
+ type: "string"
2818
+ }
2819
+ }
2209
2820
  });
2210
2821
  this.logger({
2211
2822
  category: "action",
2212
- message: `Processing DOM...`,
2823
+ message: "processing DOM",
2213
2824
  level: 2
2214
2825
  });
2215
2826
  const { outputString, selectorMap, chunk, chunks } = yield this.stagehand.page.evaluate(
@@ -2220,22 +2831,47 @@ Trace: ${exception.stack}`,
2220
2831
  );
2221
2832
  this.logger({
2222
2833
  category: "action",
2223
- message: `Looking at chunk ${chunk}. Chunks left: ${chunks.length - chunksSeen.length}`,
2224
- level: 1
2834
+ message: "looking at chunk",
2835
+ level: 1,
2836
+ auxiliary: {
2837
+ chunk: {
2838
+ value: chunk.toString(),
2839
+ type: "integer"
2840
+ },
2841
+ chunks: {
2842
+ value: chunks.length.toString(),
2843
+ type: "integer"
2844
+ },
2845
+ chunksSeen: {
2846
+ value: chunksSeen.length.toString(),
2847
+ type: "integer"
2848
+ },
2849
+ chunksLeft: {
2850
+ value: (chunks.length - chunksSeen.length).toString(),
2851
+ type: "integer"
2852
+ }
2853
+ }
2225
2854
  });
2226
2855
  let annotatedScreenshot;
2227
2856
  if (useVision === true) {
2228
2857
  if (!modelsWithVision.includes(model)) {
2229
2858
  this.logger({
2230
2859
  category: "action",
2231
- message: `${model} does not support vision. Skipping vision processing.`,
2232
- level: 1
2860
+ message: "model does not support vision. skipping vision processing.",
2861
+ level: 1,
2862
+ auxiliary: {
2863
+ model: {
2864
+ value: model,
2865
+ type: "string"
2866
+ }
2867
+ }
2233
2868
  });
2234
2869
  } else {
2235
2870
  const screenshotService = new ScreenshotService(
2236
2871
  this.stagehand.page,
2237
2872
  selectorMap,
2238
- this.verbose
2873
+ this.verbose,
2874
+ this.logger
2239
2875
  );
2240
2876
  annotatedScreenshot = yield screenshotService.getAnnotatedScreenshot(false);
2241
2877
  }
@@ -2253,8 +2889,14 @@ Trace: ${exception.stack}`,
2253
2889
  });
2254
2890
  this.logger({
2255
2891
  category: "action",
2256
- message: `Received response from LLM: ${JSON.stringify(response)}`,
2257
- level: 1
2892
+ message: "received response from LLM",
2893
+ level: 1,
2894
+ auxiliary: {
2895
+ response: {
2896
+ value: JSON.stringify(response),
2897
+ type: "object"
2898
+ }
2899
+ }
2258
2900
  });
2259
2901
  yield this.cleanupDomDebug();
2260
2902
  if (!response) {
@@ -2262,8 +2904,14 @@ Trace: ${exception.stack}`,
2262
2904
  chunksSeen.push(chunk);
2263
2905
  this.logger({
2264
2906
  category: "action",
2265
- message: `No action found in current chunk. Chunks seen: ${chunksSeen.length}.`,
2266
- level: 1
2907
+ message: "no action found in current chunk",
2908
+ level: 1,
2909
+ auxiliary: {
2910
+ chunksSeen: {
2911
+ value: chunksSeen.length.toString(),
2912
+ type: "integer"
2913
+ }
2914
+ }
2267
2915
  });
2268
2916
  return this.act({
2269
2917
  action,
@@ -2281,8 +2929,14 @@ Trace: ${exception.stack}`,
2281
2929
  } else if (useVision === "fallback") {
2282
2930
  this.logger({
2283
2931
  category: "action",
2284
- message: `Switching to vision-based processing`,
2285
- level: 1
2932
+ message: "switching to vision-based processing",
2933
+ level: 1,
2934
+ auxiliary: {
2935
+ useVision: {
2936
+ value: useVision.toString(),
2937
+ type: "string"
2938
+ }
2939
+ }
2286
2940
  });
2287
2941
  yield this.stagehand.page.evaluate(() => window.scrollToHeight(0));
2288
2942
  return yield this.act({
@@ -2301,7 +2955,7 @@ Trace: ${exception.stack}`,
2301
2955
  } else {
2302
2956
  if (this.enableCaching) {
2303
2957
  this.llmProvider.cleanRequestCache(requestId);
2304
- this.actionCache.deleteCacheForRequestId(requestId);
2958
+ (_a = this.actionCache) == null ? void 0 : _a.deleteCacheForRequestId(requestId);
2305
2959
  }
2306
2960
  return {
2307
2961
  success: false,
@@ -2315,13 +2969,29 @@ Trace: ${exception.stack}`,
2315
2969
  const method = response["method"];
2316
2970
  const args = response["args"];
2317
2971
  const elementLines = outputString.split("\n");
2318
- const elementText = ((_a = elementLines.find((line) => line.startsWith(`${elementId}:`))) == null ? void 0 : _a.split(":")[1]) || "Element not found";
2972
+ const elementText = ((_b = elementLines.find((line) => line.startsWith(`${elementId}:`))) == null ? void 0 : _b.split(":")[1]) || "Element not found";
2319
2973
  this.logger({
2320
2974
  category: "action",
2321
- message: `Executing method: ${method} on element: ${elementId} (xpaths: ${xpaths.join(
2322
- ", "
2323
- )}) with args: ${JSON.stringify(args)}`,
2324
- level: 1
2975
+ message: "executing method",
2976
+ level: 1,
2977
+ auxiliary: {
2978
+ method: {
2979
+ value: method,
2980
+ type: "string"
2981
+ },
2982
+ elementId: {
2983
+ value: elementId.toString(),
2984
+ type: "integer"
2985
+ },
2986
+ xpaths: {
2987
+ value: JSON.stringify(xpaths),
2988
+ type: "object"
2989
+ },
2990
+ args: {
2991
+ value: JSON.stringify(args),
2992
+ type: "object"
2993
+ }
2994
+ }
2325
2995
  });
2326
2996
  try {
2327
2997
  const initialUrl = this.stagehand.page.url();
@@ -2365,9 +3035,18 @@ Trace: ${exception.stack}`,
2365
3035
  }).catch((e) => {
2366
3036
  this.logger({
2367
3037
  category: "action",
2368
- message: `Error adding action step to cache: ${e.message}
2369
- Trace: ${e.stack}`,
2370
- level: 1
3038
+ message: "error adding action step to cache",
3039
+ level: 1,
3040
+ auxiliary: {
3041
+ error: {
3042
+ value: e.message,
3043
+ type: "string"
3044
+ },
3045
+ trace: {
3046
+ value: e.stack,
3047
+ type: "string"
3048
+ }
3049
+ }
2371
3050
  });
2372
3051
  });
2373
3052
  }
@@ -2388,7 +3067,7 @@ Trace: ${e.stack}`,
2388
3067
  if (!actionCompleted) {
2389
3068
  this.logger({
2390
3069
  category: "action",
2391
- message: `Continuing to next action step`,
3070
+ message: "continuing to next action step",
2392
3071
  level: 1
2393
3072
  });
2394
3073
  return this.act({
@@ -2407,7 +3086,7 @@ Trace: ${e.stack}`,
2407
3086
  } else {
2408
3087
  this.logger({
2409
3088
  category: "action",
2410
- message: `Action completed successfully`,
3089
+ message: "action completed successfully",
2411
3090
  level: 1
2412
3091
  });
2413
3092
  yield this._recordAction(action, response.step);
@@ -2420,9 +3099,22 @@ Trace: ${e.stack}`,
2420
3099
  } catch (error) {
2421
3100
  this.logger({
2422
3101
  category: "action",
2423
- message: `Error performing action - D (Retries: ${retries}): ${error.message}
2424
- Trace: ${error.stack}`,
2425
- level: 1
3102
+ message: "error performing action - d",
3103
+ level: 1,
3104
+ auxiliary: {
3105
+ error: {
3106
+ value: error.message,
3107
+ type: "string"
3108
+ },
3109
+ trace: {
3110
+ value: error.stack,
3111
+ type: "string"
3112
+ },
3113
+ retries: {
3114
+ value: retries.toString(),
3115
+ type: "integer"
3116
+ }
3117
+ }
2426
3118
  });
2427
3119
  if (retries < 2) {
2428
3120
  return this.act({
@@ -2447,16 +3139,25 @@ Trace: ${error.stack}`,
2447
3139
  }
2448
3140
  return {
2449
3141
  success: false,
2450
- message: `Error performing action - A: ${error.message}`,
3142
+ message: "error performing action - a",
2451
3143
  action
2452
3144
  };
2453
3145
  }
2454
3146
  } catch (error) {
2455
3147
  this.logger({
2456
3148
  category: "action",
2457
- message: `Error performing action - B: ${error.message}
2458
- Trace: ${error.stack}`,
2459
- level: 1
3149
+ message: "error performing action - b",
3150
+ level: 1,
3151
+ auxiliary: {
3152
+ error: {
3153
+ value: error.message,
3154
+ type: "string"
3155
+ },
3156
+ trace: {
3157
+ value: error.stack,
3158
+ type: "string"
3159
+ }
3160
+ }
2460
3161
  });
2461
3162
  if (this.enableCaching) {
2462
3163
  this.llmProvider.cleanRequestCache(requestId);
@@ -2472,14 +3173,18 @@ Trace: ${error.stack}`,
2472
3173
  }
2473
3174
  };
2474
3175
 
3176
+ // lib/dom/build/scriptContent.ts
3177
+ var scriptContent = '(() => {\n // lib/dom/xpathUtils.ts\n function getParentElement(node) {\n return isElementNode(node) ? node.parentElement : node.parentNode;\n }\n function getCombinations(attributes, size) {\n const results = [];\n function helper(start, combo) {\n if (combo.length === size) {\n results.push([...combo]);\n return;\n }\n for (let i = start; i < attributes.length; i++) {\n combo.push(attributes[i]);\n helper(i + 1, combo);\n combo.pop();\n }\n }\n helper(0, []);\n return results;\n }\n function isXPathFirstResultElement(xpath, target) {\n try {\n const result = document.evaluate(\n xpath,\n document.documentElement,\n null,\n XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,\n null\n );\n return result.snapshotItem(0) === target;\n } catch (error) {\n console.warn(`Invalid XPath expression: ${xpath}`, error);\n return false;\n }\n }\n function escapeXPathString(value) {\n if (value.includes("\'")) {\n if (value.includes(\'"\')) {\n return "concat(" + value.split(/(\'+)/).map((part) => {\n if (part === "\'") {\n return `"\'"`;\n } else if (part.startsWith("\'") && part.endsWith("\'")) {\n return `"${part}"`;\n } else {\n return `\'${part}\'`;\n }\n }).join(",") + ")";\n } else {\n return `"${value}"`;\n }\n } else {\n return `\'${value}\'`;\n }\n }\n async function generateXPathsForElement(element) {\n if (!element) return [];\n const [complexXPath, standardXPath, idBasedXPath] = await Promise.all([\n generateComplexXPath(element),\n generateStandardXPath(element),\n generatedIdBasedXPath(element)\n ]);\n return [standardXPath, ...idBasedXPath ? [idBasedXPath] : [], complexXPath];\n }\n async function generateComplexXPath(element) {\n const parts = [];\n let currentElement = element;\n while (currentElement && (isTextNode(currentElement) || isElementNode(currentElement))) {\n if (isElementNode(currentElement)) {\n const el = currentElement;\n let selector = el.tagName.toLowerCase();\n const attributePriority = [\n "data-qa",\n "data-component",\n "data-role",\n "role",\n "aria-role",\n "type",\n "name",\n "aria-label",\n "placeholder",\n "title",\n "alt"\n ];\n const attributes = attributePriority.map((attr) => {\n let value = el.getAttribute(attr);\n if (attr === "href-full" && value) {\n value = el.getAttribute("href");\n }\n return value ? { attr: attr === "href-full" ? "href" : attr, value } : null;\n }).filter((attr) => attr !== null);\n let uniqueSelector = "";\n for (let i = 1; i <= attributes.length; i++) {\n const combinations = getCombinations(attributes, i);\n for (const combo of combinations) {\n const conditions = combo.map((a) => `@${a.attr}=${escapeXPathString(a.value)}`).join(" and ");\n const xpath2 = `//${selector}[${conditions}]`;\n if (isXPathFirstResultElement(xpath2, el)) {\n uniqueSelector = xpath2;\n break;\n }\n }\n if (uniqueSelector) break;\n }\n if (uniqueSelector) {\n parts.unshift(uniqueSelector.replace("//", ""));\n break;\n } else {\n const parent = getParentElement(el);\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n (sibling) => sibling.tagName === el.tagName\n );\n const index = siblings.indexOf(el) + 1;\n selector += siblings.length > 1 ? `[${index}]` : "";\n }\n parts.unshift(selector);\n }\n }\n currentElement = getParentElement(currentElement);\n }\n const xpath = "//" + parts.join("/");\n return xpath;\n }\n async function generateStandardXPath(element) {\n const parts = [];\n while (element && (isTextNode(element) || isElementNode(element))) {\n let index = 0;\n let hasSameTypeSiblings = false;\n const siblings = element.parentElement ? Array.from(element.parentElement.childNodes) : [];\n for (let i = 0; i < siblings.length; i++) {\n const sibling = siblings[i];\n if (sibling.nodeType === element.nodeType && sibling.nodeName === element.nodeName) {\n index = index + 1;\n hasSameTypeSiblings = true;\n if (sibling.isSameNode(element)) {\n break;\n }\n }\n }\n if (element.nodeName !== "#text") {\n const tagName = element.nodeName.toLowerCase();\n const pathIndex = hasSameTypeSiblings ? `[${index}]` : "";\n parts.unshift(`${tagName}${pathIndex}`);\n }\n element = element.parentElement;\n }\n return parts.length ? `/${parts.join("/")}` : "";\n }\n async function generatedIdBasedXPath(element) {\n if (isElementNode(element) && element.id) {\n return `//*[@id=\'${element.id}\']`;\n }\n return null;\n }\n\n // lib/dom/process.ts\n function isElementNode(node) {\n return node.nodeType === Node.ELEMENT_NODE;\n }\n function isTextNode(node) {\n return node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim());\n }\n async function processDom(chunksSeen) {\n const { chunk, chunksArray } = await pickChunk(chunksSeen);\n const { outputString, selectorMap } = await processElements(chunk);\n console.log(\n `Stagehand (Browser Process): Extracted dom elements:\n${outputString}`\n );\n return {\n outputString,\n selectorMap,\n chunk,\n chunks: chunksArray\n };\n }\n async function processAllOfDom() {\n console.log("Stagehand (Browser Process): Processing all of DOM");\n const viewportHeight = window.innerHeight;\n const documentHeight = document.documentElement.scrollHeight;\n const totalChunks = Math.ceil(documentHeight / viewportHeight);\n let index = 0;\n const results = [];\n for (let chunk = 0; chunk < totalChunks; chunk++) {\n const result = await processElements(chunk, true, index);\n results.push(result);\n index += Object.keys(result.selectorMap).length;\n }\n await scrollToHeight(0);\n const allOutputString = results.map((result) => result.outputString).join("");\n const allSelectorMap = results.reduce(\n (acc, result) => ({ ...acc, ...result.selectorMap }),\n {}\n );\n console.log(\n `Stagehand (Browser Process): All dom elements: ${allOutputString}`\n );\n return {\n outputString: allOutputString,\n selectorMap: allSelectorMap\n };\n }\n async function scrollToHeight(height) {\n window.scrollTo({ top: height, left: 0, behavior: "smooth" });\n await new Promise((resolve) => {\n let scrollEndTimer;\n const handleScrollEnd = () => {\n clearTimeout(scrollEndTimer);\n scrollEndTimer = window.setTimeout(() => {\n window.removeEventListener("scroll", handleScrollEnd);\n resolve();\n }, 100);\n };\n window.addEventListener("scroll", handleScrollEnd, { passive: true });\n handleScrollEnd();\n });\n }\n var xpathCache = /* @__PURE__ */ new Map();\n async function processElements(chunk, scrollToChunk = true, indexOffset = 0) {\n console.time("processElements:total");\n const viewportHeight = window.innerHeight;\n const chunkHeight = viewportHeight * chunk;\n const maxScrollTop = document.documentElement.scrollHeight - window.innerHeight;\n const offsetTop = Math.min(chunkHeight, maxScrollTop);\n if (scrollToChunk) {\n console.time("processElements:scroll");\n await scrollToHeight(offsetTop);\n console.timeEnd("processElements:scroll");\n }\n const candidateElements = [];\n const DOMQueue = [...document.body.childNodes];\n console.log("Stagehand (Browser Process): Generating candidate elements");\n console.time("processElements:findCandidates");\n while (DOMQueue.length > 0) {\n const element = DOMQueue.pop();\n let shouldAddElement = false;\n if (element && isElementNode(element)) {\n const childrenCount = element.childNodes.length;\n for (let i = childrenCount - 1; i >= 0; i--) {\n const child = element.childNodes[i];\n DOMQueue.push(child);\n }\n if (isInteractiveElement(element)) {\n if (isActive(element) && isVisible(element)) {\n shouldAddElement = true;\n }\n }\n if (isLeafElement(element)) {\n if (isActive(element) && isVisible(element)) {\n shouldAddElement = true;\n }\n }\n }\n if (element && isTextNode(element) && isTextVisible(element)) {\n shouldAddElement = true;\n }\n if (shouldAddElement) {\n candidateElements.push(element);\n }\n }\n console.timeEnd("processElements:findCandidates");\n const selectorMap = {};\n let outputString = "";\n console.log(\n `Stagehand (Browser Process): Processing candidate elements: ${candidateElements.length}`\n );\n console.time("processElements:processCandidates");\n console.time("processElements:generateXPaths");\n const xpathLists = await Promise.all(\n candidateElements.map(async (element) => {\n if (xpathCache.has(element)) {\n return xpathCache.get(element);\n }\n const xpaths = await generateXPathsForElement(element);\n xpathCache.set(element, xpaths);\n return xpaths;\n })\n );\n console.timeEnd("processElements:generateXPaths");\n candidateElements.forEach((element, index) => {\n const xpaths = xpathLists[index];\n let elementOutput = "";\n if (isTextNode(element)) {\n const textContent = element.textContent?.trim();\n if (textContent) {\n elementOutput += `${index + indexOffset}:${textContent}\n`;\n }\n } else if (isElementNode(element)) {\n const tagName = element.tagName.toLowerCase();\n const attributes = collectEssentialAttributes(element);\n const openingTag = `<${tagName}${attributes ? " " + attributes : ""}>`;\n const closingTag = `</${tagName}>`;\n const textContent = element.textContent?.trim() || "";\n elementOutput += `${index + indexOffset}:${openingTag}${textContent}${closingTag}\n`;\n }\n outputString += elementOutput;\n selectorMap[index + indexOffset] = xpaths;\n });\n console.timeEnd("processElements:processCandidates");\n console.timeEnd("processElements:total");\n return {\n outputString,\n selectorMap\n };\n }\n function collectEssentialAttributes(element) {\n const essentialAttributes = [\n "id",\n "class",\n "href",\n "src",\n "aria-label",\n "aria-name",\n "aria-role",\n "aria-description",\n "aria-expanded",\n "aria-haspopup"\n ];\n const attrs = essentialAttributes.map((attr) => {\n const value = element.getAttribute(attr);\n return value ? `${attr}="${value}"` : "";\n }).filter((attr) => attr !== "");\n Array.from(element.attributes).forEach((attr) => {\n if (attr.name.startsWith("data-")) {\n attrs.push(`${attr.name}="${attr.value}"`);\n }\n });\n return attrs.join(" ");\n }\n window.processDom = processDom;\n window.processAllOfDom = processAllOfDom;\n window.processElements = processElements;\n window.scrollToHeight = scrollToHeight;\n var leafElementDenyList = ["SVG", "IFRAME", "SCRIPT", "STYLE", "LINK"];\n var interactiveElementTypes = [\n "A",\n "BUTTON",\n "DETAILS",\n "EMBED",\n "INPUT",\n "LABEL",\n "MENU",\n "MENUITEM",\n "OBJECT",\n "SELECT",\n "TEXTAREA",\n "SUMMARY"\n ];\n var interactiveRoles = [\n "button",\n "menu",\n "menuitem",\n "link",\n "checkbox",\n "radio",\n "slider",\n "tab",\n "tabpanel",\n "textbox",\n "combobox",\n "grid",\n "listbox",\n "option",\n "progressbar",\n "scrollbar",\n "searchbox",\n "switch",\n "tree",\n "treeitem",\n "spinbutton",\n "tooltip"\n ];\n var interactiveAriaRoles = ["menu", "menuitem", "button"];\n var isVisible = (element) => {\n const rect = element.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0 || rect.top < 0 || rect.top > window.innerHeight) {\n return false;\n }\n if (!isTopElement(element, rect)) {\n return false;\n }\n const visible = element.checkVisibility({\n checkOpacity: true,\n checkVisibilityCSS: true\n });\n return visible;\n };\n var isTextVisible = (element) => {\n const range = document.createRange();\n range.selectNodeContents(element);\n const rect = range.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0 || rect.top < 0 || rect.top > window.innerHeight) {\n return false;\n }\n const parent = element.parentElement;\n if (!parent) {\n return false;\n }\n if (!isTopElement(parent, rect)) {\n return false;\n }\n const visible = parent.checkVisibility({\n checkOpacity: true,\n checkVisibilityCSS: true\n });\n return visible;\n };\n function isTopElement(elem, rect) {\n const points = [\n { x: rect.left + rect.width * 0.25, y: rect.top + rect.height * 0.25 },\n { x: rect.left + rect.width * 0.75, y: rect.top + rect.height * 0.25 },\n { x: rect.left + rect.width * 0.25, y: rect.top + rect.height * 0.75 },\n { x: rect.left + rect.width * 0.75, y: rect.top + rect.height * 0.75 },\n { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }\n ];\n return points.some((point) => {\n const topEl = document.elementFromPoint(point.x, point.y);\n let current = topEl;\n while (current && current !== document.body) {\n if (current.isSameNode(elem)) {\n return true;\n }\n current = current.parentElement;\n }\n return false;\n });\n }\n var isActive = (element) => {\n if (element.hasAttribute("disabled") || element.hasAttribute("hidden") || element.getAttribute("aria-disabled") === "true") {\n return false;\n }\n return true;\n };\n var isInteractiveElement = (element) => {\n const elementType = element.tagName;\n const elementRole = element.getAttribute("role");\n const elementAriaRole = element.getAttribute("aria-role");\n return elementType && interactiveElementTypes.includes(elementType) || elementRole && interactiveRoles.includes(elementRole) || elementAriaRole && interactiveAriaRoles.includes(elementAriaRole);\n };\n var isLeafElement = (element) => {\n if (element.textContent === "") {\n return false;\n }\n if (element.childNodes.length === 0) {\n return !leafElementDenyList.includes(element.tagName);\n }\n if (element.childNodes.length === 1 && isTextNode(element.childNodes[0])) {\n return true;\n }\n return false;\n };\n async function pickChunk(chunksSeen) {\n const viewportHeight = window.innerHeight;\n const documentHeight = document.documentElement.scrollHeight;\n const chunks = Math.ceil(documentHeight / viewportHeight);\n const chunksArray = Array.from({ length: chunks }, (_, i) => i);\n const chunksRemaining = chunksArray.filter((chunk2) => {\n return !chunksSeen.includes(chunk2);\n });\n const currentScrollPosition = window.scrollY;\n const closestChunk = chunksRemaining.reduce((closest, current) => {\n const currentChunkTop = viewportHeight * current;\n const closestChunkTop = viewportHeight * closest;\n return Math.abs(currentScrollPosition - currentChunkTop) < Math.abs(currentScrollPosition - closestChunkTop) ? current : closest;\n }, chunksRemaining[0]);\n const chunk = closestChunk;\n if (chunk === void 0) {\n throw new Error(`No chunks remaining to check: ${chunksRemaining}`);\n }\n return {\n chunk,\n chunksArray\n };\n }\n\n // lib/dom/utils.ts\n async function waitForDomSettle() {\n return new Promise((resolve) => {\n const createTimeout = () => {\n return setTimeout(() => {\n resolve();\n }, 2e3);\n };\n let timeout = createTimeout();\n const observer = new MutationObserver(() => {\n clearTimeout(timeout);\n timeout = createTimeout();\n });\n observer.observe(window.document.body, { childList: true, subtree: true });\n });\n }\n window.waitForDomSettle = waitForDomSettle;\n\n // lib/dom/debug.ts\n async function debugDom() {\n window.chunkNumber = 0;\n const { selectorMap: multiSelectorMap, outputString } = await window.processElements(window.chunkNumber);\n const selectorMap = multiSelectorMapToSelectorMap(multiSelectorMap);\n drawChunk(selectorMap);\n setupChunkNav();\n }\n function multiSelectorMapToSelectorMap(multiSelectorMap) {\n return Object.fromEntries(\n Object.entries(multiSelectorMap).map(([key, selectors]) => [\n Number(key),\n selectors[0]\n ])\n );\n }\n function drawChunk(selectorMap) {\n cleanupMarkers();\n Object.entries(selectorMap).forEach(([_index, selector]) => {\n const element = document.evaluate(\n selector,\n document,\n null,\n XPathResult.FIRST_ORDERED_NODE_TYPE,\n null\n ).singleNodeValue;\n if (element) {\n let rect;\n if (element.nodeType === Node.ELEMENT_NODE) {\n rect = element.getBoundingClientRect();\n } else {\n const range = document.createRange();\n range.selectNodeContents(element);\n rect = range.getBoundingClientRect();\n }\n const color = "grey";\n const overlay = document.createElement("div");\n overlay.style.position = "absolute";\n overlay.style.left = `${rect.left + window.scrollX}px`;\n overlay.style.top = `${rect.top + window.scrollY}px`;\n overlay.style.padding = "2px";\n overlay.style.width = `${rect.width}px`;\n overlay.style.height = `${rect.height}px`;\n overlay.style.backgroundColor = color;\n overlay.className = "stagehand-marker";\n overlay.style.opacity = "0.3";\n overlay.style.zIndex = "1000000000";\n overlay.style.border = "1px solid";\n overlay.style.pointerEvents = "none";\n document.body.appendChild(overlay);\n }\n });\n }\n async function cleanupDebug() {\n cleanupMarkers();\n cleanupNav();\n }\n function cleanupMarkers() {\n const markers = document.querySelectorAll(".stagehand-marker");\n markers.forEach((marker) => {\n marker.remove();\n });\n }\n function cleanupNav() {\n const stagehandNavElements = document.querySelectorAll(".stagehand-nav");\n stagehandNavElements.forEach((element) => {\n element.remove();\n });\n }\n function setupChunkNav() {\n const viewportHeight = window.innerHeight;\n const documentHeight = document.documentElement.scrollHeight;\n const totalChunks = Math.ceil(documentHeight / viewportHeight);\n if (window.chunkNumber > 0) {\n const prevChunkButton = document.createElement("button");\n prevChunkButton.className = "stagehand-nav";\n prevChunkButton.textContent = "Previous";\n prevChunkButton.style.marginLeft = "50px";\n prevChunkButton.style.position = "fixed";\n prevChunkButton.style.bottom = "10px";\n prevChunkButton.style.left = "50%";\n prevChunkButton.style.transform = "translateX(-50%)";\n prevChunkButton.style.zIndex = "1000000000";\n prevChunkButton.onclick = async () => {\n cleanupMarkers();\n cleanupNav();\n window.chunkNumber -= 1;\n window.scrollTo(0, window.chunkNumber * window.innerHeight);\n await window.waitForDomSettle();\n const { selectorMap: multiSelectorMap } = await window.processElements(\n window.chunkNumber\n );\n const selectorMap = multiSelectorMapToSelectorMap(multiSelectorMap);\n drawChunk(selectorMap);\n setupChunkNav();\n };\n document.body.appendChild(prevChunkButton);\n }\n if (totalChunks > window.chunkNumber) {\n const nextChunkButton = document.createElement("button");\n nextChunkButton.className = "stagehand-nav";\n nextChunkButton.textContent = "Next";\n nextChunkButton.style.marginRight = "50px";\n nextChunkButton.style.position = "fixed";\n nextChunkButton.style.bottom = "10px";\n nextChunkButton.style.right = "50%";\n nextChunkButton.style.transform = "translateX(50%)";\n nextChunkButton.style.zIndex = "1000000000";\n nextChunkButton.onclick = async () => {\n cleanupMarkers();\n cleanupNav();\n window.chunkNumber += 1;\n window.scrollTo(0, window.chunkNumber * window.innerHeight);\n await window.waitForDomSettle();\n const { selectorMap: multiSelectorMap } = await window.processElements(\n window.chunkNumber\n );\n const selectorMap = multiSelectorMapToSelectorMap(multiSelectorMap);\n drawChunk(selectorMap);\n setupChunkNav();\n };\n document.body.appendChild(nextChunkButton);\n }\n }\n window.debugDom = debugDom;\n window.cleanupDebug = cleanupDebug;\n})();\n';
3178
+
2475
3179
  // lib/index.ts
3180
+ var import_crypto2 = require("crypto");
2476
3181
  require("dotenv").config({ path: ".env" });
2477
3182
  function getBrowser(apiKey, projectId, env = "LOCAL", headless = false, logger, browserbaseSessionCreateParams, browserbaseResumeSessionID) {
2478
3183
  return __async(this, null, function* () {
2479
3184
  if (env === "BROWSERBASE") {
2480
3185
  if (!apiKey) {
2481
3186
  logger({
2482
- category: "Init",
3187
+ category: "init",
2483
3188
  message: "BROWSERBASE_API_KEY is required to use BROWSERBASE env. Defaulting to LOCAL.",
2484
3189
  level: 0
2485
3190
  });
@@ -2487,7 +3192,7 @@ function getBrowser(apiKey, projectId, env = "LOCAL", headless = false, logger,
2487
3192
  }
2488
3193
  if (!projectId) {
2489
3194
  logger({
2490
- category: "Init",
3195
+ category: "init",
2491
3196
  message: "BROWSERBASE_PROJECT_ID is required for some Browserbase features that may not work without it.",
2492
3197
  level: 1
2493
3198
  });
@@ -2517,22 +3222,38 @@ function getBrowser(apiKey, projectId, env = "LOCAL", headless = false, logger,
2517
3222
  sessionId = browserbaseResumeSessionID;
2518
3223
  connectUrl = `wss://connect.browserbase.com?apiKey=${apiKey}&sessionId=${sessionId}`;
2519
3224
  logger({
2520
- category: "Init",
2521
- message: "Resuming existing Browserbase session...",
2522
- level: 0
3225
+ category: "init",
3226
+ message: "resuming existing browserbase session...",
3227
+ level: 1,
3228
+ auxiliary: {
3229
+ sessionId: {
3230
+ value: sessionId,
3231
+ type: "string"
3232
+ }
3233
+ }
2523
3234
  });
2524
3235
  } catch (error) {
2525
3236
  logger({
2526
- category: "Init",
2527
- message: `Failed to resume session ${browserbaseResumeSessionID}: ${error.message}`,
2528
- level: 0
3237
+ category: "init",
3238
+ message: "failed to resume session",
3239
+ level: 1,
3240
+ auxiliary: {
3241
+ error: {
3242
+ value: error.message,
3243
+ type: "string"
3244
+ },
3245
+ trace: {
3246
+ value: error.stack,
3247
+ type: "string"
3248
+ }
3249
+ }
2529
3250
  });
2530
3251
  throw error;
2531
3252
  }
2532
3253
  } else {
2533
3254
  logger({
2534
- category: "Init",
2535
- message: "Creating new Browserbase session...",
3255
+ category: "init",
3256
+ message: "creating new browserbase session...",
2536
3257
  level: 0
2537
3258
  });
2538
3259
  if (!projectId) {
@@ -2545,27 +3266,54 @@ function getBrowser(apiKey, projectId, env = "LOCAL", headless = false, logger,
2545
3266
  }, browserbaseSessionCreateParams));
2546
3267
  sessionId = session.id;
2547
3268
  connectUrl = session.connectUrl;
3269
+ logger({
3270
+ category: "init",
3271
+ message: "created new browserbase session",
3272
+ level: 1,
3273
+ auxiliary: {
3274
+ sessionId: {
3275
+ value: sessionId,
3276
+ type: "string"
3277
+ }
3278
+ }
3279
+ });
2548
3280
  }
2549
3281
  const browser = yield import_test.chromium.connectOverCDP(connectUrl);
2550
3282
  const { debuggerUrl } = yield browserbase.sessions.debug(sessionId);
2551
3283
  debugUrl = debuggerUrl;
2552
3284
  sessionUrl = `https://www.browserbase.com/sessions/${sessionId}`;
2553
3285
  logger({
2554
- category: "Init",
2555
- message: `Browserbase session ${browserbaseResumeSessionID ? "resumed" : "started"}.
2556
-
2557
- Session Url: ${sessionUrl}
2558
-
2559
- Live debug accessible here: ${debugUrl}.`,
2560
- level: 0
3286
+ category: "init",
3287
+ message: browserbaseResumeSessionID ? "browserbase session resumed" : "browserbase session started",
3288
+ level: 0,
3289
+ auxiliary: {
3290
+ sessionUrl: {
3291
+ value: sessionUrl,
3292
+ type: "string"
3293
+ },
3294
+ debugUrl: {
3295
+ value: debugUrl,
3296
+ type: "string"
3297
+ },
3298
+ sessionId: {
3299
+ value: sessionId,
3300
+ type: "string"
3301
+ }
3302
+ }
2561
3303
  });
2562
3304
  const context = browser.contexts()[0];
2563
3305
  return { browser, context, debugUrl, sessionUrl };
2564
3306
  } else {
2565
3307
  logger({
2566
- category: "Init",
2567
- message: `Launching local browser in ${headless ? "headless" : "headed"} mode`,
2568
- level: 0
3308
+ category: "init",
3309
+ message: "launching local browser",
3310
+ level: 0,
3311
+ auxiliary: {
3312
+ headless: {
3313
+ value: headless.toString(),
3314
+ type: "boolean"
3315
+ }
3316
+ }
2569
3317
  });
2570
3318
  const tmpDir = import_fs2.default.mkdtempSync(`/tmp/pwtest`);
2571
3319
  import_fs2.default.mkdirSync(`${tmpDir}/userdir/Default`, { recursive: true });
@@ -2603,8 +3351,8 @@ Live debug accessible here: ${debugUrl}.`,
2603
3351
  }
2604
3352
  );
2605
3353
  logger({
2606
- category: "Init",
2607
- message: "Local browser started successfully."
3354
+ category: "init",
3355
+ message: "local browser started successfully."
2608
3356
  });
2609
3357
  yield applyStealthScripts(context);
2610
3358
  return { context };
@@ -2658,7 +3406,7 @@ var Stagehand = class {
2658
3406
  this.is_processing_browserbase_logs = false;
2659
3407
  this.externalLogger = logger;
2660
3408
  this.logger = this.log.bind(this);
2661
- this.enableCaching = enableCaching != null ? enableCaching : false;
3409
+ this.enableCaching = enableCaching != null ? enableCaching : process.env.ENABLE_CACHING && process.env.ENABLE_CACHING === "true";
2662
3410
  this.llmProvider = llmProvider || new LLMProvider(this.logger, this.enableCaching);
2663
3411
  this.env = env;
2664
3412
  this.observations = {};
@@ -2717,32 +3465,7 @@ var Stagehand = class {
2717
3465
  yield this.page.setViewportSize({ width: 1280, height: 720 });
2718
3466
  }
2719
3467
  yield this.context.addInitScript({
2720
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "xpathUtils.js"),
2721
- content: import_fs2.default.readFileSync(
2722
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "xpathUtils.js"),
2723
- "utf8"
2724
- )
2725
- });
2726
- yield this.context.addInitScript({
2727
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "process.js"),
2728
- content: import_fs2.default.readFileSync(
2729
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "process.js"),
2730
- "utf8"
2731
- )
2732
- });
2733
- yield this.context.addInitScript({
2734
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "utils.js"),
2735
- content: import_fs2.default.readFileSync(
2736
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "utils.js"),
2737
- "utf8"
2738
- )
2739
- });
2740
- yield this.context.addInitScript({
2741
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "debug.js"),
2742
- content: import_fs2.default.readFileSync(
2743
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "debug.js"),
2744
- "utf8"
2745
- )
3468
+ content: scriptContent
2746
3469
  });
2747
3470
  return { debugUrl, sessionUrl };
2748
3471
  });
@@ -2763,52 +3486,21 @@ var Stagehand = class {
2763
3486
  yield this.page.setViewportSize({ width: 1280, height: 720 });
2764
3487
  }
2765
3488
  yield this.context.addInitScript({
2766
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "xpathUtils.js"),
2767
- content: import_fs2.default.readFileSync(
2768
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "xpathUtils.js"),
2769
- "utf8"
2770
- )
2771
- });
2772
- yield this.context.addInitScript({
2773
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "process.js"),
2774
- content: import_fs2.default.readFileSync(
2775
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "process.js"),
2776
- "utf8"
2777
- )
2778
- });
2779
- yield this.context.addInitScript({
2780
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "utils.js"),
2781
- content: import_fs2.default.readFileSync(
2782
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "utils.js"),
2783
- "utf8"
2784
- )
2785
- });
2786
- yield this.context.addInitScript({
2787
- path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "debug.js"),
2788
- content: import_fs2.default.readFileSync(
2789
- import_path2.default.join(__dirname, "..", "dist", "dom", "build", "debug.js"),
2790
- "utf8"
2791
- )
3489
+ content: scriptContent
2792
3490
  });
2793
3491
  return { context: this.context };
2794
3492
  });
2795
3493
  }
2796
- log({
2797
- message,
2798
- category,
2799
- level
2800
- }) {
2801
- const logObj = { category, message, level };
3494
+ log(logObj) {
2802
3495
  logObj.level = logObj.level || 1;
2803
3496
  if (this.externalLogger) {
2804
3497
  this.externalLogger(logObj);
2805
3498
  } else {
2806
- const categoryString = logObj.category ? `:${logObj.category}` : "";
2807
- const logMessage = `[stagehand${categoryString}] ${logObj.message}`;
3499
+ const logMessage = logLineToString(logObj);
2808
3500
  console.log(logMessage);
2809
3501
  }
2810
3502
  this.pending_logs_to_send_to_browserbase.push(__spreadProps(__spreadValues({}, logObj), {
2811
- id: Math.random().toString(36).substring(2, 15)
3503
+ id: (0, import_crypto2.randomUUID)()
2812
3504
  }));
2813
3505
  this._run_browserbase_log_processing_cycle();
2814
3506
  }
@@ -2833,7 +3525,7 @@ var Stagehand = class {
2833
3525
  }
2834
3526
  if (this.verbose >= logObj.level) {
2835
3527
  yield this.page.evaluate((logObj2) => {
2836
- const logMessage = `[stagehand${logObj2.category ? `:${logObj2.category}` : ""}] ${logObj2.message}`;
3528
+ const logMessage = logLineToString(logObj2);
2837
3529
  if (logObj2.message.toLowerCase().includes("trace") || logObj2.message.toLowerCase().includes("error:")) {
2838
3530
  console.error(logMessage);
2839
3531
  } else {
@@ -2857,8 +3549,14 @@ var Stagehand = class {
2857
3549
  timeoutHandle = setTimeout(() => {
2858
3550
  this.log({
2859
3551
  category: "dom",
2860
- message: `DOM settle timeout of ${timeout}ms exceeded, continuing anyway`,
2861
- level: 1
3552
+ message: "DOM settle timeout exceeded, continuing anyway",
3553
+ level: 1,
3554
+ auxiliary: {
3555
+ timeout_ms: {
3556
+ value: timeout.toString(),
3557
+ type: "integer"
3558
+ }
3559
+ }
2862
3560
  });
2863
3561
  resolve();
2864
3562
  }, timeout);
@@ -2887,9 +3585,18 @@ var Stagehand = class {
2887
3585
  } catch (e) {
2888
3586
  this.log({
2889
3587
  category: "dom",
2890
- message: `Error in waitForSettledDom: ${e.message}
2891
- Trace: ${e.stack}`,
2892
- level: 1
3588
+ message: "Error in waitForSettledDom",
3589
+ level: 1,
3590
+ auxiliary: {
3591
+ error: {
3592
+ value: e.message,
3593
+ type: "string"
3594
+ },
3595
+ trace: {
3596
+ value: e.stack,
3597
+ type: "string"
3598
+ }
3599
+ }
2893
3600
  });
2894
3601
  }
2895
3602
  });
@@ -2912,9 +3619,18 @@ Trace: ${e.stack}`,
2912
3619
  } catch (e) {
2913
3620
  this.log({
2914
3621
  category: "dom",
2915
- message: `Error in startDomDebug: ${e.message}
2916
- Trace: ${e.stack}`,
2917
- level: 1
3622
+ message: "Error in startDomDebug",
3623
+ level: 1,
3624
+ auxiliary: {
3625
+ error: {
3626
+ value: e.message,
3627
+ type: "string"
3628
+ },
3629
+ trace: {
3630
+ value: e.stack,
3631
+ type: "string"
3632
+ }
3633
+ }
2918
3634
  });
2919
3635
  }
2920
3636
  });
@@ -2948,8 +3664,14 @@ Trace: ${e.stack}`,
2948
3664
  }) {
2949
3665
  this.log({
2950
3666
  category: "extraction",
2951
- message: `starting extraction '${instruction}'`,
2952
- level: 1
3667
+ message: "starting extraction",
3668
+ level: 1,
3669
+ auxiliary: {
3670
+ instruction: {
3671
+ value: instruction,
3672
+ type: "string"
3673
+ }
3674
+ }
2953
3675
  });
2954
3676
  yield this._waitForSettledDom(domSettleTimeoutMs);
2955
3677
  yield this.startDomDebug();
@@ -2959,8 +3681,22 @@ Trace: ${e.stack}`,
2959
3681
  );
2960
3682
  this.log({
2961
3683
  category: "extraction",
2962
- message: `received output from processDom. Current chunk index: ${chunk}, Number of chunks left: ${chunks.length - chunksSeen.length}`,
2963
- level: 1
3684
+ message: "received output from processDom.",
3685
+ level: 1,
3686
+ auxiliary: {
3687
+ chunk: {
3688
+ value: chunk.toString(),
3689
+ type: "integer"
3690
+ },
3691
+ chunks_left: {
3692
+ value: (chunks.length - chunksSeen.length).toString(),
3693
+ type: "integer"
3694
+ },
3695
+ chunks_total: {
3696
+ value: chunks.length.toString(),
3697
+ type: "integer"
3698
+ }
3699
+ }
2964
3700
  });
2965
3701
  const extractionResponse = yield extract({
2966
3702
  instruction,
@@ -2982,22 +3718,40 @@ Trace: ${e.stack}`,
2982
3718
  yield this.cleanupDomDebug();
2983
3719
  this.log({
2984
3720
  category: "extraction",
2985
- message: `received extraction response: ${JSON.stringify(extractionResponse)}`,
2986
- level: 1
3721
+ message: "received extraction response",
3722
+ level: 1,
3723
+ auxiliary: {
3724
+ extraction_response: {
3725
+ value: JSON.stringify(extractionResponse),
3726
+ type: "object"
3727
+ }
3728
+ }
2987
3729
  });
2988
3730
  chunksSeen.push(chunk);
2989
3731
  if (completed || chunksSeen.length === chunks.length) {
2990
3732
  this.log({
2991
3733
  category: "extraction",
2992
- message: `response: ${JSON.stringify(extractionResponse)}`,
2993
- level: 1
3734
+ message: "got response",
3735
+ level: 1,
3736
+ auxiliary: {
3737
+ extraction_response: {
3738
+ value: JSON.stringify(extractionResponse),
3739
+ type: "object"
3740
+ }
3741
+ }
2994
3742
  });
2995
3743
  return output;
2996
3744
  } else {
2997
3745
  this.log({
2998
3746
  category: "extraction",
2999
- message: `continuing extraction, progress: '${newProgress}'`,
3000
- level: 1
3747
+ message: "continuing extraction",
3748
+ level: 1,
3749
+ auxiliary: {
3750
+ extraction_response: {
3751
+ value: JSON.stringify(extractionResponse),
3752
+ type: "object"
3753
+ }
3754
+ }
3001
3755
  });
3002
3756
  yield this._waitForSettledDom(domSettleTimeoutMs);
3003
3757
  return this._extract({
@@ -3027,8 +3781,14 @@ Trace: ${e.stack}`,
3027
3781
  const model = modelName != null ? modelName : this.defaultModelName;
3028
3782
  this.log({
3029
3783
  category: "observation",
3030
- message: `starting observation: ${instruction}`,
3031
- level: 1
3784
+ message: "starting observation",
3785
+ level: 1,
3786
+ auxiliary: {
3787
+ instruction: {
3788
+ value: instruction,
3789
+ type: "string"
3790
+ }
3791
+ }
3032
3792
  });
3033
3793
  yield this._waitForSettledDom(domSettleTimeoutMs);
3034
3794
  yield this.startDomDebug();
@@ -3041,14 +3801,21 @@ Trace: ${e.stack}`,
3041
3801
  if (!modelsWithVision.includes(model)) {
3042
3802
  this.log({
3043
3803
  category: "observation",
3044
- message: `${model} does not support vision. Skipping vision processing.`,
3045
- level: 1
3804
+ message: "Model does not support vision. Skipping vision processing.",
3805
+ level: 1,
3806
+ auxiliary: {
3807
+ model: {
3808
+ value: model,
3809
+ type: "string"
3810
+ }
3811
+ }
3046
3812
  });
3047
3813
  } else {
3048
3814
  const screenshotService = new ScreenshotService(
3049
3815
  this.page,
3050
3816
  selectorMap,
3051
- this.verbose
3817
+ this.verbose,
3818
+ this.externalLogger
3052
3819
  );
3053
3820
  annotatedScreenshot = yield screenshotService.getAnnotatedScreenshot(fullPage);
3054
3821
  outputString = "n/a. use the image to find the elements.";
@@ -3074,8 +3841,14 @@ Trace: ${e.stack}`,
3074
3841
  this._recordObservation(instruction, elementsWithSelectors);
3075
3842
  this.log({
3076
3843
  category: "observation",
3077
- message: `found element ${JSON.stringify(elementsWithSelectors)}`,
3078
- level: 1
3844
+ message: "found elements",
3845
+ level: 1,
3846
+ auxiliary: {
3847
+ elements: {
3848
+ value: JSON.stringify(elementsWithSelectors),
3849
+ type: "object"
3850
+ }
3851
+ }
3079
3852
  });
3080
3853
  yield this._recordObservation(instruction, elementsWithSelectors);
3081
3854
  return elementsWithSelectors;
@@ -3091,9 +3864,20 @@ Trace: ${e.stack}`,
3091
3864
  }) {
3092
3865
  useVision = useVision != null ? useVision : "fallback";
3093
3866
  const requestId = Math.random().toString(36).substring(2);
3094
- this.logger({
3867
+ this.log({
3095
3868
  category: "act",
3096
- message: `Running act with action: ${action}, requestId: ${requestId}`
3869
+ message: "running act",
3870
+ level: 1,
3871
+ auxiliary: {
3872
+ action: {
3873
+ value: action,
3874
+ type: "string"
3875
+ },
3876
+ requestId: {
3877
+ value: requestId,
3878
+ type: "string"
3879
+ }
3880
+ }
3097
3881
  });
3098
3882
  if (variables) {
3099
3883
  this.variables = __spreadValues(__spreadValues({}, this.variables), variables);
@@ -3110,10 +3894,20 @@ Trace: ${e.stack}`,
3110
3894
  skipActionCacheForThisStep: false,
3111
3895
  domSettleTimeoutMs
3112
3896
  }).catch((e) => {
3113
- this.logger({
3897
+ this.log({
3114
3898
  category: "act",
3115
- message: `Error acting: ${e.message}
3116
- Trace: ${e.stack}`
3899
+ message: "error acting",
3900
+ level: 1,
3901
+ auxiliary: {
3902
+ error: {
3903
+ value: e.message,
3904
+ type: "string"
3905
+ },
3906
+ trace: {
3907
+ value: e.stack,
3908
+ type: "string"
3909
+ }
3910
+ }
3117
3911
  });
3118
3912
  return {
3119
3913
  success: false,
@@ -3133,7 +3927,18 @@ Trace: ${e.stack}`
3133
3927
  const requestId = Math.random().toString(36).substring(2);
3134
3928
  this.logger({
3135
3929
  category: "extract",
3136
- message: `Running extract with instruction: ${instruction}, requestId: ${requestId}`
3930
+ message: "running extract",
3931
+ level: 1,
3932
+ auxiliary: {
3933
+ instruction: {
3934
+ value: instruction,
3935
+ type: "string"
3936
+ },
3937
+ requestId: {
3938
+ value: requestId,
3939
+ type: "string"
3940
+ }
3941
+ }
3137
3942
  });
3138
3943
  return this._extract({
3139
3944
  instruction,
@@ -3144,8 +3949,18 @@ Trace: ${e.stack}`
3144
3949
  }).catch((e) => {
3145
3950
  this.logger({
3146
3951
  category: "extract",
3147
- message: `Internal error: Error extracting: ${e.message}
3148
- Trace: ${e.stack}`
3952
+ message: "error extracting",
3953
+ level: 1,
3954
+ auxiliary: {
3955
+ error: {
3956
+ value: e.message,
3957
+ type: "string"
3958
+ },
3959
+ trace: {
3960
+ value: e.stack,
3961
+ type: "string"
3962
+ }
3963
+ }
3149
3964
  });
3150
3965
  if (this.enableCaching) {
3151
3966
  this.llmProvider.cleanRequestCache(requestId);
@@ -3160,7 +3975,18 @@ Trace: ${e.stack}`
3160
3975
  const requestId = Math.random().toString(36).substring(2);
3161
3976
  this.logger({
3162
3977
  category: "observe",
3163
- message: `Running observe with instruction: ${options == null ? void 0 : options.instruction}, requestId: ${requestId}`
3978
+ message: "running observe",
3979
+ level: 1,
3980
+ auxiliary: {
3981
+ instruction: {
3982
+ value: options == null ? void 0 : options.instruction,
3983
+ type: "string"
3984
+ },
3985
+ requestId: {
3986
+ value: requestId,
3987
+ type: "string"
3988
+ }
3989
+ }
3164
3990
  });
3165
3991
  return this._observe({
3166
3992
  instruction: (_a = options == null ? void 0 : options.instruction) != null ? _a : "Find actions that can be performed on this page.",
@@ -3172,8 +3998,26 @@ Trace: ${e.stack}`
3172
3998
  }).catch((e) => {
3173
3999
  this.logger({
3174
4000
  category: "observe",
3175
- message: `Error observing: ${e.message}
3176
- Trace: ${e.stack}`
4001
+ message: "error observing",
4002
+ level: 1,
4003
+ auxiliary: {
4004
+ error: {
4005
+ value: e.message,
4006
+ type: "string"
4007
+ },
4008
+ trace: {
4009
+ value: e.stack,
4010
+ type: "string"
4011
+ },
4012
+ requestId: {
4013
+ value: requestId,
4014
+ type: "string"
4015
+ },
4016
+ instruction: {
4017
+ value: options == null ? void 0 : options.instruction,
4018
+ type: "string"
4019
+ }
4020
+ }
3177
4021
  });
3178
4022
  if (this.enableCaching) {
3179
4023
  this.llmProvider.cleanRequestCache(requestId);