Skip to content

Commit dd3124d

Browse files
committed
Clarify env var handling in Python SDK
1 parent e90a4dd commit dd3124d

File tree

4 files changed

+15
-1
lines changed

4 files changed

+15
-1
lines changed

examples/local_example.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Required environment variables:
66
- BROWSERBASE_API_KEY (can be any value in local mode)
77
- BROWSERBASE_PROJECT_ID (can be any value in local mode)
8-
- MODEL_API_KEY (used for client configuration even in local mode)
8+
- MODEL_API_KEY (read by this example and passed explicitly to the client)
99
1010
1111
Install the published wheel before running this script:
@@ -45,6 +45,7 @@ def _stream_to_result(stream, label: str) -> object | None:
4545

4646
def main() -> None:
4747
load_example_env()
48+
# The example reads MODEL_API_KEY itself so the SDK configuration stays explicit.
4849
model_key = os.environ.get("MODEL_API_KEY")
4950
if not model_key:
5051
sys.exit("Set MODEL_API_KEY to run the local server.")

src/stagehand/_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ def __init__(
9292
This automatically infers the following arguments from their corresponding environment variables if they are not provided:
9393
- `browserbase_api_key` from `BROWSERBASE_API_KEY`
9494
- `browserbase_project_id` from `BROWSERBASE_PROJECT_ID`
95+
96+
`model_api_key` is intentionally not inferred from any AI provider environment variable.
97+
Pass it explicitly when you want the SDK to send `x-model-api-key` on remote requests or
98+
to forward `MODEL_API_KEY` to the local SEA child process.
9599
"""
96100
self._server_mode: Literal["remote", "local"] = server
97101
self._local_stagehand_binary_path = _local_stagehand_binary_path
@@ -366,6 +370,10 @@ def __init__(
366370
This automatically infers the following arguments from their corresponding environment variables if they are not provided:
367371
- `browserbase_api_key` from `BROWSERBASE_API_KEY`
368372
- `browserbase_project_id` from `BROWSERBASE_PROJECT_ID`
373+
374+
`model_api_key` is intentionally not inferred from any AI provider environment variable.
375+
Pass it explicitly when you want the SDK to send `x-model-api-key` on remote requests or
376+
to forward `MODEL_API_KEY` to the local SEA child process.
369377
"""
370378
self._server_mode: Literal["remote", "local"] = server
371379
self._local_stagehand_binary_path = _local_stagehand_binary_path

src/stagehand/lib/sea_server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ def _build_process_env(self, *, port: int) -> dict[str, str]:
127127
proc_env["HOST"] = self._config.host
128128
proc_env["PORT"] = str(port)
129129
proc_env["HEADLESS"] = "true" if self._config.headless else "false"
130+
# Always set MODEL_API_KEY in the child env so the SDK constructor value wins
131+
# over any inherited parent MODEL_API_KEY. An empty string preserves the
132+
# "explicitly unset" case instead of silently reusing the parent's value.
130133
proc_env["MODEL_API_KEY"] = self._config.model_api_key or ""
131134
if self._config.chrome_path:
132135
proc_env["CHROME_PATH"] = self._config.chrome_path

tests/test_local_server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ def test_local_mode_masks_inherited_model_api_key_envs_and_prefers_explicit_para
263263
expected_model_api_key: str,
264264
) -> None:
265265
_set_browserbase_env(monkeypatch)
266+
# Simulate a parent process with conflicting inherited env. The child SEA process
267+
# should keep unrelated env intact while MODEL_API_KEY follows constructor intent.
266268
monkeypatch.setenv("MODEL_API_KEY", "bad1")
267269
monkeypatch.setenv("OPENAI_API_KEY", "bad2")
268270

0 commit comments

Comments
 (0)