## Summary
- preserve caller-provided `available_file_paths` ordering when
downloads are discovered
- append new downloads in discovery order while deduplicating repeated
paths
- add a regression test covering existing inputs, ordered downloads, and
duplicate download entries
## Problem
`Agent._update_available_file_paths()` converted both the existing file
list and the latest downloads to sets, then rebuilt
`available_file_paths` from their union. Set iteration order is not the
order supplied by the caller or the browser, so the
`<available_file_paths>` block exposed to the model could change order
across processes.
## Fix
Use a set only for membership checks. Keep the original list as the
output source of truth and append each unseen download in first-seen
order.
## Verification
- regression test: RED on `main`, GREEN with this change
- `uv run pytest -q tests/ci/test_agent_download_paths.py
tests/ci/test_beta_agent.py -x`: 202 passed, 1 skipped
- `uv run pyright browser_use/agent/service.py
tests/ci/test_agent_download_paths.py`: 0 errors
- Ruff lint and format checks passed
- full `tests/ci` reached 479 passed / 33 skipped before one
pre-existing module-identity assertion failed; that exact test passed
when rerun alone
AI assistance was used to help inspect the codebase, draft the
regression test, and validate the change.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes unstable ordering of `available_file_paths` by preserving the
caller's list order and appending new downloads in discovery order.
Prevents reordering across processes and removes duplicates.
- **Bug Fixes**
- Replaced set-union logic with list + membership checks to keep
original order.
- Append only unseen downloads in first-seen order; ignore duplicates.
- Added regression test covering input order, download order, and
duplicate entries.
<sup>Written for commit e785b615d2.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5453?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Summary
- match URL negation terms as whole words instead of arbitrary
substrings
- share the negation matcher across the standard and beta agent URL
extractors
- add regression coverage for both a false positive (`notable`) and an
explicit negation (`do not`)
## Problem
The direct-navigation URL extractors used substring checks for `not`. As
a result, normal prose such as `Open this notable site:
https://example.com` was treated as a negated instruction, so the agent
skipped its initial navigation action.
## Testing
- `python -m pytest -o addopts=''
tests/ci/test_beta_agent.py::test_beta_agent_exposes_task_helper_methods`
- `ruff check browser_use/utils.py browser_use/agent/service.py
browser_use/beta/service.py tests/ci/test_beta_agent.py`
- `ruff format --check browser_use/utils.py browser_use/agent/service.py
browser_use/beta/service.py tests/ci/test_beta_agent.py`
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Matches URL negations as whole words during direct-navigation
extraction, so prose like "notable" no longer causes false skips.
Previously the extractors substring-matched "not"; now both agents share
a word-boundary regex for never/not/don't (straight or curly
apostrophes) in the 20-character pre-URL context.
- Adds `URL_NEGATION_PATTERN` and `has_url_negation` in
`browser_use/utils.py`; used by `browser_use/agent/service.py` and
`browser_use/beta/service.py`.
- Removes per-extractor `excluded_words`; keeps the 20-character window;
injects the scheme after the negation check; updates debug messaging.
- Adds regression tests allowing "notable" and blocking "Do not open …"
for both agents.
<sup>Written for commit c05a826af8.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5493?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## What
Treat keys inside a schema `properties` map as user field names before
applying schema-keyword rules. This keeps fields named `description` or
`properties` from retaining dangling `$ref` values.
Fixes#5603
## Test
- `uv run pytest -q tests/ci/models/test_llm_schema_optimizer.py`
- `uv run pre-commit run --files browser_use/llm/schema.py
tests/ci/models/test_llm_schema_optimizer.py`
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes schema optimization so user fields named `description` or
`properties` no longer keep dangling `$ref` values.
- Treats keys inside a `properties` map as field names before applying
schema-keyword rules.
- Simplifies `title` skipping, which now only applies outside
`properties`.
- Adds coverage for nested and aliased fields named after schema
keywords.
<sup>Written for commit b2507091aa.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5605?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Why
The official `cloud` skill still routes new hosted-agent integrations
through
API v2 or v3. Browser Use's current Cloud quickstart uses API v4, so
agents that
load the skill miss the current run, session, and workspace flow.
## What changed
- add a focused API v4 reference for Python, TypeScript, and REST
- route new hosted-agent setup to v4 while keeping v2 and v3 available
for existing integrations
- document the current browser boundary: v4 REST, explicit v3 SDK
namespace, and explicit stop required
- mark the old quickstart as the legacy v2 path
## Verification
- Cloud skill validator passed
- all 12 routed references resolve
- three Python examples parse
- six documented REST routes match the current v4 OpenAPI spec
- repository pre-commit passed for all three changed files
- three skill-install CI tests passed
- `git diff --check` passed
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an API v4 reference to the `cloud` skill and routes new
hosted-agent setups to v4, while keeping v2 and v3 available for
existing integrations.
- Documents runs, sessions, workspaces, and direct browser control with
Python, TypeScript, and REST examples.
- Notes that the browser-management SDK wrapper still uses the `v3`
namespace, and that browsers must be stopped explicitly because closing
CDP does not stop billing.
- Marks the old quickstart as the legacy v2 path.
- Adds a CI test that verifies the v4 reference's workspace file-listing
examples.
<sup>Written for commit 442455465b.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5591?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Fixes#5596
`ChatGoogle(include_system_in_user=True)` is meant to prepend the system
text to the first user message. When that message has list content it
replaced it instead: the system text became the only part sent, and the
user's text and images were dropped.
That is the shape an agent run always produces. `use_vision` defaults to
`True`, `AgentMessagePrompt.get_user_message()` returns list content as
soon as there is a screenshot, and `MessageHistory.get_messages()` puts
the state message first among the user messages. So with this flag on,
every step sent Gemini the system prompt and nothing else, with no error
anywhere.
The cause was structural: the content-part conversion lived in the
`else` arm of the prepend branch, so taking the prepend branch skipped
it. The fix computes the system text first and then always runs the
conversion, folding the system text into the leading text only for `str`
content, which is what it already did.
Before, on `main`:
```
include_system_in_user=False user ["'<browser_state>the page and the task live'", 'image']
include_system_in_user=True user ["'You are a browser agent.'"]
```
After:
```
include_system_in_user=False user ["'<browser_state>the page and the task live'", 'image']
include_system_in_user=True user ["'You are a browser agent.'", "'<browser_state>the page and the task live'", 'image']
```
### Tests
Three tests in `tests/ci/models/test_llm_google.py`, real objects only:
- `test_include_system_in_user_keeps_list_content_parts`: text part and
image survive alongside the prepended system text.
- `test_include_system_in_user_string_content_is_merged_into_one_part`:
parity guard for the `str` path, which was already correct and must stay
a single merged part. This one passes on `main` too.
- `test_include_system_in_user_keeps_the_agent_state_message`: builds
the message through the real `AgentMessagePrompt` with `use_vision=True`
and asserts the task and screenshot reach the serialized contents.
Reverting the change in `browser_use/llm/google/serializer.py` and
rerunning:
```
FAILED tests/ci/models/test_llm_google.py::test_include_system_in_user_keeps_list_content_parts
E AssertionError: user text was dropped
assert '<browser_state>the page and the task live here</browser_state>' in 'You are a browser agent.'
FAILED tests/ci/models/test_llm_google.py::test_include_system_in_user_keeps_the_agent_state_message
E AssertionError: the task never reached the model
2 failed, 1 passed
```
With the fix, `pytest tests/ci/models/test_llm_google.py` gives 8
passed, 1 skipped (the skip is the live `gemini-3-flash-preview` test,
no API key here).
### Checks
`pre-commit run --files browser_use/llm/google/serializer.py
tests/ci/models/test_llm_google.py` passes every hook, including ruff
check, ruff format and pyright at the versions pinned in
`.pre-commit-config.yaml`.
Full suite, `pytest tests/ci -q -o addopts="" --timeout=120`: 2 failed,
1108 passed, 34 skipped on this branch, against 2 failed, 1105 passed,
34 skipped on `main` (the +3 are the new tests). The two failures are
the same `tests/ci/test_beta_agent.py` isinstance checks in both runs;
they are order-dependent and pass on their own, and they are unrelated
to this change.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes#5596 by keeping the first user message's content when
`include_system_in_user=True` is set on `ChatGoogle`. Previously, when
the message had list content (text plus images, as the agent always
produces with vision on), the system text replaced it and the user's
text and screenshot were dropped; now the system text is prepended and
the user's parts are preserved.
- Reorders the serializer so content conversion runs for both string and
list content, merging system text only into the leading text part.
- Adds three tests covering list content, string content parity, and the
agent's actual message shape.
<sup>Written for commit 6a2b0f4f6c.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5597?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
- Read BROWSER_USE_HEADLESS env var via default_factory in
BrowserProfile
- Preserve fallback to display detection when env var is unset
- Add unit tests covering env var parsing and overrides
Fixes#5420
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Honors `BROWSER_USE_HEADLESS` in `BrowserProfile` so the env var now
sets the default headless mode instead of being ignored. Unset values
still fall back to display detection, and explicit headless args still
override. Hosts with `BROWSER_USE_HEADLESS` set may see their default
browser mode change.
- `BrowserLaunchArgs.headless` now uses a `default_factory` that parses
the env var case-insensitively: `'0'`/`'false'`/`'no'`/`'off'`/`''` =>
False, any other non-empty value => True, unset => None.
- `BrowserSession` inherits the value via its `browser_profile`.
- Tests for `BROWSER_USE_HEADLESS` and `BROWSER_USE_DISABLE_EXTENSIONS`
are deduplicated with pytest parametrization, covering profile/session
propagation and explicit overrides.
<sup>Written for commit 34d7978da9.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5475?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Summary
- replace the stale five-free-task claim with the current $15 one-time
signup credit
- fix the surrounding grammar
## Test
- `pre-commit run --files CLOUD.md`
- `git diff --check`
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Corrects the Cloud signup credit in `CLOUD.md` from five free tasks to
the current $15 one-time signup credit (if eligible), and fixes the
surrounding grammar.
<sup>Written for commit b4e68f19b2.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5602?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Summary
- replace removed pre-3.0 subcommands in the remote-browser skill with
the current piped-Python workflow
- document named Browser Use Cloud daemons for isolated sandbox browser
work
- add a regression test so deleted CLI commands do not return to the
skill
## Why
`skills/remote-browser/SKILL.md` still starts with `browser-use open`
and `browser-use state`. The current CLI exits 2 for both commands and
tells users to use `new_tab()` and `page_info()` through stdin.
## Test
- `uv run --python 3.11 pytest -q
tests/ci/test_browser_use_skill_install_docs.py`
- `uv run --python 3.11 pre-commit run --files
skills/remote-browser/SKILL.md
tests/ci/test_browser_use_skill_install_docs.py`
- `uv run --python 3.11 python
/Users/magnus/.codex/skills/.system/skill-creator/scripts/quick_validate.py
skills/remote-browser`
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Migrates the remote-browser skill to the current Browser Use CLI 3.0
workflow, replacing removed pre-3.0 subcommands (`browser-use open`,
`browser-use state`, etc.) with the piped-Python interface via stdin
heredocs.
- Documents named Browser Use Cloud daemons for isolated browser
sessions.
- Adds a regression test blocking retired CLI commands from returning to
the skill.
<sup>Written for commit 7ed622f0de.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5583?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
Fixes#5575
## What was wrong
`sanitize_url_candidate()` drops trailing prose punctuation so that "Go
to https://example.com/docs." does not navigate with the sentence's
period attached. It did that with a single character class:
```python
return re.sub(r'[.,;:!?()\[\]]+$', '', candidate)
```
which also strips closing brackets the URL opened itself.
`Agent._extract_start_url()` runs every URL it finds in the task through
this before auto-navigating, so:
```
Summarize https://en.wikipedia.org/wiki/Python_(programming_language)
```
navigated to
`https://en.wikipedia.org/wiki/Python_(programming_language` and landed
on the wrong page. Wikipedia disambiguation links are the common shape.
## The fix
Whether a trailing bracket belongs to the URL is a question of balance.
`.../Python_(programming_language)` closes a bracket the URL opened, so
it is part of the path. In "See the docs (https://example.com/guide)"
the prose opened it, so dropping it stays correct. The loop strips
trailing punctuation as before and only drops a closing bracket when the
candidate has more closers than openers.
## Before and after
```python
from browser_use.agent.service import Agent
Agent._extract_start_url(None, 'Summarize https://en.wikipedia.org/wiki/Python_(programming_language)')
```
| task text | before | after |
| --- | --- | --- |
| `Summarize
https://en.wikipedia.org/wiki/Python_(programming_language)` |
`...Python_(programming_language` | `...Python_(programming_language)` |
| `Check https://example.com/a[1] please` | `https://example.com/a[1` |
`https://example.com/a[1]` |
| `Go to https://example.com/docs. Then stop.` |
`https://example.com/docs` | `https://example.com/docs` |
| `See the docs (https://example.com/guide) for details.` |
`https://example.com/guide` | `https://example.com/guide` |
The last two rows are the behaviour that had to be preserved: a sentence
period is still dropped, and a bracket the prose opened is still
dropped.
Bracket totals are counted once and decremented while trimming, with an
end index instead of reslicing, so a candidate ending in a long run of
brackets stays linear like the regex it replaces. 200,000 trailing `)`
takes 0.011s.
## Testing
Added assertions to `test_beta_agent_exposes_task_helper_methods`, next
to the existing `_extract_start_url` cases, covering both directions:
the bracket the URL opened is kept, the one the prose opened is not.
They fail on `main` and pass here.
Full `tests/ci`, before and after, on the same machine:
```
clean tree: 2 failed, 1094 passed, 34 skipped
this branch: 2 failed, 1095 passed, 34 skipped
```
The two failures are pre-existing and unrelated, both in
`test_beta_agent.py`
(`test_beta_agent_constructor_type_hints_match_browser_use_core_params`
and `test_beta_agent_initializes_tools_and_action_models`, `Tools`
class-identity assertions). They fail identically on a clean tree. I
also diffed the skipped-test lists between the two runs and they are
identical, so nothing changed state.
```
uv run ruff check browser_use/utils.py tests/ci/test_beta_agent.py -> All checks passed!
uv run ruff format --check ... -> 2 files already formatted
uv run pyright browser_use/utils.py -> 0 errors, 0 warnings, 0 informations
```
No new warnings.
Bumps `datamodel-code-generator` from 0.53.0 to 0.75.1 in the `eval`
extra dependencies.
This is a routine dependency update to pull in bug fixes, performance
improvements, and new features from the datamodel-code-generator
project. The eval extra is used for evaluation and code generation
tasks.
No source code changes required—this is a straightforward version bump
of a transitive dependency.
https://claude.ai/code/session_013ZqGkMkydPR5r4zPpEAgKk
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Bumps `datamodel-code-generator` in the `eval` extra from 0.53.0 to
0.75.1 to clear ten CVEs the old version was vulnerable to. No source
code changes required.
**Context**
- The widest affected advisory is CVE-2026-55415 (<= 0.63.0), so any
release above 0.63.0 clears all ten.
- Nothing in the repo imports the package or calls its CLI, but CI
installs it via `uv sync --dev --all-extras`.
- Verified the full dependency graph (399 packages) still resolves and
0.75.1 generates models correctly.
- The update stays compatible with the project's `requires-python
>=3.10` and `pydantic <3,>=2` pins.
<sup>Written for commit fee260adf2.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5588?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Why
Every checked-in raw Cloud example targets retired `/api/v1` routes that
now return 404. The folder also shows the old bearer header and legacy
request fields.
## What
- replace the five broken V1 samples with one minimal V4 create → status
→ result flow
- use the current `X-Browser-Use-API-Key` header and terminal run
statuses
- load `.env` as the setup guide promises
- link optional fields to the live V4 OpenAPI spec instead of
duplicating claims that can drift
## Verification
- `uv run ruff check examples/cloud/01_basic_task.py`
- `uv run ruff format --check examples/cloud/01_basic_task.py`
- `uv run python -m py_compile examples/cloud/01_basic_task.py`
- mocked create → running → completed → summary contract test
- `uv run pre-commit run --files examples/cloud/README.md
examples/cloud/env.example examples/cloud/01_basic_task.py`
- live route probe: the three documented V1 routes return 404;
`/api/v4/runs` returns the expected missing-API-key 401 without
credentials
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Replaces the retired V1 Cloud API examples with a single V4 flow so the
checked-in samples stop hitting endpoints that return 404.
- Drops the fast-mode, structured output, proxy, and search API examples
in favor of one create → status → result flow.
- Switches to the `X-Browser-Use-API-Key` header and terminal run
statuses.
- Cancels a run that exceeds the configurable wait limit and rejects
non-positive or non-finite `BROWSER_USE_RUN_TIMEOUT` values.
- Loads `.env` via `dotenv` as the README setup promises.
- Points optional fields to the live V4 OpenAPI spec instead of
repeating them in the README.
<sup>Written for commit 1359fb22cb.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5578?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Summary
- Record WebSocket message-handler drops that occur while an automatic
reconnect is in progress.
- Schedule another automatic reconnect after the in-flight attempt
finishes.
- Clear pending reconnect state during session reset.
- Add a focused regression test.
Fixes#5366
## Tests
- `uv run pre-commit run --all-files --show-diff-on-failure`
- `uv run pyright`
- `uv run pytest -vxs tests/ci/test_browser_session.py`
- `uv run pytest -vxs tests/ci` — 483 passed, 28 skipped before an
unrelated existing failure in
`tests/ci/test_beta_agent.py::test_beta_agent_constructor_type_hints_match_browser_use_core_params`.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes WebSocket drops that happen during an in-flight reconnect by
recording them and automatically retrying after the attempt finishes.
Improves session stability and clears pending reconnect state on reset.
Fixes#5366.
- **Bug Fixes**
- Record WS drops during reconnect via `_reconnect_pending`, then
auto-schedule a follow-up reconnect once the attempt ends.
- Clear `_reconnect_pending` on session reset and wake any waiters.
- Add a focused regression test that verifies a follow-up reconnect is
scheduled after a drop during reconnect.
<sup>Written for commit 281cbc8c74.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5373?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
The eval extra pinned datamodel-code-generator==0.53.0, which falls inside
the affected range of ten advisories (CVE-2026-54621, -54653, -54654,
-54655, -54656, -54690, -54691, -55389, -55391, -55415). The widest range
is CVE-2026-55415 (<= 0.63.0), so any release above 0.63.0 clears all ten;
0.75.1 is the current latest.
CI installs this via `uv sync --dev --all-extras`, so the vulnerable
package was landing in CI environments even though nothing in the repo
imports it or invokes the datamodel-codegen CLI.
Verified the full graph (399 packages, all extras + dev) still resolves,
and that 0.75.1 installs and generates models correctly. Requires-python
>=3.10 and pydantic <3,>=2 both stay compatible with the project's pins.
The trimming loop counted brackets across the whole candidate on every
iteration, so a candidate ending in many unmatched brackets rescanned it
once per bracket. 50,000 trailing ')' took 0.9s, where the regex this
replaced was linear.
Count the four bracket characters once and decrement as characters are
trimmed, tracking the end index instead of reslicing. Same results, and
200,000 trailing ')' now takes 0.011s.
sanitize_url_candidate() strips trailing prose punctuation so that
"Go to https://example.com/docs." does not navigate with the sentence's
period attached. It also stripped every trailing ) and ], including the
ones the URL opened itself, so a task like
Summarize https://en.wikipedia.org/wiki/Python_(programming_language)
auto-navigated to .../Python_(programming_language and landed on the wrong
page. Wikipedia disambiguation links are the common case.
Whether the bracket belongs to the URL is decided by balance: a closing
bracket with a matching opener inside the candidate is part of the path,
while one the prose opened, as in "(see https://example.com/guide)", is not.
Strip trailing punctuation as before, and only drop a closing bracket when
the candidate has more of them than openers.
Fixes#5575
Fixes#4312
Image-only clickable elements can be indistinguishable in the serialized
DOM when they have no text or accessible label. Include bounded
descendant image context on the interactive parent, using
alt/title/aria-label and a query-stripped image filename while ignoring
data URLs.
Validation:
- uv run pytest -q tests/ci/test_image_only_dom_representation.py
tests/ci/test_dom_paint_order_serialization.py
- uv run ruff check browser_use/dom/serializer/serializer.py
tests/ci/test_image_only_dom_representation.py
- uv run ruff format --check browser_use/dom/serializer/serializer.py
tests/ci/test_image_only_dom_representation.py
- uv run pre-commit run --files browser_use/dom/serializer/serializer.py
tests/ci/test_image_only_dom_representation.py
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes#4312 by exposing bounded descendant image context in the
serialized DOM for image-only interactive elements. Previously,
interactive parents without text or labels serialized without context;
now they carry image alt/title/aria-label and a query/fragment-stripped
filename, with traversal and allocation bounds.
- Add `image_alt`, `image_title`, `image_label`, and `image_src`
(query/fragment-stripped filename) to interactive parents; skip `data:`
and query-only sources; cap each value to 100 chars.
- Limit to three descendant images and at most 100 descendants; traverse
lazily without copying child lists to bound allocations.
- Keep paint-order serialization unchanged; add tests for filename
propagation, query/fragment stripping, data URL filtering, traversal
limits, and non-eager traversal.
<sup>Written for commit fa29b0e05d.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5541?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
## Summary
- centralize reasoning-model pattern matching for the LLM adapters
- ignore empty or whitespace-only patterns instead of treating every
model as a reasoning model
- preserve the existing matching behavior for non-empty patterns across
OpenAI, Azure, and Vercel
This prevents an empty `reasoning_models` entry from silently dropping
sampling parameters such as `temperature` and `frequency_penalty`.
## Testing
- `py -m uv run pytest -q tests/ci/models/test_llm_openai.py` (7 passed,
1 skipped)
- `py -m uv run pytest -q tests/ci/models/test_azure_responses_api.py -k
ShouldUseResponsesAPI` (6 passed)
- `py -m uv run pyright browser_use/llm/base.py
browser_use/llm/openai/chat.py browser_use/llm/azure/chat.py
browser_use/llm/vercel/chat.py tests/ci/models/test_llm_openai.py`
- `py -m uv run ruff check browser_use/llm/base.py
browser_use/llm/openai/chat.py browser_use/llm/azure/chat.py
browser_use/llm/vercel/chat.py tests/ci/models/test_llm_openai.py`
Fixes#5543
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Ignore empty and whitespace-only reasoning-model patterns so regular
models are no longer treated as reasoning models, which previously
stripped sampling params like `temperature` and `frequency_penalty`.
Matching is centralized in `is_reasoning_model`, and the `openai`,
`azure`, and `vercel` adapters all use it so only real patterns apply.
**Bug Fixes**
- Tests cover empty-pattern cases and verify reasoning params are only
set on true matches.
Fixes#5543.
<sup>Written for commit 56b76ddbad.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/5545?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->