@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.d.ts +17 -14
- package/dist/index.js +1176 -332
- package/package.json +2 -3
- package/dist/dom/build/debug.js +0 -128
- package/dist/dom/build/global.d.js +0 -2
- package/dist/dom/build/index.js +0 -623
- package/dist/dom/build/process.js +0 -478
- package/dist/dom/build/utils.js +0 -19
- package/dist/dom/build/xpathUtils.js +0 -478
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: "
|
|
608
|
-
message:
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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:
|
|
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:
|
|
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: "
|
|
670
|
-
message:
|
|
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: "
|
|
712
|
-
message:
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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:
|
|
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:
|
|
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: "
|
|
812
|
-
message:
|
|
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: "
|
|
846
|
-
message: "
|
|
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:
|
|
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:
|
|
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:
|
|
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: "
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
1353
|
-
|
|
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
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
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: "
|
|
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: "
|
|
1398
|
-
message:
|
|
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
|
|
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: "
|
|
1482
|
-
message:
|
|
1483
|
-
level:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
1713
|
-
|
|
1714
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
1766
|
-
|
|
1767
|
-
|
|
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:
|
|
1774
|
-
|
|
1775
|
-
|
|
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:
|
|
1793
|
-
|
|
1794
|
-
|
|
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:
|
|
1806
|
-
|
|
1807
|
-
|
|
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:
|
|
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:
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
2335
|
+
message: "network idle timeout hit",
|
|
1865
2336
|
level: 1
|
|
1866
2337
|
});
|
|
1867
2338
|
});
|
|
1868
2339
|
this.logger({
|
|
1869
2340
|
category: "action",
|
|
1870
|
-
message:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
1985
|
-
|
|
1986
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
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:
|
|
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: "
|
|
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:
|
|
2134
|
-
|
|
2135
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 = ((
|
|
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:
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
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:
|
|
2369
|
-
|
|
2370
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
2424
|
-
|
|
2425
|
-
|
|
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:
|
|
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:
|
|
2458
|
-
|
|
2459
|
-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
2521
|
-
message: "
|
|
2522
|
-
level:
|
|
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: "
|
|
2527
|
-
message:
|
|
2528
|
-
level:
|
|
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: "
|
|
2535
|
-
message: "
|
|
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: "
|
|
2555
|
-
message:
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
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: "
|
|
2567
|
-
message:
|
|
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: "
|
|
2607
|
-
message: "
|
|
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 :
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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 =
|
|
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:
|
|
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:
|
|
2891
|
-
|
|
2892
|
-
|
|
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:
|
|
2916
|
-
|
|
2917
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
3867
|
+
this.log({
|
|
3095
3868
|
category: "act",
|
|
3096
|
-
message:
|
|
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.
|
|
3897
|
+
this.log({
|
|
3114
3898
|
category: "act",
|
|
3115
|
-
message:
|
|
3116
|
-
|
|
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:
|
|
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:
|
|
3148
|
-
|
|
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:
|
|
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:
|
|
3176
|
-
|
|
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);
|