diff --git a/.changeset/fuzzy-uppish-capybara.md b/.changeset/fuzzy-uppish-capybara.md new file mode 100644 index 00000000..256c81fd --- /dev/null +++ b/.changeset/fuzzy-uppish-capybara.md @@ -0,0 +1,5 @@ +--- +"stagehand": patch +--- + +Properly serialize os on browserbase session create params diff --git a/stagehand/config.py b/stagehand/config.py index e69faa20..2135c7c4 100644 --- a/stagehand/config.py +++ b/stagehand/config.py @@ -1,7 +1,6 @@ import os -from typing import Any, Callable, Literal, Optional, Union +from typing import Any, Callable, Literal, Optional -from browserbase.types import SessionCreateParams as BrowserbaseSessionCreateParams from pydantic import BaseModel, ConfigDict, Field, field_validator from stagehand.schemas import AvailableModel @@ -71,9 +70,7 @@ class StagehandConfig(BaseModel): alias="domSettleTimeoutMs", description="Timeout for DOM to settle (in ms)", ) - browserbase_session_create_params: Optional[ - Union[BrowserbaseSessionCreateParams, dict[str, Any]] - ] = Field( + browserbase_session_create_params: Optional[dict[str, Any]] = Field( None, alias="browserbaseSessionCreateParams", description="Browserbase session create params", @@ -87,7 +84,9 @@ class StagehandConfig(BaseModel): description="Session ID for resuming Browserbase sessions", ) model_name: Optional[str] = Field( - AvailableModel.GPT_4O, alias="modelName", description="Name of the model to use" + AvailableModel.GPT_4_1_MINI, + alias="modelName", + description="Name of the model to use", ) self_heal: Optional[bool] = Field( True, alias="selfHeal", description="Enable self-healing functionality" @@ -124,11 +123,25 @@ class StagehandConfig(BaseModel): @classmethod def validate_browserbase_params(cls, v, info): """Validate and convert browserbase session create params.""" - if isinstance(v, dict) and "project_id" not in v: - values = info.data - project_id = values.get("project_id") or values.get("projectId") - if project_id: - v = {**v, "project_id": project_id} + if isinstance(v, dict): + # Make a copy to avoid mutating the original + v = dict(v) + + # Add project_id if not present + if "project_id" not in v: + values = info.data + project_id = values.get("project_id") or values.get("projectId") + if project_id: + v["project_id"] = project_id + + # Handle browser_settings + if "browser_settings" in v: + # Make a copy of browser_settings to avoid mutating + v["browser_settings"] = dict(v["browser_settings"]) + + # Normalize 'os' key to lowercase + if "os" in v["browser_settings"]: + v["browser_settings"]["os"] = v["browser_settings"]["os"].lower() return v def with_overrides(self, **overrides) -> "StagehandConfig": diff --git a/stagehand/schemas.py b/stagehand/schemas.py index 3cb0d54e..de8448b2 100644 --- a/stagehand/schemas.py +++ b/stagehand/schemas.py @@ -15,6 +15,7 @@ class AvailableModel(str, Enum): GPT_4O = "gpt-4o" GPT_4O_MINI = "gpt-4o-mini" + GPT_4_1_MINI = "gpt-4.1-mini" CLAUDE_3_5_SONNET_LATEST = "claude-3-5-sonnet-latest" CLAUDE_3_7_SONNET_LATEST = "claude-3-7-sonnet-latest" COMPUTER_USE_PREVIEW = "computer-use-preview"