Magnus/browser use rust main integration#68
Conversation
…st-main-integration # Conflicts: # crates/browser-use-agent/src/tools/handlers/browser.rs
…st-main-integration
…st-main-integration # Conflicts: # crates/browser-use-browser/src/browser_script_helpers.py # crates/browser-use-browser/src/lib.rs
…st-main-integration
…st-main-integration # Conflicts: # crates/browser-use-agent/src/entrypoint/mod.rs # crates/browser-use-agent/src/tools/handlers/browser.rs # crates/browser-use-agent/src/tools/handlers/browser_tests.rs # crates/browser-use-agent/src/turn/sampling.rs # crates/browser-use-browser/src/lib.rs # crates/browser-use-cli/src/main.rs
…er-use/terminal into magnus/browser-use-rust-main-integration
There was a problem hiding this comment.
7 issues found across 36 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="crates/browser-use-agent/src/tools/handlers/browser_tests.rs">
<violation number="1" location="crates/browser-use-agent/src/tools/handlers/browser_tests.rs:476">
P3: These tests are flaky under parallel execution because they share mutable global env state without synchronization. Serialize BU_CDP_URL mutations (or run these tests serially) to avoid cross-test interference.</violation>
</file>
<file name="crates/browser-use-agent/src/entrypoint/mod.rs">
<violation number="1" location="crates/browser-use-agent/src/entrypoint/mod.rs:2558">
P2: Disabling recorded-tail replay unconditionally can drop all prompt context when runtime journal reads fail. This turns a transient runtime read error into context loss for subsequent sampling.</violation>
</file>
<file name="python/llm_browser_worker/worker.py">
<violation number="1" location="python/llm_browser_worker/worker.py:257">
P2: Domain constraints are enforced even when no constraint env vars are set. This can wrongly block valid relative navigations in the Python worker and diverges from the Rust runtime behavior.</violation>
</file>
<file name="crates/browser-use-browser/src/browser_script_helpers.py">
<violation number="1" location="crates/browser-use-browser/src/browser_script_helpers.py:429">
P2: Unconditional `ensure_real_tab()` makes `page_info`/screenshot helpers switch tabs implicitly. In multi-tab runs this can make subsequent actions inspect or act on the wrong page.</violation>
<violation number="2" location="crates/browser-use-browser/src/browser_script_helpers.py:1169">
P1: `browser_fetch` silently corrupts binary request bodies by converting bytes to latin1 text before JS fetch. Requests that require exact byte payloads will be sent with different bytes.</violation>
</file>
<file name="crates/browser-use-browser/src/lib.rs">
<violation number="1" location="crates/browser-use-browser/src/lib.rs:3845">
P1: Domain allow/block enforcement misses `Target.createTarget` URL navigation path. A blocked domain can still be opened by creating a target with that URL.</violation>
<violation number="2" location="crates/browser-use-browser/src/lib.rs:3861">
P2: Profile runtime setup dedup persists across reconnects, so required setup may not run on a new connection. This can silently drop permissions/download/storage initialization after browser restart or endpoint switch.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| if not any(k.lower() == "content-type" for k in request_headers): | ||
| request_headers["Content-Type"] = "application/json" | ||
| if isinstance(request_body, bytes): | ||
| request_body = request_body.decode("latin1") |
There was a problem hiding this comment.
P1: browser_fetch silently corrupts binary request bodies by converting bytes to latin1 text before JS fetch. Requests that require exact byte payloads will be sent with different bytes.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/browser-use-browser/src/browser_script_helpers.py, line 1169:
<comment>`browser_fetch` silently corrupts binary request bodies by converting bytes to latin1 text before JS fetch. Requests that require exact byte payloads will be sent with different bytes.</comment>
<file context>
@@ -992,3 +1096,240 @@ def http_get(url, headers=None, timeout=20.0, binary=None):
+ if not any(k.lower() == "content-type" for k in request_headers):
+ request_headers["Content-Type"] = "application/json"
+ if isinstance(request_body, bytes):
+ request_body = request_body.decode("latin1")
+ return {
+ "url": str(url),
</file context>
| request_body = request_body.decode("latin1") | |
| raise TypeError("browser_fetch body bytes are unsupported; pass str/json_body or base64-encode manually") |
| session_id: Option<&str>, | ||
| params: &Value, | ||
| ) -> Result<()> { | ||
| if method == "Page.navigate" { |
There was a problem hiding this comment.
P1: Domain allow/block enforcement misses Target.createTarget URL navigation path. A blocked domain can still be opened by creating a target with that URL.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/browser-use-browser/src/lib.rs, line 3845:
<comment>Domain allow/block enforcement misses `Target.createTarget` URL navigation path. A blocked domain can still be opened by creating a target with that URL.</comment>
<file context>
@@ -3347,6 +3836,47 @@ impl BrowserSession {
+ session_id: Option<&str>,
+ params: &Value,
+ ) -> Result<()> {
+ if method == "Page.navigate" {
+ if let Some(url) = params.get("url").and_then(Value::as_str) {
+ if !browser_profile_url_allowed(url) {
</file context>
| if method == "Page.navigate" { | |
| if matches!(method, "Page.navigate" | "Target.createTarget") { |
| .with_runtime_handle(Some(runtime_handle.clone())) | ||
| .with_mailbox_delivery_phase(mailbox_delivery_phase); | ||
| .with_mailbox_delivery_phase(mailbox_delivery_phase) | ||
| .with_durable_prompt_replay(); |
There was a problem hiding this comment.
P2: Disabling recorded-tail replay unconditionally can drop all prompt context when runtime journal reads fail. This turns a transient runtime read error into context loss for subsequent sampling.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/browser-use-agent/src/entrypoint/mod.rs, line 2558:
<comment>Disabling recorded-tail replay unconditionally can drop all prompt context when runtime journal reads fail. This turns a transient runtime read error into context loss for subsequent sampling.</comment>
<file context>
@@ -2499,13 +2547,15 @@ impl<Sd: SamplingDriver> RuntimeTurnLoopDriver<Sd> {
.with_runtime_handle(Some(runtime_handle.clone()))
- .with_mailbox_delivery_phase(mailbox_delivery_phase);
+ .with_mailbox_delivery_phase(mailbox_delivery_phase)
+ .with_durable_prompt_replay();
// Enable REAL token accounting + model-based compaction when a sampler is
// available (the real backend path). The Fake/no-credential path passes `None`
</file context>
| raw = os.environ.get("BU_BROWSER_PERMISSIONS") | ||
| if not raw: | ||
| return [] | ||
| try: |
There was a problem hiding this comment.
P2: Domain constraints are enforced even when no constraint env vars are set. This can wrongly block valid relative navigations in the Python worker and diverges from the Rust runtime behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At python/llm_browser_worker/worker.py, line 257:
<comment>Domain constraints are enforced even when no constraint env vars are set. This can wrongly block valid relative navigations in the Python worker and diverges from the Rust runtime behavior.</comment>
<file context>
@@ -230,6 +234,275 @@ def _browser_mode() -> str:
+ raw = os.environ.get("BU_BROWSER_PERMISSIONS")
+ if not raw:
+ return []
+ try:
+ parsed = json.loads(raw)
+ except json.JSONDecodeError:
</file context>
| @@ -12,9 +12,11 @@ | |||
| import os | |||
There was a problem hiding this comment.
P2: Unconditional ensure_real_tab() makes page_info/screenshot helpers switch tabs implicitly. In multi-tab runs this can make subsequent actions inspect or act on the wrong page.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/browser-use-browser/src/browser_script_helpers.py, line 429:
<comment>Unconditional `ensure_real_tab()` makes `page_info`/screenshot helpers switch tabs implicitly. In multi-tab runs this can make subsequent actions inspect or act on the wrong page.</comment>
<file context>
@@ -386,6 +425,10 @@ def goto_url(url):
def page_info():
"""Return url, title, viewport, scroll position, page size, and target info."""
+ try:
+ ensure_real_tab()
+ except Exception:
+ pass
</file context>
| if self | ||
| .browser_profile_runtime | ||
| .applied_setup_keys | ||
| .contains(&call.key) | ||
| { | ||
| continue; | ||
| } | ||
| if connection | ||
| .call(&call.method, call.session_id.as_deref(), call.params) | ||
| .is_ok() | ||
| { | ||
| self.browser_profile_runtime | ||
| .applied_setup_keys | ||
| .insert(call.key); | ||
| } |
There was a problem hiding this comment.
P2: Profile runtime setup dedup persists across reconnects, so required setup may not run on a new connection. This can silently drop permissions/download/storage initialization after browser restart or endpoint switch.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/browser-use-browser/src/lib.rs, line 3861:
<comment>Profile runtime setup dedup persists across reconnects, so required setup may not run on a new connection. This can silently drop permissions/download/storage initialization after browser restart or endpoint switch.</comment>
<file context>
@@ -3347,6 +3836,47 @@ impl BrowserSession {
+ return Ok(());
+ };
+ for call in setup_calls {
+ if self
+ .browser_profile_runtime
+ .applied_setup_keys
</file context>
| if self | |
| .browser_profile_runtime | |
| .applied_setup_keys | |
| .contains(&call.key) | |
| { | |
| continue; | |
| } | |
| if connection | |
| .call(&call.method, call.session_id.as_deref(), call.params) | |
| .is_ok() | |
| { | |
| self.browser_profile_runtime | |
| .applied_setup_keys | |
| .insert(call.key); | |
| } | |
| let scoped_key = format!("{}:{}", self.connection_generation, call.key.as_str()); | |
| if self | |
| .browser_profile_runtime | |
| .applied_setup_keys | |
| .contains(&scoped_key) | |
| { | |
| continue; | |
| } | |
| if connection | |
| .call(&call.method, call.session_id.as_deref(), call.params) | |
| .is_ok() | |
| { | |
| self.browser_profile_runtime | |
| .applied_setup_keys | |
| .insert(scoped_key); | |
| } |
|
|
||
| #[tokio::test] | ||
| async fn bare_browser_connect_resolves_to_selected_remote_cdp_mode() { | ||
| let _guard = EnvVarGuard::set( |
There was a problem hiding this comment.
P3: These tests are flaky under parallel execution because they share mutable global env state without synchronization. Serialize BU_CDP_URL mutations (or run these tests serially) to avoid cross-test interference.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/browser-use-agent/src/tools/handlers/browser_tests.rs, line 476:
<comment>These tests are flaky under parallel execution because they share mutable global env state without synchronization. Serialize BU_CDP_URL mutations (or run these tests serially) to avoid cross-test interference.</comment>
<file context>
@@ -427,6 +471,60 @@ async fn bare_browser_connect_resolves_to_selected_cloud_mode() {
+#[tokio::test]
+async fn bare_browser_connect_resolves_to_selected_remote_cdp_mode() {
+ let _guard = EnvVarGuard::set(
+ "BU_CDP_URL",
+ "ws://127.0.0.1:9222/devtools/browser/session-id",
</file context>
Summary by cubic
Integrates Remote CDP browser mode, Anthropic prompt caching, and bounded-run controls while upgrading browser scripting, result handling, and tracing across the Rust and Python paths. This improves reliability, reduces prompt size, and aligns usage accounting and finalization with Browser Use behavior.
browser_scriptpage work with clear prompt guidance; no connect/start commands.cache_creation_input_tokens.max_turnsand injects progress/final nudges; CLI applies runtime config overrides.donetool now accepts{ "result"?, "result_file"?, "text"? }; registry and tests updated.http_get_many,browser_fetch, andbrowser_fetch_many; retries transient bridge errors; sturdier startup/waits; caps inline stdout to 4 KB (summaries preserved) and image dimension to 8k; structured fallback when text is empty.Written for commit 98c530c. Summary will update on new commits.