[eric] browser: a send task is not staged until there is somewhere to write

This commit is contained in:
ciregenz
2026-08-02 17:48:00 -07:00
parent d67df490f8
commit 8a6be84a4c
2 changed files with 34 additions and 0 deletions
@@ -388,6 +388,7 @@ async def run_prestage(
p_total_timeout = OPENER_TOTAL_TIMEOUT_S if opener_mode() else TOTAL_TIMEOUT_S
p_system = P_SYSTEM_OPENER if opener_mode() else P_SYSTEM
p_results_overruled = False
p_composer_overruled = False
while (not staged_complete and steps < p_max_steps
and (time.monotonic() - t0) < p_total_timeout):
# Per-step cost, broken out. Prestage is the largest single phase of a LinkedIn write
@@ -423,6 +424,21 @@ async def run_prestage(
"one specific person or thing, CLICK through to its own page first; "
"READY again only if the task really is about this list.]")
continue
# A send task is not staged until there is somewhere to write. Measured live: on
# instagram the aux replies "I can see the Instagram home page is loaded" and calls
# READY from the feed, and on tiktok it says "CLICK [1] READY" in one breath, before
# the click it just asked for could open anything. Both then decline downstream with
# composer=0 textboxes=0, having spent the whole stage. Same overrule shape as the
# results-list rule above: nudge once, accept a second READY, because some surfaces
# really do hide their box until the fill tier clicks an opener.
if (task_is_send and not p_composer_overruled
and not browser_send_parse.composer_index_in_state(li_text)):
p_composer_overruled = True
task = task + (
"\n\n[You replied READY but no compose text box is listed in the elements. "
"OPEN the specific item the task names, on its own page, or CLICK the "
"control that reveals the box. READY again only once a textbox is listed.]")
continue
staged_complete = True
logger.info(f"[browser-prestage] READY after {steps} step(s): {arg[:80]}")
break
@@ -103,3 +103,21 @@ def test_half_an_emoji_cannot_kill_the_whole_prestage():
# A well-formed emoji is left alone; scrubbing real content would be its own bug.
assert strip_lone_surrogates("done \U0001f9e0 ok") == "done \U0001f9e0 ok"
assert strip_lone_surrogates("") == ""
def test_ready_on_a_page_with_nowhere_to_write_gets_one_nudge():
"""The instagram/tiktok shape, measured live 2026-08-02 at N=5: 0/4 each, every run declining
downstream with composer=0 textboxes=0.
Prestage took the aux model's word for "READY". On instagram it replied "I can see the Instagram
home page is loaded" and called READY from the feed; on tiktok it said "CLICK [1] READY" in one
breath, declaring done before the click it had just asked for could open anything. Both burned
the whole stage and handed the send script a page with no box in it.
A send task is not staged until something can be written into. The gate is the same shape as the
results-list overrule beside it: nudge once, accept a second READY, because some surfaces really
do hide their box behind an opener the fill tier clicks later.
"""
from backend.apps.agents.browser.browser_send_parse import composer_index_in_state
assert composer_index_in_state(NO_COMPOSER) is None, "the feed shape must read as no composer"
assert composer_index_in_state(COMPOSER_PRESENT) is not None, "a staged page must read as one"