Skip to content

Commit 47bd540

Browse files
add optional granular timeout; (#173)
* add optional granular timeout; * readme update * reduce default timeout to 30s
1 parent 8fcd233 commit 47bd540

File tree

3 files changed

+36
-8
lines changed

3 files changed

+36
-8
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ This constructor is used to create an instance of Stagehand.
137137
- `1`: SDK-level logging
138138
- `2`: LLM-client level logging (most granular)
139139
- `debugDom`: a `boolean` that draws bounding boxes around elements presented to the LLM during automation.
140-
- `domSettleTimeoutMs`: an `integer` that specifies the timeout in milliseconds for waiting for the DOM to settle. Defaults to 30000 (30 seconds).
140+
- `domSettleTimeoutMs`: an `integer` that specifies the timeout in milliseconds for waiting for the DOM to settle. It can be overriden in individual function calls if needed. Defaults to 30000 (30 seconds).
141141
- `enableCaching`: a `boolean` that enables caching of LLM responses. When set to `true`, the LLM requests will be cached on disk and reused for identical requests. Defaults to `false`.
142142

143143
- **Returns:**
@@ -179,6 +179,7 @@ This constructor is used to create an instance of Stagehand.
179179
- `action`: a `string` describing the action to perform, e.g., `"search for 'x'"`.
180180
- `modelName`: (optional) an `AvailableModel` string to specify the model to use.
181181
- `useVision`: (optional) a `boolean` or `"fallback"` to determine if vision-based processing should be used. Defaults to `"fallback"`.
182+
- `domSettleTimeoutMs`: (optional) an `integer` that specifies the timeout in milliseconds for waiting for the DOM to settle. If not set, defaults to the timeout value specified during initialization.
182183

183184
- **Returns:**
184185

@@ -201,6 +202,7 @@ This constructor is used to create an instance of Stagehand.
201202
- `instruction`: a `string` providing instructions for extraction.
202203
- `schema`: a `z.AnyZodObject` defining the structure of the data to extract.
203204
- `modelName`: (optional) an `AvailableModel` string to specify the model to use.
205+
- `domSettleTimeoutMs`: (optional) an `integer` that specifies the timeout in milliseconds for waiting for the DOM to settle. If not set, defaults to the timeout value specified during initialization.
204206

205207
- **Returns:**
206208

@@ -229,6 +231,7 @@ If you are looking for a specific element, you can also pass in an instruction t
229231

230232
- `instruction`: a `string` providing instructions for the observation.
231233
- `useVision`: (optional) a `boolean` or `"fallback"` to determine if vision-based processing should be used. Defaults to `"fallback"`.
234+
- `domSettleTimeoutMs`: (optional) an `integer` that specifies the timeout in milliseconds for waiting for the DOM to settle. If not set, defaults to the timeout value specified during initialization.
232235

233236
- **Returns:**
234237

evals/index.eval.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ const homedepot = async () => {
321321

322322
logger.init(stagehand);
323323

324-
const { debugUrl, sessionUrl } = await stagehand.init();
324+
const { debugUrl, sessionUrl } = await stagehand.init({
325+
domSettleTimeoutMs: 60_000,
326+
});
325327

326328
try {
327329
await stagehand.page.goto("https://www.homedepot.com/");

lib/index.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ export class Stagehand {
296296
this.verbose = verbose ?? 0;
297297
this.debugDom = debugDom ?? false;
298298
this.defaultModelName = "gpt-4o";
299-
this.domSettleTimeoutMs = domSettleTimeoutMs ?? 60_000;
299+
this.domSettleTimeoutMs = domSettleTimeoutMs ?? 30_000;
300300
this.headless = headless ?? false;
301301
this.browserBaseSessionCreateParams = browserBaseSessionCreateParams;
302302
this.browserbaseResumeSessionID = browserbaseResumeSessionID;
@@ -592,6 +592,7 @@ export class Stagehand {
592592
chunksSeen = [],
593593
modelName,
594594
requestId,
595+
domSettleTimeoutMs,
595596
}: {
596597
instruction: string;
597598
schema: T;
@@ -600,14 +601,15 @@ export class Stagehand {
600601
chunksSeen?: Array<number>;
601602
modelName?: AvailableModel;
602603
requestId?: string;
604+
domSettleTimeoutMs?: number;
603605
}): Promise<z.infer<T>> {
604606
this.log({
605607
category: "extraction",
606608
message: `starting extraction '${instruction}'`,
607609
level: 1,
608610
});
609611

610-
await this._waitForSettledDom();
612+
await this._waitForSettledDom(domSettleTimeoutMs);
611613
await this.startDomDebug();
612614
const { outputString, chunk, chunks } = await this.page.evaluate(
613615
(chunksSeen?: number[]) => window.processDom(chunksSeen ?? []),
@@ -661,14 +663,15 @@ export class Stagehand {
661663
message: `continuing extraction, progress: '${newProgress}'`,
662664
level: 1,
663665
});
664-
await this._waitForSettledDom();
666+
await this._waitForSettledDom(domSettleTimeoutMs);
665667
return this._extract({
666668
instruction,
667669
schema,
668670
progress: newProgress,
669671
content: output,
670672
chunksSeen,
671673
modelName,
674+
domSettleTimeoutMs,
672675
});
673676
}
674677
}
@@ -679,12 +682,14 @@ export class Stagehand {
679682
fullPage,
680683
modelName,
681684
requestId,
685+
domSettleTimeoutMs,
682686
}: {
683687
instruction: string;
684688
useVision: boolean;
685689
fullPage: boolean;
686690
modelName?: AvailableModel;
687691
requestId?: string;
692+
domSettleTimeoutMs?: number;
688693
}): Promise<{ selector: string; description: string }[]> {
689694
if (!instruction) {
690695
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.`;
@@ -698,7 +703,7 @@ export class Stagehand {
698703
level: 1,
699704
});
700705

701-
await this._waitForSettledDom();
706+
await this._waitForSettledDom(domSettleTimeoutMs);
702707
await this.startDomDebug();
703708
let { outputString, selectorMap } = await this.page.evaluate(
704709
(fullPage: boolean) =>
@@ -770,6 +775,7 @@ export class Stagehand {
770775
verifierUseVision,
771776
retries = 0,
772777
requestId,
778+
domSettleTimeoutMs,
773779
}: {
774780
action: string;
775781
steps?: string;
@@ -779,6 +785,7 @@ export class Stagehand {
779785
verifierUseVision: boolean;
780786
retries?: number;
781787
requestId?: string;
788+
domSettleTimeoutMs?: number;
782789
}): Promise<{ success: boolean; message: string; action: string }> {
783790
const model = modelName ?? this.defaultModelName;
784791

@@ -801,7 +808,7 @@ export class Stagehand {
801808
level: 2,
802809
});
803810

804-
await this._waitForSettledDom();
811+
await this._waitForSettledDom(domSettleTimeoutMs);
805812

806813
await this.startDomDebug();
807814

@@ -889,6 +896,7 @@ export class Stagehand {
889896
useVision,
890897
verifierUseVision,
891898
requestId,
899+
domSettleTimeoutMs,
892900
});
893901
} else if (useVision === "fallback") {
894902
this.log({
@@ -905,6 +913,7 @@ export class Stagehand {
905913
useVision: true,
906914
verifierUseVision,
907915
requestId,
916+
domSettleTimeoutMs,
908917
});
909918
} else {
910919
if (this.enableCaching) {
@@ -980,6 +989,7 @@ export class Stagehand {
980989
retries: retries + 1,
981990
chunksSeen,
982991
requestId,
992+
domSettleTimeoutMs,
983993
});
984994
}
985995
}
@@ -1010,6 +1020,7 @@ export class Stagehand {
10101020
retries: retries + 1,
10111021
chunksSeen,
10121022
requestId,
1023+
domSettleTimeoutMs,
10131024
});
10141025
}
10151026
}
@@ -1034,6 +1045,7 @@ export class Stagehand {
10341045
retries: retries + 1,
10351046
chunksSeen,
10361047
requestId,
1048+
domSettleTimeoutMs,
10371049
});
10381050
}
10391051
}
@@ -1070,6 +1082,7 @@ export class Stagehand {
10701082
retries: retries + 1,
10711083
chunksSeen,
10721084
requestId,
1085+
domSettleTimeoutMs,
10731086
});
10741087
}
10751088
}
@@ -1107,7 +1120,7 @@ export class Stagehand {
11071120
await newOpenedTab.close();
11081121
await this.page.goto(newOpenedTab.url());
11091122
await this.page.waitForLoadState("domcontentloaded");
1110-
await this._waitForSettledDom();
1123+
await this._waitForSettledDom(domSettleTimeoutMs);
11111124
}
11121125

11131126
// Wait for the network to be idle with timeout of 5s (will only wait if loading a new page)
@@ -1259,6 +1272,7 @@ export class Stagehand {
12591272
useVision,
12601273
verifierUseVision,
12611274
requestId,
1275+
domSettleTimeoutMs,
12621276
});
12631277
} else {
12641278
this.log({
@@ -1289,6 +1303,7 @@ export class Stagehand {
12891303
retries: retries + 1,
12901304
chunksSeen,
12911305
requestId,
1306+
domSettleTimeoutMs,
12921307
});
12931308
}
12941309

@@ -1309,10 +1324,12 @@ export class Stagehand {
13091324
action,
13101325
modelName,
13111326
useVision = "fallback",
1327+
domSettleTimeoutMs,
13121328
}: {
13131329
action: string;
13141330
modelName?: AvailableModel;
13151331
useVision?: "fallback" | boolean;
1332+
domSettleTimeoutMs?: number;
13161333
}): Promise<{
13171334
success: boolean;
13181335
message: string;
@@ -1334,6 +1351,7 @@ export class Stagehand {
13341351
useVision,
13351352
verifierUseVision: useVision !== false,
13361353
requestId,
1354+
domSettleTimeoutMs,
13371355
}).catch((e) => {
13381356
this.logger({
13391357
category: "act",
@@ -1356,10 +1374,12 @@ export class Stagehand {
13561374
instruction,
13571375
schema,
13581376
modelName,
1377+
domSettleTimeoutMs,
13591378
}: {
13601379
instruction: string;
13611380
schema: T;
13621381
modelName?: AvailableModel;
1382+
domSettleTimeoutMs?: number;
13631383
}): Promise<z.infer<T>> {
13641384
const requestId = Math.random().toString(36).substring(2);
13651385

@@ -1373,6 +1393,7 @@ export class Stagehand {
13731393
schema,
13741394
modelName,
13751395
requestId,
1396+
domSettleTimeoutMs,
13761397
}).catch((e) => {
13771398
this.logger({
13781399
category: "extract",
@@ -1391,6 +1412,7 @@ export class Stagehand {
13911412
instruction?: string;
13921413
modelName?: AvailableModel;
13931414
useVision?: boolean;
1415+
domSettleTimeoutMs?: number;
13941416
}): Promise<{ selector: string; description: string }[]> {
13951417
const requestId = Math.random().toString(36).substring(2);
13961418

@@ -1407,6 +1429,7 @@ export class Stagehand {
14071429
useVision: options?.useVision ?? false,
14081430
fullPage: false,
14091431
requestId,
1432+
domSettleTimeoutMs: options?.domSettleTimeoutMs,
14101433
}).catch((e) => {
14111434
this.logger({
14121435
category: "observe",

0 commit comments

Comments
 (0)