Skip to content

Commit 637b49a

Browse files
committed
Change BU config default viewport sizing to match kernel default.
1 parent c25c882 commit 637b49a

File tree

7 files changed

+5429
-0
lines changed

7 files changed

+5429
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copy this file to .env and fill in your API key
2+
OPENAI_API_KEY=your_openai_api_key_here
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
.Python
7+
build/
8+
develop-eggs/
9+
dist/
10+
downloads/
11+
eggs/
12+
.eggs/
13+
lib/
14+
lib64/
15+
parts/
16+
sdist/
17+
var/
18+
wheels/
19+
*.egg-info/
20+
.installed.cfg
21+
*.egg
22+
23+
# Virtual Environment
24+
.env
25+
.venv
26+
env/
27+
venv/
28+
ENV/
29+
env.bak/
30+
venv.bak/
31+
32+
# IDE
33+
.idea/
34+
.vscode/
35+
*.swp
36+
*.swo
37+
.project
38+
.pydevproject
39+
.settings/
40+
41+
# Testing
42+
.coverage
43+
htmlcov/
44+
.pytest_cache/
45+
.tox/
46+
.nox/
47+
coverage.xml
48+
*.cover
49+
.hypothesis/
50+
51+
# Logs
52+
*.log
53+
logs/
54+
55+
# OS
56+
.DS_Store
57+
Thumbs.db
58+
59+
# Browser Use specific
60+
.playwright-screenshots/
61+
.playwright-videos/
62+
.playwright-report/
63+
test-results/
64+
blob-report/
65+
playwright/.cache/
66+
playwright/.local-browsers/
67+
68+
# Misc
69+
.cache/
70+
.pytest_cache/
71+
.mypy_cache/
72+
.ruff_cache/
73+
.temp/
74+
.tmp/
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Kernel Python Sample App - Browser Use
2+
3+
This is a simple Kernel application that implements the Browser Use SDK.
4+
5+
See the [docs](https://www.kernel.sh/docs/build/browser-frameworks) for information.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from typing import TypedDict
2+
3+
import kernel
4+
from browser_use import Agent, Browser
5+
from browser_use.llm import ChatOpenAI
6+
from kernel import Kernel
7+
8+
client = Kernel()
9+
10+
app = kernel.App("python-bu")
11+
12+
13+
class TaskInput(TypedDict):
14+
task: str
15+
16+
17+
# LLM API Keys are set in the environment during `kernel deploy <filename> -e OPENAI_API_KEY=XXX`
18+
# See https://www.kernel.sh/docs/launch/deploy#environment-variables
19+
llm = ChatOpenAI(model="gpt-4.1")
20+
21+
22+
@app.action("bu-task")
23+
async def bu_task(ctx: kernel.KernelContext, input_data: TaskInput):
24+
"""
25+
A function that runs a Browser Use agent
26+
27+
Args:
28+
ctx: Kernel context containing invocation information
29+
input_data: An object with a BU task
30+
31+
Returns:
32+
An object with final_result and errors properties
33+
"""
34+
35+
kernel_browser = client.browsers.create(
36+
invocation_id=ctx.invocation_id, stealth=True
37+
)
38+
print("Kernel browser live view url: ", kernel_browser.browser_live_view_url)
39+
#######################################
40+
# Your Browser Use implementation here
41+
#######################################
42+
43+
try:
44+
browser = Browser(
45+
cdp_url=kernel_browser.cdp_ws_url,
46+
headless=False,
47+
window_size={"width": 1920, "height": 1080},
48+
viewport={"width": 1920, "height": 1080},
49+
device_scale_factor=1.0,
50+
)
51+
52+
agent = Agent(
53+
# task="Compare the price of gpt-4o and DeepSeek-V3",
54+
task=input_data["task"],
55+
llm=llm,
56+
# browser_session=BrowserSessionCustomResize(cdp_url=kernel_browser.cdp_ws_url)
57+
browser_session=browser,
58+
)
59+
result = await agent.run()
60+
if result.final_result() is not None:
61+
return {"final_result": result.final_result()}
62+
return {"errors": result.errors()}
63+
finally:
64+
client.browsers.delete_by_id(kernel_browser.session_id)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[project]
2+
name = "python-bu"
3+
version = "0.1.0"
4+
description = "Kernel sample app for Browser Use"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
dependencies = [
8+
"browser-use>=0.11.1",
9+
"kernel>=0.23.0",
10+
"pydantic>=2.12.5",
11+
]
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# This file may be needed to help resize the browser session for projects using browser-use versions < 0.7.9
2+
3+
from browser_use import BrowserSession
4+
5+
# Define a subclass of BrowserSession that overrides _setup_viewports (which mishandles resizeing on connecting via cdp)
6+
class BrowserSessionCustomResize(BrowserSession):
7+
async def _setup_viewports(self) -> None:
8+
"""Resize any existing page viewports to match the configured size, set up storage_state, permissions, geolocation, etc."""
9+
10+
assert self.browser_context, 'BrowserSession.browser_context must already be set up before calling _setup_viewports()'
11+
12+
self.browser_profile.window_size = {"width": 1024, "height": 786}
13+
self.browser_profile.viewport = {"width": 1024, "height": 786}
14+
self.browser_profile.screen = {"width": 1024, "height": 786}
15+
self.browser_profile.device_scale_factor = 1.0
16+
17+
# log the viewport settings to terminal
18+
viewport = self.browser_profile.viewport
19+
# if we have any viewport settings in the profile, make sure to apply them to the entire browser_context as defaults
20+
if self.browser_profile.permissions:
21+
try:
22+
await self.browser_context.grant_permissions(self.browser_profile.permissions)
23+
except Exception as e:
24+
print(e)
25+
try:
26+
if self.browser_profile.default_timeout:
27+
self.browser_context.set_default_timeout(self.browser_profile.default_timeout)
28+
if self.browser_profile.default_navigation_timeout:
29+
self.browser_context.set_default_navigation_timeout(self.browser_profile.default_navigation_timeout)
30+
except Exception as e:
31+
print(e)
32+
try:
33+
if self.browser_profile.extra_http_headers:
34+
self.browser_context.set_extra_http_headers(self.browser_profile.extra_http_headers)
35+
except Exception as e:
36+
print(e)
37+
38+
try:
39+
if self.browser_profile.geolocation:
40+
await self.browser_context.set_geolocation(self.browser_profile.geolocation)
41+
except Exception as e:
42+
print(e)
43+
44+
await self.load_storage_state()
45+
46+
page = None
47+
48+
for page in self.browser_context.pages:
49+
# apply viewport size settings to any existing pages
50+
if viewport:
51+
await page.set_viewport_size(viewport)
52+
53+
# show browser-use dvd screensaver-style bouncing loading animation on any about:blank pages
54+
if page.url == 'about:blank':
55+
await self._show_dvd_screensaver_loading_animation(page)
56+
57+
page = page or (await self.browser_context.new_page())
58+
59+
if (not viewport) and (self.browser_profile.window_size is not None) and not self.browser_profile.headless:
60+
# attempt to resize the actual browser window
61+
62+
# cdp api: https://chromedevtools.github.io/devtools-protocol/tot/Browser/#method-setWindowBounds
63+
try:
64+
cdp_session = await page.context.new_cdp_session(page)
65+
window_id_result = await cdp_session.send('Browser.getWindowForTarget')
66+
await cdp_session.send(
67+
'Browser.setWindowBounds',
68+
{
69+
'windowId': window_id_result['windowId'],
70+
'bounds': {
71+
**self.browser_profile.window_size,
72+
'windowState': 'normal', # Ensure window is not minimized/maximized
73+
},
74+
},
75+
)
76+
await cdp_session.detach()
77+
except Exception as e:
78+
_log_size = lambda size: f'{size["width"]}x{size["height"]}px'
79+
try:
80+
# fallback to javascript resize if cdp setWindowBounds fails
81+
await page.evaluate(
82+
"""(width, height) => {window.resizeTo(width, height)}""",
83+
**self.browser_profile.window_size,
84+
)
85+
return
86+
except Exception as e:
87+
pass

0 commit comments

Comments
 (0)