From eeb62798a96a568dcdeb27a337c9504a58b07e8f Mon Sep 17 00:00:00 2001 From: ciregenz Date: Fri, 14 Aug 2026 06:02:37 -0700 Subject: [PATCH] arena: v31 first run void -- blocker message truncated + stale bbox + empty-completion retries; all fixed and verified Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01WsbS5x2rYsMDxP2kW3qqmQ --- e2e/browser-v3/arena/ARENA.md | 9 +++++++++ e2e/browser-v3/arena/llm_policy.py | 6 ++++++ e2e/browser-v3/arena/run.py | 22 +++++++++++++++------- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/e2e/browser-v3/arena/ARENA.md b/e2e/browser-v3/arena/ARENA.md index a1e08439..5826fd78 100644 --- a/e2e/browser-v3/arena/ARENA.md +++ b/e2e/browser-v3/arena/ARENA.md @@ -339,6 +339,15 @@ Prediction: >=3 of 8 targets (click-widget compositions specifically; the blocke now actually gets exercised when the model clicks the real covered input), controls 12/12 (suppression only fires on single-child weak-named shells). +FIRST RUN VOID (implementation bugs, not a verdict): targets 0/8 but the labeled trace showed +the BLOCKED message never reached the model — (a) it was APPENDED after Playwright's multi-line +call log and truncated out of both the record and history caps; (b) the bbox source +(extra_element_properties) goes stale post-step and pointed the probe at BODY. Fixed: message +prepended; rect computed in-page from the live bid element (verified: probe names +DIV.ui-dialog-titlebar). Also fixed alongside: empty LLM completions (thinking exhausting +max_tokens) are now retried with doubled budget instead of being booked as no-action turns — +this was the entire login-composition 0-step failure mode. Prediction unchanged; pilot rerun. + ## Positioning vs public generic-harness baselines (user-supplied 2026 survey) The comparable class is generic agents, NOT MiniWoB-specialized systems (HTML-T5++ 95.2 trained diff --git a/e2e/browser-v3/arena/llm_policy.py b/e2e/browser-v3/arena/llm_policy.py index c664def0..917b40fb 100644 --- a/e2e/browser-v3/arena/llm_policy.py +++ b/e2e/browser-v3/arena/llm_policy.py @@ -244,6 +244,12 @@ class LlmPolicy: payload["temperature"] = self.temperature resp = post_json(f"{self.endpoint}/v1/chat/completions", payload) text = (resp.get("choices") or [{}])[0].get("message", {}).get("content") or "" + # Thinking models sometimes spend the whole budget before emitting text; an empty + # reply must be retried like any fault, never silently booked as a no-action turn. + if not text.strip(): + payload["max_tokens"] = min(int(self.max_tokens * 2), 2000) + self.max_tokens = payload["max_tokens"] + raise ValueError("empty completion (thinking exhausted max_tokens?)") usage = resp.get("usage") or {} d.prompt_tokens = int(usage.get("prompt_tokens") or 0) d.completion_tokens = int(usage.get("completion_tokens") or 0) diff --git a/e2e/browser-v3/arena/run.py b/e2e/browser-v3/arena/run.py index 2334f2bd..9affa9b8 100644 --- a/e2e/browser-v3/arena/run.py +++ b/e2e/browser-v3/arena/run.py @@ -218,16 +218,24 @@ def run_episode(arm: str, task: str, seed: int, rec: Recorder, args: argparse.Na if (getattr(policy, "blocker_probe", False) and "Timeout" in err and re.match(r"(?:dbl)?click\(", decision.action)): m_bid = re.search(r'"([^"]+)"', decision.action) - bbox = ((obs.get("extra_element_properties") or {}).get(m_bid.group(1)) or {}).get("bbox") if m_bid else None - if bbox: + if m_bid: try: + # Rect computed in-page from the live element (extra_element_properties + # bboxes go stale post-step and once pointed the probe at BODY). top = with_deadline(lambda: env.unwrapped.page.evaluate( - "([x,y]) => { const e = document.elementFromPoint(x,y);" - " return e ? e.tagName + (e.id?'#'+e.id:'') +" - " (e.className&&typeof e.className==='string'?'.'+e.className.split(' ')[0]:'') : ''; }", - [bbox[0] + bbox[2] / 2, bbox[1] + bbox[3] / 2]), 8) + "(bid) => { const el = document.querySelector(`[bid=\"${bid}\"]`);" + " if (!el) return ''; const r = el.getBoundingClientRect();" + " const e = document.elementFromPoint(r.x + r.width/2, r.y + r.height/2);" + " if (!e || e === el || el.contains(e)) return '';" + " return e.tagName + (e.id?'#'+e.id:'') +" + " (e.className&&typeof e.className==='string'?'.'+e.className.split(' ')[0]:''); }", + m_bid.group(1)), 8) if top: - err += f" | BLOCKED: {top} is covering this element -- move or close the cover first (drag its titlebar or dismiss it), then retry" + # PREPENDED: a suffix after Playwright's multi-line call log gets + # truncated out of both the record and the model's history. + err = (f"BLOCKED: {top} is covering the element you clicked -- move or " + f"close the cover first (drag its titlebar or dismiss it), then " + f"retry | {err}") obs["last_action_error"] = err except Exception: pass