chore: import upstream snapshot with attribution
Test Browser Use CLI Install / uv pip install (ubuntu-latest) (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use from local wheel (push) Failing after 1s
Test Browser Use CLI Install / uvx browser-use[cli] from PyPI (push) Failing after 1s
package / pip-install-on-macos-latest-py-3.11 (push) Has been skipped
package / pip-install-on-macos-latest-py-3.13 (push) Has been skipped
package / pip-install-on-ubuntu-latest-py-3.11 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.13 (push) Has been skipped
cloud_evals / trigger_cloud_eval_image_build (push) Failing after 1s
docker / build_publish_image (push) Failing after 1s
Test Browser Use CLI Install / browser-use skill sync (push) Failing after 1s
lint / code-style (push) Failing after 0s
lint / type-checker (push) Failing after 1s
package / pip-build (push) Failing after 1s
lint / syntax-errors (push) Failing after 3s
package / pip-install-on-ubuntu-latest-py-3.13 (push) Has been skipped
package / pip-install-on-windows-latest-py-3.11 (push) Has been skipped
test / ${{ matrix.test_filename }} (push) Has been skipped
test / evaluate-tasks (push) Has been skipped
test / setup-chromium (push) Failing after 2s
test / find_tests (push) Failing after 2s
Test Browser Use CLI Install / uv pip install (windows-latest) (push) Has been cancelled
Test Browser Use CLI Install / uv pip install (macos-latest) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:02:32 +08:00
commit 4cd2d4af2b
475 changed files with 121829 additions and 0 deletions
@@ -0,0 +1,43 @@
name: Build Base Image
on:
schedule:
- cron: '0 2 * * 1' # Weekly on Monday
workflow_dispatch:
push:
paths:
- 'Dockerfile.base'
jobs:
build-base:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [linux/amd64, linux/arm64]
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push base image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.base
platforms: ${{ matrix.platform }}
push: true
tags: |
browseruse/browseruse-base:chromium-138-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
browseruse/browseruse-base:latest-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
cache-from: type=registry,ref=browseruse/browseruse-base:buildcache-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
cache-to: type=registry,ref=browseruse/browseruse-base:buildcache-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }},mode=max
+150
View File
@@ -0,0 +1,150 @@
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
pull-requests: read
id-token: write
discussions: write
issues: write
env:
IS_SANDBOX: '1'
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true
activate-environment: true
- run: uv sync --dev --all-extras
- name: Detect installed Playwright version
run: echo "PLAYWRIGHT_VERSION=$(uv pip list --format json | jq -r '.[] | select(.name == "playwright") | .version')" >> $GITHUB_ENV
# - name: Cache chrome binaries
# uses: actions/cache@v4
# with:
# path: |
# /tmp/google-chrome-stable_current_amd64.deb
# key: ${{ runner.os }}-${{ runner.arch }}-chrome-stable
# - name: Install Chrome stable binary
# run: |
# sudo apt-get update -qq \
# && sudo curl -o "/tmp/google-chrome-stable_current_amd64.deb" --no-clobber "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" \
# && sudo apt-get install -y "/tmp/google-chrome-stable_current_amd64.deb" -f
# - run: patchright install chrome --with-deps
# - run: playwright install chrome --with-deps
- name: Cache chromium binaries
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-${{ runner.arch }}-playwright-${{ env.PLAYWRIGHT_VERSION }}-chromium
- run: playwright install chromium --with-deps
# - run: patchright install chromium --with-deps
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
model: "claude-opus-4-20250514"
fallback_model: "claude-3-5-sonnet-20241022"
custom_instructions: |
when making any significant changes, start by adding one or two new failing test functions to the most relevant file you can find in tests/ci/*.py, then work on your changes until you get the tests passing.
make sure all lint errors are fixed before committing: `uv run pre-commit --all-files`, you can also use mcp tools to check Github CI status.
make sure to run the whole test file at the end to make sure no other tests in that file started failing due to your changes: `uv run pytest/ci/test_....py`.
if any significant features were added or removed, or any public-facing parameters/signatures changed, make sure to look through docs/*.mdx and examples/**.py and fix any relevant areas that might need to be updated.
branch_prefix: "claude-"
additional_permissions: |
actions: read
claude_env: |
IN_DOCKER: 'true'
BROWSER_USE_CLOUD_SYNC: 'false'
ANONYMIZED_TELEMETRY: 'false'
BROWSER_USE_LOGGING_LEVEL: 'DEBUG'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PERPLEXITY_API_KEY: ${{ secrets.PERPLEXITY_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
settings: |
{
"permissions": {
"allow": [
"Bash(git:*)",
"Bash(uv:*)",
"Bash(uv run pytest:*)",
"Bash(uv run ruff:*)",
"Bash(uv run pyright:*)",
"Bash(uv run pre-commit:*)",
"Bash(uv pip:*)",
"Bash(uv add:*)",
"Bash(uv sync --all-extras --dev)",
"Bash(.venv/bin/*:*)",
"Bash(.venv/bin/python:*)",
"Bash(sed:*)",
"Bash(rg:*)",
"Bash(jq:*)",
"Bash(find:*)",
"Bash(grep:*)",
"Bash(python:*)",
"Bash(chmod:*)",
"Bash(rm:*)",
"Bash(playwright:*)",
"Bash(uv run playwright:*)",
"Bash(./bin/lint.sh)",
"Bash(./bin/test.sh)",
"WebFetch(*)",
"WebSearch(*)"
],
"additionalDirectories": ["/home/runner/work"]
}
}
allowed_tools: |
Bash(git:*)
Bash(uv:*)
Bash(uv run pytest:*)
Bash(uv run ruff:*)
Bash(uv run pyright:*)
Bash(uv run pre-commit:*)
Bash(uv pip:*)
Bash(uv add:*)
Bash(uv sync --all-extras --dev)
Bash(.venv/bin/*:*)
Bash(.venv/bin/python:*)
Bash(sed:*)
Bash(rg:*)
Bash(jq:*)
Bash(find:*)
Bash(grep:*)
Bash(python:*)
Bash(chmod:*)
Bash(rm:*)
Bash(playwright:*)
Bash(uv run playwright:*)
Bash(./bin/lint.sh)
Bash(./bin/test.sh)
WebFetch(*)
WebSearch(*)
+35
View File
@@ -0,0 +1,35 @@
name: cloud_evals
# Cancel in-progress runs when a new commit is pushed to the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
- 'releases/*'
workflow_dispatch:
inputs:
commit_hash:
description: Commit hash of the library to build the Cloud eval image for
required: false
permissions: {}
jobs:
trigger_cloud_eval_image_build:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
with:
github-token: ${{ secrets.TRIGGER_CLOUD_BUILD_GH_KEY }}
script: |
const result = await github.rest.repos.createDispatchEvent({
owner: 'browser-use',
repo: 'cloud',
event_type: 'trigger-workflow',
client_payload: {"commit_hash": "${{ github.event.inputs.commit_hash || github.sha }}"}
})
console.log(result)
+76
View File
@@ -0,0 +1,76 @@
name: docker
# Cancel in-progress runs when a new commit is pushed to the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
- stable
- 'releases/**'
tags:
- '*'
release:
types: [published]
workflow_dispatch:
jobs:
build_publish_image:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
attestations: write
id-token: write
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compute Docker tags based on tag/branch
id: meta
uses: docker/metadata-action@v5
with:
images: |
browseruse/browseruse
ghcr.io/browser-use/browser-use
tags: |
type=ref,event=branch
type=ref,event=pr
type=pep440,pattern={{version}}
type=pep440,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Docker image
id: push
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm64
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=browseruse/browseruse:buildcache
cache-to: type=registry,ref=browseruse/browseruse:buildcache,mode=max
+56
View File
@@ -0,0 +1,56 @@
name: Evaluate PR
permissions:
contents: read
pull-requests: write
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
trigger-evaluation:
runs-on: ubuntu-latest
# Only run if PR author has write access
if: |
github.event.pull_request.author_association == 'OWNER' ||
github.event.pull_request.author_association == 'MEMBER' ||
github.event.pull_request.author_association == 'COLLABORATOR'
steps:
- name: Trigger Evaluation settings
id: trigger
continue-on-error: true
run: |
echo "🚀 Triggering evaluation - PR #${{ github.event.pull_request.number }}"
echo "Commit: ${{ github.event.pull_request.head.sha }}"
# You can customize the test here
TEST_CASE="${{ vars.EVAL_TEST_CASE }}"
if [ -z "$TEST_CASE" ]; then
TEST_CASE="InteractionTasks_v8"
fi
response=$(curl -X POST \
"${{ secrets.EVAL_PLATFORM_URL }}/api/triggerInteractionTasksV6" \
-H "Authorization: Bearer ${{ secrets.EVAL_PLATFORM_KEY }}" \
-H "Content-Type: application/json" \
-d "{
\"commitSha\": \"${{ github.event.pull_request.head.sha }}\",
\"prNumber\": ${{ github.event.pull_request.number }},
\"branchName\": \"${{ github.event.pull_request.head.ref }}\",
\"testCase\": \"${TEST_CASE}\",
\"githubRepo\": \"${{ github.repository }}\"
}" -s)
echo "Response: $response"
# Check if trigger was was successful
if echo "$response" | jq -e '.success == true' > /dev/null; then
echo "✅ Evaluation triggered successfully"
exit 0
else
echo "Failed"
echo "$response"
exit 1
fi
+125
View File
@@ -0,0 +1,125 @@
name: Test Browser Use CLI Install
on:
push:
branches:
- main
paths:
- 'browser_use/cli.py'
- 'browser_use/skills/**'
- 'skills/browser-use/SKILL.md'
- 'browser_use/skills/browser-use/SKILL.md'
- 'scripts/sync_browser_harness_skill.py'
- 'pyproject.toml'
- '.github/workflows/install-script.yml'
pull_request:
paths:
- 'browser_use/cli.py'
- 'browser_use/skills/**'
- 'skills/browser-use/SKILL.md'
- 'browser_use/skills/browser-use/SKILL.md'
- 'scripts/sync_browser_harness_skill.py'
- 'pyproject.toml'
- '.github/workflows/install-script.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
check-browser-use-skill:
name: browser-use skill sync
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check generated Browser Use skill
run: python3 scripts/sync_browser_harness_skill.py --check
test-pip-install:
name: uv pip install (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Add uv to PATH
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Create venv and install browser-use
run: |
uv venv .venv --python 3.11
uv pip install --python .venv .
- name: Add venv to PATH
run: |
echo "$PWD/.venv/bin" >> $GITHUB_PATH
echo "$PWD/.venv/Scripts" >> $GITHUB_PATH
- name: Verify Browser Use CLI
run: |
browser-use --help
browser-use auth --help
browser-use skill show
- name: Verify aliases
run: |
browseruse --help
bu --help
browser --help
test-uvx-local-wheel:
name: uvx browser-use from local wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Add uv to PATH
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Build wheel from current branch
run: |
uv venv .venv --python 3.11
source .venv/bin/activate
uv pip install build
python -m build --wheel
- name: Verify uvx Browser Use CLI
run: |
WHEEL=$(ls dist/*.whl)
uvx --from "$WHEEL" browser-use --help
uvx --from "$WHEEL" browser-use auth --help
uvx --from "$WHEEL" browser-use skill show
test-uvx-pypi:
name: uvx browser-use[cli] from PyPI
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
steps:
- name: Install uv
run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Add uv to PATH
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Verify uvx Browser Use CLI
run: |
uvx "browser-use[cli]" --help
uvx "browser-use[cli]" auth --help
uvx "browser-use[cli]" skill show
+54
View File
@@ -0,0 +1,54 @@
name: lint
# Cancel in-progress runs when a new commit is pushed to the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
- stable
- 'releases/**'
tags:
- '*'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
lint-syntax:
name: syntax-errors
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- run: uv run ruff check --no-fix --select PLE
lint-style:
name: code-style
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- run: uv python install 3.11
- run: uv sync --dev --all-extras --python 3.11 --refresh-package browser-use-core
- run: uv run --no-sync pre-commit run --all-files --show-diff-on-failure
lint-typecheck:
name: type-checker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- run: uv sync --dev --all-extras --refresh-package browser-use-core # install extras for examples to avoid pyright missing imports errors-
- run: uv run --no-sync pyright
+64
View File
@@ -0,0 +1,64 @@
name: package
# Cancel in-progress runs when a new commit is pushed to the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
- stable
- 'releases/**'
tags:
- '*'
workflow_dispatch:
permissions:
contents: read
jobs:
build:
name: pip-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- run: uv build --python 3.12
- uses: actions/upload-artifact@v4
with:
name: dist-artifact
path: |
dist/*.whl
dist/*.tar.gz
build_test:
name: pip-install-on-${{ matrix.os }}-py-${{ matrix.python-version }}
needs: build
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.11", "3.13"]
env:
ANONYMIZED_TELEMETRY: 'false'
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- uses: actions/download-artifact@v4
with:
name: dist-artifact
- name: Set up venv and test for OS/Python versions
shell: bash
run: |
uv venv /tmp/testenv --python ${{ matrix.python-version }} --clear
if [[ "$RUNNER_OS" == "Windows" ]]; then
. /tmp/testenv/Scripts/activate
else
source /tmp/testenv/bin/activate
fi
uv pip install *.whl
python -c 'from browser_use import Agent, BrowserProfile, BrowserSession, Tools, ActionModel, ActionResult'
+142
View File
@@ -0,0 +1,142 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: publish
# Cancel in-progress runs when a new commit is pushed to the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
release:
types: [published] # publish full release to PyPI when a release is created on Github
# schedule:
# - cron: "0 17 * * FRI" # tag a pre-release on Github every Friday at 5 PM UTC
workflow_dispatch:
inputs:
create_tag:
description: "Create the next pre-release tag before publishing"
required: false
default: true
type: boolean
permissions:
contents: write
id-token: write
jobs:
tag_pre_release:
if: github.event_name == 'workflow_dispatch' && inputs.create_tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create pre-release tag
run: |
git fetch --tags
latest_tag=$(git tag --list --sort=-v:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+(rc[0-9]+)?$' | head -n 1)
if [ -z "$latest_tag" ]; then
echo "Failed to find the latest git tag from list:" > /dev/stderr
git tag --list --sort=-v:refname
exit 1
else
# Bump the tag rc version
if [[ "$latest_tag" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(rc([0-9]+))?$ ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
rc="${BASH_REMATCH[5]}"
echo "latest_tag: ${major}.${minor}.${patch}rc${rc:-0}"
if [ -z "$rc" ]; then
# No rc, so bump patch and set rc=1 # 0.2.1 -> 0.2.2rc1
patch=$((patch + 1))
new_tag="${major}.${minor}.${patch}rc1"
else
if [ "$rc" -ge 99 ]; then
echo "Error: rc version is already at 99 for tag $latest_tag, refusing to increment further." > /dev/stderr
exit 1
fi
rc=$((rc + 1))
new_tag="${major}.${minor}.${patch}rc${rc}" # 0.2.1rc1 -> 0.2.1rc2
fi
else
echo "Error: latest_tag '$latest_tag' does not match expected version pattern." > /dev/stderr
exit 1
fi
fi
echo "new_tag: $new_tag"
git tag $new_tag
git push origin $new_tag
publish_to_pypi:
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
environment: release
permissions:
contents: write # for the stable-branch push at the end
id-token: write # for PyPI trusted-publishing OIDC
actions: read # for the env protection verification step
env:
IN_DOCKER: 'True'
ANONYMIZED_TELEMETRY: 'false'
steps:
- name: Verify release environment is protected (fail-closed)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
ENV_NAME="release"
if ! RESP="$(gh api -H 'Accept: application/vnd.github+json' \
"/repos/${GITHUB_REPOSITORY}/environments/${ENV_NAME}" 2>/dev/null)"; then
echo "::error::Environment '${ENV_NAME}' does not exist (or is inaccessible). Create it at https://github.com/${GITHUB_REPOSITORY}/settings/environments/new with required reviewers and prevent_self_review enabled, then re-run."
exit 1
fi
HAS_REVIEWERS="$(echo "$RESP" | jq -r '[.protection_rules[]? | select(.type == "required_reviewers")] | length')"
if [ "${HAS_REVIEWERS:-0}" -lt 1 ]; then
echo "::error::Environment '${ENV_NAME}' exists but has no required-reviewers protection rule."
exit 1
fi
SELF_REVIEW_BLOCKED="$(echo "$RESP" | jq -r '[.protection_rules[]? | select(.type=="required_reviewers") | .prevent_self_review] | any')"
if [ "$SELF_REVIEW_BLOCKED" != "true" ]; then
echo "::error::Environment '${ENV_NAME}' must have prevent_self_review enabled. Without it, the gate collapses to one identity when the dispatcher is also a reviewer."
exit 1
fi
echo "::notice::Environment '${ENV_NAME}' is protected with prevent_self_review. OK."
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true
activate-environment: true
- run: uv sync
- run: uv run --no-sync ruff check --no-fix --select PLE # quick check for syntax errors to avoid waiting time doing the rest of the build
- run: uv build
# - name: Detect installed Playwright version
# run: echo "PLAYWRIGHT_VERSION=$(uv pip list --format json | jq -r '.[] | select(.name == "playwright") | .version')" >> $GITHUB_ENV
# - name: Cache playwright binaries
# uses: actions/cache@v3
# with:
# path: |
# ~/.cache/ms-playwright
# key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- run: uvx playwright install chrome
- run: uvx playwright install chromium
# TODO: just depend on the other test.yml action for this instead of re-running the tests here
# - run: uv run pytest tests/ci/test_tools.py # final sanity check: run a few of the tests before release
# publish to PyPI
- run: uv publish --trusted-publishing always
- name: Push to stable branch (if stable release)
if: github.event_name == 'release' && !contains(github.ref_name, 'rc')
run: |
git checkout -b stable
git push origin -f stable
+108
View File
@@ -0,0 +1,108 @@
name: 'Manage stale issues and PRs'
on:
schedule:
- cron: '0 2 * * *' # Run daily at 2:00 AM UTC
workflow_dispatch: # Allow manual triggering
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
with:
# General settings
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Days before marking as stale (more lenient for AI/browser automation project)
days-before-stale: 60
days-before-close: 14
# Different timing for PRs vs issues
days-before-pr-stale: 45
days-before-pr-close: 14
# Stale labels
stale-issue-label: 'stale'
stale-pr-label: 'stale'
# Remove stale label when there's activity
remove-stale-when-updated: true
remove-issue-stale-when-updated: true
remove-pr-stale-when-updated: true
# Messages
stale-issue-message: |
👋 This issue has been automatically marked as stale because it hasn't had activity for 60 days.
**⚡ We've made significant progress recently!** Please test with the latest version of browser-use to see if this issue has been resolved. If the issue persists, please let us know by commenting below.
**To keep this issue open:**
- Add a comment explaining why this is still relevant after testing the latest version
- Add the `pinned` label if this is an important long-term issue
- Reference it in a PR if you're working on a fix
**This will be automatically closed in 14 days** if no further activity occurs.
Thanks for contributing to browser-use! 🤖 If you have questions, join our [Discord](https://discord.gg/uC9hDSbt).
stale-pr-message: |
👋 This PR has been automatically marked as stale because it hasn't had activity for 45 days.
**To keep this PR open:**
- Rebase against the latest main branch
- Address any review feedback or merge conflicts
- Add a comment explaining the current status
- Add the `work-in-progress` label if you're still actively working on this
**This will be automatically closed in 14 days** if no further activity occurs.
Thanks for contributing to browser-use! 🤖
close-issue-message: |
🔒 This issue was automatically closed because it was stale for 14 days with no activity.
**Don't worry!** If this issue is still relevant:
- **First, test with the latest version** - we've made tons of improvements recently!
- **Reopen it** if you have permissions and the issue persists
- **Create a fresh issue** with updated information if the problem still exists after testing the latest version
- **Join our [Discord](https://discord.gg/uC9hDSbt)** to discuss
We appreciate your contribution to browser-use! 🤖
close-pr-message: |
🔒 This PR was automatically closed because it was stale for 14 days with no activity.
**Don't worry!** If you'd like to continue this work:
- **Reopen this PR** and rebase against main
- **Create a fresh PR** with updated changes
- **Join our [Discord](https://discord.gg/uC9hDSbt)** if you need help
Thanks for contributing to browser-use! 🤖
# Comprehensive exemptions for AI/browser automation project
exempt-issue-labels: 'pinned,security,bug,enhancement,good-first-issue,help-wanted,documentation,ci,breaking-change,feature-request,roadmap'
exempt-pr-labels: 'pinned,work-in-progress,wip,breaking-change,security,dependencies,ci'
exempt-milestones: true
exempt-all-assignees: true
exempt-all-pr-assignees: true
# Don't mark issues/PRs stale if they have recent PR references
exempt-pr-author: true
# Advanced settings
operations-per-run: 200 # More conservative to avoid rate limits
ascending: true # Process oldest issues first
# Enable debug output
debug-only: false
# Only process issues/PRs, not drafts
include-only-assigned: false
# Additional safety: don't close issues with many reactions (community interest)
ignore-issue-updates: false
ignore-pr-updates: false
+337
View File
@@ -0,0 +1,337 @@
name: test
permissions:
actions: read
contents: write
pull-requests: write # Allow writing comments on PRs
issues: write # Allow writing comments on issues
statuses: write # Allow writing statuses on PRs
discussions: write
# Cancel in-progress runs when a new commit is pushed to the same branch/PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
- stable
- 'releases/**'
tags:
- '*'
pull_request:
workflow_dispatch:
jobs:
setup-chromium:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- name: Get week number for cache key
id: week
run: echo "number=$(date +%Y-W%U)" >> $GITHUB_OUTPUT
- name: Cache chromium binaries
id: cache-chromium
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-${{ runner.arch }}-chromium-${{ steps.week.outputs.number }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-chromium-
- name: Install Chromium if not cached
if: steps.cache-chromium.outputs.cache-hit != 'true'
run: uvx playwright install chromium --with-deps --no-shell
find_tests:
runs-on: ubuntu-latest
timeout-minutes: 5 # Prevent hanging
outputs:
TEST_FILENAMES: ${{ steps.lsgrep.outputs.TEST_FILENAMES }}
# ["test_browser", "test_tools", "test_browser_session", "test_tab_management", ...]
steps:
- uses: actions/checkout@v4
with:
# Force fresh checkout to avoid any caching issues
fetch-depth: 1
- id: lsgrep
run: |
echo "🔍 Discovering test files at $(date)"
echo "Git commit: $(git rev-parse HEAD)"
echo "Git branch: $(git branch --show-current)"
echo ""
TEST_FILENAMES="$(find tests/ci -name 'test_*.py' -type f | sed 's|^tests/ci/||' | sed 's|\.py$||' | jq -R -s -c 'split("\n")[:-1]')"
echo "TEST_FILENAMES=${TEST_FILENAMES}" >> "$GITHUB_OUTPUT"
echo "📋 Test matrix: $TEST_FILENAMES"
# https://code.dblock.org/2021/09/03/generating-task-matrix-by-looping-over-repo-files-with-github-actions.html
- name: Check that at least one test file is found
run: |
if [ -z "${{ steps.lsgrep.outputs.TEST_FILENAMES }}" ]; then
echo "Failed to find any test_*.py files in tests/ci/ folder!" > /dev/stderr
exit 1
fi
tests:
needs: [setup-chromium, find_tests]
runs-on: ubuntu-latest
timeout-minutes: 4 # Reduced timeout - tests should complete quickly or retry
env:
IN_DOCKER: 'True'
ANONYMIZED_TELEMETRY: 'false'
BROWSER_USE_LOGGING_LEVEL: 'DEBUG'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PERPLEXITY_API_KEY: ${{ secrets.PERPLEXITY_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
AZURE_OPENAI_KEY: ${{ secrets.AZURE_OPENAI_KEY }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
BROWSER_USE_API_KEY: ${{ secrets.BROWSER_USE_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
strategy:
matrix:
test_filename: ${{ fromJson(needs.find_tests.outputs.TEST_FILENAMES || '["FAILED_TO_DISCOVER_TESTS"]') }}
# autodiscovers all the files in tests/ci/test_*.py
# - test_browser
# - test_tools
# - test_browser_session
# - test_tab_management
# ... and more
name: ${{ matrix.test_filename }}
steps:
- name: Check that the previous step managed to find some test files for us to run
run: |
if [[ "${{ matrix.test_filename }}" == "FAILED_TO_DISCOVER_TESTS" ]]; then
echo "Failed get list of test files in tests/ci/test_*.py from find_tests job" > /dev/stderr
exit 1
fi
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true
activate-environment: true
- name: Cache uv packages and venv
uses: actions/cache@v4
with:
path: |
~/.cache/uv
.venv
key: ${{ runner.os }}-uv-venv-${{ hashFiles('pyproject.toml') }}
restore-keys: |
${{ runner.os }}-uv-venv-
- run: uv sync --dev --all-extras --refresh-package browser-use-core
- name: Get week number for cache key
id: week
run: echo "number=$(date +%Y-W%U)" >> $GITHUB_OUTPUT
- name: Cache chromium binaries
id: cache-chromium
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-${{ runner.arch }}-chromium-${{ steps.week.outputs.number }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-chromium-
- name: Install Chromium browser if not cached
if: steps.cache-chromium.outputs.cache-hit != 'true'
run: uvx playwright install chromium --with-deps --no-shell
- name: Cache browser-use extensions
uses: actions/cache@v4
with:
path: |
~/.config/browseruse/extensions
key: ${{ runner.os }}-browseruse-extensions-${{ hashFiles('browser_use/browser/profile.py') }}
restore-keys: |
${{ runner.os }}-browseruse-extensions-
- name: Check if test file exists
id: check-file
run: |
TEST_FILE="tests/ci/${{ matrix.test_filename }}.py"
if [ -f "$TEST_FILE" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "✅ Test file found: $TEST_FILE"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "❌ Test file not found: $TEST_FILE"
echo "This file may have been renamed or removed. Current test files:"
find tests/ci -name 'test_*.py' -type f | sed 's|tests/ci/||' | sed 's|\.py$||' | sort
fi
- name: Run test with retry
if: steps.check-file.outputs.exists == 'true'
uses: nick-fields/retry@v3
with:
timeout_minutes: 4
max_attempts: 1
retry_on: error
command: pytest "tests/ci/${{ matrix.test_filename }}.py"
evaluate-tasks:
needs: setup-chromium
runs-on: ubuntu-latest
timeout-minutes: 8 # Allow more time for agent eval
env:
IN_DOCKER: 'true'
BROWSER_USE_CLOUD_SYNC: 'false'
ANONYMIZED_TELEMETRY: 'false'
BROWSER_USE_LOGGING_LEVEL: 'DEBUG'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PERPLEXITY_API_KEY: ${{ secrets.PERPLEXITY_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
BROWSER_USE_API_KEY: ${{ secrets.BROWSER_USE_API_KEY }}
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true
activate-environment: true
- name: Cache uv packages and venv
uses: actions/cache@v4
with:
path: |
~/.cache/uv
.venv
key: ${{ runner.os }}-uv-venv-${{ hashFiles('pyproject.toml') }}
restore-keys: |
${{ runner.os }}-uv-venv-
- run: uv sync --dev --all-extras --refresh-package browser-use-core
- name: Get week number for cache key
id: week
run: echo "number=$(date +%Y-W%U)" >> $GITHUB_OUTPUT
- name: Cache chromium binaries
id: cache-chromium
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-${{ runner.arch }}-chromium-${{ steps.week.outputs.number }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-chromium-
- name: Install Chromium browser if not cached
if: steps.cache-chromium.outputs.cache-hit != 'true'
run: uvx playwright install chromium --with-deps --no-shell
- name: Cache browser-use extensions
uses: actions/cache@v4
with:
path: |
~/.config/browseruse/extensions
key: ${{ runner.os }}-browseruse-extensions-${{ hashFiles('browser_use/browser/profile.py') }}
restore-keys: |
${{ runner.os }}-browseruse-extensions-
- name: Run agent tasks evaluation and capture score
id: eval
uses: nick-fields/retry@v3
with:
timeout_minutes: 4
max_attempts: 1
retry_on: error
command: |
python tests/ci/evaluate_tasks.py > result.txt
cat result.txt
echo "PASSED=$(grep '^PASSED=' result.txt | cut -d= -f2)" >> $GITHUB_ENV
echo "TOTAL=$(grep '^TOTAL=' result.txt | cut -d= -f2)" >> $GITHUB_ENV
echo "DETAILED_RESULTS=$(grep '^DETAILED_RESULTS=' result.txt | cut -d= -f2-)" >> $GITHUB_ENV
- name: Print agent evaluation summary
run: |
echo "Agent tasks passed: $PASSED / $TOTAL"
- name: Write agent evaluation summary to workflow overview
run: |
if [ "$PASSED" = "$TOTAL" ]; then
COLOR="green"
else
COLOR="yellow"
fi
echo "<h2>Agent Tasks Score: <span style='color:$COLOR;'>$PASSED/$TOTAL</span></h2>" >> $GITHUB_STEP_SUMMARY
- name: Comment PR with agent evaluation results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
const passed = parseInt(process.env.PASSED);
const total = parseInt(process.env.TOTAL);
const detailedResults = JSON.parse(process.env.DETAILED_RESULTS);
const score = `${passed}/${total}`;
const percentage = Math.round((passed / total) * 100);
// Fail the workflow if 0% pass rate
if (percentage === 0) {
core.setFailed(`Evaluation failed: 0% pass rate (${passed}/${total})`);
}
// Create detailed table
let tableRows = '';
detailedResults.forEach(result => {
const emoji = result.success ? '✅' : '❌';
const status = result.success ? 'Pass' : 'Fail';
tableRows += `| ${result.task} | ${emoji} ${status} | ${result.reason} |\n`;
});
const comment = `## Agent Task Evaluation Results: ${score} (${percentage}%)
<details>
<summary>View detailed results</summary>
| Task | Result | Reason |
|------|--------|--------|
${tableRows}
Check the [evaluate-tasks job](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for detailed task execution logs.
</details>`;
// Find existing comment to update or create new one
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Agent Task Evaluation Results')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: comment
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
}