Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fuzzy-uppish-capybara.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stagehand": patch
---

Properly serialize os on browserbase session create params
35 changes: 24 additions & 11 deletions stagehand/config.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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",
Expand All @@ -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"
Expand Down Expand Up @@ -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":
Expand Down
1 change: 1 addition & 0 deletions stagehand/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down