<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Adds a lightweight installer (`install_lite.sh`) that sets up the
`browser-use` CLI with minimal deps and Chromium, avoiding the full
library. Also extracts CLI deps into `requirements-cli.txt`, adds a CI
test, and hardens the installer with a `curl` pre-check and non-fatal
validate.
- New Features
- `install_lite.sh` installs Python 3.11+, `uv`, the CLI (`--no-deps`)
with minimal deps from `requirements-cli.txt`, and Chromium via `uvx
playwright` in `~/.browser-use-env`, and configures PATH (Linux, macOS,
Windows).
- Installs the `profile-use` helper into `~/.browser-use/bin` for
profile management.
- CI test (`tests/ci/test_cli_lite_deps.py`) boots the CLI in a clean
venv with only minimal deps and checks key imports.
- Minimal CLI deps pinned in
`browser_use/skill_cli/requirements-cli.txt`.
- Bug Fixes
- Validation is non-fatal; next steps are shown even if checks warn.
- Checks for `curl` before installing `uv` to prevent confusing
failures.
<sup>Written for commit 7e92031593.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Problem
Closes#4211
`browser_click` in the MCP server uses `oneOf` at the top level of
`inputSchema` to express "provide either `index` OR
`coordinate_x`+`coordinate_y`":
```json
{
"type": "object",
"properties": { ... },
"oneOf": [
{"required": ["index"]},
{"required": ["coordinate_x", "coordinate_y"]}
]
}
```
Claude's API (and other strict MCP clients) rejects
`oneOf`/`allOf`/`anyOf` at the top level of a tool input schema:
```
400 tools.N.custom.input_schema: input_schema does not support oneOf, allOf, or anyOf at the top level
```
This cascades — it breaks **all** MCP tools in the session, not just
`browser_click`.
## Fix
Remove the `oneOf` block. The constraint is now expressed in the
property descriptions instead. No behaviour change: the runtime guard in
`_click()` already returns a clear error string when neither `index` nor
coordinates are provided.
## Diff summary
- `-4 lines`: remove the `oneOf: [...]` block entirely
- `+3 lines`: update the three property descriptions to say "Provide
this OR ..."
The `_click()` handler is untouched.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Remove the top-level oneOf from the `browser_click` tool input schema so
Claude and other strict MCP clients accept it and the session doesn’t
break. No behavior change; `_click()` still validates, and field
descriptions now clarify using `index` or `coordinate_x`+`coordinate_y`.
<sup>Written for commit 6094cddd90.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
- derive cloud browser session UUID from Browser Use CDP host (e.g.
`<uuid>.cdp0.browser-use.com`)
- use that UUID as fallback in `BrowserSession.on_BrowserStopEvent` when
`_cloud_browser_client.current_session_id` is empty
- ensure reconnected sessions created via `BrowserSession(cdp_url=...)`
are properly stopped in cloud, not just reset locally
## Why
Reconnected cloud sessions (common MFA resume pattern) can leak browser
instances because stop logic only used `current_session_id`, which is
populated when the same process created the cloud browser. In reconnect
flows, that field is often unset.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Ensure cloud browser sessions are stopped when reconnecting via cdp_url,
preventing leaked instances during MFA/resume flows. We derive the
session UUID from the CDP URL host and pass it to `stop_browser` with
the explicit ID.
- **Bug Fixes**
- Added a helper to extract the session UUID from the CDP host (e.g.,
<uuid>.cdpN.browser-use.com).
- Updated stop logic to use `current_session_id` or the derived UUID and
call `stop_browser(id)`; logs now include the session ID.
<sup>Written for commit 4c883feb7c.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Resolves#4352
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes Windows tunnel lifecycle bugs by spawning `cloudflared` as a
detached daemon and reliably terminating it to prevent orphaned
processes. Resolves#4352.
- **Bug Fixes**
- Windows spawn uses `CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW`; Unix
uses `start_new_session=True`.
- Windows kill uses Win32 `OpenProcess/TerminateProcess` with brief
polling; Unix uses `SIGTERM` with `SIGKILL` fallback.
<sup>Written for commit 4950c3baa1.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
- Clear `last_model_output` and `last_result` at the start of `step()`
to prevent stale data from previous steps being recorded in history on
timeout
- Increment `n_steps` in `_execute_step`'s timeout handler to prevent
the main loop from retrying the same step number
Fixes#4480
## What changed
**`step()` — clear stale state at entry:**
```diff
self.step_start_time = time.time()
+
+ # Clear previous step state to prevent stale data from being recorded
+ self.state.last_model_output = None
+ self.state.last_result = None
+
browser_state_summary = None
```
**`_execute_step()` — ensure counter advances on timeout:**
```diff
self.state.last_result = [ActionResult(error=error_msg)]
+ # Ensure step counter advances on timeout
+ if self.state.n_steps == step + 1:
+ self.state.n_steps += 1
```
The guard `if self.state.n_steps == step + 1` prevents double-increment
when `_finalize()` has already incremented on the normal path.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes stale history entries and a stuck step counter when a step times
out. Clears per-step state after `_prepare_context` and ensures
`n_steps` advances on timeout.
- **Bug Fixes**
- Clear `last_model_output` and `last_result` right after
`_prepare_context` (before LLM/action calls) so prompts keep previous
output and timeouts don't record stale data.
- In `_execute_step()`, increment `n_steps` after a timeout (with a
guard) so the loop moves forward.
<sup>Written for commit c0a11dc61e.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Resolves#4510
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes double-serialized action fields in Anthropic tool responses to
prevent schema validation errors and failed tool calls. Preserves
original tracebacks in the fallback path.
- **Bug Fixes**
- Parse nested JSON strings in tool inputs; normalize newline/carriage
return/tab escapes when needed.
- Applied in `browser_use/llm/anthropic/chat.py` and
`browser_use/llm/aws/chat_anthropic.py`.
<sup>Written for commit f74a4435b1.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Slightly modified #4401
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Allow overriding the model pricing source for token cost calculations,
with URL-aware caching to keep caches from different sources separate.
Defaults remain the LiteLLM pricing JSON.
- **New Features**
- `TokenCost` accepts an optional `pricing_url`; `Agent(...,
pricing_url=...)` passes it through.
- New env var BROWSER_USE_MODEL_PRICING_URL to set a global pricing
source.
- Cache files now include `source_url` so multiple sources can coexist.
- **Bug Fixes**
- Cache validation and cleanup are source-aware and only remove expired
or same-source files.
<sup>Written for commit 4f268e4390.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Resolves#4491
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Make CDP navigation timeout configurable and apply it to
`Page.navigate`, fixing mismatched timeouts. This aligns
`NavigateToUrlEvent` (and `TIMEOUT_NavigateToUrlEvent`) with the actual
CDP call and prevents early failures on heavy pages.
- **Bug Fixes**
- Add `nav_timeout` to `_navigate_and_wait` and use it for
`Page.navigate(...)`.
- Pass `event.event_timeout`; default remains 20s when not provided.
Outer `timeout_ms` behavior is unchanged.
<sup>Written for commit 801b134f90.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Resolves#4492
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes daemon orphaning when the external browser or CDP connection dies
(with `--connect`, `--cdp-url`, or cloud). Adds safer connection
watching, bounded cleanup, and a hard exit that preserves the exit code.
Resolves#4492.
- **Bug Fixes**
- Skip shutdown while the browser is reconnecting; shut down only when
CDP stays disconnected.
- Prevent duplicate shutdowns by scheduling a single shutdown task.
- Add 10s timeouts around `browser_session.stop()`/`kill()` to avoid
hangs; log on timeout.
- Force process exit in `finally` via `os._exit(exit_code)` to preserve
error status and prevent orphaned daemons.
<sup>Written for commit a31809b83d.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Removed a redundant pass in the exception handler of
`SecurityWatchdog.on_NavigationCompleteEvent`, simplifying the code
while keeping error logging intact. No behavior change.
<sup>Written for commit 393d2c5b0f.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
The SignalHandler class registers SIGINT/SIGTERM handlers that override
host application signal handling. This breaks server embeddings
(uvicorn, FastAPI, etc.) where the framework needs to control the signal
lifecycle for graceful shutdown.
Add disabled parameter to SignalHandler class to allow opting out of
signal handling. Add enable_signal_handler parameter to Agent class
(default True for backward compatibility).
Usage for embedding applications:
Fixes#4385
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes#4385 by adding an opt-out for internal SIGINT/SIGTERM handling so
host apps like `uvicorn`/`FastAPI` can control graceful shutdown.
`SignalHandler` now supports `disabled`, and `Agent` adds
`enable_signal_handler` (default True).
- **Bug Fixes**
- `SignalHandler(disabled: bool)` added; when True,
`register()`/`unregister()` are no-ops.
- `Agent(enable_signal_handler: bool = True)` added and passed through
as `disabled=not enable_signal_handler`.
- **Migration**
- For embeddings, use `Agent(..., enable_signal_handler=False)` or
`SignalHandler(disabled=True)`.
<sup>Written for commit 4f33289c48.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
- Fix install script writing PATH to `~/.bashrc` instead of `~/.zshrc`
for zsh users
- Use `$SHELL` (user's login shell) instead of
`$BASH_VERSION`/`$ZSH_VERSION` (running shell) for shell detection
- When executed via `curl ... | bash`, the script always runs in bash,
so `$BASH_VERSION` is always set regardless of the user's actual shell
## Changes
- `configure_path()`: Replace `$BASH_VERSION`/`$ZSH_VERSION` check with
`$(basename "$SHELL")`
- `print_next_steps()`: Same fix for the shell RC file displayed in
completion message
This could be considered as a follow-up improvement if the maintainers
prefer.
Fixes#4440
Resolves#4411
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes Bedrock structured output by using `SchemaOptimizer` to generate a
flattened JSON Schema for tool inputs, preventing invalid schemas and
extraction errors. Resolves#4411.
- **Bug Fixes**
- Replaced manual `properties/required` builder with
`SchemaOptimizer.create_optimized_json_schema(...)`.
- Passed the optimized schema directly to `toolSpec.inputSchema.json`
for Bedrock tool calls.
<sup>Written for commit d897ffbd4c.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
As per the [Gemini 3 best practices
guide](https://ai.google.dev/gemini-api/docs/gemini-3#temperature),
temperature is recommended to stay at 1.0 for 3-series models. Currently
the default is 0.5 across the board, which is potentially detrimental.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Set dynamic default temperature: 1.0 for `gemini-3`, 0.5 otherwise; if
`temperature` is provided, it’s used as-is.
<sup>Written for commit c657ba72c3.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
Remove `litellm` from `pyproject.toml` dependencies entirely.
`ChatLiteLLM` wrapper is kept but requires manual installation:
```
pip install litellm
```
## What changed
- **pyproject.toml**: `litellm==1.82.2` removed from core dependencies
- **browser_use/llm/litellm/chat.py**: Added docstring noting manual
install requirement, added `# type: ignore` for pyright since litellm is
no longer in the environment
- **ChatLiteLLM stays in the public API** — it already lazy-imports
litellm inside methods, so users who don't use it are never affected
## Context
litellm versions 1.82.7 and 1.82.8 were backdoored on March 24, 2026 by
TeamPCP via a compromised Trivy CI/CD pipeline. `browser-use==0.12.3`
shipped `litellm>=1.82.2` (unpinned) as a core dependency, and BigQuery
analysis shows ~6,900 installs pulled the backdoored litellm during the
4-hour attack window.
By removing it from dependencies entirely, `pip install browser-use` no
longer pulls litellm, and browser-use will not appear in litellm's
dependency graph.
## References
- [TeamPCP Backdoors LiteLLM — The Hacker
News](https://thehackernews.com/2026/03/teampcp-backdoors-litellm-versions.html)
- [LiteLLM infected via Trivy — The
Register](https://www.theregister.com/2026/03/24/trivy_compromise_litellm/)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Medium risk because removing `litellm` from required dependencies can
break existing installs that relied on `ChatLiteLLM` working
out-of-the-box; runtime imports now require manual installation.
>
> **Overview**
> Stops installing `litellm` as a core dependency (and bumps the package
version to `0.12.5`), requiring users to install it explicitly when
using the LiteLLM integration.
>
> Keeps `ChatLiteLLM` but adds a module docstring documenting the manual
install and updates `litellm` imports with `# type: ignore` to avoid
type-check failures when `litellm` is absent.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d4b9e30188. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
litellm versions 1.82.7 and 1.82.8 were backdoored on March 24, 2026
by TeamPCP via a compromised Trivy CI/CD pipeline. browser-use 0.12.3
shipped litellm>=1.82.2 (unpinned) as a core dependency, exposing
~6,900 users to the backdoored versions during the 4-hour window.
This commit:
- Removes litellm entirely from pyproject.toml (core and optional)
- Keeps ChatLiteLLM wrapper intact with a docstring noting
`pip install litellm` is required separately
- litellm is already lazy-imported inside methods, so users who
don't use ChatLiteLLM are never affected
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>