Skip to content

Commit dfe7fae

Browse files
authored
Merge pull request #9 from browser-use/sandbox
Add sandbox template for cloud browser automation
2 parents c91b96a + e0d6aa3 commit dfe7fae

File tree

13 files changed

+361
-266
lines changed

13 files changed

+361
-266
lines changed

.github/scripts/verify_template_output.py

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#!/usr/bin/env python3
22
"""
3-
Verify that template initialization created the expected files.
3+
Validate templates.json and verify that all referenced template files exist.
44
5-
Usage: python verify_template_output.py <template-name>
5+
Usage: python verify_template_output.py
66
"""
77

88
import json
@@ -11,60 +11,90 @@
1111

1212

1313
def main():
14-
if len(sys.argv) != 2:
15-
print("Usage: python verify_template_output.py <template-name>")
16-
sys.exit(1)
17-
18-
template_name = sys.argv[1]
1914
repo_root = Path(__file__).parent.parent.parent
2015
templates_json = repo_root / 'templates.json'
2116

22-
# Load templates.json
23-
with open(templates_json) as f:
24-
templates = json.load(f)
25-
26-
if template_name not in templates:
27-
print(f"✗ Template '{template_name}' not found in templates.json")
17+
# Validate templates.json is valid JSON
18+
try:
19+
with open(templates_json) as f:
20+
templates = json.load(f)
21+
print(f"✓ templates.json is valid JSON")
22+
except json.JSONDecodeError as e:
23+
print(f"✗ templates.json is invalid JSON: {e}")
2824
sys.exit(1)
29-
30-
config = templates[template_name]
31-
template_dir = repo_root / 'test-env' / template_name
32-
33-
# Check if template directory was created
34-
if not template_dir.exists():
35-
print(f"✗ Template directory '{template_dir}' was not created")
25+
except FileNotFoundError:
26+
print(f"✗ templates.json not found")
3627
sys.exit(1)
3728

38-
print(f"✓ Template directory created: {template_dir}")
29+
errors = []
3930

40-
# For simple templates, just check the output file exists
41-
if 'files' not in config:
42-
# Simple template - should have created test_output.py
43-
output_file = template_dir / 'test_output.py'
44-
if output_file.exists():
45-
print(f"✓ Output file created: {output_file}")
46-
sys.exit(0)
47-
else:
48-
print(f"✗ Output file not found: {output_file}")
49-
sys.exit(1)
31+
# Validate each template
32+
for template_name, config in templates.items():
33+
print(f"\nValidating template: {template_name}")
5034

51-
# For complex templates, check all expected files
52-
errors = []
53-
for file_spec in config['files']:
54-
dest = file_spec['dest']
55-
expected_file = template_dir / dest
35+
# Check required fields
36+
if 'file' not in config:
37+
errors.append(f"✗ {template_name}: missing 'file' field")
38+
print(errors[-1])
39+
continue
40+
41+
if 'description' not in config:
42+
errors.append(f"✗ {template_name}: missing 'description' field")
43+
print(errors[-1])
5644

57-
if expected_file.exists():
58-
print(f"✓ File created: {dest}")
45+
# Check main file exists
46+
main_file = repo_root / config['file']
47+
if main_file.exists():
48+
print(f" ✓ Main file exists: {config['file']}")
49+
50+
# Try to compile Python files
51+
if config['file'].endswith('.py'):
52+
try:
53+
import py_compile
54+
py_compile.compile(main_file, doraise=True)
55+
print(f" ✓ Python file compiles: {config['file']}")
56+
except py_compile.PyCompileError as e:
57+
errors.append(f"✗ {template_name}: Python compilation error in {config['file']}: {e}")
58+
print(errors[-1])
5959
else:
60-
errors.append(f"✗ Missing file: {dest}")
60+
errors.append(f"✗ {template_name}: main file not found: {config['file']}")
6161
print(errors[-1])
6262

63+
# Check all files in complex templates
64+
if 'files' in config:
65+
for file_spec in config['files']:
66+
source = file_spec.get('source')
67+
if not source:
68+
errors.append(f"✗ {template_name}: file spec missing 'source' field")
69+
print(errors[-1])
70+
continue
71+
72+
source_file = repo_root / source
73+
if source_file.exists():
74+
print(f" ✓ File exists: {source}")
75+
76+
# Try to compile Python files
77+
if source.endswith('.py'):
78+
try:
79+
import py_compile
80+
py_compile.compile(source_file, doraise=True)
81+
print(f" ✓ Python file compiles: {source}")
82+
except py_compile.PyCompileError as e:
83+
errors.append(f"✗ {template_name}: Python compilation error in {source}: {e}")
84+
print(errors[-1])
85+
else:
86+
errors.append(f"✗ {template_name}: source file not found: {source}")
87+
print(errors[-1])
88+
89+
# Print summary
90+
print("\n" + "="*50)
6391
if errors:
64-
print(f"\n{len(errors)} file(s) missing")
92+
print(f"✗ Validation failed with {len(errors)} error(s)")
93+
for error in errors:
94+
print(f" {error}")
6595
sys.exit(1)
6696
else:
67-
print(f"\n✓ All {len(config['files'])} expected files created")
97+
print(f"✓ All {len(templates)} template(s) validated successfully")
6898
sys.exit(0)
6999

70100

.github/workflows/lint.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ jobs:
2525
*/main.py \
2626
*/email_tools.py \
2727
*/launch_chrome_debug.py \
28-
*/app/*.py \
29-
--exclude test-env
28+
*/app/*.py
3029
3130
lint-format:
3231
name: code-format
@@ -41,5 +40,4 @@ jobs:
4140
*/main.py \
4241
*/email_tools.py \
4342
*/launch_chrome_debug.py \
44-
*/app/*.py \
45-
--exclude test-env
43+
*/app/*.py
Lines changed: 7 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
name: test-templates
22

3+
permissions:
4+
contents: read
5+
36
concurrency:
47
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
58
cancel-in-progress: true
@@ -12,56 +15,12 @@ on:
1215
workflow_dispatch:
1316

1417
jobs:
15-
find-templates:
16-
name: find-templates
17-
runs-on: ubuntu-latest
18-
outputs:
19-
templates: ${{ steps.get-templates.outputs.templates }}
20-
steps:
21-
- uses: actions/checkout@v4
22-
- name: Get template names from templates.json
23-
id: get-templates
24-
run: |
25-
templates=$(python3 -c "
26-
import json
27-
with open('templates.json') as f:
28-
data = json.load(f)
29-
print(json.dumps(list(data.keys())))
30-
")
31-
echo "templates=$templates" >> $GITHUB_OUTPUT
32-
33-
test-init:
34-
name: test-${{ matrix.template }}
35-
needs: find-templates
18+
validate-templates:
19+
name: validate-templates
3620
runs-on: ubuntu-latest
37-
strategy:
38-
fail-fast: false
39-
matrix:
40-
template: ${{ fromJson(needs.find-templates.outputs.templates) }}
4121
steps:
4222
- uses: actions/checkout@v4
43-
- uses: astral-sh/setup-uv@v5
44-
45-
- name: Setup test environment
46-
working-directory: test-env
47-
run: uv sync
48-
49-
- name: Test template initialization
50-
working-directory: test-env
51-
run: |
52-
uv run test_templates.py --template ${{ matrix.template }} --output test_output.py
53-
54-
- name: Debug generated files
55-
run: ls -la test-env/${{ matrix.template }}/ || echo "Directory not found"
56-
57-
- name: Verify files were created
58-
run: |
59-
python3 .github/scripts/verify_template_output.py ${{ matrix.template }}
6023

61-
- name: Compile generated Python files
24+
- name: Validate templates.json
6225
run: |
63-
# Find all .py files generated (exclude __pycache__)
64-
find test-env/${{ matrix.template }} -name "*.py" -not -path "*/.*" 2>/dev/null | while read file; do
65-
echo "Compiling $file"
66-
python3 -m py_compile "$file"
67-
done || echo "No Python files to compile (simple template)"
26+
python3 .github/scripts/verify_template_output.py

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
# Test environment - committed once, then ignored
2-
test-env/

README.md

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,22 @@ uvx browser-use init --template agentmail
4040

4141
## Testing Templates Locally
4242

43-
Before submitting a PR, you can test your templates locally using the included test environment:
43+
To test your templates before submitting a PR, you can modify the browser-use CLI to use your fork/branch:
4444

45-
```bash
46-
# First time setup
47-
cd test-env
48-
uv sync
49-
50-
# Test a simple template
51-
uv run test_templates.py --template default --output my_test.py
52-
53-
# Test a complex template
54-
uv run test_templates.py --template shopping --output my_bot
55-
```
45+
1. Fork this repository and create a branch with your changes
46+
2. Clone the browser-use repository and locate `browser_use/init_cmd.py`
47+
3. Find the `TEMPLATE_REPO_URL` variable (line 27, typically set to `https://raw.githubusercontent.com/browser-use/template-library/main`)
48+
4. Replace it with your fork and branch: `https://raw.githubusercontent.com/YOUR_USERNAME/template-library/YOUR_BRANCH`
49+
5. From the browser-use directory, test your template:
50+
```bash
51+
# Interactive mode (select from list)
52+
python -m browser_use.init_cmd
5653

57-
The test script monkey-patches browser-use CLI to use your local `templates.json` and template files instead of fetching from GitHub, allowing you to verify:
54+
# Direct template selection
55+
python -m browser_use.init_cmd --template your-template --output test.py
56+
```
5857

58+
This allows you to verify:
5959
- ✓ Template files are copied correctly
6060
-`next_steps` display properly
6161
- ✓ File permissions are set (executable files)
@@ -79,12 +79,6 @@ The test script monkey-patches browser-use CLI to use your local `templates.json
7979
}
8080
```
8181

82-
3. Test it locally:
83-
```bash
84-
cd test-env
85-
uv run test_templates.py --template my-template --output test.py
86-
```
87-
8882
### Complex Template (Multiple Files)
8983

9084
1. Create a new directory with your template files:
@@ -148,12 +142,6 @@ The test script monkey-patches browser-use CLI to use your local `templates.json
148142
}
149143
```
150144

151-
3. Test it locally:
152-
```bash
153-
cd test-env
154-
uv run test_templates.py --template my-template --output my_bot
155-
```
156-
157145
## Template Structure Reference
158146

159147
### templates.json Schema
@@ -325,8 +313,7 @@ The optional `featured` boolean flag marks templates for prominent display in th
325313
1. Fork this repository
326314
2. Create a new branch for your template
327315
3. Add your template files and update `templates.json`
328-
4. Test locally using `test-env/test_templates.py`
329-
5. Submit a PR with:
316+
4. Submit a PR with:
330317
- Clear description of what the template does
331318
- Use case or problem it solves
332319
- Any special requirements or dependencies

sandbox/.env.example.template

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Browser-Use API Key
2+
# Get your key at: https://cloud.browser-use.com/dashboard/settings?tab=api-keys&new
3+
BROWSER_USE_API_KEY=your-key-here
4+
5+
# Cloud Profile ID (optional - for persistent authentication)
6+
# Get your profile ID from: https://cloud.browser-use.com/#settings/profiles
7+
CLOUD_PROFILE_ID=your-profile-id-here
8+
9+
# Cloud Proxy Country Code (optional - default: us)
10+
CLOUD_PROXY_COUNTRY_CODE=us
11+
12+
# Cloud Session Timeout in minutes (optional - default: 60)
13+
CLOUD_TIMEOUT=60

0 commit comments

Comments
 (0)