Commit Graph

9859 Commits

Author SHA1 Message Date
Magnus Müller 988362a4ed Mirror Browser Use settings in Rust agent 2026-06-02 21:17:38 +00:00
Magnus Müller 3d3de8bfd3 Bridge Rust agent browser profile CDP 2026-06-02 21:13:39 +00:00
Magnus Müller 4ee73118fc Add Rust agent lifecycle helpers 2026-06-02 21:12:25 +00:00
Magnus Müller 6e06a564bc Add real v8 Rust agent smoke runner 2026-06-02 21:07:31 +00:00
Magnus Müller 18dae84a7f Document remote CDP smoke proof 2026-06-02 20:58:43 +00:00
Magnus Müller e9f69b1cca Document Rust agent integration features 2026-06-02 20:54:20 +00:00
Magnus Müller 3b703e276f Bridge Rust agent browser mode env 2026-06-02 20:52:19 +00:00
Magnus Müller a67176f51e Harden Rust agent result handling 2026-06-02 20:48:28 +00:00
Magnus Müller 3509784bdb Add Rust agent smoke example 2026-06-02 20:46:10 +00:00
Magnus Müller 61171d1ad6 Support Rust agent follow-up sessions 2026-06-02 20:45:20 +00:00
Magnus Müller dc4318875b Add Rust-backed Browser Use agent wrapper 2026-06-02 20:43:18 +00:00
laithrw 4931a7e021 fix (#4950)
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Clarified wording and punctuation in `skills/x402/SKILL.md` (using an em
dash to introduce the two setup paths) to improve readability; no
functional changes.

<sup>Written for commit 850aa42b4c.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4950?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-01 11:49:43 -07:00
laithrw 850aa42b4c Merge branch 'main' into x402-skill 2026-06-01 11:45:08 -07:00
Laith Weinberger fb9af136f0 fix 2026-06-01 11:42:19 -07:00
laithrw 270d76b23a add x402 skill (#4782)
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Adds the `x402` skill for wallet-based USDC payments on Base for Browser
Use Cloud. It asks before spending, supports a $1 test run (SDK still
defaults to $5 top-ups), and shows your Browser Use balance after
verification or top-up.

- **New Features**
- New `x402` skill: guided setup with two setups (terminal “just use it”
vs project “build it in”) and two payment paths (accountless wallet vs
top up an existing API-key project using `X-Browser-Use-API-Key`).
Installs (`browser-use-sdk[x402]`, `@x402/fetch`, `@x402/evm`, `viem`),
saves the key to `.env` (ensure `.gitignore`), runs a $1 test via raw
client (`max_value`), and shows credits (`get_wallet_balance` for
accountless; project billing for top-ups; SDK ≥ 3.8.0). Safety: ask
before spending, never echo keys, and offer paste vs self-add for the
private key.
- `browser-use` skill: adds an “Out of credits?” flow and install
command; only suggests `x402` after a real 402/insufficient-credits
error.

<sup>Written for commit 23b6ce1cf4.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4782?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
2026-06-01 11:40:00 -07:00
Laith Weinberger 23b6ce1cf4 improved skill 2026-06-01 11:35:23 -07:00
laithrw 55490ccbbd Merge branch 'main' into x402-skill 2026-06-01 10:11:19 -07:00
Laith Weinberger 6d39576fb0 check balance 2026-06-01 10:11:05 -07:00
Magnus Müller 8342696090 fix(agent): skip screenshots on new tab pages (#4920)
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Skip screenshots on new-tab pages and drop placeholder images before LLM
serialization. This reduces noise and prevents placeholders from leaking
across steps or tabs.

- **Bug Fixes**
- In `get_user_message`, always disable vision when
`is_new_tab_page(url)` is true.
- Exclude `PLACEHOLDER_4PX_SCREENSHOT` before deciding to include
screenshots and when labeling them.

- **Dependencies**
  - Bump `browser-use` version to 0.12.9.

<sup>Written for commit 103313ed63.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4920?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
0.12.9
2026-05-25 20:44:50 -07:00
MagMueller 103313ed63 chore: bump version to 0.12.9 2026-05-25 20:42:02 -07:00
Magnus Müller 2384c3e951 Merge branch 'main' into fix/skip-new-tab-screenshots 2026-05-25 20:39:17 -07:00
MagMueller b727b36dcc fix(agent): skip screenshots on new tab pages 2026-05-25 20:38:12 -07:00
Magnus Müller 0a0abd270e Pass session id to judge LLM calls (#4918)
## Summary
- pass the agent `session_id` into Browser Use judge LLM calls when
using `ChatBrowserUse`
- keeps judge requests grouped with the same gateway/Laminar session as
normal agent calls

## Tests
- `uv run python -m py_compile browser_use/agent/service.py`
- `uv run pre-commit run --files browser_use/agent/service.py`

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Pass the agent `session_id` to judge LLM calls for the `browser-use`
provider in `ChatBrowserUse`. This keeps judge requests in the same
gateway/Laminar session as normal agent calls and groups traces
correctly.

<sup>Written for commit 6c36054ae4.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4918?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-25 14:07:32 -07:00
MagMueller 6c36054ae4 Pass session id to judge LLM calls 2026-05-25 14:05:48 -07:00
Magnus Müller d21b3da4ac Trim HistoryItem freeze follow-up (#4902)
Keeps HistoryItem frozen while removing the expanded byte-prefix
explanation and byte-stability regression test added in #4890.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Keep `HistoryItem` frozen but trim docs and tests. Removes the
byte-prefix caching explanation and drops the byte-stability regression
test from #4890.

- **Refactors**
  - Shortened the `HistoryItem` docstring to a single line.
- Removed `tests/ci/test_history_item_byte_stable.py` to stop enforcing
byte-prefix rendering in unit tests.

<sup>Written for commit 51598efd56.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4902?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
0.12.8
2026-05-23 12:25:54 -07:00
Magnus Müller 3f4207a466 Merge branch 'main' into trim-pr-4890 2026-05-23 12:25:45 -07:00
Magnus Müller d14a1c6d8c Revert evaluate restriction on restricted profiles (#4901)
Reverts #4871.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Reverts the `evaluate()` guard from #4871 to allow JavaScript evaluation
on profiles with `allowed_domains`, `prohibited_domains`, or
`block_ip_addresses` configured. Removes the restriction logic in
`browser_use/tools/service.py` and deletes
`tests/ci/security/test_evaluate_restricted.py`.

<sup>Written for commit af9d406419.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4901?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-23 12:25:38 -07:00
Magnus Müller 682c67dd92 Merge branch 'main' into revert-pr-4871 2026-05-23 12:25:25 -07:00
MagMueller 51598efd56 Trim HistoryItem freeze change tests 2026-05-23 12:20:55 -07:00
MagMueller af9d406419 Revert "fix(tools): refuse evaluate() on restricted browser profiles (#4871)"
This reverts commit d6a87c0961, reversing
changes made to eeff4d1984.
2026-05-23 12:13:38 -07:00
Magnus Müller a402567971 Revert ChatGoogle cached_content forwarding (#4900)
## Summary
- Revert #4889 (`ChatGoogle.cached_content` field and per-call
`cached_content` forwarding).
- Remove the now-unused cached-content unit test.

## Why
Cloud explicit caching does not need the OSS convenience API: the
gateway injects `cached_content` through a copied `ChatGoogle.config`
dict on its request-local model. Keeping the public field/kwarg exposes
a sharp edge because Gemini rejects cachedContent calls that also send
live `system_instruction`, which normal `ChatGoogle` messages can still
do.

## Tests
- `uv run pytest tests/ci/models/test_llm_google.py -q`
- `uv run pre-commit run --all-files`


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Reverts `ChatGoogle` `cached_content` forwarding to Gemini and removes
the field and per-call passthrough. This avoids Gemini errors when
`cachedContent` is sent with live `system_instruction`; the gateway
still injects caching, so the obsolete unit test is removed.

<sup>Written for commit 22939a2580.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4900?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-23 12:05:58 -07:00
MagMueller 22939a2580 Revert "feat(llm/google): forward cached_content into generate_content (#4889)"
This reverts commit 5a745a8502, reversing
changes made to 640360e9b7.
2026-05-23 12:03:38 -07:00
Magnus Müller dddc13030c Bump version to 0.12.8 (#4899)
## Summary
- bump browser-use package version to 0.12.8 for the next release

## Tests
- uv run ruff check pyproject.toml
-
PATH="/Users/magnus/.local/share/uv/python/cpython-3.11-macos-aarch64-none/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/opt/homebrew/bin:/Users/magnus/.codex/tmp/arg0/codex-arg0LWaL9w:/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path:/Users/magnus/.superset/bin:/Users/magnus/.whatdidido:/Users/magnus/.browser-use-env/bin:/Users/magnus/.local/bin:/Users/magnus/.bun/bin:/Users/magnus/.orbstack/bin:/Users/magnus/.orbstack/bin"
uv run pre-commit run --files pyproject.toml

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Bumps `browser-use` to 0.12.8 to publish the next patch release. Updates
the `version` in pyproject.toml from 0.12.7 to 0.12.8.

<sup>Written for commit e973caeae1.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4899?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-23 11:24:58 -07:00
MagMueller e973caeae1 Bump version to 0.12.8 2026-05-23 11:24:04 -07:00
Magnus Müller 3818b1437c Move user request before agent history (#4897)
## Summary
- move the rendered <user_request> block before <agent_history> in the
per-step agent user message
- keep <agent_state> for file system, todo, plan, sensitive data, and
file path context
- update system prompt docs and prompt-shape tests so the cacheable
prefix order is locked
- add a simple guard that the rendered agent user message contains
exactly one </agent_history> marker, which the LLM gateway cache
splitter depends on

## Why
Putting the stable user request before the append-only agent history
gives implicit and explicit provider caches a better stable prefix. The
end of <agent_history> is still the expanding part; compaction naturally
creates a new stable prefix once the compacted memory block changes.

## Tests
- uv run ruff check browser_use/agent/prompts.py
tests/ci/test_prompt_step_meta_suffix.py
- uv run pytest tests/ci/test_prompt_step_meta_suffix.py -q
-
PATH="/Users/magnus/.local/share/uv/python/cpython-3.11-macos-aarch64-none/bin:$PATH"
uv run pre-commit run --files browser_use/agent/prompts.py
browser_use/agent/system_prompts/system_prompt.md
browser_use/agent/system_prompts/system_prompt_anthropic_flash.md
browser_use/agent/system_prompts/system_prompt_no_thinking.md
tests/ci/test_prompt_step_meta_suffix.py

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Moves the `<user_request>` block before `<agent_history>` in each step’s
user message to create a more stable prefix for provider/LLM caches.
Updates system prompts and tests to lock this order and adds a guard
that enforces a single `</agent_history>` marker.

- **Refactors**
- Render `<user_request>` before `<agent_history>` in the user message;
remove `<user_request>` from `<agent_state>`.
- Keep `<agent_state>` focused on file system, todo, plan, sensitive
data, and available file paths; keep per-step metadata at the tail.
- Update `system_prompt.md`, `system_prompt_anthropic_flash.md`, and
`system_prompt_no_thinking.md` to reflect the new input order and
include the `<user_request>` block before history.
- Add a guard to ensure exactly one `</agent_history>` marker and extend
tests to lock ordering and suffix stability.

<sup>Written for commit 90a052371d.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4897?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-23 11:16:53 -07:00
MagMueller 90a052371d Move user request before agent history 2026-05-23 09:48:15 -07:00
Saurav Panda 5a745a8502 feat(llm/google): forward cached_content into generate_content (#4889)
## Context

Closes part of #4887 (item #4 — explicit CachedContent support).

Gemini's implicit context cache is great for the steady-state of an
agent loop but has a ~5-minute TTL and is per-call best-effort. For long
sessions (or sessions that go quiet for >5 minutes and resume), explicit
`CachedContent` is the deterministic alternative: you create a named
cache once with the prefix, then reference it on subsequent calls and
Google bills the cached portion at the discounted rate, period.

The wrapper in `browser_use/llm/google/chat.py` already parses
`cached_content_token_count` out of `response.usage_metadata` into
`ChatInvokeUsage.prompt_cached_tokens`, so the savings are visible — it
just had no way to *send* a cache reference.

## Change

- New `cached_content: str | None = None` field on `ChatGoogle`.
- New `cached_content` kwarg on `ainvoke()` — overrides the instance
default for one call.
- When set, threads into `config['cached_content']` before all three
`generate_content` calls (string output, native JSON, fallback JSON).

Per-call kwarg takes precedence over the instance default, so you can
pin a cache for the whole session and still override per-call when
needed.

## What's NOT in this PR

- Cache creation (`client.caches.create(...)`) is left to the caller.
That gives users full control over TTL, contents, and lifecycle without
coupling the LLM wrapper to agent-state decisions.
- Agent-side automatic cache lifecycle (create on first step, reuse on
subsequent steps, refresh near TTL) is an obvious follow-up but a
separate design discussion — it touches `agent/service.py` and depends
on what the agent considers its "stable prefix."

## Usage

```python
from google.genai import types
from google import genai

client = genai.Client(api_key=...)
cache = await client.aio.caches.create(
    model='gemini-2.5-flash',
    config=types.CreateCachedContentConfig(
        contents=[...prefix turns...],
        system_instruction='...',
        ttl='3600s',
    ),
)

llm = ChatGoogle(model='gemini-2.5-flash', cached_content=cache.name)
# Every ainvoke() now references that cache.

# Per-call override:
await llm.ainvoke(messages, cached_content='cachedContents/other')
```

## Test plan

- [x] New unit test `test_cached_content_threaded_into_config` —
verifies the kwarg flows into `generate_content`'s `config` dict, the
per-call kwarg overrides the instance default, and when unset the key is
absent (`pytest tests/ci/models/test_llm_google.py`).
- [x] Existing google tests still pass.
- [ ] Real-API smoke test against a Gemini model with an actual
`cachedContents/...` resource (requires API key + paid quota — not in
CI).

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds explicit Gemini CachedContent support to `ChatGoogle` by forwarding
a `cached_content` name into all `generate_content` calls. Addresses
#4887 (item 4) to enable deterministic cache reuse with discounted
billing.

- **New Features**
- Add `cached_content` on `ChatGoogle` with per-call override via
`ainvoke(..., cached_content=...)`.
  - Thread to `config['cached_content']` for all paths; omit when unset.
- Cache creation is caller-managed; usage already counts
`prompt_cached_tokens`.

- **Migration**
- No breaking changes; behavior is unchanged when `cached_content` is
unset.
- To adopt: create a Gemini cache and pass its name via
`ChatGoogle(cached_content=...)` or `ainvoke(..., cached_content=...)`.

<sup>Written for commit ac5ff6dd15.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4889?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-22 18:40:39 -07:00
Saurav Panda ac5ff6dd15 Merge branch 'main' into prompt-cache/gemini-cached-content 2026-05-22 18:32:45 -07:00
Saurav Panda 640360e9b7 agent(prompts): move per-step metadata out of <agent_state> into a tail block (#4891)
## Context

Closes part of #4887 (item #3 — strip per-step metadata from anything
prefix-stable).

`AgentMessagePrompt._get_agent_state_description()` was rendering two
per-step-varying values inside `<agent_state>`:

- `Step{N+1} maximum:{M}` — changes every step.
- `datetime.now().strftime('%Y-%m-%d')` — changes daily.

The user message currently looks like:

```
<agent_history>...</agent_history>          ← grows append-only (prefix-stable if HistoryItem is stable)
<agent_state>...<step_info>...</...> </agent_state>   ← cache miss starts here today
<browser_state>...</browser_state>
<read_state>...</read_state>
```

So the cache boundary already lands at `<agent_state>` and the step
counter inside it isn't actively bursting a live cache. **But**: the
layout meant that any future move of more-stable `<agent_state>` fields
(user_request, file_system, todo_contents) into the system prompt — or
anywhere we'd want to cache them — would still leave per-step varying
bytes sitting inside the would-be prefix. That silently caps how far the
cache can ever extend.

## Change

Pull the step counter + date into a new helper
`_get_step_meta_description()` and append it at the very tail of
`get_user_message()`, after `<agent_state>`, `<browser_state>`,
`<read_state>`, `<page_specific_actions>`, and the unavailable-skills
info block. The new layout:

```
<agent_history>...</agent_history>
<agent_state>...</agent_state>              ← no more <step_info> inside
<browser_state>...</browser_state>
<read_state>...</read_state>
<page_specific_actions>...</page_specific_actions>
[unavailable_skills_info]
<step_info>Step{N} maximum:{M}\nToday:{YYYY-MM-DD}</step_info>   ← suffix, explicitly per-step
```

Everything above `<step_info>` is now eligible to be treated as the
cacheable region — when/if we want to push that boundary further out, no
per-step varying bytes are in the way.

## Tests

New regression tests at `tests/ci/test_prompt_step_meta_suffix.py`:
- `<step_info>` appears after both `<agent_state>` and
`<browser_state>`.
- `<step_info>` does not leak back into `<agent_state>`.
- Bytes before `<step_info>` are byte-identical across two different
step numbers (proves the step counter isn't in the prefix).
- `<agent_state>` block is byte-identical across step numbers.

## Test plan

- [x] New tests pass.
- [x] Existing prompt / message_manager tests still pass (`pytest
tests/ci -k 'prompt or message_manager or agent_message'`).
- [x] pyright + ruff clean via pre-commit.
- [ ] Eyeball one real agent loop to confirm the model still parses
`<step_info>` correctly at the tail (no expected change in behavior —
the LLM doesn't care about position).

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Moved per-step metadata (step counter and date) out of `<agent_state>`
into a trailing `<step_info>` block so the user-message prefix is stable
for caching. Preps the prompt layout for deeper caching and covers part
of #4887.

- **Refactors**
- Added `_get_step_meta_description()` and append it at the end of
`get_user_message()` after agent, browser, read, page actions, and
unavailable-skills blocks.
- Removed per-step `<step_info>` from `<agent_state>` so all bytes
before `<step_info>` are stable across steps.
- Added tests to lock ordering, prevent leakage into `<agent_state>`,
and verify a byte-identical prefix and `<agent_state>` across step
numbers.

<sup>Written for commit b06b47a23a.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4891?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-22 18:32:16 -07:00
Saurav Panda b06b47a23a Merge branch 'main' into prompt-cache/relocate-per-step-metadata 2026-05-22 18:11:00 -07:00
Saurav Panda 67f7b9e084 agent(history): freeze HistoryItem + lock byte-prefix property (#4890)
## Context

Closes part of #4887 (item #1 — make the per-step transcript
append-only).

For Gemini's implicit cache (and similar provider caches) to actually
hit step over step, the rendered transcript for steps 1..N-1 must be
byte-identical at step N and at step N+1. The agent today appends
`HistoryItem`s immutably in practice — every site I checked constructs a
new item and `.append()`s it — but nothing in the type itself prevents a
future caller from mutating one in place. That kind of mutation would
silently kill the cache from that byte onward, and we'd only notice it
as a slow erosion of cached-token-ratio.

## Change

1. Mark `HistoryItem` `frozen=True` via pydantic `ConfigDict`, so any
mutation fails loud at runtime instead of silently burning input tokens
later.
2. Add a regression test set
(`tests/ci/test_history_item_byte_stable.py`) that asserts the cache
property directly:
- `render(items[:N])` is a strict byte-prefix of `render(items[:N+1])`
   - `to_string()` is deterministic for identical inputs
- the prefix property holds across mixed entry shapes (normal steps,
errors, system messages, follow-up tasks)
- conditional field inclusion in `to_string()` doesn't collapse to
ambiguous output (a populated field shouldn't render identically to a
missing one)

The tests pass against current behavior — they're locking it down, not
changing it.

## Known limitation (intentionally not in this PR)

`MessageManager.agent_history_description` does have one real
cache-buster I noticed during the audit: when `max_history_items` is set
and exceeded, the compaction logic at
`message_manager/service.py:173-186` rewrites earlier bytes — the `[...
N previous steps omitted...]` count changes every step past the cap, so
the prefix is not stable past the boundary.

Fixing that properly means either (a) capping the omitted-count at a
stable value, or (b) restructuring the compaction to omit at a fixed
cutoff. Either way it's a bigger design call than this hygiene PR, so I
left it for a follow-up. Calling it out in the commit message.

## Test plan

- [x] New byte-stability tests pass (`pytest
tests/ci/test_history_item_byte_stable.py`).
- [x] Existing message_manager / history tests still pass (`pytest
tests/ci -k 'message_manager or history'`).
- [x] `pyright` + `ruff` clean via pre-commit.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Freeze `HistoryItem` to make agent step transcripts append-only and
preserve byte-prefix stability for provider caches (e.g., Gemini). Adds
regression tests to lock deterministic rendering and strict prefix
growth. Part of #4887.

- **Refactors**
- Set `frozen=True` in `pydantic` `ConfigDict` for `HistoryItem`;
mutation now raises instead of silently changing rendered bytes.
- Added regression tests to enforce: strict byte-prefix growth across
steps, deterministic `to_string()`, stability with mixed entry shapes,
and disambiguation of optional fields.

<sup>Written for commit 8236cc7506.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4890?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-22 18:09:49 -07:00
Saurav Panda a3bae60ed2 agent(prompts): move per-step metadata out of <agent_state> into a tail block
The step counter (Step N maximum:M) and datetime.now() were rendered
inside <agent_state>, ahead of <browser_state> in the user message.
The cache miss already happens at the <agent_state> boundary today, so
this isn't a live cache regression — but the layout meant that any
future move of more-stable agent_state fields into the system prompt
would still leave per-step varying bytes in the middle of the prefix,
silently capping how far the cache could extend.

Pull both fields into a new _get_step_meta_description() and append it
at the very end of get_user_message(), after <agent_state>,
<browser_state>, <read_state>, <page_specific_actions>, and unavailable-
skills info. Everything above this tail block is now eligible to be
treated as the cacheable region.

Adds regression tests that lock the layout:
- <step_info> must appear after <agent_state> and <browser_state>
- <step_info> must not leak back into <agent_state>
- bytes before <step_info> must be identical across two different step
  numbers (the step counter must not be in the prefix)
2026-05-22 17:58:13 -07:00
Saurav Panda 8236cc7506 agent(history): freeze HistoryItem + lock byte-prefix property in tests
For Gemini's implicit cache (and similar provider caches) to actually
hit step over step, the rendered transcript for steps 1..N-1 must be
byte-identical at step N and at step N+1. The agent already appends
HistoryItems immutably in practice, but nothing in the type prevented
a future caller from mutating one in place — which would silently kill
the cache from that byte onward.

Mark HistoryItem frozen so any mutation now fails loud at runtime
rather than slowly burning input tokens. Add a regression test set
that asserts the cache property directly:

- render(items[:N]) must be a strict byte-prefix of render(items[:N+1])
- to_string() is deterministic for identical inputs
- the prefix property holds across mixed entry shapes (normal steps,
  errors, system messages, follow-up tasks)
- conditional field inclusion doesn't collapse to ambiguous output

Known limitation, not addressed here: max_history_items compaction in
MessageManager.agent_history_description rewrites earlier bytes once
the cap is exceeded (the omitted-count message changes). That's a
larger redesign and deserves its own PR.
2026-05-22 17:55:43 -07:00
Saurav Panda df063f9068 feat(llm/google): forward cached_content into generate_content
Adds a cached_content field on ChatGoogle (and a per-call kwarg on
ainvoke) that gets threaded into the GenerateContentConfigDict before
each generate_content call. This lets callers point Gemini at an
explicit CachedContent resource (e.g. "cachedContents/abc123") instead
of relying on implicit caching, which is constrained by the ~5-minute
TTL window.

Token accounting already pulls cached_content_token_count from
response.usage_metadata into ChatInvokeUsage.prompt_cached_tokens, so
the savings show up in usage stats without further work.

Cache creation itself (client.caches.create) is left to the caller —
this PR only adds the forwarding hook so explicit caching becomes
opt-in usable. A follow-up can wire agent-side cache lifecycle if
useful.
2026-05-22 17:54:04 -07:00
Saurav Panda fb9357fa1c fix(tokens): add OpenRouter pricing fallback 2026-05-22 13:58:42 -07:00
Saurav Panda db39960431 fix(tokens): add OpenRouter pricing fallback 2026-05-22 13:53:29 -07:00
Saurav Panda 2b30c4852f chore(llm): recommend gemini-3-flash-preview in examples and tests (#4885)
## Summary
- Adds `gemini-3-flash-preview-lite` to `VerifiedGeminiModels` and token
mappings (the non-lite preview was already verified).
- Lists both `gemini-3-flash-preview[-lite]` alongside the existing
`gemini-flash-latest` / `-lite-latest` aliases in `CLOUD.md` and
`skills/cloud/references/api-v2.md` `SupportedLLMs` — the old aliases
stay valid.
- Switches all example code / recommendations (`examples/`, `AGENTS.md`,
`skills/open-source/references/quickstart.md`, bug-report placeholder)
to `gemini-3-flash-preview`.
- Updates the Google CI button-click test and the `evaluate_tasks` judge
LLM to `gemini-3-flash-preview` / `gemini-3-flash-preview-lite`.

The thinking-config branch at `browser_use/llm/google/chat.py:268`
(`is_gemini_3_flash`) already handles both new names — defaults
`thinking_budget=-1` for parity with the old `gemini-flash` substring
path.

## Test plan
- [ ] `uv run pyright` clean (verified locally)
- [ ] pre-commit hooks pass (verified locally)
- [ ] `uv run pytest -vxs tests/ci/models/test_llm_google.py` against
`GOOGLE_API_KEY` — confirm the new `gemini-3-flash-preview` test passes
- [ ] `uv run pytest -vxs tests/ci/evaluate_tasks.py` (or whatever CI
invokes it) — confirm judge LLM swap still works
- [ ] Spot-check `examples/models/gemini.py` runs end-to-end against the
new model

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Switch our recommended Google model to `gemini-3-flash-preview`, add
`gemini-3.1-flash-lite`, and support `gemini-3.1-pro-preview`. Examples,
docs, and CI now default to the new Flash models; existing
`gemini-flash-*-latest` aliases still work.

- **New Features**
- Added `gemini-3-flash-preview`, `gemini-3.1-flash-lite`, and
`gemini-3.1-pro-preview` to verified models; mapped the first two in
`MODEL_TO_LITELLM`.
- Listed `gemini-3-flash-preview` and `gemini-3.1-flash-lite` in
`CLOUD.md` and API `SupportedLLMs`.

- **Bug Fixes**
- Route `gemini-3.1-flash-*` and `gemini-3.1-pro-*` through the correct
thinking paths.
- Map `gemini-3.1-flash-lite` to LiteLLM slug
`gemini/gemini-3.1-flash-lite-preview` to avoid lookup failures while
keeping the user-facing name unchanged.

<sup>Written for commit 5ef0d9dbac.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browser-use/browser-use/pull/4885?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->
2026-05-22 11:54:50 -07:00
Saurav Panda 5ef0d9dbac feat(llm/google): add gemini-3.1-pro-preview to verified models
Routes through the existing Gemini 3 Pro thinking branch by extending
is_gemini_3_pro to match 'gemini-3.1-pro' alongside 'gemini-3-pro'.
2026-05-22 11:48:10 -07:00
Saurav Panda 81f5c49854 fix(tokens): map gemini-3.1-flash-lite to litellm preview slug
LiteLLM only recognizes gemini/gemini-3.1-flash-lite-preview today; the GA
slug fails the model lookup. Keeps the user-facing name unchanged.
2026-05-22 11:03:14 -07:00
Saurav Panda 9e8dfdd18f fix(llm/google): route gemini-3.1-flash through gemini-3 flash thinking branch 2026-05-22 10:50:35 -07:00