@browserbasehq/stagehand 1.0.3 → 1.1.0-alpha.1
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/README.md +10 -5
- package/dist/evals/index.eval.js +1075 -0
- package/dist/evals/index.eval.js.map +1 -0
- package/dist/evals/playground.js +112 -0
- package/dist/evals/playground.js.map +1 -0
- package/dist/evals/utils.js +52 -0
- package/dist/evals/utils.js.map +1 -0
- package/dist/examples/2048.js +108 -0
- package/dist/examples/2048.js.map +1 -0
- package/dist/examples/debugUrl.js +35 -0
- package/dist/examples/debugUrl.js.map +1 -0
- package/dist/examples/example.js +37 -0
- package/dist/examples/example.js.map +1 -0
- package/dist/index.d.ts +22 -6
- package/dist/index.js +629 -152
- package/dist/lib/browserbase.js +56 -0
- package/dist/lib/browserbase.js.map +1 -0
- package/dist/lib/cache.js +78 -0
- package/dist/lib/cache.js.map +1 -0
- package/dist/lib/dom/debug.js +119 -0
- package/dist/lib/dom/debug.js.map +1 -0
- package/dist/lib/dom/index.js +20 -0
- package/dist/lib/dom/index.js.map +1 -0
- package/dist/lib/dom/process.js +396 -0
- package/dist/lib/dom/process.js.map +1 -0
- package/dist/lib/dom/utils.js +28 -0
- package/dist/lib/dom/utils.js.map +1 -0
- package/dist/lib/index.js +978 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/inference.js +226 -0
- package/dist/lib/inference.js.map +1 -0
- package/dist/lib/llm/AnthropicClient.js +150 -0
- package/dist/lib/llm/AnthropicClient.js.map +1 -0
- package/dist/lib/llm/LLMClient.js +12 -0
- package/dist/lib/llm/LLMClient.js.map +1 -0
- package/dist/lib/llm/LLMProvider.js +34 -0
- package/dist/lib/llm/LLMProvider.js.map +1 -0
- package/dist/lib/llm/OpenAIClient.js +69 -0
- package/dist/lib/llm/OpenAIClient.js.map +1 -0
- package/dist/lib/prompt.js +288 -0
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/vision.js +194 -0
- package/dist/lib/vision.js.map +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -84,6 +84,7 @@ module.exports = __toCommonJS(lib_exports);
|
|
|
84
84
|
var import_test = require("@playwright/test");
|
|
85
85
|
var import_crypto = __toESM(require("crypto"));
|
|
86
86
|
var import_fs2 = __toESM(require("fs"));
|
|
87
|
+
var import_sdk2 = require("@browserbasehq/sdk");
|
|
87
88
|
|
|
88
89
|
// lib/prompt.ts
|
|
89
90
|
var actSystemPrompt = `
|
|
@@ -334,6 +335,7 @@ var modelsWithVision = [
|
|
|
334
335
|
"gpt-4o-mini",
|
|
335
336
|
"claude-3-5-sonnet-latest",
|
|
336
337
|
"claude-3-5-sonnet-20240620",
|
|
338
|
+
"claude-3-5-sonnet-20241022",
|
|
337
339
|
"gpt-4o-2024-08-06"
|
|
338
340
|
];
|
|
339
341
|
var AnnotatedScreenshotText = "This is a screenshot of the current page state with the elements annotated on it. Each element id is annotated with a number to the top left of it. Duplicate annotations at the same location are under each other vertically.";
|
|
@@ -347,9 +349,10 @@ function verifyActCompletion(_0) {
|
|
|
347
349
|
modelName,
|
|
348
350
|
screenshot,
|
|
349
351
|
domElements,
|
|
350
|
-
logger
|
|
352
|
+
logger,
|
|
353
|
+
requestId
|
|
351
354
|
}) {
|
|
352
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
355
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
353
356
|
const messages = [
|
|
354
357
|
buildVerifyActCompletionSystemPrompt(),
|
|
355
358
|
buildVerifyActCompletionUserPrompt(goal, steps, domElements)
|
|
@@ -398,9 +401,10 @@ function act(_0) {
|
|
|
398
401
|
modelName,
|
|
399
402
|
screenshot,
|
|
400
403
|
retries = 0,
|
|
401
|
-
logger
|
|
404
|
+
logger,
|
|
405
|
+
requestId
|
|
402
406
|
}) {
|
|
403
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
407
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
404
408
|
const messages = [
|
|
405
409
|
buildActSystemPrompt(),
|
|
406
410
|
buildActUserPrompt(action, steps, domElements)
|
|
@@ -437,7 +441,8 @@ function act(_0) {
|
|
|
437
441
|
llmProvider,
|
|
438
442
|
modelName,
|
|
439
443
|
retries: retries + 1,
|
|
440
|
-
logger
|
|
444
|
+
logger,
|
|
445
|
+
requestId
|
|
441
446
|
});
|
|
442
447
|
}
|
|
443
448
|
});
|
|
@@ -452,9 +457,10 @@ function extract(_0) {
|
|
|
452
457
|
llmProvider,
|
|
453
458
|
modelName,
|
|
454
459
|
chunksSeen,
|
|
455
|
-
chunksTotal
|
|
460
|
+
chunksTotal,
|
|
461
|
+
requestId
|
|
456
462
|
}) {
|
|
457
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
463
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
458
464
|
const extractionResponse = yield llmClient.createChatCompletion({
|
|
459
465
|
model: modelName,
|
|
460
466
|
messages: [
|
|
@@ -527,7 +533,8 @@ function observe(_0) {
|
|
|
527
533
|
domElements,
|
|
528
534
|
llmProvider,
|
|
529
535
|
modelName,
|
|
530
|
-
image
|
|
536
|
+
image,
|
|
537
|
+
requestId
|
|
531
538
|
}) {
|
|
532
539
|
const observeSchema = import_zod.z.object({
|
|
533
540
|
elements: import_zod.z.array(
|
|
@@ -539,7 +546,7 @@ function observe(_0) {
|
|
|
539
546
|
})
|
|
540
547
|
).describe("an array of elements that match the instruction")
|
|
541
548
|
});
|
|
542
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
549
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
543
550
|
const observationResponse = yield llmClient.createChatCompletion({
|
|
544
551
|
model: modelName,
|
|
545
552
|
messages: [
|
|
@@ -567,12 +574,31 @@ function observe(_0) {
|
|
|
567
574
|
var import_openai = __toESM(require("openai"));
|
|
568
575
|
var import_zod2 = require("openai/helpers/zod");
|
|
569
576
|
var OpenAIClient = class {
|
|
570
|
-
constructor(logger) {
|
|
577
|
+
constructor(logger, enableCaching = false, cache, requestId) {
|
|
571
578
|
this.client = new import_openai.default();
|
|
572
579
|
this.logger = logger;
|
|
580
|
+
this.requestId = requestId;
|
|
581
|
+
this.cache = cache;
|
|
582
|
+
this.enableCaching = enableCaching;
|
|
573
583
|
}
|
|
574
584
|
createChatCompletion(options) {
|
|
575
585
|
return __async(this, null, function* () {
|
|
586
|
+
const cacheOptions = {
|
|
587
|
+
model: options.model,
|
|
588
|
+
messages: options.messages,
|
|
589
|
+
temperature: options.temperature,
|
|
590
|
+
top_p: options.top_p,
|
|
591
|
+
frequency_penalty: options.frequency_penalty,
|
|
592
|
+
presence_penalty: options.presence_penalty,
|
|
593
|
+
image: options.image,
|
|
594
|
+
response_model: options.response_model
|
|
595
|
+
};
|
|
596
|
+
if (this.enableCaching) {
|
|
597
|
+
const cachedResponse = yield this.cache.get(cacheOptions, this.requestId);
|
|
598
|
+
if (cachedResponse) {
|
|
599
|
+
return cachedResponse;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
576
602
|
if (options.image) {
|
|
577
603
|
const screenshotMessage = {
|
|
578
604
|
role: "user",
|
|
@@ -602,8 +628,18 @@ var OpenAIClient = class {
|
|
|
602
628
|
if (response_model) {
|
|
603
629
|
const extractedData = response.choices[0].message.content;
|
|
604
630
|
const parsedData = JSON.parse(extractedData);
|
|
631
|
+
if (this.enableCaching) {
|
|
632
|
+
this.cache.set(
|
|
633
|
+
cacheOptions,
|
|
634
|
+
__spreadValues({}, parsedData),
|
|
635
|
+
this.requestId
|
|
636
|
+
);
|
|
637
|
+
}
|
|
605
638
|
return __spreadValues({}, parsedData);
|
|
606
639
|
}
|
|
640
|
+
if (this.enableCaching) {
|
|
641
|
+
this.cache.set(cacheOptions, response, this.requestId);
|
|
642
|
+
}
|
|
607
643
|
return response;
|
|
608
644
|
});
|
|
609
645
|
}
|
|
@@ -613,16 +649,33 @@ var OpenAIClient = class {
|
|
|
613
649
|
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
614
650
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
615
651
|
var AnthropicClient = class {
|
|
616
|
-
constructor(logger) {
|
|
652
|
+
constructor(logger, enableCaching = false, cache, requestId) {
|
|
617
653
|
this.client = new import_sdk.default({
|
|
618
654
|
apiKey: process.env.ANTHROPIC_API_KEY
|
|
619
|
-
// Make sure to set this environment variable
|
|
620
655
|
});
|
|
621
656
|
this.logger = logger;
|
|
657
|
+
this.cache = cache;
|
|
658
|
+
this.enableCaching = enableCaching;
|
|
659
|
+
this.requestId = requestId;
|
|
622
660
|
}
|
|
623
661
|
createChatCompletion(options) {
|
|
624
662
|
return __async(this, null, function* () {
|
|
625
663
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
664
|
+
const cacheOptions = {
|
|
665
|
+
model: options.model,
|
|
666
|
+
messages: options.messages,
|
|
667
|
+
temperature: options.temperature,
|
|
668
|
+
image: options.image,
|
|
669
|
+
response_model: options.response_model,
|
|
670
|
+
tools: options.tools,
|
|
671
|
+
retries: options.retries
|
|
672
|
+
};
|
|
673
|
+
if (this.enableCaching) {
|
|
674
|
+
const cachedResponse = yield this.cache.get(cacheOptions, this.requestId);
|
|
675
|
+
if (cachedResponse) {
|
|
676
|
+
return cachedResponse;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
626
679
|
const systemMessage = options.messages.find((msg) => msg.role === "system");
|
|
627
680
|
const userMessages = options.messages.filter(
|
|
628
681
|
(msg) => msg.role !== "system"
|
|
@@ -724,26 +777,318 @@ var AnthropicClient = class {
|
|
|
724
777
|
if (options.response_model) {
|
|
725
778
|
const toolUse = response.content.find((c) => c.type === "tool_use");
|
|
726
779
|
if (toolUse && "input" in toolUse) {
|
|
727
|
-
|
|
780
|
+
const result = toolUse.input;
|
|
781
|
+
if (this.enableCaching) {
|
|
782
|
+
this.cache.set(cacheOptions, result, this.requestId);
|
|
783
|
+
}
|
|
784
|
+
return result;
|
|
728
785
|
} else {
|
|
729
|
-
if (!options.retries || options.retries <
|
|
786
|
+
if (!options.retries || options.retries < 5) {
|
|
730
787
|
return this.createChatCompletion(__spreadProps(__spreadValues({}, options), {
|
|
731
788
|
retries: ((_g = options.retries) != null ? _g : 0) + 1
|
|
732
789
|
}));
|
|
733
790
|
}
|
|
734
791
|
throw new Error(
|
|
735
|
-
"
|
|
792
|
+
"Create Chat Completion Failed: No tool use with input in response"
|
|
736
793
|
);
|
|
737
794
|
}
|
|
738
795
|
}
|
|
796
|
+
if (this.enableCaching) {
|
|
797
|
+
this.cache.set(cacheOptions, transformedResponse, this.requestId);
|
|
798
|
+
}
|
|
739
799
|
return transformedResponse;
|
|
740
800
|
});
|
|
741
801
|
}
|
|
742
802
|
};
|
|
743
803
|
|
|
804
|
+
// lib/llm/LLMCache.ts
|
|
805
|
+
var fs = __toESM(require("fs"));
|
|
806
|
+
var path = __toESM(require("path"));
|
|
807
|
+
var crypto = __toESM(require("crypto"));
|
|
808
|
+
var LLMCache = class {
|
|
809
|
+
constructor(logger, cacheDir = path.join(process.cwd(), "tmp", ".cache"), cacheFile = "llm_calls.json") {
|
|
810
|
+
this.CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
811
|
+
// 1 week in milliseconds
|
|
812
|
+
this.CLEANUP_PROBABILITY = 0.01;
|
|
813
|
+
// 1% chance
|
|
814
|
+
this.LOCK_TIMEOUT_MS = 1e3;
|
|
815
|
+
this.lock_acquired = false;
|
|
816
|
+
this.count_lock_acquire_failures = 0;
|
|
817
|
+
this.request_id_to_used_hashes = {};
|
|
818
|
+
this.logger = logger;
|
|
819
|
+
this.cacheDir = cacheDir;
|
|
820
|
+
this.cacheFile = path.join(cacheDir, cacheFile);
|
|
821
|
+
this.lockFile = path.join(cacheDir, "llm_cache.lock");
|
|
822
|
+
this.ensureCacheDirectory();
|
|
823
|
+
this.setupProcessHandlers();
|
|
824
|
+
}
|
|
825
|
+
setupProcessHandlers() {
|
|
826
|
+
const releaseLockAndExit = () => {
|
|
827
|
+
this.releaseLock();
|
|
828
|
+
process.exit();
|
|
829
|
+
};
|
|
830
|
+
process.on("exit", releaseLockAndExit);
|
|
831
|
+
process.on("SIGINT", releaseLockAndExit);
|
|
832
|
+
process.on("SIGTERM", releaseLockAndExit);
|
|
833
|
+
process.on("uncaughtException", (err) => {
|
|
834
|
+
this.logger({
|
|
835
|
+
category: "llm_cache",
|
|
836
|
+
message: `Uncaught exception: ${err}`,
|
|
837
|
+
level: 2
|
|
838
|
+
});
|
|
839
|
+
if (this.lock_acquired) {
|
|
840
|
+
releaseLockAndExit();
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
ensureCacheDirectory() {
|
|
845
|
+
if (!fs.existsSync(this.cacheDir)) {
|
|
846
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
createHash(data) {
|
|
850
|
+
const hash = crypto.createHash("sha256");
|
|
851
|
+
return hash.update(JSON.stringify(data)).digest("hex");
|
|
852
|
+
}
|
|
853
|
+
sleep(ms) {
|
|
854
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
855
|
+
}
|
|
856
|
+
acquireLock() {
|
|
857
|
+
return __async(this, null, function* () {
|
|
858
|
+
const startTime = Date.now();
|
|
859
|
+
while (Date.now() - startTime < this.LOCK_TIMEOUT_MS) {
|
|
860
|
+
try {
|
|
861
|
+
if (fs.existsSync(this.lockFile)) {
|
|
862
|
+
const lockAge = Date.now() - fs.statSync(this.lockFile).mtimeMs;
|
|
863
|
+
if (lockAge > this.LOCK_TIMEOUT_MS) {
|
|
864
|
+
fs.unlinkSync(this.lockFile);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
fs.writeFileSync(this.lockFile, process.pid.toString(), { flag: "wx" });
|
|
868
|
+
this.count_lock_acquire_failures = 0;
|
|
869
|
+
this.lock_acquired = true;
|
|
870
|
+
return true;
|
|
871
|
+
} catch (error) {
|
|
872
|
+
yield this.sleep(5);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
this.logger({
|
|
876
|
+
category: "llm_cache",
|
|
877
|
+
message: "Failed to acquire lock after timeout",
|
|
878
|
+
level: 2
|
|
879
|
+
});
|
|
880
|
+
this.count_lock_acquire_failures++;
|
|
881
|
+
if (this.count_lock_acquire_failures >= 3) {
|
|
882
|
+
this.logger({
|
|
883
|
+
category: "llm_cache",
|
|
884
|
+
message: "Failed to acquire lock 3 times in a row. Releasing lock manually.",
|
|
885
|
+
level: 1
|
|
886
|
+
});
|
|
887
|
+
this.releaseLock();
|
|
888
|
+
}
|
|
889
|
+
return false;
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
releaseLock() {
|
|
893
|
+
try {
|
|
894
|
+
if (fs.existsSync(this.lockFile)) {
|
|
895
|
+
fs.unlinkSync(this.lockFile);
|
|
896
|
+
}
|
|
897
|
+
this.lock_acquired = false;
|
|
898
|
+
} catch (error) {
|
|
899
|
+
this.logger({
|
|
900
|
+
category: "llm_cache",
|
|
901
|
+
message: `Error releasing lock: ${error}`,
|
|
902
|
+
level: 2
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
readCache() {
|
|
907
|
+
if (fs.existsSync(this.cacheFile)) {
|
|
908
|
+
return JSON.parse(fs.readFileSync(this.cacheFile, "utf-8"));
|
|
909
|
+
}
|
|
910
|
+
return {};
|
|
911
|
+
}
|
|
912
|
+
writeCache(cache) {
|
|
913
|
+
try {
|
|
914
|
+
if (Math.random() < this.CLEANUP_PROBABILITY) {
|
|
915
|
+
this.cleanupStaleEntries(cache);
|
|
916
|
+
}
|
|
917
|
+
fs.writeFileSync(this.cacheFile, JSON.stringify(cache, null, 2));
|
|
918
|
+
} finally {
|
|
919
|
+
this.releaseLock();
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
cleanupStaleEntries(cache) {
|
|
923
|
+
if (!this.acquireLock()) {
|
|
924
|
+
this.logger({
|
|
925
|
+
category: "llm_cache",
|
|
926
|
+
message: "Failed to acquire lock for cleaning up cache",
|
|
927
|
+
level: 2
|
|
928
|
+
});
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
try {
|
|
932
|
+
const now = Date.now();
|
|
933
|
+
let entriesRemoved = 0;
|
|
934
|
+
for (const [hash, entry] of Object.entries(cache)) {
|
|
935
|
+
if (now - entry.timestamp > this.CACHE_MAX_AGE_MS) {
|
|
936
|
+
delete cache[hash];
|
|
937
|
+
entriesRemoved++;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (entriesRemoved > 0) {
|
|
941
|
+
this.logger({
|
|
942
|
+
category: "llm_cache",
|
|
943
|
+
message: `Cleaned up ${entriesRemoved} stale cache entries`,
|
|
944
|
+
level: 1
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
} catch (error) {
|
|
948
|
+
this.logger({
|
|
949
|
+
category: "llm_cache",
|
|
950
|
+
message: `Error cleaning up stale cache entries: ${error}`,
|
|
951
|
+
level: 1
|
|
952
|
+
});
|
|
953
|
+
} finally {
|
|
954
|
+
this.releaseLock();
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
resetCache() {
|
|
958
|
+
if (!this.acquireLock()) {
|
|
959
|
+
this.logger({
|
|
960
|
+
category: "llm_cache",
|
|
961
|
+
message: "Failed to acquire lock for resetting cache",
|
|
962
|
+
level: 2
|
|
963
|
+
});
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
try {
|
|
967
|
+
this.ensureCacheDirectory();
|
|
968
|
+
fs.writeFileSync(this.cacheFile, "{}");
|
|
969
|
+
} finally {
|
|
970
|
+
this.releaseLock();
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
get(options, requestId) {
|
|
974
|
+
return __async(this, null, function* () {
|
|
975
|
+
var _a, _b;
|
|
976
|
+
if (!(yield this.acquireLock())) {
|
|
977
|
+
this.logger({
|
|
978
|
+
category: "llm_cache",
|
|
979
|
+
message: "Failed to acquire lock for getting cache",
|
|
980
|
+
level: 2
|
|
981
|
+
});
|
|
982
|
+
return null;
|
|
983
|
+
}
|
|
984
|
+
try {
|
|
985
|
+
const hash = this.createHash(options);
|
|
986
|
+
const cache = this.readCache();
|
|
987
|
+
if (cache[hash]) {
|
|
988
|
+
this.logger({
|
|
989
|
+
category: "llm_cache",
|
|
990
|
+
message: "Cache hit",
|
|
991
|
+
level: 1
|
|
992
|
+
});
|
|
993
|
+
(_b = (_a = this.request_id_to_used_hashes)[requestId]) != null ? _b : _a[requestId] = [];
|
|
994
|
+
this.request_id_to_used_hashes[requestId].push(hash);
|
|
995
|
+
return cache[hash].response;
|
|
996
|
+
}
|
|
997
|
+
return null;
|
|
998
|
+
} catch (error) {
|
|
999
|
+
this.logger({
|
|
1000
|
+
category: "llm_cache",
|
|
1001
|
+
message: `Error getting cache: ${error}. Resetting cache.`,
|
|
1002
|
+
level: 1
|
|
1003
|
+
});
|
|
1004
|
+
this.resetCache();
|
|
1005
|
+
return null;
|
|
1006
|
+
} finally {
|
|
1007
|
+
this.releaseLock();
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
deleteCacheForRequestId(requestId) {
|
|
1012
|
+
return __async(this, null, function* () {
|
|
1013
|
+
var _a;
|
|
1014
|
+
if (!(yield this.acquireLock())) {
|
|
1015
|
+
this.logger({
|
|
1016
|
+
category: "llm_cache",
|
|
1017
|
+
message: "Failed to acquire lock for deleting cache",
|
|
1018
|
+
level: 2
|
|
1019
|
+
});
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
try {
|
|
1023
|
+
const cache = this.readCache();
|
|
1024
|
+
let entriesRemoved = [];
|
|
1025
|
+
for (const hash of (_a = this.request_id_to_used_hashes[requestId]) != null ? _a : []) {
|
|
1026
|
+
if (cache[hash]) {
|
|
1027
|
+
entriesRemoved.push(cache[hash]);
|
|
1028
|
+
delete cache[hash];
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
this.logger({
|
|
1032
|
+
category: "llm_cache",
|
|
1033
|
+
message: `Deleted ${entriesRemoved.length} cache entries for requestId ${requestId}`,
|
|
1034
|
+
level: 1
|
|
1035
|
+
});
|
|
1036
|
+
this.writeCache(cache);
|
|
1037
|
+
} catch (exception) {
|
|
1038
|
+
this.logger({
|
|
1039
|
+
category: "llm_cache",
|
|
1040
|
+
message: `Error deleting cache for requestId ${requestId}: ${exception}`,
|
|
1041
|
+
level: 1
|
|
1042
|
+
});
|
|
1043
|
+
} finally {
|
|
1044
|
+
this.releaseLock();
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
set(options, response, requestId) {
|
|
1049
|
+
return __async(this, null, function* () {
|
|
1050
|
+
var _a, _b;
|
|
1051
|
+
if (!(yield this.acquireLock())) {
|
|
1052
|
+
this.logger({
|
|
1053
|
+
category: "llm_cache",
|
|
1054
|
+
message: "Failed to acquire lock for setting cache",
|
|
1055
|
+
level: 2
|
|
1056
|
+
});
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
try {
|
|
1060
|
+
const hash = this.createHash(options);
|
|
1061
|
+
const cache = this.readCache();
|
|
1062
|
+
cache[hash] = {
|
|
1063
|
+
response,
|
|
1064
|
+
timestamp: Date.now(),
|
|
1065
|
+
requestId
|
|
1066
|
+
};
|
|
1067
|
+
this.writeCache(cache);
|
|
1068
|
+
(_b = (_a = this.request_id_to_used_hashes)[requestId]) != null ? _b : _a[requestId] = [];
|
|
1069
|
+
this.request_id_to_used_hashes[requestId].push(hash);
|
|
1070
|
+
this.logger({
|
|
1071
|
+
category: "llm_cache",
|
|
1072
|
+
message: "Cache miss - saved new response",
|
|
1073
|
+
level: 1
|
|
1074
|
+
});
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
this.logger({
|
|
1077
|
+
category: "llm_cache",
|
|
1078
|
+
message: `Error setting cache: ${error}. Resetting cache.`,
|
|
1079
|
+
level: 1
|
|
1080
|
+
});
|
|
1081
|
+
this.resetCache();
|
|
1082
|
+
} finally {
|
|
1083
|
+
this.releaseLock();
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
|
|
744
1089
|
// lib/llm/LLMProvider.ts
|
|
745
1090
|
var LLMProvider = class {
|
|
746
|
-
constructor(logger) {
|
|
1091
|
+
constructor(logger, enableCaching) {
|
|
747
1092
|
this.modelToProviderMap = {
|
|
748
1093
|
"gpt-4o": "openai",
|
|
749
1094
|
"gpt-4o-mini": "openai",
|
|
@@ -753,17 +1098,36 @@ var LLMProvider = class {
|
|
|
753
1098
|
"claude-3-5-sonnet-20241022": "anthropic"
|
|
754
1099
|
};
|
|
755
1100
|
this.logger = logger;
|
|
1101
|
+
this.enableCaching = enableCaching;
|
|
1102
|
+
this.cache = new LLMCache(logger);
|
|
756
1103
|
}
|
|
757
|
-
|
|
1104
|
+
cleanRequestCache(requestId) {
|
|
1105
|
+
this.logger({
|
|
1106
|
+
category: "llm_cache",
|
|
1107
|
+
message: `Cleaning up cache for requestId: ${requestId}`
|
|
1108
|
+
});
|
|
1109
|
+
this.cache.deleteCacheForRequestId(requestId);
|
|
1110
|
+
}
|
|
1111
|
+
getClient(modelName, requestId) {
|
|
758
1112
|
const provider = this.modelToProviderMap[modelName];
|
|
759
1113
|
if (!provider) {
|
|
760
1114
|
throw new Error(`Unsupported model: ${modelName}`);
|
|
761
1115
|
}
|
|
762
1116
|
switch (provider) {
|
|
763
1117
|
case "openai":
|
|
764
|
-
return new OpenAIClient(
|
|
1118
|
+
return new OpenAIClient(
|
|
1119
|
+
this.logger,
|
|
1120
|
+
this.enableCaching,
|
|
1121
|
+
this.cache,
|
|
1122
|
+
requestId
|
|
1123
|
+
);
|
|
765
1124
|
case "anthropic":
|
|
766
|
-
return new AnthropicClient(
|
|
1125
|
+
return new AnthropicClient(
|
|
1126
|
+
this.logger,
|
|
1127
|
+
this.enableCaching,
|
|
1128
|
+
this.cache,
|
|
1129
|
+
requestId
|
|
1130
|
+
);
|
|
767
1131
|
default:
|
|
768
1132
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
769
1133
|
}
|
|
@@ -773,55 +1137,6 @@ var LLMProvider = class {
|
|
|
773
1137
|
// lib/index.ts
|
|
774
1138
|
var import_path2 = __toESM(require("path"));
|
|
775
1139
|
|
|
776
|
-
// lib/browserbase.ts
|
|
777
|
-
var Browserbase = class {
|
|
778
|
-
createSession() {
|
|
779
|
-
return __async(this, null, function* () {
|
|
780
|
-
if (!process.env.BROWSERBASE_API_KEY || !process.env.BROWSERBASE_PROJECT_ID) {
|
|
781
|
-
throw new Error(
|
|
782
|
-
"BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID must be set"
|
|
783
|
-
);
|
|
784
|
-
}
|
|
785
|
-
const response = yield fetch(`https://www.browserbase.com/v1/sessions`, {
|
|
786
|
-
method: "POST",
|
|
787
|
-
headers: {
|
|
788
|
-
"x-bb-api-key": `${process.env.BROWSERBASE_API_KEY}`,
|
|
789
|
-
"Content-Type": "application/json"
|
|
790
|
-
},
|
|
791
|
-
body: JSON.stringify({
|
|
792
|
-
projectId: process.env.BROWSERBASE_PROJECT_ID
|
|
793
|
-
})
|
|
794
|
-
});
|
|
795
|
-
const json = yield response.json();
|
|
796
|
-
if (json.error) {
|
|
797
|
-
throw new Error(json.error);
|
|
798
|
-
}
|
|
799
|
-
return {
|
|
800
|
-
sessionId: json.id,
|
|
801
|
-
connectUrl: json.connectUrl
|
|
802
|
-
};
|
|
803
|
-
});
|
|
804
|
-
}
|
|
805
|
-
retrieveDebugConnectionURL(sessionId) {
|
|
806
|
-
return __async(this, null, function* () {
|
|
807
|
-
if (!process.env.BROWSERBASE_API_KEY) {
|
|
808
|
-
throw new Error("BROWSERBASE_API_KEY must be set");
|
|
809
|
-
}
|
|
810
|
-
const response = yield fetch(
|
|
811
|
-
`https://www.browserbase.com/v1/sessions/${sessionId}/debug`,
|
|
812
|
-
{
|
|
813
|
-
method: "GET",
|
|
814
|
-
headers: {
|
|
815
|
-
"x-bb-api-key": `${process.env.BROWSERBASE_API_KEY}`
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
);
|
|
819
|
-
const json = yield response.json();
|
|
820
|
-
return json.debuggerFullscreenUrl;
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
};
|
|
824
|
-
|
|
825
1140
|
// lib/vision.ts
|
|
826
1141
|
var import_fs = __toESM(require("fs"));
|
|
827
1142
|
var import_path = __toESM(require("path"));
|
|
@@ -1004,40 +1319,85 @@ var ScreenshotService = class _ScreenshotService {
|
|
|
1004
1319
|
|
|
1005
1320
|
// lib/index.ts
|
|
1006
1321
|
require("dotenv").config({ path: ".env" });
|
|
1007
|
-
function getBrowser(env = "LOCAL", headless = false, logger) {
|
|
1322
|
+
function getBrowser(apiKey, projectId, env = "LOCAL", headless = false, logger, browserbaseSessionCreateParams, browserbaseResumeSessionID) {
|
|
1008
1323
|
return __async(this, null, function* () {
|
|
1009
|
-
if (env === "BROWSERBASE"
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1324
|
+
if (env === "BROWSERBASE") {
|
|
1325
|
+
if (!apiKey) {
|
|
1326
|
+
logger({
|
|
1327
|
+
category: "Init",
|
|
1328
|
+
message: "BROWSERBASE_API_KEY is required to use BROWSERBASE env. Defaulting to LOCAL.",
|
|
1329
|
+
level: 0
|
|
1330
|
+
});
|
|
1331
|
+
env = "LOCAL";
|
|
1332
|
+
}
|
|
1333
|
+
if (!projectId) {
|
|
1334
|
+
logger({
|
|
1335
|
+
category: "Init",
|
|
1336
|
+
message: "BROWSERBASE_PROJECT_ID is required for some Browserbase features that may not work without it.",
|
|
1337
|
+
level: 1
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1024
1340
|
}
|
|
1025
1341
|
if (env === "BROWSERBASE") {
|
|
1342
|
+
if (!apiKey) {
|
|
1343
|
+
throw new Error("BROWSERBASE_API_KEY is required.");
|
|
1344
|
+
}
|
|
1026
1345
|
let debugUrl = void 0;
|
|
1027
1346
|
let sessionUrl = void 0;
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1347
|
+
let sessionId;
|
|
1348
|
+
let connectUrl;
|
|
1349
|
+
const browserbase = new import_sdk2.Browserbase({
|
|
1350
|
+
apiKey
|
|
1032
1351
|
});
|
|
1033
|
-
|
|
1034
|
-
|
|
1352
|
+
if (browserbaseResumeSessionID) {
|
|
1353
|
+
try {
|
|
1354
|
+
const sessionStatus = yield browserbase.sessions.retrieve(
|
|
1355
|
+
browserbaseResumeSessionID
|
|
1356
|
+
);
|
|
1357
|
+
if (sessionStatus.status !== "RUNNING") {
|
|
1358
|
+
throw new Error(
|
|
1359
|
+
`Session ${browserbaseResumeSessionID} is not running (status: ${sessionStatus.status})`
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
sessionId = browserbaseResumeSessionID;
|
|
1363
|
+
connectUrl = `wss://connect.browserbase.com?apiKey=${apiKey}&sessionId=${sessionId}`;
|
|
1364
|
+
logger({
|
|
1365
|
+
category: "Init",
|
|
1366
|
+
message: "Resuming existing Browserbase session...",
|
|
1367
|
+
level: 0
|
|
1368
|
+
});
|
|
1369
|
+
} catch (error) {
|
|
1370
|
+
logger({
|
|
1371
|
+
category: "Init",
|
|
1372
|
+
message: `Failed to resume session ${browserbaseResumeSessionID}: ${error.message}`,
|
|
1373
|
+
level: 0
|
|
1374
|
+
});
|
|
1375
|
+
throw error;
|
|
1376
|
+
}
|
|
1377
|
+
} else {
|
|
1378
|
+
logger({
|
|
1379
|
+
category: "Init",
|
|
1380
|
+
message: "Creating new Browserbase session...",
|
|
1381
|
+
level: 0
|
|
1382
|
+
});
|
|
1383
|
+
if (!projectId) {
|
|
1384
|
+
throw new Error(
|
|
1385
|
+
"BROWSERBASE_PROJECT_ID is required for new Browserbase sessions."
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
const session = yield browserbase.sessions.create(__spreadValues({
|
|
1389
|
+
projectId
|
|
1390
|
+
}, browserbaseSessionCreateParams));
|
|
1391
|
+
sessionId = session.id;
|
|
1392
|
+
connectUrl = session.connectUrl;
|
|
1393
|
+
}
|
|
1035
1394
|
const browser = yield import_test.chromium.connectOverCDP(connectUrl);
|
|
1036
|
-
|
|
1395
|
+
const { debuggerUrl } = yield browserbase.sessions.debug(sessionId);
|
|
1396
|
+
debugUrl = debuggerUrl;
|
|
1037
1397
|
sessionUrl = `https://www.browserbase.com/sessions/${sessionId}`;
|
|
1038
1398
|
logger({
|
|
1039
1399
|
category: "Init",
|
|
1040
|
-
message: `Browserbase session started.
|
|
1400
|
+
message: `Browserbase session ${browserbaseResumeSessionID ? "resumed" : "started"}.
|
|
1041
1401
|
|
|
1042
1402
|
Session Url: ${sessionUrl}
|
|
1043
1403
|
|
|
@@ -1124,12 +1484,17 @@ function applyStealthScripts(context) {
|
|
|
1124
1484
|
var Stagehand = class {
|
|
1125
1485
|
constructor({
|
|
1126
1486
|
env,
|
|
1127
|
-
|
|
1128
|
-
|
|
1487
|
+
apiKey,
|
|
1488
|
+
projectId,
|
|
1489
|
+
verbose,
|
|
1490
|
+
debugDom,
|
|
1129
1491
|
llmProvider,
|
|
1130
|
-
headless
|
|
1492
|
+
headless,
|
|
1131
1493
|
logger,
|
|
1132
|
-
|
|
1494
|
+
browserBaseSessionCreateParams,
|
|
1495
|
+
domSettleTimeoutMs,
|
|
1496
|
+
enableCaching,
|
|
1497
|
+
browserbaseResumeSessionID
|
|
1133
1498
|
} = {
|
|
1134
1499
|
env: "BROWSERBASE"
|
|
1135
1500
|
}) {
|
|
@@ -1138,24 +1503,34 @@ var Stagehand = class {
|
|
|
1138
1503
|
this.is_processing_browserbase_logs = false;
|
|
1139
1504
|
this.externalLogger = logger;
|
|
1140
1505
|
this.logger = this.log.bind(this);
|
|
1141
|
-
this.
|
|
1506
|
+
this.enableCaching = enableCaching != null ? enableCaching : false;
|
|
1507
|
+
this.llmProvider = llmProvider || new LLMProvider(this.logger, this.enableCaching);
|
|
1142
1508
|
this.env = env;
|
|
1143
1509
|
this.observations = {};
|
|
1510
|
+
this.apiKey = apiKey;
|
|
1511
|
+
this.projectId = projectId;
|
|
1144
1512
|
this.actions = {};
|
|
1145
|
-
this.verbose = verbose;
|
|
1146
|
-
this.debugDom = debugDom;
|
|
1513
|
+
this.verbose = verbose != null ? verbose : 0;
|
|
1514
|
+
this.debugDom = debugDom != null ? debugDom : false;
|
|
1147
1515
|
this.defaultModelName = "gpt-4o";
|
|
1148
|
-
this.
|
|
1149
|
-
this.
|
|
1516
|
+
this.domSettleTimeoutMs = domSettleTimeoutMs != null ? domSettleTimeoutMs : 3e4;
|
|
1517
|
+
this.headless = headless != null ? headless : false;
|
|
1518
|
+
this.browserBaseSessionCreateParams = browserBaseSessionCreateParams;
|
|
1519
|
+
this.browserbaseResumeSessionID = browserbaseResumeSessionID;
|
|
1150
1520
|
}
|
|
1151
1521
|
init() {
|
|
1152
1522
|
return __async(this, arguments, function* ({
|
|
1153
1523
|
modelName = "gpt-4o"
|
|
1154
1524
|
} = {}) {
|
|
1525
|
+
console.log("haha fucker");
|
|
1155
1526
|
const { context, debugUrl, sessionUrl } = yield getBrowser(
|
|
1527
|
+
this.apiKey,
|
|
1528
|
+
this.projectId,
|
|
1156
1529
|
this.env,
|
|
1157
1530
|
this.headless,
|
|
1158
|
-
this.logger
|
|
1531
|
+
this.logger,
|
|
1532
|
+
this.browserBaseSessionCreateParams,
|
|
1533
|
+
this.browserbaseResumeSessionID
|
|
1159
1534
|
).catch((e) => {
|
|
1160
1535
|
console.error("Error in init:", e);
|
|
1161
1536
|
return { context: void 0, debugUrl: void 0, sessionUrl: void 0 };
|
|
@@ -1173,14 +1548,23 @@ var Stagehand = class {
|
|
|
1173
1548
|
if (this.headless) {
|
|
1174
1549
|
yield this.page.setViewportSize({ width: 1280, height: 720 });
|
|
1175
1550
|
}
|
|
1176
|
-
yield this.
|
|
1177
|
-
|
|
1551
|
+
yield this.context.addInitScript({
|
|
1552
|
+
content: import_fs2.default.readFileSync(
|
|
1553
|
+
import_path2.default.join(__dirname, "..", "dist", "dom", "build", "process.js"),
|
|
1554
|
+
"utf8"
|
|
1555
|
+
)
|
|
1178
1556
|
});
|
|
1179
|
-
yield this.
|
|
1180
|
-
|
|
1557
|
+
yield this.context.addInitScript({
|
|
1558
|
+
content: import_fs2.default.readFileSync(
|
|
1559
|
+
import_path2.default.join(__dirname, "..", "dist", "dom", "build", "utils.js"),
|
|
1560
|
+
"utf8"
|
|
1561
|
+
)
|
|
1181
1562
|
});
|
|
1182
|
-
yield this.
|
|
1183
|
-
|
|
1563
|
+
yield this.context.addInitScript({
|
|
1564
|
+
content: import_fs2.default.readFileSync(
|
|
1565
|
+
import_path2.default.join(__dirname, "..", "dist", "dom", "build", "debug.js"),
|
|
1566
|
+
"utf8"
|
|
1567
|
+
)
|
|
1184
1568
|
});
|
|
1185
1569
|
return { debugUrl, sessionUrl };
|
|
1186
1570
|
});
|
|
@@ -1271,11 +1655,9 @@ var Stagehand = class {
|
|
|
1271
1655
|
return __async(this, null, function* () {
|
|
1272
1656
|
try {
|
|
1273
1657
|
const timeout = timeoutMs != null ? timeoutMs : this.domSettleTimeoutMs;
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
`[stagehand:dom] DOM settle timeout of ${timeout}ms exceeded, continuing anyway`
|
|
1278
|
-
);
|
|
1658
|
+
let timeoutHandle;
|
|
1659
|
+
const timeoutPromise = new Promise((resolve, reject) => {
|
|
1660
|
+
timeoutHandle = setTimeout(() => {
|
|
1279
1661
|
this.log({
|
|
1280
1662
|
category: "dom",
|
|
1281
1663
|
message: `DOM settle timeout of ${timeout}ms exceeded, continuing anyway`,
|
|
@@ -1284,16 +1666,12 @@ var Stagehand = class {
|
|
|
1284
1666
|
resolve();
|
|
1285
1667
|
}, timeout);
|
|
1286
1668
|
});
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
yield this.page.waitForLoadState("domcontentloaded");
|
|
1291
|
-
yield this.page.evaluate(() => {
|
|
1669
|
+
try {
|
|
1670
|
+
yield Promise.race([
|
|
1671
|
+
this.page.evaluate(() => {
|
|
1292
1672
|
return new Promise((resolve) => {
|
|
1293
1673
|
if (typeof window.waitForDomSettle === "function") {
|
|
1294
|
-
window.waitForDomSettle().then(
|
|
1295
|
-
resolve();
|
|
1296
|
-
});
|
|
1674
|
+
window.waitForDomSettle().then(resolve);
|
|
1297
1675
|
} else {
|
|
1298
1676
|
console.warn(
|
|
1299
1677
|
"waitForDomSettle is not defined, considering DOM as settled"
|
|
@@ -1301,10 +1679,14 @@ var Stagehand = class {
|
|
|
1301
1679
|
resolve();
|
|
1302
1680
|
}
|
|
1303
1681
|
});
|
|
1304
|
-
})
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1682
|
+
}),
|
|
1683
|
+
this.page.waitForLoadState("domcontentloaded"),
|
|
1684
|
+
this.page.waitForSelector("body"),
|
|
1685
|
+
timeoutPromise
|
|
1686
|
+
]);
|
|
1687
|
+
} finally {
|
|
1688
|
+
clearTimeout(timeoutHandle);
|
|
1689
|
+
}
|
|
1308
1690
|
} catch (e) {
|
|
1309
1691
|
this.log({
|
|
1310
1692
|
category: "dom",
|
|
@@ -1374,14 +1756,16 @@ Trace: ${e.stack}`,
|
|
|
1374
1756
|
progress = "",
|
|
1375
1757
|
content = {},
|
|
1376
1758
|
chunksSeen = [],
|
|
1377
|
-
modelName
|
|
1759
|
+
modelName,
|
|
1760
|
+
requestId,
|
|
1761
|
+
domSettleTimeoutMs
|
|
1378
1762
|
}) {
|
|
1379
1763
|
this.log({
|
|
1380
1764
|
category: "extraction",
|
|
1381
1765
|
message: `starting extraction '${instruction}'`,
|
|
1382
1766
|
level: 1
|
|
1383
1767
|
});
|
|
1384
|
-
yield this._waitForSettledDom();
|
|
1768
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1385
1769
|
yield this.startDomDebug();
|
|
1386
1770
|
const { outputString, chunk, chunks } = yield this.page.evaluate(
|
|
1387
1771
|
(chunksSeen2) => window.processDom(chunksSeen2 != null ? chunksSeen2 : []),
|
|
@@ -1401,7 +1785,8 @@ Trace: ${e.stack}`,
|
|
|
1401
1785
|
schema,
|
|
1402
1786
|
modelName: modelName || this.defaultModelName,
|
|
1403
1787
|
chunksSeen: chunksSeen.length,
|
|
1404
|
-
chunksTotal: chunks.length
|
|
1788
|
+
chunksTotal: chunks.length,
|
|
1789
|
+
requestId
|
|
1405
1790
|
});
|
|
1406
1791
|
const _a = extractionResponse, {
|
|
1407
1792
|
metadata: { progress: newProgress, completed }
|
|
@@ -1428,14 +1813,15 @@ Trace: ${e.stack}`,
|
|
|
1428
1813
|
message: `continuing extraction, progress: '${newProgress}'`,
|
|
1429
1814
|
level: 1
|
|
1430
1815
|
});
|
|
1431
|
-
yield this._waitForSettledDom();
|
|
1816
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1432
1817
|
return this._extract({
|
|
1433
1818
|
instruction,
|
|
1434
1819
|
schema,
|
|
1435
1820
|
progress: newProgress,
|
|
1436
1821
|
content: output,
|
|
1437
1822
|
chunksSeen,
|
|
1438
|
-
modelName
|
|
1823
|
+
modelName,
|
|
1824
|
+
domSettleTimeoutMs
|
|
1439
1825
|
});
|
|
1440
1826
|
}
|
|
1441
1827
|
});
|
|
@@ -1445,7 +1831,9 @@ Trace: ${e.stack}`,
|
|
|
1445
1831
|
instruction,
|
|
1446
1832
|
useVision,
|
|
1447
1833
|
fullPage,
|
|
1448
|
-
modelName
|
|
1834
|
+
modelName,
|
|
1835
|
+
requestId,
|
|
1836
|
+
domSettleTimeoutMs
|
|
1449
1837
|
}) {
|
|
1450
1838
|
if (!instruction) {
|
|
1451
1839
|
instruction = `Find elements that can be used for any future actions in the page. These may be navigation links, related pages, section/subsection links, buttons, or other interactive elements. Be comprehensive: if there are multiple elements that may be relevant for future actions, return all of them.`;
|
|
@@ -1456,7 +1844,7 @@ Trace: ${e.stack}`,
|
|
|
1456
1844
|
message: `starting observation: ${instruction}`,
|
|
1457
1845
|
level: 1
|
|
1458
1846
|
});
|
|
1459
|
-
yield this._waitForSettledDom();
|
|
1847
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1460
1848
|
yield this.startDomDebug();
|
|
1461
1849
|
let { outputString, selectorMap } = yield this.page.evaluate(
|
|
1462
1850
|
(fullPage2) => fullPage2 ? window.processAllOfDom() : window.processDom([]),
|
|
@@ -1485,7 +1873,8 @@ Trace: ${e.stack}`,
|
|
|
1485
1873
|
domElements: outputString,
|
|
1486
1874
|
llmProvider: this.llmProvider,
|
|
1487
1875
|
modelName: modelName || this.defaultModelName,
|
|
1488
|
-
image: annotatedScreenshot
|
|
1876
|
+
image: annotatedScreenshot,
|
|
1877
|
+
requestId
|
|
1489
1878
|
});
|
|
1490
1879
|
const elementsWithSelectors = observationResponse.elements.map(
|
|
1491
1880
|
(element) => {
|
|
@@ -1514,7 +1903,9 @@ Trace: ${e.stack}`,
|
|
|
1514
1903
|
modelName,
|
|
1515
1904
|
useVision,
|
|
1516
1905
|
verifierUseVision,
|
|
1517
|
-
retries = 0
|
|
1906
|
+
retries = 0,
|
|
1907
|
+
requestId,
|
|
1908
|
+
domSettleTimeoutMs
|
|
1518
1909
|
}) {
|
|
1519
1910
|
var _a;
|
|
1520
1911
|
const model = modelName != null ? modelName : this.defaultModelName;
|
|
@@ -1532,7 +1923,7 @@ Trace: ${e.stack}`,
|
|
|
1532
1923
|
message: `Running / Continuing action: ${action} on page: ${this.page.url()}`,
|
|
1533
1924
|
level: 2
|
|
1534
1925
|
});
|
|
1535
|
-
yield this._waitForSettledDom();
|
|
1926
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1536
1927
|
yield this.startDomDebug();
|
|
1537
1928
|
this.log({
|
|
1538
1929
|
category: "action",
|
|
@@ -1574,7 +1965,8 @@ Trace: ${e.stack}`,
|
|
|
1574
1965
|
llmProvider: this.llmProvider,
|
|
1575
1966
|
modelName: model,
|
|
1576
1967
|
screenshot: annotatedScreenshot,
|
|
1577
|
-
logger: this.logger
|
|
1968
|
+
logger: this.logger,
|
|
1969
|
+
requestId
|
|
1578
1970
|
});
|
|
1579
1971
|
this.log({
|
|
1580
1972
|
category: "action",
|
|
@@ -1596,7 +1988,9 @@ Trace: ${e.stack}`,
|
|
|
1596
1988
|
chunksSeen,
|
|
1597
1989
|
modelName,
|
|
1598
1990
|
useVision,
|
|
1599
|
-
verifierUseVision
|
|
1991
|
+
verifierUseVision,
|
|
1992
|
+
requestId,
|
|
1993
|
+
domSettleTimeoutMs
|
|
1600
1994
|
});
|
|
1601
1995
|
} else if (useVision === "fallback") {
|
|
1602
1996
|
this.log({
|
|
@@ -1611,9 +2005,14 @@ Trace: ${e.stack}`,
|
|
|
1611
2005
|
chunksSeen,
|
|
1612
2006
|
modelName,
|
|
1613
2007
|
useVision: true,
|
|
1614
|
-
verifierUseVision
|
|
2008
|
+
verifierUseVision,
|
|
2009
|
+
requestId,
|
|
2010
|
+
domSettleTimeoutMs
|
|
1615
2011
|
});
|
|
1616
2012
|
} else {
|
|
2013
|
+
if (this.enableCaching) {
|
|
2014
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2015
|
+
}
|
|
1617
2016
|
return {
|
|
1618
2017
|
success: false,
|
|
1619
2018
|
message: `Action was not able to be completed.`,
|
|
@@ -1670,7 +2069,9 @@ Trace: ${e.stack}`,
|
|
|
1670
2069
|
useVision,
|
|
1671
2070
|
verifierUseVision,
|
|
1672
2071
|
retries: retries + 1,
|
|
1673
|
-
chunksSeen
|
|
2072
|
+
chunksSeen,
|
|
2073
|
+
requestId,
|
|
2074
|
+
domSettleTimeoutMs
|
|
1674
2075
|
});
|
|
1675
2076
|
}
|
|
1676
2077
|
}
|
|
@@ -1699,7 +2100,9 @@ Trace: ${e.stack}`,
|
|
|
1699
2100
|
useVision,
|
|
1700
2101
|
verifierUseVision,
|
|
1701
2102
|
retries: retries + 1,
|
|
1702
|
-
chunksSeen
|
|
2103
|
+
chunksSeen,
|
|
2104
|
+
requestId,
|
|
2105
|
+
domSettleTimeoutMs
|
|
1703
2106
|
});
|
|
1704
2107
|
}
|
|
1705
2108
|
}
|
|
@@ -1722,7 +2125,9 @@ Trace: ${e.stack}`,
|
|
|
1722
2125
|
useVision,
|
|
1723
2126
|
verifierUseVision,
|
|
1724
2127
|
retries: retries + 1,
|
|
1725
|
-
chunksSeen
|
|
2128
|
+
chunksSeen,
|
|
2129
|
+
requestId,
|
|
2130
|
+
domSettleTimeoutMs
|
|
1726
2131
|
});
|
|
1727
2132
|
}
|
|
1728
2133
|
}
|
|
@@ -1751,7 +2156,9 @@ Trace: ${e.stack}`,
|
|
|
1751
2156
|
useVision,
|
|
1752
2157
|
verifierUseVision,
|
|
1753
2158
|
retries: retries + 1,
|
|
1754
|
-
chunksSeen
|
|
2159
|
+
chunksSeen,
|
|
2160
|
+
requestId,
|
|
2161
|
+
domSettleTimeoutMs
|
|
1755
2162
|
});
|
|
1756
2163
|
}
|
|
1757
2164
|
}
|
|
@@ -1781,7 +2188,7 @@ Trace: ${e.stack}`,
|
|
|
1781
2188
|
yield newOpenedTab.close();
|
|
1782
2189
|
yield this.page.goto(newOpenedTab.url());
|
|
1783
2190
|
yield this.page.waitForLoadState("domcontentloaded");
|
|
1784
|
-
yield this._waitForSettledDom();
|
|
2191
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1785
2192
|
}
|
|
1786
2193
|
yield Promise.race([
|
|
1787
2194
|
this.page.waitForLoadState("networkidle"),
|
|
@@ -1820,9 +2227,14 @@ Trace: ${e.stack}`,
|
|
|
1820
2227
|
useVision,
|
|
1821
2228
|
verifierUseVision,
|
|
1822
2229
|
retries: retries + 1,
|
|
1823
|
-
chunksSeen
|
|
2230
|
+
chunksSeen,
|
|
2231
|
+
requestId,
|
|
2232
|
+
domSettleTimeoutMs
|
|
1824
2233
|
});
|
|
1825
2234
|
} else {
|
|
2235
|
+
if (this.enableCaching) {
|
|
2236
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2237
|
+
}
|
|
1826
2238
|
return {
|
|
1827
2239
|
success: false,
|
|
1828
2240
|
message: `Internal error: Chosen method ${method} is invalid`,
|
|
@@ -1889,7 +2301,8 @@ Trace: ${e.stack}`,
|
|
|
1889
2301
|
modelName: model,
|
|
1890
2302
|
screenshot: fullpageScreenshot,
|
|
1891
2303
|
domElements,
|
|
1892
|
-
logger: this.logger
|
|
2304
|
+
logger: this.logger,
|
|
2305
|
+
requestId
|
|
1893
2306
|
});
|
|
1894
2307
|
this.log({
|
|
1895
2308
|
category: "action",
|
|
@@ -1909,7 +2322,9 @@ Trace: ${e.stack}`,
|
|
|
1909
2322
|
modelName,
|
|
1910
2323
|
chunksSeen,
|
|
1911
2324
|
useVision,
|
|
1912
|
-
verifierUseVision
|
|
2325
|
+
verifierUseVision,
|
|
2326
|
+
requestId,
|
|
2327
|
+
domSettleTimeoutMs
|
|
1913
2328
|
});
|
|
1914
2329
|
} else {
|
|
1915
2330
|
this.log({
|
|
@@ -1939,10 +2354,15 @@ Trace: ${error.stack}`,
|
|
|
1939
2354
|
useVision,
|
|
1940
2355
|
verifierUseVision,
|
|
1941
2356
|
retries: retries + 1,
|
|
1942
|
-
chunksSeen
|
|
2357
|
+
chunksSeen,
|
|
2358
|
+
requestId,
|
|
2359
|
+
domSettleTimeoutMs
|
|
1943
2360
|
});
|
|
1944
2361
|
}
|
|
1945
2362
|
yield this._recordAction(action, "");
|
|
2363
|
+
if (this.enableCaching) {
|
|
2364
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2365
|
+
}
|
|
1946
2366
|
return {
|
|
1947
2367
|
success: false,
|
|
1948
2368
|
message: `Error performing action: ${error.message}`,
|
|
@@ -1955,15 +2375,37 @@ Trace: ${error.stack}`,
|
|
|
1955
2375
|
return __async(this, arguments, function* ({
|
|
1956
2376
|
action,
|
|
1957
2377
|
modelName,
|
|
1958
|
-
useVision = "fallback"
|
|
2378
|
+
useVision = "fallback",
|
|
2379
|
+
domSettleTimeoutMs
|
|
1959
2380
|
}) {
|
|
1960
2381
|
useVision = useVision != null ? useVision : "fallback";
|
|
2382
|
+
const requestId = Math.random().toString(36).substring(2);
|
|
2383
|
+
this.logger({
|
|
2384
|
+
category: "act",
|
|
2385
|
+
message: `Running act with action: ${action}, requestId: ${requestId}`
|
|
2386
|
+
});
|
|
1961
2387
|
return this._act({
|
|
1962
2388
|
action,
|
|
1963
2389
|
modelName,
|
|
1964
2390
|
chunksSeen: [],
|
|
1965
2391
|
useVision,
|
|
1966
|
-
verifierUseVision: useVision !== false
|
|
2392
|
+
verifierUseVision: useVision !== false,
|
|
2393
|
+
requestId,
|
|
2394
|
+
domSettleTimeoutMs
|
|
2395
|
+
}).catch((e) => {
|
|
2396
|
+
this.logger({
|
|
2397
|
+
category: "act",
|
|
2398
|
+
message: `Error acting: ${e.message}
|
|
2399
|
+
Trace: ${e.stack}`
|
|
2400
|
+
});
|
|
2401
|
+
if (this.enableCaching) {
|
|
2402
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2403
|
+
}
|
|
2404
|
+
return {
|
|
2405
|
+
success: false,
|
|
2406
|
+
message: `Internal error: Error acting: ${e.message}`,
|
|
2407
|
+
action
|
|
2408
|
+
};
|
|
1967
2409
|
});
|
|
1968
2410
|
});
|
|
1969
2411
|
}
|
|
@@ -1971,23 +2413,58 @@ Trace: ${error.stack}`,
|
|
|
1971
2413
|
return __async(this, arguments, function* ({
|
|
1972
2414
|
instruction,
|
|
1973
2415
|
schema,
|
|
1974
|
-
modelName
|
|
2416
|
+
modelName,
|
|
2417
|
+
domSettleTimeoutMs
|
|
1975
2418
|
}) {
|
|
2419
|
+
const requestId = Math.random().toString(36).substring(2);
|
|
2420
|
+
this.logger({
|
|
2421
|
+
category: "extract",
|
|
2422
|
+
message: `Running extract with instruction: ${instruction}, requestId: ${requestId}`
|
|
2423
|
+
});
|
|
1976
2424
|
return this._extract({
|
|
1977
2425
|
instruction,
|
|
1978
2426
|
schema,
|
|
1979
|
-
modelName
|
|
2427
|
+
modelName,
|
|
2428
|
+
requestId,
|
|
2429
|
+
domSettleTimeoutMs
|
|
2430
|
+
}).catch((e) => {
|
|
2431
|
+
this.logger({
|
|
2432
|
+
category: "extract",
|
|
2433
|
+
message: `Internal error: Error extracting: ${e.message}
|
|
2434
|
+
Trace: ${e.stack}`
|
|
2435
|
+
});
|
|
2436
|
+
if (this.enableCaching) {
|
|
2437
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2438
|
+
}
|
|
2439
|
+
throw e;
|
|
1980
2440
|
});
|
|
1981
2441
|
});
|
|
1982
2442
|
}
|
|
1983
2443
|
observe(options) {
|
|
1984
2444
|
return __async(this, null, function* () {
|
|
1985
2445
|
var _a, _b;
|
|
2446
|
+
const requestId = Math.random().toString(36).substring(2);
|
|
2447
|
+
this.logger({
|
|
2448
|
+
category: "observe",
|
|
2449
|
+
message: `Running observe with instruction: ${options == null ? void 0 : options.instruction}, requestId: ${requestId}`
|
|
2450
|
+
});
|
|
1986
2451
|
return this._observe({
|
|
1987
2452
|
instruction: (_a = options == null ? void 0 : options.instruction) != null ? _a : "Find actions that can be performed on this page.",
|
|
1988
2453
|
modelName: options == null ? void 0 : options.modelName,
|
|
1989
2454
|
useVision: (_b = options == null ? void 0 : options.useVision) != null ? _b : false,
|
|
1990
|
-
fullPage: false
|
|
2455
|
+
fullPage: false,
|
|
2456
|
+
requestId,
|
|
2457
|
+
domSettleTimeoutMs: options == null ? void 0 : options.domSettleTimeoutMs
|
|
2458
|
+
}).catch((e) => {
|
|
2459
|
+
this.logger({
|
|
2460
|
+
category: "observe",
|
|
2461
|
+
message: `Error observing: ${e.message}
|
|
2462
|
+
Trace: ${e.stack}`
|
|
2463
|
+
});
|
|
2464
|
+
if (this.enableCaching) {
|
|
2465
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2466
|
+
}
|
|
2467
|
+
throw e;
|
|
1991
2468
|
});
|
|
1992
2469
|
});
|
|
1993
2470
|
}
|