mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] browser: composer finder self-budgets its reveal ladder + 30s find_composer timeout
This commit is contained in:
@@ -15,6 +15,7 @@ BROWSER_CMD_TIMEOUTS = {
|
||||
"replay_route": 20.0, # an API fetch can be slow
|
||||
"wait": 12.0, # smart-wait already caps itself well under this
|
||||
"perform_action": 35.0, # session-borrow shims pack navigate + wait + scrape into ONE command, so it needs more than navigate alone
|
||||
"find_composer": 30.0, # packs trigger + scroll-ladder + retop + open-first into ONE command; on the 15s default the last two tiers were unreachable and heavy pages died mid-ladder (measured: linkedin timed out 2 of 3 runs). The in-page routine self-caps well under this.
|
||||
}
|
||||
BROWSER_CMD_REBROADCAST_S = 3.0
|
||||
# A CPU-starved renderer can briefly drop its WS (a missed heartbeat) and the frontend auto-reconnects a beat later; bridge that gap instead of hard-failing a live run into it. Short enough that a genuinely-closed window still fails quickly (and no LLM turns are ever burned waiting); long enough to ride out a reconnect even on a loaded machine.
|
||||
|
||||
@@ -570,11 +570,19 @@ async function handleFindComposer(wv: BrowserWebview, params: Record<string, any
|
||||
let hit = findBest();
|
||||
const acts = [];
|
||||
if (!hit && ${reveal}) {
|
||||
// Self-imposed budget. The tiers below sum to ~24s of worst case but the command that
|
||||
// carries them is killed at its own timeout, which threw away ALL the work and returned
|
||||
// nothing (measured: linkedin died mid-scroll 2 of 3 runs, so retop/open-first could never
|
||||
// run). Each tier now only STARTS if the budget can still pay for it, and polls are clipped
|
||||
// to what is left, so the routine always returns its own best answer instead of being shot.
|
||||
const DEADLINE = Date.now() + 21000;
|
||||
const left = () => DEADLINE - Date.now();
|
||||
const budget = (want) => Math.max(0, Math.min(want, left()));
|
||||
// 1. A compose opener visible up top (Gmail "Compose", LinkedIn "Start a post"). Patient
|
||||
// poll: LinkedIn code-splits its share modal, and under a heavy session the editor
|
||||
// chunk lands past 2.5s (measured: the 2.5s poll missed ~half the time; poll exits the
|
||||
// moment the editable appears, so the patience costs nothing on the happy path).
|
||||
try { if (clickTrigger(false)) { acts.push('trigger'); hit = await pollFind(6000); } } catch (e) { /* keep going */ }
|
||||
try { if (clickTrigger(false)) { acts.push('trigger'); hit = await pollFind(budget(6000)); } } catch (e) { /* keep going */ }
|
||||
// 2. Progressive scroll for a below-fold / lazy composer: YouTube comments hydrate on
|
||||
// scroll and start as a placeholder that only becomes editable once clicked, so scroll
|
||||
// a step, re-scan, and re-click the trigger on whatever just entered the viewport, up to
|
||||
@@ -582,13 +590,14 @@ async function handleFindComposer(wv: BrowserWebview, params: Record<string, any
|
||||
if (!hit) {
|
||||
const sc = document.scrollingElement || document.documentElement;
|
||||
let scrolled = false;
|
||||
for (let step = 0; step < 6 && !hit; step++) {
|
||||
// Reserve time for the retop + open-first tiers below, so the ladder can't eat the budget.
|
||||
for (let step = 0; step < 6 && !hit && left() > 7000; step++) {
|
||||
const before = sc.scrollTop;
|
||||
sc.scrollBy(0, Math.round(window.innerHeight * 0.9));
|
||||
scrolled = true;
|
||||
await sleep(500);
|
||||
hit = findBest();
|
||||
if (!hit) { try { if (clickTrigger(true)) hit = await pollFind(1400); } catch (e) { /* keep going */ } }
|
||||
if (!hit) { try { if (clickTrigger(true)) hit = await pollFind(budget(1400)); } catch (e) { /* keep going */ } }
|
||||
if (sc.scrollTop === before) break;
|
||||
}
|
||||
if (scrolled) acts.push('scroll');
|
||||
@@ -596,16 +605,16 @@ async function handleFindComposer(wv: BrowserWebview, params: Record<string, any
|
||||
// 3. Back to the top opener: the scroll ladder ends at page bottom with the top compose
|
||||
// entry off-screen; a modal that opened slowly (or needed a second click) is only
|
||||
// winnable by returning and retrying once.
|
||||
if (!hit) {
|
||||
if (!hit && left() > 2500) {
|
||||
try {
|
||||
(document.scrollingElement || document.documentElement).scrollTo(0, 0);
|
||||
await sleep(400);
|
||||
if (clickTrigger(false)) { acts.push('retop'); hit = await pollFind(4000); }
|
||||
if (clickTrigger(false)) { acts.push('retop'); hit = await pollFind(budget(4000)); }
|
||||
} catch (e) { /* keep going */ }
|
||||
}
|
||||
// 4. Last resort: open the first list item (X DMs / chat lists). Navigational, so it runs
|
||||
// only after trigger+scroll fail, which stops it from yanking YouTube to another video.
|
||||
if (!hit) { let did = false; try { did = openFirstItem(); } catch (e) { did = false; } if (did) { acts.push('open-first'); hit = await pollFind(2000); } }
|
||||
if (!hit && left() > 1200) { let did = false; try { did = openFirstItem(); } catch (e) { did = false; } if (did) { acts.push('open-first'); hit = await pollFind(budget(2000)); } }
|
||||
}
|
||||
if (!hit) return { found: false, reveals: acts };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user