diff --git a/backend/apps/agents/browser/browser_plan_dispatch.py b/backend/apps/agents/browser/browser_plan_dispatch.py index f8655e85..4fcfa790 100644 --- a/backend/apps/agents/browser/browser_plan_dispatch.py +++ b/backend/apps/agents/browser/browser_plan_dispatch.py @@ -105,7 +105,8 @@ async def run_plan_dispatch( ), timeout=P_AUX_TIMEOUT_S)) steps = parse_plan(reply) if not steps: - logger.info("[plan-dispatch] aux emitted no safe mechanical steps") + logger.info(f"[plan-dispatch] aux emitted no safe mechanical steps " + f"(state={len(state_text)}ch, reply: {(reply or '')[:160]!r})") return "" done: list[str] = [] for step in steps: diff --git a/backend/apps/agents/browser/browser_prestage.py b/backend/apps/agents/browser/browser_prestage.py index 5c7adf1e..4887ca9a 100644 --- a/backend/apps/agents/browser/browser_prestage.py +++ b/backend/apps/agents/browser/browser_prestage.py @@ -337,6 +337,13 @@ async def run_prestage( if steps or not li_text: li_text, gt_text, seen_url = await perceive() current_url = seen_url or current_url + # Perceive-only lost the aux asks that ACCIDENTALLY doubled as settle time, so a cold SPA hands back a half-hydrated list (measured: plan-dispatch emitted [] on a thin search page). Wait for substance, bounded. + if perceive_only: + p_sub_t0 = time.monotonic() + while len(li_text or "") < 800 and time.monotonic() - p_sub_t0 < 4.0: + await asyncio.sleep(0.8) + li_text, gt_text, seen_url = await perceive() + current_url = seen_url or current_url block = perception_block(li_text, gt_text, stage_note_for(start_url, done_desc, current_url, staged_complete)) for tool_name, text in (("BrowserListInteractives", li_text), ("BrowserGetText", gt_text)): if text: