fix(native): auto_launch() honours AGENT_BROWSER_PROVIDER for cloud providers (#1126)
When a non-launch command (e.g. open, snapshot) triggers auto_launch() before the explicit launch command is processed, auto_launch() now checks AGENT_BROWSER_PROVIDER and connects via the provider API instead of always falling back to a local Chrome instance. Also redirects daemon stderr to /dev/null when not in debug mode to prevent crashes from broken pipe after the CLI drops the piped stderr handle. Cloud providers may write to stderr during connection setup. Fixes #1125 Related: #979
This commit is contained in:
@@ -1481,6 +1481,48 @@ async fn auto_launch(state: &mut DaemonState) -> Result<(), String> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cloud provider: when AGENT_BROWSER_PROVIDER is set, connect via the
|
||||||
|
// provider API instead of launching a local Chrome instance. This mirrors
|
||||||
|
// the logic in handle_launch() so that auto_launch (triggered by any
|
||||||
|
// command arriving before an explicit "launch") honours the provider env.
|
||||||
|
if let Ok(provider) = env::var("AGENT_BROWSER_PROVIDER") {
|
||||||
|
let p = provider.to_lowercase();
|
||||||
|
// ios/safari are device providers handled via explicit launch command
|
||||||
|
if !p.is_empty() && p != "ios" && p != "safari" {
|
||||||
|
let conn = providers::connect_provider(&p).await?;
|
||||||
|
let ws_headers = if p == "agentcore" {
|
||||||
|
providers::take_agentcore_ws_headers()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let connect_result = if conn.direct_page {
|
||||||
|
BrowserManager::connect_cdp_direct(&conn.ws_url).await
|
||||||
|
} else if ws_headers.is_some() {
|
||||||
|
BrowserManager::connect_cdp_with_headers(&conn.ws_url, ws_headers).await
|
||||||
|
} else {
|
||||||
|
BrowserManager::connect_cdp(&conn.ws_url).await
|
||||||
|
};
|
||||||
|
match connect_result {
|
||||||
|
Ok(mgr) => {
|
||||||
|
state.reset_input_state();
|
||||||
|
state.browser = Some(mgr);
|
||||||
|
state.subscribe_to_browser_events();
|
||||||
|
state.start_fetch_handler();
|
||||||
|
state.start_dialog_handler();
|
||||||
|
state.update_stream_client().await;
|
||||||
|
write_provider_file(&state.session_id, &p);
|
||||||
|
try_auto_restore_state(state).await;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if let Some(ref ps) = conn.session {
|
||||||
|
providers::close_provider_session(ps).await;
|
||||||
|
}
|
||||||
|
return Err(format!("Provider '{}' connection failed: {}", p, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let mgr = BrowserManager::launch(options, engine.as_deref()).await?;
|
let mgr = BrowserManager::launch(options, engine.as_deref()).await?;
|
||||||
state.reset_input_state();
|
state.reset_input_state();
|
||||||
state.browser = Some(mgr);
|
state.browser = Some(mgr);
|
||||||
|
|||||||
@@ -41,6 +41,22 @@ pub async fn run_daemon(session: &str) {
|
|||||||
session
|
session
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Redirect stderr to /dev/null to prevent daemon crash when the
|
||||||
|
// parent CLI drops the piped stderr handle after startup. Cloud
|
||||||
|
// providers (AgentCore, Browserbase, etc.) may write to stderr
|
||||||
|
// during connection setup; a broken pipe would kill the daemon.
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::io::IntoRawFd;
|
||||||
|
if let Ok(devnull) = fs::File::create("/dev/null") {
|
||||||
|
let fd = devnull.into_raw_fd();
|
||||||
|
unsafe {
|
||||||
|
libc::dup2(fd, 2);
|
||||||
|
libc::close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pid_path = socket_dir.join(format!("{}.pid", session));
|
let pid_path = socket_dir.join(format!("{}.pid", session));
|
||||||
|
|||||||
Reference in New Issue
Block a user