Skip to content

Commit ad7a4d5

Browse files
committed
bump to 0.3.0, add persistent browser examples
1 parent bb04eea commit ad7a4d5

File tree

16 files changed

+742
-9
lines changed

16 files changed

+742
-9
lines changed

.cursor/environment.json

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

templates/python/browser-use/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ readme = "README.md"
66
requires-python = ">=3.11"
77
dependencies = [
88
"browser-use>=0.1.46",
9-
"kernel==0.2.0",
9+
"kernel==0.3.0",
1010
"langchain-openai>=0.3.11",
1111
"pydantic>=2.10.6",
1212
]
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
activate/
32+
33+
# IDE
34+
.idea/
35+
.vscode/
36+
*.swp
37+
*.swo
38+
.project
39+
.pydevproject
40+
.settings/
41+
42+
# Testing
43+
.coverage
44+
htmlcov/
45+
.pytest_cache/
46+
.tox/
47+
.nox/
48+
coverage.xml
49+
*.cover
50+
.hypothesis/
51+
52+
# Logs
53+
*.log
54+
logs/
55+
56+
# OS
57+
.DS_Store
58+
Thumbs.db
59+
60+
# Misc
61+
.cache/
62+
.pytest_cache/
63+
.mypy_cache/
64+
.ruff_cache/
65+
.temp/
66+
.tmp/
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Kernel Python Persistent Browser Example
2+
3+
This is a simple Kernel application that shows how to use a persistent browser.
4+
5+
The action reuses the same browser across invocations of the action, which lets it optimize for the case where the browser is already open and at the page of interest.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import kernel
2+
from kernel import Kernel
3+
from playwright.async_api import async_playwright
4+
from typing import TypedDict
5+
from urllib.parse import urlparse
6+
from datetime import datetime
7+
8+
client = Kernel()
9+
10+
# Create a new Kernel app
11+
app = kernel.App("python-persistent-browser")
12+
13+
class PageTitleInput(TypedDict):
14+
url: str
15+
16+
class PageTitleOutput(TypedDict):
17+
title: str
18+
elapsed_ms: float
19+
20+
@app.action("get-page-title")
21+
async def get_page_title(ctx: kernel.KernelContext, input_data: PageTitleInput) -> PageTitleOutput:
22+
"""
23+
A function that extracts the title of a webpage
24+
25+
Args:
26+
ctx: Kernel context containing invocation information
27+
input_data: An object with a URL property
28+
29+
Returns:
30+
A dictionary containing the page title
31+
"""
32+
url = input_data.get("url")
33+
if not url or not isinstance(url, str):
34+
raise ValueError("URL is required and must be a string")
35+
36+
# Add https:// if no protocol is present
37+
if not url.startswith(('http://', 'https://')):
38+
url = f"https://{url}"
39+
40+
# Validate the URL
41+
try:
42+
urlparse(url)
43+
except Exception:
44+
raise ValueError(f"Invalid URL: {url}")
45+
46+
# Create a browser instance using the context's invocation_id and a persistent id
47+
kernel_browser = client.browsers.create(
48+
invocation_id=ctx.invocation_id,
49+
persistence={"id": "my-awesome-persistent-browser-2"}
50+
)
51+
print("Kernel browser live view url: ", kernel_browser.browser_live_view_url)
52+
53+
async with async_playwright() as playwright:
54+
browser = await playwright.chromium.connect_over_cdp(kernel_browser.cdp_ws_url)
55+
try:
56+
now = datetime.now()
57+
context = len(browser.contexts) > 0 and browser.contexts[0] or await browser.new_context()
58+
page = len(context.pages) > 0 and context.pages[0] or await context.new_page()
59+
current_url = page.url
60+
print("Current url: ", current_url)
61+
if current_url != url:
62+
print("Not at url, navigating to it")
63+
await page.goto(url)
64+
else:
65+
print("Already at url, skipping navigation")
66+
# for some reason going straight to page.title() leads to an error: Page.title: Execution context was destroyed, most likely because of a navigation
67+
# calling bring_to_front() seems to fix it :shrug:
68+
await page.bring_to_front()
69+
title = await page.title()
70+
elapsedMilliseconds = (datetime.now() - now).total_seconds() * 1000
71+
return {"title": title, "elapsed_ms": elapsedMilliseconds}
72+
finally:
73+
await browser.close()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[project]
2+
name = "persistent-browser"
3+
version = "0.1.0"
4+
description = "Basic Kernel application that demonstrates the use of persistent browsers"
5+
readme = "README.md"
6+
requires-python = ">=3.11"
7+
dependencies = ["kernel==0.3.0", "playwright>=1.52.0"]
8+
9+
[dependency-groups]
10+
dev = ["mypy>=1.15.0"]

0 commit comments

Comments
 (0)