@browserbasehq/stagehand 1.0.3-alpha.2 → 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/dom/build/types.js +2 -0
- 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 +25 -6
- package/dist/index.js +666 -151
- 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 = `
|
|
@@ -283,8 +284,10 @@ var metadataSystemPrompt = `You are an AI assistant tasked with evaluating the p
|
|
|
283
284
|
Analyze the extraction response and determine if the task is completed or if more information is needed.
|
|
284
285
|
|
|
285
286
|
Strictly abide by the following criteria:
|
|
286
|
-
1.
|
|
287
|
-
2.
|
|
287
|
+
1. Once the instruction has been satisfied by the current extraction response, ALWAYS set completion status to true and stop processing, regardless of remaining chunks.
|
|
288
|
+
2. Only set completion status to false if BOTH of these conditions are true:
|
|
289
|
+
- The instruction has not been satisfied yet
|
|
290
|
+
- There are still chunks left to process (chunksTotal > chunksSeen)`;
|
|
288
291
|
function buildMetadataSystemPrompt() {
|
|
289
292
|
return {
|
|
290
293
|
role: "system",
|
|
@@ -296,8 +299,8 @@ function buildMetadataPrompt(instruction, extractionResponse, chunksSeen, chunks
|
|
|
296
299
|
role: "user",
|
|
297
300
|
content: `Instruction: ${instruction}
|
|
298
301
|
Extracted content: ${JSON.stringify(extractionResponse, null, 2)}
|
|
299
|
-
|
|
300
|
-
|
|
302
|
+
chunksSeen: ${chunksSeen}
|
|
303
|
+
chunksTotal: ${chunksTotal}`
|
|
301
304
|
};
|
|
302
305
|
}
|
|
303
306
|
var observeSystemPrompt = `
|
|
@@ -332,6 +335,7 @@ var modelsWithVision = [
|
|
|
332
335
|
"gpt-4o-mini",
|
|
333
336
|
"claude-3-5-sonnet-latest",
|
|
334
337
|
"claude-3-5-sonnet-20240620",
|
|
338
|
+
"claude-3-5-sonnet-20241022",
|
|
335
339
|
"gpt-4o-2024-08-06"
|
|
336
340
|
];
|
|
337
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.";
|
|
@@ -345,9 +349,10 @@ function verifyActCompletion(_0) {
|
|
|
345
349
|
modelName,
|
|
346
350
|
screenshot,
|
|
347
351
|
domElements,
|
|
348
|
-
logger
|
|
352
|
+
logger,
|
|
353
|
+
requestId
|
|
349
354
|
}) {
|
|
350
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
355
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
351
356
|
const messages = [
|
|
352
357
|
buildVerifyActCompletionSystemPrompt(),
|
|
353
358
|
buildVerifyActCompletionUserPrompt(goal, steps, domElements)
|
|
@@ -396,9 +401,10 @@ function act(_0) {
|
|
|
396
401
|
modelName,
|
|
397
402
|
screenshot,
|
|
398
403
|
retries = 0,
|
|
399
|
-
logger
|
|
404
|
+
logger,
|
|
405
|
+
requestId
|
|
400
406
|
}) {
|
|
401
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
407
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
402
408
|
const messages = [
|
|
403
409
|
buildActSystemPrompt(),
|
|
404
410
|
buildActUserPrompt(action, steps, domElements)
|
|
@@ -435,7 +441,8 @@ function act(_0) {
|
|
|
435
441
|
llmProvider,
|
|
436
442
|
modelName,
|
|
437
443
|
retries: retries + 1,
|
|
438
|
-
logger
|
|
444
|
+
logger,
|
|
445
|
+
requestId
|
|
439
446
|
});
|
|
440
447
|
}
|
|
441
448
|
});
|
|
@@ -450,9 +457,10 @@ function extract(_0) {
|
|
|
450
457
|
llmProvider,
|
|
451
458
|
modelName,
|
|
452
459
|
chunksSeen,
|
|
453
|
-
chunksTotal
|
|
460
|
+
chunksTotal,
|
|
461
|
+
requestId
|
|
454
462
|
}) {
|
|
455
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
463
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
456
464
|
const extractionResponse = yield llmClient.createChatCompletion({
|
|
457
465
|
model: modelName,
|
|
458
466
|
messages: [
|
|
@@ -525,7 +533,8 @@ function observe(_0) {
|
|
|
525
533
|
domElements,
|
|
526
534
|
llmProvider,
|
|
527
535
|
modelName,
|
|
528
|
-
image
|
|
536
|
+
image,
|
|
537
|
+
requestId
|
|
529
538
|
}) {
|
|
530
539
|
const observeSchema = import_zod.z.object({
|
|
531
540
|
elements: import_zod.z.array(
|
|
@@ -537,7 +546,7 @@ function observe(_0) {
|
|
|
537
546
|
})
|
|
538
547
|
).describe("an array of elements that match the instruction")
|
|
539
548
|
});
|
|
540
|
-
const llmClient = llmProvider.getClient(modelName);
|
|
549
|
+
const llmClient = llmProvider.getClient(modelName, requestId);
|
|
541
550
|
const observationResponse = yield llmClient.createChatCompletion({
|
|
542
551
|
model: modelName,
|
|
543
552
|
messages: [
|
|
@@ -565,12 +574,31 @@ function observe(_0) {
|
|
|
565
574
|
var import_openai = __toESM(require("openai"));
|
|
566
575
|
var import_zod2 = require("openai/helpers/zod");
|
|
567
576
|
var OpenAIClient = class {
|
|
568
|
-
constructor(logger) {
|
|
577
|
+
constructor(logger, enableCaching = false, cache, requestId) {
|
|
569
578
|
this.client = new import_openai.default();
|
|
570
579
|
this.logger = logger;
|
|
580
|
+
this.requestId = requestId;
|
|
581
|
+
this.cache = cache;
|
|
582
|
+
this.enableCaching = enableCaching;
|
|
571
583
|
}
|
|
572
584
|
createChatCompletion(options) {
|
|
573
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
|
+
}
|
|
574
602
|
if (options.image) {
|
|
575
603
|
const screenshotMessage = {
|
|
576
604
|
role: "user",
|
|
@@ -600,8 +628,18 @@ var OpenAIClient = class {
|
|
|
600
628
|
if (response_model) {
|
|
601
629
|
const extractedData = response.choices[0].message.content;
|
|
602
630
|
const parsedData = JSON.parse(extractedData);
|
|
631
|
+
if (this.enableCaching) {
|
|
632
|
+
this.cache.set(
|
|
633
|
+
cacheOptions,
|
|
634
|
+
__spreadValues({}, parsedData),
|
|
635
|
+
this.requestId
|
|
636
|
+
);
|
|
637
|
+
}
|
|
603
638
|
return __spreadValues({}, parsedData);
|
|
604
639
|
}
|
|
640
|
+
if (this.enableCaching) {
|
|
641
|
+
this.cache.set(cacheOptions, response, this.requestId);
|
|
642
|
+
}
|
|
605
643
|
return response;
|
|
606
644
|
});
|
|
607
645
|
}
|
|
@@ -611,16 +649,33 @@ var OpenAIClient = class {
|
|
|
611
649
|
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
612
650
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
613
651
|
var AnthropicClient = class {
|
|
614
|
-
constructor(logger) {
|
|
652
|
+
constructor(logger, enableCaching = false, cache, requestId) {
|
|
615
653
|
this.client = new import_sdk.default({
|
|
616
654
|
apiKey: process.env.ANTHROPIC_API_KEY
|
|
617
|
-
// Make sure to set this environment variable
|
|
618
655
|
});
|
|
619
656
|
this.logger = logger;
|
|
657
|
+
this.cache = cache;
|
|
658
|
+
this.enableCaching = enableCaching;
|
|
659
|
+
this.requestId = requestId;
|
|
620
660
|
}
|
|
621
661
|
createChatCompletion(options) {
|
|
622
662
|
return __async(this, null, function* () {
|
|
623
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
|
+
}
|
|
624
679
|
const systemMessage = options.messages.find((msg) => msg.role === "system");
|
|
625
680
|
const userMessages = options.messages.filter(
|
|
626
681
|
(msg) => msg.role !== "system"
|
|
@@ -722,26 +777,318 @@ var AnthropicClient = class {
|
|
|
722
777
|
if (options.response_model) {
|
|
723
778
|
const toolUse = response.content.find((c) => c.type === "tool_use");
|
|
724
779
|
if (toolUse && "input" in toolUse) {
|
|
725
|
-
|
|
780
|
+
const result = toolUse.input;
|
|
781
|
+
if (this.enableCaching) {
|
|
782
|
+
this.cache.set(cacheOptions, result, this.requestId);
|
|
783
|
+
}
|
|
784
|
+
return result;
|
|
726
785
|
} else {
|
|
727
|
-
if (!options.retries || options.retries <
|
|
786
|
+
if (!options.retries || options.retries < 5) {
|
|
728
787
|
return this.createChatCompletion(__spreadProps(__spreadValues({}, options), {
|
|
729
788
|
retries: ((_g = options.retries) != null ? _g : 0) + 1
|
|
730
789
|
}));
|
|
731
790
|
}
|
|
732
791
|
throw new Error(
|
|
733
|
-
"
|
|
792
|
+
"Create Chat Completion Failed: No tool use with input in response"
|
|
734
793
|
);
|
|
735
794
|
}
|
|
736
795
|
}
|
|
796
|
+
if (this.enableCaching) {
|
|
797
|
+
this.cache.set(cacheOptions, transformedResponse, this.requestId);
|
|
798
|
+
}
|
|
737
799
|
return transformedResponse;
|
|
738
800
|
});
|
|
739
801
|
}
|
|
740
802
|
};
|
|
741
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
|
+
|
|
742
1089
|
// lib/llm/LLMProvider.ts
|
|
743
1090
|
var LLMProvider = class {
|
|
744
|
-
constructor(logger) {
|
|
1091
|
+
constructor(logger, enableCaching) {
|
|
745
1092
|
this.modelToProviderMap = {
|
|
746
1093
|
"gpt-4o": "openai",
|
|
747
1094
|
"gpt-4o-mini": "openai",
|
|
@@ -751,71 +1098,44 @@ var LLMProvider = class {
|
|
|
751
1098
|
"claude-3-5-sonnet-20241022": "anthropic"
|
|
752
1099
|
};
|
|
753
1100
|
this.logger = logger;
|
|
1101
|
+
this.enableCaching = enableCaching;
|
|
1102
|
+
this.cache = new LLMCache(logger);
|
|
1103
|
+
}
|
|
1104
|
+
cleanRequestCache(requestId) {
|
|
1105
|
+
this.logger({
|
|
1106
|
+
category: "llm_cache",
|
|
1107
|
+
message: `Cleaning up cache for requestId: ${requestId}`
|
|
1108
|
+
});
|
|
1109
|
+
this.cache.deleteCacheForRequestId(requestId);
|
|
754
1110
|
}
|
|
755
|
-
getClient(modelName) {
|
|
1111
|
+
getClient(modelName, requestId) {
|
|
756
1112
|
const provider = this.modelToProviderMap[modelName];
|
|
757
1113
|
if (!provider) {
|
|
758
1114
|
throw new Error(`Unsupported model: ${modelName}`);
|
|
759
1115
|
}
|
|
760
1116
|
switch (provider) {
|
|
761
1117
|
case "openai":
|
|
762
|
-
return new OpenAIClient(
|
|
1118
|
+
return new OpenAIClient(
|
|
1119
|
+
this.logger,
|
|
1120
|
+
this.enableCaching,
|
|
1121
|
+
this.cache,
|
|
1122
|
+
requestId
|
|
1123
|
+
);
|
|
763
1124
|
case "anthropic":
|
|
764
|
-
return new AnthropicClient(
|
|
1125
|
+
return new AnthropicClient(
|
|
1126
|
+
this.logger,
|
|
1127
|
+
this.enableCaching,
|
|
1128
|
+
this.cache,
|
|
1129
|
+
requestId
|
|
1130
|
+
);
|
|
765
1131
|
default:
|
|
766
1132
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
767
1133
|
}
|
|
768
1134
|
}
|
|
769
1135
|
};
|
|
770
1136
|
|
|
771
|
-
// lib/
|
|
772
|
-
var
|
|
773
|
-
createSession() {
|
|
774
|
-
return __async(this, null, function* () {
|
|
775
|
-
if (!process.env.BROWSERBASE_API_KEY || !process.env.BROWSERBASE_PROJECT_ID) {
|
|
776
|
-
throw new Error(
|
|
777
|
-
"BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID must be set"
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
|
-
const response = yield fetch(`https://www.browserbase.com/v1/sessions`, {
|
|
781
|
-
method: "POST",
|
|
782
|
-
headers: {
|
|
783
|
-
"x-bb-api-key": `${process.env.BROWSERBASE_API_KEY}`,
|
|
784
|
-
"Content-Type": "application/json"
|
|
785
|
-
},
|
|
786
|
-
body: JSON.stringify({
|
|
787
|
-
projectId: process.env.BROWSERBASE_PROJECT_ID
|
|
788
|
-
})
|
|
789
|
-
});
|
|
790
|
-
const json = yield response.json();
|
|
791
|
-
if (json.error) {
|
|
792
|
-
throw new Error(json.error);
|
|
793
|
-
}
|
|
794
|
-
return {
|
|
795
|
-
sessionId: json.id,
|
|
796
|
-
connectUrl: json.connectUrl
|
|
797
|
-
};
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
retrieveDebugConnectionURL(sessionId) {
|
|
801
|
-
return __async(this, null, function* () {
|
|
802
|
-
if (!process.env.BROWSERBASE_API_KEY) {
|
|
803
|
-
throw new Error("BROWSERBASE_API_KEY must be set");
|
|
804
|
-
}
|
|
805
|
-
const response = yield fetch(
|
|
806
|
-
`https://www.browserbase.com/v1/sessions/${sessionId}/debug`,
|
|
807
|
-
{
|
|
808
|
-
method: "GET",
|
|
809
|
-
headers: {
|
|
810
|
-
"x-bb-api-key": `${process.env.BROWSERBASE_API_KEY}`
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
);
|
|
814
|
-
const json = yield response.json();
|
|
815
|
-
return json.debuggerFullscreenUrl;
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
};
|
|
1137
|
+
// lib/index.ts
|
|
1138
|
+
var import_path2 = __toESM(require("path"));
|
|
819
1139
|
|
|
820
1140
|
// lib/vision.ts
|
|
821
1141
|
var import_fs = __toESM(require("fs"));
|
|
@@ -999,40 +1319,85 @@ var ScreenshotService = class _ScreenshotService {
|
|
|
999
1319
|
|
|
1000
1320
|
// lib/index.ts
|
|
1001
1321
|
require("dotenv").config({ path: ".env" });
|
|
1002
|
-
function getBrowser(env = "LOCAL", headless = false, logger) {
|
|
1322
|
+
function getBrowser(apiKey, projectId, env = "LOCAL", headless = false, logger, browserbaseSessionCreateParams, browserbaseResumeSessionID) {
|
|
1003
1323
|
return __async(this, null, function* () {
|
|
1004
|
-
if (env === "BROWSERBASE"
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
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
|
+
}
|
|
1019
1340
|
}
|
|
1020
1341
|
if (env === "BROWSERBASE") {
|
|
1342
|
+
if (!apiKey) {
|
|
1343
|
+
throw new Error("BROWSERBASE_API_KEY is required.");
|
|
1344
|
+
}
|
|
1021
1345
|
let debugUrl = void 0;
|
|
1022
1346
|
let sessionUrl = void 0;
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1347
|
+
let sessionId;
|
|
1348
|
+
let connectUrl;
|
|
1349
|
+
const browserbase = new import_sdk2.Browserbase({
|
|
1350
|
+
apiKey
|
|
1027
1351
|
});
|
|
1028
|
-
|
|
1029
|
-
|
|
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
|
+
}
|
|
1030
1394
|
const browser = yield import_test.chromium.connectOverCDP(connectUrl);
|
|
1031
|
-
|
|
1395
|
+
const { debuggerUrl } = yield browserbase.sessions.debug(sessionId);
|
|
1396
|
+
debugUrl = debuggerUrl;
|
|
1032
1397
|
sessionUrl = `https://www.browserbase.com/sessions/${sessionId}`;
|
|
1033
1398
|
logger({
|
|
1034
1399
|
category: "Init",
|
|
1035
|
-
message: `Browserbase session started.
|
|
1400
|
+
message: `Browserbase session ${browserbaseResumeSessionID ? "resumed" : "started"}.
|
|
1036
1401
|
|
|
1037
1402
|
Session Url: ${sessionUrl}
|
|
1038
1403
|
|
|
@@ -1119,12 +1484,17 @@ function applyStealthScripts(context) {
|
|
|
1119
1484
|
var Stagehand = class {
|
|
1120
1485
|
constructor({
|
|
1121
1486
|
env,
|
|
1122
|
-
|
|
1123
|
-
|
|
1487
|
+
apiKey,
|
|
1488
|
+
projectId,
|
|
1489
|
+
verbose,
|
|
1490
|
+
debugDom,
|
|
1124
1491
|
llmProvider,
|
|
1125
|
-
headless
|
|
1492
|
+
headless,
|
|
1126
1493
|
logger,
|
|
1127
|
-
|
|
1494
|
+
browserBaseSessionCreateParams,
|
|
1495
|
+
domSettleTimeoutMs,
|
|
1496
|
+
enableCaching,
|
|
1497
|
+
browserbaseResumeSessionID
|
|
1128
1498
|
} = {
|
|
1129
1499
|
env: "BROWSERBASE"
|
|
1130
1500
|
}) {
|
|
@@ -1133,24 +1503,34 @@ var Stagehand = class {
|
|
|
1133
1503
|
this.is_processing_browserbase_logs = false;
|
|
1134
1504
|
this.externalLogger = logger;
|
|
1135
1505
|
this.logger = this.log.bind(this);
|
|
1136
|
-
this.
|
|
1506
|
+
this.enableCaching = enableCaching != null ? enableCaching : false;
|
|
1507
|
+
this.llmProvider = llmProvider || new LLMProvider(this.logger, this.enableCaching);
|
|
1137
1508
|
this.env = env;
|
|
1138
1509
|
this.observations = {};
|
|
1510
|
+
this.apiKey = apiKey;
|
|
1511
|
+
this.projectId = projectId;
|
|
1139
1512
|
this.actions = {};
|
|
1140
|
-
this.verbose = verbose;
|
|
1141
|
-
this.debugDom = debugDom;
|
|
1513
|
+
this.verbose = verbose != null ? verbose : 0;
|
|
1514
|
+
this.debugDom = debugDom != null ? debugDom : false;
|
|
1142
1515
|
this.defaultModelName = "gpt-4o";
|
|
1143
|
-
this.
|
|
1144
|
-
this.
|
|
1516
|
+
this.domSettleTimeoutMs = domSettleTimeoutMs != null ? domSettleTimeoutMs : 3e4;
|
|
1517
|
+
this.headless = headless != null ? headless : false;
|
|
1518
|
+
this.browserBaseSessionCreateParams = browserBaseSessionCreateParams;
|
|
1519
|
+
this.browserbaseResumeSessionID = browserbaseResumeSessionID;
|
|
1145
1520
|
}
|
|
1146
1521
|
init() {
|
|
1147
1522
|
return __async(this, arguments, function* ({
|
|
1148
1523
|
modelName = "gpt-4o"
|
|
1149
1524
|
} = {}) {
|
|
1525
|
+
console.log("haha fucker");
|
|
1150
1526
|
const { context, debugUrl, sessionUrl } = yield getBrowser(
|
|
1527
|
+
this.apiKey,
|
|
1528
|
+
this.projectId,
|
|
1151
1529
|
this.env,
|
|
1152
1530
|
this.headless,
|
|
1153
|
-
this.logger
|
|
1531
|
+
this.logger,
|
|
1532
|
+
this.browserBaseSessionCreateParams,
|
|
1533
|
+
this.browserbaseResumeSessionID
|
|
1154
1534
|
).catch((e) => {
|
|
1155
1535
|
console.error("Error in init:", e);
|
|
1156
1536
|
return { context: void 0, debugUrl: void 0, sessionUrl: void 0 };
|
|
@@ -1168,12 +1548,54 @@ var Stagehand = class {
|
|
|
1168
1548
|
if (this.headless) {
|
|
1169
1549
|
yield this.page.setViewportSize({ width: 1280, height: 720 });
|
|
1170
1550
|
}
|
|
1171
|
-
yield this.
|
|
1172
|
-
content:
|
|
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
|
+
)
|
|
1556
|
+
});
|
|
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
|
+
)
|
|
1562
|
+
});
|
|
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
|
+
)
|
|
1173
1568
|
});
|
|
1174
1569
|
return { debugUrl, sessionUrl };
|
|
1175
1570
|
});
|
|
1176
1571
|
}
|
|
1572
|
+
initFromPage(page, modelName) {
|
|
1573
|
+
return __async(this, null, function* () {
|
|
1574
|
+
this.page = page;
|
|
1575
|
+
this.context = page.context();
|
|
1576
|
+
this.defaultModelName = modelName || this.defaultModelName;
|
|
1577
|
+
const originalGoto = this.page.goto.bind(this.page);
|
|
1578
|
+
this.page.goto = (url, options) => __async(this, null, function* () {
|
|
1579
|
+
const result = yield originalGoto(url, options);
|
|
1580
|
+
yield this.page.waitForLoadState("domcontentloaded");
|
|
1581
|
+
yield this._waitForSettledDom();
|
|
1582
|
+
return result;
|
|
1583
|
+
});
|
|
1584
|
+
if (this.headless) {
|
|
1585
|
+
yield this.page.setViewportSize({ width: 1280, height: 720 });
|
|
1586
|
+
}
|
|
1587
|
+
yield this.page.addInitScript({
|
|
1588
|
+
path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "process.js")
|
|
1589
|
+
});
|
|
1590
|
+
yield this.page.addInitScript({
|
|
1591
|
+
path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "utils.js")
|
|
1592
|
+
});
|
|
1593
|
+
yield this.page.addInitScript({
|
|
1594
|
+
path: import_path2.default.join(__dirname, "..", "dist", "dom", "build", "debug.js")
|
|
1595
|
+
});
|
|
1596
|
+
return { context: this.context };
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1177
1599
|
log({
|
|
1178
1600
|
message,
|
|
1179
1601
|
category,
|
|
@@ -1233,11 +1655,9 @@ var Stagehand = class {
|
|
|
1233
1655
|
return __async(this, null, function* () {
|
|
1234
1656
|
try {
|
|
1235
1657
|
const timeout = timeoutMs != null ? timeoutMs : this.domSettleTimeoutMs;
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
`[stagehand:dom] DOM settle timeout of ${timeout}ms exceeded, continuing anyway`
|
|
1240
|
-
);
|
|
1658
|
+
let timeoutHandle;
|
|
1659
|
+
const timeoutPromise = new Promise((resolve, reject) => {
|
|
1660
|
+
timeoutHandle = setTimeout(() => {
|
|
1241
1661
|
this.log({
|
|
1242
1662
|
category: "dom",
|
|
1243
1663
|
message: `DOM settle timeout of ${timeout}ms exceeded, continuing anyway`,
|
|
@@ -1246,16 +1666,12 @@ var Stagehand = class {
|
|
|
1246
1666
|
resolve();
|
|
1247
1667
|
}, timeout);
|
|
1248
1668
|
});
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
yield this.page.waitForLoadState("domcontentloaded");
|
|
1253
|
-
yield this.page.evaluate(() => {
|
|
1669
|
+
try {
|
|
1670
|
+
yield Promise.race([
|
|
1671
|
+
this.page.evaluate(() => {
|
|
1254
1672
|
return new Promise((resolve) => {
|
|
1255
1673
|
if (typeof window.waitForDomSettle === "function") {
|
|
1256
|
-
window.waitForDomSettle().then(
|
|
1257
|
-
resolve();
|
|
1258
|
-
});
|
|
1674
|
+
window.waitForDomSettle().then(resolve);
|
|
1259
1675
|
} else {
|
|
1260
1676
|
console.warn(
|
|
1261
1677
|
"waitForDomSettle is not defined, considering DOM as settled"
|
|
@@ -1263,10 +1679,14 @@ var Stagehand = class {
|
|
|
1263
1679
|
resolve();
|
|
1264
1680
|
}
|
|
1265
1681
|
});
|
|
1266
|
-
})
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1682
|
+
}),
|
|
1683
|
+
this.page.waitForLoadState("domcontentloaded"),
|
|
1684
|
+
this.page.waitForSelector("body"),
|
|
1685
|
+
timeoutPromise
|
|
1686
|
+
]);
|
|
1687
|
+
} finally {
|
|
1688
|
+
clearTimeout(timeoutHandle);
|
|
1689
|
+
}
|
|
1270
1690
|
} catch (e) {
|
|
1271
1691
|
this.log({
|
|
1272
1692
|
category: "dom",
|
|
@@ -1336,14 +1756,16 @@ Trace: ${e.stack}`,
|
|
|
1336
1756
|
progress = "",
|
|
1337
1757
|
content = {},
|
|
1338
1758
|
chunksSeen = [],
|
|
1339
|
-
modelName
|
|
1759
|
+
modelName,
|
|
1760
|
+
requestId,
|
|
1761
|
+
domSettleTimeoutMs
|
|
1340
1762
|
}) {
|
|
1341
1763
|
this.log({
|
|
1342
1764
|
category: "extraction",
|
|
1343
1765
|
message: `starting extraction '${instruction}'`,
|
|
1344
1766
|
level: 1
|
|
1345
1767
|
});
|
|
1346
|
-
yield this._waitForSettledDom();
|
|
1768
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1347
1769
|
yield this.startDomDebug();
|
|
1348
1770
|
const { outputString, chunk, chunks } = yield this.page.evaluate(
|
|
1349
1771
|
(chunksSeen2) => window.processDom(chunksSeen2 != null ? chunksSeen2 : []),
|
|
@@ -1363,7 +1785,8 @@ Trace: ${e.stack}`,
|
|
|
1363
1785
|
schema,
|
|
1364
1786
|
modelName: modelName || this.defaultModelName,
|
|
1365
1787
|
chunksSeen: chunksSeen.length,
|
|
1366
|
-
chunksTotal: chunks.length
|
|
1788
|
+
chunksTotal: chunks.length,
|
|
1789
|
+
requestId
|
|
1367
1790
|
});
|
|
1368
1791
|
const _a = extractionResponse, {
|
|
1369
1792
|
metadata: { progress: newProgress, completed }
|
|
@@ -1390,14 +1813,15 @@ Trace: ${e.stack}`,
|
|
|
1390
1813
|
message: `continuing extraction, progress: '${newProgress}'`,
|
|
1391
1814
|
level: 1
|
|
1392
1815
|
});
|
|
1393
|
-
yield this._waitForSettledDom();
|
|
1816
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1394
1817
|
return this._extract({
|
|
1395
1818
|
instruction,
|
|
1396
1819
|
schema,
|
|
1397
1820
|
progress: newProgress,
|
|
1398
1821
|
content: output,
|
|
1399
1822
|
chunksSeen,
|
|
1400
|
-
modelName
|
|
1823
|
+
modelName,
|
|
1824
|
+
domSettleTimeoutMs
|
|
1401
1825
|
});
|
|
1402
1826
|
}
|
|
1403
1827
|
});
|
|
@@ -1407,7 +1831,9 @@ Trace: ${e.stack}`,
|
|
|
1407
1831
|
instruction,
|
|
1408
1832
|
useVision,
|
|
1409
1833
|
fullPage,
|
|
1410
|
-
modelName
|
|
1834
|
+
modelName,
|
|
1835
|
+
requestId,
|
|
1836
|
+
domSettleTimeoutMs
|
|
1411
1837
|
}) {
|
|
1412
1838
|
if (!instruction) {
|
|
1413
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.`;
|
|
@@ -1418,7 +1844,7 @@ Trace: ${e.stack}`,
|
|
|
1418
1844
|
message: `starting observation: ${instruction}`,
|
|
1419
1845
|
level: 1
|
|
1420
1846
|
});
|
|
1421
|
-
yield this._waitForSettledDom();
|
|
1847
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1422
1848
|
yield this.startDomDebug();
|
|
1423
1849
|
let { outputString, selectorMap } = yield this.page.evaluate(
|
|
1424
1850
|
(fullPage2) => fullPage2 ? window.processAllOfDom() : window.processDom([]),
|
|
@@ -1447,7 +1873,8 @@ Trace: ${e.stack}`,
|
|
|
1447
1873
|
domElements: outputString,
|
|
1448
1874
|
llmProvider: this.llmProvider,
|
|
1449
1875
|
modelName: modelName || this.defaultModelName,
|
|
1450
|
-
image: annotatedScreenshot
|
|
1876
|
+
image: annotatedScreenshot,
|
|
1877
|
+
requestId
|
|
1451
1878
|
});
|
|
1452
1879
|
const elementsWithSelectors = observationResponse.elements.map(
|
|
1453
1880
|
(element) => {
|
|
@@ -1476,7 +1903,9 @@ Trace: ${e.stack}`,
|
|
|
1476
1903
|
modelName,
|
|
1477
1904
|
useVision,
|
|
1478
1905
|
verifierUseVision,
|
|
1479
|
-
retries = 0
|
|
1906
|
+
retries = 0,
|
|
1907
|
+
requestId,
|
|
1908
|
+
domSettleTimeoutMs
|
|
1480
1909
|
}) {
|
|
1481
1910
|
var _a;
|
|
1482
1911
|
const model = modelName != null ? modelName : this.defaultModelName;
|
|
@@ -1494,7 +1923,7 @@ Trace: ${e.stack}`,
|
|
|
1494
1923
|
message: `Running / Continuing action: ${action} on page: ${this.page.url()}`,
|
|
1495
1924
|
level: 2
|
|
1496
1925
|
});
|
|
1497
|
-
yield this._waitForSettledDom();
|
|
1926
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1498
1927
|
yield this.startDomDebug();
|
|
1499
1928
|
this.log({
|
|
1500
1929
|
category: "action",
|
|
@@ -1536,7 +1965,8 @@ Trace: ${e.stack}`,
|
|
|
1536
1965
|
llmProvider: this.llmProvider,
|
|
1537
1966
|
modelName: model,
|
|
1538
1967
|
screenshot: annotatedScreenshot,
|
|
1539
|
-
logger: this.logger
|
|
1968
|
+
logger: this.logger,
|
|
1969
|
+
requestId
|
|
1540
1970
|
});
|
|
1541
1971
|
this.log({
|
|
1542
1972
|
category: "action",
|
|
@@ -1558,7 +1988,9 @@ Trace: ${e.stack}`,
|
|
|
1558
1988
|
chunksSeen,
|
|
1559
1989
|
modelName,
|
|
1560
1990
|
useVision,
|
|
1561
|
-
verifierUseVision
|
|
1991
|
+
verifierUseVision,
|
|
1992
|
+
requestId,
|
|
1993
|
+
domSettleTimeoutMs
|
|
1562
1994
|
});
|
|
1563
1995
|
} else if (useVision === "fallback") {
|
|
1564
1996
|
this.log({
|
|
@@ -1573,9 +2005,14 @@ Trace: ${e.stack}`,
|
|
|
1573
2005
|
chunksSeen,
|
|
1574
2006
|
modelName,
|
|
1575
2007
|
useVision: true,
|
|
1576
|
-
verifierUseVision
|
|
2008
|
+
verifierUseVision,
|
|
2009
|
+
requestId,
|
|
2010
|
+
domSettleTimeoutMs
|
|
1577
2011
|
});
|
|
1578
2012
|
} else {
|
|
2013
|
+
if (this.enableCaching) {
|
|
2014
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2015
|
+
}
|
|
1579
2016
|
return {
|
|
1580
2017
|
success: false,
|
|
1581
2018
|
message: `Action was not able to be completed.`,
|
|
@@ -1632,7 +2069,9 @@ Trace: ${e.stack}`,
|
|
|
1632
2069
|
useVision,
|
|
1633
2070
|
verifierUseVision,
|
|
1634
2071
|
retries: retries + 1,
|
|
1635
|
-
chunksSeen
|
|
2072
|
+
chunksSeen,
|
|
2073
|
+
requestId,
|
|
2074
|
+
domSettleTimeoutMs
|
|
1636
2075
|
});
|
|
1637
2076
|
}
|
|
1638
2077
|
}
|
|
@@ -1661,7 +2100,9 @@ Trace: ${e.stack}`,
|
|
|
1661
2100
|
useVision,
|
|
1662
2101
|
verifierUseVision,
|
|
1663
2102
|
retries: retries + 1,
|
|
1664
|
-
chunksSeen
|
|
2103
|
+
chunksSeen,
|
|
2104
|
+
requestId,
|
|
2105
|
+
domSettleTimeoutMs
|
|
1665
2106
|
});
|
|
1666
2107
|
}
|
|
1667
2108
|
}
|
|
@@ -1684,7 +2125,9 @@ Trace: ${e.stack}`,
|
|
|
1684
2125
|
useVision,
|
|
1685
2126
|
verifierUseVision,
|
|
1686
2127
|
retries: retries + 1,
|
|
1687
|
-
chunksSeen
|
|
2128
|
+
chunksSeen,
|
|
2129
|
+
requestId,
|
|
2130
|
+
domSettleTimeoutMs
|
|
1688
2131
|
});
|
|
1689
2132
|
}
|
|
1690
2133
|
}
|
|
@@ -1713,7 +2156,9 @@ Trace: ${e.stack}`,
|
|
|
1713
2156
|
useVision,
|
|
1714
2157
|
verifierUseVision,
|
|
1715
2158
|
retries: retries + 1,
|
|
1716
|
-
chunksSeen
|
|
2159
|
+
chunksSeen,
|
|
2160
|
+
requestId,
|
|
2161
|
+
domSettleTimeoutMs
|
|
1717
2162
|
});
|
|
1718
2163
|
}
|
|
1719
2164
|
}
|
|
@@ -1743,7 +2188,7 @@ Trace: ${e.stack}`,
|
|
|
1743
2188
|
yield newOpenedTab.close();
|
|
1744
2189
|
yield this.page.goto(newOpenedTab.url());
|
|
1745
2190
|
yield this.page.waitForLoadState("domcontentloaded");
|
|
1746
|
-
yield this._waitForSettledDom();
|
|
2191
|
+
yield this._waitForSettledDom(domSettleTimeoutMs);
|
|
1747
2192
|
}
|
|
1748
2193
|
yield Promise.race([
|
|
1749
2194
|
this.page.waitForLoadState("networkidle"),
|
|
@@ -1782,9 +2227,14 @@ Trace: ${e.stack}`,
|
|
|
1782
2227
|
useVision,
|
|
1783
2228
|
verifierUseVision,
|
|
1784
2229
|
retries: retries + 1,
|
|
1785
|
-
chunksSeen
|
|
2230
|
+
chunksSeen,
|
|
2231
|
+
requestId,
|
|
2232
|
+
domSettleTimeoutMs
|
|
1786
2233
|
});
|
|
1787
2234
|
} else {
|
|
2235
|
+
if (this.enableCaching) {
|
|
2236
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2237
|
+
}
|
|
1788
2238
|
return {
|
|
1789
2239
|
success: false,
|
|
1790
2240
|
message: `Internal error: Chosen method ${method} is invalid`,
|
|
@@ -1851,7 +2301,8 @@ Trace: ${e.stack}`,
|
|
|
1851
2301
|
modelName: model,
|
|
1852
2302
|
screenshot: fullpageScreenshot,
|
|
1853
2303
|
domElements,
|
|
1854
|
-
logger: this.logger
|
|
2304
|
+
logger: this.logger,
|
|
2305
|
+
requestId
|
|
1855
2306
|
});
|
|
1856
2307
|
this.log({
|
|
1857
2308
|
category: "action",
|
|
@@ -1871,7 +2322,9 @@ Trace: ${e.stack}`,
|
|
|
1871
2322
|
modelName,
|
|
1872
2323
|
chunksSeen,
|
|
1873
2324
|
useVision,
|
|
1874
|
-
verifierUseVision
|
|
2325
|
+
verifierUseVision,
|
|
2326
|
+
requestId,
|
|
2327
|
+
domSettleTimeoutMs
|
|
1875
2328
|
});
|
|
1876
2329
|
} else {
|
|
1877
2330
|
this.log({
|
|
@@ -1901,10 +2354,15 @@ Trace: ${error.stack}`,
|
|
|
1901
2354
|
useVision,
|
|
1902
2355
|
verifierUseVision,
|
|
1903
2356
|
retries: retries + 1,
|
|
1904
|
-
chunksSeen
|
|
2357
|
+
chunksSeen,
|
|
2358
|
+
requestId,
|
|
2359
|
+
domSettleTimeoutMs
|
|
1905
2360
|
});
|
|
1906
2361
|
}
|
|
1907
2362
|
yield this._recordAction(action, "");
|
|
2363
|
+
if (this.enableCaching) {
|
|
2364
|
+
this.llmProvider.cleanRequestCache(requestId);
|
|
2365
|
+
}
|
|
1908
2366
|
return {
|
|
1909
2367
|
success: false,
|
|
1910
2368
|
message: `Error performing action: ${error.message}`,
|
|
@@ -1917,15 +2375,37 @@ Trace: ${error.stack}`,
|
|
|
1917
2375
|
return __async(this, arguments, function* ({
|
|
1918
2376
|
action,
|
|
1919
2377
|
modelName,
|
|
1920
|
-
useVision = "fallback"
|
|
2378
|
+
useVision = "fallback",
|
|
2379
|
+
domSettleTimeoutMs
|
|
1921
2380
|
}) {
|
|
1922
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
|
+
});
|
|
1923
2387
|
return this._act({
|
|
1924
2388
|
action,
|
|
1925
2389
|
modelName,
|
|
1926
2390
|
chunksSeen: [],
|
|
1927
2391
|
useVision,
|
|
1928
|
-
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
|
+
};
|
|
1929
2409
|
});
|
|
1930
2410
|
});
|
|
1931
2411
|
}
|
|
@@ -1933,23 +2413,58 @@ Trace: ${error.stack}`,
|
|
|
1933
2413
|
return __async(this, arguments, function* ({
|
|
1934
2414
|
instruction,
|
|
1935
2415
|
schema,
|
|
1936
|
-
modelName
|
|
2416
|
+
modelName,
|
|
2417
|
+
domSettleTimeoutMs
|
|
1937
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
|
+
});
|
|
1938
2424
|
return this._extract({
|
|
1939
2425
|
instruction,
|
|
1940
2426
|
schema,
|
|
1941
|
-
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;
|
|
1942
2440
|
});
|
|
1943
2441
|
});
|
|
1944
2442
|
}
|
|
1945
2443
|
observe(options) {
|
|
1946
2444
|
return __async(this, null, function* () {
|
|
1947
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
|
+
});
|
|
1948
2451
|
return this._observe({
|
|
1949
2452
|
instruction: (_a = options == null ? void 0 : options.instruction) != null ? _a : "Find actions that can be performed on this page.",
|
|
1950
2453
|
modelName: options == null ? void 0 : options.modelName,
|
|
1951
2454
|
useVision: (_b = options == null ? void 0 : options.useVision) != null ? _b : false,
|
|
1952
|
-
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;
|
|
1953
2468
|
});
|
|
1954
2469
|
});
|
|
1955
2470
|
}
|