mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-26 06:22:22 +02:00
40 lines
2.6 KiB
TypeScript
40 lines
2.6 KiB
TypeScript
// Renderer-side mirror of the backend's smart-wait (browser_wait.py): a `wait` that returns the instant the page is READY instead of blind-sleeping. A top-level BrowserWait gets this on the backend, but a `wait` INSIDE a BrowserBatch runs entirely here, so without this it would fall back to a dumb sleep. Two readiness signals plus a target: settle when the agent's `until` target is present (no waiting blind), else when the page goes quiet by EITHER the network OR the DOM settling (beacon-heavy SPAs never idle the network but their DOM does).
|
|
|
|
export const SETTLE_FLOOR_MS = 250; // never settle before this unless the target is already there
|
|
export const SETTLE_QUIET_MS = 400; // network OR DOM must be quiet this long to count as settled
|
|
export const SETTLE_POLL_MS = 150;
|
|
|
|
// Probe built per wait so it can also look for the agent's target. Returns ready + quiet (network-idle ms) + elems (element count; the caller watches it stop changing = DOM settle) + found (the `until` target is present + visible). `until` is JSON- encoded into a string literal, so it is data, never executable.
|
|
export function settleProbeJs(until: string): string {
|
|
const spec = JSON.stringify(until || '');
|
|
return (
|
|
'(()=>{const n=performance.now();' +
|
|
"const es=performance.getEntriesByType('resource');let last=0;" +
|
|
'for(const e of es){const t=Math.max(e.responseEnd||0,e.startTime||0);if(t>last)last=t;}' +
|
|
'let found=false;const spec=' + spec + ';' +
|
|
'if(spec){try{const low=spec.toLowerCase();' +
|
|
"let el=[...document.querySelectorAll('button,a,[role],input,textarea,[contenteditable],[aria-label],h1,h2')]" +
|
|
".find(e=>((e.innerText||e.value||e.getAttribute('aria-label')||'')+'').toLowerCase().includes(low));" +
|
|
'if(!el){try{el=document.querySelector(spec);}catch(_){}}' +
|
|
'if(el){const r=el.getBoundingClientRect();found=r.width>0&&r.height>0;}}catch(_){}}' +
|
|
"return JSON.stringify({ready:document.readyState==='complete'," +
|
|
'quiet:Math.round(n-last),elems:document.getElementsByTagName(\'*\').length,found});})()'
|
|
);
|
|
}
|
|
|
|
// Pure decision. Stop the instant the target is present; otherwise, past the floor and once the document is complete, stop as soon as it's quiet by EITHER network OR DOM.
|
|
export function shouldStopWaiting(
|
|
ready: boolean,
|
|
quietMs: number,
|
|
domStableMs: number,
|
|
found: boolean,
|
|
elapsedMs: number,
|
|
floorMs = SETTLE_FLOOR_MS,
|
|
windowMs = SETTLE_QUIET_MS,
|
|
): boolean {
|
|
if (found) return true;
|
|
if (elapsedMs < floorMs) return false;
|
|
if (!ready) return false;
|
|
return (quietMs || 0) >= windowMs || (domStableMs || 0) >= windowMs;
|
|
}
|