From 53ffe92c14f22c1b970e2ea0907bdb3970fe16ac Mon Sep 17 00:00:00 2001 From: ciregenz Date: Thu, 4 Jun 2026 18:40:06 -0700 Subject: [PATCH] [eric] browser: return navigate on dom-ready so heavy SPAs stop hanging the 20s cap --- frontend/src/shared/browserCommandHandler.ts | 23 +++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/frontend/src/shared/browserCommandHandler.ts b/frontend/src/shared/browserCommandHandler.ts index 52888e34..05bb0997 100644 --- a/frontend/src/shared/browserCommandHandler.ts +++ b/frontend/src/shared/browserCommandHandler.ts @@ -155,10 +155,27 @@ async function handleNavigate(wv: BrowserWebview, params: Record): const raw = params.url as string; if (!raw) return { error: 'url parameter is required' }; const url = resolveInput(raw); + // loadURL resolves only on the full 'load' event, which heavy SPAs (LinkedIn, + // Gmail) hold open with persistent connections long past our timeout even though + // the page is usable in a second. Return the moment the DOM is ready and let the + // agent's next wait settle the rest, the way a person clicks before every + // background request has finished. + let removeReady = () => {}; + const domReady = new Promise((resolve) => { + const onReady = () => resolve(); + wv.addEventListener('dom-ready', onReady, { once: true }); + removeReady = () => wv.removeEventListener('dom-ready', onReady); + }); + const fullyLoaded = wv.loadURL(url).catch((err: any) => { + // A superseded navigation aborts the old load; that's normal, not a failure. + if (err?.message?.includes('ERR_ABORTED')) return; + throw err; + }); + fullyLoaded.catch(() => {}); // a late load failure shouldn't throw once dom-ready returned try { - await wv.loadURL(url); - } catch (err: any) { - if (!err?.message?.includes('ERR_ABORTED')) throw err; + await Promise.race([fullyLoaded, domReady]); + } finally { + removeReady(); } // Route-count is sampled on the next READ (handleGetText), not here: at // navigate-return the SPA's XHRs haven't fired yet, so this would always be ~0.