Skip to content

Commit bffc770

Browse files
authored
Merge branch 'browserbase:main' into a11y-include-input-attributes
2 parents 49951d4 + 1e7086e commit bffc770

File tree

12 files changed

+266
-175
lines changed

12 files changed

+266
-175
lines changed

.changeset/fortunate-friendly-avocet.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/smiling-snobbish-cockle.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Stagehand Python Changelog
22

3+
## 0.5.5
4+
5+
### Patch Changes
6+
7+
[#215](https://github.com/browserbase/stagehand-python/pull/215) [`cb35254`](https://github.com/browserbase/stagehand-python/commit/cb35254) Thanks @derekmeegan! - Fix ability to pass raw JSON to Extract schema
8+
[#225](https://github.com/browserbase/stagehand-python/pull/225) [`b23e005`](https://github.com/browserbase/stagehand-python/commit/b23e005) Thanks @derekmeegan! - add local cua example, remove root model from types
9+
[#218](https://github.com/browserbase/stagehand-python/pull/218) [`1a919ad`](https://github.com/browserbase/stagehand-python/commit/1a919ad) Thanks @derekmeegan! - Pass api_timeout param to Stagehand API correctly
10+
[#223](https://github.com/browserbase/stagehand-python/pull/223) [`de7d883`](https://github.com/browserbase/stagehand-python/commit/de7d883) Thanks @derekmeegan! - Fix search, navigate, go back, and go forward for gemini cua agent
11+
[#221](https://github.com/browserbase/stagehand-python/pull/221) [`da570a1`](https://github.com/browserbase/stagehand-python/commit/da570a1) Thanks @miguelg719! - Add support for Haiku 4.5 CUA
12+
313
## 0.5.4
414

515
### Patch Changes

examples/agent_example.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,11 @@ async def main():
3636
# Build a unified configuration object for Stagehand
3737
config = StagehandConfig(
3838
env="BROWSERBASE",
39-
# env="LOCAL",
4039
api_key=os.getenv("BROWSERBASE_API_KEY"),
4140
project_id=os.getenv("BROWSERBASE_PROJECT_ID"),
42-
model_name="gpt-4o",
43-
self_heal=True,
4441
system_prompt="You are a browser automation assistant that helps users navigate websites effectively.",
4542
model_client_options={"apiKey": os.getenv("MODEL_API_KEY")},
43+
self_heal=True,
4644
verbose=2,
4745
)
4846

@@ -51,12 +49,11 @@ async def main():
5149

5250
# Initialize - this creates a new session automatically.
5351
console.print("\n🚀 [info]Initializing Stagehand...[/]")
54-
await stagehand.init()
55-
if stagehand.env == "BROWSERBASE":
56-
console.print(f"\n[yellow]Created new session:[/] {stagehand.session_id}")
57-
console.print(
58-
f"🌐 [white]View your live browser:[/] [url]https://www.browserbase.com/sessions/{stagehand.session_id}[/]"
59-
)
52+
await stagehand.init()
53+
console.print(f"\n[yellow]Created new session:[/] {stagehand.session_id}")
54+
console.print(
55+
f"🌐 [white]View your live browser:[/] [url]https://www.browserbase.com/sessions/{stagehand.session_id}[/]"
56+
)
6057

6158
console.print("\n▶️ [highlight] Navigating[/] to Google")
6259
await stagehand.page.goto("https://google.com/")

examples/agent_example_local.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import asyncio
2+
import logging
3+
import os
4+
5+
from dotenv import load_dotenv
6+
from rich.console import Console
7+
from rich.panel import Panel
8+
from rich.theme import Theme
9+
10+
from stagehand import Stagehand, StagehandConfig, configure_logging
11+
12+
# Create a custom theme for consistent styling
13+
custom_theme = Theme(
14+
{
15+
"info": "cyan",
16+
"success": "green",
17+
"warning": "yellow",
18+
"error": "red bold",
19+
"highlight": "magenta",
20+
"url": "blue underline",
21+
}
22+
)
23+
24+
# Create a Rich console instance with our theme
25+
console = Console(theme=custom_theme)
26+
27+
load_dotenv()
28+
29+
# Configure logging with the utility function
30+
configure_logging(
31+
level=logging.INFO, # Set to INFO for regular logs, DEBUG for detailed
32+
quiet_dependencies=True, # Reduce noise from dependencies
33+
)
34+
35+
async def main():
36+
# Build a unified configuration object for Stagehand
37+
config = StagehandConfig(
38+
env="LOCAL",
39+
system_prompt="You are a browser automation assistant that helps users navigate websites effectively.",
40+
model_client_options={"apiKey": os.getenv("MODEL_API_KEY")},
41+
self_heal=True,
42+
verbose=2,
43+
)
44+
45+
# Create a Stagehand client using the configuration object.
46+
stagehand = Stagehand(config)
47+
48+
# Initialize - this creates a new session automatically.
49+
console.print("\n🚀 [info]Initializing Stagehand...[/]")
50+
await stagehand.init()
51+
52+
console.print("\n▶️ [highlight] Navigating[/] to Google")
53+
await stagehand.page.goto("https://google.com/")
54+
console.print("✅ [success]Navigated to Google[/]")
55+
56+
console.print("\n▶️ [highlight] Using Agent to perform a task[/]: playing a game of 2048")
57+
agent = stagehand.agent(
58+
model="gemini-2.5-computer-use-preview-10-2025",
59+
instructions="You are a helpful web navigation assistant that helps users find information. You are currently on the following page: google.com. Do not ask follow up questions, the user will trust your judgement.",
60+
options={"apiKey": os.getenv("GEMINI_API_KEY")}
61+
)
62+
agent_result = await agent.execute(
63+
instruction="Play a game of 2048",
64+
max_steps=20,
65+
auto_screenshot=True,
66+
)
67+
68+
console.print(agent_result)
69+
70+
console.print("📊 [info]Agent execution result:[/]")
71+
console.print(f"🎯 Completed: [bold]{'Yes' if agent_result.completed else 'No'}[/]")
72+
if agent_result.message:
73+
console.print(f"💬 Message: [italic]{agent_result.message}[/]")
74+
75+
if agent_result.actions:
76+
console.print(f"🔄 Actions performed: [bold]{len(agent_result.actions)}[/]")
77+
for i, action in enumerate(agent_result.actions):
78+
action_type = action.type
79+
80+
console.print(f" Action {i+1}: {action_type if action_type else 'Unknown'}")
81+
82+
# For debugging, you can also print the full JSON
83+
console.print("[dim]Full response JSON:[/]")
84+
console.print_json(f"{agent_result.model_dump_json()}")
85+
86+
# Close the session
87+
console.print("\n⏹️ [warning]Closing session...[/]")
88+
await stagehand.close()
89+
console.print("✅ [success]Session closed successfully![/]")
90+
console.rule("[bold]End of Example[/]")
91+
92+
93+
if __name__ == "__main__":
94+
# Add a fancy header
95+
console.print(
96+
"\n",
97+
Panel(
98+
"[light_gray]Stagehand 🤘 Agent Example[/]",
99+
border_style="green",
100+
padding=(1, 10),
101+
),
102+
)
103+
asyncio.run(main())

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "stagehand"
7-
version = "0.5.4"
7+
version = "0.5.5"
88
description = "Python SDK for Stagehand"
99
readme = "README.md"
1010
classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent",]

stagehand/agent/agent.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@
1717
from .openai_cua import OpenAICUAClient
1818

1919
MODEL_TO_CLIENT_CLASS_MAP: dict[str, type[AgentClient]] = {
20-
"computer-use-preview-03-11": OpenAICUAClient,
20+
"computer-use-preview-2025-03-11": OpenAICUAClient,
2121
"claude-3-5-sonnet-latest": AnthropicCUAClient,
2222
"claude-3-7-sonnet-latest": AnthropicCUAClient,
23+
"claude-haiku-4-5-20251001": AnthropicCUAClient,
2324
"claude-sonnet-4-20250514": AnthropicCUAClient,
2425
"claude-sonnet-4-5-20250929": AnthropicCUAClient,
2526
"gemini-2.5-computer-use-preview-10-2025": GoogleCUAClient,
2627
}
2728
MODEL_TO_PROVIDER_MAP: dict[str, AgentProvider] = {
28-
"computer-use-preview-03-11": AgentProvider.OPENAI,
29+
"computer-use-preview-2025-03-11": AgentProvider.OPENAI,
2930
"claude-3-5-sonnet-20240620": AgentProvider.ANTHROPIC,
3031
"claude-3-7-sonnet-20250219": AgentProvider.ANTHROPIC,
32+
"claude-haiku-4-5-20251001": AgentProvider.ANTHROPIC,
3133
"claude-sonnet-4-20250514": AgentProvider.ANTHROPIC,
3234
"claude-sonnet-4-5-20250929": AgentProvider.ANTHROPIC,
3335
"gemini-2.5-computer-use-preview-10-2025": AgentProvider.GOOGLE,
@@ -168,13 +170,10 @@ async def execute(
168170
f"Agent execution finished. Success: {agent_result.completed}. Message: {agent_result.message}",
169171
category="agent",
170172
)
171-
# To clean up pydantic model output
172-
actions_repr = [action.root for action in agent_result.actions]
173173
self.logger.debug(
174-
f"Agent actions: {actions_repr}",
174+
f"Agent actions: {agent_result.actions}",
175175
category="agent",
176176
)
177-
agent_result.actions = actions_repr
178177
return agent_result
179178
else:
180179
agent_config_payload = self.config.model_dump(

0 commit comments

Comments
 (0)