44import sys
55import time
66from pathlib import Path
7- from typing import Any , Literal , Optional
7+ from typing import Any , Optional
88
99import httpx
1010from dotenv import load_dotenv
3939
4040class Stagehand :
4141 """
42- Python client for interacting with a running Stagehand server and Browserbase remote headless browser.
43-
44- Now supports automatically creating a new session if no session_id is provided.
45- You can provide a configuration via the 'config' parameter, or use individual parameters to override
46- the default configuration values.
42+ Main Stagehand class.
4743 """
4844
49- # Dictionary to store one lock per session_id
5045 _session_locks = {}
51-
52- # Flag to track if cleanup has been called
5346 _cleanup_called = False
5447
5548 def __init__ (
5649 self ,
57- config : Optional [StagehandConfig ] = None ,
58- * ,
59- api_url : Optional [str ] = None ,
60- model_api_key : Optional [str ] = None ,
61- session_id : Optional [str ] = None ,
62- env : Optional [Literal ["BROWSERBASE" , "LOCAL" ]] = None ,
63- httpx_client : Optional [httpx .AsyncClient ] = None ,
64- timeout_settings : Optional [httpx .Timeout ] = None ,
65- use_rich_logging : bool = True ,
50+ config : StagehandConfig = default_config ,
6651 ** config_overrides ,
6752 ):
6853 """
6954 Initialize the Stagehand client.
7055
7156 Args:
7257 config (Optional[StagehandConfig]): Configuration object. If not provided, uses default_config.
73- api_url (Optional[str]): The running Stagehand server URL. Overrides config if provided.
74- model_api_key (Optional[str]): Your model API key (e.g. OpenAI, Anthropic, etc.). Overrides config if provided.
75- session_id (Optional[str]): Existing Browserbase session ID to connect to. Overrides config if provided.
76- env (Optional[Literal["BROWSERBASE", "LOCAL"]]): Environment to run in. Overrides config if provided.
77- httpx_client (Optional[httpx.AsyncClient]): Optional custom httpx.AsyncClient instance.
78- timeout_settings (Optional[httpx.Timeout]): Optional custom timeout settings for httpx.
79- use_rich_logging (bool): Whether to use Rich for colorized logging.
8058 **config_overrides: Additional configuration overrides to apply to the config.
8159 """
82- # Start with provided config or default config
83- if config is None :
84- config = default_config
8560
8661 # Apply any overrides
8762 overrides = {}
88- if api_url is not None :
89- # api_url isn't in config, handle separately
90- pass
91- if model_api_key is not None :
92- # model_api_key isn't in config, handle separately
93- pass
94- if session_id is not None :
95- overrides ["browserbase_session_id" ] = session_id
96- if env is not None :
97- overrides ["env" ] = env
9863
9964 # Add any additional config overrides
10065 overrides .update (config_overrides )
@@ -106,8 +71,9 @@ def __init__(
10671 self .config = config
10772
10873 # Handle non-config parameters
109- self .api_url = api_url or os .getenv ("STAGEHAND_API_URL" )
110- self .model_api_key = model_api_key or os .getenv ("MODEL_API_KEY" )
74+ self .api_url = self .config .api_url or os .getenv ("STAGEHAND_API_URL" )
75+ self .model_api_key = self .config .model_api_key or os .getenv ("MODEL_API_KEY" )
76+ self .model_name = self .config .model_name
11177
11278 # Extract frequently used values from config for convenience
11379 self .browserbase_api_key = self .config .api_key or os .getenv (
@@ -117,7 +83,6 @@ def __init__(
11783 "BROWSERBASE_PROJECT_ID"
11884 )
11985 self .session_id = self .config .browserbase_session_id
120- self .model_name = self .config .model_name
12186 self .dom_settle_timeout_ms = self .config .dom_settle_timeout_ms
12287 self .self_heal = self .config .self_heal
12388 self .wait_for_captcha_solves = self .config .wait_for_captcha_solves
@@ -161,8 +126,7 @@ def __init__(
161126 # Handle streaming response setting
162127 self .streamed_response = True
163128
164- self .httpx_client = httpx_client
165- self .timeout_settings = timeout_settings or httpx .Timeout (
129+ self .timeout_settings = httpx .Timeout (
166130 connect = 180.0 ,
167131 read = 180.0 ,
168132 write = 180.0 ,
@@ -184,7 +148,9 @@ def __init__(
184148 # Initialize the centralized logger with the specified verbosity
185149 self .on_log = self .config .logger or default_log_handler
186150 self .logger = StagehandLogger (
187- verbose = self .verbose , external_logger = self .on_log , use_rich = use_rich_logging
151+ verbose = self .verbose ,
152+ external_logger = self .on_log ,
153+ use_rich = self .config .use_rich_logging ,
188154 )
189155
190156 # If using BROWSERBASE, session_id or creation params are needed
@@ -456,9 +422,7 @@ async def init(self):
456422
457423 if self .env == "BROWSERBASE" :
458424 if not self ._client :
459- self ._client = self .httpx_client or httpx .AsyncClient (
460- timeout = self .timeout_settings
461- )
425+ self ._client = httpx .AsyncClient (timeout = self .timeout_settings )
462426
463427 # Create session if we don't have one
464428 if not self .session_id :
@@ -570,8 +534,7 @@ async def close(self):
570534 "Cannot end server session: HTTP client not available."
571535 )
572536
573- # Close internal HTTPX client if it was created by Stagehand
574- if self ._client and not self .httpx_client :
537+ if self ._client :
575538 self .logger .debug ("Closing the internal HTTPX client..." )
576539 await self ._client .aclose ()
577540 self ._client = None
0 commit comments