mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-05 17:27:42 +02:00
[eric] browser: make a read wait until the page stops growing, not just until it looks long enough
This commit is contained in:
@@ -14,8 +14,14 @@ class Resp:
|
||||
|
||||
|
||||
class Aux:
|
||||
def __init__(self, text): self.txt = text; self.messages = self; self.calls = 0
|
||||
async def create(self, **kw): self.calls += 1; return Resp(self.txt)
|
||||
def __init__(self, text):
|
||||
self.txt = text; self.messages = self; self.calls = 0; self.last_page = ""
|
||||
|
||||
async def create(self, **kw):
|
||||
self.calls += 1
|
||||
# Keep what the aux was actually shown: which page reached it IS the hydration contract.
|
||||
self.last_page = str(kw.get("messages", [{}])[0].get("content", ""))
|
||||
return Resp(self.txt)
|
||||
|
||||
|
||||
def tool_returning(text):
|
||||
@@ -28,6 +34,65 @@ def tool_returning(text):
|
||||
PAGE = "Tyler Chen\nHe/Him · 1st\nSomething Here\nIrvine, California\nEntrepreneurs First\n" + ("filler " * 200)
|
||||
|
||||
|
||||
def tool_returning_sequence(pages):
|
||||
"""A page that changes between reads, like an SPA finishing its render."""
|
||||
seen = []
|
||||
|
||||
async def run_tool(name, params, browser_id, tab_id):
|
||||
assert name == "BrowserGetText"
|
||||
seen.append(len(seen))
|
||||
return {"text": pages[min(len(seen) - 1, len(pages) - 1)]}
|
||||
run_tool.seen = seen
|
||||
return run_tool
|
||||
|
||||
|
||||
# Chrome that clears the 500-char floor while the actual content is still missing. This is the
|
||||
# shape that made the bug invisible: it is long enough to look like a real page.
|
||||
CHROME_ONLY = ("Home Feed My Network Jobs Messaging Notifications Me Work "
|
||||
"Skip to main content Keyboard shortcuts Close jump menu " * 12)
|
||||
HYDRATED = CHROME_ONLY + "\nTyler Chen\nSomething Here\nEntrepreneurs First\n" + ("filler " * 200)
|
||||
|
||||
|
||||
def test_waits_for_the_page_to_stop_growing(monkeypatch):
|
||||
"""The false-clean: a hydrating SPA crosses the char floor on nav and footer chrome long before
|
||||
the content lands. Answering from that first passing read produces a CONFIDENT WRONG answer,
|
||||
because the aux reports what it can see and nothing declines, so the INSUFFICIENT retry never
|
||||
fires. Two reads have to agree the page stopped growing before the aux sees anything."""
|
||||
monkeypatch.setattr(rs, "P_THIN_SETTLE_S", 0)
|
||||
monkeypatch.setattr(rs, "P_STABLE_SETTLE_S", 0)
|
||||
aux = Aux("His title is \"Something Here\".")
|
||||
tool = tool_returning_sequence([CHROME_ONLY, HYDRATED, HYDRATED])
|
||||
out = asyncio.run(rs.run_read_script(aux, "m", "find tyler chen's title", "b1", "t1", tool))
|
||||
|
||||
assert out == "His title is \"Something Here\"."
|
||||
assert len(tool.seen) >= 3, "must re-read until two reads agree, not answer off the first"
|
||||
sent = aux.last_page
|
||||
assert "Tyler Chen" in sent, "the aux must be handed the HYDRATED page, not the chrome-only one"
|
||||
|
||||
|
||||
def test_a_settled_page_still_answers_without_extra_waiting(monkeypatch):
|
||||
"""The guard must not turn every read into a slow read: a page that is already done answers as
|
||||
soon as two reads agree, which is immediately."""
|
||||
monkeypatch.setattr(rs, "P_THIN_SETTLE_S", 0)
|
||||
monkeypatch.setattr(rs, "P_STABLE_SETTLE_S", 0)
|
||||
aux = Aux("answer")
|
||||
tool = tool_returning_sequence([HYDRATED, HYDRATED])
|
||||
assert asyncio.run(rs.run_read_script(aux, "m", "q", "b1", "t1", tool)) == "answer"
|
||||
assert len(tool.seen) == 2, "a settled page costs exactly one confirming re-read"
|
||||
|
||||
|
||||
def test_a_page_that_never_settles_still_answers_from_the_last_read(monkeypatch):
|
||||
"""Something that keeps streaming forever (a live feed) must not fail closed to the loop just
|
||||
for being busy; after the read budget we use the fullest page we got."""
|
||||
monkeypatch.setattr(rs, "P_THIN_SETTLE_S", 0)
|
||||
monkeypatch.setattr(rs, "P_STABLE_SETTLE_S", 0)
|
||||
grows = [HYDRATED + ("more " * 200 * i) for i in range(1, 8)]
|
||||
aux = Aux("answer")
|
||||
tool = tool_returning_sequence(grows)
|
||||
assert asyncio.run(rs.run_read_script(aux, "m", "q", "b1", "t1", tool)) == "answer"
|
||||
assert len(tool.seen) == rs.MAX_READS
|
||||
|
||||
|
||||
def test_flag_gate(monkeypatch):
|
||||
monkeypatch.delenv("OSW_READ_SCRIPT", raising=False)
|
||||
assert rs.read_script_enabled() is False
|
||||
|
||||
Reference in New Issue
Block a user