[eric] browser: send-script decline logging + prestage settle detects overlay opens via interactives diff

This commit is contained in:
ciregenz
2026-07-07 02:18:13 -07:00
parent 46c300e4ee
commit b9cf6b9e3f
2 changed files with 10 additions and 5 deletions
@@ -149,13 +149,14 @@ async def run_prestage(
seen_steps: set[tuple[str, str]] = set()
staged_complete = False
async def settle(pre_url: str, pre_text: str) -> bool:
# A click returns before the page swaps; perceiving too early reads the OLD page and the aux re-issues the same click (observed 4x loop). Wait for the page to actually change, capped. False = the action verifiably did NOT take.
async def settle(pre_url: str, pre_text: str, pre_li: str) -> bool:
# A click returns before the page swaps; perceiving too early reads the OLD page and the aux re-issues the same click (observed 4x loop). Wait for the page to actually change, capped. False = the action verifiably did NOT take. An overlay (message composer) changes the INTERACTIVES but not the URL and often not the first 400 chars of text, so the element list counts as change too.
t_s = time.monotonic()
while time.monotonic() - t_s < 3.0:
await asyncio.sleep(0.35)
li2, gt2, u2 = await perceive()
if (u2 and u2 != pre_url) or (gt2 and gt2[:400] != pre_text[:400]):
if ((u2 and u2 != pre_url) or (gt2 and gt2[:400] != pre_text[:400])
or (li2 and pre_li and li2 != pre_li)):
return True
return False
while steps < MAX_STEPS and (time.monotonic() - t0) < TOTAL_TIMEOUT_S:
@@ -193,7 +194,7 @@ async def run_prestage(
logger.info(f"[browser-prestage] step {steps + 1}: nav {arg} ok={ok}")
if not ok:
break
if not await settle(current_url, gt_text):
if not await settle(current_url, gt_text, li_text):
logger.info(f"[browser-prestage] nav {arg} did not settle; stopping unstaged")
break
done_desc.append(f"navigated to {arg}")
@@ -213,7 +214,7 @@ async def run_prestage(
logger.info(f"[browser-prestage] step {steps + 1}: click [{idx}] {entry[:60]!r} ok={ok}")
if not ok:
break
if not await settle(current_url, gt_text):
if not await settle(current_url, gt_text, li_text):
# The click ran but the page never changed (occluded element, overlay, stale index). Recording it would make the handoff note LIE ("navigation done") and send the main loop on a walkabout; observed live as 27-turn/112s regressions.
logger.info(f"[browser-prestage] click [{idx}] did not settle; stopping unstaged")
break
@@ -80,6 +80,7 @@ async def run_send_script(
t0 = time.monotonic()
payload = quoted_payload(task)
if not payload:
logger.info("[browser-sendscript] decline: no unambiguous quoted payload")
return None
log: list[dict] = []
@@ -96,7 +97,9 @@ async def run_send_script(
# Reversible-opener hop: prestage often stops on the profile with the "Message" opener visible (its settle raced the overlay). Opening a composer is the allowed opener class; the irreversible bar is unchanged.
opener = opener_index_in_state(state_text)
if not opener:
logger.info("[browser-sendscript] decline: no composer and no single exact-named opener in staged state")
return None
logger.info(f"[browser-sendscript] firing via opener {opener[1]!r} [{opener[0]}]")
r_open = await execute_tool("BrowserClickIndex", {"index": opener[0]}, browser_id, tab_id)
if not (isinstance(r_open, dict) and "error" not in r_open):
return None
@@ -112,6 +115,7 @@ async def run_send_script(
logger.info("[browser-sendscript] opener clicked but no composer appeared; handing to model")
return None
# No Send-button precondition: composer sites (LinkedIn) lazy-render Send only AFTER text commits, so it's resolved post-fill; never appearing = clean pre-click abort.
logger.info(f"[browser-sendscript] fill target {composer[1]!r} [{composer[0]}]")
# 1. fill (focused by node, the composer overlay path coordinate clicks miss)
r_fill = await execute_tool("BrowserClickIndex", {"index": composer[0], "text": payload}, browser_id, tab_id)