feat(stealth): silent operation — never steal the user's foreground tab
Driving the user's real Chrome should not yank their view around. Now the agent operates entirely in the background: - New tabs are created with `background: true` (CreateTargetParams) so opening one never foregrounds it (the ab-connect extension already used active:false; this covers the raw-CDP path too). - Dropped the two AUTO `Page.bringToFront` calls (auto-connect fresh tab, and the internal active-page switch). The explicit `bringToFront` command is untouched — surfacing a tab stays opt-in. - enable_domains now sets `Emulation.setFocusEmulationEnabled(true)` so a backgrounded agent tab still renders (screenshots work), isn't render-throttled, and reports document.hasFocus()/visibilityState='visible' — which also removes the "tab is hidden the whole session" bot tell. Verified headless: hasFocus=true/visible while backgrounded; click + screenshot still work. Default behaviour, no flag.
This commit is contained in:
@@ -581,6 +581,7 @@ impl BrowserManager {
|
||||
&CreateTargetParams {
|
||||
url: "about:blank".to_string(),
|
||||
agent_group,
|
||||
background: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
@@ -687,6 +688,20 @@ impl BrowserManager {
|
||||
Some(session_id),
|
||||
)
|
||||
.await;
|
||||
// Silent operation: agent tabs are driven in the background (we never
|
||||
// force them to the foreground), so emulate focus. Without this a
|
||||
// backgrounded tab is render-throttled and reports `document.hidden` /
|
||||
// `!document.hasFocus()` — which both breaks timing-sensitive pages and
|
||||
// is itself a bot signal (a real user looks at the page). Best-effort;
|
||||
// ignored on engines without Emulation support.
|
||||
let _ = self
|
||||
.client
|
||||
.send_command(
|
||||
"Emulation.setFocusEmulationEnabled",
|
||||
Some(json!({ "enabled": true })),
|
||||
Some(session_id),
|
||||
)
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -973,6 +988,7 @@ impl BrowserManager {
|
||||
&CreateTargetParams {
|
||||
url: "about:blank".to_string(),
|
||||
agent_group,
|
||||
background: None,
|
||||
},
|
||||
None,
|
||||
)
|
||||
@@ -1137,6 +1153,7 @@ impl BrowserManager {
|
||||
&CreateTargetParams {
|
||||
url: target_url.to_string(),
|
||||
agent_group,
|
||||
background: Some(true),
|
||||
},
|
||||
None,
|
||||
)
|
||||
@@ -1192,11 +1209,10 @@ impl BrowserManager {
|
||||
let session_id = self.pages[index].session_id.clone();
|
||||
self.enable_domains(&session_id).await?;
|
||||
|
||||
// Bring tab to front
|
||||
let _ = self
|
||||
.client
|
||||
.send_command("Page.bringToFront", None, Some(&session_id))
|
||||
.await;
|
||||
// Silent: switching the agent's *internal* active page must not yank the
|
||||
// user's foreground tab. The page is driven in the background (focus is
|
||||
// emulated in enable_domains); the explicit `bringToFront` command is the
|
||||
// only way a tab is deliberately surfaced.
|
||||
|
||||
let url = self.get_url().await.unwrap_or_default();
|
||||
let title = self.get_title().await.unwrap_or_default();
|
||||
|
||||
Reference in New Issue
Block a user