mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-08 02:37:45 +02:00
[eric] browser: stall backstop only fires after a real action, never cuts short early orientation
This commit is contained in:
@@ -1041,7 +1041,15 @@ async def run_browser_agent(
|
||||
# so reset and let it continue (multi-send stays safe).
|
||||
if _turn_actions == 0:
|
||||
perception_stall += 1
|
||||
_stall_limit = _POST_SEND_STALL_LIMIT if send_confirmed else _PERCEPTION_STALL_LIMIT
|
||||
# The general backstop only applies AFTER the agent has actually done
|
||||
# something (a real mutation, not a read), early pure-perception is
|
||||
# legitimate orienting (a cold/slow page can need several look turns
|
||||
# before the first action) and we must never cut that short. Reads
|
||||
# land in action_log with ok=True too, so check the TOOL, not just ok.
|
||||
_acted = any(a.get("ok") and a.get("tool") in (_BATCHABLE_ACTION_TOOLS | {"BrowserBatch"})
|
||||
for a in action_log)
|
||||
_stall_limit = (_POST_SEND_STALL_LIMIT if send_confirmed
|
||||
else (_PERCEPTION_STALL_LIMIT if _acted else 10 ** 9))
|
||||
if perception_stall >= _stall_limit:
|
||||
logger.info(
|
||||
f"[browser-agent {session_id}] ending: {perception_stall} pure-perception "
|
||||
|
||||
@@ -233,6 +233,25 @@ def test_confirmed_send_ends_the_run_instead_of_stalling(monkeypatch):
|
||||
assert result["summary"].startswith("OUTCOME: DONE") or "DONE" in result["summary"]
|
||||
|
||||
|
||||
def test_early_perception_is_not_cut_short_before_any_action(monkeypatch):
|
||||
# Orienting on a cold/slow page can take several look-only turns; the stall
|
||||
# backstop must NOT fire before the agent has done anything (it only bounds a
|
||||
# POST-action spin). Here 7 perception turns precede the finish; all must run.
|
||||
BH._browser_history.clear(); BH._domain_notes.clear()
|
||||
# varied read tools so the (separate) identical-repeat loop detector doesn't trip;
|
||||
# this isolates the stall backstop, which must NOT fire pre-action
|
||||
_reads = ["BrowserListInteractives", "BrowserGetText", "BrowserScreenshot"]
|
||||
primary = FakeLLM([
|
||||
*[Resp([_rp("still orienting"), _tu(_reads[i % 3])]) for i in range(7)],
|
||||
Resp([Blk("text", "OUTCOME: NOT DONE - could not find it")], stop_reason="end_turn"),
|
||||
])
|
||||
aux = FakeAux()
|
||||
_install(monkeypatch, primary, aux)
|
||||
asyncio.run(BA.run_browser_agent(task="find the thing", browser_id="b1", model="sonnet"))
|
||||
# it ran all 8 scripted turns (was NOT force-ended at the 6-perception backstop)
|
||||
assert primary.turn >= 8, f"early orientation was cut short at turn {primary.turn}"
|
||||
|
||||
|
||||
def test_aux_adjudication_fires_even_when_loop_detector_trips(monkeypatch):
|
||||
# Repeated IDENTICAL failing clicks trip the exact-repeat loop detector AND
|
||||
# reach stagnation exhaustion on the same turn. The aux escape hatch must
|
||||
|
||||
Reference in New Issue
Block a user