1244 Commits

Author SHA1 Message Date
Laith Weinberger d8e556b92f eval.yml: max-parallel 15 for the failed-task rerun (60min timeout, 429 headroom) 2026-07-23 00:57:04 -07:00
MagMueller 962cada3cb style: ruff format 2026-07-22 20:33:49 -07:00
MagMueller 69f69bb06b skeleton hint: actionable data-driven wording; empty-page hint tells the model what to do
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 20:29:35 -07:00
MagMueller 5adce7bf9b fix: gate skeleton-screen hint on in-flight network requests
The low-text-density heuristic fires on ~76% of prompts on fully rendered
element-heavy pages (measured over ~40k eval steps), and models have learned
to ignore it. pending_network_requests is already computed on every browser
state build and was previously unread; using it as a gate keeps the hint for
the one case it is true.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 20:29:35 -07:00
MagMueller ba755a735c test: lock in that output_model_schema no longer auto-bridges into extraction_schema 2026-07-22 20:05:08 -07:00
Mark McDonald a567c6dacf Merge branch 'main' into gemini-params 2026-07-20 08:48:31 +05:30
Alexander Yue 4b1cc6375a feat: accept bu-qa-1 model alias in ChatBrowserUse 2026-07-14 12:46:07 -07:00
Laith Weinberger b376851b5a fix test 2026-07-09 11:00:08 -07:00
Mark McDonald 8b38ec09d8 fix: dont send default params in gemini genconfig
Gemini 3+ models may throw errors if a default value is set for
parameters like temperature, top-p, etc.

The 3-series models use 1.0 as the default temperature, so this
should be a backwards-compatible change.
2026-07-08 17:47:10 +08:00
Saurav Panda 94ea8f60c8 Strengthen DOM visibility idempotency test 2026-07-06 18:27:04 -07:00
Saurav Panda 9863fe17fb Fix visibility check mutating shared snapshot bounds
is_element_visible_according_to_all_parents mutated snapshot_node.bounds in
place while walking the frame chain, permanently shifting every checked
node's coordinates by frame offsets and scroll — corrupting values shared
with absolute_position math, paint-order filtering, and any later visibility
check (the function was not even idempotent).

Worse, a frame node appears in its own frame chain (_construct_enhanced_node
appends it before computing visibility), so an iframe's bounds were offset
by themselves — coordinates doubled — wrongly classifying iframes past
half the viewport threshold as invisible and silently dropping their entire
content subtree from extraction.

Work on a copy of the bounds and skip self in the frame chain.
2026-07-06 17:40:46 -07:00
Saurav Panda e672ab6de7 Detect truncation before the missing-content guard
OpenAI reasoning models can spend the entire max_completion_tokens budget on
hidden reasoning, returning finish_reason='length' with content=null. The
truncation check ran after the missing-content guard, so that case raised
the generic 'Failed to parse structured output' (500) instead of
ModelOutputTruncatedError — no truncation signal, no fallback switch. Check
finish_reason first; it does not depend on content.
2026-07-06 16:45:33 -07:00
Saurav Panda db70a813c1 Let truncation errors switch to the fallback LLM
The 400 status chosen for truncation errors (deliberately outside provider
retry lists — an identical retry truncates identically) also fell outside
Agent._try_switch_to_fallback_llm's allowlist, so a configured fallback_llm
could no longer rescue a truncated run. Before this PR the downstream parse
failure was wrapped as a 502 ModelProviderError, which did allow the switch.

Introduce ModelOutputTruncatedError(ModelProviderError, status 400): the
three providers raise it, provider retry loops still skip it, and the
agent's fallback check treats it as switchable explicitly — a fallback with
a different output cap can succeed where the primary truncated.
2026-07-06 16:31:18 -07:00
Saurav Panda db2b2c67f9 Describe truncation gracefully when the token cap is unset
max_completion_tokens (OpenAI) and max_output_tokens (Google) are optional;
when set to None the truncation message printed 'truncated at
max_output_tokens=None'. Fall back to "the model's output token limit" —
a MAX_TOKENS/length finish reason means some server-side cap fired even
with no client-side cap configured. Anthropic's max_tokens is non-optional
and unaffected.
2026-07-06 15:56:03 -07:00
Saurav Panda 5f690c207e Detect LLM output truncation instead of failing with misleading parse errors
Structured output cut off at the completion-token cap was never detected:
OpenAI's finish_reason='length', Anthropic's stop_reason='max_tokens', and
Gemini's MAX_TOKENS finish reason all produced JSON cut mid-string, which
surfaced as an opaque parse error ('Unterminated string starting at...') —
or worse, a valid-but-chopped prefix. The actual cause (output token cap)
was never mentioned, and with defaults like max_completion_tokens=4096 this
regularly hits long done()/extract outputs.

Each provider now checks the finish/stop reason before parsing structured
output and raises a clear ModelProviderError ('Model output was truncated
at max_*_tokens=N; increase it or request shorter output'). Status code 400
is used deliberately: it is not in any retry list, and retrying the same
request would truncate identically.

Also adds an 'except ModelProviderError: raise' guard in the Anthropic
handler so the new error is not re-wrapped by the generic catch-all.
2026-07-06 15:17:52 -07:00
Saurav Panda 782535c34f Keep plain BrowserErrors recoverable: only structured ones bypass the generic handler
An unconditional re-raise sent BrowserErrors without long_term_memory (e.g.
upload_file's failure paths) into Tools.act's handle_browser_error, which
re-raises exactly those — escaping act() as an exception where callers
previously got a recoverable ActionResult(error=...).

Guard the bypass on long_term_memory being present (the exact condition
handle_browser_error formats without re-raising; short_term_memory alone
would still re-raise), and flatten plain BrowserErrors to RuntimeError as
before. Regression test covers the plain-BrowserError path through
tools.act.
2026-07-06 15:04:37 -07:00
Saurav Panda f30c3952c9 Preserve BrowserError's structured memory through execute_action
Registry.execute_action's catch-all handler flattened BrowserError into a
generic 'Error executing action ...' RuntimeError, destroying the structured
short_term_memory/long_term_memory the error carries to steer the LLM's next
action (e.g. the list of available dropdown options when clicking a select).
The 'except BrowserError' branch in Tools.act that formats those memories
into an ActionResult was dead code for any action that let a BrowserError
propagate (upload_file, dropdown_options via event_result, extraction
handlers).

Re-raise BrowserError before the generic handlers so handle_browser_error
becomes the single formatting point again.
2026-07-06 14:52:39 -07:00
Saurav Panda ab08dea62c Fix markdown extraction destroying URLs and dropping long link lines
Two content-destruction bugs in extract_clean_markdown:

- A cleanup regex stripped every %XX sequence from the converted markdown,
  corrupting all percent-encoded URLs (%20, %2F, ...) — precisely when
  extract_links=True was requested.
- The JSON-blob line filter dropped any line over 100 chars starting with
  '{' OR '[' — silently deleting long markdown links [text](long-url),
  clickable images, and citation-style lines.

Delete the %XX regex, and only drop long lines that actually parse as JSON
(json.loads) so SPA state blobs are still filtered while markdown links
survive. Also extract the HTML->markdown conversion into a pure
convert_html_to_markdown() helper so this stage is unit-testable.
2026-07-06 14:45:25 -07:00
Saurav Panda b4b6868232 Handle same-document navigations without burning the readiness timeout
Page.navigate omits loaderId for same-document navigations (#fragment,
History API), and Chrome emits no new load/DOMContentLoaded lifecycle events
for them — the navigation is already committed when Page.navigate returns.
The stale-event timestamp guard would otherwise reject all buffered events
and burn the full readiness timeout.

Short-circuit when loaderId is absent, and simplify the stale-event guard
(the no-navigation-id case can no longer reach it). Regression test drains
the previous load's trailing networkIdle first so a stale event can't
accidentally satisfy the wait.
2026-07-04 04:27:18 +08:00
Saurav Panda c5f0fa767c Fix navigation readiness detection: per-target lifecycle event storage
Navigation waits polled a per-session event deque whose feeding handler was
registered per-session on cdp-use's single-slot event registry. Any later
target attach replaced the handler, freezing existing tabs' deques with only
pre-navigation events, so every navigation on those tabs burned the full
readiness timeout (3s same-domain / 8s cross-domain) and then proceeded on a
page in unknown load state.

- Store lifecycle events per target_id in SessionManager, fed by ONE global
  Page.lifecycleEvent handler registered in start_monitoring() and routed by
  session_id; buffers are freed on target removal
- _navigate_and_wait reads the per-target buffer and now returns a timeout
  status string instead of swallowing readiness timeouts;
  on_NavigateToUrlEvent surfaces it via NavigationCompleteEvent.loading_status
- Skip loaderId-less lifecycle events that predate the current navigation
- Drop unused CDPSession._lifecycle_lock

Deterministic regression test: navigating tab A after opening tab B took
exactly the 3s fallback timeout before this fix, <0.5s after.
2026-07-03 22:48:20 +08:00
Laith Weinberger 66ad0c95b6 fix test 2026-07-01 22:30:41 +08:00
Laith Weinberger 334df2e4f5 change install cmd 2026-07-01 17:59:10 +08:00
Laith Weinberger 44f017fbc2 telemetry, fix issues
docs: remove rust; skills.sh install cmd
2026-07-01 17:57:24 +08:00
Laith Weinberger d73eea6329 sync browser-use skill from browser-harness 2026-06-29 15:20:21 +08:00
Laith Weinberger 53c3ba2e72 Fix browser use CLI review issues 2026-06-29 14:00:13 +08:00
Laith Weinberger f768a06cfe new browser use CLI; new functions for deleted CLI methods 2026-06-29 13:10:55 +08:00
Laith Weinberger bfaad696bf remove old CLI 2026-06-29 13:00:44 +08:00
Laith Weinberger d5338ec208 Check skill install path ancestors 2026-06-29 10:58:38 +08:00
Laith Weinberger f197139aec Validate skill install destination first 2026-06-29 10:55:31 +08:00
Laith Weinberger c8e386959d Overwrite browser-use skill installs 2026-06-29 10:52:50 +08:00
Laith Weinberger e4ceae8d8e Wrap browser-harness skill install 2026-06-29 10:18:12 +08:00
laithrw 1e2799288d Merge branch 'main' into browser-use-skill-harness 2026-06-29 09:57:37 +08:00
Laith Weinberger 3e8f620b70 add browser-use skill backed by browser-harness 2026-06-29 09:42:26 +08:00
Saurav Panda 5123e4fc08 style: tighten ResilientEventBus docstring and comments 2026-06-26 15:56:17 +08:00
Saurav Panda 9c1db02dd3 fix(browser): preserve EventBus_ name prefix on ResilientEventBus
bubus derives the default bus name from the class name, so the
ResilientEventBus default factory changed session bus names from
EventBus_* to ResilientEventBus_*, breaking the EventBus_ prefix contract
asserted in tests/ci/browser/test_session_start.py. Default the subclass
name back to EventBus_<id> when none is given (explicit names still honored).
2026-06-26 15:48:59 +08:00
Saurav Panda 16c2745a37 fix(browser): tolerate stepping a torn-down event bus on warm-Lambda resume
The V2 worker reuses a keep_alive BrowserSession across warm Lambda
invocations. At the end of a run Agent.close() stops the session's event
bus and nulls out its async primitives (event_queue / _on_idle) to release
the event loop. On resume the worker can step() the bus before any
dispatch() restarts it, and stock bubus EventBus.step() asserts
"EventBus._start() must be called before step()" in that state — crashing
the run deterministically so the task dead-letters after max receives
(~1,600+ occurrences over 2 days).

Wrap the session's bus in a ResilientEventBus subclass whose step() and
wait_until_idle() are safe no-ops when the bus has not been started,
instead of asserting. The nulling stays (it's what lets the next dispatch()
recreate a fresh queue and _start() the bus), so a later dispatch() still
restarts the bus and processes events normally.

Fixes ENG-5280.
2026-06-26 13:28:53 +08:00
Saurav Panda e29cdeae06 fix(tests): bump retired claude-sonnet-4-0 to claude-sonnet-4-6
Anthropic retired Claude Sonnet 4 (claude-sonnet-4-0 /
claude-sonnet-4-20250514) on 2026-06-15. The live-API model test in
tests/ci/models/test_llm_anthropic.py pinned that alias, so every CI run
now gets a 404 not_found_error and the agent never completes the task,
failing the models/test_llm_anthropic job on all branches.

Bump the test to the current GA Sonnet (claude-sonnet-4-6).
2026-06-26 12:22:17 +08:00
Saurav Panda b88fd70481 fix(tools): truncate long URLs in save_as_pdf footer so page numbers stay visible
A flex item defaults to min-width:auto and won't shrink below its content,
so a long/unbroken URL in the default footer template overflowed and pushed
the page / totalPages span off the printable area. Give the url span
min-width:0 + overflow ellipsis so it truncates, and flex-shrink:0 on the
page-count span so it always renders. Adds a long-URL regression test.
2026-06-15 13:54:38 +05:30
Saurav Panda 5fd4e40efb Merge branch 'main' into saurav/pdf-header-footer-metadata 2026-06-15 11:37:09 +05:30
Saurav Panda 47a52790a6 chore(llm): remove bu-3 / bu-3-max, default beta example to openai/gpt-5.5
Drop the bu-3 and bu-3-max model ids everywhere they were surfaced:
- ChatBrowserUse no longer lists them as valid bu-* aliases (provider-prefixed
  ids like openai/gpt-5.5 are still accepted by the gateway).
- Remove their custom pricing entries and the README pricing blocks.
- Update docstrings, README quickstart, and the beta_agent example to use
  openai/gpt-5.5 as the default, with bu-2-0 shown as a commented alternative.
- Drop the tests that asserted bu-3/bu-3-max acceptance and pricing.
2026-06-11 22:50:30 +05:30
Saurav Panda ad8f3a4dd7 feat(tools): print page metadata in save_as_pdf header/footer
The save_as_pdf action now renders page metadata into the PDF margins by
default, matching Chrome's Print dialog: the date in the header and the page
URL plus page numbers in the footer.

- Add display_header_footer (default True), header_template, and
  footer_template params to SaveAsPdfAction.
- Pass displayHeaderFooter + header/footer templates and explicit margins to
  CDP Page.printToPDF so the metadata has room to render (Chrome clips it
  otherwise, and defaults header/footer font-size to 0px).
- Default templates show the date / URL + page numbers; callers can override
  with custom HTML or disable entirely for a clean PDF.
2026-06-11 08:29:41 +05:30
Saurav Panda 4cbc5dfa4d feat(llm): accept provider-prefixed models in ChatBrowserUse
ChatBrowserUse now accepts provider-prefixed model ids (anthropic/*,
openai/*, google/*) alongside the bu-* aliases and browser-use/* models,
so a single BROWSER_USE_API_KEY can reach them. bu-* aliases and the
bu-latest -> bu-2-0 normalization are unchanged; bare ids are rejected
with guidance toward the provider/model form.

Also matches provider-prefixed Claude Sonnet ids in the Agent
llm_screenshot_size auto-config, so the screenshot optimization isn't
lost when Claude is reached via ChatBrowserUse.

Adds an example, a README FAQ entry, and tests.

ENG-5060
2026-06-10 12:03:51 +05:30
Magnus Müller a4d8418334 Merge branch 'main' into MagMueller/implement-bu3max-model-with-caching-in-cloud-repos 2026-06-09 19:27:07 -07:00
Gregor Žunič 8c9ed8281e Fix packaged agent tools env 2026-06-09 16:45:42 -07:00
MagMueller 6caf43e5a9 Add BU3 pricing rows 2026-06-09 08:04:00 -07:00
Magnus Müller 8a3d202291 Merge branch 'main' into MagMueller/implement-bu3max-model-with-caching-in-cloud-repos 2026-06-08 18:49:50 -07:00
Gregor Žunič 0cfe7bf7c5 Close beta SDK browser resources 2026-06-08 14:21:31 -07:00
MagMueller be81a1bfe5 add bu3 browser use models 2026-06-08 14:13:33 -07:00
Gregor Žunič a75b950dc7 Fix prerelease version upgrade check 2026-06-08 13:35:20 -07:00
Gregor Žunič 683fd178cf Avoid URL substring assertions in beta tests 2026-06-08 13:08:10 -07:00