From eae31e744f76a3a7375f786fdb30e73443da144a Mon Sep 17 00:00:00 2001 From: ciregenz Date: Wed, 8 Jul 2026 17:08:16 -0700 Subject: [PATCH] [eric] browser: fold page text into the auto-attached post-action state (OSW_FOLD_TEXT, default off) = after any action the model has BOTH clickable elements AND readable text, so it stops double-perceiving (measured: 52% of tool calls are perception, ~half redundant list+GetText pairs, the biggest untouched turn-cost) --- backend/apps/agents/browser/browser_agent.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/apps/agents/browser/browser_agent.py b/backend/apps/agents/browser/browser_agent.py index 1be0462b..e3a4fc59 100644 --- a/backend/apps/agents/browser/browser_agent.py +++ b/backend/apps/agents/browser/browser_agent.py @@ -523,6 +523,16 @@ async def post_action_state( return "" state = lst["text"] if seen_lines is None else delta_state(lst["text"], seen_lines) out = f"\n\n{PAGE_STATE_MARKER}\n{p_truncate_state(state)}" + # Fold the page's READABLE TEXT in alongside the clickable elements (flag-gated). The model perceives nearly every page TWICE, once via list_interactives and once via GetText (measured: ~52% of all tool calls are perception, half of that redundant list+text pairs). Attaching a trimmed text excerpt here means after any action it already has BOTH views, so it never spends a separate GetText turn. A cheap code-side read (ms) trades for a ~4s model turn. + if os.environ.get("OSW_FOLD_TEXT", "0") == "1": + try: + p_gt = await asyncio.wait_for( + wait_exec("BrowserGetText", {}, browser_id, tab_id), timeout=5.0) + p_txt = str(p_gt.get("text") or "") if isinstance(p_gt, dict) and "error" not in p_gt else "" + if p_txt: + out += f"\n\n[Page text (you have this already, no need to GetText):]\n{p_txt[:1800]}" + except Exception: + pass # Hand the Send button's index over so the model clicks it directly instead of scanning the list or hunting via CSS/JS/screenshots (the polled list above is what makes Send actually present to point at, the two work together). if p_send_si: out = (f"\n\n[send-ready] Your message is typed and the Send button is index "